mirror of
https://github.com/LostArtefacts/TRX.git
synced 2025-04-28 20:58:07 +03:00
room: refactor lava and trigger interpretation
This creates an is_death_sector property on sectors and updates the checks for when this is applicable in terms of collision and trigger checks. Triggers are also now directly in sectors, and their list of commands. Most duplicated FD iterations are now removed; injection logic to follow suit and use the new approach.
This commit is contained in:
parent
3405e8ca80
commit
da2353e05f
18 changed files with 282 additions and 396 deletions
|
@ -782,20 +782,14 @@ void Camera_UpdateCutscene(void)
|
|||
Viewport_SetFOV(ref->fov);
|
||||
}
|
||||
|
||||
void Camera_RefreshFromTrigger(int16_t type, int16_t *data)
|
||||
void Camera_RefreshFromTrigger(const TRIGGER *const trigger)
|
||||
{
|
||||
int16_t trigger;
|
||||
int16_t target_ok = 2;
|
||||
do {
|
||||
trigger = *data++;
|
||||
int16_t value = trigger & VALUE_BITS;
|
||||
|
||||
switch (TRIG_BITS(trigger)) {
|
||||
case TO_CAMERA:
|
||||
trigger = *data++;
|
||||
|
||||
if (value == g_Camera.last) {
|
||||
g_Camera.number = value;
|
||||
for (int32_t i = 0; i < trigger->command_count; i++) {
|
||||
const TRIGGER_CMD *const cmd = &trigger->commands[i];
|
||||
if (cmd->type == TO_CAMERA) {
|
||||
if (cmd->parameter == g_Camera.last) {
|
||||
g_Camera.number = cmd->parameter;
|
||||
|
||||
if (g_Camera.timer < 0 || g_Camera.type == CAM_LOOK
|
||||
|| g_Camera.type == CAM_COMBAT) {
|
||||
|
@ -808,15 +802,12 @@ void Camera_RefreshFromTrigger(int16_t type, int16_t *data)
|
|||
} else {
|
||||
target_ok = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case TO_TARGET:
|
||||
} else if (cmd->type == TO_TARGET) {
|
||||
if (g_Camera.type != CAM_LOOK && g_Camera.type != CAM_COMBAT) {
|
||||
g_Camera.item = &g_Items[value];
|
||||
g_Camera.item = &g_Items[cmd->parameter];
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while (!(trigger & END_BIT));
|
||||
}
|
||||
|
||||
if (g_Camera.item != NULL) {
|
||||
if (!target_ok
|
||||
|
|
|
@ -14,6 +14,6 @@ void Camera_Fixed(void);
|
|||
void Camera_Update(void);
|
||||
void Camera_UpdateCutscene(void);
|
||||
void Camera_OffsetReset(void);
|
||||
void Camera_RefreshFromTrigger(int16_t type, int16_t *data);
|
||||
void Camera_RefreshFromTrigger(const TRIGGER *trigger);
|
||||
void Camera_MoveManual(void);
|
||||
void Camera_Apply(void);
|
||||
|
|
|
@ -135,8 +135,8 @@ void Collide_GetCollisionInfo(
|
|||
&& coll->front_floor > 0) {
|
||||
coll->front_floor = 512;
|
||||
} else if (
|
||||
coll->lava_is_pit && coll->front_floor > 0 && g_TriggerIndex
|
||||
&& (g_TriggerIndex[0] & DATA_TYPE) == FT_LAVA) {
|
||||
coll->lava_is_pit && coll->front_floor > 0
|
||||
&& Room_GetPitSector(sector, x, z)->is_death_sector) {
|
||||
coll->front_floor = 512;
|
||||
}
|
||||
}
|
||||
|
@ -170,8 +170,8 @@ void Collide_GetCollisionInfo(
|
|||
&& coll->left_floor > 0) {
|
||||
coll->left_floor = 512;
|
||||
} else if (
|
||||
coll->lava_is_pit && coll->left_floor > 0 && g_TriggerIndex
|
||||
&& (g_TriggerIndex[0] & DATA_TYPE) == FT_LAVA) {
|
||||
coll->lava_is_pit && coll->left_floor > 0
|
||||
&& Room_GetPitSector(sector, x, z)->is_death_sector) {
|
||||
coll->left_floor = 512;
|
||||
}
|
||||
}
|
||||
|
@ -205,8 +205,8 @@ void Collide_GetCollisionInfo(
|
|||
&& coll->right_floor > 0) {
|
||||
coll->right_floor = 512;
|
||||
} else if (
|
||||
coll->lava_is_pit && coll->right_floor > 0 && g_TriggerIndex
|
||||
&& (g_TriggerIndex[0] & DATA_TYPE) == FT_LAVA) {
|
||||
coll->lava_is_pit && coll->right_floor > 0
|
||||
&& Room_GetPitSector(sector, x, z)->is_death_sector) {
|
||||
coll->right_floor = 512;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -240,7 +240,7 @@ void Lara_HandleAboveWater(ITEM_INFO *item, COLL_INFO *coll)
|
|||
g_LaraCollisionRoutines[item->current_anim_state](item, coll);
|
||||
Item_UpdateRoom(item, -LARA_HEIGHT / 2);
|
||||
Gun_Control();
|
||||
Room_TestTriggers(coll->trigger, false);
|
||||
Room_TestTriggers(item);
|
||||
}
|
||||
|
||||
void Lara_HandleSurface(ITEM_INFO *item, COLL_INFO *coll)
|
||||
|
@ -307,7 +307,7 @@ void Lara_HandleSurface(ITEM_INFO *item, COLL_INFO *coll)
|
|||
g_LaraCollisionRoutines[item->current_anim_state](item, coll);
|
||||
Item_UpdateRoom(item, 100);
|
||||
Gun_Control();
|
||||
Room_TestTriggers(coll->trigger, false);
|
||||
Room_TestTriggers(item);
|
||||
}
|
||||
|
||||
void Lara_HandleUnderwater(ITEM_INFO *item, COLL_INFO *coll)
|
||||
|
@ -397,5 +397,5 @@ void Lara_HandleUnderwater(ITEM_INFO *item, COLL_INFO *coll)
|
|||
g_LaraCollisionRoutines[item->current_anim_state](item, coll);
|
||||
Item_UpdateRoom(item, 0);
|
||||
Gun_Control();
|
||||
Room_TestTriggers(coll->trigger, false);
|
||||
Room_TestTriggers(item);
|
||||
}
|
||||
|
|
|
@ -556,7 +556,7 @@ bool Lara_LandedBad(ITEM_INFO *item, COLL_INFO *coll)
|
|||
|
||||
item->floor = height;
|
||||
item->pos.y = height;
|
||||
Room_TestTriggers(g_TriggerIndex, false);
|
||||
Room_TestTriggers(item);
|
||||
item->pos.y = old_y;
|
||||
|
||||
int landspeed = item->fall_speed - DAMAGE_START;
|
||||
|
|
|
@ -116,13 +116,11 @@ void BaconLara_Control(int16_t item_num)
|
|||
const int32_t h = Room_GetHeight(sector, x, y, z);
|
||||
item->floor = h;
|
||||
|
||||
Room_TestTriggers(g_TriggerIndex, true);
|
||||
Room_TestTriggers(item);
|
||||
if (item->pos.y >= h) {
|
||||
item->floor = h;
|
||||
item->pos.y = h;
|
||||
sector = Room_GetSector(x, h, z, &room_num);
|
||||
Room_GetHeight(sector, x, h, z);
|
||||
Room_TestTriggers(g_TriggerIndex, true);
|
||||
Room_TestTriggers(item);
|
||||
item->gravity_status = 0;
|
||||
item->fall_speed = 0;
|
||||
item->goal_anim_state = LS_DEATH;
|
||||
|
|
|
@ -255,10 +255,7 @@ void Torso_Control(int16_t item_num)
|
|||
if (item->status == IS_DEACTIVATED) {
|
||||
Sound_Effect(SFX_ATLANTEAN_DEATH, &item->pos, SPM_NORMAL);
|
||||
Effect_ExplodingDeath(item_num, -1, TORSO_PART_DAMAGE);
|
||||
const SECTOR_INFO *const sector = Room_GetSector(
|
||||
item->pos.x, item->pos.y, item->pos.z, &item->room_number);
|
||||
Room_GetHeight(sector, item->pos.x, item->pos.y, item->pos.z);
|
||||
Room_TestTriggers(g_TriggerIndex, true);
|
||||
Room_TestTriggers(item);
|
||||
|
||||
Item_Kill(item_num);
|
||||
item->status = IS_DEACTIVATED;
|
||||
|
|
|
@ -116,11 +116,7 @@ void Scion_Control3(int16_t item_num)
|
|||
if (counter == 0) {
|
||||
item->status = IS_INVISIBLE;
|
||||
item->hit_points = DONT_TARGET;
|
||||
int16_t room_num = item->room_number;
|
||||
const SECTOR_INFO *const sector =
|
||||
Room_GetSector(item->pos.x, item->pos.y, item->pos.z, &room_num);
|
||||
Room_GetHeight(sector, item->pos.x, item->pos.y, item->pos.z);
|
||||
Room_TestTriggers(g_TriggerIndex, true);
|
||||
Room_TestTriggers(item);
|
||||
Item_RemoveDrawn(item_num);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#define LAVA_EMBER_DAMAGE 10
|
||||
#define LAVA_WEDGE_SPEED 25
|
||||
|
||||
bool Lava_TestFloor(ITEM_INFO *item)
|
||||
bool Lava_TestFloor(const ITEM_INFO *const item)
|
||||
{
|
||||
if (item->hit_points < 0 || g_Lara.water_status == LWS_CHEAT
|
||||
|| (g_Lara.water_status == LWS_ABOVE_WATER
|
||||
|
@ -25,40 +25,11 @@ bool Lava_TestFloor(ITEM_INFO *item)
|
|||
// OG fix: check if floor index has lava
|
||||
int16_t room_num = item->room_number;
|
||||
const SECTOR_INFO *const sector =
|
||||
Room_GetSector(item->pos.x, 32000, item->pos.z, &room_num);
|
||||
|
||||
int16_t *data = &g_FloorData[sector->index];
|
||||
int16_t type;
|
||||
do {
|
||||
type = *data++;
|
||||
|
||||
switch (type & DATA_TYPE) {
|
||||
case FT_TILT: {
|
||||
data++;
|
||||
break;
|
||||
}
|
||||
|
||||
case FT_ROOF:
|
||||
case FT_DOOR:
|
||||
data++;
|
||||
break;
|
||||
|
||||
case FT_LAVA:
|
||||
return true;
|
||||
|
||||
case FT_TRIGGER:
|
||||
data++;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while (!(type & END_BIT));
|
||||
|
||||
return false;
|
||||
Room_GetSector(item->pos.x, MAX_HEIGHT, item->pos.z, &room_num);
|
||||
return sector->is_death_sector;
|
||||
}
|
||||
|
||||
void Lava_Burn(ITEM_INFO *item)
|
||||
void Lava_Burn(ITEM_INFO *const item)
|
||||
{
|
||||
if (g_Lara.water_status == LWS_CHEAT) {
|
||||
return;
|
||||
|
@ -70,8 +41,9 @@ void Lava_Burn(ITEM_INFO *item)
|
|||
|
||||
int16_t room_num = item->room_number;
|
||||
const SECTOR_INFO *const sector =
|
||||
Room_GetSector(item->pos.x, 32000, item->pos.z, &room_num);
|
||||
int16_t height = Room_GetHeight(sector, item->pos.x, 32000, item->pos.z);
|
||||
Room_GetSector(item->pos.x, MAX_HEIGHT, item->pos.z, &room_num);
|
||||
const int16_t height =
|
||||
Room_GetHeight(sector, item->pos.x, MAX_HEIGHT, item->pos.z);
|
||||
|
||||
if (item->floor != height) {
|
||||
return;
|
||||
|
@ -84,7 +56,7 @@ void Lava_Burn(ITEM_INFO *item)
|
|||
}
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
int16_t fx_num = Effect_Create(item->room_number);
|
||||
const int16_t fx_num = Effect_Create(item->room_number);
|
||||
if (fx_num != NO_ITEM) {
|
||||
FX_INFO *fx = &g_Effects[fx_num];
|
||||
fx->object_number = O_FLAME;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
bool Lava_TestFloor(ITEM_INFO *item);
|
||||
bool Lava_TestFloor(const ITEM_INFO *item);
|
||||
void Lava_Burn(ITEM_INFO *item);
|
||||
|
||||
void Lava_Setup(OBJECT_INFO *obj);
|
||||
|
|
|
@ -276,12 +276,7 @@ void MovableBlock_Control(int16_t item_num)
|
|||
item->status = IS_NOT_ACTIVE;
|
||||
Item_RemoveActive(item_num);
|
||||
Room_AlterFloorHeight(item, -WALL_L);
|
||||
|
||||
room_num = item->room_number;
|
||||
sector =
|
||||
Room_GetSector(item->pos.x, item->pos.y, item->pos.z, &room_num);
|
||||
Room_GetHeight(sector, item->pos.x, item->pos.y, item->pos.z);
|
||||
Room_TestTriggers(g_TriggerIndex, true);
|
||||
Room_TestTriggers(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ void RollingBall_Control(int16_t item_num)
|
|||
item->floor =
|
||||
Room_GetHeight(sector, item->pos.x, item->pos.y, item->pos.z);
|
||||
|
||||
Room_TestTriggers(g_TriggerIndex, true);
|
||||
Room_TestTriggers(item);
|
||||
|
||||
if (item->pos.y >= item->floor - STEP_L) {
|
||||
item->gravity_status = 0;
|
||||
|
|
|
@ -113,11 +113,7 @@ void ThorsHandle_Control(int16_t item_num)
|
|||
int32_t old_x = x;
|
||||
int32_t old_z = z;
|
||||
|
||||
int16_t room_num = item->room_number;
|
||||
const SECTOR_INFO *const sector =
|
||||
Room_GetSector(x, item->pos.y, z, &room_num);
|
||||
Room_GetHeight(sector, x, item->pos.y, z);
|
||||
Room_TestTriggers(g_TriggerIndex, true);
|
||||
Room_TestTriggers(item);
|
||||
|
||||
switch (item->rot.y) {
|
||||
case 0:
|
||||
|
|
426
src/game/room.c
426
src/game/room.c
|
@ -1,6 +1,7 @@
|
|||
#include "game/room.h"
|
||||
|
||||
#include "game/camera.h"
|
||||
#include "game/gamebuf.h"
|
||||
#include "game/items.h"
|
||||
#include "game/lot.h"
|
||||
#include "game/music.h"
|
||||
|
@ -17,6 +18,7 @@
|
|||
|
||||
#include <libtrx/utils.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define NEG_TILT(T, H) ((T * (H & (WALL_L - 1))) >> 2)
|
||||
|
@ -28,7 +30,7 @@ int32_t g_FlipEffect = -1;
|
|||
int32_t g_FlipStatus = 0;
|
||||
int32_t g_FlipMapTable[MAX_FLIP_MAPS] = { 0 };
|
||||
|
||||
static void Room_TriggerMusicTrack(int16_t track, int16_t flags, int16_t type);
|
||||
static void Room_TriggerMusicTrack(int16_t track, const TRIGGER *const trigger);
|
||||
static void Room_AddFlipItems(ROOM_INFO *r);
|
||||
static void Room_RemoveFlipItems(ROOM_INFO *r);
|
||||
|
||||
|
@ -36,17 +38,15 @@ static int16_t Room_GetFloorTiltHeight(
|
|||
const SECTOR_INFO *sector, const int32_t x, const int32_t z);
|
||||
static int16_t Room_GetCeilingTiltHeight(
|
||||
const SECTOR_INFO *sector, const int32_t x, const int32_t z);
|
||||
static SECTOR_INFO *Room_GetPitSector(
|
||||
const SECTOR_INFO *sector, int32_t x, int32_t z);
|
||||
static SECTOR_INFO *Room_GetSkySector(
|
||||
const SECTOR_INFO *sector, int32_t x, int32_t z);
|
||||
|
||||
static void Room_PopulateSectorData(
|
||||
SECTOR_INFO *sector, const int16_t *floor_data);
|
||||
|
||||
static void Room_TriggerMusicTrack(int16_t track, int16_t flags, int16_t type)
|
||||
static void Room_TriggerMusicTrack(int16_t track, const TRIGGER *const trigger)
|
||||
{
|
||||
if (track == MX_UNUSED_0 && type == TT_ANTIPAD) {
|
||||
if (track == MX_UNUSED_0 && trigger->type == TT_ANTIPAD) {
|
||||
Music_Stop();
|
||||
return;
|
||||
}
|
||||
|
@ -108,16 +108,16 @@ static void Room_TriggerMusicTrack(int16_t track, int16_t flags, int16_t type)
|
|||
return;
|
||||
}
|
||||
|
||||
if (type == TT_SWITCH) {
|
||||
g_MusicTrackFlags[track] ^= flags & IF_CODE_BITS;
|
||||
} else if (type == TT_ANTIPAD) {
|
||||
g_MusicTrackFlags[track] &= -1 - (flags & IF_CODE_BITS);
|
||||
} else if (flags & IF_CODE_BITS) {
|
||||
g_MusicTrackFlags[track] |= flags & IF_CODE_BITS;
|
||||
if (trigger->type == TT_SWITCH) {
|
||||
g_MusicTrackFlags[track] ^= trigger->mask;
|
||||
} else if (trigger->type == TT_ANTIPAD) {
|
||||
g_MusicTrackFlags[track] &= -1 - trigger->mask;
|
||||
} else if (trigger->mask) {
|
||||
g_MusicTrackFlags[track] |= trigger->mask;
|
||||
}
|
||||
|
||||
if ((g_MusicTrackFlags[track] & IF_CODE_BITS) == IF_CODE_BITS) {
|
||||
if (flags & IF_ONESHOT) {
|
||||
if (trigger->one_shot) {
|
||||
g_MusicTrackFlags[track] |= IF_ONESHOT;
|
||||
}
|
||||
Music_Play(track);
|
||||
|
@ -235,7 +235,7 @@ void Room_GetNewRoom(int32_t x, int32_t y, int32_t z, int16_t room_num)
|
|||
}
|
||||
}
|
||||
|
||||
static SECTOR_INFO *Room_GetPitSector(
|
||||
SECTOR_INFO *Room_GetPitSector(
|
||||
const SECTOR_INFO *sector, const int32_t x, const int32_t z)
|
||||
{
|
||||
while (sector->portal_room.pit != NO_ROOM) {
|
||||
|
@ -344,48 +344,22 @@ int16_t Room_GetCeiling(
|
|||
int16_t height = Room_GetCeilingTiltHeight(sky_sector, x, z);
|
||||
|
||||
sector = Room_GetPitSector(sector, x, z);
|
||||
if (!sector->index) {
|
||||
if (sector->trigger == NULL) {
|
||||
return height;
|
||||
}
|
||||
|
||||
data = &g_FloorData[sector->index];
|
||||
do {
|
||||
type = *data++;
|
||||
|
||||
switch (type & DATA_TYPE) {
|
||||
case FT_DOOR:
|
||||
case FT_TILT:
|
||||
case FT_ROOF:
|
||||
data++;
|
||||
break;
|
||||
|
||||
case FT_LAVA:
|
||||
break;
|
||||
|
||||
case FT_TRIGGER:
|
||||
data++;
|
||||
do {
|
||||
trigger = *data++;
|
||||
if (TRIG_BITS(trigger) != TO_OBJECT) {
|
||||
if (TRIG_BITS(trigger) == TO_CAMERA) {
|
||||
trigger = *data++;
|
||||
}
|
||||
} else {
|
||||
ITEM_INFO *item = &g_Items[trigger & VALUE_BITS];
|
||||
OBJECT_INFO *object = &g_Objects[item->object_number];
|
||||
if (object->ceiling_height_func) {
|
||||
height =
|
||||
object->ceiling_height_func(item, x, y, z, height);
|
||||
}
|
||||
}
|
||||
} while (!(trigger & END_BIT));
|
||||
break;
|
||||
|
||||
default:
|
||||
Shell_ExitSystem("GetCeiling(): Unknown type");
|
||||
break;
|
||||
for (int32_t i = 0; i < sector->trigger->command_count; i++) {
|
||||
const TRIGGER_CMD *const cmd = §or->trigger->commands[i];
|
||||
if (cmd->type != TO_OBJECT) {
|
||||
continue;
|
||||
}
|
||||
} while (!(type & END_BIT));
|
||||
|
||||
const ITEM_INFO *const item = &g_Items[cmd->parameter];
|
||||
const OBJECT_INFO *const object = &g_Objects[item->object_number];
|
||||
if (object->ceiling_height_func) {
|
||||
height = object->ceiling_height_func(item, x, y, z, height);
|
||||
}
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
@ -398,57 +372,22 @@ int16_t Room_GetHeight(
|
|||
|
||||
int16_t height = Room_GetFloorTiltHeight(sector, x, z);
|
||||
|
||||
g_TriggerIndex = NULL;
|
||||
|
||||
if (!sector->index) {
|
||||
if (sector->trigger == NULL) {
|
||||
return height;
|
||||
}
|
||||
|
||||
int16_t *data = &g_FloorData[sector->index];
|
||||
int16_t type;
|
||||
int16_t trigger;
|
||||
do {
|
||||
type = *data++;
|
||||
|
||||
switch (type & DATA_TYPE) {
|
||||
case FT_TILT:
|
||||
case FT_ROOF:
|
||||
case FT_DOOR:
|
||||
data++;
|
||||
break;
|
||||
|
||||
case FT_LAVA:
|
||||
g_TriggerIndex = data - 1;
|
||||
break;
|
||||
|
||||
case FT_TRIGGER:
|
||||
if (!g_TriggerIndex) {
|
||||
g_TriggerIndex = data - 1;
|
||||
}
|
||||
|
||||
data++;
|
||||
do {
|
||||
trigger = *data++;
|
||||
if (TRIG_BITS(trigger) != TO_OBJECT) {
|
||||
if (TRIG_BITS(trigger) == TO_CAMERA) {
|
||||
trigger = *data++;
|
||||
}
|
||||
} else {
|
||||
ITEM_INFO *item = &g_Items[trigger & VALUE_BITS];
|
||||
OBJECT_INFO *object = &g_Objects[item->object_number];
|
||||
if (object->floor_height_func) {
|
||||
height =
|
||||
object->floor_height_func(item, x, y, z, height);
|
||||
}
|
||||
}
|
||||
} while (!(trigger & END_BIT));
|
||||
break;
|
||||
|
||||
default:
|
||||
Shell_ExitSystem("GetHeight(): Unknown type");
|
||||
break;
|
||||
for (int32_t i = 0; i < sector->trigger->command_count; i++) {
|
||||
const TRIGGER_CMD *const cmd = §or->trigger->commands[i];
|
||||
if (cmd->type != TO_OBJECT) {
|
||||
continue;
|
||||
}
|
||||
} while (!(type & END_BIT));
|
||||
|
||||
const ITEM_INFO *const item = &g_Items[cmd->parameter];
|
||||
const OBJECT_INFO *const object = &g_Objects[item->object_number];
|
||||
if (object->floor_height_func) {
|
||||
height = object->floor_height_func(item, x, y, z, height);
|
||||
}
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
@ -698,6 +637,8 @@ static void Room_PopulateSectorData(
|
|||
sector->floor.tilt = 0;
|
||||
sector->ceiling.tilt = 0;
|
||||
sector->portal_room.wall = NO_ROOM;
|
||||
sector->is_death_sector = false;
|
||||
sector->trigger = NULL;
|
||||
|
||||
if (sector->index == 0) {
|
||||
return;
|
||||
|
@ -722,18 +663,39 @@ static void Room_PopulateSectorData(
|
|||
break;
|
||||
|
||||
case FT_LAVA:
|
||||
break; // TODO: (bool)is_death_sector
|
||||
sector->is_death_sector = true;
|
||||
break;
|
||||
|
||||
case FT_TRIGGER: {
|
||||
// TODO: (TRIGGER *)trigger
|
||||
assert(sector->trigger == NULL);
|
||||
|
||||
TRIGGER *const trigger =
|
||||
GameBuf_Alloc(sizeof(TRIGGER), GBUF_FLOOR_DATA);
|
||||
sector->trigger = trigger;
|
||||
|
||||
const int16_t trig_setup = *data++;
|
||||
const TRIGGER_TYPE trig_type = TRIG_TYPE(fd_entry);
|
||||
if (trig_type == TT_SWITCH || trig_type == TT_KEY
|
||||
|| trig_type == TT_PICKUP) {
|
||||
data++; // TODO: (int16_t)item_index
|
||||
trigger->type = TRIG_TYPE(fd_entry);
|
||||
trigger->timer = trig_setup & 0xFF;
|
||||
trigger->one_shot = trig_setup & IF_ONESHOT;
|
||||
trigger->mask = trig_setup & IF_CODE_BITS;
|
||||
trigger->item_index = NO_ITEM;
|
||||
trigger->command_count = 0;
|
||||
|
||||
if (trigger->type == TT_SWITCH || trigger->type == TT_KEY
|
||||
|| trigger->type == TT_PICKUP) {
|
||||
const int16_t item_data = *data++;
|
||||
trigger->item_index = item_data & VALUE_BITS;
|
||||
if (item_data & END_BIT) {
|
||||
// See City of Khamoon room 49 - two dangling key triggers
|
||||
// with no commands. Exit early to avoid populating garbage
|
||||
// command data.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const int16_t *command_data = data;
|
||||
while (true) {
|
||||
trigger->command_count++;
|
||||
int16_t command = *data++;
|
||||
if (TRIG_BITS(command) == TO_CAMERA) {
|
||||
command = *data++;
|
||||
|
@ -743,6 +705,22 @@ static void Room_PopulateSectorData(
|
|||
}
|
||||
}
|
||||
|
||||
trigger->commands = GameBuf_Alloc(
|
||||
sizeof(TRIGGER_CMD) * trigger->command_count, GBUF_FLOOR_DATA);
|
||||
for (int32_t i = 0; i < trigger->command_count; i++) {
|
||||
int16_t command = *command_data++;
|
||||
TRIGGER_CMD *const cmd = &trigger->commands[i];
|
||||
cmd->type = TRIG_BITS(command);
|
||||
cmd->parameter = command & VALUE_BITS;
|
||||
|
||||
if (cmd->type == TO_CAMERA) {
|
||||
command = *command_data++;
|
||||
cmd->camera.timer = command & 0xFF;
|
||||
cmd->camera.glide = (command & IF_CODE_BITS) >> 6;
|
||||
cmd->camera.one_shot = command & IF_ONESHOT;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -752,68 +730,65 @@ static void Room_PopulateSectorData(
|
|||
} while (!(fd_entry & END_BIT));
|
||||
}
|
||||
|
||||
void Room_TestTriggers(int16_t *data, bool heavy)
|
||||
void Room_TestTriggers(const ITEM_INFO *const item)
|
||||
{
|
||||
if (!data) {
|
||||
const bool is_heavy = item->object_number != O_LARA;
|
||||
int16_t room_num = item->room_number;
|
||||
const SECTOR_INFO *const sector =
|
||||
Room_GetSector(item->pos.x, MAX_HEIGHT, item->pos.z, &room_num);
|
||||
|
||||
if (!is_heavy && sector->is_death_sector && Lava_TestFloor(item)) {
|
||||
Lava_Burn(g_LaraItem);
|
||||
}
|
||||
|
||||
const TRIGGER *const trigger = sector->trigger;
|
||||
if (trigger == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((*data & DATA_TYPE) == FT_LAVA) {
|
||||
if (!heavy && Lava_TestFloor(g_LaraItem)) {
|
||||
Lava_Burn(g_LaraItem);
|
||||
}
|
||||
|
||||
if (*data & END_BIT) {
|
||||
return;
|
||||
}
|
||||
|
||||
data++;
|
||||
}
|
||||
|
||||
int16_t type = (*data++ >> 8) & 0x3F;
|
||||
int32_t switch_off = 0;
|
||||
int32_t flip = 0;
|
||||
int32_t new_effect = -1;
|
||||
int16_t flags = *data++;
|
||||
int16_t timer = flags & 0xFF;
|
||||
|
||||
if (g_Camera.type != CAM_HEAVY) {
|
||||
Camera_RefreshFromTrigger(type, data);
|
||||
Camera_RefreshFromTrigger(trigger);
|
||||
}
|
||||
|
||||
if (heavy) {
|
||||
if (type != TT_HEAVY) {
|
||||
bool switch_off = false;
|
||||
bool flip_map = false;
|
||||
int32_t new_effect = -1;
|
||||
ITEM_INFO *camera_item = NULL;
|
||||
|
||||
if (is_heavy) {
|
||||
if (trigger->type != TT_HEAVY) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
switch (type) {
|
||||
switch (trigger->type) {
|
||||
case TT_TRIGGER:
|
||||
break;
|
||||
|
||||
case TT_SWITCH: {
|
||||
int16_t value = *data++ & VALUE_BITS;
|
||||
if (!Switch_Trigger(value, timer)) {
|
||||
if (!Switch_Trigger(trigger->item_index, trigger->timer)) {
|
||||
return;
|
||||
}
|
||||
switch_off = g_Items[value].current_anim_state == LS_RUN;
|
||||
switch_off =
|
||||
g_Items[trigger->item_index].current_anim_state == LS_RUN;
|
||||
break;
|
||||
}
|
||||
|
||||
case TT_PAD:
|
||||
case TT_ANTIPAD:
|
||||
if (g_LaraItem->pos.y != g_LaraItem->floor) {
|
||||
if (item->pos.y != item->floor) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case TT_KEY: {
|
||||
int16_t value = *data++ & VALUE_BITS;
|
||||
if (!KeyHole_Trigger(value)) {
|
||||
if (!KeyHole_Trigger(trigger->item_index)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TT_PICKUP: {
|
||||
int16_t value = *data++ & VALUE_BITS;
|
||||
if (!Pickup_Trigger(value)) {
|
||||
if (!Pickup_Trigger(trigger->item_index)) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
@ -831,38 +806,35 @@ void Room_TestTriggers(int16_t *data, bool heavy)
|
|||
}
|
||||
}
|
||||
|
||||
ITEM_INFO *camera_item = NULL;
|
||||
int16_t trigger;
|
||||
do {
|
||||
trigger = *data++;
|
||||
int16_t value = trigger & VALUE_BITS;
|
||||
for (int32_t i = 0; i < trigger->command_count; i++) {
|
||||
const TRIGGER_CMD *const cmd = &trigger->commands[i];
|
||||
|
||||
switch (TRIG_BITS(trigger)) {
|
||||
switch (cmd->type) {
|
||||
case TO_OBJECT: {
|
||||
ITEM_INFO *item = &g_Items[value];
|
||||
|
||||
const int16_t item_num = cmd->parameter;
|
||||
ITEM_INFO *const item = &g_Items[item_num];
|
||||
if (item->flags & IF_ONESHOT) {
|
||||
break;
|
||||
}
|
||||
|
||||
item->timer = timer;
|
||||
if (timer != 1) {
|
||||
item->timer = trigger->timer;
|
||||
if (item->timer != 1) {
|
||||
item->timer *= LOGIC_FPS;
|
||||
}
|
||||
|
||||
if (type == TT_SWITCH) {
|
||||
item->flags ^= flags & IF_CODE_BITS;
|
||||
} else if (type == TT_ANTIPAD) {
|
||||
item->flags &= -1 - (flags & IF_CODE_BITS);
|
||||
} else if (flags & IF_CODE_BITS) {
|
||||
item->flags |= flags & IF_CODE_BITS;
|
||||
if (trigger->type == TT_SWITCH) {
|
||||
item->flags ^= trigger->mask;
|
||||
} else if (trigger->type == TT_ANTIPAD) {
|
||||
item->flags &= -1 - trigger->mask;
|
||||
} else if (trigger->mask) {
|
||||
item->flags |= trigger->mask;
|
||||
}
|
||||
|
||||
if ((item->flags & IF_CODE_BITS) != IF_CODE_BITS) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (flags & IF_ONESHOT) {
|
||||
if (trigger->one_shot) {
|
||||
item->flags |= IF_ONESHOT;
|
||||
}
|
||||
|
||||
|
@ -871,73 +843,71 @@ void Room_TestTriggers(int16_t *data, bool heavy)
|
|||
if (item->status == IS_NOT_ACTIVE) {
|
||||
item->touch_bits = 0;
|
||||
item->status = IS_ACTIVE;
|
||||
Item_AddActive(value);
|
||||
LOT_EnableBaddieAI(value, 1);
|
||||
Item_AddActive(item_num);
|
||||
LOT_EnableBaddieAI(item_num, 1);
|
||||
} else if (item->status == IS_INVISIBLE) {
|
||||
item->touch_bits = 0;
|
||||
if (LOT_EnableBaddieAI(value, 0)) {
|
||||
if (LOT_EnableBaddieAI(item_num, 0)) {
|
||||
item->status = IS_ACTIVE;
|
||||
} else {
|
||||
item->status = IS_INVISIBLE;
|
||||
}
|
||||
Item_AddActive(value);
|
||||
Item_AddActive(item_num);
|
||||
}
|
||||
} else {
|
||||
item->touch_bits = 0;
|
||||
item->status = IS_ACTIVE;
|
||||
Item_AddActive(value);
|
||||
Item_AddActive(item_num);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TO_CAMERA: {
|
||||
trigger = *data++;
|
||||
int16_t camera_flags = trigger;
|
||||
int16_t camera_timer = trigger & 0xFF;
|
||||
|
||||
if (g_Camera.fixed[value].flags & IF_ONESHOT) {
|
||||
const int16_t camera_num = cmd->parameter;
|
||||
if (g_Camera.fixed[camera_num].flags & IF_ONESHOT) {
|
||||
break;
|
||||
}
|
||||
|
||||
g_Camera.number = value;
|
||||
g_Camera.number = camera_num;
|
||||
|
||||
if (g_Camera.type == CAM_LOOK || g_Camera.type == CAM_COMBAT) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (type == TT_COMBAT) {
|
||||
if (trigger->type == TT_COMBAT) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (type == TT_SWITCH && timer && switch_off) {
|
||||
if (trigger->type == TT_SWITCH && trigger->timer && switch_off) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (g_Camera.number == g_Camera.last && type != TT_SWITCH) {
|
||||
if (g_Camera.number == g_Camera.last
|
||||
&& trigger->type != TT_SWITCH) {
|
||||
break;
|
||||
}
|
||||
|
||||
g_Camera.timer = camera_timer;
|
||||
g_Camera.timer = cmd->camera.timer;
|
||||
if (g_Camera.timer != 1) {
|
||||
g_Camera.timer *= LOGIC_FPS;
|
||||
}
|
||||
|
||||
if (camera_flags & IF_ONESHOT) {
|
||||
if (cmd->camera.one_shot) {
|
||||
g_Camera.fixed[g_Camera.number].flags |= IF_ONESHOT;
|
||||
}
|
||||
|
||||
g_Camera.speed = ((camera_flags & IF_CODE_BITS) >> 6) + 1;
|
||||
g_Camera.type = heavy ? CAM_HEAVY : CAM_FIXED;
|
||||
g_Camera.speed = cmd->camera.glide + 1;
|
||||
g_Camera.type = is_heavy ? CAM_HEAVY : CAM_FIXED;
|
||||
break;
|
||||
}
|
||||
|
||||
case TO_TARGET:
|
||||
camera_item = &g_Items[value];
|
||||
camera_item = &g_Items[cmd->parameter];
|
||||
break;
|
||||
|
||||
case TO_SINK: {
|
||||
OBJECT_VECTOR *obvector = &g_Camera.fixed[value];
|
||||
OBJECT_VECTOR *obvector = &g_Camera.fixed[cmd->parameter];
|
||||
|
||||
if (g_Lara.LOT.required_box != obvector->flags) {
|
||||
g_Lara.LOT.target.x = obvector->x;
|
||||
|
@ -950,46 +920,48 @@ void Room_TestTriggers(int16_t *data, bool heavy)
|
|||
break;
|
||||
}
|
||||
|
||||
case TO_FLIPMAP:
|
||||
if (g_FlipMapTable[value] & IF_ONESHOT) {
|
||||
case TO_FLIPMAP: {
|
||||
const int16_t flip_slot = cmd->parameter;
|
||||
if (g_FlipMapTable[flip_slot] & IF_ONESHOT) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (type == TT_SWITCH) {
|
||||
g_FlipMapTable[value] ^= flags & IF_CODE_BITS;
|
||||
} else if (flags & IF_CODE_BITS) {
|
||||
g_FlipMapTable[value] |= flags & IF_CODE_BITS;
|
||||
if (trigger->type == TT_SWITCH) {
|
||||
g_FlipMapTable[flip_slot] ^= trigger->mask;
|
||||
} else if (trigger->mask) {
|
||||
g_FlipMapTable[flip_slot] |= trigger->mask;
|
||||
}
|
||||
|
||||
if ((g_FlipMapTable[value] & IF_CODE_BITS) == IF_CODE_BITS) {
|
||||
if (flags & IF_ONESHOT) {
|
||||
g_FlipMapTable[value] |= IF_ONESHOT;
|
||||
if ((g_FlipMapTable[flip_slot] & IF_CODE_BITS) == IF_CODE_BITS) {
|
||||
if (trigger->one_shot) {
|
||||
g_FlipMapTable[flip_slot] |= IF_ONESHOT;
|
||||
}
|
||||
|
||||
if (!g_FlipStatus) {
|
||||
flip = 1;
|
||||
flip_map = true;
|
||||
}
|
||||
} else if (g_FlipStatus) {
|
||||
flip = 1;
|
||||
flip_map = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TO_FLIPON:
|
||||
if ((g_FlipMapTable[value] & IF_CODE_BITS) == IF_CODE_BITS
|
||||
if ((g_FlipMapTable[cmd->parameter] & IF_CODE_BITS) == IF_CODE_BITS
|
||||
&& !g_FlipStatus) {
|
||||
flip = 1;
|
||||
flip_map = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case TO_FLIPOFF:
|
||||
if ((g_FlipMapTable[value] & IF_CODE_BITS) == IF_CODE_BITS
|
||||
if ((g_FlipMapTable[cmd->parameter] & IF_CODE_BITS) == IF_CODE_BITS
|
||||
&& g_FlipStatus) {
|
||||
flip = 1;
|
||||
flip_map = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case TO_FLIPEFFECT:
|
||||
new_effect = value;
|
||||
new_effect = cmd->parameter;
|
||||
break;
|
||||
|
||||
case TO_FINISH:
|
||||
|
@ -997,26 +969,28 @@ void Room_TestTriggers(int16_t *data, bool heavy)
|
|||
break;
|
||||
|
||||
case TO_CD:
|
||||
Room_TriggerMusicTrack(value, flags, type);
|
||||
Room_TriggerMusicTrack(cmd->parameter, trigger);
|
||||
break;
|
||||
|
||||
case TO_SECRET:
|
||||
if ((g_GameInfo.current[g_CurrentLevel].stats.secret_flags
|
||||
& (1 << value))) {
|
||||
case TO_SECRET: {
|
||||
const int16_t secret_num = 1 << cmd->parameter;
|
||||
if (g_GameInfo.current[g_CurrentLevel].stats.secret_flags
|
||||
& secret_num) {
|
||||
break;
|
||||
}
|
||||
g_GameInfo.current[g_CurrentLevel].stats.secret_flags |= 1 << value;
|
||||
g_GameInfo.current[g_CurrentLevel].stats.secret_flags |= secret_num;
|
||||
Music_Play(MX_SECRET);
|
||||
break;
|
||||
}
|
||||
} while (!(trigger & END_BIT));
|
||||
}
|
||||
}
|
||||
|
||||
if (camera_item
|
||||
&& (g_Camera.type == CAM_FIXED || g_Camera.type == CAM_HEAVY)) {
|
||||
g_Camera.item = camera_item;
|
||||
}
|
||||
|
||||
if (flip) {
|
||||
if (flip_map) {
|
||||
Room_FlipMap();
|
||||
if (new_effect != -1) {
|
||||
g_FlipEffect = new_effect;
|
||||
|
@ -1032,50 +1006,24 @@ bool Room_IsOnWalkable(
|
|||
sector = Room_GetPitSector(sector, x, z);
|
||||
|
||||
int16_t height = sector->floor.height;
|
||||
if (sector->trigger == NULL) {
|
||||
return room_height == height;
|
||||
}
|
||||
|
||||
bool object_found = false;
|
||||
|
||||
int16_t *floor_data = &g_FloorData[sector->index];
|
||||
int16_t type;
|
||||
int16_t trigger;
|
||||
int16_t trig_flags;
|
||||
int16_t trig_type;
|
||||
|
||||
do {
|
||||
type = *floor_data++;
|
||||
|
||||
switch (type & DATA_TYPE) {
|
||||
case FT_TILT:
|
||||
case FT_ROOF:
|
||||
case FT_DOOR:
|
||||
floor_data++;
|
||||
break;
|
||||
|
||||
case FT_LAVA:
|
||||
break;
|
||||
|
||||
case FT_TRIGGER:
|
||||
trig_flags = *floor_data;
|
||||
floor_data++;
|
||||
trig_type = (type >> 8) & 0x3F;
|
||||
do {
|
||||
trigger = *floor_data++;
|
||||
|
||||
if (TRIG_BITS(trigger) == TO_OBJECT) {
|
||||
const int16_t item_num = trigger & VALUE_BITS;
|
||||
ITEM_INFO *item = &g_Items[item_num];
|
||||
OBJECT_INFO *object = &g_Objects[item->object_number];
|
||||
if (object->floor_height_func) {
|
||||
height =
|
||||
object->floor_height_func(item, x, y, z, height);
|
||||
object_found = true;
|
||||
}
|
||||
} else if (TRIG_BITS(trigger) == TO_CAMERA) {
|
||||
trigger = *floor_data++;
|
||||
}
|
||||
} while (!(trigger & END_BIT));
|
||||
break;
|
||||
for (int32_t i = 0; i < sector->trigger->command_count; i++) {
|
||||
const TRIGGER_CMD *const cmd = §or->trigger->commands[i];
|
||||
if (cmd->type != TO_OBJECT) {
|
||||
continue;
|
||||
}
|
||||
} while (!(type & END_BIT));
|
||||
|
||||
const ITEM_INFO *const item = &g_Items[cmd->parameter];
|
||||
const OBJECT_INFO *const object = &g_Objects[item->object_number];
|
||||
if (object->floor_height_func) {
|
||||
height = object->floor_height_func(item, x, y, z, height);
|
||||
object_found = true;
|
||||
}
|
||||
}
|
||||
|
||||
return object_found && room_height == height;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ void Room_GetNewRoom(int32_t x, int32_t y, int32_t z, int16_t room_num);
|
|||
void Room_GetNearByRooms(
|
||||
int32_t x, int32_t y, int32_t z, int32_t r, int32_t h, int16_t room_num);
|
||||
SECTOR_INFO *Room_GetSector(int32_t x, int32_t y, int32_t z, int16_t *room_num);
|
||||
SECTOR_INFO *Room_GetPitSector(const SECTOR_INFO *sector, int32_t x, int32_t z);
|
||||
int16_t Room_GetCeiling(
|
||||
const SECTOR_INFO *sector, int32_t x, int32_t y, int32_t z);
|
||||
int16_t Room_GetHeight(
|
||||
|
@ -29,7 +30,7 @@ int16_t Room_GetIndexFromPos(int32_t x, int32_t y, int32_t z);
|
|||
void Room_AlterFloorHeight(ITEM_INFO *item, int32_t height);
|
||||
|
||||
void Room_ParseFloorData(const int16_t *floor_data);
|
||||
void Room_TestTriggers(int16_t *data, bool heavy);
|
||||
void Room_TestTriggers(const ITEM_INFO *item);
|
||||
void Room_FlipMap(void);
|
||||
bool Room_IsOnWalkable(
|
||||
const SECTOR_INFO *sector, int32_t x, int32_t y, int32_t z,
|
||||
|
|
|
@ -83,80 +83,49 @@ static void Stats_CheckTriggers(
|
|||
const SECTOR_INFO *const sector =
|
||||
&m_CachedSectorArray[room_num][z_sector + x_sector * r->z_size];
|
||||
|
||||
if (!sector->index) {
|
||||
if (sector->trigger == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
int16_t *data = &g_FloorData[sector->index];
|
||||
int16_t type;
|
||||
int16_t trigger;
|
||||
int16_t trig_flags;
|
||||
int16_t trig_type;
|
||||
do {
|
||||
type = *data++;
|
||||
for (int32_t i = 0; i < sector->trigger->command_count; i++) {
|
||||
const TRIGGER_CMD *const cmd = §or->trigger->commands[i];
|
||||
|
||||
switch (type & DATA_TYPE) {
|
||||
case FT_TILT:
|
||||
case FT_ROOF:
|
||||
case FT_DOOR:
|
||||
data++;
|
||||
break;
|
||||
if (cmd->type == TO_SECRET) {
|
||||
const int16_t secret_num = 1 << cmd->parameter;
|
||||
if (!(m_SecretRoom & secret_num)) {
|
||||
m_SecretRoom |= secret_num;
|
||||
m_LevelSecrets++;
|
||||
}
|
||||
} else if (cmd->type == TO_OBJECT) {
|
||||
const int16_t item_num = cmd->parameter;
|
||||
if (m_KillableItems[item_num]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
case FT_LAVA:
|
||||
break;
|
||||
const ITEM_INFO *const item = &g_Items[item_num];
|
||||
|
||||
case FT_TRIGGER:
|
||||
trig_flags = *data;
|
||||
data++;
|
||||
trig_type = (type >> 8) & 0x3F;
|
||||
do {
|
||||
trigger = *data++;
|
||||
if (TRIG_BITS(trigger) == TO_SECRET) {
|
||||
int16_t number = trigger & VALUE_BITS;
|
||||
if (!(m_SecretRoom & (1 << number))) {
|
||||
m_SecretRoom |= (1 << number);
|
||||
m_LevelSecrets++;
|
||||
}
|
||||
// Add Pierre pickup and kills if oneshot
|
||||
if (item->object_number == O_PIERRE && sector->trigger->one_shot) {
|
||||
Stats_IncludeKillableItem(item_num);
|
||||
}
|
||||
|
||||
// Check for only valid pods
|
||||
if ((item->object_number == O_PODS
|
||||
|| item->object_number == O_BIG_POD)
|
||||
&& item->data != NULL) {
|
||||
const int16_t bug_item_num = *(int16_t *)item->data;
|
||||
const ITEM_INFO *const bug_item = &g_Items[bug_item_num];
|
||||
if (g_Objects[bug_item->object_number].loaded) {
|
||||
Stats_IncludeKillableItem(item_num);
|
||||
}
|
||||
if (TRIG_BITS(trigger) != TO_OBJECT) {
|
||||
if (TRIG_BITS(trigger) == TO_CAMERA) {
|
||||
trigger = *data++;
|
||||
}
|
||||
} else {
|
||||
int16_t idx = trigger & VALUE_BITS;
|
||||
}
|
||||
|
||||
if (m_KillableItems[idx]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ITEM_INFO *item = &g_Items[idx];
|
||||
|
||||
// Add Pierre pickup and kills if oneshot
|
||||
if (item->object_number == O_PIERRE
|
||||
&& trig_flags & IF_ONESHOT) {
|
||||
Stats_IncludeKillableItem(idx);
|
||||
}
|
||||
|
||||
// Check for only valid pods
|
||||
if ((item->object_number == O_PODS
|
||||
|| item->object_number == O_BIG_POD)
|
||||
&& item->data != NULL) {
|
||||
int16_t bug_item_num = *(int16_t *)item->data;
|
||||
const ITEM_INFO *bug_item = &g_Items[bug_item_num];
|
||||
if (g_Objects[bug_item->object_number].loaded) {
|
||||
Stats_IncludeKillableItem(idx);
|
||||
}
|
||||
}
|
||||
|
||||
// Add killable if object triggered
|
||||
if (Stats_IsObjectKillable(item->object_number)) {
|
||||
Stats_IncludeKillableItem(idx);
|
||||
}
|
||||
}
|
||||
} while (!(trigger & END_BIT));
|
||||
break;
|
||||
// Add killable if object triggered
|
||||
if (Stats_IsObjectKillable(item->object_number)) {
|
||||
Stats_IncludeKillableItem(item_num);
|
||||
}
|
||||
}
|
||||
} while (!(type & END_BIT));
|
||||
}
|
||||
}
|
||||
|
||||
static bool Stats_IsObjectKillable(int32_t obj_num)
|
||||
|
|
|
@ -123,6 +123,7 @@
|
|||
#define DONT_TARGET (-16384)
|
||||
#define UNIT_SHADOW 256
|
||||
#define NO_HEIGHT (-32512)
|
||||
#define MAX_HEIGHT 32000
|
||||
#define NO_BAD_POS (-NO_HEIGHT)
|
||||
#define NO_BAD_NEG NO_HEIGHT
|
||||
#define BAD_JUMP_CEILING ((STEP_L * 3) / 4) // = 192
|
||||
|
|
|
@ -1160,9 +1160,31 @@ typedef struct DOOR_INFOS {
|
|||
DOOR_INFO door[];
|
||||
} DOOR_INFOS;
|
||||
|
||||
typedef struct TRIGGER_CMD {
|
||||
TRIGGER_OBJECT type;
|
||||
int16_t parameter;
|
||||
struct {
|
||||
int8_t timer;
|
||||
int8_t glide;
|
||||
bool one_shot;
|
||||
} camera;
|
||||
} TRIGGER_CMD;
|
||||
|
||||
typedef struct TRIGGER {
|
||||
TRIGGER_TYPE type;
|
||||
int8_t timer;
|
||||
int16_t mask;
|
||||
bool one_shot;
|
||||
int16_t item_index;
|
||||
int32_t command_count;
|
||||
TRIGGER_CMD *commands;
|
||||
} TRIGGER;
|
||||
|
||||
typedef struct SECTOR_INFO {
|
||||
uint16_t index;
|
||||
int16_t box;
|
||||
bool is_death_sector;
|
||||
TRIGGER *trigger;
|
||||
struct {
|
||||
uint8_t pit;
|
||||
uint8_t sky;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue