Files
goldeneye-pc-port/src/bondtypes.h
T
James Dansereau 57e24a374b M-28: watch-menu text (D150/D151) + audio-lock deadlock mitigation (D152)
D150 (src/str.c) — NULL-tolerant strcpy/strncpy/strcat under #ifdef PORT.
The watch BRIEF/OBJECTIVES pages build text with strcat(buf, langGet(id));
langGet() returns NULL on PC for a string bank the in-level flow never
loaded, and str.c's primitives are __nonnull__ builtins so a plain param
NULL check is optimised away — the guard launders the ptr through an empty
asm (GE_IS_NULL). NULL src -> empty string instead of an AV crash.

D151 (src/bondtypes.h) — watch data (objectives / mission background / M /
Q / Moneypenny) all rendered blank. propDef types 35 (WatchMenuObjectiveText)
and 23 (ObjectiveStart) store a plain s32 lang slot id in their 3rd word;
the decomp structs decode it as [u16 reserved][u16 text] reading text at
offset 0xA, which only works because the id is in the low 16 bits of a
big-endian word. d88_propdefs.py bswap32's the whole word -> text @0xA
reads 0 -> langGet(0) -> NULL. Fix: text is a full u32 at the word offset
under #ifdef PORT (N64 layout kept under #else). No converter change, no
sidecar regen. This is the D143/D150 "briefing text renders blank" root cause.

D152 (port/src/libultra.c) — mission-failed / objective-failed permanent
black screen. The D147 recursive-mutex behind osSetIntMask can be leaked
(libaudio has unbalanced / early-return mask calls; a transient thread can
acquire OS_IM_NONE and exit) -> mainThread + amMain both block forever in
alEvtq* -> gfx pipeline stalls. Live gdb.txt from the user's session
confirmed the deadlock (mainThread in the mission-fail audio fade-out
sndSetScalerApplyVolumeAllSfxSlot -> alEvtqPostEvent). Mitigation: model
the mask as a self-healing logical lock (owner/depth under s_imMx + condvar)
— normal microsecond critical sections behave as before, but a waiter
blocked > 2s concludes the holder leaked it, logs the stale owner + the
stealing caller's return address, and steals the section. Worst case is a
~2s audio hiccup + a log line naming the leak, instead of a hung game.
Proper narrow fix (dedicated ALEventQueue lock) still owed.

D153 investigated and dismissed — the "-level_09 crashes at frame ~900"
seen while regression-testing was D117/D134 host-scheduling flakiness under
heavy concurrent build+run load; on a quiet machine -level_09 runs past
frame 2400 clean with all three changes applied.

Build: green (ntsc-final). Golden framediff not run clean (same machine-load
flakiness); one quiet -level_09 run = 2400+ frames, 0 heartbeats.
2026-08-30 20:25:02 -04:00

4354 lines
135 KiB
C

