Files
goldeneye-pc-port/src/game/prop.c
T
James Dansereau daa2522511 D489-D502: settings persistence, collision, A/B harnesses, D441 census
F10 pad slider persistence (D489), glass collision hull (D490), A/B input
harnesses (1964 virtual pad, GE_INPUTSCRIPT, live one-pad launcher), adjacent
global struct reads (D491), vibration percent, D441 complete pointer-width
census with high-arena tier-1 build, fix batches 1-5 and an ABI warning
ratchet, playtest verification of D493-D502.

Refs: D489 D490 D491 D492-D502 D441
2026-10-06 18:35:42 -04:00

2162 lines
78 KiB
C

#include <ultra64.h>
#ifdef PORT
#include <stdio.h>
#include <stdlib.h>
#endif
#include <memp.h>
#include "game/mp_weapon.h"
#include "game/bondview_r.h"
#include "bg.h"
#include "bondview_r.h"
#include "chr.h"
#include "chrai.h"
#include "chraction.h"
#include "propobj.h"
#include "inititemslots.h"
#include "initobjects.h"
#include "initpathtablesomething.h"
#include "limits.h"
#include "loadobjectmodel.h"
#include "language.h"
#include "math_atan2f.h"
#include "matrixmath.h"
#include "mp_weapon.h"
#include "ob.h"
#include "objective.h"
#include "objective_status.h"
#include "objecthandler.h"
#include "player.h"
#include "prop.h"
#include "stan.h"
#include "model.h"
#include "token.h"
/**
* EU .bss 0x80068480
*/
ITEM_IDS lastmpweaponnum;
// redeclare with the element count so ARRAYCOUNT works in proplvreset2
extern ItemModelFileRecord PitemZ_entries[341];
// forward declarations
s32 load_proptype(PROPDEF_TYPE type);
void sub_GAME_7F001BD4(struct BoundPadRecord *pad, struct coord3d *arg1);
void domakedefaultobj(s32 arg0, ObjectRecord *arg1, s32 cmdindex);
void weaponAssignToHome(s32 arg0, WeaponObjRecord* weapon, s32 cmdindex);
void setupHat(s32 arg0, ObjectRecord* hat, s32 cmdindex);
void setupKey(s32 arg0, ObjectRecord* key, s32 cmdindex);
void setupCctv(s32 arg0, CCTVRecord *arg1, s32 cmdindex);
void setupAutogun(s32 stageID, AutogunRecord *autogun, s32 cmdindex);
void setupHangingMonitors(s32 arg0, ObjectRecord* rack, s32 cmdindex);
void setupSingleMonitor(s32 stageID, MonitorObjRecord *monitor, s32 cmdindex);
void setupMultiMonitor(s32 stageID, MultiMonitorObjRecord* monitor, s32 cmdindex);
void sub_GAME_7F00324C(struct BoundPadRecord *arg0, s32 *arg1, s32 *arg2, struct coord3d *arg3, struct coord3d *arg4);
void setupDoor(s32 arg0, struct DoorRecord *door, s32 arg2);
s32 load_proptype(PROPDEF_TYPE type)
{
PropDefHeaderRecord *propdef = (PropDefHeaderRecord *) g_CurrentSetup.propDefs;
s32 count = 0;
if (propdef != NULL)
{
while (propdef->type != PROPDEF_END)
{
if (propdef->type == (type & 0xFF))
{
count ++;
}
propdef = &propdef[sizepropdef((PropDefHeaderRecord* ) propdef)];
}
}
return count;
}
/**
* perfect dark padGetCentre (pad.c)
*
* NTSC address 0x7F001BD4.
*/
void sub_GAME_7F001BD4(struct BoundPadRecord *pad, struct coord3d *arg1)
{
struct coord3d normal;
f32 scale;
struct bbox bb;
f32 temp;
bb.zmax = pad->bbox.xmin;
bb.zmin = pad->bbox.xmax;
bb.ymax = pad->bbox.ymin;
bb.ymin = pad->bbox.ymax;
bb.xmax = pad->bbox.zmin;
bb.xmin = pad->bbox.zmax;
normal.f[0] = (pad->up.f[1] * pad->look.f[2]) - (pad->up.f[2] * pad->look.f[1]);
normal.f[1] = (pad->up.f[2] * pad->look.f[0]) - (pad->up.f[0] * pad->look.f[2]);
normal.f[2] = (pad->up.f[0] * pad->look.f[1]) - (pad->up.f[1] * pad->look.f[0]);
temp = (normal.f[0] * normal.f[0]) + (normal.f[1] * normal.f[1]) + (normal.f[2] * normal.f[2]);
scale = 1.0f / sqrtf(temp);
normal.f[0] *= scale;
normal.f[1] *= scale;
normal.f[2] *= scale;
arg1->f[0] = pad->pos.f[0] + (
(bb.zmax + bb.zmin) * normal.f[0] +
(bb.ymax + bb.ymin) * pad->up.f[0] +
(bb.xmax + bb.xmin) * pad->look.f[0]) * 0.5f;
arg1->f[1] = pad->pos.f[1] + (
(bb.zmax + bb.zmin) * normal.f[1] +
(bb.ymax + bb.ymin) * pad->up.f[1] +
(bb.xmax + bb.xmin) * pad->look.f[1]) * 0.5f;
arg1->f[2] = pad->pos.f[2] + (
(bb.zmax + bb.zmin) * normal.f[2] +
(bb.ymax + bb.ymin) * pad->up.f[2] +
(bb.xmax + bb.xmin) * pad->look.f[2]) * 0.5f;
}
/**
* NTSC address 0x7F001D9C.
*/
void domakedefaultobj(s32 arg0, ObjectRecord *arg1, s32 cmdindex)
{
s32 padding;
s32 spF0;
f32 var_f0;
struct coord3d spE0;
struct StandTile *spDC;
struct coord3d spD0;
StandTile *spCC;
Mtxf sp8C;
struct coord3d sp80;
struct PropRecord *var_v0;
f32 sp78;
s32 sp74;
struct BoundPadRecord *var_s0;
ChrRecord *sp6C;
ModelRoData_BoundingBoxRecord *temp_v0_3;
struct PadRecord *sp64;
struct PropRecord *sp60;
s32 padding2;
f32 sp58;
f32 sp54;
f32 sp50;
s32 padding3;
f32 sp48;
spF0 = arg1->obj;
var_s0 = NULL;
modelLoad(spF0);
sp78 = arg1->extrascale * 0.00390625f;
arg1->damage = *(s32*)&arg1->damage / 65536.0f;
if (getPlayerCount() >= 2)
{
sp74 = 1;
if ((get_scenario() == SCENARIO_TLD) && (arg1->obj == PROP_FLAG))
{
sp74 = 0;
}
else if ((get_scenario() == SCENARIO_MWTGG) && (arg1->obj == PROP_CHRGOLDEN))
{
sp74 = 0;
}
if (sp74 != 0)
{
arg1->state |= PROPSTATE_RESPAWN; // respawn enabled
}
}
if (arg1->flags & PROPFLAG_INSIDEANOTHEROBJ)
{
if (arg1->type == PROP_TYPE_SMOKE)
{
sub_GAME_7F051DD8(arg1, PitemZ_entries[spF0].header);
}
else
{
objInitWithModelDef(arg1, PitemZ_entries[spF0].header);
}
modelSetScale(arg1->model, arg1->model->scale * sp78);
}
else if (arg1->flags & PROPFLAG_ASSIGNEDTOCHR)
{
sp6C = chrFindByLiteralId(arg1->pad);
if ((sp6C != NULL) && (sp6C->prop != NULL) && (sp6C->model != NULL))
{
if (arg1->type == 8)
{
var_v0 = sub_GAME_7F051DD8(arg1, PitemZ_entries[spF0].header);
}
else
{
var_v0 = objInitWithModelDef(arg1, PitemZ_entries[spF0].header);
}
modelSetScale(arg1->model, arg1->model->scale * sp78);
chrpropReparent(var_v0, sp6C->prop);
}
#ifdef DEBUG
else
{
osSyncPrintf("domakedefaultobj: no chr number %d for obj number %d!\n",arg1->pad,cmdindex + 1);
}
#endif
}
else
{
if (isNotBoundPad(arg1->pad))
{
sp64 = &g_CurrentSetup.pads[arg1->pad];
matrix_4x4_set_basis_and_position_target(&sp8C, 0.0f, 0.0f, 0.0f, -sp64->look.f[0], -sp64->look.f[1], -sp64->look.f[2], sp64->up.f[0], sp64->up.f[1], sp64->up.f[2]);
spD0.f[0] = sp64->pos.f[0];
spD0.f[1] = sp64->pos.f[1];
spD0.f[2] = sp64->pos.f[2];
if (arg1->flags & PROPFLAG_ONSCREEN)
{
sp80.f[0] = sp64->pos.f[0];
sp80.f[1] = sp64->pos.f[1];
sp80.f[2] = sp64->pos.f[2];
}
else
{
// same as above?
sp80.f[0] = sp64->pos.f[0];
sp80.f[1] = sp64->pos.f[1];
sp80.f[2] = sp64->pos.f[2];
}
spCC = sp64->stan;
}
else
{
var_s0 = &g_CurrentSetup.boundpads[getBoundPadNum(arg1->pad)];
matrix_4x4_set_basis_and_position_target(&sp8C, 0.0f, 0.0f, 0.0f, -var_s0->look.f[0], -var_s0->look.f[1], -var_s0->look.f[2], var_s0->up.f[0], var_s0->up.f[1], var_s0->up.f[2]);
if (!(arg1->flags2 & PROPFLAG2_00000001))
{
sub_GAME_7F001BD4(var_s0, &spD0);
sp80.f[0] = spD0.f[0] + (var_s0->up.f[0] * ((var_s0->bbox.ymin - var_s0->bbox.ymax) * 0.5f));
sp80.f[1] = spD0.f[1] + (var_s0->up.f[1] * ((var_s0->bbox.ymin - var_s0->bbox.ymax) * 0.5f));
sp80.f[2] = spD0.f[2] + (var_s0->up.f[2] * ((var_s0->bbox.ymin - var_s0->bbox.ymax) * 0.5f));
spCC = var_s0->stan;
if (walkTilesBetweenPoints_NoCallback(&spCC, var_s0->pos.f[0], var_s0->pos.f[2], spD0.f[0], spD0.f[2]) == 0)
{
spD0.f[0] = var_s0->pos.f[0];
spD0.f[1] = var_s0->pos.f[1];
spD0.f[2] = var_s0->pos.f[2];
spCC = var_s0->stan;
if (!(arg1->flags & PROPFLAG_ONSCREEN) && !(arg1->flags & PROPFLAG_00001000))
{
// removed
#ifdef DEBUG
osSyncPrintf("object number %d not positioned correctly!\n",cmdindex + 1);
#endif
}
}
}
else
{
spD0.f[0] = var_s0->pos.f[0];
spD0.f[1] = var_s0->pos.f[1];
spD0.f[2] = var_s0->pos.f[2];
spCC = var_s0->stan;
sub_GAME_7F001BD4(var_s0, &sp80);
sp80.f[0] += (var_s0->bbox.ymin - var_s0->bbox.ymax) * 0.5f * var_s0->up.f[0];
sp80.f[1] += (var_s0->bbox.ymin - var_s0->bbox.ymax) * 0.5f * var_s0->up.f[1];
sp80.f[2] += (var_s0->bbox.ymin - var_s0->bbox.ymax) * 0.5f * var_s0->up.f[2];
}
}
if (getposstan(&spD0, spCC, 0.0f, &spE0, &spDC) != 0)
{
if (arg1->type == PROP_TYPE_SMOKE)
{
sp60 = sub_GAME_7F051DD8(arg1, PitemZ_entries[spF0].header);
}
else
{
sp60 = objInitWithAutoModel(arg1);
}
if (var_s0 != NULL)
{
temp_v0_3 = chrobjGetBboxFromObjectRecord(arg1);
if (temp_v0_3 != NULL)
{
sp58 = 1.0f;
sp54 = 1.0f;
sp50 = 1.0f;
if (arg1->flags & (PROPFLAG_00000010 | PROPFLAG_00000020))
{
if (temp_v0_3->Bounds.xmin < temp_v0_3->Bounds.xmax)
{
if (arg1->flags & PROPFLAG_ONSCREEN)
{
sp58 = (var_s0->bbox.xmax - var_s0->bbox.xmin) / ((temp_v0_3->Bounds.xmax - temp_v0_3->Bounds.xmin) * arg1->model->scale);
}
else
{
sp58 = (var_s0->bbox.xmax - var_s0->bbox.xmin) / ((temp_v0_3->Bounds.xmax - temp_v0_3->Bounds.xmin) * arg1->model->scale);
}
}
}
if (arg1->flags & (PROPFLAG_00000010 | PROPFLAG_00000040))
{
if (temp_v0_3->Bounds.ymin < temp_v0_3->Bounds.ymax)
{
if (arg1->flags & PROPFLAG_ONSCREEN)
{
sp50 = (var_s0->bbox.zmax - var_s0->bbox.zmin) / ((temp_v0_3->Bounds.ymax - temp_v0_3->Bounds.ymin) * arg1->model->scale);
}
else
{
sp54 = (var_s0->bbox.ymax - var_s0->bbox.ymin) / ((temp_v0_3->Bounds.ymax - temp_v0_3->Bounds.ymin) * arg1->model->scale);
}
}
}
if (arg1->flags & (PROPFLAG_00000010 | PROPFLAG_00000080))
{
if (temp_v0_3->Bounds.zmin < temp_v0_3->Bounds.zmax)
{
if (arg1->flags & PROPFLAG_ONSCREEN)
{
sp54 = (var_s0->bbox.ymax - var_s0->bbox.ymin) / ((temp_v0_3->Bounds.zmax - temp_v0_3->Bounds.zmin) * arg1->model->scale);
}
else
{
sp50 = (var_s0->bbox.zmax - var_s0->bbox.zmin) / ((temp_v0_3->Bounds.zmax - temp_v0_3->Bounds.zmin) * arg1->model->scale);
}
}
}
var_f0 = sp58;
if (sp54 < var_f0)
{
var_f0 = sp54;
}
if (sp50 < var_f0)
{
var_f0 = sp50;
}
sp48 = sp58;
if (sp58 < sp54)
{
sp48 = sp54;
}
if (sp48 < sp50)
{
sp48 = sp50;
}
if (arg1->flags & PROPFLAG_00000010)
{
sp50 = var_f0;
sp54 = var_f0;
sp58 = var_f0;
}
else
{
if (!(arg1->flags & PROPFLAG_00000020))
{
if (arg1->flags & PROPFLAG_ONSCREEN)
{
if (temp_v0_3->Bounds.xmax == temp_v0_3->Bounds.xmin)
{
sp58 = sp48;
}
}
else if (temp_v0_3->Bounds.xmax == temp_v0_3->Bounds.xmin)
{
sp58 = sp48;
}
}
if (!(arg1->flags & PROPFLAG_00000040))
{
if (arg1->flags & PROPFLAG_ONSCREEN)
{
if (temp_v0_3->Bounds.ymax == temp_v0_3->Bounds.ymin)
{
sp50 = sp48;
}
}
else if (temp_v0_3->Bounds.ymax == temp_v0_3->Bounds.ymin)
{
sp54 = sp48;
}
}
if (!(arg1->flags & PROPFLAG_00000080))
{
if (arg1->flags & PROPFLAG_ONSCREEN)
{
if (temp_v0_3->Bounds.zmax == temp_v0_3->Bounds.zmin)
{
sp54 = sp48;
}
}
else if (temp_v0_3->Bounds.zmax == temp_v0_3->Bounds.zmin)
{
sp50 = sp48;
}
}
}
sp58 /= sp48;
sp54 /= sp48;
sp50 /= sp48;
if ((sp58 <= 0.000001f) || (sp54 <= 0.000001f) || (sp50 <= 0.000001f))
{
#ifdef DEBUG
osSyncPrintf("Scale warning: object number %d has a small scale: %f,%f,%f\n",cmdindex +1, sp58,sp54,sp50);
#endif
sp50 = 1.0f;
sp54 = 1.0f;
sp58 = 1.0f;
}
matrix_column_1_scalar_multiply(sp58, sp8C.m[0]);
matrix_column_2_scalar_multiply(sp54, sp8C.m[0]);
matrix_column_3_scalar_multiply_2(sp50, sp8C.m[0]);
modelSetScale(arg1->model, arg1->model->scale * sp48);
}
}
modelSetScale(arg1->model, arg1->model->scale * sp78);
matrix_scalar_multiply(arg1->model->scale, sp8C.m[0]);
if (arg1->flags & PROPFLAG_ONSCREEN)
{
sub_GAME_7F040BA0(arg1, &spE0, &sp8C, spDC, &sp80);
}
else
{
sub_GAME_7F04088C(arg1, &spE0, &sp8C, spDC, &sp80);
}
setupUpdateObjectRoomPosition(arg1);
chrpropActivate(sp60);
chrpropEnable(sp60);
}
#ifdef DEBUG
else
{
osSyncPrintf("domakedefaultobj: prop obj number %d not reset!\n",cmdindex + 1);
}
#endif
}
}
/**
* NTSC address 0x7F002738.
* PAL address 0x7F002738.
*/
void weaponAssignToHome(s32 arg0, WeaponObjRecord* weapon, s32 cmdindex)
{
s32 padding;
bool hastoken;
ChrRecord* chr;
bool giveweapon;
s32 temp_a0;
struct s_mp_weapon_set* weapon_set;
if ((weapon->flags & PROPFLAG_ASSIGNEDTOCHR))
{
chr = chrFindByLiteralId(weapon->pad);
if (chr && chr->prop && chr->model)
{
if (cheatIsActive(CHEAT_ENEMY_ROCKETS))
{
switch ((s8)weapon->weaponnum)
{
case ITEM_KNIFE:
case ITEM_THROWKNIFE:
case ITEM_WPPK:
case ITEM_WPPKSIL:
case ITEM_TT33:
case ITEM_SKORPION:
case ITEM_AK47:
case ITEM_UZI:
case ITEM_MP5K:
case ITEM_MP5KSIL:
case ITEM_SPECTRE:
case ITEM_M16:
case ITEM_FNP90:
case ITEM_SHOTGUN:
case ITEM_AUTOSHOT:
case ITEM_SNIPERRIFLE:
case ITEM_RUGER:
case ITEM_GOLDENGUN:
case ITEM_SILVERWPPK:
case ITEM_GOLDWPPK:
case ITEM_LASER:
case ITEM_WATCHLASER:
case ITEM_REMOTEMINE:
case ITEM_TRIGGER:
case ITEM_TASER:
weapon->weaponnum = ITEM_ROCKETLAUNCH;
weapon->obj = PROP_CHRROCKETLAUNCH;
weapon->extrascale = 256;
break;
}
}
weaponLoadProjectileModels((s8)weapon->weaponnum);
sub_GAME_7F052030(weapon, chr);
}
#ifdef DEBUG
else
{
osSyncPrintf("domakeweaponobj: no chr number %d for obj number %d!\n",weapon->pad, cmdindex + 1);
}
#endif
}
else
{
hastoken = 1;
giveweapon = 1;
if (getPlayerCount() >= 2)
{
lastmpweaponnum = -1;
switch ((u8)weapon->weaponnum)
{
case ITEM_UNARMED + 0xF0:
case ITEM_FIST + 0xF0:
case ITEM_KNIFE + 0xF0:
case ITEM_THROWKNIFE + 0xF0:
case ITEM_WPPK + 0xF0:
case ITEM_WPPKSIL + 0xF0:
case ITEM_TT33 + 0xF0:
case ITEM_SKORPION + 0xF0:
weapon_set = getPtrMPWeaponSetData();
temp_a0 = (u8)weapon->weaponnum - 0xF0;
lastmpweaponnum = temp_a0;
weapon->weaponnum = weapon_set[temp_a0].itemID;
weapon->obj = weapon_set[temp_a0].propID;
#if defined(VERSION_EU)
weapon->extrascale = (weapon_set[temp_a0].size16);
#else
weapon->extrascale = (weapon_set[temp_a0].size * 256.0f);
#endif
giveweapon = weapon_set[temp_a0].allowpickup;
break;
case ITEM_TOKEN:
hastoken = 1;
giveweapon = 1;
if (get_scenario() != SCENARIO_TLD)
{
giveweapon = 0;
}
break;
}
}
if ((weapon->weaponnum != ITEM_UNARMED) && giveweapon)
{
weaponLoadProjectileModels(weapon->weaponnum);
domakedefaultobj(arg0, (struct ObjectRecord*)weapon, cmdindex);
}
}
}
//i should be object hat
void setupHat(s32 arg0, ObjectRecord* hat, s32 cmdindex)
{
if (hat->flags & PROPFLAG_ASSIGNEDTOCHR) {
ChrRecord* chr = chrFindByLiteralId(hat->pad);
if (chr && chr->prop && chr->model) {
hatAssignToChr(hat, chr);
}
#ifdef DEBUG
else
{
osSyncPrintf("domakehatobj: no chr number %d for obj number %d!\n",hat->pad, cmdindex + 1);
}
#endif
} else {
domakedefaultobj(arg0, hat, cmdindex);
}
}
//i should be object key
void setupKey(s32 arg0, ObjectRecord* key, s32 cmdindex)
{
domakedefaultobj(arg0, key, cmdindex);
}
/**
* NTSC address 0x7F002A3C.
*/
void setupCctv(s32 arg0, CCTVRecord *arg1, s32 cmdindex)
{
struct coord3d *temp_a2;
struct PadRecord *sp50;
struct coord3d sp44;
Mtxf *sp3C;
domakedefaultobj(arg0, (struct ObjectRecord*)arg1, cmdindex);
#ifdef PORT
/* D307 (M-201): on N64, CCTVRecord's own s32 `pad` @0x80 (the LOOK-AT
* pad) shadows the inherited ObjectRecord s16 `pad` @0x08 (the mount pad),
* so `arg1->pad` here is the look-at pad. The PC struct renames the
* duplicate to `lookpad` (GCC rejects duplicate members), which silently
* re-pointed these reads at the MOUNT pad: the look vector became the
* lens's own offset from its mount and every camera faced backwards.
* Read the correctly named field (A1 class: layout/naming only; PD's
* setupCreateCctv uses cctv->lookatpadnum for the same step). */
#define CCTV_LOOKPAD (arg1->lookpad)
#else
#define CCTV_LOOKPAD (arg1->pad)
#endif
if (CCTV_LOOKPAD >= 0)
{
temp_a2 = (struct coord3d*)arg1->model->obj->Switches[0]->Data;
if (isNotBoundPad(CCTV_LOOKPAD))
{
sp50 = &g_CurrentSetup.pads[CCTV_LOOKPAD];
}
else
{
sp50 = (struct PadRecord *)&g_CurrentSetup.boundpads[getBoundPadNum(CCTV_LOOKPAD)];
}
sp44.f[0] = temp_a2->f[0];
sp44.f[1] = temp_a2->f[1];
sp44.f[2] = temp_a2->f[2];
mtx4RotateVecInPlace(&arg1->mtx, &sp44);
sp3C = &arg1->unk84;
sp44.f[0] += arg1->prop->pos.f[0];
sp44.f[1] += arg1->prop->pos.f[1];
sp44.f[2] += arg1->prop->pos.f[2];
matrix_4x4_set_basis_and_position_target(sp3C, 0.0f, 0.0f, 0.0f, sp44.f[0] - sp50->pos.f[0], sp44.f[1] - sp50->pos.f[1], sp44.f[2] - sp50->pos.f[2], 0.0f, 1.0f, 0.0f);
matrix_scalar_multiply(arg1->model->scale, sp3C->m[0]);
if (arg1->convert_to_f32 == 0)
{
arg1->convert_to_f32 = 1;
arg1->unkCC = (*(s32*)&arg1->unkCC * M_TAU_F) / 65536.0f;
arg1->unkD0 = (*(s32*)&arg1->unkD0 * M_TAU_F) / 65536.0f;
arg1->unkDC = (*(s32*)&arg1->unkDC * M_TAU_F) / 65536.0f;
arg1->unkE8 = *(s32*)&arg1->unkE8;
}
arg1->unkD4 = 0;
arg1->unkD8 = 0.0f;
arg1->unkC8 = arg1->unkCC;
arg1->unkC4 = atan2f(sp44.f[0] - sp50->pos.f[0], sp44.f[2] - sp50->pos.f[2]);
arg1->timer = 0;
#ifdef PORT
/* D307 probe: dump every input + the derived orientation so a PC run
* can be compared word-for-word against a ROM decode of the same
* record (facing-backwards CCTV report). Env-gated, load-time only. */
if (getenv("GE_D307")) {
fprintf(stderr,
"D307: cctv cmd=%d obj=%d pad=%d bound=%d pos=(%.6g,%.6g,%.6g) "
"mtx=(%.6g,%.6g,%.6g %.6g,%.6g,%.6g %.6g,%.6g,%.6g) "
"sw=(%.6g,%.6g,%.6g) watch=(%.6g,%.6g,%.6g) padpos=(%.6g,%.6g,%.6g) "
"target=(%.6g,%.6g,%.6g) C4=%.6f CC=%.6f basis=(%.6g,%.6g,%.6g %.6g,%.6g,%.6g %.6g,%.6g,%.6g)\n",
cmdindex, arg1->obj, arg1->pad, !isNotBoundPad(arg1->pad),
arg1->prop->pos.f[0], arg1->prop->pos.f[1], arg1->prop->pos.f[2],
arg1->mtx.m[0][0], arg1->mtx.m[0][1], arg1->mtx.m[0][2],
arg1->mtx.m[1][0], arg1->mtx.m[1][1], arg1->mtx.m[1][2],
arg1->mtx.m[2][0], arg1->mtx.m[2][1], arg1->mtx.m[2][2],
temp_a2->f[0], temp_a2->f[1], temp_a2->f[2],
sp44.f[0], sp44.f[1], sp44.f[2],
sp50->pos.f[0], sp50->pos.f[1], sp50->pos.f[2],
sp44.f[0] - sp50->pos.f[0], sp44.f[1] - sp50->pos.f[1], sp44.f[2] - sp50->pos.f[2],
arg1->unkC4, arg1->unkCC,
sp3C->m[0][0], sp3C->m[0][1], sp3C->m[0][2],
sp3C->m[1][0], sp3C->m[1][1], sp3C->m[1][2],
sp3C->m[2][0], sp3C->m[2][1], sp3C->m[2][2]);
if (arg1->pad == 10018) {
for (int d307i = 16; d307i <= 24; d307i++) {
struct PadRecord *d307p = &g_CurrentSetup.boundpads[d307i];
fprintf(stderr, "D307: bpad[%d] ptr=%p pos=(%.6g,%.6g,%.6g)\n",
d307i, (void *)d307p,
d307p->pos.f[0], d307p->pos.f[1], d307p->pos.f[2]);
}
}
}
#endif
}
}
void setupAutogun(s32 stageID, AutogunRecord *autogun, s32 cmdindex)
{
s8 *beam;
domakedefaultobj(stageID, (ObjectRecord *) autogun, cmdindex);
#ifdef VERSION_EU
autogun->speed = ((*((s32 *) (&autogun->speed))) * 7.5398226f) / 65536.0f;
autogun->aimdist = ((*((s32 *) (&autogun->aimdist))) * 100.0f) / 65536.0f;
autogun->unk88 = ((*((s32 *) (&autogun->unk88))) * M_TAU_F) / 65536.0f;
autogun->unk8C = ((*((s32 *) (&autogun->unk8C))) * M_TAU_F) / 65536.0f;
#endif
autogun->unkAC = 0;
autogun->unkB8 = -1;
autogun->unkBC = -1;
autogun->unkC0 = -1;
autogun->unkC4 = 0;
autogun->unkC8 = 0;
autogun->unk90 = 0.0f;
autogun->unk94 = 0.0f;
autogun->rot_related = 0.0f;
autogun->unk9C = 0.0f;
autogun->unkA0 = 0.0f;
autogun->unk98 = 0.0f;
autogun->unkB0 = 0.0f;
autogun->unkB4 = 0.0f;
#ifndef VERSION_EU
autogun->speed = ((*((s32 *) (&autogun->speed))) * M_TAU_F) / 65536.0f;
autogun->aimdist = ((*((s32 *) (&autogun->aimdist))) * 100.0f) / 65536.0f;
autogun->unk88 = ((*((s32 *) (&autogun->unk88))) * M_TAU_F) / 65536.0f;
autogun->unk8C = ((*((s32 *) (&autogun->unk8C))) * M_TAU_F) / 65536.0f;
#endif
beam = mempAllocBytesInBank(0x30U, MEMPOOL_STAGE);
autogun->beam = beam;
*beam = -1;
autogun->is_active = FALSE;
autogun->unkD4 = 0.0f;
if (autogun->padID >= 0)
{
s32 stack1;
f32 xdiff;
f32 ydiff;
f32 zdiff;
PadRecord *pad;
PropRecord *prop;
if (autogun->padID < 0x2710)
{
if (1);
pad = &g_CurrentSetup.pads[autogun->padID];
}
else
{
pad = &g_CurrentSetup.boundpads[getBoundPadNum(autogun->padID)];
}
prop = autogun->prop;
xdiff = pad->pos.x - prop->pos.x;
ydiff = pad->pos.y - prop->pos.y;
zdiff = pad->pos.z - prop->pos.z;
autogun->rot_related = atan2f(xdiff, zdiff);
autogun->unk98 = atan2f(ydiff, sqrtf((xdiff * xdiff) + (zdiff * zdiff)));
}
}
//i should be object rack
void setupHangingMonitors(s32 arg0, ObjectRecord* rack, s32 cmdindex)
{
domakedefaultobj(arg0, rack, cmdindex);
}
void setupSingleMonitor(s32 stageID, MonitorObjRecord *monitor, s32 cmdindex)
{
MonitorRecord *record;
s32 unused;
s32 modelnum;
ObjectRecord *owner;
PropRecord *prop;
f32 scale;
monitor->Monitor = g_MonitorAnimController;
record = &monitor->Monitor;
monitorSetImageByNum(&monitor->Monitor, monitor->ImageNum);
if (monitor->pad < 0 && (monitor->flags & PROPFLAG_INSIDEANOTHEROBJ) == 0)
{
modelnum = monitor->obj;
owner = (struct ObjectRecord *)setupGetPtrToCommandByIndex(cmdindex + monitor->OwnerOffset);
modelLoad(modelnum);
scale = monitor->extrascale * (1.0f / 256.0f);
monitor->damage = *(s32*)&monitor->damage / M_U16_MAX_VALUE_F;
if (getPlayerCount() >= 2)
{
monitor->state |= PROPSTATE_RESPAWN;
}
prop = objInitWithAutoModel((ObjectRecord*)monitor);
monitor->embedment = embedmentAllocate();
if (prop && monitor->embedment)
{
monitor->runtime_bitflags |= RUNTIMEBITFLAG_EMBEDDED;
modelSetScale(monitor->model, monitor->model->scale * scale);
monitor->model->attachedto = owner->model;
if (monitor->OwnerPart == 0)
{
monitor->model->attachedto_objinst = owner->model->obj->Switches[0];
}
else if (monitor->OwnerPart == 1)
{
monitor->model->attachedto_objinst = owner->model->obj->Switches[1];
}
else if (monitor->OwnerPart == 2)
{
monitor->model->attachedto_objinst = owner->model->obj->Switches[2];
}
else
{
monitor->model->attachedto_objinst = owner->model->obj->Switches[3];;
}
chrpropReparent(prop, owner->prop);
matrix_4x4_set_rotation_around_x(0.36651915f, (Mtxf*)&monitor->embedment->matrix);
matrix_scalar_multiply(monitor->model->scale / owner->model->scale, (f32*)&monitor->embedment->matrix);
}
}
else
{
domakedefaultobj(stageID, (ObjectRecord*)monitor, cmdindex);
}
if ((monitor->flags & PROPFLAG_MONITOR_RENDERPOSTBG) && monitor->prop)
{
monitor->prop->flags |= PROPFLAG_RENDERPOSTBG;
}
}
void setupMultiMonitor(s32 stageID, MultiMonitorObjRecord* monitor, s32 cmdindex)
{
monitor->Monitor[0] = g_MonitorAnimController;
monitorSetImageByNum(&monitor->Monitor[0], monitor->ImageNums[0]);
monitor->Monitor[1] = g_MonitorAnimController;
monitorSetImageByNum(&monitor->Monitor[1], monitor->ImageNums[1]);
monitor->Monitor[2] = g_MonitorAnimController;
monitorSetImageByNum(&monitor->Monitor[2], monitor->ImageNums[2]);
monitor->Monitor[3] = g_MonitorAnimController;
monitorSetImageByNum(&monitor->Monitor[3], monitor->ImageNums[3]);
domakedefaultobj(stageID, monitor, cmdindex);
}
void sub_GAME_7F00324C(struct BoundPadRecord *arg0, s32 *arg1, s32 *arg2, struct coord3d *arg3, struct coord3d *arg4)
{
StandTile *sp4C;
struct coord3d normal;
s32 padding;
struct coord3d center;
StandTile *sp2C;
f32 scale;
sub_GAME_7F001BD4(arg0, &center);
sp2C = (StandTile *)arg0->stan;
if (walkTilesBetweenPoints_NoCallback(&sp2C, arg0->pos.f[0], arg0->pos.f[2], center.f[0], center.f[2]) == 0)
{
sp2C = (StandTile *)arg0->stan;
center.f[0] = arg0->pos.f[0];
center.f[1] = arg0->pos.f[1];
center.f[2] = arg0->pos.f[2];
}
normal.f[0] = (arg0->up.f[1] * arg0->look.f[2]) - (arg0->up.f[2] * arg0->look.f[1]);
normal.f[1] = (arg0->up.f[2] * arg0->look.f[0]) - (arg0->up.f[0] * arg0->look.f[2]);
normal.f[2] = (arg0->up.f[0] * arg0->look.f[1]) - (arg0->up.f[1] * arg0->look.f[0]);
scale = 1.0f / sqrtf(((normal.f[0] * normal.f[0]) + (normal.f[1] * normal.f[1])) + (normal.f[2] * normal.f[2]));
sp4C = sp2C;
normal.f[0] *= scale;
normal.f[1] *= scale;
normal.f[2] *= scale;
arg3->f[0] = center.f[0] + (normal.f[0] * 50.0f);
arg3->f[1] = center.f[1];
arg3->f[2] = center.f[2] + (normal.f[2] * 50.0f);
walkTilesBetweenPoints_NoCallback(&sp4C, center.f[0], center.f[2], arg3->f[0], arg3->f[2]);
if (1);
*arg1 = (s32) sp4C->room;
sp4C = sp2C;
arg4->f[0] = center.f[0] - (normal.f[0] * 50.0f);
arg4->f[1] = center.f[1];
arg4->f[2] = center.f[2] - (normal.f[2] * 50.0f);
walkTilesBetweenPoints_NoCallback(&sp4C, center.f[0], center.f[2], arg4->f[0], arg4->f[2]);
if (1);
*arg2 = (s32) sp4C->room;
if (*arg2 == *arg1)
{
*arg2 = -1;
}
}
extern f32 g_DoorScale;
/**
*
* NTSC ADDRESS: 7F003480
* PAL ADDRESS: 7F0033F0
* Perfect Dark: void setupCreateDoor(struct doorobj *door, s32 cmdindex)
*/
void setupDoor(s32 arg0, struct DoorRecord *door, s32 arg2)
{
s32 padding; // no sp
s32 modelnum;
struct BoundPadRecord *pad;
StandTile *sp1C8_stan;
PropRecord *prop;
struct coord3d sp1B8;
s32 portalnum; //sp1b4
s32 sp1B0;
s32 sp1AC;
struct coord3d sp1A0;
struct coord3d sp194;
struct PortalMetric sp180;
struct ModelRoData_BoundingBoxRecord *temp_v0;
struct coord3d sp170;
StandTile *sp16C;
Mtxf sp12C;
f32 temp_f2; // no sp
ModelFileHeader *sp124;
struct coord3d sp118; /* compiler-managed */
StandTile *sp114_stan;
Mtxf spD4;
struct coord3d spC8;
Mtxf sp88;
struct coord3d sp7C;
struct bbox bb2;
f32 xscale;
f32 yscale;
f32 zscale;
f32 scale;
//StandTile *stan;
u8 *padding2;
modelnum = door->obj;
portalnum = -1;
sp1B0 = -1;
sp1AC = -1;
modelLoad(modelnum);
pad = &(g_CurrentSetup.boundpads[door->pad]);
if ((door->flags & PROPFLAG_CULL_BEHIND_DOOR) || (door->flags & PROPFLAG_NO_PORTAL_CLOSE))
{
sub_GAME_7F00324C(pad, &sp1B0, &sp1AC, &sp1A0, &sp194);
if ((door->flags & PROPFLAG_CULL_BEHIND_DOOR) && (sp1B0 >= 0) && (sp1AC >= 0))
{
portalnum = bgGetPortalBetweenRooms(sp1B0, sp1AC, &sp1A0, &sp194);
}
}
if (g_DoorScale != 1.0f)
{
if (portalnum >= 0)
{
sub_GAME_7F0B96CC(portalnum, &sp180);
sp180.min *= get_room_data_float2();
temp_f2 = (pad->pos.f[0] * sp180.normal.f[0]) + (pad->pos.f[1] * sp180.normal.f[1]) + (pad->pos.f[2] * sp180.normal.f[2]);
if (g_DoorScale < 1.0f)
{
temp_f2 = (temp_f2 - sp180.min) * (1.0f - g_DoorScale);
sp170.f[0] = pad->pos.f[0] - (sp180.normal.f[0] * temp_f2);
sp170.f[1] = pad->pos.f[1] - (sp180.normal.f[1] * temp_f2);
sp170.f[2] = pad->pos.f[2] - (sp180.normal.f[2] * temp_f2);
}
else
{
temp_f2 = (temp_f2 - sp180.min) * (g_DoorScale - 1.0f);
sp170.f[0] = pad->pos.f[0] + (sp180.normal.f[0] * temp_f2);
sp170.f[1] = pad->pos.f[1] + (sp180.normal.f[1] * temp_f2);
sp170.f[2] = pad->pos.f[2] + (sp180.normal.f[2] * temp_f2);
}
sp16C = pad->stan;
if (walkTilesBetweenPoints_NoCallback(&sp16C, pad->pos.f[0], pad->pos.f[2], sp170.f[0], sp170.f[2]) != 0)
{
pad->stan = sp16C;
pad->pos.f[0] = sp170.f[0];
pad->pos.f[1] = sp170.f[1];
pad->pos.f[2] = sp170.f[2];
pad->bbox.xmin *= g_DoorScale;
pad->bbox.xmax *= g_DoorScale;
}
#ifdef DEBUG
else
{
osSyncPrintf("volume for door object number %d did not have depth changed!\n",arg2 + 1);
}
#endif
}
else
{
pad->bbox.xmin *= g_DoorScale;
pad->bbox.xmax *= g_DoorScale;
}
}
if (getposstan(&pad->pos, pad->stan, 0.0f, &sp1B8, &sp1C8_stan) != 0)
{
matrix_4x4_set_basis_and_position_target(&sp12C, 0, 0, 0, -pad->look.f[0], -pad->look.f[1], -pad->look.f[2], pad->up.f[0], pad->up.f[1], pad->up.f[2]);
sp124 = PitemZ_entries[modelnum].header;
sp114_stan = sp1C8_stan;
bb2.zmax = pad->bbox.xmin;
bb2.zmin = pad->bbox.xmax; //78
bb2.ymax = pad->bbox.ymin; //74
bb2.ymin = pad->bbox.ymax; //70
bb2.xmax = pad->bbox.zmin; //6c
bb2.xmin = pad->bbox.zmax; //68
matrix_4x4_set_rotation_around_x(M_HALF_PI, &spD4);
matrix_4x4_set_rotation_around_z(M_HALF_PI, &sp88);
matrix_4x4_multiply_in_place(&sp88, &spD4);
matrix_4x4_multiply_in_place(&sp12C, &spD4);
sub_GAME_7F001BD4(pad, &sp118);
temp_v0 = (struct ModelRoData_BoundingBoxRecord *)sp124->RootNode->Child->Data;
xscale = (bb2.ymin - bb2.ymax) / (temp_v0->Bounds.xmax - temp_v0->Bounds.xmin);
yscale = (bb2.xmin - bb2.xmax) / (temp_v0->Bounds.ymax - temp_v0->Bounds.ymin);
zscale = (bb2.zmin - bb2.zmax) / (temp_v0->Bounds.zmax - temp_v0->Bounds.zmin);
if ((xscale <= 0.000001f) || (yscale <= 0.000001f) || (zscale <= 0.000001f))
{
#ifdef DEBUG
osSyncPrintf("Scale warning: door object number %d has a small scale: %f,%f,%f\n",arg2 +1, xscale,yscale,zscale);
#endif
xscale =
yscale =
zscale = 1.0f;
}
matrix_column_1_scalar_multiply(xscale, spD4.m[0]);
matrix_column_2_scalar_multiply(yscale, spD4.m[0]);
matrix_column_3_scalar_multiply_2(zscale, spD4.m[0]);
spC8.f[0] = sp118.f[0];
spC8.f[1] = sp118.f[1];
spC8.f[2] = sp118.f[2];
if (!(door->flags2 & 1))
{
if (walkTilesBetweenPoints_NoCallback(&sp114_stan, sp1B8.f[0], sp1B8.f[2], sp118.f[0], sp118.f[2]) != 0)
{
sp1C8_stan = sp114_stan;
}
else
{
sp118.f[0] = sp1B8.f[0];
sp118.f[2] = sp1B8.f[2];
if (!(door->flags & 0x1000)) // prop flag PROPFLAG_00001000 "Absolute Position"
{
#ifdef DEBUG
osSyncPrintf("door object number %d not positioned correctly!\n",arg2 +1);
#endif
}
}
}
else
{
sp118.f[0] = sp1B8.f[0];
sp118.f[1] = sp1B8.f[1];
sp118.f[2] = sp1B8.f[2];
}
if ((door->doorType == DOORTYPE_VERTICAL) || (door->doorType == DOORTYPE_FALLAWAY))
{
sp7C.f[0] = pad->look.f[0] * (bb2.xmin - bb2.xmax);
sp7C.f[1] = pad->look.f[1] * (bb2.xmin - bb2.xmax);
sp7C.f[2] = pad->look.f[2] * (bb2.xmin - bb2.xmax);
}
else
{
sp7C.f[0] = pad->up.f[0] * (bb2.ymax - bb2.ymin);
sp7C.f[1] = pad->up.f[1] * (bb2.ymax - bb2.ymin);
sp7C.f[2] = pad->up.f[2] * (bb2.ymax - bb2.ymin);
}
// These values are stored in the setup files as integers, but at
// runtime they are floats. Hence reading a "float" as an integer,
// converting it to a float and writing it back to the same property.
door->maxFrac = *(s32 *) &door->maxFrac / 65536.0f;
door->perimFrac = *(s32 *) &door->perimFrac / 65536.0f;
#if defined(VERSION_EU)
door->accel = (*(s32 *) &door->accel) * 1.2f / 65536.0f;
door->decel = (*(s32 *) &door->decel) * 1.2f / 65536.0f;
door->maxSpeed = (*(s32 *) &door->maxSpeed) * 1.2f / 65536.0f;
#else
door->accel = (*(s32 *) &door->accel) / 65536.0f;
door->decel = (*(s32 *) &door->decel) / 65536.0f;
door->maxSpeed = (*(s32 *) &door->maxSpeed) / 65536.0f;
#endif
prop = doorInit(door, &sp118, &spD4, sp1C8_stan, &sp7C, &spC8);
if (door->flags & PROPFLAG_CULL_BEHIND_DOOR)
{
door->portalNumber = portalnum;
if ((portalnum >= 0) && (door->openPosition == 0.0f))
{
doorDeactivatePortal(door);
}
#ifdef DEBUG
else
{
osSyncPrintf("No portal for door object number %d ",arg2 + 1);
}
#endif
}
prop->rooms[0] = prop->stan->room;
chrpropRegisterRoom(prop, prop->stan->room);
prop->rooms[1] = 0xFFU;
prop->rooms[2] = 0xFFU;
if ((door->flags & PROPFLAG_CULL_BEHIND_DOOR) || (door->flags & PROPFLAG_NO_PORTAL_CLOSE))
{
if (sp1B0 != prop->stan->room)
{
if (sp1B0 >= 0)
{
prop->rooms[1] = sp1B0;
chrpropRegisterRoom(prop, sp1B0);
}
}
else if (sp1AC >= 0)
{
prop->rooms[1] = sp1AC;
chrpropRegisterRoom(prop, sp1AC);
}
if (prop->rooms[1] != 0xff && 1)
{
if (!prop->stan->room)
{
#ifdef DEBUG
osSyncPrintf("3 rooms for door object number %d\n",arg2 + 1);
#endif
}
}
#ifdef DEBUG
else
{
osSyncPrintf("No 2nd room for door object number %d\n",arg2 + 1);
}
#endif
}
if (door->model != NULL)
{
scale = xscale;
if (scale < yscale)
{
scale = yscale;
}
if (scale < zscale)
{
scale = zscale;
}
modelSetScale(door->model, door->model->scale * scale);
}
chrpropActivate(prop);
chrpropEnable(prop);
if (door->linkedDoorOffset != 0)
{
door->linkedDoor = (struct DoorRecord *)setupGetPtrToCommandByIndex(door->linkedDoorOffset + arg2);
}
}
else
{
door->prop = NULL;
#ifdef DEBUG
osSyncPrintf("proplvreset: prop door object number %d not reset!\n",arg2 + 1);
#endif
}
}
// Perfect Dark void setupLoadFiles(s32 stagenum)
void proplvreset2(enum LEVELID stageId)
{
ItemModelFileRecord *pitem;
s32 withchrs;
s32 withobjs;
withchrs = (((void *) tokenFind(1, "-nochr")) == NULL) && (((void *) tokenFind(1, "-noprop")) == NULL);
withobjs = (((void *) tokenFind(1, "-noobj")) == NULL) && (((void *) tokenFind(1, "-noprop")) == NULL);
g_DoorScale = 1.0f;
/**
* Mark every prop model as "not resident" so the model loads later in this function actually fetch data. Essentially
* RootNode is doubling as a loaded flag for function modelLoad().
*
* The last entry in the PitemZ_entries table is a terminator which is why 1 is subtracted from the loop length.
*/
for (pitem = PitemZ_entries; pitem < &PitemZ_entries[ARRAYCOUNT(PitemZ_entries) - 1]; pitem++)
{
pitem->header->RootNode = NULL;
}
if ((stageId <= (LEVELID_MAX + 1)) && setup_text_pointers[stageId])
{
char strResource[0x100] = ""; // Scratch buffer for synthesizing the setup file's name at runtime.
s32 numAnimatedObjects = 0;
s32 numObjects = 0;
s32 i1 = 0;
s32 i2 = 0;
s32 i3 = 0;
f32 roompos_1;
s32 i5 = 0;
s32 i8;
f32 roompos_2;
struct stagesetup *local_stage;
strResource[0] = setup_text_pointers[stageId][0]; // 'U' -> "U"
strResource[1] = 0; // Terminate so strcat has a valid string.
/**
* There are no slots for the mp stages in setup_text_pointers. The name is created
* by adding "mp_" after the "U" e.g. "Ump_setuparchZ"
*/
if (getPlayerCount() >= 2)
{
strcat(strResource, "mp_"); // -> "Ump_"
}
strcat(strResource, setup_text_pointers[stageId] + 1); // Add remaining text back U[mp_] + setupxxxZ
g_ptrStageSetupFile = _fileNameLoadToBank(strResource, FILELOADMETHOD_DEFAULT, 256, MEMPOOL_STAGE);
local_stage = g_ptrStageSetupFile;
langLoadToAddr(langGetLangBankIndexFromStagenum(stageId));
/**
* The setup file stores every internal reference as a byte offset from the start of the file,
* so rebase them all onto the RAM copy at local_stage.
*/
#ifdef PORT
g_CurrentSetup.pathwaypoints = (void *) (((uintptr_t) local_stage) + ((u32) local_stage->pathwaypoints));
#else
g_CurrentSetup.pathwaypoints = (void *) (((u32) local_stage) + ((u32) local_stage->pathwaypoints));
#endif
#ifdef PORT
g_CurrentSetup.waypointgroups = (void *) (((uintptr_t) local_stage) + ((u32) local_stage->waypointgroups));
#else
g_CurrentSetup.waypointgroups = (void *) (((u32) local_stage) + ((u32) local_stage->waypointgroups));
#endif
#ifdef PORT
g_CurrentSetup.intro = (void *) (((uintptr_t) local_stage) + ((u32) local_stage->intro));
#else
g_CurrentSetup.intro = (void *) (((u32) local_stage) + ((u32) local_stage->intro));
#endif
#ifdef PORT
g_CurrentSetup.propDefs = (void *) (((uintptr_t) local_stage) + ((u32) local_stage->propDefs));
#else
g_CurrentSetup.propDefs = (void *) (((u32) local_stage) + ((u32) local_stage->propDefs));
#endif
#ifdef PORT
g_CurrentSetup.patrolpaths = (void *) (((uintptr_t) local_stage) + ((u32) local_stage->patrolpaths));
#else
g_CurrentSetup.patrolpaths = (void *) (((u32) local_stage) + ((u32) local_stage->patrolpaths));
#endif
#ifdef PORT
g_CurrentSetup.ailists = (void *) (((uintptr_t) local_stage) + ((u32) local_stage->ailists));
#else
g_CurrentSetup.ailists = (void *) (((u32) local_stage) + ((u32) local_stage->ailists));
#endif
#ifdef PORT
g_CurrentSetup.pads = (void *) (((uintptr_t) local_stage) + ((u32) local_stage->pads));
#else
g_CurrentSetup.pads = (void *) (((u32) local_stage) + ((u32) local_stage->pads));
#endif
#ifdef PORT
g_CurrentSetup.boundpads = (void *) (((uintptr_t) local_stage) + ((u32) local_stage->boundpads));
#else
g_CurrentSetup.boundpads = (void *) (((u32) local_stage) + ((u32) local_stage->boundpads));
#endif
// Pad names and bound names are optional. An offset of 0 means absent.
if (local_stage->padnames != 0)
{
#ifdef PORT
g_CurrentSetup.padnames = (void *) (((uintptr_t) local_stage) + ((u32) local_stage->padnames));
#else
g_CurrentSetup.padnames = (void *) (((u32) local_stage) + ((u32) local_stage->padnames));
#endif
}
else
{
g_CurrentSetup.padnames = NULL;
}
if (local_stage->boundpadnames != 0)
{
#ifdef PORT
g_CurrentSetup.boundpadnames = (void *) (((uintptr_t) local_stage) + ((u32) local_stage->boundpadnames));
#else
g_CurrentSetup.boundpadnames = (void *) (((u32) local_stage) + ((u32) local_stage->boundpadnames));
#endif
}
else
{
g_CurrentSetup.boundpadnames = NULL;
}
if (g_CurrentSetup.pathwaypoints)
{
for (i1 = 0; g_CurrentSetup.pathwaypoints[i1].padID >= 0; i1++)
{
#ifdef PORT
g_CurrentSetup.pathwaypoints[i1].neighbours = (void *) (((u32) g_CurrentSetup.pathwaypoints[i1].neighbours) + ((uintptr_t) local_stage));
#else
g_CurrentSetup.pathwaypoints[i1].neighbours = (void *) (((u32) g_CurrentSetup.pathwaypoints[i1].neighbours) + ((u32) local_stage));
#endif
}
}
if (g_CurrentSetup.waypointgroups)
{
for (i2 = 0; g_CurrentSetup.waypointgroups[i2].neighbours; i2++)
{
#ifdef PORT
g_CurrentSetup.waypointgroups[i2].neighbours = (void *) (((u32) g_CurrentSetup.waypointgroups[i2].neighbours) + ((uintptr_t) local_stage));
#else
g_CurrentSetup.waypointgroups[i2].neighbours = (void *) (((u32) g_CurrentSetup.waypointgroups[i2].neighbours) + ((u32) local_stage));
#endif
#ifdef PORT
g_CurrentSetup.waypointgroups[i2].waypoints = (void *) (((u32) g_CurrentSetup.waypointgroups[i2].waypoints) + ((uintptr_t) local_stage));
#else
g_CurrentSetup.waypointgroups[i2].waypoints = (void *) (((u32) g_CurrentSetup.waypointgroups[i2].waypoints) + ((u32) local_stage));
#endif
}
}
// Convert ailist pointers a.k.a. Action Blocks from file-local to proper pointers
{
AIListRecord *ailists = g_CurrentSetup.ailists;
if (ailists)
{
for (i3 = 0; g_CurrentSetup.ailists[i3].ailist != 0; i3++)
{
#ifdef PORT
g_CurrentSetup.ailists[i3].ailist = (void *) (((u32) g_CurrentSetup.ailists[i3].ailist) + ((uintptr_t) local_stage));
#else
g_CurrentSetup.ailists[i3].ailist = (void *) (((u32) g_CurrentSetup.ailists[i3].ailist) + ((u32) local_stage));
#endif
}
}
}
if (g_CurrentSetup.patrolpaths)
{
for (i3 = 0; g_CurrentSetup.patrolpaths[i3].waypoints != NULL; i3++)
{
#ifdef PORT
g_CurrentSetup.patrolpaths[i3].waypoints = (void *) (((u32) g_CurrentSetup.patrolpaths[i3].waypoints) + ((uintptr_t) local_stage));
#else
g_CurrentSetup.patrolpaths[i3].waypoints = (void *) (((u32) g_CurrentSetup.patrolpaths[i3].waypoints) + ((u32) local_stage));
#endif
for (i5 = 0; g_CurrentSetup.patrolpaths[i3].waypoints[i5] >= 0; i5++)
{
// Empty
}
g_CurrentSetup.patrolpaths[i3].len = i5;
}
}
if (g_CurrentSetup.pads)
{
struct PadRecord *pad;
roompos_1 = get_room_data_float2();
pad = g_CurrentSetup.pads;
for (; pad->plink != NULL; pad++)
{
#ifdef PORT
pad->plink = (void *) (((uintptr_t) local_stage) + ((u32) pad->plink));
#else
pad->plink = (void *) (((u32) local_stage) + ((u32) pad->plink));
#endif
pad->pos.f[0] *= roompos_1;
pad->pos.f[1] *= roompos_1;
pad->pos.f[2] *= roompos_1;
#ifdef DEBUG
{
s32 sret = init_pathtable_something(pad, pad->plink, &pad->stan);
if (sret == 0)
{
osSyncPrintf("pad number %d has no stan! (%s)\n", (s32)(pad - g_CurrentSetup.pads), pad->plink);
}
else if (sret == 2)
{
osSyncPrintf("pad number %d changed stan from %s to %s\n", (s32)(pad - g_CurrentSetup.pads), pad->plink, GetStanName(pad->stan));
}
}
#else
init_pathtable_something(pad, pad->plink, &pad->stan);
#endif
if (1);
}
}
if (g_CurrentSetup.boundpads)
{
struct BoundPadRecord *vol;
roompos_2 = get_room_data_float2();
vol = g_CurrentSetup.boundpads;
for (; vol->plink != NULL; vol++)
{
/** Ugly matching hack.
* TODO: investigate if there's a way to get rid of this.
*/
if ((((u32) local_stage) ^ 0) + ((u32)vol->plink));
#ifdef PORT
vol->plink = (void *) (((uintptr_t) local_stage) + ((u32)vol->plink));
#else
vol->plink = (void *) (((u32) local_stage) + ((u32)vol->plink));
#endif
vol->pos.f[0] *= roompos_2;
vol->pos.f[1] *= roompos_2;
vol->pos.f[2] *= roompos_2;
vol->bbox.xmin *= roompos_2;
vol->bbox.xmax *= roompos_2;
vol->bbox.ymin *= roompos_2;
vol->bbox.ymax *= roompos_2;
vol->bbox.zmin *= roompos_2;
vol->bbox.zmax *= roompos_2;
#ifdef DEBUG
{
s32 sret = init_pathtable_something((struct PadRecord *) vol, vol->plink, &vol->stan);
if (sret == 0)
{
osSyncPrintf("vol number %d has no stan! (%s)\n", (s32)(vol - g_CurrentSetup.boundpads), vol->plink);
}
else if (sret == 2)
{
osSyncPrintf("vol number %d changed stan from %s to %s\n", (s32)(vol - g_CurrentSetup.boundpads), vol->plink, GetStanName(vol->stan));
}
}
#else
init_pathtable_something((struct PadRecord *) vol, vol->plink, &vol->stan);
#endif
if (1);
}
}
if (g_CurrentSetup.padnames)
{
for (i1 = 0; g_CurrentSetup.padnames[i1].p; i1++)
{
#ifdef PORT
g_CurrentSetup.padnames[i1].p = (void *) (((u32) g_CurrentSetup.padnames[i1].p) + ((uintptr_t) local_stage));
#else
g_CurrentSetup.padnames[i1].p = (void *) (((u32) g_CurrentSetup.padnames[i1].p) + ((u32) local_stage));
#endif
}
}
if (g_CurrentSetup.boundpadnames)
{
// Required for matching.
if (g_CurrentSetup.ailists && g_CurrentSetup.ailists);
for (i1 = 0; g_CurrentSetup.boundpadnames[i1].p; i1++)
{
#ifdef PORT
g_CurrentSetup.boundpadnames[i1].p = (void *) (((u32) g_CurrentSetup.boundpadnames[i1].p) + ((uintptr_t) local_stage));
#else
g_CurrentSetup.boundpadnames[i1].p = (void *) (((u32) g_CurrentSetup.boundpadnames[i1].p) + ((u32) local_stage));
#endif
}
}
// PD rejoins here
if (withchrs)
{
alloc_init_GUARDdata_entries(load_proptype(PROPDEF_GUARD));
numAnimatedObjects += load_proptype(PROPDEF_GUARD);
numObjects += load_proptype(PROPDEF_COLLECTABLE);
numObjects += load_proptype(PROPDEF_KEY);
numObjects += load_proptype(PROPDEF_HAT);
}
else
{
alloc_init_GUARDdata_entries(0); // chrmgrConfigure
}
if (withobjs)
{
// load std props for all stages
numObjects += load_proptype(PROPDEF_DOOR);
numObjects += load_proptype(PROPDEF_CCTV);
numObjects += load_proptype(PROPDEF_AUTOGUN);
numObjects += load_proptype(PROPDEF_RACK);
numObjects += load_proptype(PROPDEF_MONITOR);
numObjects += load_proptype(PROPDEF_MULTI_MONITOR);
numObjects += load_proptype(PROPDEF_ARMOUR);
numObjects += load_proptype(PROPDEF_PROP);
numObjects += load_proptype(PROPDEF_GLASS);
numObjects += load_proptype(PROPDEF_TINTED_GLASS);
numObjects += load_proptype(PROPDEF_SAFE);
numObjects += load_proptype(PROPDEF_UNK41);
numObjects += load_proptype(PROPDEF_GAS_RELEASING);
numObjects += load_proptype(PROPDEF_ALARM);
numObjects += load_proptype(PROPDEF_MAGAZINE);
numObjects += load_proptype(PROPDEF_AMMO);
numObjects += load_proptype(PROPDEF_VEHICHLE);
numObjects += load_proptype(PROPDEF_TANK);
numAnimatedObjects += load_proptype(PROPDEF_AIRCRAFT);
}
modelmgrAllocateModelSlots(numObjects);
modelmgrAllocateAnimModelSlots(numAnimatedObjects);
for (i8 = 0; i8 < getPlayerCount(); i8++)
{
set_cur_player(i8);
alloc_additional_item_slots(load_proptype(PROPDEF_LINK));
}
if (g_CurrentSetup.propDefs)
{
PropDefHeaderRecord *phead;
s32 flags;
s32 pdefIndex;
// per-difficulty "Don't Load" mask: PROPFLAG2_00000010/20/40 for Agent/Secret/00
flags = 1 << (lvlGetSelectedDifficulty() + 4);
/**
* Complete the skip loading mask started on the line above. Checks for:
* - don't load on 2 players
* - don't load on 3 players
* - don't load on 4 players
* - don't load in multiplayer
*/
if (getPlayerCount() >= 2)
{
flags |= 1 << (getPlayerCount() + 20);
}
phead = g_CurrentSetup.propDefs;
pdefIndex = 0;
while ((i1 = phead->type) != PROPDEF_END)
{
switch (phead->type)
{
case PROPDEF_GUARD_ATTRIBUTE:
{
GuardAttributeRecord *pdef_guarda;
u8 prob;
ChrRecord *chr;
pdef_guarda = (GuardAttributeRecord *) phead;
prob = (u8) pdef_guarda->GrenadeProb;
chr = chrFindByLiteralId(pdef_guarda->chrnum);
if ((chr && chr->prop) && chr->model)
{
chr->grenadeprob = prob;
}
#ifdef DEBUG
else
{
osSyncPrintf("grenade prob: no chr number %d for obj number %d! ", pdef_guarda->GrenadeProb, pdefIndex + 1);
}
#endif
break;
}
case PROPDEF_GUARD:
if (withchrs)
{
expand_09_characters(stageId, (struct GuardRecord *) phead, pdefIndex);
}
break;
case PROPDEF_DOOR:
if (withobjs && (!(((struct DoorRecord *) phead)->flags2 & flags)))
{
setupDoor(stageId, (struct DoorRecord *) phead, pdefIndex);
}
break;
case PROPDEF_DOOR_SCALE:
g_DoorScale = ((struct GlobalDoorScaleRecord *) phead)->Scale / M_U16_MAX_VALUE_F;
break;
case PROPDEF_COLLECTABLE:
if (withchrs && (!(((struct WeaponObjRecord *) phead)->flags2 & flags)))
{
weaponAssignToHome(stageId, (struct WeaponObjRecord *) phead, pdefIndex);
}
break;
case PROPDEF_KEY:
if (withchrs && (!(((struct KeyRecord *) phead)->flags2 & flags)))
{
setupKey(stageId, (struct ObjectRecord *) phead, pdefIndex);
}
break;
case PROPDEF_HAT:
if (withchrs && (!(((struct ObjectRecord *) phead)->flags2 & flags)))
{
setupHat(stageId, (struct ObjectRecord *) phead, pdefIndex);
}
break;
case PROPDEF_CCTV:
if (withobjs && (!(((struct CCTVRecord *) phead)->flags2 & flags)))
{
setupCctv(stageId, (struct CCTVRecord *) phead, pdefIndex);
}
break;
case PROPDEF_AUTOGUN:
if (withobjs && (!(((struct AutogunRecord *) phead)->flags2 & flags)))
{
setupAutogun(stageId, (struct AutogunRecord *) phead, pdefIndex);
}
break;
case PROPDEF_RACK:
if (withobjs && (!(((struct ObjectRecord *) phead)->flags2 & flags)))
{
setupHangingMonitors(stageId, (struct ObjectRecord *) phead, pdefIndex);
}
break;
case PROPDEF_MONITOR:
if (withobjs && (!(((struct MonitorObjRecord *) phead)->flags2 & flags)))
{
setupSingleMonitor(stageId, (struct MonitorObjRecord *) phead, pdefIndex);
}
break;
case PROPDEF_MULTI_MONITOR:
if (withobjs && (!(((struct MultiMonitorObjRecord *) phead)->flags2 & flags)))
{
setupMultiMonitor(stageId, (struct MultiMonitorObjRecord *) phead, pdefIndex);
}
break;
case PROPDEF_ARMOUR:
{
struct BodyArmourRecord *pdef_ba = (struct BodyArmourRecord *) phead;
#ifndef VERSION_US
if (withobjs && (((pdef_ba->flags2 & flags) == 0) || j_text_trigger)) // JP: armour setup also proceeds when j_text_trigger is set
#else
if (withobjs && ((pdef_ba->flags2 & flags) == 0))
#endif
{
pdef_ba->initialamount = (*((s32 *) (&pdef_ba->initialamount))) / M_U16_MAX_VALUE_F;
pdef_ba->amount = pdef_ba->initialamount;
domakedefaultobj(stageId, (struct ObjectRecord *) phead, pdefIndex);
}
break;
}
case PROPDEF_TINTED_GLASS:
{
if (withobjs && (!(((struct TintedGlassRecord *) phead)->flags2 & flags)))
{
if (((struct TintedGlassRecord *) phead)->flags & PROPFLAG_GLASS_HASPORTAL)
{
if (!(((struct TintedGlassRecord *) phead)->pad < 10000))
{
struct coord3d up;
struct coord3d up2;
BoundPadRecord *pad3d;
pad3d = &g_CurrentSetup.boundpads[((struct TintedGlassRecord *) phead)->pad - 10000];
sub_GAME_7F001BD4(pad3d, &up);
up2.x = (10.0f * pad3d->up.x) + up.x;
up2.y = (10.0f * pad3d->up.y) + up.y;
up2.z = (10.0f * pad3d->up.z) + up.z;
up.x -= 10.0f * pad3d->up.x;
up.y -= 10.0f * pad3d->up.y;
up.z -= 10.0f * pad3d->up.z;
((struct TintedGlassRecord *) phead)->portalnum = sub_GAME_7F0B9E04(&up, &up2);
((struct TintedGlassRecord *) phead)->unk90 = (*((s32 *) (&((struct TintedGlassRecord *) phead)->unk90))) / M_U16_MAX_VALUE_F;
}
}
domakedefaultobj(stageId, (struct ObjectRecord *) phead, pdefIndex);
}
break;
}
case PROPDEF_PROP:
case PROPDEF_ALARM:
case PROPDEF_MAGAZINE:
case PROPDEF_GAS_RELEASING:
case PROPDEF_UNK41:
case PROPDEF_GLASS:
case PROPDEF_SAFE:
if (withobjs && (!(((ObjectRecord *) phead)->flags2 & flags)))
{
domakedefaultobj(stageId, (struct ObjectRecord *) phead, pdefIndex);
}
break;
case PROPDEF_AMMO:
{
struct MultiAmmoCrateRecord *pdef_macr = (struct MultiAmmoCrateRecord *) phead;
s32 ammoqty = 1;
s32 i9;
if (getPlayerCount() >= 2)
{
struct s_mp_weapon_set *mpweapon = &getPtrMPWeaponSetData()[lastmpweaponnum];
ammoqty = mpweapon->ammoamount;
if (mpweapon->ammotype);
pdef_macr->slots[mpweapon->ammotype - 1].quantity = ammoqty;
}
if (((ammoqty > 0) && withobjs) && (!(pdef_macr->flags2 & flags)))
{
for (i9 = 0; i9 < AMMOTYPE_GLOBAL_MAX; i9++)
{
if ((pdef_macr->slots[i9].quantity > 0) && (pdef_macr->slots[i9].modelnum != 0xFFFF))
{
modelLoad(pdef_macr->slots[i9].modelnum);
}
}
domakedefaultobj(stageId, (struct ObjectRecord *) pdef_macr, pdefIndex);
}
break;
}
case PROPDEF_TANK:
if (withobjs && (!(((struct TankRecord *) phead)->flags2 & flags)))
{
struct TankRecord *pdef_tank = (struct TankRecord *) phead;
struct PropRecord *tank_prop;
s32 padding;
f32 stan_y = 0.0f;
s32 paddinggg[4];
weaponLoadProjectileModels(ITEM_TANKSHELLS);
domakedefaultobj(stageId, (struct ObjectRecord *) pdef_tank, pdefIndex);
pdef_tank->turret_vertical_angle = 0.0f;
pdef_tank->turret_orientation_angle = 0.0f;
pdef_tank->tank_orientation_angle = M_TAU_F - atan2f(pdef_tank->mtx.m[2][0], pdef_tank->mtx.m[2][2]);
tank_prop = pdef_tank->prop;
if (tank_prop)
{
stan_y = stanGetPositionYValue(tank_prop->stan, tank_prop->pos.f[0], tank_prop->pos.f[2]);
}
pdef_tank->stan_y = stan_y;
#ifdef VERSION_EU
pdef_tank->unkD0 = stan_y / 0.2004f; // EU-tuned constant
#else
pdef_tank->unkD0 = stan_y / 0.17000002f;
#endif
}
break;
case PROPDEF_VEHICHLE:
if (withobjs && (!(((struct VehichleRecord *) phead)->flags2 & flags)))
{
struct VehichleRecord *pdef_veh = (struct VehichleRecord *) phead;
domakedefaultobj(stageId, (struct ObjectRecord *) pdef_veh, pdefIndex);
if (pdef_veh->model != NULL)
{
if (pdef_veh->model->obj->Switches[5] != NULL)
{
modelGetNodeRwData(pdef_veh->model, pdef_veh->model->obj->Switches[5])->Raw.unk00 = (pdef_veh->flags & 0x10000000) == 0;
}
}
pdef_veh->speed = 0.0f;
pdef_veh->wheelxrot = 0.0f;
pdef_veh->wheelyrot = 0.0f;
pdef_veh->speedaim = 0.0f;
pdef_veh->turnrot60 = 0.0f;
pdef_veh->roty = 0.0f;
pdef_veh->speedtime60 = -1.0f;
pdef_veh->ailist = ailistFindById(pdef_veh->ailist);
pdef_veh->aioffset = 0;
pdef_veh->aireturnlist = -1;
pdef_veh->path = 0;
pdef_veh->nextstep = 0;
pdef_veh->Sound = 0;
}
break;
case PROPDEF_AIRCRAFT:
if (withobjs && (!(((struct AircraftRecord *) phead)->flags2 & flags)))
{
struct AircraftRecord *pdef_air = (struct AircraftRecord *) phead;
domakedefaultobj(stageId, (struct ObjectRecord *) pdef_air, pdefIndex);
pdef_air->speed = 0.0f;
pdef_air->speedaim = 0.0f;
pdef_air->rotoryrot = 0.0f;
pdef_air->rotaryspeed = 0.0f;
pdef_air->rotaryspeedaim = 0.0f;
pdef_air->yrot = 0.0f;
pdef_air->speedtime60 = -1.0f;
pdef_air->rotaryspeedtime = -1.0f;
pdef_air->ailist = ailistFindById(pdef_air->ailist);
pdef_air->aioffset = 0;
pdef_air->aireturnlist = -1;
pdef_air->nextstep = 0;
pdef_air->path = 0;
pdef_air->Sound = 0;
}
break;
case PROPDEF_TAG:
{
struct TagObjectRecord *pdef_tag;
struct ObjectRecord *taggedobj;
pdef_tag = (struct TagObjectRecord *) phead;
taggedobj = setupCommandGetObject(stageId, pdefIndex + ((s32) pdef_tag->OffsetToObj));
pdef_tag->TaggedObject = taggedobj;
if (taggedobj)
{
taggedobj->runtime_bitflags |= RUNTIMEBITFLAG_TAGGED;
}
set_parent_cur_tag_entry(pdef_tag);
break;
}
case PROPDEF_RENAME:
{
struct RenameObjectRecord *pdef_ren;
struct ObjectRecord *targetobj;
pdef_ren = (struct RenameObjectRecord *) phead;
i3 = pdef_ren->TagID + pdefIndex;
targetobj = setupCommandGetObject(stageId, i3);
pdef_ren->renobj = targetobj;
if (targetobj)
{
targetobj->runtime_bitflags |= RUNTIMEBITFLAG_DESTROYED;
}
bondinvAddTextOverride((struct textoverride *) pdef_ren);
break;
}
case PROPDEF_WATCH_MENU_OBJECTIVE_TEXT:
setup_briefing_text_entry_parent((struct setup_objective_text *) phead);
break;
case PROPDEF_CAMERAPOS:
{
struct CutsceneRecord *pdef_cam = (struct CutsceneRecord *) phead;
pdef_cam->pos.f[0] = (*((s32 *) (&pdef_cam->pos.f[0]))) / 100.0f;
pdef_cam->pos.f[1] = (*((s32 *) (&pdef_cam->pos.f[1]))) / 100.0f;
pdef_cam->pos.f[2] = (*((s32 *) (&pdef_cam->pos.f[2]))) / 100.0f;
pdef_cam->theta = (*((s32 *) (&pdef_cam->theta))) / M_U16_MAX_VALUE_F;
pdef_cam->verta = (*((s32 *) (&pdef_cam->verta))) / M_U16_MAX_VALUE_F;
break;
}
case PROPDEF_OBJECTIVE_START:
add_ptr_to_objective((struct objective_entry *) phead);
break;
case PROPDEF_OBJECTIVE_ENTER_ROOM:
set_parent_cur_obj_enter_room((struct criteria_roomentered *) phead);
break;
case PROPDEF_OBJECTIVE_DEPOSIT_OBJECT_IN_ROOM:
set_parent_cur_obj_deposited_in_room((struct criteria_deposit *) phead);
break;
case PROPDEF_OBJECTIVE_PHOTOGRAPH:
set_parent_cur_obj_photograph((struct criteria_picture *) phead);
break;
}
phead = (PropDefHeaderRecord *) (((u32 *) phead) + sizepropdef(phead));
pdefIndex++;
}
phead = g_CurrentSetup.propDefs;
pdefIndex = 0;
while (phead->type != PROPDEF_END)
{
switch (phead->type)
{
case PROPDEF_PROP:
case PROPDEF_KEY:
case PROPDEF_MAGAZINE:
case PROPDEF_COLLECTABLE:
case PROPDEF_MONITOR:
case PROPDEF_AMMO:
case PROPDEF_ARMOUR:
case PROPDEF_GAS_RELEASING:
case PROPDEF_UNK41:
case PROPDEF_GLASS:
case PROPDEF_SAFE:
case PROPDEF_TINTED_GLASS:
{
struct ObjectRecord *pdef_obj = (struct ObjectRecord *) phead;
if (pdef_obj->prop && (pdef_obj->flags & PROPFLAG_INSIDEANOTHEROBJ))
{
u32 offset = pdef_obj->pad;
struct ObjectRecord *inobj = setupCommandGetObject(stageId, offset + pdefIndex);
if (inobj && inobj->prop)
{
pdef_obj->runtime_bitflags |= RUNTIMEBITFLAG_HASOWNER;
modelSetScale(pdef_obj->model, pdef_obj->model->scale);
chrpropReparent(pdef_obj->prop, inobj->prop);
}
#ifdef DEBUG
//possibly wrong place
else
{
osSyncPrintf("inobj link not found for object number %d\n", pdefIndex + 1);
}
#endif
}
break;
}
case PROPDEF_LINK:
{
struct LinkRecord *pdef_link = (struct LinkRecord *) phead;
struct WeaponObjRecord *guna = (struct WeaponObjRecord *) setupGetPtrToCommandByIndex(pdef_link->Index1 + pdefIndex);
struct WeaponObjRecord *gunb = (struct WeaponObjRecord *) setupGetPtrToCommandByIndex(pdef_link->Index2 + pdefIndex);
if (guna && gunb)
{
if ((guna->type == PROPDEF_COLLECTABLE) && (gunb->type == PROPDEF_COLLECTABLE))
{
propweaponSetDual(guna, gunb);
}
#ifdef DEBUG
else
{
osSyncPrintf("link type wrong for doublegun object number %d\n", pdefIndex + 1);
}
}
else
{
osSyncPrintf("link not found for doublegun object number %d\n", pdefIndex + 1);
#endif
}
break;
}
case PROPDEF_SWITCH:
{
struct LinkRecord *pdef_switch;
struct ObjectRecord *doorA;
struct ObjectRecord *doorB;
s32 index1;
s32 index2;
pdef_switch = (struct LinkRecord *) phead;
index1 = pdef_switch->Index1;
index2 = pdef_switch->Index2;
doorA = (struct ObjectRecord *) setupCommandGetObject(stageId, pdefIndex + index1);
doorB = (struct ObjectRecord *) setupGetPtrToCommandByIndex(pdefIndex + index2);
if ((((doorA && doorA->prop) && doorB) && (doorB->type == PROPDEF_DOOR)) && doorB->prop)
{
pdef_switch->first = doorA->prop;
pdef_switch->second = doorB->prop;
initSetLevelLoadPropSwitch(pdef_switch);
doorA->runtime_bitflags |= RUNTIMEBITFLAG_00000001; // linked door
}
#ifdef DEBUG
else
{
osSyncPrintf("doorlink object number %d not initialised\n", pdefIndex + 1);
}
#endif
break;
}
case PROPDEF_SAFE_ITEM:
{
s32 index1;
struct SafeObjectRecord *pdef_safe;
s32 index2;
s32 index3;
struct ObjectRecord *safe_item;
struct SafeRecord *safe;
struct DoorRecord *door;
pdef_safe = (struct SafeObjectRecord *) phead;
index1 = pdef_safe->Index1;
index2 = pdef_safe->Index2;
index3 = pdef_safe->Index3;
safe_item = setupCommandGetObject(stageId, pdefIndex + index1);
safe = (struct SafeRecord *) setupCommandGetObject(stageId, pdefIndex + index2);
door = (struct DoorRecord *) setupCommandGetObject(stageId, pdefIndex + index3);
if (((((((safe_item && safe_item->prop) && safe) && safe->prop) && (safe->type == PROPDEF_SAFE)) && door) && door->prop) && (door->type == PROPDEF_DOOR))
{
pdef_safe->item = safe_item;
pdef_safe->safe = safe;
pdef_safe->door = door;
initSetLevelLoadPropSafeItem((struct ObjectRecord *) pdef_safe);
safe_item->flags2 |= PROPFLAG2_LINKEDTOSAFE;
door->flags2 |= PROPFLAG2_LINKEDTOSAFE;
}
#ifdef DEBUG
else
{
osSyncPrintf("safelink object number %d not initialised\n", pdefIndex + 1);
}
#endif
break;
}
case PROPDEF_LOCK_DOOR:
{
struct LockDoorRecord *pdef_lock_door;
struct DoorRecord *door;
struct ObjectRecord *lock;
s32 index1;
s32 index2;
pdef_lock_door = (struct LockDoorRecord *) phead;
index1 = pdef_lock_door->Index1;
index2 = pdef_lock_door->Index2;
door = (struct DoorRecord *) setupCommandGetObject(stageId, pdefIndex + index1);
lock = setupCommandGetObject(stageId, pdefIndex + index2);
if ((((door && door->prop) && lock) && lock->prop) && (door->type == PROPDEF_DOOR))
{
pdef_lock_door->door = door;
pdef_lock_door->lock = lock;
initSetLevelLoadPropLockDoor(pdef_lock_door);
door->runtime_bitflags |= RUNTIMEBITFLAG_PADLOCKEDDOOR;
}
#ifdef DEBUG
else
{
osSyncPrintf("doorlock object number %d not initialised\n", pdefIndex + 1);
}
#endif
break;
}
}
phead = (PropDefHeaderRecord *) (((u32 *) phead) + sizepropdef(phead));
pdefIndex += 1;
}
}
}
else
{
g_CurrentSetup.pathwaypoints = NULL;
g_CurrentSetup.waypointgroups = NULL;
g_CurrentSetup.intro = 0;
g_CurrentSetup.propDefs = 0;
g_CurrentSetup.patrolpaths = NULL;
g_CurrentSetup.ailists = NULL;
g_CurrentSetup.pads = NULL;
g_CurrentSetup.boundpads = NULL;
g_CurrentSetup.padnames = NULL;
g_CurrentSetup.boundpadnames = NULL;
alloc_init_GUARDdata_entries(0);
modelmgrAllocateModelSlots(0);
modelmgrAllocateAnimModelSlots(0);
}
alloc_false_GUARDdata_to_exec_global_action();
}