door: move door module to TRX

This moves the door module fully to TRX as the logic is identical in
both games.
This commit is contained in:
lahm86 2025-04-26 10:21:03 +01:00
parent 155ae34fcc
commit 1f4c223ef2
10 changed files with 34 additions and 297 deletions

View file

@ -1,13 +1,16 @@
#include "game/box.h"
#include "game/items.h"
#include "game/objects/common.h"
#include "game/room.h"
#include "global/vars.h"
#include "game/objects/general/door.h"
#include <libtrx/game/collision.h>
#include <libtrx/game/game_buf.h>
#include <libtrx/game/lara/common.h>
#include <libtrx/game/objects/general/door.h>
#include "game/game_buf.h"
#include "game/lara/common.h"
#include "game/objects/common.h"
#include "game/pathing.h"
#include "game/rooms.h"
typedef struct {
SECTOR *sector;
SECTOR old_sector;
int16_t box_num;
} DOORPOS_DATA;
typedef struct {
DOORPOS_DATA d1;
@ -82,7 +85,7 @@ static void M_Shut(DOORPOS_DATA *const d)
sector->portal_room.pit = NO_ROOM_NEG;
sector->portal_room.wall = NO_ROOM;
const int16_t box_num = d->block;
const int16_t box_num = d->box_num;
if (box_num != NO_BOX) {
Box_GetBox(box_num)->overlap_index |= BOX_BLOCKED;
}
@ -96,7 +99,7 @@ static void M_Open(DOORPOS_DATA *const d)
*d->sector = d->old_sector;
const int16_t box_num = d->block;
const int16_t box_num = d->box_num;
if (box_num != NO_BOX) {
Box_GetBox(box_num)->overlap_index &= ~BOX_BLOCKED;
}
@ -117,10 +120,11 @@ static void M_InitialisePortal(
}
int16_t box_num = sector->box;
if (!(Box_GetBox(box_num)->overlap_index & BOX_BLOCKABLE)) {
const BOX_INFO *const box = Box_GetBox(box_num);
if ((box->overlap_index & BOX_BLOCKABLE) == 0) {
box_num = NO_BOX;
}
door_pos->block = box_num;
door_pos->box_num = box_num;
door_pos->old_sector = *door_pos->sector;
}
@ -192,32 +196,32 @@ static void M_Initialise(const int16_t item_num)
static void M_Control(const int16_t item_num)
{
ITEM *const item = Item_Get(item_num);
DOOR_DATA *const data = item->data;
DOOR_DATA *const door = item->data;
if (Item_IsTriggerActive(item)) {
if (item->current_anim_state == DOOR_STATE_CLOSED) {
item->goal_anim_state = DOOR_STATE_OPEN;
} else {
M_Open(&data->d1);
M_Open(&data->d2);
M_Open(&data->d1flip);
M_Open(&data->d2flip);
M_Open(&door->d1);
M_Open(&door->d2);
M_Open(&door->d1flip);
M_Open(&door->d2flip);
}
} else {
if (item->current_anim_state == DOOR_STATE_OPEN) {
item->goal_anim_state = DOOR_STATE_CLOSED;
} else {
M_Shut(&data->d1);
M_Shut(&data->d2);
M_Shut(&data->d1flip);
M_Shut(&data->d2flip);
M_Shut(&door->d1);
M_Shut(&door->d2);
M_Shut(&door->d1flip);
M_Shut(&door->d2flip);
}
}
M_Check(&data->d1);
M_Check(&data->d2);
M_Check(&data->d1flip);
M_Check(&data->d2flip);
M_Check(&door->d1);
M_Check(&door->d2);
M_Check(&door->d1flip);
M_Check(&door->d2flip);
Item_Animate(item);
}
@ -237,8 +241,8 @@ void Door_Collision(
if (coll->enable_baddie_push) {
Lara_Push(
item, coll,
item->current_anim_state != item->goal_anim_state ? coll->enable_hit
: false,
coll->enable_hit
&& item->current_anim_state != item->goal_anim_state,
true);
}
}

View file

@ -36,6 +36,7 @@ void Object_SwapMesh(
ANIM *Object_GetAnim(const OBJECT *obj, int32_t anim_idx);
ANIM_BONE *Object_GetBone(const OBJECT *obj, int32_t bone_idx);
extern void Object_DrawUnclippedItem(const ITEM *item);
extern void Object_DrawMesh(int32_t mesh_idx, int32_t clip, bool interpolated);
void Object_DrawInterpolatedObject(

View file

@ -176,6 +176,7 @@ sources = [
'game/objects/general/bridge_flat.c',
'game/objects/general/bridge_tilt1.c',
'game/objects/general/bridge_tilt2.c',
'game/objects/general/door.c',
'game/objects/general/drawbridge.c',
'game/objects/general/trapdoor.c',
'game/objects/names.c',

View file

@ -12,7 +12,6 @@ void Object_DrawDummyItem(const ITEM *item);
void Object_DrawSpriteItem(const ITEM *item);
void Object_DrawPickupItem(const ITEM *item);
void Object_DrawAnimatingItem(const ITEM *item);
void Object_DrawUnclippedItem(const ITEM *item);
void Object_SetMeshReflective(
GAME_OBJECT_ID obj_id, int32_t mesh_idx, bool enabled);
void Object_SetReflective(GAME_OBJECT_ID obj_id, bool enabled);

View file

@ -1,253 +0,0 @@
#include "game/box.h"
#include "game/items.h"
#include "game/lara/common.h"
#include "game/objects/common.h"
#include "game/room.h"
#include "global/vars.h"
#include <libtrx/game/collision.h>
#include <libtrx/game/game_buf.h>
#include <libtrx/game/objects/general/door.h>
#include <libtrx/utils.h>
typedef struct {
DOORPOS_DATA d1;
DOORPOS_DATA d1flip;
DOORPOS_DATA d2;
DOORPOS_DATA d2flip;
} DOOR_DATA;
static SECTOR *M_GetRoomRelSector(
const ROOM *room, const ITEM *item, int32_t sector_dx, int32_t sector_dz);
static void M_InitialisePortal(
const ROOM *room, const ITEM *item, int32_t sector_dx, int32_t sector_dz,
DOORPOS_DATA *door_pos);
static bool M_LaraDoorCollision(const SECTOR *sector);
static void M_Check(DOORPOS_DATA *d);
static void M_Shut(DOORPOS_DATA *d);
static void M_Open(DOORPOS_DATA *d);
static void M_Setup(OBJECT *obj);
static void M_Initialise(int16_t item_num);
static void M_Control(int16_t item_num);
static SECTOR *M_GetRoomRelSector(
const ROOM *const room, const ITEM *item, const int32_t sector_dx,
const int32_t sector_dz)
{
const XZ_32 sector = {
.x = ((item->pos.x - room->pos.x) >> WALL_SHIFT) + sector_dx,
.z = ((item->pos.z - room->pos.z) >> WALL_SHIFT) + sector_dz,
};
return Room_GetUnitSector(room, sector.x, sector.z);
}
static void M_InitialisePortal(
const ROOM *const room, const ITEM *const item, const int32_t sector_dx,
const int32_t sector_dz, DOORPOS_DATA *const door_pos)
{
door_pos->sector = M_GetRoomRelSector(room, item, sector_dx, sector_dz);
const SECTOR *sector = door_pos->sector;
const int16_t room_num = sector->portal_room.wall;
if (room_num != NO_ROOM) {
sector =
M_GetRoomRelSector(Room_Get(room_num), item, sector_dx, sector_dz);
}
int16_t box_num = sector->box;
if (!(Box_GetBox(box_num)->overlap_index & BOX_BLOCKABLE)) {
box_num = NO_BOX;
}
door_pos->block = box_num;
door_pos->old_sector = *door_pos->sector;
}
static bool M_LaraDoorCollision(const SECTOR *const sector)
{
// Check if Lara is on the same tile as the invisible block.
if (g_LaraItem == nullptr) {
return false;
}
int16_t room_num = g_LaraItem->room_num;
const SECTOR *const lara_sector = Room_GetSector(
g_LaraItem->pos.x, g_LaraItem->pos.y, g_LaraItem->pos.z, &room_num);
return lara_sector == sector;
}
static void M_Check(DOORPOS_DATA *const d)
{
// Forcefully remove the invisible block if Lara happens to occupy the same
// tile. This ensures that Lara doesn't void if a timed door happens to
// close right on her, or the player loads the game while standing on a
// closed door's block tile.
if (M_LaraDoorCollision(d->sector)) {
M_Open(d);
}
}
static void M_Shut(DOORPOS_DATA *const d)
{
// Change the level geometry so that the door tile is impassable.
SECTOR *const sector = d->sector;
if (sector == nullptr) {
return;
}
sector->box = NO_BOX;
sector->floor.height = NO_HEIGHT;
sector->ceiling.height = NO_HEIGHT;
sector->floor.tilt = 0;
sector->ceiling.tilt = 0;
sector->portal_room.sky = NO_ROOM;
sector->portal_room.pit = NO_ROOM;
sector->portal_room.wall = NO_ROOM;
const int16_t box_num = d->block;
if (box_num != NO_BOX) {
Box_GetBox(box_num)->overlap_index |= BOX_BLOCKED;
}
}
static void M_Open(DOORPOS_DATA *const d)
{
// Restore the level geometry so that the door tile is passable.
SECTOR *const sector = d->sector;
if (!sector) {
return;
}
*sector = d->old_sector;
const int16_t box_num = d->block;
if (box_num != NO_BOX) {
Box_GetBox(box_num)->overlap_index &= ~BOX_BLOCKED;
}
}
static void M_Setup(OBJECT *const obj)
{
obj->initialise_func = M_Initialise;
obj->control_func = M_Control;
obj->draw_func = Object_DrawUnclippedItem;
obj->collision_func = Door_Collision;
obj->save_anim = 1;
obj->save_flags = 1;
}
static void M_Initialise(const int16_t item_num)
{
ITEM *const item = Item_Get(item_num);
DOOR_DATA *const door = GameBuf_Alloc(sizeof(DOOR_DATA), GBUF_ITEM_DATA);
item->data = door;
int32_t dx = 0;
int32_t dz = 0;
if (item->rot.y == 0) {
dz = -1;
} else if (item->rot.y == -DEG_180) {
dz = 1;
} else if (item->rot.y == DEG_90) {
dx = -1;
} else {
dx = 1;
}
int16_t room_num = item->room_num;
const ROOM *room = Room_Get(room_num);
M_InitialisePortal(room, item, dx, dz, &door->d1);
if (room->flipped_room == -1) {
door->d1flip.sector = nullptr;
} else {
room = Room_Get(room->flipped_room);
M_InitialisePortal(room, item, dx, dz, &door->d1flip);
}
room_num = door->d1.sector->portal_room.wall;
M_Shut(&door->d1);
M_Shut(&door->d1flip);
if (room_num == NO_ROOM) {
door->d2.sector = nullptr;
door->d2flip.sector = nullptr;
return;
}
room = Room_Get(room_num);
M_InitialisePortal(room, item, 0, 0, &door->d2);
if (room->flipped_room == -1) {
door->d2flip.sector = nullptr;
} else {
room = Room_Get(room->flipped_room);
M_InitialisePortal(room, item, 0, 0, &door->d2flip);
}
M_Shut(&door->d2);
M_Shut(&door->d2flip);
const int16_t prev_room = item->room_num;
Item_NewRoom(item_num, room_num);
item->room_num = prev_room;
}
static void M_Control(const int16_t item_num)
{
ITEM *const item = Item_Get(item_num);
DOOR_DATA *door = item->data;
if (Item_IsTriggerActive(item)) {
if (item->current_anim_state == DOOR_STATE_CLOSED) {
item->goal_anim_state = DOOR_STATE_OPEN;
} else {
M_Open(&door->d1);
M_Open(&door->d2);
M_Open(&door->d1flip);
M_Open(&door->d2flip);
}
} else {
if (item->current_anim_state == DOOR_STATE_OPEN) {
item->goal_anim_state = DOOR_STATE_CLOSED;
} else {
M_Shut(&door->d1);
M_Shut(&door->d2);
M_Shut(&door->d1flip);
M_Shut(&door->d2flip);
}
}
M_Check(&door->d1);
M_Check(&door->d2);
M_Check(&door->d1flip);
M_Check(&door->d2flip);
Item_Animate(item);
}
void Door_Collision(int16_t item_num, ITEM *lara_item, COLL_INFO *coll)
{
ITEM *const item = Item_Get(item_num);
if (!Lara_TestBoundsCollide(item, coll->radius)) {
return;
}
if (!Collide_TestCollision(item, lara_item)) {
return;
}
if (coll->enable_baddie_push) {
if (item->current_anim_state != item->goal_anim_state) {
Lara_Push(item, coll, coll->enable_hit, true);
} else {
Lara_Push(item, coll, false, true);
}
}
}
REGISTER_OBJECT(O_DOOR_TYPE_1, M_Setup)
REGISTER_OBJECT(O_DOOR_TYPE_2, M_Setup)
REGISTER_OBJECT(O_DOOR_TYPE_3, M_Setup)
REGISTER_OBJECT(O_DOOR_TYPE_4, M_Setup)
REGISTER_OBJECT(O_DOOR_TYPE_5, M_Setup)
REGISTER_OBJECT(O_DOOR_TYPE_6, M_Setup)
REGISTER_OBJECT(O_DOOR_TYPE_7, M_Setup)
REGISTER_OBJECT(O_DOOR_TYPE_8, M_Setup)

View file

@ -123,12 +123,6 @@ typedef struct {
};
} PHD_VBUF;
typedef struct {
SECTOR *sector;
SECTOR old_sector;
int16_t block;
} DOORPOS_DATA;
typedef struct {
PASSPORT_MODE passport_selection;
int32_t select_save_slot;

View file

@ -197,7 +197,6 @@ sources = [
'game/objects/general/cabin.c',
'game/objects/general/camera_target.c',
'game/objects/general/cog.c',
'game/objects/general/door.c',
'game/objects/general/earthquake.c',
'game/objects/general/keyhole.c',
'game/objects/general/moving_bar.c',

View file

@ -6,7 +6,6 @@
void Object_DrawDummyItem(const ITEM *item);
void Object_DrawAnimatingItem(const ITEM *item);
void Object_DrawUnclippedItem(const ITEM *item);
void Object_DrawSpriteItem(const ITEM *item);
void Object_Collision(int16_t item_num, ITEM *lara_item, COLL_INFO *coll);

View file

@ -120,12 +120,6 @@ typedef enum {
GFE_REMOVE_AMMO = 22,
} GF_EVENTS;
typedef struct {
SECTOR *sector;
SECTOR old_sector;
int16_t block;
} DOORPOS_DATA;
typedef enum {
TRAP_SET = 0,
TRAP_ACTIVATE = 1,

View file

@ -195,7 +195,6 @@ sources = [
'game/objects/general/cutscene_player.c',
'game/objects/general/detonator.c',
'game/objects/general/ding_dong.c',
'game/objects/general/door.c',
'game/objects/general/earthquake.c',
'game/objects/general/final_cutscene.c',
'game/objects/general/final_level_counter.c',