/*
* Notes:
* Hacky structures allows coords/rgb etc to be accessed using
* coord->x, coord->y and coord->z, but also as
* coord->AsArray[0], coord->AsArray[1] and coord->AsArray[2] or
* u32 rgba = rgba.AsInteger
*
* In some places code only matches when using the float array.
* Resources of the time including SDK use array.
* Sometimes its nice to be verbose and see the structures instead of
* random arrays or conglomerate integers.
*
*
* While typedefs are used to avoid typing "struct" and to help intellisence
* they are not foolproof.
* Using structs before they are declaired need to have the struct keyword or
* be re-ordered.
*
* Structs that "inherit" other structs can use the syntax
* struct A {int adef};
* struct B {inherits A; int extra};
*
* using adef from B is as simple as calling B->adef, no need for sub-structs anymore
*/
#ifndef _BONDTYPES_H_
#define _BONDTYPES_H_
#include <ultra64.h>
#include <bondconstants.h>
#include "snd.h"
#ifndef AIPARSE
#include "game/chrobjdata.h"
#endif
/**
* Syntax Sugar for clarification of intent
* Inheritance allows child structs to directly use parent elements
* without sub-struct style calls
* obj->type and wep->base.type becomes simply
* obj->type and wep->type (wep inherits obj)
* Usage:
* Define the first entry to the inheriting struct as "inherits xxx"
* to inherit all elements of xxx
*/
#define inherits struct
/*
* Use of int is faster than char (1 less instruction)
* If Sepertion of OS from Game means that it is undesirable to edit this file
* then move bool to bondtypes.h
*/
typedef s32 bool; /* Boolean (TRUE/FALSE) */
// forward declare for inherit structures
typedef u32 romptr_t;
struct object_standard;
struct ChrRecord;
struct PropRecord;
struct ObjectRecord;
struct WeaponObjRecord;
struct WeaponObjRecordExtended;
union ModelRoData;
/**
* The following region deals with various AI structures that can be applied to
* the AI bytestream
*/
#pragma region AI
typedef struct AIRecord
{
u8 cmd;
u8 val[];
} AIRecord;
typedef struct AIRecord1
{
u8 cmd;
u8 val;
} AIRecord1;
typedef struct AIRecord1s
{
u8 cmd;
s8 val;
} AIRecord1s;
typedef struct AIListRecord
{
AIRecord *ailist;
int ID;
} AIListRecord;
#pragma endregion AI
/**
* This region contains all geometry related structures (points colours and volumes)
*/
#pragma region geometry
/*
Float version of a graphics matrix, which has higher precision than an Mtx.
Matrices are stored as Mtxfs then converted to an Mtx when passed to the GPU.
Mtxs use a union and a long long int to force alignments. Mtxfs are not
aligned but still use the union for consistency with Mtx.
*/
typedef union
{
f32 m[4][4];
s32 unused;
} Mtxf;
typedef union
{
Mtxf pos;
s32 view[4][4];
} RenderPosView;
#pragma region colour
typedef struct rgba_u8
{
union
{
struct
{
u8 r;
u8 g;
u8 b;
u8 a;
};
u8 rgba[4];
u32 word; //added to match
};
} rgba_u8;
typedef struct rgba_16
{
union
{
struct
{
u16 r : 5;
u16 g : 5;
u16 b : 5;
u16 a : 1;
};
u16 AsInteger;
};
} rgba_16;
typedef struct rgba_f32
{
union
{
struct
{
f32 r;
f32 g;
f32 b;
f32 a;
};
f32 rgba[4];
};
} rgba_f32;
typedef struct rgb_s32
{
union
{
struct
{
s32 r;
s32 g;
s32 b;
};
s32 rgb[3];
};
} rgb_s32;
typedef struct rgba_s32
{
union
{
struct
{
s32 r;
s32 g;
s32 b;
s32 a;
};
s32 rgba[4];
};
} rgba_s32;
#pragma endregion
#pragma region coordinates
/**
2D Co-ordinate.
Use either Z OR Y not both
*/
typedef struct coord2d
{
union
{
struct
{
f32 x;
f32 y;
};
f32 f[2];
};
} coord2d;
/**
2D Vector.
Use either Z OR Y not both
*/
typedef coord2d vec2;
/**
2D Co-ordinate.
Use either Z OR Y not both
*/
typedef struct point2d
{
union
{
struct
{
s32 x;
s32 y;
};
s32 p[2];
};
} point2d;
typedef struct coord3d
{
union
{
struct
{
f32 x;
f32 y;
f32 z;
};
f32 f[3];
};
} coord3d;
#define New_Coord3d(x, y, z) \
{ \
IF_ELSE(IS_EMPTY(x)) \
(0)(x), \
IF_ELSE(IS_EMPTY(y))(0)(y), \
IF_ELSE(IS_EMPTY(z))(0)(z) \
}
typedef coord3d vec3d; //canononical name
#define New_Vector(x, y, z) \
{ \
IF_ELSE(IS_EMPTY(x))(0)(x),\
IF_ELSE(IS_EMPTY(y))(0)(y),\
IF_ELSE(IS_EMPTY(z))(0)(z) \
}
/**
16bit Co-Ordinate used for Integer co-ordinates eg, pumping straight to RSP.
*/
typedef struct coord16
{
union
{
struct
{
s16 x;
s16 y;
s16 z;
};
s16 AsArray[3];
};
} coord16;
#pragma endregion
// Used for rendering watch menu
struct WatchVertex {
struct coord16 coord1;
struct coord16 coord2;
struct rgba_u8 color;
};
// Buffer defined on player struct, used
// to render rectangles in bottom of watch menu.
// Vertex order:
// upper left
// lower left
// upper right
// lower right
struct WatchRectangle {
struct WatchVertex vtx[4];
};
#pragma region volumes and areas
typedef struct bbox2d
{
union
{
struct
{
coord2d min;
coord2d max;
};
f32 f[2][2];
};
} bbox2d;
typedef struct bbox
{
union
{
struct
{
float xmin;
float xmax;
float ymin;
float ymax;
float zmin;
float zmax;
};
struct
{
coord3d min;
coord3d max;
};
f32 f[3][2];
f32 AsArray[6];
};
} bbox;
typedef struct view4s32
{
union
{
struct
{
s32 left;
s32 top;
s32 width;
s32 height;
};
s32 v[4];
f32 f[4];
};
}Vew4s32;
typedef struct view4f
{
union
{
struct
{
f32 left;
f32 top;
f32 width;
f32 height;
};
s32 v[4];
f32 f[4];
};
}view4f;
typedef struct rect4f
{
union
{
struct coord2d points[4];
f32 f[8];
};
}rect4f;
struct rectbbox
{
f32 left;
f32 up;
f32 right;
f32 down;
};
#pragma endregion
#pragma endregion
#pragma region Stand Tiles
/* They appear to have performed the bit field work themselves here,
but we provide the members for clarity - it should be unused I believe.
(I agree if match, I was thinking about other such scenarios too -Trevor)
seen lh, not lhu. Also seen with an explicit unnecessary '& 0xF'
*/
typedef struct StandTilePoint
{
inherits coord16; //points for tile
u16 link; //link to another tile
} StandTilePoint;
/*
unused struct for clarity of intent
*/
#ifdef PORT
/* D69 (bitfield ABI, same class as D78): MIPS/GCC (N64) packs the
* FIRST-declared bitfield into the HIGH bits of the storage unit;
* x86 GCC packs it into the LOW bits. `tile->tail.hdrTail.pointCount`
* is read pervasively by stan.c (list_of_tilesizes[] tile-size lookup,
* navigation, edge walks) -- with the stock (N64-source-order)
* declaration this silently reads the WRONG nibble on PC (verified via
* offsetof/union probe against the real project headers: source order
* reads the bottom nibble, `pointCount` needs the top one), producing
* out-of-range list_of_tilesizes indices and an infinite navigation
* loop (list_of_tilesizes[12..15] is out-of-bounds / reads a stray 0,
* so `tile` never advances). Declaring the fields in REVERSE order
* under PORT makes x86's low-to-high packing land each field in the
* same bit position MIPS's high-to-low packing does -- byte-identical
* numeric result, no behavior change. `special`/`r`/`g`/`b` are never
* read via their bitfield names either (only via `.mid.half >> 0xc`
* shifts elsewhere in stan.c), so this is precautionary but free. */
typedef struct StandTileHeaderMid
{
u16 b : 4;
u16 g : 4;
u16 r : 4;
u16 special : 4;// 0=normal 1=kneeling 3=ladder
} StandTileHeaderMid;
typedef struct StandTileHeaderTail
{
s16 headerE : 4;
s16 headerD : 4;
// Indices of the most extreme points (the resulting triangle should encompass _MOST_ of the tile)
s16 headerC : 4;
s16 pointCount : 4; // seen lh, not lhu. Also seen with an explicit unnecessary '& 0xF'
} StandTileHeaderTail;
#else
typedef struct StandTileHeaderMid
{
u16 special : 4;// 0=normal 1=kneeling 3=ladder
u16 r : 4;
u16 g : 4;
u16 b : 4;
} StandTileHeaderMid;
typedef struct StandTileHeaderTail
{
s16 pointCount : 4; // seen lh, not lhu. Also seen with an explicit unnecessary '& 0xF'
// Indices of the most extreme points (the resulting triangle should encompass _MOST_ of the tile)
s16 headerC : 4;
s16 headerD : 4;
s16 headerE : 4;
} StandTileHeaderTail;
#endif
typedef struct StandTile
{
/* u16 ID; // Decimal
u16 GroupID : 4; // a1,a2,a3...z5,z6,z7
u16 RoomID : 4; // compared to 0xFF, not -1 in a function. Seen LBUs.
*/
#ifdef PORT
/* D69: on N64 (MIPS/BE), `u32 id:24` followed by a non-bitfield `u8
* room` packs into a single 4-byte unit (id in the high 24 bits,
* room in the low byte) — the 8-byte-tile-header math baked into
* list_of_tilesizes[]/stanFillin's `link << 3` addressing depends on
* this exact stride. x86 GCC never shares a bitfield's storage unit
* with a following non-bitfield member, so the stock declaration
* below compiles to a 10-byte header (room at +4, mid at +6, tail at
* +8) — silently misaligning every StandTile field read regardless
* of byte-swapping. `id` is provably dead (no `.id`/`->id` read or
* write anywhere in the compiled game code), so it is safe to widen
* to a plain 3-byte array; this restores the N64 stride (room@3,
* mid@4, tail@6, points@8) without touching any StandTile consumer.
* Layout-only, no behavior change. */
u8 id[3];
u8 room; // compared to 0xFF, not -1 in a function. Seen LBUs.
#else
u32 id : 24;
u8 room; // compared to 0xFF, not -1 in a function. Seen LBUs.
#endif
union
{
StandTileHeaderMid headerMid;
s16 half;
} mid;
/* 0x06 */
// They appear to have performed the bit field work themselves here,
// but we provide the StandTileHeaderTail member for clarity - it should be unused I believe.
union
{
StandTileHeaderTail hdrTail;
s16 half;
} tail;
/* 0x08 */
StandTilePoint points[];
} StandTile;
typedef struct StandFilePoint
{
u16 x;
u16 y;
u16 z;
u16 link;
} StandFilePoint;
typedef struct StandFileTile
{
u32 id : 24;
//u8 name2;
u8 room; // compared to 0xFF, not -1 in a function. Seen LBUs.
union
{
StandTileHeaderMid headerMid;
s16 half;
} mid;
/* 0x06 */
// They appear to have performed the bit field work themselves here,
// but we provide the StandTileHeaderTail member for clarity - it should be unused I believe.
union
{
StandTileHeaderTail hdrTail;
s16 half;
} tail;
/* 0x08 */
//hack remove for compiling stan files
//struct StandTilePoint points[1];
} StandFileTile;
typedef struct StandFileHeader
{
void * unk1;
StandTile *firstTile;
u8 unk2[];
} StandFileHeader;
// May be internal only, nice here.
struct StandTileWalkCallbackRecord
{
s32 *roomBuf;
s32 count;
s32 bufMax;
s32 lastRoom;
};
typedef void (*standTileWalkCallback_t)(struct StandTile *, struct StandTile *, struct StandTileWalkCallbackRecord *);
// Very similar but definitely different to the above?
struct StandTileLocusCallbackRecord
{
s32 *rooms; /* 0x00 */
s32 count; /* 0x04 */
s32 bufMax; /* 0x08 */
s32 nearEdgeCount; /* 0x0c */
};
typedef struct StandFileFooter
{
char strictstring[8];
void *unk3;
void *unk4;
void *unk5;
void *unk6;
} StandFileFooter;
typedef s32 (*standTileLocusCallback_A_t)(struct StandTile *, struct StandTileLocusCallbackRecord *);
typedef s32 (*standTileLocusCallback_B_t)(StandTile *arg0, s32 arg1, f32 arg2, f32 arg3, f32 arg4, struct StandTileLocusCallbackRecord *arg5);
typedef s32 (*standTileLocusCallback_C_t)(struct StandTile **, s32, struct StandTileLocusCallbackRecord *);
typedef s32 (*tilePredicate_t)(struct StandTile *);
/* Beta definitions, to allow citadel stan in .c file to build into .bin */
typedef struct BetaStandFilePoint
{
inherits coord3d;
u32 link;
} BetaStandFilePoint;
typedef struct BetaStandTileHeaderTail
{
u8 pointCount;
u8 headerC;
u8 headerD;
u8 headerE;
} BetaStandTileHeaderTail;
typedef struct BetaStandTile
{
const char *id;
StandTileHeaderMid headerMid;
u16 betaUnknown;
BetaStandTileHeaderTail hdrTail;
struct BetaStandFilePoint points[];
} BetaStandTile;
#pragma endregion
//Animation controller located in initobjects.h
#pragma region AnimationStuff
typedef struct AnimTable2
{
int a;
char b;
} AnimTable2;
typedef struct ModelAnimBitField {
u16 bitOffset;
u8 bitCount;
u8 padding;
u16 valueOffset;
} ModelAnimBitField;
typedef struct ModelAnimRootMotionChannel
{
u16 bitOffset;
u8 bitCount;
u8 padding;
u16 valueOffset;
} ModelAnimRootMotionChannel;
typedef struct ModelAnimation
{
s32 address;
u16 unk04; // number of frames in the animation
u8 unk06;
u8 unk07; // bit 0 is a loop flag: 0 means freeze anim at end, 1 means loop anim
u32 bitDescriptors; // 0x08 (PC port D32: was `ModelAnimBitField *`; stored as u32 so the
// ROM-serialized layout matches N64 on x86-64 — cast at use sites)
u16 unk0C;
u16 unk0E;
u32 bitStream; // 0x10 (PC port D32: was `u8 *`; see bitDescriptors note above)
s32 unk14;
s32 unk18;
s32 unk1c;
s32 unk20;
s32 unk24;
s32 unk28;
s32 unk2c;
s32 unk30;
s32 unk34;
s32 unk38;
s32 unk3c; // end frame
} ModelAnimation;
struct object_animation_controller
{
void *ptranimation; // 0x00
u16 offsettocurcmd; // 0x04
u16 waitcounter; // 0x06
u32 imagenum; // 0x08
f32 rotation; // 0x0C
f32 curzoomx; // 0x10
f32 startzoomx; // 0x14
f32 zoomxtimer; // 0x18
f32 initialzoomx; // 0x1C
f32 finalzoomx; // 0x20
f32 curzoomy; // 0x24
f32 startzoomy; // 0x28
f32 zoomytimer; // 0x2C
f32 initialzoomy; // 0x30
f32 finalzoomy; // 0x34
f32 curhorizontalpos; // 0x38
f32 starthorscroll; // 0x3C
f32 horscrolltimer; // 0x40
f32 horinitpos; // 0x44
f32 horfinalpos; // 0x48
f32 curverpos; // 0x4C
f32 startverscroll; // 0x50
f32 verscrolltimer; // 0x54
f32 verinitpos; // 0x58
f32 verfinalpos; // 0x5C
u8 curredcomponant; // 0x60
u8 initredcomponant; // 0x61
u8 finalredcomponant; // 0x62
u8 curgreencomponant; // 0x63
u8 initgreencomponant; // 0x64
u8 finalgreencomponant; // 0x65
u8 curbluecomponant; // 0x66
u8 initbluecomponant; // 0x67
u8 finalbluecomponant; // 0x68
u8 curalphacomponant; // 0x69
u8 initalphacomponant; // 0x6A
u8 finalalphacomponant; // 0x6B
f32 startcolorshift; // 0x6C
f32 colorshifttimer; // 0x70
};
#pragma endregion AnimationStuff
#pragma region ModelTypes
/**
* Taken from PD, unsure that all of the fields line up
*/
typedef struct ModelRenderData
{
Mtxf *basemtx; /*0x00*/ // Canonical name. See instcalcmatrices in model.c.
bool zbufferenabled; /*0x04*/
u32 flags; /*0x08*/
Gfx *gdl; /*0x0c*/
Mtxf *mtxlist; /*0x10*/ // Canonical name. See instcalcmatrices in model.c.
u32 unk14; /*0x14*/
u32 unk18; /*0x18*/
u32 unk1c; /*0x1c*/
u32 unk20; /*0x20*/
u32 unk24; /*0x24*/
u32 unk28; /*0x28*/
u32 unk2c; /*0x2c*/
s32 PropType; /*0x30*/
rgba_u8 envcolour; /*0x34*/
rgba_u8 fogcolour; /*0x38*/
u32 cullmode; /*0x3c*/
} ModelRenderData;
/**
* Binary compatible with gbi Vtx but more verbose and with "collision"
* information in place of "flags" for use in Openflight Records below
*/
typedef struct Vertex
{
coord16 coord;
s16 index; /* 0x6 Collisions Only - points to vertex */
union
{
struct
{
s16 s; /* 0x8 */
s16 t; /* 0xa */
};
#ifdef PORT
/* PC port (D43/D45): stored as a raw vma (0x05xxxxxx) instead of a real
* pointer so sizeof(Vertex) stays 16 bytes — the gSPVertex stride is
* hardcoded to 16B and propobj.c copies vertices with sizeof(Vertex).
* modelPromoteNodeOffsetsToPointers rebases it via PROMOTE32; chr.c casts
* back to ModelNode* at the use site. N64 layout unchanged (4B either way). */
u32 LinkedTo;
/* Collision vertices only: points to related model node (raw vma). */
u32 CollisionRelatedNode; /* 0x8 */
#else
struct Vertex *LinkedTo;
/* Collision vertices only: points to related model node. */
void *CollisionRelatedNode; /* 0x8 */
#endif
};
union
{
struct
{
u8 r; /* 0xc */
u8 g; /* 0xd */
u8 b; /* 0xe */
u8 a; /* 0xf */
};
struct
{
u8 nx; /* 0xc */
u8 ny; /* 0xd */
u8 nz; /* 0xe */
u8 nflag; /* 0xf */
};
struct
{
s16 CollisionRelatedIndex; /* 0xc */
s16 CollisionReserved; /* 0xe */
};
};
} Vertex;
#pragma region OpenFlight Records
/*
The following structures are derived from the MultiGen OpenFlight binary data
format for use in GE/PD.
Databases in this format can be created and edited using PerfectGold
The format supports variable levels of detail, degrees of freedom, instancing
(both within a file and to external files), animation sequences, bounding
volumes (box for collision, sphere for culling), shadows, and several other
features.
The OpenFlight database hierarchy allows the visual database to be organized
in logical groupings and is designed to facilitate real-time functions such
as level of detail switching and instancing. The OpenFlight database is
organized in a tree structure. Each node (or bead) of the tree can point down
and/or across (see Figure 1-1).
Header: There is one header record per file. It is always the first record in
the file and represents the top of the database hierarchy and tree structure.
The header always points down to a group.
Group: A group node is used to organize a logical subset of a database.
MultiGen allows groups to be manipulated (translated, rotated, scaled, etc.)
as a single entity. Groups can point down and across to other groups, level
of detail nodes, or objects.
Level of Detail: A level of detail (LOD) node is similar to a group, but
serves as a switch to turn the display of everything below it on or off based
on range (the switch in/switch out distance and center location).
Switch: A switch node is a more general case of an LOD node. It allows the
selection of multiple children by invoking a selector mask.
Object: An object node contains a logical collection of polygons. An object
can point across to another object, group or LOD.
Bounding Volume: A Bounding Volume can be used by the real-time software to
determine if a particular group is in view. The (optional) bounding volume
opcode records are placed immediately after the group record and include the
extents created by instancing and replication. A bounding volume can be
either a box, a sphere, or a cylinder. Each group node can have only one
bounding volume.
Pointers:
Pointers are offsets relative to model root.
eg, the first child of the model has an offset of
*/
typedef struct ModelFileTextures
{
u32 TextureID;
u8 Width;
u8 Height;
u8 MipMapTiles;
u8 Type;
u8 RenderDepth; /*use G_IM_SIZ_ Note: CI uses 16bit*/
u8 sflags; /*use G_TX_*/
u8 tflags; /*use G_TX_*/
} ModelFileTextures;
/*
This defines each row of the Node Table
*/
typedef struct ModelNode
{
//u8 UseAdditionalMatrices; //1 = group use MatrixID1 also. not actually used
u16 Opcode; /*0x00*/
union ModelRoData *Data; /*0x04 Node Data*/
struct ModelNode *Parent; /*0x08*/
struct ModelNode *Next; /*0x0c*/
struct ModelNode *Prev; /*0x10*/
struct ModelNode *Child; /*0x14*/
} ModelNode;
#pragma region Model Node OpCode Definitions
/*
* These are some extra RoData structs that are used by Op07 (and presumably Op05)
* Not sure how these fit in with the rest, they appear to be separate
*/
typedef struct ModelRoData_Child
{
u8 NumEntries; /*0x00*/
u8 unk01; /*0x01*/
u16 unk02; /*0x02*/
u8 *unk04; /*0x04*/
} ModelRoData_Child;
typedef struct ModelRoData_Child_Vtx
{
u8 Type; /*0x00*/
u8 unk01; /*0x01*/
u16 VtxIndex; /*0x02*/
} ModelRoData_Child_Vtx;
typedef struct ModelRoData_Child_Tri
{
u8 Type; /*0x00*/
u8 VtxIndex1; /*0x01*/
u8 VtxIndex2; /*0x02*/
u8 VtxIndex3; /*0x03*/
} ModelRoData_Child_Tri;
typedef struct ModelRoData_Child_Image
{
u8 Type; /*0x00*/
u8 ImageIndex; /*0x01*/
} ModelRoData_Child_Image;
#pragma endregion
#pragma region Model Node OpCode Definitions
/**
* Opcode 1
* The header record is found at the beginning of the database file.
* Used on Character Bodies Only
*/
typedef struct ModelRoData_HeaderRecord
{
u16 AnimPart; /* 0x00 */
s16 MatrixIndex; /* 0x02 */
union {
struct ModelRoData_GroupRecord *FirstGroup; /* 0x04 */ /*0x4 First group in tree*/
ModelNode *FirstGroupNode;
};
union
{
struct
{
u16 Group1; /*0x8*/
u16 Group2; /*0xA*/
};
f32 GroupsAsF32; /*0x8*/
};
u16 RwDataIndex; /*0xC*/
u16 reserved; /*0xE padding*/
} ModelRoData_HeaderRecord;
typedef struct ModelRwData_HeaderRecord
{
s8 unk00;
s8 unk01;
s8 unk02;
f32 ground;
coord3d pos;
f32 unk14; // angle
f32 unk18;
f32 unk1c;
f32 unk20; // angle
coord3d unk24;
f32 unk30; // angle
coord3d unk34;
coord3d unk40; // "2" version of unk24
coord3d unk4c; // "2" version of unk34
f32 unk58;
f32 unk5c;
} ModelRwData_HeaderRecord;
/**
* Opcode 2
* Positions Child nodes reletivly.
* Used for character joints with assosiated Matrices
*
* Group flags are available to the real-time software as follows:
* The animation flags specify that the nodes directly below the group are an
* animation sequence, each node being one frame of the sequence.
* The special effects IDs are normally zero, but can be set to support an
* application program's interpretation of the data.
* The group's relative priority specifies a fixed ordering of the object
* relative to the other groups at this level.
* Since MultiGen sorts based on this field before saving the database, it can
* be ignored by the real-time software.
*/
typedef struct ModelRoData_GroupRecord
{
coord3d Origin; /*0x0*/
u16 JointID; /*0xC*/
union {
s16 MatrixIDs[3]; /*0xE*/
struct {
s16 MatrixID0; /*0xE*/
s16 MatrixID1; /*0x10*/
s16 MatrixID2; /*0x12 never used*/
};
};
union { /*0x14*/
struct ModelRoData_GroupRecord *ChildGroup;
ModelNode *ChildGroupNode;
};
f32 BoundingVolumeRadius; /*0x18*/
} ModelRoData_GroupRecord;
/**
* Opcode 3
* unused
*/
/**
* Opcode 4
* Collisionless Display List used primarely for guns
*/
typedef struct ModelRoData_DisplayListRecord
{
Gfx *Primary; /*0x0*/
Gfx *Secondary; /*0x4*/ // optional
void *BaseAddr; /*0x8*/
Vertex *Vertices; /*0xC*/
u16 numVertices; /*0x10*/
/*
0x12 Type of pre-defined rendermode and combiner setup to use
0 = NoSetup - RenderMode and Combiner must be set in DList
1 = 1Cycle No Sec
2 = 2Cycle No Sec
3 = GunLighting - Reduced Secondary Commands (guns)
4 = Normal Fog/Lighting object
*/
s8 ModelType;
} ModelRoData_DisplayListRecord;
typedef struct ModelRwData_DisplayListRecord // this record is a guess
{
s32 unk00;
} ModelRwData_DisplayListRecord;
/**
* Opcode 5
* unused
*/
typedef struct ModelRoData_Op05Record
{
// shares this structure with op07
s32 NumChildren; /*0x00*/
struct ModelRoData_Child *Children; /*0x04*/
struct Vertex *Vertices; /*0x08*/
struct sImageTableEntry *Images; /*0x0C*/
u8 Data[400]; /*0x10*/
u32 unk1A0; /*0x1A0*/
void* BaseAddr; /*0x1A4*/
} ModelRoData_Op05Record;
/**
* Opcode 6
* unused
*/
typedef struct ModelRoData_Op06Record
{
u32 unk00;
u32 unk04;
u32 unk08;
u32 unk0C;
u32 unk10;
void* BaseAddr; /*0x14*/
} ModelRoData_Op06Record;
/**
* Opcode 7
* unused but referenced
*/
typedef struct ModelRoData_Op07Record
{
struct ModelNode* unk00; /*0x00*/
struct ModelNode* unk04; /*0x04*/
// shares this structure with op05
s32 NumChildren; /*0x08*/
struct ModelRoData_Child *Children; /*0x0C*/
struct Vertex *Vertices; /*0x10*/
struct sImageTableEntry *Images; /*0x14*/
u8 Data[400]; /*0x18*/
u16 unk1A8; /*0x1A8*/
u16 RwDataIndex; /*0x1AA*/
void* BaseAddr;
} ModelRoData_Op07Record;
typedef struct ModelRwData_Op07Record
{
s32 index;
} ModelRwData_Op07Record;
/**
* Opcode 8
* Level of Detail Record
* The distance is calculated by the real-time software by using the distance
* from the eye-point to the LOD center found
*/
typedef struct ModelRoData_LODRecord
{
f32 MinDistance; /*0x0 Switch in distance*/
f32 MaxDistance; /*0x4 Switch out distance*/
ModelNode *Affects; /*0x8 Affects this node (Must be child)*/
u16 RwDataIndex; /*0xC*/
u16 reserved; /*0xE padding*/
} ModelRoData_LODRecord;
typedef struct ModelRwData_LODRecord
{
bool visible;
} ModelRwData_LODRecord;
/**
* Opcode 9
* Binary Separating Plane
* BSPs allow you to model 3D databases with the Z buffer turned off.
*/
typedef struct ModelRoData_BSPRecord
{
coord3d Point; /*0x0*/
coord3d Vector; /*0xC*/
ModelNode *leftChild; /*0x18 back/first */
ModelNode *rightChild; /*0x1C front/last */
s16 reserved; /*0x20 padding or u32*/
u16 RwDataIndex; /*0x22*/
} ModelRoData_BSPRecord;
typedef struct ModelRwData_BSPRecord
{
bool visible;
} ModelRwData_BSPRecord;
/**
* Opcode 10 0xA
* Box within which collisions are tested
*/
typedef struct ModelRoData_BoundingBoxRecord
{
u32 ModelNumber; /*0x0*/
struct bbox Bounds; /*0x4*/
} ModelRoData_BoundingBoxRecord;
/**
* Opcode 11
* unused but referenced
*/
typedef struct ModelRoData_Op11Record
{
union {
coord3d pos; /* 0x00 */
u32 unk0c[16]; /* 0x00 */
};
f32 BoundingVolumeRadius; /* 0x40 */
u16 RwDataIndex; /* 0x44 */
u16 unk46; /* 0x46 */
void *BaseAddr; /* 0x48 */
} ModelRoData_Op11Record;
typedef struct ModelRwData_Op11Record
{
s16 unk00;
s16 unk02;
} ModelRwData_Op11Record;
/**
* Opcode 12 0xC
*/
typedef struct ModelRoData_GunfireRecord
{
coord3d Offset; /*0x0*/
coord3d Size; /*0xC*/
void * Image; /*0x18*/
f32 Scale; /*0x1c*/
u16 RwDataIndex; /*0x20*/
u16 reserved; /*0x22 padding*/
u32 BaseAddr; /*0x24 padding*/
} ModelRoData_GunfireRecord;
typedef struct ModelRwData_GunfireRecord
{
s16 visible;
u16 unk02;
} ModelRwData_GunfireRecord;
/**
* Opcode 13 0xD
* Draws a shadow under character only
*/
typedef struct ModelRoData_ShadowRecord
{
coord2d pos; /* 0x00 */
coord2d size; /* 0x08 */
void *image; /* 0x10 */
union { /* 0x14 */
ModelRoData_HeaderRecord *Header;
ModelNode *HeaderNode;
};
f32 Scale; /* 0x18 */
void *BaseAddr; /* 0x1c */
} ModelRoData_ShadowRecord;
/**
* Opcode 14
* unused
*/
typedef struct ModelRoData_Op14Record
{
coord3d pos; /*0x0*/
f32 Scale; /*0xC*/
} ModelRoData_Op14Record;
/**
* Opcode 15 0xF
* Database linkages use key table records.
* Linkage data consists of two different constructs: nodes and arcs.
* Nodes usually contain data pertaining to database entities such as
* degrees of freedom (DOFs).
* In addition, the nodes may represent modeling driver functions and code nodes.
* The arcs contain information on how all the nodes are connected to each other.
* The key value is used to represent a node, an arc, or a node name, if the
* node represents a database entity
*/
typedef struct ModelRoData_InterlinkageRecord
{
coord3d pos; /* 0x00 */
coord3d pos2; /* 0x0c */
f32 Scale; /* 0x18 */
} ModelRoData_InterlinkageRecord;
/**
* Opcode 16
* unused but referenced
*/
typedef struct ModelNode_Op16Record
{
coord3d pos; /* 0x00 */
s16 nodeindex0c; /* 0x0c */
s16 nodeindex0e; /* 0x0e */
s16 nodeindex10; /* 0x10 */
s16 unk12; /* 0x12 */
f32 Scale; /* 0x14 */
} ModelNode_Op16Record;
/**
* Opcode 17
*/
typedef struct ModelRoData_Op17Record
{
s32 hitpart; /* 0x00 */
f32 radiusSq; /* 0x04 */
coord3d pos; /* 0x08 */
ModelNode *othernode; /* 0x14 */
f32 scale1; /* 0x18 */
f32 scale2; /* 0x1c */
} ModelRoData_Op17Record;
typedef struct
{
u8 pad0[0x8];
struct
{
coord3d pos;
f32 radiusSq;
coord3d rel;
coord3d dir;
} data;
} ModelOp17MainStack;
typedef struct
{
struct
{
coord3d axis;
f32 scale;
} axisAdjustment;
u8 pad0[0x0c];
} ModelOp17AxisStack;
/**
* Opcode 18 0x12
* A switch node is a set of masks that controls the display of its children.
* The mask may inhibit the display of some, none, or all of the switch node
* children.
*/
typedef struct ModelRoData_SwitchRecord
{
ModelNode *Controls; /*0x0 Which node to display (Must be Child)*/
u16 RwDataIndex; /*0x4*/
u16 reserved; /*0x6 padding*/
} ModelRoData_SwitchRecord;
typedef struct ModelRwData_SwitchRecord
{
bool visible;
} ModelRwData_SwitchRecord;
/**
* Opcode 19
* unused
*/
/**
* Opcode 20
* unused
*/
/**
* Opcode 21 0x15
* Simple Group used to position Cartridge ejection and held items
*/
typedef struct ModelRoData_GroupSimpleRecord
{
coord3d Origin; /*0x0*/
s16 Group1; /*0xC*/
u16 Group2; /*0xE*/
f32 BoundingVolumeRadius; /*0x10*/
} ModelRoData_GroupSimpleRecord;
/**
* Opcode 22 0x16
* Primary Display List Only
*/
typedef struct ModelRoData_DisplayListPrimaryRecord
{
s32 numVertices; /*0x0*/
Vertex *Vertices; /*0x4*/
Gfx *Primary; /*0x8*/
void *BaseAddr; /*0xC*/
} ModelRoData_DisplayListPrimaryRecord;
/**
* Opcode 23 0x17
* Head Placeholder for Random Heads
*/
typedef struct ModelRoData_HeadPlaceholderRecord
{
u16 RwDataIndex;
} ModelRoData_HeadPlaceholderRecord;
typedef struct ModelRwData_HeadPlaceholderRecord
{
struct ModelFileHeader *ModelFileHeader;
void *RwDatas;
} ModelRwData_HeadPlaceholderRecord;
/**
* Opcode 24 0x18
* Full Display List with Collision Table
*/
typedef struct ModelRoData_DisplayList_CollisionRecord
{
Gfx *Primary; /*0x0*/
Gfx *Secondary; /*0x4*/ // optional
Vertex *Vertices; /*0x8*/
s16 numVertices; /*0xC*/
s16 numCollisionVertices; /*0xE*/
Vertex *CollisionVertices; /*0x10 Table of vertices with unique point in space (UV's and Colour are disregarded). */
s16 *PointUsage; /*0x14*/
s16 ModelType; /*0x18*/
u16 RwDataIndex; /*0x1A*/
void *BaseAddr; /*0x1C*/
} ModelRoData_DisplayList_CollisionRecord;
typedef struct ModelRwData_DisplayList_CollisionRecord
{
Vertex *Vertices;
Gfx *gdl;
} ModelRwData_DisplayList_CollisionRecord;
// placeholder struct when need to access offset but don't know type.
struct ModelRwData_Raw
{
s32 unk00;
};
#pragma endregion Model Node OpCode Definitions
/*
* Handy Union for each type of RoData
*/
union ModelRoData
{
struct ModelRoData_HeaderRecord Header;
struct ModelRoData_GroupRecord Group;
struct ModelRoData_DisplayListRecord DisplayList;
struct ModelRoData_Op05Record Op05;
struct ModelRoData_Op06Record Op06;
struct ModelRoData_Op07Record Op07;
struct ModelRoData_LODRecord LOD;
struct ModelRoData_BSPRecord BSP;
struct ModelRoData_BoundingBoxRecord BoundingBox;
struct ModelRoData_Op11Record Op11;
struct ModelRoData_GunfireRecord Gunfire;
struct ModelRoData_ShadowRecord Shadow;
struct ModelRoData_Op14Record Op14;
struct ModelRoData_InterlinkageRecord Interlinkage;
struct ModelNode_Op16Record Op16;
struct ModelRoData_SwitchRecord Switch;
struct ModelRoData_GroupSimpleRecord GroupSimple;
struct ModelRoData_DisplayListPrimaryRecord DisplayListPrimary;
struct ModelRoData_HeadPlaceholderRecord HeadPlaceholder;
struct ModelRoData_DisplayList_CollisionRecord DisplayListCollisions;
};
/*
* Handy Union for each type of RwData
*/
union ModelRwData
{
struct ModelRwData_HeaderRecord Header;
struct ModelRwData_DisplayListRecord DisplayList;
struct ModelRwData_Op07Record Op07;
struct ModelRwData_LODRecord LOD;
struct ModelRwData_BSPRecord BSP;
struct ModelRwData_Op11Record Op11;
struct ModelRwData_GunfireRecord Gunfire;
struct ModelRwData_SwitchRecord Switch;
struct ModelRwData_HeadPlaceholderRecord HeadPlaceholder;
struct ModelRwData_DisplayList_CollisionRecord DisplayListCollisions;
struct ModelRwData_Raw Raw;
};
#pragma endregion OpenFlight Records
#pragma region Data Structures
//21990 stuff below
/*
Defines which Node is the Joint and which matrices are applied to it.
This Node (usualy a group) will move/rotate accordingly, however to animate
vertices, remember to paint them with the same matrices.
*/
typedef struct ModelJoint
{
u16 NodeType;
u16 mtxA;
u16 mtxB;
} ModelJoint;
/*
This struct defines joint nodes and the matrices assosiated with them.
There is Always at least 1 Joint used for positioning the object in-game
*/
typedef struct ModelSkeleton
{
short numjoints; //Always at least 1 (root)
short pad1; //pad
ModelJoint *Joints;
short SkeletonSize;
short pad2;
#ifdef DEBUG
char **JointNames;
#endif
} ModelSkeleton;
typedef struct ModelFileHeader
{
ModelNode *RootNode; //possibly this is "root data"
ModelSkeleton *Skeleton;
/* This is a pointer to a variable length array of pointers to modelnodes, but the array is followed by an s16 array of part numbers.*/
ModelNode **Switches;
s16 numSwitches; // c Number of "05"s, these link to positions/switches Note: Does not reflect number actually used
s16 numMatrices; // Number of matrices used. (GE Name is LCase)
f32 BoundingVolumeRadius; // 10 radius from model center to frustrum edge before culling.
s16 numRecords; // 14 used in runtime for number of records
s16 numtextures; // 16 Number of textures in table
ModelFileTextures *Textures; // 18 offset to texture table
#ifdef DEBUG
char **SwitchNames;
#endif
#if defined(VERSION_EU)
#else
s32 isLoaded;
#endif
} ModelFileHeader;
typedef struct ItemModelFileRecord
{
ModelFileHeader *header;
char *filename;
float scale;
#ifdef DEBUG
bool isLoaded;
#endif
} ItemModelFileRecord;
typedef struct ChrModelFileRecord
{
ModelFileHeader *header;
char *filename;
float scale;
float pov;
u8 isMale;
u8 hasHead;
u8 pad1;
u8 pad2;
#ifdef DEBUG
char **SwitchNames;
#endif
} ChrModelFileRecord;
/*
typedef struct GunModelFileRecord
{
ModelFileHeader *Header;
char *Filename;
s32 HasNoModel;
struct weapon_stats *Stats;
u16 WatchUpperTextID;
u16 WatchLowerTextID;
coord3d WatchPos;
coord2d WatchRot;
u16 WeaponOfChoiceTextID;
u16 WatchEquipmentTextID;
coord3d WatchRotationOrigin;
} GunModelFileRecord;
struct CartrigeModelFileRecord
{
ModelFileHeader *Header;
char *FileName;
};
*/
/*
* Model Root Runtime Data (pos, heading, height etc)
*/
struct modeldata_root
{ // type 0x01
u16 unk00; /*0*/
u8 unk02; /*2*/
f32 ground; /*4*/
coord3d pos; //8, 12, 16 - this is the right poition for this, but no idea what this node actually is (used in modelGetNodeRwData)
f32 subroty; //14 angle - this also happens to fit best for getsubroty
f32 unk18; /*18*/
u32 unk1c; /*1c*/
f32 unk20; //20 angle
coord3d unk24;
f32 unk30; // angle copy of 20
coord3d unk34;
coord3d unk40; // "2" version of unk24
coord3d unk4c; // "2" version of unk34
f32 unk58;
f32 unk5c;
};
/**
* I beleve that "datas" is actually " struct modeldata_root" and that
* unk1c is the model node data array
*/
typedef struct Model
{
s16 unk00; /*0x00*/ // objInit() indicates that unk00 is a s16...
s16 rwdatalen; /*0x01*/
struct ChrRecord *chr; /*0x04*/
ModelFileHeader *obj; /*0x08 GE Name confirmed*/
/**
* List of length model->obj->numMatrices dynamically allocated.
*/
RenderPosView *render_pos; /*0x0c*/
#ifdef PORT
/* PC port (D52): `datas` is the model's RW-data pool itself, not an
* array of pointers. RwDataIndex values are 4-byte WORD offsets:
* modelCalculateRwDataIndexes() accumulates sizeof(record)/4 and
* sizes the pool as round16(numRecords*4) bytes (modelmgrInstantiate*
*ModelWithAnim). On N64, `union ModelRwData **` strides 4B so
* &datas[i] lands on record i; on PC the same type strides 8B and
* every non-zero index addresses the wrong record (crash in
* modelInitRwData at the first BSP node). u32* keeps the N64 byte
* math exactly; use sites cast to the record type. Layout is a
* single pointer either way, so struct Model is unchanged. */
u32 *datas;
#else
union ModelRwData **datas; // array of pointers to modeldata structs /*0x10*/
#endif
f32 scale; /*0x14*/
struct Model *attachedto; /*0x18*/
ModelNode *attachedto_objinst; /*0x1c*/
// need `struct anim` definition from AI branch.
ModelAnimation *anim; /*0x20*/
s8 gunhand; // used by ACT_STAND
s8 unk25;
s8 animlooping; /*0x26*/
s8 unk27;
f32 animframe1; /*0x28*/
f32 unk2c;
/**
* Animation framea (per debug message)
* Offset 0x30.
*/
s16 framea;
/**
* Animation frameb (per debug message)
* Offset 0x32.
*/
s16 frameb;
s32 unk34;
s32 unk38;
f32 endframe;
f32 speed; /*0x40*/
f32 newspeed; /*0x44*/
f32 oldspeed; /*0x48*/
f32 timespeed; /*0x4C*/
f32 elapsespeed; /*0x50*/
ModelAnimation *anim2;
f32 animframe2; /* 0x58*/
f32 unk5c;
/**
* Animation frame2a (per debug message)
* Offset 0x60.
*/
s16 frame2a;
/**
* Animation frame2b (per debug message)
* Offset 0x62.
*/
s16 frame2b;
s32 unk64;
s32 unk68;
f32 unk6c;
// 0x70
f32 speed2;
f32 unk74;
f32 unk78;
f32 unk7c;
// 0x80
f32 unk80;
/**
* Related to "anim2", per debug message.
*/
f32 unk84;
f32 unk88;
f32 unk8c;
// 0x90
f32 animloopframe; /*0x90*/
f32 animloopmerge; /*0x94*/
s32 animflipfunc; /*0x98*/
s32 unk9c;
// 0xa0
s32 unka0; // This is likely a function pointer, see sub_GAME_7F06D490()
f32 playspeed; // used by ACT_STAND in chrlv
f32 animrate;
f32 unkac;
// 0xb0
f32 unkb0;
f32 unkb4;
f32 anim_translation_scale; // used by ACT_ANIM in chrlv
} Model;
/*
typedef struct headHat
{
float xoffset;
float yoffset;
float zoffset;
float xsize;
float ysize;
float zsize;
} headHat;*/
#pragma endregion Data Structures
#pragma endregion ModelTypes
#pragma region Explosion Stuff
typedef struct ExplosionDetailsRecord
{
s16 TypeID;
s16 Seed[6];
} ExplosionDetailsRecord;
struct ExplosionDetailsRecordSeed
{
s16 seed[6];
};
typedef struct ExplosionDetailsRecordEuList
{
u8 typeids[344];
struct ExplosionDetailsRecordSeed seeds[105];
} ExplosionDetailsRecordEuList;
#pragma endregion Explosion Stuff
#pragma region Hit Structures
typedef struct HitThing {
coord3d hitpos; // 0x00
coord3d normal; // 0x0c
Vertex *vtx0; // 0x18
Vertex *vtx1; // 0x1c
Vertex *vtx2; // 0x20
Gfx *tricmd; // 0x24 - display-list command associated with hit triangle
s16 unk28; // 0x28
s16 texturenum; // 0x2a
s16 tileformat; // 0x2c
s16 tilesize; // 0x2e
} HitThing;
typedef struct BulletHit {
f32 dist; // 0x00
struct PropRecord *prop; // 0x04
s32 hitpart; // 0x08
struct ModelNode *node; // 0x0c
HitThing hit; // 0x10, size 0x30
s32 room; // 0x40
struct ModelNode *unk44; // 0x44
struct Model *model; // 0x48
s32 countsAsPenetration; // 0x4c
} BulletHit;
typedef struct ShotData {
coord3d viewOrigin; // 0x00
coord3d viewDir; // 0x0c
ITEM_IDS weapon; // 0x18
coord3d gunpos; // 0x1c
coord3d dir; // 0x28
f32 maxdist; // 0x34
BulletHit hits[10]; // 0x38
} ShotData;
typedef struct ModelHitEntry {
struct Model *model; /* 0x00 */
struct ModelNode *rootnode; /* 0x04 */
f32 sortvalue; /* 0x08 */
struct ModelHitEntry *next; /* 0x0c */
struct ModelHitEntry *prev; /* 0x10 */
} ModelHitEntry;
#pragma endregion Hit Structures
#pragma region PadAndPaths
/**
* Pads hold a location in space and are tied to a specified Stand Tile.
* Other attributes include its rotation and normal.
*/
typedef struct PadRecord /*0x2c (44) long confirmed*/
{
coord3d pos; /*0x00*/
coord3d up; /*0x0c*/
coord3d look; /*0x18*/
char *plink; /*0x24 canonical name */
StandTile *stan; /*0x28 canonical name */
} PadRecord;
/**
* Bound Pads hold an extra Bounding Box which any prop assigned will try to
* fill (non-uniform scaling).
*/
typedef struct BoundPadRecord /*0x44 (68) long confirmed*/
{
//inherits PadRecord; /*0x00 confirmed*/
coord3d pos; /*0x00*/
coord3d up; /*0x0c*/
coord3d look; /*0x18*/
char * plink; /*0x24 canonical name */
StandTile *stan; /*0x28 canonical name */
//temporary fix for no inheritance support by glibtools
bbox bbox; /*0x2c - 0x40 confirmed*/
} BoundPadRecord;
/**
//##Paths
Paths are formed by connecting several pads together in 3 tables.
The first table is the waypoint node table which lists the pad used, and
the subset group the waypoint belongs to.
Next is the waygroup table which lists the IDs of the waypoints that
belong to each group. waypoints are grouped into subsets to reduce
calculations on large numbers of nodes.
Finally is the Path table which again lists all the waypoints used in
the path and gives the path an ID. Paths do not contribute to pathfinding.
Possible Graph Algorithm used A*
*/
/**
* The waypoint table lists the pad used, and the group the waypoint
* belongs to as well as any connected waypoints.
*/
typedef struct waypoint
{
s32 padID; // Pad ID to anchor waypoint to.
s32 *neighbours; // Array of neighbouring (connected) waypoint IDs (ending in -1)
s32 groupNum; // index entry in the waygroup table that contains this path entry
s32 dist; // Initialise to 0, used by engine for pathfinding Heuristics between waypoints within a set.
} waypoint;
/**
* The Subset waygroup table which lists the IDs of the waypoints that
* belong to each group as well as any connected groups
*/
typedef struct waygroup
{
s32 *neighbours; // Array of neighbouring (connected) waygroup IDs (ending in -1)
s32 *waypoints; // Array of waypoint IDs (ending in -1)
s32 dist; // Initialise to 0, used by engine for pathfinding Heuristics between sets
} waygroup;
/**
* Path for guard to patrol (loop) or get from A to B (linear)
*/
typedef struct PathRecord
{
s32 *waypoints; // array of waypoint IDs in path (ending in -1)
u8 ID; // path ID
u8 isLoop; // 0x05 Path loops
u16 len; /*0x06 unused*/
} PathRecord;
//path finder
struct waydata
{
/**
* player.act_gopos.waydata starts at 0x5c.
*/
s8 mode; /*0x00 */
// next mode?
s8 unk01; /*0x01 */
/**
* Related to pos field.
* Set/unset flag?
* Offset 0x2.
*/
s8 unk02;
/**
* Related to pos_copy field.
* Set/unset flag?
* Offset 0x3.
*/
s8 unk03;
coord3d pos; /*0x04 */
// from PD - unverified/unmatched
coord3d pos2; /*0x10 */
coord3d pos3; /*0x1c */
// from PD - unverified/unmatched
s32 age; /*0x28 */
// from PD - unverified/unmatched
coord3d pos_copy; /*0x2c */
// These are the distances between the current waypoint and the previous
// when using cheap mode.
// from PD - unverified/unmatched
f32 segdistdone; /*0x38 */
// from PD - unverified/unmatched
f32 segdisttotal; /*0x3c */
};
#pragma endregion PadAndPaths
#pragma region ACT_TYPES
struct act_init
{
int padding[30];
};
struct act_stand
{
s32 prestand; /*0x2c*/
s32 face_entitytype; /*0x30*/
s32 face_entityid; /*0x34*/
s32 reaim; /*0x38*/
s32 turning; /*0x3c*/
u32 checkfacingwall; /*0x40*/
s32 wallcount; /*0x44*/
f32 mergetime; /*0x48*/
s8 face_target; /*0x4c*/
};
struct act_kneel
{
int padding[30];
};
struct act_anim
{
u32 unk02c; /*0x2c*/
u32 holdLastFrame; /*0x30*/
u32 playSfx; /*0x34*/
u32 idleOnEnd; /*0x38*/
u32 noTranslate; /*0x3c*/
u8 unk040; /*0x40*/
u8 unk041; /*0x41*/
u16 unk042; /*0x42*/
u16 unk044; /*0x44*/
u16 unk046; /*0x46*/
s16 animnum; /*0x48*/
u8 flip; /*0x4a*/
f32 startframe; /*0x4c*/
f32 endframe; /*0x50*/
f32 unk054; /*0x54*/
f32 unk058; /*0x58*/
};
struct act_die
{
s32 notifychrindex; /*0x2c*/
f32 thudframe1; /*0x30*/
f32 thudframe2; /*0x34*/
f32 timeextra; /* name from PD */ /*0x38*/
f32 elapseextra; /* name from PD */ /*0x3c*/
coord3d extraspeed; /* name from PD */ /*0x40*/
s16 drcarollimagedelay; /*0x4c*/
};
struct act_dead
{
bool allowfade; /*0x2c*/
bool allowreap; /*0x30*/
s32 reaptimer; /*0x34*/
s32 fadetimer; /*0x38*/
s32 notifychrindex; /*0x3c*/
};
struct act_argh
{
s32 notifychrindex; /*0x2c*/
s32 unk30;
};
struct act_preargh
{
coord3d pos; /*0x2c vec*/
f32 unk038; /*0x38 relshotangle*/
s32 unk03c; /*0x3c hitpart*/
s32 unk040; /*0x40 weaponid*/
u32 unk044; /*0x44*/
};
struct act_attack
{
struct weapon_firing_animation_table *animfloats; /*0x2c*/
s8 unk30; /*0x30*/
s8 unk31;
s8 unk32; /*0x32*/
s8 unk33; /*0x33*/
s8 unk34; /*0x34*/
s8 unk35; /*0x35*/
s8 unk36; /*0x36*/
s8 unk37;
s8 unk38[2]; /*0x38*/
s8 unk3a[2];
s8 unk3c[2]; /*0x3c*/
s8 unk3e;
s8 unk3f;
u32 unk40; /*0x40*/
/**
* Related to attack_time, maybe previous attack time?
* Offset 0x44.
*/
s32 unk44;
/**
* Offset 0x48.
*/
s32 attack_time;
/**
* attack type is the target flag used by the AI fire at target commands.
* chr offset 0x4c.
*/
u32 attacktype;
u32 entityid; /*0x50*/
u32 unk54; /*0x54*/
s32 type_of_motion; /*0x58 reaim*/
u32 unk5C;
u32 unk60;
u32 unk64;
u32 unk68;
u32 unk6c;
u32 unk70;
u32 unk74;
u32 unk78;
u32 unk7c;
s8 attack_item;
u8 unk81;
u8 unk82;
u8 unk83;
};
struct act_attackwalk
{
u32 unk02c; /*0x2c*/
s32 clock_timer30; /*0x30*/
s32 clock_timer34; /*0x34*/
u32 unk038; /*0x38*/
struct weapon_firing_animation_table *animfloats; /*0x3c*/
s32 timer40; /*0x40*/
s32 unk044; /*0x44*/
s8 unk48[2]; /*0x48*/
s8 unk4a[2]; /*0x48*/
s8 unk4C[2]; /*0x4c*/
u8 flip; /*0x4e*/
s8 unk4f;
s32 unk50;
f32 speed;
u32 unk58;
u32 unk5C;
u32 unk60;
u32 unk64;
u32 unk68;
u32 unk6c;
u32 unk70;
u32 unk74;
u32 unk78;
u32 unk7c;
s8 attack_item;
u8 unk81;
u8 unk82;
u8 unk83;
};
struct act_attackroll
{
struct weapon_firing_animation_table *animfloats; /*0x2c*/
s8 unk30; /*0x30*/
s8 unk31;
s8 unk32; /*0x32*/
s8 unk33; /*0x33*/
s8 unk34; /*0x34*/
s8 unk35; /*0x35*/
s8 unk36; /*0x36*/
s8 unk37;
s8 unk38[2]; /*0x38*/
s8 unk3a[2];
s8 unk3c[2]; /*0x3c*/
s8 unk3e;
s8 unk3f;
u32 unk40; /*0x40*/
/**
* Related to attack_time, maybe previous attack time?
* Offset 0x44.
*/
s32 unk44;
/**
* Offset 0x48.
*/
s32 attack_time;
s32 unk4c[2];
s32 unk54[2];
u32 unk5C;
u32 unk60;
u32 unk64;
u32 unk68;
u32 unk6c;
u32 unk70;
u32 unk74;
u32 unk78;
u32 unk7c;
s8 attack_item;
u8 unk81;
u8 unk82;
u8 unk83;
};
struct act_sidestep
{
bool side; /*0x2c*/
};
struct act_jumpout
{
bool side; /*0x2c*/
};
struct act_runpos
{
coord3d pos; /*0x2c*/
/**
* chr offset 0x38.
*/
f32 neardist; /*0x38*/
/**
* chr offset 0x3c.
*/
s32 eta60; /*0x3c*/
/**
* chr offset 0x40.
*/
f32 turnspeed; /*0x40*/
};
struct patrol_path
{
s32 *data;
u8 unk04;
u8 flags;
u16 len;
};
struct act_patrol
{
struct patrol_path *path; /*0x02c*/
s32 nextstep; /*0x030*/
bool forward; /*0x034*/
struct waydata waydata; /*0x038*/
s32 lastvisible60;
/**
* Offset 0x7c.
*/
f32 speed;
s32 unk80;
s32 unk84;
s32 unk88;
s32 unk8c;
s32 unk90;
s32 unk94;
s32 unk98;
s32 unk9c;
s32 unka0;
};
struct act_gopos
{
coord3d targetpos; // Target pos /*0x02c*/
StandTile *target; // Target/final waypoint /*0x038*/
waypoint *target_path; /*0x03c*/
// Array of pointers to the next couple of waypoints. Recalculated each time
// a waypoint is reached, and probably even more frequently than that.
waypoint *waypoints[MAX_CHRWAYPOINTS]; /*0x040*/
// Index of the waypoint in the above array that the chr is running to. If
// the chr has line of sight (through doors) to the next or next + 1 then
// the index can be changed to that one and the chr will run straight to it.
// This index will always be 0, 1 or 2. When it reaches 3 the pathfinding is
// recalculated, the array replaced with a new one and index set to 0.
/* player offset 0x58 */
u8 curindex;
u8 unk59; // guess: room
// g_ClockTimer related
u16 unk5a;
// offset 0x5c
struct waydata waydata;
// last update time?
s32 unk9c;
/**
* Offset 0x9a.
*/
f32 speed;
// PD reference below:
// Array of pointers to the next couple of waypoints. Recalculated each time
// a waypoint is reached, and probably even more frequently than that.
// struct waypoint *waypoints[5]; // MAX_CHRWAYPOINTS]; /*0x040*/
// Index of the waypoint in the above array that the chr is running to. If
// the chr has line of sight (through doors) to the next or next + 1 then
// the index can be changed to that one and the chr will run straight to it.
// This index will always be 0, 1 or 2. When it reaches 3 the pathfinding is
// recalculated, the array replaced with a new one and index set to 0.
//u8 curindex; /*0x054*/
// x....... = walking directly to pad due to PADFLAG_AIWALKDIRECT
// .x...... = ducking due to PADFLAG_AIDUCK
// ....x... = on preset path
// ......xx = speed
//u8 flags; /*0x055*/
//u16 restartttl; /*0x056*/
//struct waydata waydata; /*0x058*/
///////////////////////////////////////////
// u8 mode; /*0x00 58*/
// u8 unk01; /*0x01 59*/
// u16 unk02; /*0x02 5a*/
// coord3d pos; /*0x04 5c*/
// coord3d pos2; /*0x10 68*/
// u32 unk1c; /*0x1c 74*/
// u32 unk20; /*0x20 78*/
// u32 unk24; /*0x24 7c*/
// s32 age; /*0x28 80*/
// coord3d pos_copy; /*0x2c 84*/
// // These are the distances between the current waypoint and the previous
// // when using cheap mode.
// f32 segdistdone; /*0x38 90*/
// f32 segdisttotal; /*0x3c 94*/
///////////////////////////////////////////
//s32 cheapend60; // lvframe60 time that the chr exited cheap method of wayfinding /*0x098*/
//f32 unk0ac; /*0x09c*/
};
struct act_surrender
{
int padding[30];
};
struct act_lookattarget
{
int padding[30];
};
struct act_surprised
{
u32 type; /*0x2c*/
};
struct act_startalarm
{
int padding[30];
};
struct act_throwgrenade
{
u32 entitytype; /*0x2c*/
u32 entityid; /*0x30*/
u32 hand; /*0x34*/
bool needsequip; /*0x38*/
};
struct act_turndir
{
int padding[30];
};
struct act_test
{
int padding[30];
};
struct act_bondintro
{
int padding[30];
};
struct act_bonddie
{
int padding[30];
};
struct act_bondmulti
{
f32 *unk2c; // probably pointer to animation data, similar to weapon_firing_animation_table
s32 unk30;
s32 unk34;
s32 unk38;
s32 unk3c;
int padding[25];
};
struct act_null
{
int padding[30];
};
struct act_bytes
{
s8 padding[120];
};
struct act_ubytes
{
u8 padding[120];
};
#pragma endregion ACT_TYPES
#pragma region Prop, Chr and Definition Records
/**
* Prop Record holds the relationship between various "props" on a stage.
*/
typedef struct PropRecord
{
u8 type; /*0x00 PROP_TYPE */
u8 flags; /*0x01*/
s16 timetoregen; // ticks down /*0x02*/
union
{
struct ChrRecord *chr;
struct ObjectRecord *obj;
struct DoorRecord *door;
struct WeaponObjRecord *weapon;
struct Explosion *explosion;
struct Smoke *smoke;
struct Scorch *scorch;
void *voidp;
}; /*0x04*/
coord3d pos; /*0x08*/
StandTile *stan; /*0x14 canonical name */
/**
* Maybe float. Something related to draw (render) distance.
*/
f32 zDepth; /*0x18*/
struct PropRecord *parent; /*0x1c*/
struct PropRecord *child; /*0x20*/
struct PropRecord *prev; /*0x24*/
struct PropRecord *next; /*0x28*/
u8 rooms[PROPRECORD_STAN_ROOM_LEN]; /*0x2c*/
s32 unk30;
// u16 unk38; /*0x38* /
// s16 unk3a; /*0x3a* /
// u8 unk3c; /*0x3c* /
// u8 propstateindex; /*0x3d* /
// u8 unk3e; /*0x3e* /
// u8 unk3f_00 : 1; /*0x3f* /
// u8 unk3f_01 : 1; /*0x3f* /
// u8 unk3f_02 : 1; /*0x3f* /
// u8 unk3f_03 : 1; /*0x3f* /
// u8 unk3f_04 : 1; /*0x3f* /
// u8 unk3f_05 : 1; /*0x3f* /
// u8 unk3f_06 : 1; /*0x3f* /
// u8 unk3f_07 : 1; /*0x3f* /
// u32 unk40; /*0x40* /
// u32 unk44; /*0x44*/
} PropRecord;
#pragma region GlobalPropDef
/**
* Record for bullet/laser beam tracers.
*
* sizeof = 0x2c = 44 bytes.
*/
typedef struct BeamRecord
{
/***/
s8 unk00;
s8 item_id; // type ITEM_IDS
char unk02;
char unk03;
coord3d pos;
/**
* Offset 0x10
*/
struct coord3d delta;
f32 unk1c;
f32 unk20;
f32 unk24;
f32 unk28;
} BeamRecord;
typedef struct PropDefHeaderRecord
{
u16 extrascale; /*0x0 Fixed-Point format u8.8 eg: 0x03.80 = 3.5*/
/*
Destroyed, respawn, defused etc
8x destroyed
4x datathief/defuser/decoder used on obj (activated?)
2x
1x
x8 external allocated collision block present
x4 respawn enabled
x2
x1 damaged
*/
u8 state;
u8 type; /*0x3*/
} PropDefHeaderRecord;
#define New_PropDefHeaderRecord(scale, Type) \
{ \
(scale) * 256, PROPSTATE_NORMAL, Type \
}
#pragma endregion GlobalPropDef
/* unfinished struct, WIP */
typedef struct ChrRecord
{
s16 chrnum; /* 0x0000 */
s8 accuracyrating; /* 0x0002 */
s8 speedrating; /* 0x0003 */ //0-100
u8 firecount[2]; /* 0x0004 */
s8 headnum; /* 0x0006 */
ACT_TYPE actiontype : 8; /* 0x0007 */ //force 8bit
s8 sleep; /* 0x0008 */
s8 invalidmove; /* 0x0009 */
s8 numclosearghs; /* 0x000A */
s8 numarghs; /* 0x000B */
u8 fadealpha; /* 0x000C */
s8 arghrating; /* 0x000D */
s8 aimendcount; /* 0x000E */
s8 bodynum; /* 0x000F */
u8 grenadeprob; /* 0x0010 */
s8 flinchcnt; /* 0x0011 */
u16 hidden; /* 0x0012 */
CHRFLAG chrflags; /* 0x0014 */
PropRecord *prop; /* 0x0018 */
Model *model; /* 0x001C */
ModelHitEntry *field_20; /* 0x0020 */
f32 chrwidth; /* 0x0024 */
f32 chrheight; /* 0x0028 */
union
{
struct act_init act_init;
struct act_stand act_stand;
struct act_kneel act_kneel;
struct act_anim act_anim;
struct act_die act_die;
struct act_dead act_dead;
struct act_argh act_argh;
struct act_preargh act_preargh;
struct act_attack act_attack;
struct act_attackwalk act_attackwalk;
struct act_attackroll act_attackroll;
struct act_sidestep act_sidestep;
struct act_jumpout act_jumpout;
struct act_runpos act_runpos;
struct act_patrol act_patrol;
struct act_gopos act_gopos;
struct act_surrender act_surrender;
struct act_lookattarget act_lookattarget;
struct act_surprised act_surprised;
struct act_startalarm act_startalarm;
struct act_throwgrenade act_throwgrenade;
struct act_turndir act_turndir;
struct act_test act_test;
struct act_bondintro act_bondintro;
struct act_bonddie act_bonddie;
struct act_bondmulti act_bondmulti;
struct act_null act_null;
struct act_bytes act_bytes;
struct act_ubytes act_ubytes;
};
f32 sumground; /*0xA4*/
f32 manground; /*0xA8*/
f32 ground; /*0xAC*/
coord3d fallspeed; /*0xB0*/
coord3d prevpos; /*0xBC*/
s32 lastwalk60; /*0xC8*/
s32 lastmoveok60; /*0xCC*/
f32 visionrange; /*0xD0*/
s32 lastseetarget60; /*0xD4*/
coord3d lastknowntargetpos; /*0xD8 confirmed*/
void *targetTile; /*0xE4 maybe lastshooter*/
/*0xE8 */
union
{
s32 seen_bond_time;
struct
{
s16 lastshooter; /*0xE8 */
s16 timeshooter; /*0xEA*/
};
};
f32 hearingscale; /*0xEC increases when shot at*/
s32 lastheartarget60; /*0xF0 increases after hearing bond (NOTE s32 not u32) */
/* this next block MUST exist here */
rgba_u8 shadecol; /*0xF4 stan colour eg, white = 0,0,0,0, grey = 0,0,0,64, black = 0,0,0,128, red = 255,0,0,128*/
rgba_u8 nextcol; /*0xF8 (allows gradual transition) Stan colour is applied via "FOG" colour reg*/
f32 damage; /* 0x00FC confirmed*/
f32 maxdamage; /* 0x0100 confirmed*/
AIRecord *ailist; /* 0x0104 confirmed*/
u16 aioffset; /* 0x0108 confirmed*/
s16 aireturnlist; /* 0x010A confirmed*/
u8 morale; /* used by ai commands 81-85 */
u8 alertness; /* used by ai commands 86-8A */
u8 flags2; /*canonical name */
u8 random;
s32 timer60; /* 0x0110 */
s16 padpreset1; /* ID PAD_PRESET */
s16 chrpreset1; /* ID CHR_PRESET */
s16 chrseeshot; /* ID CHR_SEE_SHOT - ignores invincible/armoured guards */
s16 chrseedie; /* ID CHR_SEE_DIE */
/* 0x011C */
/**
* Four pairs are:
* - Stans? head
* - yminmax
* - xz
* - width
* Offset 0x011c.
*/
rect4f collision_bounds;
/* 0x013c */
f32 shotbondsum;
/* 0x0140 */
f32 aimuplshoulder;
f32 aimuprshoulder;
f32 aimupback;
f32 aimsideback;
/* 0x0150 */
f32 aimendlshoulder;
f32 aimendrshoulder;
f32 aimendback;
f32 aimendsideback;
PropRecord *weapons_held[2]; /* handle_positiondata 0x0160 0x0164 Right, Left */
struct { /* 0x0168 */
ALSoundState *ptr_SEbuffer1;
ALSoundState *ptr_SEbuffer2;
} field_160[2];
s32 field_178[2]; // 0x178-17c
/* 0x0180 */
/**
* Method chrlvFireWeaponRelated calls CapBeamLengthAndDecideIfRendered, and passes an address
* which makes it look like this is an array at ChrRecord offset 180.
*/
BeamRecord beams[2];
PropRecord *handle_positiondata_hat;
} ChrRecord;
// ChrRecord *pChrData; //not Global, local to Object or function
typedef struct ChrRenderContext {
s32 unk00;
ChrRecord *chr;
} ChrRenderContext;
#pragma region IndividualObjectTypes
typedef struct collision_data
{
s32 edges; // 0x00
coord2d polygon[8]; // 0x04 - 0x43
f32 top; // 0x44
f32 bottom; // 0x48
} collision_data;
typedef struct Projectile {
u32 flags;
coord3d speed;
coord3d unk10;
f32 unk1C;
Mtxf mtx; // 0x20-0x5c
f32 unk60;
f32 unk64;
f32 unk68[4];
f32 unk78[4];
struct PropRecord* ownerprop; // 0x88
f32 unk8C;
u32 unk90;
f32 unk94;
struct ALSoundState* sounds[2]; // 0x98
u32 lastSfxTimer; // 0xa0
u32 soundSlot; // 0xa4
u32 unkA8;
u32 unkAC;
f32 unkB0; // runtime y position?
f32 unkB4; // previous pos.y?
DROPTYPE droptype; // 0xB8
s32 refreshrate; // 0xBC;
f32 unkC0;
f32 unkC4;
f32 unkC8;
u8 unkCC[8]; // array of rooms
f32 unkd4; // probably struct coord3d
u32 unkD8;
u32 unkDC;
u32 age; //0xE0
struct ObjectRecord* obj; // 0xE4;
s32 unkE8;
} Projectile;
typedef struct Embedment {
/*0x000*/ s32 flags;
/*0x004*/ Mtxf matrix;
/*0x044*/ struct Projectile *projectile;
} Embedment;
// Not exactly sure where this belongs or if it may even already have an existing struct
typedef struct AttachmentChild {
u8 pad00[0x01];
u8 flags1; // 0x01
u8 pad02[0x16];
f32 unk18; // 0x18
} AttachmentChild;
// Not exactly sure where this belongs or if it may even already have an existing struct
typedef struct AttachedObj {
u8 pad00[0x10];
AttachmentChild *child; // 0x10
Model *model; // 0x14
Mtxf transform; // 0x18
coord3d position; // 0x58
} AttachedObj;
/**
* Object (Prop Definition) Record holds common data such as pad and health.
*/
typedef struct ObjectRecord
{
inherits PropDefHeaderRecord;
s16 obj; //canonical name, use with PROP_ enum eg PROP_ALARM1
/* ID 0x6
0000+ or 2710+ (10,000+) to use standard presets.
-1 to -256 to set this object
inside the previous object.(solo only)
if control nibble 4x is set at 0xB,
then this number matches the ID of a guard
*/
s16 pad;
/*0x8
8x indicates right-handed gun assignment
4x 08 weapon does not provide ammunition when collected
2x indicates object in motion or special function is activated
1x indicates left-handed normal pickup or opposite alignment
0x indicates no control features set
x8
x4 (unknown) Jungle bushes
x2 (unknown) pete grenade
x1 indicates embedded crate or other object, creating a chain of boxes, for
example x0 indicates normal preset, or beginning/end of chain
Doors:
8x open by default
4x area behind door is always visible (no blackouts for gates, lab doors, etc)
2x open backwards
1x same as 0 as far as I can tell
x8 always open away from the player regardless what side you're on
x4
x2 player can't activate door (spawn block or 16 type activation)
x1
0x9:
8x
4x immobile
2x (unknown) Silo DAT tape
1x uncollectable
x8
x4 allows object pickup (chr_name objects only)
x2 invincibility
x1
0xA:
8x indicates contained within another object (forward or back # objects = preset value)
4x indicates object does not use normal presets but is assigned to guard #preset
2x (unknown) part of forced collectable objects
1x think this sets object to absolute position. (similar to 2xxx type)
x8 something to do with free-standing glass (glass walls)
x4 (unknown) streets buildings/roadblocks
x2 seems to align image to preset values for glass
x1 force collisions (2xxx presets, mostly)
0xB:
0xxx presets:
00 default, on ground
x1 forced to ground
x2 room upper limit, rotated y 90 degrees. top faces direction, front faces up
x4 room upper limit, upside-down
x8 room upper limit, right side up
2xxx presets:
x1 normal placement
x2 rotated y 90 degrees. top faces direction, front faces up. (use on obj 68-6B)
x4 upside-down
x8 in-air
1x scale object to fit completely within preset bounds
2x x set to preset bounds
4x y set to preset bounds
8x z set to preset bounds
*/
u32 flags;
/*0xC:
8x force maximum explosion radius/disable detecting
player
4x autoturrets: reset to default, not preset position
2x no AI interaction
1x 1-way lock (back)
x8 1-way lock (front)
x4
x2 Objects (rockets, mines, etc) do not collide with object
x1 don't load 4 player
0xD:
8x don't load 3 player
4x don't load 2 player
2x immune to explosions (only gunfire damages object)
1x bulletproof
x8 invisible! can't shoot, but can hit with rockets, bugs, etc. not counted as a hit
x4
x2 (unknown) streets buildings
x1
0xE:
8x Can fire through object
4x immune to gunfire (Only explosives damage object)
2x Remove from game when destroyed (anything on top doesn't fall off! Just Poof! gone)
1x
x8 only activate at close range
x4
x2 explode on contact with tank?
x1 (unknown) jungle bush
0xF:
8x don't load on 007
4x don't load on 00 agent
2x don't load on secret agent
1x don't load on agent
x8 don't load multiplayer (difficulty = -1)
x4 disable activation text
x2 lightweight (previous: 2xxx drops to ground when destroyed)
x1 used on stuff in egyptian, sevx
*/
u32 flags2;
PropRecord *prop; /*0x10*/
Model *model; /*0x14*/
// mtx realrot;
#if 0
void *runtime_MATRIX0; /*0x18*/
void *runtime_MATRIX1; /*0x1c*/
void *runtime_MATRIX2; /*0x20*/
void *runtime_MATRIX3; /*0x14*/
void *runtime_MATRIX4; /*0x28*/
void *runtime_MATRIX5; /*0x2c*/
void *runtime_MATRIX6; /*0x30*/
void *runtime_MATRIX7; /*0x34*/
void *runtime_MATRIX8; /*0x38*/
void *runtime_MATRIX9; /*0x3c*/
void *runtime_MATRIXA; /*0x40*/
void *runtime_MATRIXB; /*0x44*/
void *runtime_MATRIXC; /*0x48*/
void *runtime_MATRIXD; /*0x4c*/
void *runtime_MATRIXE; /*0x50*/
void *runtime_MATRIXF; /*0x54*/
#endif
Mtxf mtx; /* Hopefully this is 16 words long*/
coord3d runtime_pos; /*0x58 - 0x60*/
union
{
#if 0
/*This union is a test but is less efficient than doing binary compare by hand eg runtimebitflags && REMOVED*/
struct
{
bool _80000000 : 1;
bool _40000000 : 1;
bool _20000000 : 1;
bool _10000000 : 1;
bool _08000000 : 1;
bool _04000000 : 1;
bool _02000000 : 1;
bool _01000000 : 1;
bool _00800000 : 1;
bool _00400000 : 1;
bool _00200000 : 1;
bool _00100000 : 1;
bool _00080000 : 1;
s32 owner : 2; /*Owner 2bit (0-3)*/
bool _00010000 : 1;
bool _00008000 : 1;
bool isActivated : 1; /* activated*/
bool _00002000 : 1;
bool _00001000 : 1;
bool _00000800 : 1;
bool _00000400 : 1;
bool isDestroyed : 1; /* only set with disabled or destroyed doors */
bool hasBeenOpened : 1;
bool isDeposited : 1; /* depositted (thrown) */
bool _00000040 : 1;
bool _00000020 : 1;
bool _00000010 : 1;
bool _00000008 : 1;
bool remove : 1; /* removes object when set */
bool _00000002 : 1;
bool _00000001 : 1;
} runtime_bitflag;
#endif
/*0x64*
10000000
00060000 owner (0-3); used to attribute kills to players
00004000 activated
00000200 only set with disabled or destroyed doors
00000080 depositted (thrown)
00000004 removes object when set
*/
u32 runtime_bitflags;
};
collision_data *ptr_allocated_collisiondata_block;
union {
struct Projectile *projectile; // 0x6c
struct Embedment *embedment; // 0x6c
};
f32 maxdamage; // 0x70
f32 damage; // 0x74
rgba_u8 shadecol; // 0x78
rgba_u8 nextcol; // 0x7C
} ObjectRecord;
#define New_ObjectRecord(pad) \
{ \
New_PropDefHeaderRecord(3), 0, pad + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xbadbee6c, 0, 1000, 0, 0, \
0, 0, 0, 0, 0, 0, 0 \
}
// PROPDEF_DOOR (1)
typedef struct DoorRecord
{
inherits ObjectRecord;
/* GE Door maybe different to PD?
80: linked with other doors (4 bytes)
if used, uses # objects up/down to other door.
when this object activates, targetted object also activates
you usually want both doors to point at each other, obviously
84: distance door travels when opening/closing (total%)
88: distance before door loses collisions (total%)
00150000 -> 41a80000
8C: open/close accelleration rate
90: rate used when someone activates a door as it opens/closes
0100 -> 3B800000
94: open/close max speed
1999 -> 3DCCC800
note: *speed sets the speed the door opens at.
the two rate features affect how long it takes to reach this max speed.
98: open technique (2+2 bytes)
0000 0000 slider (left/right) clears the door away as it slides, stopping visual problems when opening into a wall
0004 0000 slider (left/right)
0000 0004 shutter (up/down) clears the door as it slides
0004 0004 shutter (up/down)
0000 0005 special (swinging) defined here
0000 0006 special (eye) defined here in block
0000 0007 special (iris) defined here
9F: nonzero to lock
A0: amount of ms door remains open
A7: opening sound effect
A8: runtime - (float)
AC: runtime - (float)
B0: runtime - (float)
B4: runtime - (float) current distance travelled
B8: runtime - (float)
BC: runtime -
BD: runtime -
C8: runtime -
CC: runtime - p->vertex buffer when door does not clear
F0: runtime -
F4: runtime -
F8: runtime -
*/
s32 linkedDoorOffset; /*0x80*/
/**
* Distance door travels when opening/closing (total%).
* Offset 0x84.
*/
f32 maxFrac;
/**
* Distance before door loses collisions (total%) (vertical height % until Bond can walk through).
* Offset 0x88.
*/
f32 perimFrac;
/**
* Start moving acceleration rate (when a door is first opened/closed).
* Offset 0x8c.
*/
f32 accel;
/**
* Start slowing down acceleration rate (when a door is almost entirely opened/closed).
* Offset 0x90.
*/
f32 decel;
/**
* Maximum speed door can move on each update.
* Offset 0x94.
*/
f32 maxSpeed;
/**
* open technique (2+2 bytes).
*
* 0000 0000 slider (left/right) clears the door away as it slides, stopping visual problems when opening into a wall
* 0004 0000 slider (left/right)
* 0000 0004 shutter (up/down) clears the door as it slides
* 0004 0004 shutter (up/down)
* 0000 0005 special (swinging) defined here
* 0000 0006 special (eye) defined here in block
* 0000 0007 special (iris) defined here
*
* Offset 0x98.
*/
u16 doorFlags;
/**
* See doorFlags.
* Offset 0x9a.
*/
u16 doorType;
/**
* nonzero to lock.
* Offset 0x9c.
*/
u32 keyflags;
/**
* Number of frames the door remains open before closing.
* Offset 0xa0.
*/
u32 autoCloseFrames;
/**
* Sound effect played when the door is opened.
* (Actually sets the initial open, continued opening, and final open sounds).
* Offset 0xa4.
*/
u32 doorOpenSound;
/**
* Max fraction open, aka max displacement.
* Offset 0xa8.
*/
f32 frac;
f32 unkac; /*0xac*/
f32 unkb0; /*0xb0*/
/**
* Current distance travelled, aka displacement percent.
* Offset 0xb4.
*/
f32 openPosition;
/**
* Current speed of the door as it is opening or closing.
* Offset 0xb8.
*/
f32 speed;
/**
* Current open/close/other state of the door.
* States are defined in enum DOORSTATE, but asm expects a single byte.
* Offset 0xbc.
*/
s8 openstate;
s8 unkbd; /*0xbd*/
// something related to rendering
s16 calculatedopacity; /*0xbe*/
s32 TintDist; /*0xc0*/
s16 CullDist; /*0xc4*/
s8 soundType; /*0xc6*/
s8 fadeTime60; /*0xc7*/
/**
* Connected door. Opening/closing this door will also open the linkedDoor.
* Offset 0xc8.
*/
struct DoorRecord *linkedDoor;
Vertex* unkcc; /*0xcc*/
struct ModelRoData_BoundingBoxRecord bbox;
/**
* When the door completely opens, the current global timer value is
* copied into this property. Once autoCloseFrames have elapsed
* (once the difference between the timer and this value has exceeded autoCloseFrames)
* the door will start closing.
* Offset 0xec.
*/
u32 openedTime;
/**
* Portal number.
* Offset 0xf0.
*/
s32 portalNumber;
/**
* Unknown. Changes at runtime. Appears to be set to a pointer
* while the door is moving, then cleared when the door is stationary.
* If you reset this to 0 (NULL pointer), then the door opening
* sound never stops playing.
*/
ALSoundState *openSoundState;
ALSoundState *closeSoundState;
/**
* Copy of global timer value.
*
* For each sibling, the original frac is backed up into the sibling's
* lastcalc60 field. The desired frac is then calculated and set in the
* sibling's frac property. Then collision checks are done, and the original
* frac is restored if any sibling is blocked.
* Offset 0xfc.
*/
union {
s32 lastcalc60i;
f32 lastcalc60f;
};
} DoorRecord;
#define New_DoorRecord(pad) \
{ \
New_PropDefHeaderRecord(1), New_ObjectRecord(pad) \
}
/** PROPDEF_GLOBAL_DOOR_SCALE (2)
* The value is used for door calculations. Changing it will shrink/enlarge doors.
* Why they ever made it is beyond me.
* @param Scale: Fixed-Point converted to float and divided by 65536 (0x10000)
*/
typedef struct GlobalDoorScaleRecord
{
inherits PropDefHeaderRecord;
s32 Scale;
} GlobalDoorScaleRecord;
#define New_GlobalDoorScaleRecord(Scale) \
{ \
New_PropDefHeaderRecord(2), Scale + 0 \
}
// PROPDEF_PROP (3) - See ObjectRecord above
// PROPDEF_KEY (4)
typedef struct KeyRecord
{
inherits ObjectRecord;
union
{
s8 keyID;
u32 keyflags;
};
} KeyRecord;
#define New_KeyRecord \
{ \
New_PropDefHeaderRecord(4) \
}
// PROPDEF_ALARM = ObjectRecord (5)
#define New_AlarmRecord(pad) \
{ \
New_PropDefHeaderRecord(5), 0, pad + 0 \
}
struct beam {
/*0x00*/ s8 age;
/*0x01*/ s8 weaponnum;
/*0x04*/ struct coord3d from;
/*0x10*/ struct coord3d dir;
/*0x1c*/ f32 maxdist;
/*0x20*/ f32 speed;
/*0x24*/ f32 mindist;
/*0x28*/ f32 dist;
};
typedef struct AutogunRecord
{
inherits ObjectRecord;
s32 padID; // 0x80
// Units seem to be radians.
f32 rot_related; // 0x84
// Units seem to be radians.
f32 unk88;
// yzero or limit related. Units might be radians.
f32 unk8C;
// Units seem to be radians. Changes when active/firing.
f32 unk90;
// changes when active/firing
f32 unk94;
f32 unk98;
// changes when active/firing
f32 unk9C;
// Units seem to be radians. Changes when active/firing
f32 unkA0;
// How fast the gun turns. Runway default is around 0.01f.
f32 speed; // 0xA4
/**
* Distance before deactivating.
* Default (on Runway at least): 7500.0f
* Offset 0xa0.
*/
f32 aimdist; // 0xA8
s32 unkAC;
// changes when active/firing
f32 unkB0;
// changes when active/firing
f32 unkB4;
s32 unkB8;
s32 unkBC;
s32 unkC0;
ALSoundState *unkC4;
ALSoundState *unkC8;
struct beam *beam;
/**
* Offset 0xd0.
* Used in objTick, setting to zero won't disable.
*/
s32 is_active; // 0xD0
// changes when active/firing
f32 unkD4;
} AutogunRecord;
// PROPDEF_CCTV (6)
typedef struct CCTVRecord
{
inherits ObjectRecord;
#ifdef PORT
/* PC port: `inherits` expands to `struct ObjectRecord;`, which the host
* compiler (GCC) resolves by inlining ObjectRecord's members. ObjectRecord
* already has a `pad` member (s16 @0x08, the pad index set by
* New_CCTVRecord), so this `pad` (s32 @0x80) is a duplicate name that GCC
* rejects as a hard error (IDO tolerates it). The game code's `->pad`
* (e.g. setupCctv) refers to the INHERITED pad index @0x08, never to this
* member, so renaming it keeps the layout byte-identical. See
* docs/PCPortResearch.md. */
s32 lookpad; // lookpad
#else
s32 pad; // lookpad
#endif
Mtxf unk84;
f32 unkC4;
f32 unkC8;
f32 unkCC;
f32 unkD0;
s32 unkD4;
f32 unkD8;
f32 unkDC;
s32 timer; // 0xe0
s32 convert_to_f32;
f32 unkE8;
s32 unkEC;
s32 unkF0;
s32 unkF4;
s32 unkF8;
} CCTVRecord;
#define New_CCTVRecord(pad) \
{ \
New_PropDefHeaderRecord(6), 0, pad + 0 \
}
// PROPDEF_MAGAZINE (7)
typedef struct AmmoCrateRecord
{
inherits ObjectRecord;
AMMOTYPE ammoType; /*0x80*/
} AmmoCrateRecord;
#define New_AmmoCrateRecord(pad) \
{ \
New_PropDefHeaderRecord(7), 0, pad + 0 \
}
// PROPDEF_COLLECTABLE (8)
typedef struct WeaponObjRecord
{
inherits ObjectRecord;
s8 weaponnum; /*0x80 ITEM_IDS*/
s8 LinkedWeaponType; /*0x81*/
s16 timer; /*0x82*/
//u8 thrown; // Dragon and Laptop Gun /*0x83*/
//s8 unk60; /*0x60*/
//s8 dualweaponnum; /*0x61*/
/**
* Appears to have multiple uses:
* Grenades = timer?
* Proxy mines = timer? Or isarmed
* CTC briefcase = team index
*/
//s16 unk62; /*0x62*/
struct WeaponObjRecord *dualweapon; // other weapon when dual wielding /*0x84*/
} WeaponObjRecord;
#define New_WeaponObjRecord(pad) \
{ \
New_PropDefHeaderRecord(8), 0, pad + 0 \
}
#define Collectable(index, type, flag, value) _mkword(256, _mkshort(0, 8)), _mkword(184, index), flag, value, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// PROPDEF_GUARD (9) (7 words)
typedef struct GuardRecord
{
inherits PropDefHeaderRecord;
u16 chrnum; /*0x4*/
u16 PadID; /*0x6*/
u16 BodyID; /*0x8*/
u16 AIListID; /*0xa*/
u16 Preset; /*0xc*/
u16 chrpreset1; /*0xe*/
u16 health; /*0x10*/
u16 ReactionTime; /*0x12*/
/**
* Bitflags.
* See enum GUARD_SETUP_FLAG.
*/
u16 bitflags; /*0x14*/
s16 HeadID; /*0x16*/
ChrRecord *Data; /*0x18*/
} GuardRecord;
#define New_GuardRecord(pad) \
{ \
New_PropDefHeaderRecord(9), 0, pad + 0 \
}
//[This struct uses original names]
typedef struct MonitorRecord
{
u32 *cmdlist; // 0x80 4 image pointer for this monitor
u16 offset; // 0x84 2 [runtime] cur. #commands from start of routine
s16 pause60; // 0x86 2 [runtime] loop counter
struct sImageTableEntry *tconfig; //0x88 4 [runtime] monitor image# or p->image header
f32 rot; // 0x8C 4 [runtime][float] rotation
f32 xscale; // 0x90 4 [runtime] [float] cur. horizontal zoom
f32 xscalefrac; // 0x94 4 [runtime] [float] cur. h.zoom time
f32 xscaleinc; // 0x98 4 [runtime] [float] final h.zoom time
f32 xscaleold; // 0x9C 4 [runtime] [float] initial h.zoom
f32 xscalenew; // 0xA0 4 [runtime] [float] final h.zoom
f32 yscale; // 0xA4 4 [runtime] [float] cur. vertical zoom
f32 yscalefrac; // 0xA8 4 [runtime] [float] cur. v.zoom time
f32 yscaleinc; // 0xAC 4 [runtime] [float] final v.zoom time
f32 yscaleold; // 0xB0 4 [runtime] [float] initial v.zoom
f32 yscalenew; // 0xB4 4 [runtime] [float] final v.zoom
f32 xmid; // 0xB8 4 [runtime] [float] cur. horizontal position
f32 xmidfrac; // 0xBC 4 [runtime] [float] cur. h.scroll time
f32 xmidinc; // 0xC0 4 [runtime] [float] final h.scroll time
f32 xmidold; // 0xC4 4 [runtime] [float] initial h.pos.
f32 xmidnew; // 0xC8 4 [runtime] [float] final h.pos.
f32 ymid; // 0xCC 4 [runtime] [float] cur. vertical position
f32 ymidfrac; // 0xD0 4 [runtime] [float] cur. v.scroll time
f32 ymidinc; // 0xD4 4 [runtime] [float] final v.scroll time
f32 ymidold; // 0xD8 4 [runtime] [float] initial v.pos.
f32 ymidnew; // 0xDC 4 [runtime] [float] final v.pos.
u8 red; // 0xE0 1 [runtime] cur. Red
u8 redold; // 0xE1 1 [runtime] initial R
u8 rednew; // 0xE2 1 [runtime] final R
u8 green; // 0xE3 1 [runtime] cur. Green
u8 greenold; // 0xE4 1 [runtime] initial G
u8 greennew; // 0xE5 1 [runtime] final G
u8 blue; // 0xE6 1 [runtime] cur. Blue
u8 blueold; // 0xE7 1 [runtime] initial B
u8 bluenew; // 0xE8 1 [runtime] final B
u8 alpha; // 0xE9 1 [runtime] cur. Alpha
u8 alphaold; // 0xEA 1 [runtime] initial A
u8 alphanew; // 0xEB 1 [runtime] final A
f32 colfrac; // 0xEC 4 [runtime] [float] cur. colour transition time
f32 colinc; // 0xF0 4 [runtime] [float] final colour transition time
} MonitorRecord;
// PROPDEF_MONITOR (10)
typedef struct MonitorObjRecord /*116 (0x74) long*/
{
inherits ObjectRecord;
MonitorRecord Monitor;
s32 OwnerOffset;
s32 OwnerPart;
s32 ImageNum;
} MonitorObjRecord;
#define New_MonitorObjRecord(pad) \
{ \
New_PropDefHeaderRecord(10), 0, pad + 0 \
}
// PROPDEF_MULTI_MONITOR (11)
typedef struct MultiMonitorObjRecord
{
inherits ObjectRecord;
MonitorRecord Monitor[4];
u8 ImageNums[4];
} MultiMonitorObjRecord;
#define New_MultiMonitorObjRecord(pad) \
{ \
New_PropDefHeaderRecord(11), 0, pad + 0 \
}
// PROPDEF_RACK (12) - see ObjectRecrd
#define New_RackRecord(pad) \
{ \
New_PropDefHeaderRecord(12), 0, pad + 0 \
}
// PROPDEF_AUTOGUN (13)
#define New_AutogunRecord(pad) \
{ \
New_PropDefHeaderRecord(13), 0, pad + 0 \
}
// PROPDEF_LINK (14)
typedef struct LinkRecord
{
inherits PropDefHeaderRecord;
union
{
struct PropRecord *first;
s32 Index1;
};
union
{
struct PropRecord *second;
s32 Index2;
};
struct LinkRecord *next;
} LinkRecord;
#define New_LinkRecord(ID1, ID2) \
{ \
New_PropDefHeaderRecord(14), ID1 + 0, ID2 + 0 \
}
//Types 15,16 missing?
// PROPDEF_HAT (17)
typedef struct HatRecord
{
inherits ObjectRecord;
} HatRecord;
// PROPDEF_GUARD_ATTRIBUTE (18)
typedef struct GuardAttributeRecord
{
inherits PropDefHeaderRecord;
s32 chrnum; //0x4
s16 unk8; //0x8
s8 unkA; // 0xa
s8 GrenadeProb; //0xb
} GuardAttributeRecord;
#define New_GuardAttributeRecord(ID1, ID2) \
{ \
New_PropDefHeaderRecord(19), ID1 + 0, ID2 + 0 \
}
// PROPDEF_SWITCH (19) - see LinkRecord
typedef LinkRecord SwitchRecord;
#define New_SwitchRecord(ID1, ID2) \
{ \
New_PropDefHeaderRecord(19), ID1 + 0, ID2 + 0 \
}
struct multiammocrateslot {
u16 modelnum;
u16 quantity;
};
// PROPDEF_AMMO (20)
typedef struct MultiAmmoCrateRecord
{
inherits ObjectRecord;
struct multiammocrateslot slots[AMMOTYPE_GLOBAL_MAX];
} MultiAmmoCrateRecord;
#define New_MultiAmmoCrateRecord(pad) \
{ \
New_PropDefHeaderRecord(20), 0, pad + 0 \
}
// PROPDEF_ARMOUR (21)
typedef struct BodyArmourRecord
{
inherits ObjectRecord;
f32 initialamount;
f32 amount;
} BodyArmourRecord;
#define New_BodyArmourRecord(pad) \
{ \
New_PropDefHeaderRecord(21), 0, pad + 0 \
}
// PROPDEF_TAG (22)
typedef struct TagObjectRecord
{
inherits PropDefHeaderRecord;
u16 ID;
s16 OffsetToObj; //offset from tag
struct TagObjectRecord *NextTag;
ObjectRecord * TaggedObject;
} TagObjectRecord;
#define New_TagObjectRecord(Object) \
{ \
New_PropDefHeaderRecord(22), 0, Object + 0 \
}
// PROPDEF_WATCH_MENU_OBJECTIVE_TEXT (35)
typedef struct WatchMenuObjectiveTextRecord
{
inherits PropDefHeaderRecord;
u16 unk4;
} WatchMenuObjectiveTextRecord;
#define New_CollectObjectRecord(TagID) \
{ \
New_PropDefHeaderRecord(28), TagID + 0 \
}
// PROPDEF_OBJECTIVE_x (23,24 ) - maybe wrong...
typedef struct MissionObjectiveRecord
{
inherits PropDefHeaderRecord; /*0*/
s32 ObjRefID; /*4*/
u32 TextID; /*8*/
DIFFICULTY MinDificulty; /*c*/
WatchMenuObjectiveTextRecord *nextentry; /*10*/
} MissionObjectiveRecord;
#define New_MissionObjectiveRecord(TextID) \
{ \
New_PropDefHeaderRecord(23), 0, TextID + 0 \
}
#define New_EndMissionObjectiveRecord(TextID) \
{ \
New_PropDefHeaderRecord(24), 0, TextID + 0 \
}
// PROPDEF_OBJECTIVE_DESTROY_OBJECT (25)
typedef struct DestroyObjectRecord
{
inherits PropDefHeaderRecord;
u16 unk4;
} DestroyObjectRecord;
#define New_DestroyObjectRecord(TagID) \
{ \
New_PropDefHeaderRecord(25), TagID + 0 \
}
// PROPDEF_OBJECTIVE_COMPLETE_CONDITION (26)
typedef struct CompleteConditionRecord
{
inherits PropDefHeaderRecord;
u16 unk4;
} CompleteConditionRecord;
#define New_CompleteConditionRecord(TagID) \
{ \
New_PropDefHeaderRecord(25), TagID + 0 \
}
// PROPDEF_OBJECTIVE_FAIL_CONDITION (27)
typedef struct FailConditionRecord
{
inherits PropDefHeaderRecord;
u16 unk4;
} FailConditionRecord;
#define New_FailConditionRecord(TagID) \
{ \
New_PropDefHeaderRecord(27), TagID + 0 \
}
// PROPDEF_OBJECTIVE_COLLECT_OBJECT (28)
typedef struct CollectObjectRecord
{
inherits PropDefHeaderRecord;
u16 unk4;
} CollectObjectRecord;
#define New_CollectObjectRecord(TagID) \
{ \
New_PropDefHeaderRecord(28), TagID + 0 \
}
// PROPDEF_OBJECTIVE_DEPOSIT_OBJECT (29)
typedef struct DepositObjectRecord
{
inherits PropDefHeaderRecord;
u16 unk4;
} DepositObjectRecord;
#define New_CollectObjectRecord(TagID) \
{ \
New_PropDefHeaderRecord(28), TagID + 0 \
}
// PROPDEF_OBJECTIVE_PHOTOGRAPH (30)
typedef struct PhotographObjectRecord
{
inherits PropDefHeaderRecord;
u16 unk4;
u16 unk6;
u32 unk8;
PropRecord *lastprop;
} PhotographObjectRecord;
#define New_CollectObjectRecord(TagID) \
{ \
New_PropDefHeaderRecord(28), TagID + 0 \
}
// PROPDEF_OBJECTIVE_NULL (31)
typedef struct NULLObjectRecord
{
inherits PropDefHeaderRecord;
} NULLObjectRecord;
#define New_CollectObjectRecord(TagID) \
{ \
New_PropDefHeaderRecord(28), TagID + 0 \
}
// PROPDEF_OBJECTIVE_ENTER_ROOM (32)
typedef struct EnterRoomRecord
{
inherits PropDefHeaderRecord;
u16 unk4;
u32 unk8;
s32 lastroomentered;
} EnterRoomRecord;
#define New_CollectObjectRecord(TagID) \
{ \
New_PropDefHeaderRecord(28), TagID + 0 \
}
// PROPDEF_OBJECTIVE_DEPOSIT_OBJECT_IN_ROOM (33)
typedef struct DepositObjectInRoomRecord
{
inherits PropDefHeaderRecord;
u16 unk4;
} DepositObjectInRoomRecord;
#define New_CollectObjectRecord(TagID) \
{ \
New_PropDefHeaderRecord(28), TagID + 0 \
}
// PROPDEF_OBJECTIVE_COPY_ITEM (34)
typedef struct CoopyObjectRecord
{
inherits PropDefHeaderRecord;
u16 unk4;
} CoopyObjectRecord;
#define New_CollectObjectRecord(TagID) \
{ \
New_PropDefHeaderRecord(28), TagID + 0 \
}
// PROPDEF_GAS_RELEASING (36)
typedef struct GasReleasingRecord
{
inherits PropDefHeaderRecord;
u16 unk4;
} GasReleasingRecord;
#define New_CollectObjectRecord(TagID) \
{ \
New_PropDefHeaderRecord(28), TagID + 0 \
}
// PROPDEF_RENAME (37)
typedef struct RenameObjectRecord
{
inherits PropDefHeaderRecord;
s32 TagID;
s32 unk08;
s32 unk0c;
s32 unk10;
s32 unk14;
s32 unk18;
s32 unk1c;
s32 unk20;
ObjectRecord *renobj;
} RenameObjectRecord;
#define New_RenameObjectRecord(TagID) \
{ \
New_PropDefHeaderRecord(37), TagID + 0 \
}
// PROPDEF_LOCK_DOOR (38)
typedef struct LockDoorRecord
{
inherits PropDefHeaderRecord;
union
{
struct DoorRecord* door;
s32 Index1;
};
union
{
struct ObjectRecord* lock;
s32 Index2;
};
struct LockDoorRecord* next;
} LockDoorRecord;
#define New_RenameObjectRecord(TagID) \
{ \
New_PropDefHeaderRecord(37), TagID + 0 \
}
// PROPDEF_TRUCK (39)
// Vehichle Record attaches AI ailist to Object.
// [This struct uses original names]
typedef struct VehichleRecord
{
inherits ObjectRecord;
AIRecord * ailist; /*0x80*/
u16 aioffset; /*0x84*/
s16 aireturnlist; /*0x86*/
f32 speed; /*0x88 ?*/
f32 wheelxrot; /*0x8c ? changes when onscreen*/
f32 wheelyrot; /*0x90 ?*/
f32 speedaim; /*0x94 CONFIRNMED*/
f32 speedtime60; /*0x98 CONFIRNMED*/
f32 turnrot60; /*0x9c*/
f32 roty; /*0xa0*/
PathRecord *path; /*0xa4*/
s32 nextstep; /*0xa8*/
struct ALSoundState *Sound; /*0xac*/
} VehichleRecord;
// VehichleRecord *pVehichleData;//not Global, local to Object or function
// VehichleRecord *pAircraftData;//not Global, local to Object or function
#define New_VehichleRecord(pad) \
{ \
New_PropDefHeaderRecord(39), 0, pad + 0 \
}
// PROPDEF_HELI (40)
// Aircraft Record attaches Rotors to Vehichle.
// [This struct uses original names]
typedef struct AircraftRecord
{
inherits ObjectRecord;
AIRecord * ailist; /*0x80*/
u16 aioffset; /*0x84*/
s16 aireturnlist; /*0x86*/
f32 rotoryrot; /*0x88 changes when onscreen even after destruction*/
f32 rotaryspeed; /*0x8c*/
f32 rotaryspeedaim; /*0x90 CONFIRMED*/
f32 rotaryspeedtime; /*0x94 CONFIRMED*/
f32 speed; /*0x98*/
f32 speedaim; /*0x9c*/
f32 speedtime60; /*0xa0*/
f32 yrot; /*0xa4*/
s32 nextstep; /*0xa8*/
PathRecord *path; /*0xac*/
struct ALSoundState *Sound; /*0xb0*/
} AircraftRecord;
#define New_AircraftRecord(pad) \
{ \
New_PropDefHeaderRecord(40), 0, pad + 0 \
}
//PROPDEF_UNKNOWN (41)
//PROPDEF_glass (42)
typedef struct GlassRecord
{
inherits ObjectRecord;
coord3d normal;
} GlassRecord;
//PROPDEF_SAFE (42)
typedef struct SafeRecord
{
inherits ObjectRecord;
coord3d normal;
} SafeRecord;
//PROPDEF_SAFE_ITEM (42)
typedef struct SafeObjectRecord
{
inherits PropDefHeaderRecord;
union {
struct ObjectRecord *item;
s32 Index1;
};
union {
struct SafeRecord *safe;
s32 Index2;
};
union {
struct DoorRecord *door;
s32 Index3;
};
struct SafeObjectRecord *next;
} SafeObjectRecord;
// PROPDEF_TANK (45)
// [This struct uses original names] - Locs need confirming
typedef struct TankRecord
{
inherits ObjectRecord;
collision_data *collision /*0x80*/;
rect4f rect; /*0x84*/
//s32 unk88;
//s32 unk8C;
//s32 unk90;
//s32 unk94;
//s32 unk98;
//s32 unk9C;
//s32 unkA0;
s32 unkA4;
s32 unkA8;
s32 unkAC;
s32 unkB0;
s32 unkB4; // Tank! Acceleration
s32 unkB8; // Tank! Top Speed, Low Angle, Gun Type, Gun Check
s32 unkBC; // Tank! Ignition sfx, Idle sfx
s32 unkC0; // Tank! Motion sfx, crush sfx
s32 is_firing_tank;
f32 turret_vertical_angle;
f32 turret_orientation_angle;
f32 unkD0;
f32 stan_y;
s32 unkD8; // ammo related
f32 tank_orientation_angle;
} TankRecord;
#define New_TankRecord(pad) \
{ \
New_PropDefHeaderRecord(45), 0, pad + 0 \
}
// PROPDEF_CAMERAPOS (46)
typedef struct CutsceneRecord
{
inherits PropDefHeaderRecord;
coord3d pos;
f32 theta; //10
f32 verta; //14
s32 pad; //18
} CutsceneRecord;
#define New_CutsceneRecord(pad) \
{ \
New_PropDefHeaderRecord(46), 0, 0, 0, 0, 0, pad + 0 \
}
// objtype 47
typedef struct TintedGlassRecord
{
inherits ObjectRecord;
s32 TintDist;
s32 CullDist;
s32 calculatedopacity;
s32 portalnum;
f32 unk90;
} TintedGlassRecord;
#define New_TintedGlassRecord(pad) \
{ \
New_PropDefHeaderRecord(47), 0, pad + 0 \
}
// objtype 48+
#define EndObjectList PropDefHeaderRecord endme = New_PropDefHeaderRecord(48)
#pragma endregion IndividualObjectTypes
#pragma endregion //Propdefs
#pragma region Intro
#define MemberRename(from, to) \
union \
{ \
from; \
to; \
}
typedef union fs15_16
{
f32 fval;
s32 ival;
s32 full;
struct
{
s16 integer : 16;
u16 fraction : 16;
};
} fs15_16;
union SetupFloatInt
{
f32 fval;
s32 ival;
};
/**
* sizeof == 0x4
*/
typedef struct SetupIntroEmpty
{
s32 type;
} SetupIntroEmpty;
/**
* type == INTROTYPE_SPAWN
* sizeof == 0xc
*/
typedef struct SetupIntroSpawn
{
s32 type;
s32 index; // pad
MemberRename(s32 is_demo_playback, s32 demoSlot); // demoindex, perhaps called during demo
} SetupIntroSpawn;
/**
* type == INTROTYPE_ITEM
* sizeof == 0x10
*/
struct SetupIntroItem
{
s32 type;
s32 item_right;
s32 item_left;
MemberRename(s32 is_demo_playback, s32 demoSlot); // demoindex, perhaps called during demo
};
/**
* type == INTROTYPE_AMMO
* sizeof == 0x10
*/
struct SetupIntroAmmo
{
s32 type;
s32 ammo_type;
s32 ammo_amount;
MemberRename(s32 is_demo_playback, s32 demoSlot); // demoindex, perhaps called during demo
};
/**
* type == INTROTYPE_SWIRL
* sizeof == 0x20
*/
struct SetupIntroSwirl
{
s32 type;
MemberRename(s32 unk04, s32 bitflags); // bitflags
MemberRename(struct {fs15_16 unk08; fs15_16 unk0C; fs15_16 unk10; }, fs15_16 offsetfromBond[3]); // offset from Bond in cm
MemberRename(fs15_16 unk14, fs15_16 scale); // splinescale
MemberRename(fs15_16 unk18, fs15_16 duration); // duration
MemberRename(s32 unk1C, s32 pad); // lookAt
};
/**
* type == INTROTYPE_ANIM
* sizeof == 0x8
*/
struct SetupIntroAnim
{
s32 type;
s32 intro_anim;
};
/**
* type == INTROTYPE_CUFF
* sizeof == 0x8
*/
struct SetupIntroCuff
{
s32 type;
s32 bondtype;
};
/**
* type == INTROTYPE_CAMERA
* sizeof == 0x28
*/
typedef struct SetupIntroCamera
{
s32 type;
MemberRename(struct {
fs15_16 unk04;
fs15_16 unk08;
fs15_16 unk0C; }, fs15_16 coords[3]); // co-ordinates in cm scale
fs15_16 unk10; // yaw in radians
fs15_16 unk14; // pitch in radians
s32 unk18; // pad
#ifdef PORT
/* D88: lang_ptr/prev are ROM-serialized as N64 4-byte pointer-sized
* union members / struct members, but are NEVER read from file data --
* every use site (bondview_r.c) writes them (via langGet()/list-link)
* before the sole subsequent reads (bondview_r.c/bondview2.c). Widening
* them to real 8-byte PC pointers would grow sizeof(SetupIntroCamera)
* from 40 (0x28) to 56, breaking the intro-record walk's
* `(s32)intro_record + sizeof(SetupIntroCamera)` stride (bondview_r.c/
* bondview2.c) against the still-40-byte-per-record file data. Kept as
* u32 (same class as D79/D53.1); cast to the real pointer type at each
* use site under #ifdef PORT. No behavior change -- see D88 in
* PCPortResearch.md. */
union
{
u16 lang_index[2];
u32 lang_ptr;
} lang1c;
union
{
s32 lang_index;
u32 lang_ptr;
} lang20;
u32 prev;
#else
union
{
u16 lang_index[2];
char *lang_ptr;
} lang1c;
union
{
s32 lang_index;
char *lang_ptr;
} lang20;
struct SetupIntroCamera *prev;
#endif
} SetupIntroCamera;
/**
* type == INTROTYPE_WATCH
* sizeof == 0xc
*/
struct SetupIntroWatch
{
s32 type;
s32 hours;
s32 minutes;
};
/**
* sizeof == 0xc
*/
typedef struct CreditsEntry_s
{
u16 TextId1;
u16 TextId2;
s16 Position1;
/**
* See CREDITS_ALIGNMENT.
*/
u16 Alignment1;
s16 Position2;
/**
* See CREDITS_ALIGNMENT.
*/
u16 Alignment2;
} CreditsEntry;
/**
* type == INTROTYPE_CREDITS
* sizeof == 0x8
*/
struct SetupIntroCredits
{
s32 type;
s32 unk04;
};
#define CharArrayFrom32(input) ((input) & 0xFF000000) >> 24, ((input) & 0x00FF0000) >> 16, ((input) & 0x0000FF00) >> 8, (input) & 0x000000FF
#define CharArrayFrom16(input) ((input) & 0xFF00) >> 8, (input) & 0x00FF
#define IntroEmpty() CharArrayFrom32(0)
#define IntroSpawn(index, is_demo_playback) CharArrayFrom32(INTROTYPE_SPAWN), CharArrayFrom32(index), CharArrayFrom32(is_demo_playback)
#define IntroItem(item_right, item_left, is_demo_playback) CharArrayFrom32(INTROTYPE_ITEM), CharArrayFrom32(item_right), CharArrayFrom32(item_left), CharArrayFrom32(is_demo_playback)
#define IntroAmmo(ammo_type, ammo_amount, is_demo_playback) CharArrayFrom32(INTROTYPE_AMMO), CharArrayFrom32(ammo_type), CharArrayFrom32(ammo_amount), CharArrayFrom32(is_demo_playback)
#define IntroSwirl(unk04, unk08, unk0C, unk10, unk14, unk18, unk1C) CharArrayFrom32(INTROTYPE_SWIRL), CharArrayFrom32(unk04), CharArrayFrom32(unk08), CharArrayFrom32(unk0C), CharArrayFrom32(unk10), CharArrayFrom32(unk14), CharArrayFrom32(unk18), CharArrayFrom32(unk1C)
#define IntroAnim(intro_anim) CharArrayFrom32(INTROTYPE_ANIM), CharArrayFrom32(intro_anim)
#define IntroCuff(bondtype) CharArrayFrom32(INTROTYPE_CUFF), CharArrayFrom32(bondtype)
#define IntroCamera(unk04, unk08, unk0C, unk10, unk14, unk18, lang1c, lang20) CharArrayFrom32(INTROTYPE_CAMERA), CharArrayFrom32(unk04), CharArrayFrom32(unk08), CharArrayFrom32(unk0C), CharArrayFrom32(unk10), CharArrayFrom32(unk14), CharArrayFrom32(unk18), CharArrayFrom32(lang1c), CharArrayFrom32(lang20), 0
#define IntroWatch(hours, minutes) CharArrayFrom32(INTROTYPE_WATCH), CharArrayFrom32(hours), CharArrayFrom32(minutes)
#define IntroCredits(unk04) CharArrayFrom32(INTROTYPE_CREDITS), CharArrayFrom32(unk04)
#pragma endregion Intro
#pragma region Objectives
// PROPDEF_WATCH_MENU_OBJECTIVE_TEXT (35)
struct watchMenuObjectiveText
{
u32 id;
enum WATCH_BRIEFING_PAGE menu;
#ifdef PORT
/* D151: the serialized propDefs word here is a plain s32 slot id (see
* assets/obseg/setup/Usetup*Z.c `propDefs[]`: `_mkword(0,_mkshort(0,35)),
* menu, textid, 0`). The N64 decode `[u16 reserved][u16 text]` only reads
* the id because it lives in the low 16 bits of a big-endian word. On LE
* the offline d88 converter bswap32's the whole word, so the id lands in
* `text`'s low bytes only when `text` covers the full word. Was: watch
* BRIEF/OBJECTIVES + M/Q/Moneypenny pages all rendered blank (langGet(0)). */
u32 text;
#else
u16 reserved;
u16 text;
#endif
struct watchMenuObjectiveText *nextentry;
};
// PROPDEF_OBJECTIVE_x (23,24 ) - maybe not a propdef
//! FIXME all but text field cannot be trusted
struct objective_entry
{
u32 id; // 0
enum WATCH_BRIEFING_PAGE menu; // 4
#ifdef PORT
u32 text; // 8 (D151: full-word slot id, see above)
#else
u16 reserved; // 8
u16 text; // a
#endif
u16 unkC; // c
u8 unkD; // d
s8 difficulty; // f
};
#pragma endregion Objectives
#pragma region gamefile
#pragma endregion gamefile
#pragma region Images
typedef struct sImageTableEntry
{
u32 index;
u8 width;
u8 height;
u8 level;
u8 format;
u8 depth;
u8 flagsS;
u8 flagsT;
u8 pad;
} sImageTableEntry;
#pragma endregion Images
#pragma region Player
typedef struct SkyRelated38
{
f32 unk00; /*0x00*/
f32 unk04; /*0x04*/
f32 unk08; /*0x08*/
f32 unk0c; /*0x0c*/
f32 r; /*0x10*/
f32 g; /*0x14*/
f32 b; /*0x18*/
f32 a; /*0x1c*/
f32 unk20; /*0x20*/
f32 unk24; /*0x24*/
f32 unk28; /*0x28*/
f32 unk2c; /*0x2c*/
f32 unk30; /*0x30*/
f32 unk34; /*0x34*/
} SkyRelated38;
typedef struct SkyRelated18
{
f32 unk00; /*0x00*/
f32 unk04; /*0x04*/
f32 unk08; /*0x08*/
f32 unk0c; /*0x0c*/
f32 unk10; /*0x10*/
u8 r; /*0x14*/
u8 g; /*0x15*/
u8 b; /*0x16*/
u8 a; /*0x17*/
} SkyRelated18;
#pragma endregion Player
#pragma region stagesetup.h
typedef struct pname
{
union
{
char *p;
s32 offset;
};
} pname;
typedef struct stagesetup
{
waypoint *pathwaypoints;
waygroup *waypointgroups;
s32 *intro;
PropDefHeaderRecord *propDefs;
PathRecord *patrolpaths;
AIListRecord *ailists;
PadRecord *pads;
BoundPadRecord *boundpads;
pname *padnames;
pname *boundpadnames;
} stagesetup;
#pragma endregion stagesetup.h
typedef struct sfxRecord //Need 24 size
{
ALSoundState *state; //0
s32 Volume2; //4
s32 sfxID; //8
s32 Volume; //12
coord3d *pos; //16
ObjectRecord *Obj; //20
} sfxRecord;
struct sfx2 {
u16 half[2];
};
struct sfx3 {
u16 half[3];
};
typedef struct object_standard {
s16 scale;
u8 state;
u8 type;
u16 objectID;
u16 presetID;
u32 flags1;
u32 flags2;
void* ptrPOSData;
void* ptrObjInstanceController;
f32 runtime_MATRIX[4][4];
f32 xPOS;
f32 yPOS;
f32 zPOS;
int bitflags;
int ptrCollisionblock;
int field_6C;
float field_70;
short damage;
short maxdamage;
int field_78;
int field_7C;
} object_standard;
typedef struct object_weapon {
object_standard object;
u8 gun_pickup;
u8 linked_item;
s16 timer;
void* ptr_linkeditem;
} object_weapon;
struct MoveData {
// 0x0, bondviewProcessInput sp120
s32 analogWalk; // sp120 ?
s32 analogStrafe; // sp124 ?
s32 analogPitch; // sp128 ?
s32 analogTurn; // sp12C ?
// 0x10
s32 controlStickYRaw;
s32 controlStickXRaw;
s32 controlStickYSafe;
s32 controlStickXSafe;
// 0x20
s32 disableLookAhead;
s32 invertPitch;
s32 canAutoAim;
s32 detonating;
// 0x30
s32 rLeanRight;
s32 rLeanLeft;
s32 crouchUp;
s32 crouchDown;
// 0x40, bondviewProcessInput sp160
f32 zoomInFovPersec;
// sp164
f32 zoomOutFovPersec;
s32 zooming;
s32 aiming;
// 0x50
s32 weaponForwardOffset;
s32 weaponBackOffset;
f32 aimTurnRightSpeed;
f32 aimTurnLeftSpeed;
// 0x60
f32 speedVertaUp;
f32 speedVertaDown;
f32 tankTurnRightSpeed;
f32 tankTurnLeftSpeed;
// 0x70
s32 digitalStepRight;
s32 digitalStepLeft;
s32 digitalStepBack;
s32 digitalStepForward;
// 0x80
s32 canNaturalPitch;
s32 canNaturalTurn;
s32 canTurnTank;
s32 canLookAhead;
// 0x90
s32 btap;
s32 triggerOn;
s32 canManualAim;
// sp1BC
s32 canSwivelGun;
};
struct gun_trigger_state
{
s32 triggerOn[2]; // 0 = weapon trigger not held, 1 = weapon trigger held
};
struct setup_objective_text {
s32 unk00;
s32 unk04;
s32 unk08;
struct setup_objective_text *next;
};
/* matches Perfect Dark */
struct criteria_roomentered {
u32 unk00;
u32 pad;
u32 status;
struct criteria_roomentered *next;
};
/* completely made up */
struct criteria_deposit {
s32 unk00;
s32 weaponnum;
s32 padid;
s32 flag;
struct criteria_deposit *next;
};
struct criteria_picture {
s32 unk00;
s32 tag_id;
s32 flag;
struct criteria_picture *next;
};
struct PortalMetric {
struct coord3d normal;
f32 min;
f32 max;
};
struct FolderSelectColour {
s32 red;
s32 green;
s32 blue;
};
struct damage_display_val {
coord16 pos;
coord16 normal;
rgba_u8 colour;
};
struct damage_display_parent {
struct damage_display_val items[2];
};
// is this the same as damage_display_val ?
struct s_display_list_something
{
s16 unk0;
s16 unk2;
s16 unk4;
s16 unk6;
s16 unk8;
s16 unkA;
u8 unkC;
u8 unkD;
u8 unkE;
u8 unkF;
};
struct fontchar {
s32 index;
s32 baseline;
s32 height;
s32 width;
s32 kerningindex;
u8 *pixeldata;
};
struct font {
s32 kerning[13 * 13];
struct fontchar chars[94]; // can be 135 in PAL
};
#endif