diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index 9b5ce1dec..a90499665 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -439,3 +439,17 @@ These PAL reconstructions also use the public RAC3 sources pinned below; each ta | `src/pal/overlays/shared/L00_006F2370.c` | `src/levels/shared/L39_00662678.c` | `func_L39_00665CC0` | `cd0e7c20fd8a93116566ba2e024fa2f3536bd30c` | | `src/pal/overlays/l41_battledome_tower/L41_00411F80.c` | `src/levels/shared/L40_00420998.c` | `func_L40_004224F8` | `cd0e7c20fd8a93116566ba2e024fa2f3536bd30c` | | `src/pal/overlays/l41_battledome_tower/L41_00621CE8.c` | `src/levels/shared/L40_005416F0.c` | `func_L40_005416F0` | `cd0e7c20fd8a93116566ba2e024fa2f3536bd30c` | + +## Further PAL engine-family references + +The additional PAL reconstructions listed in +[`config/pal/crossgame_parallel01.tsv`](config/pal/crossgame_parallel01.tsv) +use public RAC3 decompilations as algorithm and interface references, including +the unified OpenRAC checkout. Each row records the repository, immutable commit, +file and reference function; the C sources also carry their credits. + +The RAC3 game-source scope is described in the earlier public-decompilations +notice and the reference project's `LEGAL.md`. Fingerprints identify candidates; +these reconstructions were checked independently against RAC4 PAL instructions, +actual address targets and caller/callee interfaces. No proprietary SDK source, +samples or headers were used. diff --git a/config/pal/crossgame_parallel01.tsv b/config/pal/crossgame_parallel01.tsv new file mode 100644 index 000000000..c44da6824 --- /dev/null +++ b/config/pal/crossgame_parallel01.tsv @@ -0,0 +1,13 @@ +# Public references for independently reconstructed PAL functions. +# Fingerprints are candidate metadata; acceptance requires RAC4 retail audits. +name repository commit path reference_function fingerprint +func_0042BA60 OpenRAC/rac3-decomp cd0e7c20fd8a93116566ba2e024fa2f3536bd30c src/levels/shared/L01_00314158.c func_L01_00315800 1618af86d8d943eb +func_0044B100 OpenRAC/OpenRAC 73f725bf54bb1bf6d8b9bb5b1511ed00d551fbde games/rac3/ntsc/src/frontbin/37E0F0.c func_00387B10 c314de3988bc1f3f +func_00454C38 OpenRAC/OpenRAC 73f725bf54bb1bf6d8b9bb5b1511ed00d551fbde games/rac3/ntsc/src/frontbin/3896E8.c func_003899B8 03eda974ec39dcfc +func_00459FD0 OpenRAC/OpenRAC 73f725bf54bb1bf6d8b9bb5b1511ed00d551fbde games/rac3/ntsc/src/frontbin/3896E8.c func_0038DF10 6e59892a8fe0710a +func_004644A8 OpenRAC/rac3-decomp cd0e7c20fd8a93116566ba2e024fa2f3536bd30c src/levels/shared/L01_0042B4F8.c func_L01_0042C370 17bef0551d1644ad +func_00489550 OpenRAC/OpenRAC 73f725bf54bb1bf6d8b9bb5b1511ed00d551fbde games/rac3/ntsc/src/frontbin/39BC00.c func_0039C028 2ae2ba1adad65e1c +func_00493D48 OpenRAC/rac3-decomp cd0e7c20fd8a93116566ba2e024fa2f3536bd30c src/levels/shared/L01_0046A938.c func_L01_0046ABC0 895824762f6e3406 +func_004E3C48 OpenRAC/OpenRAC 73f725bf54bb1bf6d8b9bb5b1511ed00d551fbde games/rac3/ntsc/src/frontbin/3C9888.c func_003C99D0 e297d0b7984082fb +func_004F16C8 OpenRAC/OpenRAC 73f725bf54bb1bf6d8b9bb5b1511ed00d551fbde games/rac3/ntsc/src/frontbin/3ABA48.c func_003ABA48 4a299efcf138e3d3 +func_004F2D88 OpenRAC/OpenRAC 73f725bf54bb1bf6d8b9bb5b1511ed00d551fbde games/rac3/ntsc/src/frontbin/3ABA48.c func_003AD108 1bc2c8df1ccd99fd diff --git a/src/pal/game/0040BAB8.c b/src/pal/game/0040BAB8.c new file mode 100644 index 000000000..2ae0442ac --- /dev/null +++ b/src/pal/game/0040BAB8.c @@ -0,0 +1,34 @@ +#include "common.h" +typedef struct { + u8 *data; + u32 remaining; +} Cursor; +typedef struct { + u8 prefix[12]; + Cursor cursor; +} Input; +s32 func_0040BAB8(const Input *input, Cursor *output) +{ + u32 remaining; + u8 *nextData; + *output = input->cursor; + remaining = output->remaining; + if (!remaining || (output->data[0] & 0x80)) + return 0x801; + goto test; +next: + { + u32 nextRemaining = remaining - 1; + output->data = nextData; + output->remaining = nextRemaining; + remaining = nextRemaining; + } +test: + if (remaining) { + u8 *data = output->data; + nextData = data + 1; + if (!*data) + goto next; + } + return 0; +} diff --git a/src/pal/game/0042BA60.c b/src/pal/game/0042BA60.c new file mode 100644 index 000000000..a155469d6 --- /dev/null +++ b/src/pal/game/0042BA60.c @@ -0,0 +1,33 @@ +#include "common.h" + +/* Reference: OpenRAC/rac3-decomp@cd0e7c20fd8a93116566ba2e024fa2f3536bd30c + * rac3-decomp/src/levels/shared/L01_00314158.c func_L01_00315800. + * Independently reconstructed from RAC4 PAL retail. */ + +typedef struct { + u8 *object; + u32 color; + s32 reserved; + f32 fraction; + u8 tail[16]; +} Entry; +extern Entry D_00227A20[]; +extern u8 **func_00476E90(void *); +extern u32 func_00454480(u32, u32, f32); +extern void func_00470990(void *, u32, u32, u32); +void func_0042BA60(s32 index, u32 color) +{ + s32 alpha; + u8 **child; + s32 mixed, red, green, blue; + alpha = (s32)(D_00227A20[index].fraction * 96.0f); + D_00227A20[index].object[35] = alpha; + child = func_00476E90(D_00227A20[index].object); + if (child != 0 && *child != 0) + (*child)[35] = alpha; + mixed = func_00454480(color, D_00227A20[index].color, D_00227A20[index].fraction); + blue = (mixed >> 16) & 0xFF; + green = (mixed >> 8) & 0xFF; + red = mixed & 0xFF; + func_00470990(D_00227A20[index].object, red, green, blue); +} diff --git a/src/pal/game/0044B100.c b/src/pal/game/0044B100.c new file mode 100644 index 000000000..3b197ef5c --- /dev/null +++ b/src/pal/game/0044B100.c @@ -0,0 +1,32 @@ +#include "common.h" + +/* Reference: OpenRAC/OpenRAC@73f725bf54bb1bf6d8b9bb5b1511ed00d551fbde + * OpenRAC/games/rac3/ntsc/src/frontbin/37E0F0.c func_00387B10. + * Independently reconstructed from RAC4 PAL retail. */ + +typedef int Quad __attribute__((mode(TI))); +extern u8 *D_00221F20; +extern Quad D_00220000; +void func_0044B100(const u64 *coordinates, const s32 *values) +{ + u8 *first, *next, *cursor; + *(u32 *)(D_00221F20 + 0) = 0x10000005; + *(u32 *)(D_00221F20 + 4) = 0; + *(u32 *)(D_00221F20 + 8) = 0; + *(u32 *)(D_00221F20 + 12) = 0x50000005; + cursor = (u8 *)D_00221F20; + D_00221F20 = cursor + 16; + *(Quad *)(cursor + 16) = D_00220000; + first = (u8 *)D_00221F20; + next = first + 16; + D_00221F20 = next; + *(u64 *)(first + 16) = 0x4C; + *(u64 *)(next + 8) = (s64)values[0]; + *(u64 *)(next + 16) = coordinates[0]; + *(u64 *)(next + 24) = coordinates[2]; + *(u64 *)(next + 32) = (s64)values[1]; + *(u64 *)(next + 40) = coordinates[1]; + *(u64 *)(next + 48) = coordinates[3]; + *(u64 *)(next + 56) = 0; + D_00221F20 += 64; +} diff --git a/src/pal/game/00452F08.c b/src/pal/game/00452F08.c new file mode 100644 index 000000000..48b22d62b --- /dev/null +++ b/src/pal/game/00452F08.c @@ -0,0 +1,32 @@ +#include "common.h" + +typedef struct { + u8 unknown0[0xA4]; + s32 count; +} Collection; + +typedef struct { + u8 unknown0[0x10]; + u8 *entries[0]; +} Entries; + +void func_00452F08(void *unused, Collection *collection, const void *clearFirst, s32 value) +{ + s32 i; + s32 j; + u8 *entry; + + for (i = 0; i < collection->count; i++) { + entry = ((Entries *)collection)->entries[i]; + if (clearFirst != 0) { + for (j = 0; j < entry[0xA]; j++) { + entry[9 + j * 0x40] = 0; + } + } else { + entry[9] = value; + for (j = 1; j < entry[0xA]; j++) { + entry[9 + j * 0x40] = 0; + } + } + } +} diff --git a/src/pal/game/00454C38.c b/src/pal/game/00454C38.c new file mode 100644 index 000000000..d8a495774 --- /dev/null +++ b/src/pal/game/00454C38.c @@ -0,0 +1,42 @@ +#include "common.h" + +/* Reference: OpenRAC/OpenRAC@73f725bf54bb1bf6d8b9bb5b1511ed00d551fbde + * OpenRAC/games/rac3/ntsc/src/frontbin/3896E8.c func_003899B8. + * Independently reconstructed from RAC4 PAL retail. */ + +typedef struct { + u32 first; + u32 metrics; +} Glyph; +extern Glyph *D_0021DF14; +extern s32 func_00454C18(void); +s32 func_00454C38(f32 *width, f32 *height, s32 mode) +{ + s32 result; + *width = 0.0f; + *height = 0.0f; + result = 0; + if (D_0021DF14 != 0) { + if (mode != 0) { + *width = (f32)((D_0021DF14[0x41].metrics >> 17) & 0x3F); + *height = (f32)((D_0021DF14[0x41].metrics >> 9) & 0xFF) * 0.25f; + result = 1; + } else { + s32 count = func_00454C18(); + if (count > 0) { + s32 i; + u32 maximum = 0; + for (i = 0; i < count; i++) { + u32 current = (D_0021DF14[i].metrics >> 17) & 0x3F; + if (maximum < current) { + maximum = current; + *height = (f32)((D_0021DF14[i].metrics >> 9) & 0xFF) * 0.25f; + } + } + *width = (f32)maximum; + result = 1; + } + } + } + return result; +} diff --git a/src/pal/game/00459FD0.c b/src/pal/game/00459FD0.c new file mode 100644 index 000000000..4747944a5 --- /dev/null +++ b/src/pal/game/00459FD0.c @@ -0,0 +1,29 @@ +#include "common.h" + +/* Reference: OpenRAC/OpenRAC@73f725bf54bb1bf6d8b9bb5b1511ed00d551fbde + * OpenRAC/games/rac3/ntsc/src/frontbin/3896E8.c func_0038DF10. + * Independently reconstructed from RAC4 PAL retail. */ + +extern u32 *D_00221F20; +extern u8 D_003D9FF0[], D_003DA010[], D_0020BF90[], D_003D9F80[]; +void func_00459FD0(s32 alternate) +{ + D_00221F20[0] = 0x30000002; + if (alternate) + D_00221F20[1] = (u32)D_003D9FF0; + else + D_00221F20[1] = (u32)D_003DA010; + D_00221F20[2] = 0; + D_00221F20[3] = 0x50000002; + D_00221F20 += 4; + D_00221F20[0] = 0x30000029; + D_00221F20[1] = (u32)D_0020BF90; + D_00221F20[2] = 0; + D_00221F20[3] = 0x50000029; + D_00221F20 += 4; + D_00221F20[0] = 0x30000003; + D_00221F20[1] = (u32)D_003D9F80; + D_00221F20[2] = 0; + D_00221F20[3] = 0x50000003; + D_00221F20 += 4; +} diff --git a/src/pal/game/004644A8.c b/src/pal/game/004644A8.c new file mode 100644 index 000000000..a3aa81b3a --- /dev/null +++ b/src/pal/game/004644A8.c @@ -0,0 +1,19 @@ +#include "common.h" + +/* Reference: OpenRAC/rac3-decomp@cd0e7c20fd8a93116566ba2e024fa2f3536bd30c + * rac3-decomp/src/levels/shared/L01_0042B4F8.c func_L01_0042C370. + * Independently reconstructed from RAC4 PAL retail. */ + +typedef struct { + u8 prefix[0x8C]; + s16 count; +} State; +extern State D_00237100; +extern void func_00464E28(void); +void func_004644A8(void) +{ + while (D_00237100.count > 0) { + func_00464E28(); + D_00237100.count--; + } +} diff --git a/src/pal/game/00466940.c b/src/pal/game/00466940.c new file mode 100644 index 000000000..41ea58adb --- /dev/null +++ b/src/pal/game/00466940.c @@ -0,0 +1,31 @@ +#include "common.h" + +typedef struct { + s32 type, size, offset, state; +} Descriptor; +extern Descriptor D_003D8130[], D_003D8310[]; +extern s32 func_004693D0(const Descriptor *); +extern s32 func_004696E8(const u8 *, const u8 *, s32, Descriptor *); +extern void func_00469D68(void); +void func_00466940(const u8 *packet) +{ + s32 first = func_004693D0(D_003D8130); + s32 second = func_004693D0(D_003D8310); + s32 index; + const u8 *next; + s32 storedFirst = *(const s32 *)packet; + if (storedFirst == first && *(const s32 *)(packet + 4) == second) { + packet += 8; + next = packet + storedFirst; + func_004696E8(packet, next, 0, D_003D8130); + packet = next; + index = 0; + do { + const u8 *end = packet + second; + func_004696E8(packet, end, index, D_003D8310); + index++; + packet = end; + } while (index < 15); + func_00469D68(); + } +} diff --git a/src/pal/game/0046BC78.c b/src/pal/game/0046BC78.c new file mode 100644 index 000000000..a004804e9 --- /dev/null +++ b/src/pal/game/0046BC78.c @@ -0,0 +1,28 @@ +#include "common.h" + +typedef struct { + u8 prefix[0x20]; + s32 value; +} Config; +extern s32 func_0054C070(s32, s32); +extern Config *func_0054BF00(s32); +extern s32 func_0045D348(void); +extern s32 D_0021DE98; +extern f32 D_003DB0A0[]; +extern u8 D_001F8878[]; +s32 func_0046BC78(s32 world, s32 slot) +{ + s32 value = func_0054BF00(func_0054C070(world, slot))->value; + if (func_0045D348()) { + value = (s32)((f32)value * D_003DB0A0[(D_0021DE98 - 1) % 20]); + value /= 1000; + value *= 1000; + } else { + s32 level = D_001F8878[slot * 12 + ((world - 1) % 20) * 0x304 + 9]; + if (level >= 3) + value = 0; + else if (level) + value >>= level; + } + return value; +} diff --git a/src/pal/game/0046F2C8.c b/src/pal/game/0046F2C8.c new file mode 100644 index 000000000..9f269ab15 --- /dev/null +++ b/src/pal/game/0046F2C8.c @@ -0,0 +1,33 @@ +#include "common.h" +typedef struct { + char pad[0x10]; + u8 frames; + char gap[11]; + u8 *data; +} Object; +extern void func_0046A080(const void *, s32, u32), func_0046A0C0(void), func_0046E560(f32); +void func_0046F2C8(Object *p, f32 frame) +{ + s32 i = (s32)frame, j = i + 1; + f32 frac = frame - i; + u8 *d = p->data; + s32 size = d[2], head = d[1]; + u8 *first, *second; + if (j == p->frames) + j = 0; + i *= size; + j *= size; + first = d + (head + i) * 16; + second = d + (j + head) * 16; + if (head) { + func_0046A080(d, head, 0x2000); + func_0046A0C0(); + } + if (size) { + func_0046A080(first, size, 0x3000); + func_0046A0C0(); + func_0046A080(second, size, 0x3800); + func_0046A0C0(); + } + func_0046E560(frac); +} diff --git a/src/pal/game/00489550.c b/src/pal/game/00489550.c new file mode 100644 index 000000000..723d9019b --- /dev/null +++ b/src/pal/game/00489550.c @@ -0,0 +1,40 @@ +#include "common.h" + +/* Reference: OpenRAC/OpenRAC@73f725bf54bb1bf6d8b9bb5b1511ed00d551fbde + * OpenRAC/games/rac3/ntsc/src/frontbin/39BC00.c func_0039C028. + * Independently reconstructed from RAC4 PAL retail. */ + +typedef struct { + u8 prefix[0x74]; + s32 count; +} State; +extern State D_00237100; +extern u32 *D_00221F20; +extern u32 D_0021DAFC; +extern u8 D_0020C220[]; +extern s32 D_0023A900[]; +extern void func_00449D20(void), func_00449E80(void); +void func_00489550(u32 *buffer) +{ + D_00221F20 = buffer; + buffer[0] = 0x30000009; + D_00221F20[1] = (D_0021DAFC + 0xC0) & 0x0FFFFFFF; + D_00221F20[2] = 0; + D_00221F20[3] = 0x50000009; + D_00221F20[4] = 0x30000025; + D_00221F20[5] = (u32)D_0020C220; + D_00221F20[6] = 0; + D_00221F20[7] = 0x50000025; + D_00221F20 += 8; + D_00237100.count++; + if (D_0023A900[0] != 0) { + func_00449D20(); + buffer = D_00221F20; + } else { + func_00449E80(); + buffer = D_00221F20; + } + buffer[0] = 0x70000000; + D_00221F20[1] = 0; + D_00221F20 += 4; +} diff --git a/src/pal/game/0048C5F0.c b/src/pal/game/0048C5F0.c new file mode 100644 index 000000000..646ac9acb --- /dev/null +++ b/src/pal/game/0048C5F0.c @@ -0,0 +1,18 @@ +#include "common.h" +extern u8 *D_002215D8; +extern void func_00453F30(void *, const void *, u32); +extern u8 *func_0048C2D0(u32, u8 **, const u8 *); +s32 func_0048C5F0(const u8 *source, u8 **cursor, const u8 *limit) +{ + s32 i; + func_00453F30(D_002215D8 + 0x3024, source, 4); + source += 4; + *(u8 **)(D_002215D8 + 0x3028) = func_0048C2D0((u32) * (s32 *)(D_002215D8 + 0x3024) << 3, cursor, limit); + if (!*(u8 **)(D_002215D8 + 0x3028)) + return 1; + for (i = 0; i < *(s32 *)(D_002215D8 + 0x3024); i++) { + func_00453F30(*(u8 **)(D_002215D8 + 0x3028) + (i << 3), source, 8); + source += 8; + } + return 0; +} diff --git a/src/pal/game/00493D48.c b/src/pal/game/00493D48.c new file mode 100644 index 000000000..a56a8f537 --- /dev/null +++ b/src/pal/game/00493D48.c @@ -0,0 +1,39 @@ +#include "common.h" + +/* Reference: OpenRAC/rac3-decomp@cd0e7c20fd8a93116566ba2e024fa2f3536bd30c + * rac3-decomp/src/levels/shared/L01_0046A938.c func_L01_0046ABC0. + * Independently reconstructed from RAC4 PAL retail. */ + +typedef int Quad __attribute__((mode(TI))); +typedef struct { + Quad direction; + f32 rotation; + f32 gravity; + s32 lifetime; +} Motion; +extern u8 *func_00491450(s32); +extern s32 func_00472E40(s32); +extern f32 func_00472EB8(f32, f32); +extern u8 *D_00270AD0[]; +u8 *func_00493D48(const Quad *position, const Quad *direction, s32 lifetime, f32 scale, f32 gravity) +{ + u8 *particle = func_00491450(46); + Motion *motion; + if (particle != 0) { + *(Quad *)(particle + 0x10) = *position; + motion = (Motion *)(particle + 0x20); + *(u32 *)(particle + 4) = ((u32)(func_00472E40(10) + 38) << 24) | 0x808080; + particle[9] = 33; + particle[3] = 72; + particle[1] = 1; + particle[2] = *D_00270AD0[0]; + *(s16 *)(particle + 10) = 5; + *(f32 *)(particle + 12) = scale * 210000.0f; + motion->direction = *direction; + motion->rotation = func_00472EB8(0.0f, 256.0f); + particle[8] = (s32)motion->rotation; + motion->gravity = gravity; + motion->lifetime = lifetime; + } + return particle; +} diff --git a/src/pal/game/004A0398.c b/src/pal/game/004A0398.c new file mode 100644 index 000000000..435a11bd3 --- /dev/null +++ b/src/pal/game/004A0398.c @@ -0,0 +1,27 @@ +#include "common.h" +typedef struct { + char pad[0x14]; + f32 x, y, w, h; + u8 active; + char gap[7]; + s32 choice; + char rest[0x1D0]; +} State; +extern State D_00307354[]; +extern void func_004A0928(s32), func_004A0490(s32, f32 *, f32 *, f32 *, f32 *), func_004A0560(s32, s32, f32 *, f32 *, f32 *, f32 *), func_0049DD20(s32, s32, f32, f32, f32, f32), func_0049CCF8(s32, s32, s32, f32, f32, f32, f32); +void func_004A0398(s32 index, f32 x, f32 y, f32 w, f32 h) +{ + f32 c, d; + State *p = D_00307354 + index; + p->x = x; + p->y = y; + p->w = w; + p->h = h; + if (p->active) { + func_004A0928(index); + func_004A0490(index, &x, &y, &c, &d); + func_0049DD20(index, 0, x, y, c, d); + func_004A0560(index, p->choice, &x, &y, &c, &d); + func_0049CCF8(index, 0, 0, x, y, c, d); + } +} diff --git a/src/pal/game/004A0490.c b/src/pal/game/004A0490.c new file mode 100644 index 000000000..be26f4117 --- /dev/null +++ b/src/pal/game/004A0490.c @@ -0,0 +1,28 @@ +#include "common.h" + +typedef struct { + u8 prefix[0x14]; + f32 x, y, width, factor; + u8 gap[0xC]; + s32 frame; + u8 gap34[0x10]; + u8 active; + u8 tail[0x1BB]; +} State; +extern State D_00307354[]; +void func_004A0490(s32 index, f32 *x, f32 *y, f32 *width, f32 *height) +{ + f32 intermediate, spacing; + State *state = &D_00307354[index]; + if (state->active) + spacing = state->width * 0.48582998f; + else + spacing = 0.024038462f; + intermediate = state->factor * (f32)state->frame; + *height = intermediate; + *height = intermediate + (f32)(state->frame + 1) * 0.0072115385f + + (spacing + 0.024038462f) + 0.009615385f; + *x = state->x; + *y = state->y; + *width = state->width + 0.0078125f; +} diff --git a/src/pal/game/004A0560.c b/src/pal/game/004A0560.c new file mode 100644 index 000000000..a02fb2c66 --- /dev/null +++ b/src/pal/game/004A0560.c @@ -0,0 +1,37 @@ +#include "common.h" + +typedef struct { + u8 prefix[0x14]; + f32 x, y, width, factor; + u8 gap[0xC]; + s32 frame; + u8 gap34[0x10]; + u8 active; + u8 tail[0x1BB]; +} State; +extern State D_00307354[]; +void func_004A0560(s32 index, s32 row, f32 *x, f32 *y, f32 *width, f32 *height) +{ + State *state = &D_00307354[index]; + f32 spacing; + f32 value; + + f32 a, b, c; + s32 frame; + if (state->active) + spacing = state->width * 0.48582998f; + else + spacing = 0.024038462f; + frame = state->frame; + a = state->factor * (f32)frame; + b = (f32)(frame + 1) * 0.0072115385f; + c = spacing + 0.024038462f; + *width = state->width; + *height = state->factor; + *x = state->x; + value = (state->y - ((a + b + c) * 0.5f)) + (spacing + 0.0072115385f); + *y = value; + value = value + *height * 0.5f; + *y = value; + *y = value + (*height + 0.0072115385f) * (f32)row; +} diff --git a/src/pal/game/004A1F78.c b/src/pal/game/004A1F78.c new file mode 100644 index 000000000..ac3692e09 --- /dev/null +++ b/src/pal/game/004A1F78.c @@ -0,0 +1,47 @@ +#include "common.h" + +typedef struct { + u8 unknown0[12]; + u8 dirty; + u8 unknownD[11]; +} Row; + +typedef s32 (*Validator)(s32); + +typedef struct { + u8 unknown0[0x34]; + Row *rows; + u8 unknown38[12]; + Validator validate; + u8 unknown48[8]; + s32 count; + s32 selected; + u32 flags; +} List; + +extern void func_004A2048(List *); + +void func_004A1F78(List *list, s32 index) +{ + s32 maximum; + + if (list->count != 0) { + maximum = list->count - 1; + index = index > maximum ? maximum : index; + index = index < 0 ? 0 : index; + if (index != list->selected) { + if (list->selected >= 0) { + list->rows[list->selected].dirty = 1; + } + list->selected = index; + if (index >= 0) { + list->rows[index].dirty = 1; + } + list->flags |= 2; + } + if (list->selected >= 0 && list->validate != 0 && + list->validate(list->selected) == 0) { + func_004A2048(list); + } + } +} diff --git a/src/pal/game/004A55F8.c b/src/pal/game/004A55F8.c new file mode 100644 index 000000000..5d7321ac8 --- /dev/null +++ b/src/pal/game/004A55F8.c @@ -0,0 +1,29 @@ +#include "common.h" +typedef struct { + s32 flags; + char pad[0xD4]; + f32 timer; + char rest[0x10]; +} State; +extern u8 D_00307C58[]; +extern s32 func_00506BB8(void), func_00506000(s32, s32), func_005063C0(s32, u32), func_00505A50(s32, u32); +void func_004A55F8(void) +{ + s32 offset = func_00506BB8() * 0xEC; + u8 *base = D_00307C58; + f32 *first = &((State *)base)->timer; + f32 *timer = (f32 *)((char *)first + offset); + *timer -= 0.05f; + if (*timer <= 0) { + func_00506000(0xE0007, 0); + func_00506000(0xE0008, 0); + ((State *)(offset + base))->flags &= ~4; + } else if (*timer < 1) { + u32 color = (u32)(s32)(*timer * 128.0f) << 24; + u32 shadow = (u32)(s32)(*timer * 64.0f) << 24; + func_005063C0(0xE0007, color | 0xD0D0D0); + func_00505A50(0xE0007, shadow); + func_005063C0(0xE0008, ((u32)(s32)(*timer * 128.0f) << 24) | 0x20F0F0); + func_00505A50(0xE0008, shadow); + } +} diff --git a/src/pal/game/004A66E8.c b/src/pal/game/004A66E8.c new file mode 100644 index 000000000..8778f5b0a --- /dev/null +++ b/src/pal/game/004A66E8.c @@ -0,0 +1,67 @@ +#include "common.h" + +typedef struct { + f32 targetX; + f32 x; + u8 unknown8[4]; + f32 targetY; + f32 y; + u8 unknown14[0xC]; + f32 target20; + f32 current24; + u8 visible; + u8 unknown29[3]; + f32 alpha; + u8 unknown30[8]; + s32 yTimer; + s32 xTimer; + u8 unknown40[4]; + s32 changed; + u8 tail[8]; +} State; + +extern State D_00308068[]; +extern s32 D_0021EE54; +extern s32 func_00506BB8(void); +extern f32 func_004760C0(f32 *, f32, f32, f32); +extern s32 func_00453CE8(s32 *); +extern void func_004A6888(void); + +void func_004A66E8(void) +{ + s32 changed = 0; + State *state = &D_00308068[func_00506BB8()]; + + if (func_004760C0(&state->alpha, (f32)state->visible, 0.0f, 0.05f) != 0.0f) { + changed = 1; + } + if (state->y != state->targetY) { + if (state->visible) { + state->y = state->targetY; + } else if (state->yTimer) { + func_00453CE8(&state->yTimer); + } else { + func_004760C0(&state->y, state->targetY, 0.1f, 0.3f); + } + changed = 1; + } else { + state->yTimer = 30; + } + if (state->x != state->targetX) { + if (!state->visible) { + state->x = state->targetX; + } else if (state->xTimer) { + func_00453CE8(&state->xTimer); + } else { + func_004760C0(&state->x, state->targetX, 0.1f, 0.3f); + } + changed = 1; + } else { + state->xTimer = 30; + } + if (D_0021EE54 != 1 && state->current24 != state->target20) { + state->current24 = state->target20; + } + func_004A6888(); + state->changed = changed; +} diff --git a/src/pal/game/004A9BF0.c b/src/pal/game/004A9BF0.c new file mode 100644 index 000000000..0842c18a1 --- /dev/null +++ b/src/pal/game/004A9BF0.c @@ -0,0 +1,58 @@ +#include "common.h" + +typedef struct { + u8 unknown0[0x70]; + s32 cost; + s32 amount; + s32 displayedAmount; + u8 tail[0x3C]; +} State; +typedef struct { + u8 unknown0[0x26E4]; + void *inventory; +} Hero; +typedef struct { + u8 unknown0[0x20]; + s8 suppressCost; +} Mode; + +extern State D_00308208[]; +extern s32 D_0021EE54; +extern Mode *D_0021E078; +extern s32 func_00506BB8(void); +extern s32 func_004A9450(void); +extern Hero *func_00511CC0(s32); +extern s32 func_00549580(s32); +extern s32 func_00549398(void *, s32); +extern s32 func_00549368(void *, s32); +extern void func_004A94E8(s32, s32); +extern void func_004A9718(s32, s32); + +void func_004A9BF0(void) +{ + s32 index = func_00506BB8(); + s32 item = func_004A9450(); + State *state = &D_00308208[index]; + Hero *hero = func_00511CC0(index); + s32 cost; + s32 amount; + + if (func_00549580(item)) { + cost = 0; + } else { + cost = func_00549398(hero->inventory, item); + } + if (D_0021EE54 == 1 && D_0021E078->suppressCost) { + cost = 0; + } + if (state->cost != cost) { + state->cost = cost; + func_004A94E8(index, cost); + } + amount = func_00549368(hero->inventory, item); + state->amount = amount; + if (state->displayedAmount != amount) { + state->displayedAmount = amount; + func_004A9718(index, amount); + } +} diff --git a/src/pal/game/004AAD18.c b/src/pal/game/004AAD18.c new file mode 100644 index 000000000..36f504003 --- /dev/null +++ b/src/pal/game/004AAD18.c @@ -0,0 +1,49 @@ +#include "common.h" + +typedef struct { + u8 unknown0[0x10]; + s32 pending; + u8 unknown14[0x12C]; + f32 scale; + u8 unknown144[8]; + s32 mask; + u8 unknown150[8]; + s32 selected; + s32 value15C; + s32 value160; + s32 value164; + s32 value168; + u8 tail[4]; +} State; + +typedef struct { + f32 scale; + f32 unknown4; +} Scale; + +extern State D_00308C80[]; +extern const Scale D_003D1A70[]; +extern s32 func_00506BB8(void); +extern void func_004AC740(s32); +extern void func_004AD8E8(void); +extern s32 func_00498468(s32); +extern void func_00498560(s32, s32); +extern void func_00497780(void *, s32); + +void func_004AAD18(void) +{ + s32 index = func_00506BB8(); + + func_004AC740(1); + func_004AD8E8(); + D_00308C80[index].pending = 0; + D_00308C80[index].selected = -1; + D_00308C80[index].value164 = 0; + D_00308C80[index].value168 = 0; + D_00308C80[index].value15C = 0; + D_00308C80[index].value160 = 0; + D_00308C80[index].scale = D_003D1A70[func_00498468(index)].scale; + D_00308C80[index].mask = 0x3F; + func_00498560(index, 0x18); + func_00497780(&D_00308C80[index], 0); +} diff --git a/src/pal/game/004AE058.c b/src/pal/game/004AE058.c new file mode 100644 index 000000000..eadae01e6 --- /dev/null +++ b/src/pal/game/004AE058.c @@ -0,0 +1,47 @@ +#include "common.h" + +typedef struct { + s16 id; + u8 unknown2[0x12]; + u32 value; + u8 tail[4]; +} Record; + +typedef struct { + u8 unknown0[0x158]; + s32 selected; + u8 tail[0x14]; +} State; + +typedef struct { + s32 count; +} Count; + +extern u8 D_00308C60[]; +extern State D_00308C80[]; +extern Record D_00308560[64]; +extern Count *D_0021DE2C; +extern void func_00453E20(void *, s32, u32); +extern void *func_004A37A8(s32); +extern s32 func_004A3AF0(void *, s32, s32); +extern void *func_00497120(void); + +void func_004AE058(void) +{ + Record *record; + s32 i; + + func_00453E20(D_00308C60, 0, 0x20); + func_00453E20(D_00308C80, 0, 0x5C0); + record = D_00308560; + do { + record->id = -1; + record->value = 0; + record++; + } while ((s32)record < (s32)(D_00308560 + 64)); + for (i = 0; i < D_0021DE2C->count; i++) { + D_00308C80[i].selected = -1; + } + func_004A3AF0(func_004A37A8(0), 0, 0); + func_00453E20(func_00497120(), 0, 0x20); +} diff --git a/src/pal/game/004AE7A8.c b/src/pal/game/004AE7A8.c new file mode 100644 index 000000000..eeb3aabce --- /dev/null +++ b/src/pal/game/004AE7A8.c @@ -0,0 +1,39 @@ +#include "common.h" + +typedef struct { + s32 state; + f32 fade; + u8 unknown8[0x48]; +} State; + +extern State D_003092A0[]; +extern s32 func_00506BB8(void); +extern s32 func_0049B418(f32 *, f32); +extern void func_004AE890(void); +extern void func_004AE918(void); +extern void func_004AEAA0(void); +extern void func_00502520(void *); + +void func_004AE7A8(void *object) +{ + State *state = &D_003092A0[func_00506BB8()]; + + switch (state->state) { + case 0: + if (!(u8)func_0049B418(&state->fade, 1.0f)) { + state->state = 1; + } + func_004AE890(); + break; + case 1: + break; + case 2: + if (!(u8)func_0049B418(&state->fade, 0.0f)) { + func_00502520(object); + } + func_004AE890(); + break; + } + func_004AE918(); + func_004AEAA0(); +} diff --git a/src/pal/game/004B64A0.c b/src/pal/game/004B64A0.c new file mode 100644 index 000000000..26d7620c5 --- /dev/null +++ b/src/pal/game/004B64A0.c @@ -0,0 +1,27 @@ +#include "common.h" + +extern u8 D_001CE3E8[]; +extern s32 D_00221868; +extern s32 D_0022186C; +extern u8 D_00171E6B[]; +extern void func_004B66B0(void); +extern s32 func_0049A9D8(const void *, s32); +extern s32 func_004A2798(s32 *, s32); +extern s32 func_00506590(s32, s32); +extern s32 func_005071B8(s32, s32); +extern s32 func_005053D0(s32, f32); +extern s32 func_00505488(s32, f32); + +void func_004B64A0(void) +{ + func_004B66B0(); + D_0022186C = func_0049A9D8(D_001CE3E8, -1); + func_00506590(func_004A2798(&D_00221868, 0x15), 1); + func_005071B8(func_004A2798(&D_00221868, 0x15), D_0022186C); + func_005053D0(func_004A2798(&D_00221868, 1), -0.5f); + func_005053D0(func_004A2798(&D_00221868, 0xB), 1.5f); + if (D_00171E6B[0]) { + func_00505488(func_004A2798(&D_00221868, 1), 0.405f); + func_00505488(func_004A2798(&D_00221868, 0xB), 0.61f); + } +} diff --git a/src/pal/game/004B7778.c b/src/pal/game/004B7778.c new file mode 100644 index 000000000..f1e598060 --- /dev/null +++ b/src/pal/game/004B7778.c @@ -0,0 +1,28 @@ +#include "common.h" + +typedef s32 (*Callback)(s32); + +typedef struct { + u8 unknown0[0x10]; + s32 value; + u8 tail[0x1E4]; +} State; +extern State D_003099F0[]; +extern void func_004A0F28(s32, s32); +extern void func_004B6CE8(s32); +extern char *func_0045E850(s32); +extern void func_004B6D08(s32, const char *, Callback, s32); +extern void func_004B6D60(s32, Callback, const char *); +extern s32 func_004B8128(s32); +extern s32 func_004B8230(s32); +extern s32 func_004B7B98(s32); + +void func_004B7778(s32 index) +{ + func_004A0F28(index, D_003099F0[index].value); + func_004B6CE8(index); + func_004B6D08(index, func_0045E850(0x1CF), func_004B8128, 1); + func_004B6D08(index, func_0045E850(0x2387), func_004B8230, 1); + func_004B6D08(index, func_0045E850(0x362D), func_004B7B98, 1); + func_004B6D60(index, func_004B7B98, func_0045E850(0x106)); +} diff --git a/src/pal/game/004BA498.c b/src/pal/game/004BA498.c new file mode 100644 index 000000000..7b28b0ad9 --- /dev/null +++ b/src/pal/game/004BA498.c @@ -0,0 +1,36 @@ +#include "common.h" + +typedef struct { + f32 x; + f32 y; +} Position; +extern const Position D_003D1E70[]; +extern s32 D_002218B0; +extern s32 func_004A2798(s32 *, s32); +extern s32 func_004A1720(s32); +extern s32 func_005052D0(s32, f32, f32); +extern s32 func_00506978(s32, f32, f32); +extern s32 func_005060D8(s32, s32); +extern s32 func_00506000(s32, s32); +extern s32 func_00505F00(s32, s32, s32); +extern s32 func_005063C0(s32, u32); +extern s32 func_00506E68(s32, s32); + +void func_004BA498(void) +{ + s32 i; + const Position *position = D_003D1E70; + + for (i = 0; i < 13; i++, position++) { + s32 handle = func_004A2798(&D_002218B0, i + 0xB4); + + func_004A1720(handle); + func_005052D0(handle, position->x, position->y); + func_00506978(handle, 0.8f, 0.8f); + func_005060D8(handle, 1); + func_00506000(handle, 1); + func_00505F00(handle, 1 + (i <= 4), 3); + func_005063C0(handle, 0x80D0D0D0); + func_00506E68(D_002218B0, handle); + } +} diff --git a/src/pal/game/004C32B8.c b/src/pal/game/004C32B8.c new file mode 100644 index 000000000..bcba50148 --- /dev/null +++ b/src/pal/game/004C32B8.c @@ -0,0 +1,33 @@ +#include "common.h" +typedef struct { + s32 a, b, flags, selection; + char pad[0x60]; + s32 handle; +} State; +typedef struct { + char pad[0x29]; + u8 label; +} Info; +extern State D_0030B7F8[]; +extern char D_001CDA00[]; +extern s32 D_00221980; +extern s32 func_00506BB8(void), func_00498518(s32), func_0049A9D8(void *, s32), func_004A2798(s32 *, s32), func_005071B8(s32, s32); +extern void *func_00511CC0(s32); +extern Info *func_0054A290(s32, s32); +extern void func_0049AA18(s32); +void func_004C32B8(void) +{ + s32 index = func_00506BB8(); + State *p; + char *text; + func_00511CC0(index); + p = D_0030B7F8 + index; + text = D_001CDA00 + func_0054A290(func_00498518(p->selection), 0)->label * 8; + if (p->handle) { + func_0049AA18(p->handle); + p->handle = 0; + } + p->handle = func_0049A9D8(text, -1); + func_005071B8(func_004A2798(&D_00221980, 0x1D), p->handle); + p->flags &= ~4; +} diff --git a/src/pal/game/004C4D20.c b/src/pal/game/004C4D20.c new file mode 100644 index 000000000..eafe8356c --- /dev/null +++ b/src/pal/game/004C4D20.c @@ -0,0 +1,36 @@ +#include "common.h" +typedef struct { + s32 mode, a, flags, b, selection; + char rest[0x60]; +} State; +extern State D_0030B7F8[]; +extern s32 D_00221988; +extern s32 func_00506BB8(void), func_004A2798(s32 *, s32), func_005062D0(s32, const char *); +extern const char *func_0045E850(s32); +extern void func_0049D060(s32, s32, s32), func_0049CF80(s32, s32), func_004C47B0(void), func_004C41F8(void), func_004985F0(s32); +void func_004C4D20(void) +{ + s32 index = func_00506BB8(); + State *p = D_0030B7F8 + index; + func_0049D060(index, 0, 1); + func_0049D060(index, 1, 1); + func_0049CF80(index, 2); + func_0049CF80(index, 3); + switch (p->selection) { + case 1: { + s32 handle; + func_004C47B0(); + handle = func_004A2798(&D_00221988, 0x51); + func_005062D0(handle, func_0045E850(0x304F)); + } break; + case 2: { + s32 handle; + func_004C41F8(); + handle = func_004A2798(&D_00221988, 0x50); + func_005062D0(handle, func_0045E850(0x304E)); + } break; + } + func_004985F0(8); + p->mode = 1; + p->flags |= 0x80; +} diff --git a/src/pal/game/004C7F90.c b/src/pal/game/004C7F90.c new file mode 100644 index 000000000..891931219 --- /dev/null +++ b/src/pal/game/004C7F90.c @@ -0,0 +1,35 @@ +#include "common.h" + +typedef struct { + u8 prefix[0x50]; + s32 count, index; +} List; +typedef struct { + u8 prefix[0x10]; + u32 flags; + u8 gap[0xAA0]; + List list; + u8 tail[0x24]; +} State; +extern State D_0030B9D8[]; +extern s32 func_00506BB8(void); +extern void func_004A2090(List *); +extern void func_004A2048(List *); +extern void func_004985F0(s32); +void func_004C7F90(s32 direction) +{ + s32 index = func_00506BB8(); + State *state = D_0030B9D8 + index; + List *list = &state->list; + if (list->count >= 2) { + if (direction) + func_004A2090(list); + else + func_004A2048(list); + if (state->list.count >= 2) + func_004985F0(10); + else + func_004985F0(4); + D_0030B9D8[index].flags |= 3; + } +} diff --git a/src/pal/game/004C9EB8.c b/src/pal/game/004C9EB8.c new file mode 100644 index 000000000..52e087aca --- /dev/null +++ b/src/pal/game/004C9EB8.c @@ -0,0 +1,40 @@ +#include "common.h" +typedef struct { + s32 kind, other, count; +} Data; +typedef struct { + s32 a, b; + Data *data; + char tail[12]; +} Item; +typedef struct { + char pad[0x34]; + Item *items; + char gap[0x18]; + s32 count, index; +} List; +extern List D_0030E494; +extern s32 func_004E7EC8(Data *), func_00506BB8(void); +extern const char *func_0045E850(s32); +extern void func_004C9DD8(s32), func_004985F0(s32), func_0049F4C8(s32, const char *, void (*)(s32), s32, s32, s32, s32, f32); +static inline Item *selected(List *l) +{ + if (l->index < 0) + return 0; + return l->items + l->index; +} +void func_004C9EB8(void) +{ + if (D_0030E494.count) { + Data *d = selected(&D_0030E494)->data; + if (func_004E7EC8(d)) { + if (d->count <= 0 || d->kind == 1) + func_004C9DD8(1); + else { + s32 index = func_00506BB8(); + func_0049F4C8(index, func_0045E850(0x8D0), func_004C9DD8, 3, 0, 0, 0, -1.0f); + } + } else + func_004985F0(4); + } +} diff --git a/src/pal/game/004CD188.c b/src/pal/game/004CD188.c new file mode 100644 index 000000000..297ee4398 --- /dev/null +++ b/src/pal/game/004CD188.c @@ -0,0 +1,40 @@ +#include "common.h" +typedef struct { + s32 mode, selection, flags; + char rest[0x58]; +} State; +extern State D_0030EAA0[]; +extern s32 func_00506BB8(void), func_004981D8(s32 *, s32, s32 (*)(s32)), func_00498280(s32 *, s32, s32 (*)(s32)), func_004CCF58(s32); +extern void func_004CCFA0(s32), func_004CCFE8(s32), func_004985F0(s32); +void func_004CD188(s32 mode) +{ + State *p = D_0030EAA0 + func_00506BB8(); + if (p->selection >= 0) { + s32 found; + func_004CCFA0(p->selection); + switch (mode) { + case 0: + p->selection--; + found = func_004981D8(&p->selection, 12, func_004CCF58); + break; + case 1: + p->selection++; + found = func_00498280(&p->selection, 12, func_004CCF58); + break; + case 3: + found = func_00498280(&p->selection, 12, func_004CCF58); + break; + case 2: + found = func_004981D8(&p->selection, 12, func_004CCF58); + break; + default: + found = 0; + break; + } + if (found) { + func_004CCFE8(p->selection); + func_004985F0(15); + p->flags |= 1; + } + } +} diff --git a/src/pal/game/004D07F0.c b/src/pal/game/004D07F0.c new file mode 100644 index 000000000..f304dc2f5 --- /dev/null +++ b/src/pal/game/004D07F0.c @@ -0,0 +1,45 @@ +#include "common.h" +typedef struct { + char pad[0x30]; + s32 label; +} Data; +typedef struct { + s32 a, b; + Data *data; + char tail[12]; +} Item; +typedef struct { + char pad[0x34]; + Item *items; + char gap[0x18]; + s32 count, index; +} List; +typedef struct { + s32 a, b, flags; + char pad[0x968]; + List list; + char tail[0x14]; +} State; +extern State D_00316D00[]; +extern s32 D_00221A80; +extern s32 func_00506BB8(void), func_004A2798(s32 *, s32), func_005062D0(s32, const char *), func_00506000(s32, s32); +extern const char *func_0045E850(s32); +static inline Item *selected(List *l) +{ + if (l->index < 0) + return 0; + return l->items + l->index; +} +void func_004D07F0(void) +{ + State *p = D_00316D00 + func_00506BB8(); + List *l = &p->list; + if (l->count > 0) { + Data *d = selected(l)->data; + s32 handle = func_004A2798(&D_00221A80, 0xD); + func_005062D0(handle, func_0045E850(d->label)); + func_00506000(func_004A2798(&D_00221A80, 0xD), 1); + } else + func_00506000(func_004A2798(&D_00221A80, 0xD), 0); + p->flags &= ~2; +} diff --git a/src/pal/game/004D2928.c b/src/pal/game/004D2928.c new file mode 100644 index 000000000..59f9aeeff --- /dev/null +++ b/src/pal/game/004D2928.c @@ -0,0 +1,31 @@ +#include "common.h" +typedef struct { + s32 mode, a, flags; + char gap[0xE4]; + char list[0x6C]; +} State; +extern State D_0031B050[]; +extern s32 func_00506BB8(void), func_004A2468(void *); +extern void func_004D2D48(void), func_004D2AD0(void), func_004D2B10(void), func_004D2C08(void), func_00502520(void *); +void func_004D2928(void *descriptor) +{ + State *p = D_0031B050 + func_00506BB8(); + switch (p->mode) { + case 1: + p->mode = 0; + break; + case 2: + func_00502520(descriptor); + break; + case 0: + func_004D2D48(); + break; + } + if (p->flags & 1) + func_004D2AD0(); + if (p->flags & 2) + func_004D2B10(); + func_004A2468(p->list); + if (p->flags & 4) + func_004D2C08(); +} diff --git a/src/pal/game/004D2E08.c b/src/pal/game/004D2E08.c new file mode 100644 index 000000000..1c2c60b61 --- /dev/null +++ b/src/pal/game/004D2E08.c @@ -0,0 +1,31 @@ +#include "common.h" + +extern s32 D_00221AC0; +extern s32 func_00506BB8(void); +extern s32 func_005026A8(s32 *, s32, s32); +extern s32 func_00506C08(s32, s32); +extern s32 func_004984A0(s32); +extern void func_005027A0(s32 *, s32, f32); +extern s32 func_004A2798(s32 *, s32); +extern char *func_0045E850(s32); +extern s32 func_005062D0(s32, const char *); +extern s32 func_00507270(s32, s32, s32, s32, s32, s32, s32, s32, s32); +extern s32 func_005060D8(s32, s32); +extern s32 func_005074A0(s32, s32, s32, f32); + +void func_004D2E08(void) +{ + s32 index = func_00506BB8(); + s32 handle; + + func_005026A8(&D_00221AC0, 0x33, -1); + func_00506C08(0xF, D_00221AC0); + func_005027A0(&D_00221AC0, -1, (f32)func_004984A0(index)); + handle = func_004A2798(&D_00221AC0, 0xE); + func_005062D0(handle, func_0045E850(0x2350)); + handle = func_004A2798(&D_00221AC0, 0xF); + func_005062D0(handle, func_0045E850(0x2387)); + func_00507270(func_004A2798(&D_00221AC0, 0x10), 1, 1, 1, 0, 0, 0, 0, 0); + func_005060D8(func_004A2798(&D_00221AC0, 0x10), 1); + func_005074A0(func_004A2798(&D_00221AC0, 0x10), 0xB4, 10, 0.00031f); +} diff --git a/src/pal/game/004DA960.c b/src/pal/game/004DA960.c new file mode 100644 index 000000000..34644a146 --- /dev/null +++ b/src/pal/game/004DA960.c @@ -0,0 +1,44 @@ +#include "common.h" +typedef struct { + s32 a, b; + void *data; + char tail[12]; +} Item; +typedef struct { + char pad[0x34]; + Item *items; + char gap[0x18]; + s32 count, index; +} List; +typedef struct { + s32 a, b, flags; + char pad[0xA8]; + List list; + char gap[0x14]; + s32 handle; +} State; +extern State D_00321650[]; +extern char D_001CE230[]; +extern s32 D_00221C68; +extern s32 func_00506BB8(void), func_0049A9D8(void *, s32), func_004A2798(s32 *, s32), func_005071B8(s32, s32); +extern void func_0049AA18(s32); +static inline Item *selected(List *l) +{ + if (l->index < 0) + return 0; + return l->items + l->index; +} +void func_004DA960(void) +{ + State *p = D_00321650 + func_00506BB8(); + List *l = &p->list; + if (l->count > 0) { + if (p->handle) { + func_0049AA18(p->handle); + p->handle = 0; + } + p->handle = func_0049A9D8(D_001CE230 + *(s32 *)selected(l)->data * 8, -1); + func_005071B8(func_004A2798(&D_00221C68, 4), p->handle); + } + p->flags &= ~2; +} diff --git a/src/pal/game/004DCAC8.c b/src/pal/game/004DCAC8.c new file mode 100644 index 000000000..bd63a755f --- /dev/null +++ b/src/pal/game/004DCAC8.c @@ -0,0 +1,32 @@ +#include "common.h" +typedef struct { + s32 a, b; + void *data; + char tail[12]; +} Item; +typedef struct { + s32 mode, flags; + char gap[4]; + Item items[9]; + char list[0x7C]; + f32 timer; + char tail[4]; +} State; +extern State D_00322FC8[]; +extern s32 D_00221C88; +extern s32 func_00506BB8(void), func_004A2798(s32 *, s32); +extern void func_004DCDC0(void), func_004A1E78(void *, Item *, s32, void (*)(void *, Item *, s32), s32, s32), func_004A1EA8(void *), func_0049CF80(s32, s32), func_0049DEA8(s32, s32, s32), func_0049DFB8(s32, s32); +void func_004DCAC8(void) +{ + s32 index = func_00506BB8(); + State *p = D_00322FC8 + index; + func_004DCDC0(); + p->mode = 0; + func_004A1E78(p->list, p->items, 9, 0, 0, 0); + p->timer = 0.024543693f; + func_0049CF80(index, 0); + func_0049DEA8(index, 0, func_004A2798(&D_00221C88, 0x12)); + func_0049DFB8(index, 1); + func_004A1EA8(p->list); + p->flags = 7; +} diff --git a/src/pal/game/004DCBE8.c b/src/pal/game/004DCBE8.c new file mode 100644 index 000000000..0af8720fc --- /dev/null +++ b/src/pal/game/004DCBE8.c @@ -0,0 +1,29 @@ +#include "common.h" +typedef struct { + s32 mode, flags; + char rest[0x160]; +} State; +extern State D_00322FC8[]; +extern s32 func_00506BB8(void); +extern void func_004DCCB8(void), func_004DD160(void), func_004DD558(void), func_004DDA40(void), func_004DD810(void), func_00502520(void *); +void func_004DCBE8(void *descriptor) +{ + State *p = D_00322FC8 + func_00506BB8(); + switch (p->mode) { + case 0: + p->mode = 2; + break; + case 2: + func_004DCCB8(); + break; + case 1: + func_00502520(descriptor); + break; + } + if (p->flags & 1) + func_004DD160(); + if (p->flags & 2) + func_004DD558(); + func_004DDA40(); + func_004DD810(); +} diff --git a/src/pal/game/004DFA40.c b/src/pal/game/004DFA40.c new file mode 100644 index 000000000..cdc8e9682 --- /dev/null +++ b/src/pal/game/004DFA40.c @@ -0,0 +1,31 @@ +#include "common.h" +typedef struct { + u8 active; + u8 pad[3]; + u32 color, unused, base; + u8 tail[16]; +} Row; +typedef struct { + u8 pad[8]; + s16 count; + u8 gap[0x12]; + Row *rows; +} Manager; +extern Manager *D_00221DF0; +extern s32 func_001633D8(void); +void func_004DFA40(void) +{ + s32 i; + for (i = 0; i < D_00221DF0->count; i++) { + Row *p = D_00221DF0->rows + i; + if (p->active) { + s32 random = func_001633D8() >> 16; + { + s32 red = ((random & 0x1F00) << 10) - 0x202020; + s32 green = (random & 0x1F0) << 6; + s32 blue = (random & 0x1F) << 2; + p->color = p->base + red + green + blue; + } + } + } +} diff --git a/src/pal/game/004E3C48.c b/src/pal/game/004E3C48.c new file mode 100644 index 000000000..2ca5711b1 --- /dev/null +++ b/src/pal/game/004E3C48.c @@ -0,0 +1,34 @@ +#include "common.h" + +/* Reference: OpenRAC/OpenRAC@73f725bf54bb1bf6d8b9bb5b1511ed00d551fbde + * OpenRAC/games/rac3/ntsc/src/frontbin/3C9888.c func_003C99D0. + * Independently reconstructed from RAC4 PAL retail. */ + +extern u32 *D_00221F20, *D_00221E2C; +extern s32 D_0021DAB0, D_00221E34; +extern void func_004E4B68(void), func_004E8AB0(void); +extern s32 func_004E4CD0(s32); +void func_004E3C48(void) +{ + u32 *saved = D_00221F20; + s32 size; + D_00221F20 += 4; + D_00221E2C[0] = 0x20000000; + D_00221E2C[1] = (u32)D_00221F20; + D_00221E2C[2] = 0; + D_00221E2C[3] = 0; + func_004E4B68(); + size = func_004E4CD0(D_0021DAB0); + func_004E8AB0(); + if (D_00221E34 < size) + D_00221E34 = size; + D_00221F20[0] = 0x20000000; + D_00221F20[1] = (u32)(D_00221E2C + 4); + D_00221F20[2] = 0; + D_00221F20[3] = 0; + D_00221F20 += 4; + saved[0] = 0x20000000; + saved[1] = (u32)D_00221F20; + saved[2] = 0; + saved[3] = 0; +} diff --git a/src/pal/game/004F16C8.c b/src/pal/game/004F16C8.c new file mode 100644 index 000000000..dec16665c --- /dev/null +++ b/src/pal/game/004F16C8.c @@ -0,0 +1,42 @@ +#include "common.h" + +/* Reference: OpenRAC/OpenRAC@73f725bf54bb1bf6d8b9bb5b1511ed00d551fbde + * OpenRAC/games/rac3/ntsc/src/frontbin/3ABA48.c func_003ABA48. + * Independently reconstructed from RAC4 PAL retail. */ +typedef struct Stream Stream; +typedef struct { + u8 prefix[8]; + u8 *source; + s32 size; + u64 first, second; +} Block; +extern Stream *D_00221FD4; +extern char D_003D3210[]; +extern void func_004F2C78(Stream *, u8 **, s32 *, u8 **, s32 *); +extern s32 func_004F18B0(u8 *, s32, u8 *, s32, const u8 *, s32, const u8 *, s32); +extern s32 func_004F2D20(Stream *, u64, u64, const u8 *, s32); +extern void func_004F0708(const char *); +extern void func_004F2C98(Stream *, s32); +s32 func_004F16C8(s32 unused, Block *block, const u8 *buffer) +{ + u8 *first, *second; + s32 firstSize, secondSize; + s32 offset = *(const s32 *)(buffer + 0x50008); + const u8 *source = block->source; + s32 size = block->size; + s32 count = (s32)((u32)buffer + offset - (u32)source); + s32 remaining; + s32 copied; + if (size < count) + count = size; + remaining = size - count; + func_004F2C78(D_00221FD4, &first, &firstSize, &second, &secondSize); + copied = func_004F18B0((u8 *)(((u32)first & 0x0FFFFFFF) | 0x20000000), firstSize, + (u8 *)(((u32)second & 0x0FFFFFFF) | 0x20000000), secondSize, source, count, buffer, remaining); + if (copied > 0) { + if (!func_004F2D20(D_00221FD4, block->first, block->second, first, copied)) + func_004F0708(D_003D3210); + } + func_004F2C98(D_00221FD4, copied); + return copied > 0; +} diff --git a/src/pal/game/004F2D88.c b/src/pal/game/004F2D88.c new file mode 100644 index 000000000..9b11f775d --- /dev/null +++ b/src/pal/game/004F2D88.c @@ -0,0 +1,38 @@ +#include "common.h" + +/* Reference: OpenRAC/OpenRAC@73f725bf54bb1bf6d8b9bb5b1511ed00d551fbde + * OpenRAC/games/rac3/ntsc/src/frontbin/3ABA48.c func_003AD108. + * Independently reconstructed from RAC4 PAL retail. */ +typedef struct Stream { + u8 prefix[0x48]; + u8 ring[0x60]; + s32 state; +} Stream; +typedef struct { + u8 bytes[4]; +} Command; +extern Command D_002209B8[]; +extern Stream *D_00221FD4; +extern void func_004F2C78(Stream *, u8 **, s32 *, u8 **, s32 *); +extern s32 func_004F31A0(u8 *, s32, u8 *, s32, const void *, s32, const void *, s32); +extern void func_004F2C98(Stream *, s32); +extern void func_004F2728(void *); +s32 func_004F2D88(Stream *stream) +{ + Command command = D_002209B8[0]; + u8 *first; + s32 firstSize; + u8 *second; + s32 secondSize; + s32 copied; + func_004F2C78(stream, &first, &firstSize, &second, &secondSize); + if (firstSize + secondSize < 4) + return 0; + copied = func_004F31A0((u8 *)(((u32)first & 0x0FFFFFFF) | 0x20000000), firstSize, + (u8 *)(((u32)second & 0x0FFFFFFF) | 0x20000000), secondSize, &command, 4, 0, 0); + func_004F2C98(D_00221FD4, copied); + func_004F2728(stream->ring); + if (stream->state == 0) + stream->state = 2; + return 1; +} diff --git a/src/pal/game/004FBB28.c b/src/pal/game/004FBB28.c new file mode 100644 index 000000000..cc093f800 --- /dev/null +++ b/src/pal/game/004FBB28.c @@ -0,0 +1,19 @@ +#include "common.h" +extern s32 D_0021DFB0; +extern u32 *D_00221F20; +extern u8 D_0020F480[]; +extern s32 D_00222070, D_00222080, D_0021DF78; +s32 D_00220A70 = 128; +s32 D_00220A5C = 0; +extern void func_004F97F8(s32, s32, s32, s32, s32, s32, u32, u32); +void func_004FBB28(void) +{ + D_00221F20[0] = (D_0021DFB0 >> 4) | 0x30000000; + D_00221F20[1] = (u32)D_0020F480; + D_00221F20[2] = D_00222070 | 0x03000000; + D_00221F20[3] = 0x02000000; + D_00222070 += D_00222080; + D_00221F20 += 4; + func_004F97F8(D_0021DF78, 256, 256, 1, 0, D_00220A70, 0x00808080, 0x00ffffff); + D_00220A5C = 0; +} diff --git a/src/pal/game/004FEB10.c b/src/pal/game/004FEB10.c new file mode 100644 index 000000000..d6dd24c93 --- /dev/null +++ b/src/pal/game/004FEB10.c @@ -0,0 +1,30 @@ +#include "common.h" +const char *func_004FEB10(const char *input, char *output, u32 capacity) +{ + s32 comment = 0; + s32 quoted = 0; + u32 i = 0; + capacity--; + while (i < capacity) { + u32 c = *(const u8 *)input; + if ((u8)c == '"' && ((const u8 *)input)[-1] != '\\') + quoted = !quoted; + if ((u8)c == '\n' && !quoted) + break; + if (!(u8)c) + break; + if ((u8)c == ';') + comment = !comment; + if ((u8)c != '\r' && !comment) + *output++ = c; + input++; + i++; + } + *output = 0; + { + const char *next = input + 1; + if (!*(const u8 *)input) + next = input; + return next; + } +} diff --git a/src/pal/game/00502BB8.c b/src/pal/game/00502BB8.c index 31fea30d4..600910b89 100644 --- a/src/pal/game/00502BB8.c +++ b/src/pal/game/00502BB8.c @@ -10,3 +10,63 @@ void func_00502BB8(float *a, float *b, float *c, float *d) { *c = p->c < *c ? p->c : *c; *d = p->d < *d ? p->d : *d; } + +/* These viewport helpers share the GP-resident view index. */ +typedef struct { + u8 prefix[0x14]; + s32 index; +} Context; +typedef struct { + s32 first; + Context *context; +} Manager; +typedef struct { + f32 x, y, z, w; +} Rect; +extern Manager D_00222138[]; +extern Manager *func_00502150(void); +extern s32 func_004490A8(s32); +extern void *func_00449060(s32); +extern f32 D_00220B7C, D_00220B80; +extern Rect D_00335EE0[]; + +extern void func_00502C10(f32, f32, f32, f32), func_00502C38(void); +extern s32 *D_0021DE2C; +extern u8 D_00171E6B[]; +void func_00502D28(void) +{ + Manager *m = D_00222138; + char *state; + char *p; + if (!m->context) + m = func_00502150(); + state = (char *)m->context; + p = func_00449060(func_004490A8(state ? *(s32 *)(state + 0x14) : -1)); + D_00220B9C = 0; + if (*D_0021DE2C && D_00171E6B[0]) + func_00502C10(0.0f, 0.0f, 1.0f, *(f32 *)(p + 0x14)); + else + func_00502C10(0.0f, 0.0f, *(f32 *)(p + 0x10), *(f32 *)(p + 0x14)); + func_00502C38(); +} + +void func_00502E90(s32 *x1, s32 *x2, s32 *y1, s32 *y2) +{ + Manager *manager; + Rect *view; + Rect *offset; + s32 index; + if (D_00222138[0].context) + manager = D_00222138; + else + manager = func_00502150(); + index = -1; + if (manager->context) + index = manager->context->index; + view = func_00449060(func_004490A8(index)); + offset = &D_00335EE0[D_00220B9C]; + *x1 = (s32)(offset->x * D_00220B7C + view->x * 512.0f); + *x2 = (s32)(offset->z * D_00220B7C + view->x * 512.0f); + *y1 = (s32)(offset->y * D_00220B80 + view->z * 448.0f); + *y2 = (s32)(offset->w * D_00220B80 + view->z * 448.0f); +} diff --git a/src/pal/game/00502D28.c b/src/pal/game/00502D28.c deleted file mode 100644 index 633e8137c..000000000 --- a/src/pal/game/00502D28.c +++ /dev/null @@ -1,29 +0,0 @@ -#include "common.h" -typedef struct { - s32 f0; - char *state; -} Manager; -extern Manager D_00222138[]; -extern Manager *func_00502150(void); -extern s32 func_004490A8(s32); -extern char *func_00449060(s32); -extern void func_00502C10(f32, f32, f32, f32), func_00502C38(void); -s32 D_00220B9C = 0; -extern s32 *D_0021DE2C; -extern u8 D_00171E6B[]; -void func_00502D28(void) -{ - Manager *m = D_00222138; - char *state; - char *p; - if (!m->state) - m = func_00502150(); - state = m->state; - p = func_00449060(func_004490A8(state ? *(s32 *)(state + 0x14) : -1)); - D_00220B9C = 0; - if (*D_0021DE2C && D_00171E6B[0]) - func_00502C10(0.0f, 0.0f, 1.0f, *(f32 *)(p + 0x14)); - else - func_00502C10(0.0f, 0.0f, *(f32 *)(p + 0x10), *(f32 *)(p + 0x14)); - func_00502C38(); -} diff --git a/src/pal/game/00506978.c b/src/pal/game/00506978.c new file mode 100644 index 000000000..70fc0121b --- /dev/null +++ b/src/pal/game/00506978.c @@ -0,0 +1,52 @@ +#include "common.h" +typedef struct Object Object; +typedef struct Vtable { + void *unused[3]; + u32 (*type)(Object *); + void *f10; + s32 (*supports)(Object *, u32); +} Vtable; +struct Object { + s32 f0, f4; + Vtable *vtable; +}; +typedef struct { + s32 f0; + void *context; +} Manager; +extern Manager D_00222138[]; +extern Manager *func_00502150(void); +extern Object *func_00501658(void *, s32); +extern u32 D_00220B50; +static inline Object *resolve(s32 handle) +{ + Manager *m; + Object *obj; + void *world; + if (D_00222138[0].context) + m = D_00222138; + else + m = func_00502150(); + world = 0; + if (m->context) + world = *(void **)((u32)m->context + ((u32) * (s32 *)((char *)m->context + 0x14) << 2)); + obj = func_00501658(world, handle); + if (obj && obj->vtable->supports(obj, D_00220B50)) + return obj; + return 0; +} +typedef s32 (*Callback)(Object *, f32, f32); +extern char D_00335FF0[]; +extern Callback func_00508A38(void *, u32); +s32 func_00506978(s32 handle, f32 a, f32 b) +{ + s32 result = 0; + Object *obj = resolve(handle); + if (obj) { + u32 type = obj->vtable->type(obj); + Callback callback = func_00508A38(D_00335FF0, type); + if (callback) + result = callback(obj, a, b); + } + return result; +} diff --git a/src/pal/game/0050B488.c b/src/pal/game/0050B488.c new file mode 100644 index 000000000..0b40a5521 --- /dev/null +++ b/src/pal/game/0050B488.c @@ -0,0 +1,40 @@ +#include "common.h" +typedef struct Object Object; +typedef struct { + f32 x, y, w, h, a, b; +} Rect; +typedef struct { + char pad[0x14]; + s32 (*supports)(Object *, u32); + char rest[0x10]; + void (*bounds)(Object *, Rect *, Rect *, s32); +} Vtable; +struct Object { + s32 f0, f4; + Vtable *v; +}; +extern u32 D_00220BF4; +static inline void init(Rect *p) +{ + p->x = 0; + p->y = 0; + p->w = 1; + p->h = 1; + p->a = 0; + p->b = 0; +} +s32 func_0050B488(Object *p, f32 *x, f32 *y, f32 *w, f32 *h) +{ + Rect input, output; + if (p->v->supports(p, D_00220BF4)) { + init(&input); + init(&output); + p->v->bounds(p, &input, &output, 1); + *x = output.x; + *y = output.y; + *w = output.w; + *h = output.h; + return 1; + } + return 0; +} diff --git a/src/pal/game/0050C250.c b/src/pal/game/0050C250.c new file mode 100644 index 000000000..236430c22 --- /dev/null +++ b/src/pal/game/0050C250.c @@ -0,0 +1,40 @@ +#include "common.h" +typedef struct Object Object; +typedef struct { + f32 x, y, w, h, a, b; +} Rect; +typedef struct { + char pad[0x14]; + s32 (*supports)(Object *, u32); + char rest[0x10]; + void (*bounds)(Object *, Rect *, Rect *, s32); +} Vtable; +struct Object { + s32 f0, f4; + Vtable *v; +}; +extern u32 D_00220C04; +static inline void init(Rect *p) +{ + p->x = 0; + p->y = 0; + p->w = 1; + p->h = 1; + p->a = 0; + p->b = 0; +} +s32 func_0050C250(Object *p, f32 *x, f32 *y, f32 *w, f32 *h) +{ + Rect input, output; + if (p->v->supports(p, D_00220C04)) { + init(&input); + init(&output); + p->v->bounds(p, &input, &output, 1); + *x = output.x; + *y = output.y; + *w = output.w; + *h = output.h; + return 1; + } + return 0; +} diff --git a/src/pal/game/0050D040.c b/src/pal/game/0050D040.c new file mode 100644 index 000000000..10a52ca9a --- /dev/null +++ b/src/pal/game/0050D040.c @@ -0,0 +1,36 @@ +#include "common.h" + +typedef struct Object Object; +typedef struct { + u8 prefix[0x14]; + s32 (*supports)(Object *, u32); +} Vtable; +typedef struct { + f32 x, y; +} Pair; +struct Object { + u32 first; + u8 flags; + u8 reserved[3]; + Vtable *vtable; + u32 options; + f32 scale; + Pair position, size, offset; + u32 spare, first_handle, second_handle; +}; +extern s32 func_00502650(Object *, const Object *); +s32 func_0050D040(Object *destination, Object *source) +{ + if (source->vtable->supports(source, 1)) { + func_00502650(destination, source); + destination->options = source->options; + destination->scale = source->scale; + destination->position = source->position; + destination->size = source->size; + destination->offset = source->offset; + destination->first_handle = source->first_handle; + destination->second_handle = source->second_handle; + return 1; + } + return 0; +} diff --git a/src/pal/game/0053EA90.c b/src/pal/game/0053EA90.c new file mode 100644 index 000000000..b3208ab22 --- /dev/null +++ b/src/pal/game/0053EA90.c @@ -0,0 +1,30 @@ +#include "common.h" +typedef struct { + s32 count; +} Manager; +typedef struct { + char pad[0x2EF8]; + s32 *state; + char gap[0x1C]; + s32 owner; +} Object; +extern Manager *D_0021DE2C, *D_0021DE30; +extern Object *func_00511CC0(s32), *func_00511CE8(s32); +void func_0053EA90(s32 owner, s32 id) +{ + s32 i; + for (i = 0; i < D_0021DE2C->count; i++) { + Object *p = func_00511CC0(i); + if (p && p->owner == owner && p->state) { + if (*p->state == id) + p->owner = 0; + } + } + for (i = 0; i < D_0021DE30->count; i++) { + Object *p = func_00511CE8(i); + if (p && p->owner == owner && p->state) { + if (*p->state == id) + p->owner = 0; + } + } +} diff --git a/src/pal/game/0054B628.c b/src/pal/game/0054B628.c new file mode 100644 index 000000000..9f60fb419 --- /dev/null +++ b/src/pal/game/0054B628.c @@ -0,0 +1,23 @@ +#include "common.h" + +typedef struct { + u8 unknown0[0xD]; + u8 allowed[10]; + u8 unknown17[0x21]; +} Definition; + +extern const Definition *func_0054B050(s32); + +s32 func_0054B628(s32 item, s32 mode) +{ + Definition definition; + s32 i; + + definition = *func_0054B050(mode); + for (i = 0; i < 10; i++) { + if (definition.allowed[i] == item) { + return 1; + } + } + return 0; +}