D92: two truncated pointers on the chr/AI spawn path

(a) chrAllocate's 5th param was declared s32 but callers pass
ailistFindById()'s AIRecord* -- the 64-bit pointer was truncated before
reaching init_GUARDdata_with_set_values, so chr->ailist held a bogus
address and ai() faulted dereferencing (AiListp + Offset)->cmd on the
first AI tick. Param widened to AIListRecord* under PORT.

(b) Model.unka0 is a 32-bit field that on N64 holds a function pointer
(always sub_GAME_7F01FC10). chr.c stored (s32)sub_GAME_7F01FC10 into it
and model.c subcalcpos called it back -- truncated jump target on PC.
Widening the field would shift the rest of Model, so under PORT the
setter stores a flag and subcalcpos calls sub_GAME_7F01FC10 directly.

BUNKER1 now loads and ticks through to the first render, where it hits
D85 (room GDL/texture decode: 'Bad size for RGBA texture').
This commit is contained in:
James Dansereau committed 2026-08-28 12:38:11 -04:00
1 parent b2a77d53ec
commit d2177db3a5
3 files changed
+27

No files matched your search

+9
View File
@@ -1615,7 +1615,11 @@ PropRecord *init_GUARDdata_with_set_values(PropRecord *arg0, Model *arg1, struct
arg0->pos.f[2] = arg2->f[2];
arg0->stan = arg4;
#ifdef PORT
sub_GAME_7F06FF5C(arg1, 1); /* D92: flag only; model.c subcalcpos calls sub_GAME_7F01FC10 directly */
#else
sub_GAME_7F06FF5C(arg1, (s32) sub_GAME_7F01FC10);
#endif
arg1->unk00 = 0xA;
arg1->chr = var_s0;
@@ -1726,7 +1730,12 @@ PropRecord *init_GUARDdata_with_set_values(PropRecord *arg0, Model *arg1, struct
/**
* Address 0x7F0203B8.
*/
#ifdef PORT
/* D92: see chr.h -- arg4 must stay a pointer or the ailist is truncated. */
PropRecord * chrAllocate( Model * arg0, coord3d * arg1, f32 arg2, StandTile * arg3, struct AIListRecord *arg4)
#else
PropRecord * chrAllocate( Model * arg0, coord3d * arg1, f32 arg2, StandTile * arg3, s32 arg4)
#endif
{
PropRecord * ret;
s32 phi_a0;
+6
View File
@@ -268,7 +268,13 @@ void chrSetMoving(ChrRecord *guard,s32 param_2);
f32 getAnimationRate(void);
void setAnimationRate(f32);
PropRecord *init_GUARDdata_with_set_values(PropRecord *, Model *, coord3d *, f32 arg2, StandTile * arg3, struct AIListRecord *arg4);
#ifdef PORT
/* D92: arg4 is an AIListRecord* (ailistFindById's return); declaring it s32
* truncates the 64-bit pointer on PC. */
PropRecord *chrAllocate(struct Model * arg0, coord3d * arg1, f32 arg2, StandTile * arg3, struct AIListRecord *arg4);
#else
PropRecord *chrAllocate(struct Model * arg0, coord3d * arg1, f32 arg2, StandTile * arg3, s32 arg4);
#endif
void chrSetHiddenToRandom(ChrRecord *arg0);
void chrRemoved7F022E1C(f32 arg0);
void chrDecrementAnimationTablePointerCount(void);
+12
View File
@@ -1187,10 +1187,22 @@ void sub_GAME_7F06D490(Model *model, ModelNode *modelNode)
sp2c.y = sp38.y;
sp2c.z = sp38.z;
#ifdef PORT
/* D92: `unka0` is a 32-bit Model field that on N64 holds a function
* pointer -- always sub_GAME_7F01FC10 (the only value chr.c ever hands
* the setter). Widening the field would shift the rest of Model, so on
* PC the setter stores a nonzero flag and the single indirect call is
* made directly here. */
if (model->unka0 && !sub_GAME_7F01FC10(model, &rw->Header.pos, &sp2c, &rw->Header.ground))
{
return;
}
#else
if (model->unka0 && !((s32 (*)(Model *, coord3d *, coord3d *, f32 *)) model->unka0)(model, &rw->Header.pos, &sp2c, &rw->Header.ground))
{
return;
}
#endif
sp38.x = sp2c.x - sp38.x;
sp38.z = sp2c.z - sp38.z;