mirror of
https://gitlab.com/ryandwyer/perfect-dark
synced 2026-07-03 20:00:03 -04:00
1182 lines
30 KiB
C
1182 lines
30 KiB
C
#include <ultra64.h>
|
|
#include "constants.h"
|
|
#include "game/game_00b820.h"
|
|
#include "game/setup.h"
|
|
#include "game/playerreset.h"
|
|
#include "game/botmgr.h"
|
|
#include "game/chr.h"
|
|
#include "game/chrmgr.h"
|
|
#include "game/body.h"
|
|
#include "game/prop.h"
|
|
#include "game/setuputils.h"
|
|
#include "game/atan2f.h"
|
|
#include "game/inv.h"
|
|
#include "game/playermgr.h"
|
|
#include "game/bg.h"
|
|
#include "game/stagetable.h"
|
|
#include "game/file.h"
|
|
#include "game/lv.h"
|
|
#include "game/mplayer/scenarios.h"
|
|
#include "game/challenge.h"
|
|
#include "game/lang.h"
|
|
#include "game/mplayer/mplayer.h"
|
|
#include "game/pad.h"
|
|
#include "game/propobj.h"
|
|
#include "bss.h"
|
|
#include "lib/args.h"
|
|
#include "lib/memp.h"
|
|
#include "lib/model.h"
|
|
#include "lib/path.h"
|
|
#include "lib/rng.h"
|
|
#include "lib/mtx.h"
|
|
#include "lib/anim.h"
|
|
#include "lib/collision.h"
|
|
#include "lib/vars.h"
|
|
#include "data.h"
|
|
#include "types.h"
|
|
|
|
s32 var8009cc30;
|
|
u32 var8009cc34;
|
|
u32 var8009cc38;
|
|
u32 var8009cc3c;
|
|
|
|
s32 g_NumBots = 0;
|
|
|
|
u32 var80061bdc = 0x00000000;
|
|
f32 g_DoorScale = 1;
|
|
u32 var80061be4 = 0x00000000;
|
|
u32 var80061be8 = 0x00000000;
|
|
u32 var80061bec = 0x00000000;
|
|
|
|
void propsReset(bool withlaptops)
|
|
{
|
|
s32 i;
|
|
|
|
for (i = 0; i < ARRAYCOUNT(g_Lifts); i++) {
|
|
g_Lifts[i] = NULL;
|
|
}
|
|
|
|
g_MaxWeaponSlots = 50;
|
|
g_MaxAmmoCrates = 20;
|
|
g_MaxProjectiles = 20;
|
|
g_MaxEmbedments = 40;
|
|
|
|
if (g_Vars.stagenum >= STAGE_TITLE) {
|
|
g_MaxWeaponSlots = 0;
|
|
g_MaxAmmoCrates = 0;
|
|
g_MaxProjectiles = 0;
|
|
g_MaxEmbedments = 0;
|
|
}
|
|
|
|
setupResetProxyMines();
|
|
|
|
g_PlayersDetonatingMines = 0;
|
|
g_TintedGlassEnabled = false;
|
|
|
|
if (g_MaxWeaponSlots == 0) {
|
|
g_WeaponSlots = NULL;
|
|
} else {
|
|
g_WeaponSlots = mempAlloc(ALIGN16(g_MaxWeaponSlots * sizeof(struct weaponobj)), MEMPOOL_STAGE);
|
|
|
|
for (i = 0; i < g_MaxWeaponSlots; i++) {
|
|
g_WeaponSlots[i].base.prop = NULL;
|
|
}
|
|
|
|
g_NextWeaponSlot = 0;
|
|
}
|
|
|
|
if (g_MaxAmmoCrates == 0) {
|
|
g_AmmoCrates = NULL;
|
|
} else {
|
|
g_AmmoCrates = mempAlloc(ALIGN16(g_MaxAmmoCrates * sizeof(struct ammocrateobj)), MEMPOOL_STAGE);
|
|
|
|
for (i = 0; i < g_MaxAmmoCrates; i++) {
|
|
g_AmmoCrates[i].base.prop = NULL;
|
|
}
|
|
}
|
|
|
|
if (g_MaxProjectiles == 0) {
|
|
g_Projectiles = NULL;
|
|
} else {
|
|
g_Projectiles = mempAlloc(ALIGN16(g_MaxProjectiles * sizeof(struct projectile)), MEMPOOL_STAGE);
|
|
|
|
for (i = 0; i < g_MaxProjectiles; i++) {
|
|
g_Projectiles[i].flags = PROJECTILEFLAG_FREE;
|
|
}
|
|
}
|
|
|
|
if (g_MaxEmbedments == 0) {
|
|
g_Embedments = NULL;
|
|
} else {
|
|
g_Embedments = mempAlloc(ALIGN16(g_MaxEmbedments * sizeof(struct embedment)), MEMPOOL_STAGE);
|
|
|
|
for (i = 0; i < g_MaxEmbedments; i++) {
|
|
g_Embedments[i].flags = EMBEDMENTFLAG_FREE;
|
|
}
|
|
}
|
|
|
|
g_LiftDoors = NULL;
|
|
|
|
g_EmbedProp = NULL;
|
|
g_EmbedHitPart = -1;
|
|
g_AutogunAccuracyScale = 1;
|
|
g_AutogunDamageTxScale = 1;
|
|
g_AutogunDamageRxScale = 1;
|
|
g_AmmoQuantityScale = 1;
|
|
|
|
if (withlaptops) {
|
|
g_MaxThrownLaptops = PLAYERCOUNT() + g_NumBots;
|
|
g_ThrownLaptops = mempAlloc(ALIGN16(g_MaxThrownLaptops * sizeof(struct autogunobj)), MEMPOOL_STAGE);
|
|
g_ThrownLaptopBeams = mempAlloc(ALIGN16(g_MaxThrownLaptops * sizeof(struct beam)), MEMPOOL_STAGE);
|
|
|
|
for (i = 0; i < g_MaxThrownLaptops; i++) {
|
|
g_ThrownLaptops[i].base.prop = NULL;
|
|
}
|
|
} else {
|
|
g_MaxThrownLaptops = 0;
|
|
g_ThrownLaptops = NULL;
|
|
g_ThrownLaptopBeams = NULL;
|
|
}
|
|
}
|
|
|
|
void setupCreateLiftDoor(struct linkliftdoorobj *link)
|
|
{
|
|
link->next = g_LiftDoors;
|
|
g_LiftDoors = link;
|
|
}
|
|
|
|
void setupResetProxyMines(void)
|
|
{
|
|
s32 i;
|
|
|
|
for (i = 0; i < ARRAYCOUNT(g_Proxies); i++) {
|
|
g_Proxies[i] = NULL;
|
|
}
|
|
}
|
|
|
|
s32 setupCountCommandType(u32 type)
|
|
{
|
|
struct defaultobj *obj = (struct defaultobj *)g_StageSetup.props;
|
|
s32 count = 0;
|
|
|
|
if (obj) {
|
|
while (obj->type != OBJTYPE_END) {
|
|
if (obj->type == (u8)type) {
|
|
count++;
|
|
}
|
|
|
|
obj = (struct defaultobj *)((u32 *)obj + setupGetCmdLength((u32 *)obj));
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
void setupCreateObject(struct defaultobj *obj, s32 cmdindex)
|
|
{
|
|
f32 f0;
|
|
s32 modelnum;
|
|
struct pad pad;
|
|
Mtxf mtx;
|
|
struct coord centre;
|
|
f32 scale;
|
|
struct coord pos;
|
|
s16 rooms[8];
|
|
struct prop *prop2;
|
|
u32 flag40;
|
|
u32 stack;
|
|
struct chrdata *chr;
|
|
struct prop *prop;
|
|
|
|
modelnum = obj->modelnum;
|
|
setupLoadModeldef(modelnum);
|
|
scale = obj->extrascale * (1.0f / 256.0f);
|
|
|
|
if (g_Vars.normmplayerisrunning || g_Vars.lvmpbotlevel) {
|
|
obj->hidden2 |= OBJH2FLAG_CANREGEN;
|
|
}
|
|
|
|
if (obj->flags & OBJFLAG_INSIDEANOTHEROBJ) {
|
|
if (obj->type == OBJTYPE_WEAPON) {
|
|
func0f08ae0c((struct weaponobj *)obj, g_ModelStates[modelnum].filedata);
|
|
} else {
|
|
objInitWithModelDef(obj, g_ModelStates[modelnum].filedata);
|
|
}
|
|
|
|
modelSetScale(obj->model, obj->model->scale * scale);
|
|
return;
|
|
}
|
|
|
|
if (obj->flags & OBJFLAG_ASSIGNEDTOCHR) {
|
|
chr = chrFindByLiteralId(obj->pad);
|
|
|
|
if (chr && chr->prop && chr->model) {
|
|
if (obj->type == OBJTYPE_WEAPON) {
|
|
prop = func0f08ae0c((struct weaponobj *)obj, g_ModelStates[modelnum].filedata);
|
|
} else {
|
|
prop = objInitWithModelDef(obj, g_ModelStates[modelnum].filedata);
|
|
}
|
|
|
|
modelSetScale(obj->model, obj->model->scale * scale);
|
|
propReparent(prop, chr->prop);
|
|
}
|
|
} else {
|
|
if (obj->pad < 0) {
|
|
if (obj->type == OBJTYPE_WEAPON) {
|
|
func0f08ae0c((struct weaponobj *)obj, g_ModelStates[modelnum].filedata);
|
|
} else {
|
|
objInitWithModelDef(obj, g_ModelStates[modelnum].filedata);
|
|
}
|
|
|
|
modelSetScale(obj->model, obj->model->scale * scale);
|
|
return;
|
|
}
|
|
|
|
padUnpack(obj->pad, PADFIELD_POS | PADFIELD_LOOK | PADFIELD_UP | PADFIELD_BBOX | PADFIELD_ROOM, &pad);
|
|
|
|
if (pad.room > 0) {
|
|
mtx00016d58(&mtx, 0, 0, 0, -pad.look.x, -pad.look.y, -pad.look.z, pad.up.x, pad.up.y, pad.up.z);
|
|
|
|
pos.x = pad.pos.x;
|
|
pos.y = pad.pos.y;
|
|
pos.z = pad.pos.z;
|
|
|
|
rooms[0] = pad.room;
|
|
rooms[1] = -1;
|
|
|
|
if (!padHasBboxData(obj->pad)) {
|
|
if (obj->flags & OBJFLAG_00000002) {
|
|
centre.x = pad.pos.x;
|
|
centre.y = pad.pos.y;
|
|
centre.z = pad.pos.z;
|
|
} else {
|
|
centre.x = pad.pos.x;
|
|
centre.y = pad.pos.y;
|
|
centre.z = pad.pos.z;
|
|
}
|
|
} else {
|
|
padGetCentre(obj->pad, ¢re);
|
|
centre.x += (pad.bbox.ymin - pad.bbox.ymax) * 0.5f * pad.up.x;
|
|
centre.y += (pad.bbox.ymin - pad.bbox.ymax) * 0.5f * pad.up.y;
|
|
centre.z += (pad.bbox.ymin - pad.bbox.ymax) * 0.5f * pad.up.z;
|
|
}
|
|
|
|
if (obj->type == OBJTYPE_WEAPON) {
|
|
prop2 = func0f08ae0c((struct weaponobj *)obj, g_ModelStates[modelnum].filedata);
|
|
} else {
|
|
prop2 = objInitWithAutoModel(obj);
|
|
}
|
|
|
|
if (padHasBboxData(obj->pad)) {
|
|
struct modelrodata_bbox *bbox = objFindBboxRodata(obj);
|
|
|
|
if (bbox != NULL) {
|
|
f32 xscale = 1.0f;
|
|
f32 yscale = 1.0f;
|
|
f32 zscale = 1.0f;
|
|
f32 minscale;
|
|
f32 maxscale;
|
|
|
|
flag40 = OBJFLAG_00000040;
|
|
|
|
if (obj->flags & OBJFLAG_00000020) {
|
|
if (bbox->xmin < bbox->xmax) {
|
|
if (obj->flags & OBJFLAG_00000002) {
|
|
xscale = (pad.bbox.xmax - pad.bbox.xmin) / ((bbox->xmax - bbox->xmin) * obj->model->scale);
|
|
} else {
|
|
xscale = (pad.bbox.xmax - pad.bbox.xmin) / ((bbox->xmax - bbox->xmin) * obj->model->scale);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (obj->flags & flag40) {
|
|
if (bbox->ymin < bbox->ymax) {
|
|
if (obj->flags & OBJFLAG_00000002) {
|
|
zscale = (pad.bbox.zmax - pad.bbox.zmin) / ((bbox->ymax - bbox->ymin) * obj->model->scale);
|
|
} else {
|
|
yscale = (pad.bbox.ymax - pad.bbox.ymin) / ((bbox->ymax - bbox->ymin) * obj->model->scale);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (obj->flags & OBJFLAG_00000080) {
|
|
if (bbox->zmin < bbox->zmax) {
|
|
if (obj->flags & OBJFLAG_00000002) {
|
|
yscale = (pad.bbox.ymax - pad.bbox.ymin) / ((bbox->zmax - bbox->zmin) * obj->model->scale);
|
|
} else {
|
|
zscale = (pad.bbox.zmax - pad.bbox.zmin) / ((bbox->zmax - bbox->zmin) * obj->model->scale);
|
|
}
|
|
}
|
|
}
|
|
|
|
minscale = xscale;
|
|
|
|
if (yscale < minscale) {
|
|
minscale = yscale;
|
|
}
|
|
|
|
if (zscale < minscale) {
|
|
minscale = zscale;
|
|
}
|
|
|
|
maxscale = xscale;
|
|
|
|
if (yscale > maxscale) {
|
|
maxscale = yscale;
|
|
}
|
|
|
|
if (zscale > maxscale) {
|
|
maxscale = zscale;
|
|
}
|
|
|
|
if ((obj->flags & OBJFLAG_00000020) == 0) {
|
|
if (obj->flags & OBJFLAG_00000002) {
|
|
if (bbox->xmax == bbox->xmin) {
|
|
xscale = maxscale;
|
|
}
|
|
} else if (bbox->xmax == bbox->xmin) {
|
|
xscale = maxscale;
|
|
}
|
|
}
|
|
|
|
if ((u32)(obj->flags & flag40) == 0) {
|
|
if (obj->flags & OBJFLAG_00000002) {
|
|
if (bbox->ymax == bbox->ymin) {
|
|
zscale = maxscale;
|
|
}
|
|
} else if (bbox->ymax == bbox->ymin) {
|
|
yscale = maxscale;
|
|
}
|
|
}
|
|
|
|
if ((obj->flags & OBJFLAG_00000080) == 0) {
|
|
if (obj->flags & OBJFLAG_00000002) {
|
|
if (bbox->zmax == bbox->zmin) {
|
|
yscale = maxscale;
|
|
}
|
|
} else if (bbox->zmax == bbox->zmin) {
|
|
zscale = maxscale;
|
|
}
|
|
}
|
|
|
|
xscale /= maxscale;
|
|
yscale /= maxscale;
|
|
zscale /= maxscale;
|
|
|
|
if (xscale <= 0.000001f || yscale <= 0.000001f || zscale <= 0.000001f) {
|
|
xscale = yscale = zscale = 1;
|
|
}
|
|
|
|
mtx00015e24(xscale, &mtx);
|
|
mtx00015e80(yscale, &mtx);
|
|
mtx00015edc(zscale, &mtx);
|
|
|
|
modelSetScale(obj->model, obj->model->scale * maxscale);
|
|
}
|
|
}
|
|
|
|
modelSetScale(obj->model, obj->model->scale * scale);
|
|
mtx00015f04(obj->model->scale, &mtx);
|
|
|
|
if (obj->flags2 & OBJFLAG2_00020000) {
|
|
prop2->flags |= PROPFLAG_DONTPAUSE;
|
|
}
|
|
|
|
if (obj->flags & OBJFLAG_00000002) {
|
|
func0f06ab60(obj, &pos, &mtx, rooms, ¢re);
|
|
} else {
|
|
func0f06a730(obj, &pos, &mtx, rooms, ¢re);
|
|
}
|
|
|
|
if (obj->hidden & OBJHFLAG_00008000) {
|
|
propActivateThisFrame(prop2);
|
|
} else {
|
|
propActivate(prop2);
|
|
}
|
|
|
|
propEnable(prop2);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Assigns a weapon to its home.
|
|
*
|
|
* Its home is a chr's hand or a pad, as defined in the stage's setup file.
|
|
*
|
|
* The Marquis of Queensbury Rules (everyone unarmed) and Enemy Rockets cheats
|
|
* are implemented here.
|
|
*/
|
|
void setupPlaceWeapon(struct weaponobj *weapon, s32 cmdindex)
|
|
{
|
|
if (weapon->base.flags & OBJFLAG_ASSIGNEDTOCHR) {
|
|
u32 stack[2];
|
|
struct chrdata *chr = chrFindByLiteralId(weapon->base.pad);
|
|
|
|
if (chr && chr->prop && chr->model) {
|
|
modelmgrLoadProjectileModeldefs(weapon->weaponnum);
|
|
func0f08b25c(weapon, chr);
|
|
}
|
|
} else {
|
|
bool giveweapon = true;
|
|
|
|
if (g_Vars.normmplayerisrunning || g_Vars.lvmpbotlevel) {
|
|
struct mpweapon *mpweapon;
|
|
s32 mpweaponnum;
|
|
|
|
var8009cc30 = -1;
|
|
|
|
// Seems like a weaponnum >= 240 means an mpweaponnum...
|
|
switch (weapon->weaponnum) {
|
|
case 0xf0:
|
|
case 0xf1:
|
|
case 0xf2:
|
|
case 0xf3:
|
|
case 0xf4:
|
|
case 0xf5:
|
|
case 0xf6:
|
|
case 0xf7:
|
|
case 0xf8:
|
|
case 0xf9:
|
|
case 0xfa:
|
|
case 0xfb:
|
|
case 0xfc:
|
|
case 0xfd:
|
|
case 0xfe:
|
|
case 0xff:
|
|
mpweaponnum = weapon->weaponnum - 0xf0;
|
|
mpweapon = func0f188e24(mpweaponnum);
|
|
var8009cc30 = mpweaponnum;
|
|
weapon->weaponnum = mpweapon->weaponnum;
|
|
weapon->base.modelnum = mpweapon->model;
|
|
weapon->base.extrascale = mpweapon->extrascale;
|
|
giveweapon = mpweapon->giveweapon;
|
|
|
|
if (mpweapon->weaponnum == WEAPON_MPSHIELD) {
|
|
struct shieldobj *shield = (struct shieldobj *)weapon;
|
|
shield->base.modelnum = MODEL_CHRSHIELD;
|
|
shield->base.type = OBJTYPE_SHIELD;
|
|
shield->base.flags |= OBJFLAG_01000000 | OBJFLAG_INVINCIBLE;
|
|
shield->base.flags2 |= OBJFLAG2_00200000 | OBJFLAG2_IMMUNETOGUNFIRE;
|
|
shield->initialamount = 1;
|
|
shield->amount = 1;
|
|
setupCreateObject(&shield->base, cmdindex);
|
|
giveweapon = false;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (weapon->weaponnum != WEAPON_NONE && giveweapon) {
|
|
modelmgrLoadProjectileModeldefs(weapon->weaponnum);
|
|
setupCreateObject(&weapon->base, cmdindex);
|
|
}
|
|
}
|
|
}
|
|
|
|
s32 setupGetPortalByPad(s32 padnum)
|
|
{
|
|
f32 mult;
|
|
struct coord centre;
|
|
struct coord coord;
|
|
u32 stack;
|
|
struct pad pad;
|
|
|
|
padGetCentre(padnum, ¢re);
|
|
padUnpack(padnum, PADFIELD_BBOX | PADFIELD_UP, &pad);
|
|
|
|
mult = (pad.bbox.ymax - pad.bbox.ymin) * 0.5f + 10;
|
|
|
|
coord.x = pad.up.x * mult + centre.x;
|
|
coord.y = pad.up.y * mult + centre.y;
|
|
coord.z = pad.up.z * mult + centre.z;
|
|
|
|
centre.x = centre.x - pad.up.x * mult;
|
|
centre.y = centre.y - pad.up.y * mult;
|
|
centre.z = centre.z - pad.up.z * mult;
|
|
|
|
return bg0f164e8c(¢re, &coord);
|
|
}
|
|
|
|
s32 setupGetPortalByDoorPad(s32 padnum)
|
|
{
|
|
f32 mult;
|
|
struct coord centre;
|
|
struct coord coord;
|
|
u32 stack;
|
|
struct pad pad;
|
|
|
|
padGetCentre(padnum, ¢re);
|
|
padUnpack(padnum, PADFIELD_BBOX | PADFIELD_NORMAL, &pad);
|
|
|
|
mult = (pad.bbox.xmax - pad.bbox.xmin) * 0.5f + 10;
|
|
|
|
coord.x = pad.normal.x * mult + centre.x;
|
|
coord.y = pad.normal.y * mult + centre.y;
|
|
coord.z = pad.normal.z * mult + centre.z;
|
|
|
|
centre.x = centre.x - pad.normal.x * mult;
|
|
centre.y = centre.y - pad.normal.y * mult;
|
|
centre.z = centre.z - pad.normal.z * mult;
|
|
|
|
return bg0f164e8c(¢re, &coord);
|
|
}
|
|
|
|
void setupCreateDoor(struct doorobj *door, s32 cmdindex)
|
|
{
|
|
f32 scale;
|
|
s32 modelnum = door->base.modelnum;
|
|
s32 portalnum = -1;
|
|
struct pad pad;
|
|
|
|
setupLoadModeldef(modelnum);
|
|
|
|
if (door->doorflags & DOORFLAG_ROTATEDPAD) {
|
|
padRotateForDoor(door->base.pad);
|
|
}
|
|
|
|
if (door->base.flags & OBJFLAG_DOOR_HASPORTAL) {
|
|
portalnum = setupGetPortalByDoorPad(door->base.pad);
|
|
}
|
|
|
|
padUnpack(door->base.pad, PADFIELD_POS | PADFIELD_LOOK | PADFIELD_UP | PADFIELD_NORMAL | PADFIELD_BBOX | PADFIELD_ROOM, &pad);
|
|
|
|
if (g_DoorScale != 1) {
|
|
pad.bbox.xmin *= g_DoorScale;
|
|
pad.bbox.xmax *= g_DoorScale;
|
|
|
|
// If the door has a portal, adjust the pad's bbox to match the portal's dimensions
|
|
if (portalnum >= 0) {
|
|
struct var800a4ccc *ptr = &var800a4ccc[portalnum];
|
|
f32 f0 = pad.pos.f[0] * ptr->coord.f[0] + pad.pos.f[1] * ptr->coord.f[1] + pad.pos.f[2] * ptr->coord.f[2];
|
|
f32 min = ptr->min;
|
|
struct coord sp150;
|
|
f0 = (f0 - min) * (g_DoorScale - 1);
|
|
|
|
sp150.x = ptr->coord.x * f0;
|
|
sp150.y = ptr->coord.y * f0;
|
|
sp150.z = ptr->coord.z * f0;
|
|
|
|
f0 = sp150.f[0] * pad.normal.f[0] + sp150.f[1] * pad.normal.f[1] + sp150.f[2] * pad.normal.f[2];
|
|
pad.bbox.xmin += f0;
|
|
pad.bbox.xmax += f0;
|
|
|
|
f0 = sp150.f[0] * pad.up.f[0] + sp150.f[1] * pad.up.f[1] + sp150.f[2] * pad.up.f[2];
|
|
pad.bbox.ymin += f0;
|
|
pad.bbox.ymax += f0;
|
|
|
|
f0 = sp150.f[0] * pad.look.f[0] + sp150.f[1] * pad.look.f[1] + sp150.f[2] * pad.look.f[2];
|
|
pad.bbox.zmin += f0;
|
|
pad.bbox.zmax += f0;
|
|
}
|
|
|
|
// Write the modified bbox into the pad file data
|
|
padCopyBboxFromPad(door->base.pad, &pad);
|
|
}
|
|
|
|
if (pad.room > 0) {
|
|
Mtxf sp110;
|
|
struct prop *prop;
|
|
s32 siblingcmdindex;
|
|
struct coord pos;
|
|
s16 rooms[8];
|
|
Mtxf finalmtx;
|
|
struct coord centre;
|
|
Mtxf zrotmtx;
|
|
struct coord sp54;
|
|
f32 xscale;
|
|
f32 yscale;
|
|
f32 zscale;
|
|
struct modelrodata_bbox *bbox;
|
|
|
|
bbox = modelFileDataFindBboxRodata(g_ModelStates[modelnum].filedata);
|
|
|
|
mtx00016d58(&sp110, 0, 0, 0,
|
|
-pad.look.x, -pad.look.y, -pad.look.z,
|
|
pad.up.x, pad.up.y, pad.up.z);
|
|
mtx4LoadXRotation(1.5705462694168f, &finalmtx);
|
|
mtx4LoadZRotation(1.5705462694168f, &zrotmtx);
|
|
mtx4MultMtx4InPlace(&zrotmtx, &finalmtx);
|
|
mtx4MultMtx4InPlace(&sp110, &finalmtx);
|
|
|
|
padGetCentre(door->base.pad, ¢re);
|
|
|
|
xscale = (pad.bbox.ymax - pad.bbox.ymin) / (bbox->xmax - bbox->xmin);
|
|
yscale = (pad.bbox.zmax - pad.bbox.zmin) / (bbox->ymax - bbox->ymin);
|
|
zscale = (pad.bbox.xmax - pad.bbox.xmin) / (bbox->zmax - bbox->zmin);
|
|
|
|
if (xscale <= 0.000001f || yscale <= 0.000001f || zscale <= 0.000001f) {
|
|
xscale = yscale = zscale = 1;
|
|
}
|
|
|
|
mtx00015e24(xscale, &finalmtx);
|
|
mtx00015e80(yscale, &finalmtx);
|
|
mtx00015edc(zscale, &finalmtx);
|
|
|
|
pos.x = pad.pos.x;
|
|
pos.y = pad.pos.y;
|
|
pos.z = pad.pos.z;
|
|
|
|
rooms[0] = pad.room;
|
|
rooms[1] = -1;
|
|
|
|
if (door->doortype == DOORTYPE_VERTICAL || door->doortype == DOORTYPE_FALLAWAY) {
|
|
sp54.x = pad.look.f[0] * (pad.bbox.zmax - pad.bbox.zmin);
|
|
sp54.y = pad.look.f[1] * (pad.bbox.zmax - pad.bbox.zmin);
|
|
sp54.z = pad.look.f[2] * (pad.bbox.zmax - pad.bbox.zmin);
|
|
} else {
|
|
sp54.x = pad.up.f[0] * (pad.bbox.ymin - pad.bbox.ymax);
|
|
sp54.y = pad.up.f[1] * (pad.bbox.ymin - pad.bbox.ymax);
|
|
sp54.z = pad.up.f[2] * (pad.bbox.ymin - pad.bbox.ymax);
|
|
}
|
|
|
|
// 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;
|
|
door->accel = PALUPF(*(s32 *) &door->accel) / 65536000.0f;
|
|
door->decel = PALUPF(*(s32 *) &door->decel) / 65536000.0f;
|
|
door->maxspeed = PALUPF(*(s32 *) &door->maxspeed) / 65536.0f;
|
|
|
|
// The sibling door is stored as a relative command number,
|
|
// but at runtime it's a pointer.
|
|
if (door->sibling) {
|
|
siblingcmdindex = *(s32 *) &door->sibling + cmdindex;
|
|
door->sibling = (struct doorobj *) setupGetCmdByIndex(siblingcmdindex);
|
|
}
|
|
|
|
prop = doorInit(door, &pos, &finalmtx, rooms, &sp54, ¢re);
|
|
|
|
if (door->base.flags & OBJFLAG_DOOR_HASPORTAL) {
|
|
door->portalnum = portalnum;
|
|
|
|
if (door->portalnum >= 0 && door->frac == 0) {
|
|
doorDeactivatePortal(door);
|
|
}
|
|
}
|
|
|
|
if (door->base.model) {
|
|
scale = xscale;
|
|
|
|
if (yscale > scale) {
|
|
scale = yscale;
|
|
}
|
|
|
|
if (zscale > scale) {
|
|
scale = zscale;
|
|
}
|
|
|
|
modelSetScale(door->base.model, door->base.model->scale * scale);
|
|
}
|
|
|
|
propActivate(prop);
|
|
propEnable(prop);
|
|
} else {
|
|
door->base.prop = NULL;
|
|
}
|
|
}
|
|
|
|
void setupCreateHov(struct defaultobj *obj, struct hov *hov)
|
|
{
|
|
hov->unk04 = 0;
|
|
hov->unk08 = 0;
|
|
hov->unk0c = 0;
|
|
hov->unk10 = atan2f(obj->realrot[2][0], obj->realrot[2][2]);
|
|
hov->unk14 = 0;
|
|
hov->unk18 = 0;
|
|
hov->unk1c = 0;
|
|
hov->unk20 = 0;
|
|
hov->unk24 = 0;
|
|
hov->unk28 = 0;
|
|
hov->unk2c = 0;
|
|
hov->unk30 = 0;
|
|
hov->ground = 0;
|
|
hov->nexttick60 = -1;
|
|
hov->prevtick60 = -1;
|
|
}
|
|
|
|
void setupLoadFiles(s32 stagenum)
|
|
{
|
|
s32 i;
|
|
s32 j;
|
|
s32 numchrs = 0;
|
|
s32 numobjs = 0;
|
|
s32 extra;
|
|
struct stagesetup *setup;
|
|
u16 filenum;
|
|
bool modified;
|
|
|
|
g_DoorScale = 1;
|
|
|
|
for (i = 0; i < NUM_MODELS; i++) {
|
|
g_ModelStates[i].filedata = NULL;
|
|
}
|
|
|
|
if (stagenum < STAGE_TITLE) {
|
|
if (g_Vars.normmplayerisrunning) {
|
|
filenum = g_Stages[g_StageIndex].mpsetupfileid;
|
|
} else {
|
|
filenum = g_Stages[g_StageIndex].setupfileid;
|
|
}
|
|
|
|
g_LoadType = LOADTYPE_SETUP;
|
|
|
|
g_GeCreditsData = (u8 *)fileLoadToNew(filenum, FILELOADMETHOD_DEFAULT);
|
|
setup = (struct stagesetup *)g_GeCreditsData;
|
|
langLoad(langGetLangBankIndexFromStagenum(stagenum));
|
|
|
|
g_StageSetup.intro = (s32 *)((u32)setup + (u32)setup->intro);
|
|
g_StageSetup.props = (u32 *)((u32)setup + (u32)setup->props);
|
|
g_StageSetup.paths = (struct path *)((u32)setup + (u32)setup->paths);
|
|
|
|
g_LoadType = LOADTYPE_PADS;
|
|
|
|
g_StageSetup.padfiledata = fileLoadToNew(g_Stages[g_StageIndex].padsfileid, FILELOADMETHOD_DEFAULT);
|
|
|
|
g_StageSetup.waypoints = NULL;
|
|
g_StageSetup.waygroups = NULL;
|
|
g_StageSetup.cover = NULL;
|
|
|
|
// Convert path pad pointers from file-local to proper pointers
|
|
// and calculate the path lengths
|
|
if (g_StageSetup.paths) {
|
|
for (i = 0; g_StageSetup.paths[i].pads != NULL; i++) {
|
|
g_StageSetup.paths[i].pads = (s32 *)((u32)g_StageSetup.paths[i].pads + (u32)setup);
|
|
|
|
for (j = 0; g_StageSetup.paths[i].pads[j] >= 0; j++);
|
|
|
|
g_StageSetup.paths[i].len = j;
|
|
}
|
|
}
|
|
|
|
// Count the number of objects so enough model slots can be allocated
|
|
numchrs += setupCountCommandType(OBJTYPE_CHR);
|
|
|
|
numobjs += setupCountCommandType(OBJTYPE_WEAPON);
|
|
numobjs += setupCountCommandType(OBJTYPE_KEY);
|
|
numobjs += setupCountCommandType(OBJTYPE_HAT);
|
|
numobjs += setupCountCommandType(OBJTYPE_DOOR);
|
|
numobjs += setupCountCommandType(OBJTYPE_CCTV);
|
|
numobjs += setupCountCommandType(OBJTYPE_AUTOGUN);
|
|
numobjs += setupCountCommandType(OBJTYPE_HANGINGMONITORS);
|
|
numobjs += setupCountCommandType(OBJTYPE_SINGLEMONITOR);
|
|
numobjs += setupCountCommandType(OBJTYPE_MULTIMONITOR);
|
|
numobjs += setupCountCommandType(OBJTYPE_SHIELD);
|
|
numobjs += setupCountCommandType(OBJTYPE_BASIC);
|
|
numobjs += setupCountCommandType(OBJTYPE_DEBRIS);
|
|
numobjs += setupCountCommandType(OBJTYPE_GLASS);
|
|
numobjs += setupCountCommandType(OBJTYPE_TINTEDGLASS);
|
|
numobjs += setupCountCommandType(OBJTYPE_SAFE);
|
|
numobjs += setupCountCommandType(OBJTYPE_29);
|
|
numobjs += setupCountCommandType(OBJTYPE_GASBOTTLE);
|
|
numobjs += setupCountCommandType(OBJTYPE_ALARM);
|
|
numobjs += setupCountCommandType(OBJTYPE_AMMOCRATE);
|
|
numobjs += setupCountCommandType(OBJTYPE_MULTIAMMOCRATE);
|
|
numobjs += setupCountCommandType(OBJTYPE_TRUCK);
|
|
numobjs += setupCountCommandType(OBJTYPE_TANK);
|
|
numobjs += setupCountCommandType(OBJTYPE_LIFT);
|
|
numobjs += setupCountCommandType(OBJTYPE_HOVERPROP);
|
|
numobjs += setupCountCommandType(OBJTYPE_FAN);
|
|
numobjs += setupCountCommandType(OBJTYPE_HOVERCAR);
|
|
numobjs += setupCountCommandType(OBJTYPE_CHOPPER);
|
|
numobjs += setupCountCommandType(OBJTYPE_HELI);
|
|
numobjs += setupCountCommandType(OBJTYPE_ESCASTEP);
|
|
|
|
if (g_Vars.normmplayerisrunning) {
|
|
numobjs += scenarioNumProps();
|
|
}
|
|
} else {
|
|
// cover isn't set to NULL here... I guess it's not important
|
|
g_StageSetup.waypoints = NULL;
|
|
g_StageSetup.waygroups = NULL;
|
|
g_StageSetup.intro = 0;
|
|
g_StageSetup.props = 0;
|
|
g_StageSetup.paths = NULL;
|
|
g_StageSetup.ailists = NULL;
|
|
g_StageSetup.padfiledata = NULL;
|
|
}
|
|
|
|
g_ModelNumObjs = numobjs;
|
|
g_Vars.maxprops = numobjs + MAX_DROPPED_ITEMS;
|
|
}
|
|
|
|
s32 setupGetNumRequestedBots(void)
|
|
{
|
|
s32 i;
|
|
s32 numbots = 0;
|
|
|
|
if (g_Vars.normmplayerisrunning && mpHasSimulants()) {
|
|
for (i = 0; i < MAX_BOTS; i++) {
|
|
if ((g_MpSetup.chrslots & (1 << (i + 4))) && mpIsSimSlotEnabled(i)) {
|
|
numbots += g_BotConfigsArray[i].quantity;
|
|
}
|
|
}
|
|
}
|
|
|
|
return numbots;
|
|
}
|
|
|
|
s32 setupCalculateMaxBots(s32 numrequested, bool haslaptops)
|
|
{
|
|
return numrequested > 8 ? 8 : numrequested;
|
|
}
|
|
|
|
bool g_DebugEnable = false;
|
|
|
|
void setupAllocateEverything(void)
|
|
{
|
|
s32 numhumans;
|
|
s32 numbotsrequested;
|
|
bool haslaptops = false;
|
|
s32 botcfgnum;
|
|
s32 i;
|
|
s16 *killcounts;
|
|
s32 chrnum = 0;
|
|
|
|
numhumans = PLAYERCOUNT();
|
|
|
|
// Count how many bots were requested
|
|
numbotsrequested = setupGetNumRequestedBots();
|
|
|
|
// Check if we have laptop guns in our setup
|
|
haslaptops = false;
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
if (g_MpSetup.weapons[i] == MPWEAPON_LAPTOPGUN) {
|
|
haslaptops = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Figure out how many we can allocate based on available memory
|
|
g_NumBots = setupCalculateMaxBots(numbotsrequested, haslaptops);
|
|
|
|
// Allocate everything
|
|
modelmgrAllocateSlots(g_ModelNumObjs, PLAYERCOUNT() + g_NumBots, haslaptops);
|
|
|
|
g_Vars.maxprops += PLAYERCOUNT() + g_NumBots;
|
|
|
|
varsReset();
|
|
propsReset(haslaptops);
|
|
|
|
chrmgrReset();
|
|
chrmgrConfigure(g_NumBots);
|
|
|
|
g_MpNumChrs = numhumans + g_NumBots;
|
|
|
|
g_MpChrs = mempAlloc(g_MpNumChrs * sizeof(struct mpchr), MEMPOOL_STAGE);
|
|
|
|
killcounts = mempAlloc(g_MpNumChrs * g_MpNumChrs * sizeof(s16), MEMPOOL_STAGE);
|
|
|
|
g_MpRankings = mempAlloc(MAX(8, g_MpNumChrs) * sizeof(struct ranking), MEMPOOL_STAGE);
|
|
|
|
for (i = 0; i < g_MpNumChrs * g_MpNumChrs; i++) {
|
|
killcounts[i] = 0;
|
|
}
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
if (g_MpSetup.chrslots & (1 << i)) {
|
|
// player->prop is null here, so chr gets copied later on in playerReset
|
|
g_MpChrs[chrnum].isbot = false;
|
|
g_MpChrs[chrnum].team = g_PlayerConfigsArray[i].base.team;
|
|
g_MpChrs[chrnum].playerconfig = &g_PlayerConfigsArray[i];
|
|
g_MpChrs[chrnum].placement = 0;
|
|
g_MpChrs[chrnum].rankablescore = 0;
|
|
g_MpChrs[chrnum].killcounts = &killcounts[chrnum * g_MpNumChrs];
|
|
g_MpChrs[chrnum].numdeaths = 0;
|
|
g_MpChrs[chrnum].numpoints = 0;
|
|
|
|
chrnum++;
|
|
}
|
|
}
|
|
|
|
if (mpHasSimulants()) {
|
|
s32 botnum = 0;
|
|
s32 botconfignum;
|
|
|
|
for (botcfgnum = 0; botcfgnum < MAX_BOTS; botcfgnum++) {
|
|
if ((g_MpSetup.chrslots & (1 << (botcfgnum + 4))) && mpIsSimSlotEnabled(botcfgnum)) {
|
|
for (i = 0; i < g_BotConfigsArray[botcfgnum].quantity; i++) {
|
|
g_MpChrs[chrnum].isbot = true;
|
|
g_MpChrs[chrnum].team = g_BotConfigsArray[botcfgnum].base.team;
|
|
g_MpChrs[chrnum].botconfig = &g_BotConfigsArray[botcfgnum];
|
|
g_MpChrs[chrnum].chr = NULL;
|
|
g_MpChrs[chrnum].placement = 0;
|
|
g_MpChrs[chrnum].rankablescore = 0;
|
|
g_MpChrs[chrnum].killcounts = &killcounts[chrnum * g_MpNumChrs];
|
|
g_MpChrs[chrnum].numdeaths = 0;
|
|
g_MpChrs[chrnum].numpoints = 0;
|
|
|
|
botmgrAllocateBot(chrnum, botcfgnum, botnum);
|
|
botnum++;
|
|
chrnum++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
scenarioInitProps();
|
|
}
|
|
|
|
void setupCreateProps(s32 stagenum)
|
|
{
|
|
s32 withchrs = !argFindByPrefix(1, "-nochr") && !argFindByPrefix(1, "-noprop");
|
|
s32 withobjs = !argFindByPrefix(1, "-noobj") && !argFindByPrefix(1, "-noprop");
|
|
s32 withhovercars;
|
|
s32 escstepx;
|
|
s32 escstepy;
|
|
struct defaultobj *obj;
|
|
s32 i;
|
|
s32 j;
|
|
s32 liftnum = 0;
|
|
|
|
withhovercars = true;
|
|
|
|
escstepx = 0;
|
|
escstepy = 0;
|
|
g_Vars.textoverrides = NULL;
|
|
|
|
for (j = 0; j != 6; j++) {
|
|
g_Briefing.objectivenames[j] = 0;
|
|
g_Briefing.objectivedifficulties[j] = 0;
|
|
}
|
|
|
|
g_Briefing.briefingtextnum = L_MISC_042; // "No briefing for this mission"
|
|
|
|
if (stagenum < STAGE_TITLE) {
|
|
if (g_StageSetup.padfiledata) {
|
|
setupPreparePads();
|
|
}
|
|
|
|
setupLoadWaypoints();
|
|
|
|
for (j = 0; j < PLAYERCOUNT(); j++) {
|
|
setCurrentPlayerNum(j);
|
|
invInit();
|
|
}
|
|
|
|
if (g_StageSetup.props) {
|
|
u32 diffflag = 0;
|
|
s32 index;
|
|
|
|
diffflag |= 1 << (lvGetDifficulty() + 4);
|
|
|
|
if (g_Vars.mplayerisrunning) {
|
|
if (PLAYERCOUNT() == 2) {
|
|
diffflag |= OBJFLAG2_EXCLUDE_2P;
|
|
} else if (PLAYERCOUNT() == 3) {
|
|
diffflag |= OBJFLAG2_EXCLUDE_3P;
|
|
} else if (PLAYERCOUNT() == 4) {
|
|
diffflag |= OBJFLAG2_EXCLUDE_4P;
|
|
}
|
|
}
|
|
|
|
setupAllocateEverything();
|
|
|
|
index = 0;
|
|
|
|
obj = (struct defaultobj *)g_StageSetup.props;
|
|
|
|
while (obj->type != OBJTYPE_END) {
|
|
switch (obj->type) {
|
|
case OBJTYPE_DOOR:
|
|
if (withobjs && (obj->flags2 & diffflag) == 0) {
|
|
setupCreateDoor((struct doorobj *)obj, index);
|
|
}
|
|
break;
|
|
case OBJTYPE_WEAPON:
|
|
if (withchrs && (obj->flags2 & diffflag) == 0) {
|
|
setupPlaceWeapon((struct weaponobj *)obj, index);
|
|
}
|
|
break;
|
|
case OBJTYPE_TINTEDGLASS:
|
|
if (withobjs && (obj->flags2 & diffflag) == 0) {
|
|
if (obj->flags & OBJFLAG_GLASS_HASPORTAL) {
|
|
struct tintedglassobj *glass = (struct tintedglassobj *)obj;
|
|
glass->portalnum = setupGetPortalByPad(obj->pad);
|
|
glass->unk64 = *(s32 *)&glass->unk64 / 65536.0f;
|
|
}
|
|
|
|
setupCreateObject(obj, index);
|
|
}
|
|
break;
|
|
case OBJTYPE_LIFT:
|
|
if (withobjs && (obj->flags2 & diffflag) == 0) {
|
|
struct liftobj *lift = (struct liftobj *)obj;
|
|
struct modelstate *modelstate;
|
|
s32 modelnum = obj->modelnum;
|
|
struct prop *prop;
|
|
s32 i;
|
|
|
|
lift->accel = PALUPF(*(s32 *)&lift->accel) / 65536.0f;
|
|
lift->maxspeed = PALUPF(*(s32 *)&lift->maxspeed) / 65536.0f;
|
|
lift->dist = 0;
|
|
lift->speed = 0;
|
|
lift->levelcur = 0;
|
|
lift->levelaim = 0;
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
if (lift->doors[i]) {
|
|
lift->doors[i] = (struct doorobj *)setupGetCmdByIndex(index + *(s32*)&lift->doors[i]);
|
|
}
|
|
}
|
|
|
|
obj->geocount = 1;
|
|
setupLoadModeldef(modelnum);
|
|
modelstate = &g_ModelStates[modelnum];
|
|
|
|
if (modelstate->filedata) {
|
|
if (modelGetPartRodata(modelstate->filedata, 1)) {
|
|
obj->geocount++;
|
|
}
|
|
if (modelGetPartRodata(modelstate->filedata, 2)) {
|
|
obj->geocount++;
|
|
}
|
|
if (modelGetPartRodata(modelstate->filedata, 3)) {
|
|
obj->geocount++;
|
|
}
|
|
if (modelGetPartRodata(modelstate->filedata, 4)) {
|
|
obj->geocount++;
|
|
}
|
|
if (modelGetPartRodata(modelstate->filedata, 6)) {
|
|
obj->geocount++;
|
|
}
|
|
}
|
|
|
|
obj->flags &= ~OBJFLAG_00000100;
|
|
|
|
setupCreateObject(obj, index);
|
|
|
|
prop = obj->prop;
|
|
|
|
if (prop) {
|
|
lift->prevpos.x = prop->pos.x;
|
|
lift->prevpos.y = prop->pos.y;
|
|
lift->prevpos.z = prop->pos.z;
|
|
|
|
liftUpdateTiles(lift, true);
|
|
}
|
|
|
|
liftnum++;
|
|
liftActivate(prop, liftnum);
|
|
}
|
|
break;
|
|
case OBJTYPE_HOVERPROP:
|
|
if (withobjs && (obj->flags2 & diffflag) == 0) {
|
|
struct hoverpropobj *hoverprop = (struct hoverpropobj *)obj;
|
|
|
|
setupCreateObject(obj, index);
|
|
setupCreateHov(obj, &hoverprop->hov);
|
|
}
|
|
break;
|
|
case OBJTYPE_GLASS:
|
|
if (withobjs && (obj->flags2 & diffflag) == 0) {
|
|
if (obj->flags & OBJFLAG_GLASS_HASPORTAL) {
|
|
struct glassobj *glass = (struct glassobj *)obj;
|
|
glass->portalnum = setupGetPortalByPad(obj->pad);
|
|
}
|
|
|
|
setupCreateObject(obj, index);
|
|
}
|
|
break;
|
|
case OBJTYPE_BASIC:
|
|
case OBJTYPE_AMMOCRATE:
|
|
if (withobjs && (obj->flags2 & diffflag) == 0) {
|
|
setupCreateObject(obj, index);
|
|
}
|
|
break;
|
|
case OBJTYPE_MULTIAMMOCRATE:
|
|
{
|
|
struct multiammocrateobj *crate = (struct multiammocrateobj *)obj;
|
|
s32 ammoqty = 1;
|
|
s32 i;
|
|
|
|
if (g_Vars.normmplayerisrunning && var8009cc30 >= 0) {
|
|
struct mpweapon *mpweapon = func0f188e24(var8009cc30);
|
|
ammoqty = mpweapon->weapon1ammoqty;
|
|
|
|
if (mpweapon->weapon1ammotypeminusone > 0 && mpweapon->weapon1ammotypeminusone < 20) {
|
|
crate->slots[mpweapon->weapon1ammotypeminusone - 1].quantity = ammoqty;
|
|
}
|
|
|
|
if (mpweapon->weapon2ammotypeminusone > 0 && mpweapon->weapon2ammotypeminusone < 20) {
|
|
crate->slots[mpweapon->weapon2ammotypeminusone - 1].quantity = mpweapon->weapon2ammoqty;
|
|
}
|
|
}
|
|
|
|
if (ammoqty > 0 && withobjs && (obj->flags2 & diffflag) == 0) {
|
|
for (i = 0; i < 19; i++) {
|
|
if (crate->slots[i].quantity > 0 && crate->slots[i].modelnum != 0xffff) {
|
|
setupLoadModeldef(crate->slots[i].modelnum);
|
|
}
|
|
}
|
|
|
|
setupCreateObject(obj, index);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
obj = (struct defaultobj *)((u32 *)obj + setupGetCmdLength((u32 *)obj));
|
|
index++;
|
|
}
|
|
|
|
index = 0;
|
|
|
|
obj = (struct defaultobj *)g_StageSetup.props;
|
|
|
|
while (obj->type != OBJTYPE_END) {
|
|
switch (obj->type) {
|
|
case OBJTYPE_BASIC:
|
|
case OBJTYPE_KEY:
|
|
case OBJTYPE_AMMOCRATE:
|
|
case OBJTYPE_WEAPON:
|
|
case OBJTYPE_SINGLEMONITOR:
|
|
case OBJTYPE_DEBRIS:
|
|
case OBJTYPE_MULTIAMMOCRATE:
|
|
case OBJTYPE_SHIELD:
|
|
case OBJTYPE_GASBOTTLE:
|
|
case OBJTYPE_29:
|
|
case OBJTYPE_GLASS:
|
|
case OBJTYPE_SAFE:
|
|
case OBJTYPE_TINTEDGLASS:
|
|
if (obj->prop && (obj->flags & OBJFLAG_INSIDEANOTHEROBJ)) {
|
|
s32 offset = obj->pad;
|
|
struct defaultobj *owner = setupGetObjByCmdIndex(index + offset);
|
|
|
|
if (owner && owner->prop) {
|
|
obj->hidden |= OBJHFLAG_HASOWNER;
|
|
modelSetScale(obj->model, obj->model->scale);
|
|
propReparent(obj->prop, owner->prop);
|
|
}
|
|
}
|
|
break;
|
|
case OBJTYPE_LINKLIFTDOOR:
|
|
{
|
|
struct linkliftdoorobj *link = (struct linkliftdoorobj *)obj;
|
|
s32 dooroffset = (s32)link->door;
|
|
s32 liftoffset = (s32)link->lift;
|
|
struct defaultobj *door = setupGetObjByCmdIndex(index + dooroffset);
|
|
struct defaultobj *lift = setupGetObjByCmdIndex(index + liftoffset);
|
|
|
|
if (door && door->prop && lift && lift->prop) {
|
|
link->door = door->prop;
|
|
link->lift = lift->prop;
|
|
|
|
setupCreateLiftDoor(link);
|
|
|
|
door->hidden |= OBJHFLAG_LIFTDOOR;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
obj = (struct defaultobj *)((u32 *)obj + setupGetCmdLength((u32 *)obj));
|
|
index++;
|
|
}
|
|
}
|
|
} else {
|
|
modelmgrAllocateSlots(0, 0, 0);
|
|
}
|
|
}
|