refactor traps.c

This commit is contained in:
rr- 2021-03-13 23:58:40 +01:00
parent 65f0e220cd
commit a10ed3e961
43 changed files with 1784 additions and 1563 deletions

View file

@ -10,10 +10,10 @@
#include "game/items.h"
#include "game/lara.h"
#include "game/lot.h"
#include "game/moveblock.h"
#include "game/pickup.h"
#include "game/savegame.h"
#include "game/traps.h"
#include "game/traps/lava.h"
#include "game/traps/movable_block.h"
#include "game/vars.h"
#include "specific/input.h"
#include "specific/shed.h"

View file

@ -1,22 +0,0 @@
#ifndef T1M_GAME_LIGHTNING_H
#define T1M_GAME_LIGHTNING_H
#include "game/types.h"
#include <stdint.h>
void DrawLightning(ITEM_INFO *item);
void InitialiseLightning(int16_t item_num);
void LightningControl(int16_t item_num);
void LightningCollision(
int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll);
void InitialiseThorsHandle(int16_t item_num);
void ThorsHandleControl(int16_t item_num);
void ThorsHandleCollision(
int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll);
void ThorsHeadCollision(
int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll);
void T1MInjectGameLightning();
#endif

View file

@ -0,0 +1,70 @@
#include "game/objects/trapdoor.h"
#include "game/control.h"
#include "game/vars.h"
void SetupTrapDoor(OBJECT_INFO *obj)
{
obj->control = TrapDoorControl;
obj->floor = TrapDoorFloor;
obj->ceiling = TrapDoorCeiling;
obj->save_anim = 1;
obj->save_flags = 1;
}
void TrapDoorControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
if (TriggerActive(item)) {
if (item->current_anim_state == DOOR_CLOSED) {
item->goal_anim_state = DOOR_OPEN;
}
} else if (item->current_anim_state == DOOR_OPEN) {
item->goal_anim_state = DOOR_CLOSED;
}
AnimateItem(item);
}
void TrapDoorFloor(
ITEM_INFO *item, int32_t x, int32_t y, int32_t z, int16_t *height)
{
if (!OnTrapDoor(item, x, z)) {
return;
}
if (y <= item->pos.y && item->current_anim_state == DOOR_CLOSED
&& item->pos.y < *height) {
*height = item->pos.y;
}
}
void TrapDoorCeiling(
ITEM_INFO *item, int32_t x, int32_t y, int32_t z, int16_t *height)
{
if (!OnTrapDoor(item, x, z)) {
return;
}
if (y > item->pos.y && item->current_anim_state == DOOR_CLOSED
&& item->pos.y > *height) {
*height = (int16_t)item->pos.y + STEP_L;
}
}
int32_t OnTrapDoor(ITEM_INFO *item, int32_t x, int32_t z)
{
x >>= WALL_SHIFT;
z >>= WALL_SHIFT;
int32_t tx = item->pos.x >> WALL_SHIFT;
int32_t tz = item->pos.z >> WALL_SHIFT;
if (item->pos.y_rot == 0 && x == tx && (z == tz || z == tz + 1)) {
return 1;
} else if (
item->pos.y_rot == -PHD_180 && x == tx && (z == tz || z == tz - 1)) {
return 1;
} else if (
item->pos.y_rot == PHD_90 && z == tz && (x == tx || x == tx + 1)) {
return 1;
} else if (
item->pos.y_rot == -PHD_90 && z == tz && (x == tx || x == tx - 1)) {
return 1;
}
return 0;
}

View file

@ -0,0 +1,15 @@
#ifndef T1M_GAME_OBJECTS_TRAPDOOR_H
#define T1M_GAME_OBJECTS_TRAPDOOR_H
#include "game/types.h"
#include <stdint.h>
void SetupTrapDoor(OBJECT_INFO *obj);
void TrapDoorControl(int16_t item_num);
void TrapDoorFloor(
ITEM_INFO *item, int32_t x, int32_t y, int32_t z, int16_t *height);
void TrapDoorCeiling(
ITEM_INFO *item, int32_t x, int32_t y, int32_t z, int16_t *height);
int32_t OnTrapDoor(ITEM_INFO *item, int32_t x, int32_t z);
#endif

View file

@ -67,21 +67,6 @@ static int16_t PickUpScion4Bounds[12] = {
0,
};
static int16_t MidasBounds[12] = {
-700,
+700,
+384 - 100,
+384 + 100 + 512,
-700,
+700,
-10 * PHD_DEGREE,
+10 * PHD_DEGREE,
-30 * PHD_DEGREE,
+30 * PHD_DEGREE,
-10 * PHD_DEGREE,
+10 * PHD_DEGREE,
};
static int16_t Switch1Bounds[12] = {
-200,
+200,
@ -284,71 +269,6 @@ void PickUpScion4Collision(
}
}
void MidasCollision(int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll)
{
ITEM_INFO *item = &Items[item_num];
if (!lara_item->gravity_status && lara_item->current_anim_state == AS_STOP
&& lara_item->pos.x > item->pos.x - 512
&& lara_item->pos.x < item->pos.x + 512
&& lara_item->pos.z > item->pos.z - 512
&& lara_item->pos.z < item->pos.z + 512) {
lara_item->current_anim_state = AS_DIEMIDAS;
lara_item->goal_anim_state = AS_DIEMIDAS;
lara_item->anim_number = Objects[O_LARA_EXTRA].anim_index + 1;
lara_item->frame_number = Anims[lara_item->anim_number].frame_base;
lara_item->hit_points = -1;
lara_item->gravity_status = 0;
Lara.air = -1;
Lara.gun_status = LGS_HANDSBUSY;
Lara.gun_type = LGT_UNARMED;
Camera.type = CAM_CINEMATIC;
CineFrame = 0;
CinematicPosition = lara_item->pos;
return;
}
if ((InventoryChosen == -1 && !CHK_ANY(Input, IN_ACTION))
|| Lara.gun_status != LGS_ARMLESS || lara_item->gravity_status
|| lara_item->current_anim_state != AS_STOP) {
return;
}
uint16_t quadrant = (uint16_t)(lara_item->pos.y_rot + PHD_45) / PHD_90;
switch (quadrant) {
case DIR_NORTH:
item->pos.y_rot = 0;
break;
case DIR_EAST:
item->pos.y_rot = PHD_90;
break;
case DIR_SOUTH:
item->pos.y_rot = -PHD_180;
break;
case DIR_WEST:
item->pos.y_rot = -PHD_90;
break;
}
if (!TestLaraPosition(MidasBounds, item, lara_item)) {
return;
}
if (InventoryChosen == -1) {
Display_Inventory(INV_KEYS_MODE);
}
if (InventoryChosen == O_LEADBAR_OPTION) {
Inv_RemoveItem(O_LEADBAR_OPTION);
Inv_AddItem(O_PUZZLE_ITEM1);
lara_item->current_anim_state = AS_USEMIDAS;
lara_item->goal_anim_state = AS_USEMIDAS;
lara_item->anim_number = Objects[O_LARA_EXTRA].anim_index;
lara_item->frame_number = Anims[item->anim_number].frame_base;
Lara.gun_status = LGS_HANDSBUSY;
}
}
void SwitchCollision(int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll)
{
ITEM_INFO *item = &Items[item_num];
@ -743,7 +663,6 @@ void T1MInjectGamePickup()
INJECT(0x00433080, PickUpCollision);
INJECT(0x00433240, PickUpScionCollision);
INJECT(0x004333B0, PickUpScion4Collision);
INJECT(0x004334C0, MidasCollision);
INJECT(0x004336F0, SwitchCollision);
INJECT(0x00433810, SwitchCollision2);
INJECT(0x00433900, KeyHoleCollision);

View file

@ -9,7 +9,6 @@ void PickUpScionCollision(
int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll);
void PickUpScion4Collision(
int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll);
void MidasCollision(int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll);
void SwitchCollision(int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll);
void SwitchCollision2(int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll);
void KeyHoleCollision(int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll);

View file

@ -1,14 +1,14 @@
#include "game/ai/pod.h"
#include "game/traps/movable_block.h"
#include "game/traps/rolling_block.h"
#include "game/control.h"
#include "game/gameflow.h"
#include "game/inv.h"
#include "game/items.h"
#include "game/lara.h"
#include "game/lot.h"
#include "game/moveblock.h"
#include "game/pickup.h"
#include "game/savegame.h"
#include "game/traps.h"
#include "game/vars.h"
#include "game/warrior.h"
#include "specific/shed.h"

View file

@ -35,16 +35,30 @@
#include "game/inv.h"
#include "game/items.h"
#include "game/lara.h"
#include "game/lightning.h"
#include "game/lot.h"
#include "game/moveblock.h"
#include "game/objects.h"
#include "game/objects/gunshot.h"
#include "game/objects/trapdoor.h"
#include "game/pickup.h"
#include "game/savegame.h"
#include "game/setup.h"
#include "game/text.h"
#include "game/traps.h"
#include "game/traps/damocles_sword.h"
#include "game/traps/dart.h"
#include "game/traps/dart_emitter.h"
#include "game/traps/falling_block.h"
#include "game/traps/falling_ceiling.h"
#include "game/traps/flame.h"
#include "game/traps/lava.h"
#include "game/traps/lightning_emitter.h"
#include "game/traps/midas_touch.h"
#include "game/traps/movable_block.h"
#include "game/traps/pendulum.h"
#include "game/traps/rolling_ball.h"
#include "game/traps/rolling_block.h"
#include "game/traps/spikes.h"
#include "game/traps/teeth_trap.h"
#include "game/traps/thors_hammer.h"
#include "game/types.h"
#include "game/vars.h"
#include "game/warrior.h"
@ -185,138 +199,31 @@ void BaddyObjects()
void TrapObjects()
{
Objects[O_FALLING_BLOCK].control = FallingBlockControl;
Objects[O_FALLING_BLOCK].floor = FallingBlockFloor;
Objects[O_FALLING_BLOCK].ceiling = FallingBlockCeiling;
Objects[O_FALLING_BLOCK].save_position = 1;
Objects[O_FALLING_BLOCK].save_anim = 1;
Objects[O_FALLING_BLOCK].save_flags = 1;
Objects[O_PENDULUM].control = PendulumControl;
Objects[O_PENDULUM].collision = TrapCollision;
Objects[O_PENDULUM].shadow_size = UNIT_SHADOW / 2;
Objects[O_PENDULUM].save_flags = 1;
Objects[O_PENDULUM].save_anim = 1;
Objects[O_TEETH_TRAP].control = TeethTrapControl;
Objects[O_TEETH_TRAP].collision = TrapCollision;
Objects[O_TEETH_TRAP].save_flags = 1;
Objects[O_TEETH_TRAP].save_anim = 1;
Objects[O_ROLLING_BALL].initialise = InitialiseRollingBall;
Objects[O_ROLLING_BALL].control = RollingBallControl;
Objects[O_ROLLING_BALL].collision = RollingBallCollision;
Objects[O_ROLLING_BALL].save_position = 1;
Objects[O_ROLLING_BALL].save_anim = 1;
Objects[O_ROLLING_BALL].save_flags = 1;
Objects[O_SPIKES].collision = SpikeCollision;
Objects[O_FALLING_CEILING1].control = FallingCeilingControl;
Objects[O_FALLING_CEILING1].collision = TrapCollision;
Objects[O_FALLING_CEILING1].save_position = 1;
Objects[O_FALLING_CEILING1].save_anim = 1;
Objects[O_FALLING_CEILING1].save_flags = 1;
Objects[O_FALLING_CEILING2].control = FallingCeilingControl;
Objects[O_FALLING_CEILING2].collision = TrapCollision;
Objects[O_FALLING_CEILING2].save_position = 1;
Objects[O_FALLING_CEILING2].save_anim = 1;
Objects[O_FALLING_CEILING2].save_flags = 1;
Objects[O_DAMOCLES_SWORD].initialise = InitialiseDamoclesSword;
Objects[O_DAMOCLES_SWORD].control = DamoclesSwordControl;
Objects[O_DAMOCLES_SWORD].collision = DamoclesSwordCollision;
Objects[O_DAMOCLES_SWORD].shadow_size = UNIT_SHADOW;
Objects[O_DAMOCLES_SWORD].save_position = 1;
Objects[O_DAMOCLES_SWORD].save_anim = 1;
Objects[O_DAMOCLES_SWORD].save_flags = 1;
Objects[O_MOVABLE_BLOCK].initialise = InitialiseMovableBlock;
Objects[O_MOVABLE_BLOCK].control = MovableBlockControl;
Objects[O_MOVABLE_BLOCK].draw_routine = DrawMovableBlock;
Objects[O_MOVABLE_BLOCK].collision = MovableBlockCollision;
Objects[O_MOVABLE_BLOCK].save_position = 1;
Objects[O_MOVABLE_BLOCK].save_anim = 1;
Objects[O_MOVABLE_BLOCK].save_flags = 1;
Objects[O_MOVABLE_BLOCK2].initialise = InitialiseMovableBlock;
Objects[O_MOVABLE_BLOCK2].control = MovableBlockControl;
Objects[O_MOVABLE_BLOCK2].draw_routine = DrawMovableBlock;
Objects[O_MOVABLE_BLOCK2].collision = MovableBlockCollision;
Objects[O_MOVABLE_BLOCK2].save_position = 1;
Objects[O_MOVABLE_BLOCK2].save_anim = 1;
Objects[O_MOVABLE_BLOCK2].save_flags = 1;
Objects[O_MOVABLE_BLOCK3].initialise = InitialiseMovableBlock;
Objects[O_MOVABLE_BLOCK3].draw_routine = DrawMovableBlock;
Objects[O_MOVABLE_BLOCK3].control = MovableBlockControl;
Objects[O_MOVABLE_BLOCK3].collision = MovableBlockCollision;
Objects[O_MOVABLE_BLOCK3].save_position = 1;
Objects[O_MOVABLE_BLOCK3].save_anim = 1;
Objects[O_MOVABLE_BLOCK3].save_flags = 1;
Objects[O_MOVABLE_BLOCK4].initialise = InitialiseMovableBlock;
Objects[O_MOVABLE_BLOCK4].control = MovableBlockControl;
Objects[O_MOVABLE_BLOCK4].draw_routine = DrawMovableBlock;
Objects[O_MOVABLE_BLOCK4].collision = MovableBlockCollision;
Objects[O_MOVABLE_BLOCK4].save_position = 1;
Objects[O_MOVABLE_BLOCK4].save_anim = 1;
Objects[O_MOVABLE_BLOCK4].save_flags = 1;
Objects[O_ROLLING_BLOCK].initialise = InitialiseRollingBlock;
Objects[O_ROLLING_BLOCK].control = RollingBlockControl;
Objects[O_ROLLING_BLOCK].save_position = 1;
Objects[O_ROLLING_BLOCK].save_anim = 1;
Objects[O_ROLLING_BLOCK].save_flags = 1;
Objects[O_LIGHTNING_EMITTER].initialise = InitialiseLightning;
Objects[O_LIGHTNING_EMITTER].control = LightningControl;
Objects[O_LIGHTNING_EMITTER].draw_routine = DrawLightning;
Objects[O_LIGHTNING_EMITTER].collision = LightningCollision;
Objects[O_LIGHTNING_EMITTER].save_flags = 1;
Objects[O_THORS_HANDLE].initialise = InitialiseThorsHandle;
Objects[O_THORS_HANDLE].control = ThorsHandleControl;
Objects[O_THORS_HANDLE].draw_routine = DrawUnclippedItem;
Objects[O_THORS_HANDLE].collision = ThorsHandleCollision;
Objects[O_THORS_HANDLE].save_flags = 1;
Objects[O_THORS_HANDLE].save_anim = 1;
Objects[O_THORS_HEAD].collision = ThorsHeadCollision;
Objects[O_THORS_HEAD].draw_routine = DrawUnclippedItem;
Objects[O_THORS_HEAD].save_flags = 1;
Objects[O_THORS_HEAD].save_anim = 1;
Objects[O_MIDAS_TOUCH].collision = MidasCollision;
Objects[O_MIDAS_TOUCH].draw_routine = DrawDummyItem;
Objects[O_DART_EMITTER].control = DartEmitterControl;
Objects[O_DARTS].collision = ObjectCollision;
Objects[O_DARTS].control = DartsControl;
Objects[O_DARTS].shadow_size = UNIT_SHADOW / 2;
Objects[O_DARTS].save_flags = 1;
Objects[O_DART_EFFECT].control = DartEffectControl;
Objects[O_DART_EFFECT].draw_routine = DrawSpriteItem;
Objects[O_FLAME_EMITTER].control = FlameEmitterControl;
Objects[O_FLAME_EMITTER].draw_routine = DrawDummyItem;
Objects[O_FLAME].control = FlameControl;
Objects[O_LAVA_EMITTER].control = LavaEmitterControl;
Objects[O_LAVA_EMITTER].draw_routine = DrawDummyItem;
Objects[O_LAVA_EMITTER].collision = ObjectCollision;
Objects[O_LAVA].control = LavaControl;
Objects[O_LAVA_WEDGE].control = LavaWedgeControl;
Objects[O_LAVA_WEDGE].collision = CreatureCollision;
Objects[O_LAVA_WEDGE].save_position = 1;
Objects[O_LAVA_WEDGE].save_anim = 1;
Objects[O_LAVA_WEDGE].save_flags = 1;
SetupFallingBlock(&Objects[O_FALLING_BLOCK]);
SetupPendulum(&Objects[O_PENDULUM]);
SetupTeethTrap(&Objects[O_TEETH_TRAP]);
SetupRollingBall(&Objects[O_ROLLING_BALL]);
SetupSpikes(&Objects[O_SPIKES]);
SetupFallingCeilling(&Objects[O_FALLING_CEILING1]);
SetupFallingCeilling(&Objects[O_FALLING_CEILING2]);
SetupDamoclesSword(&Objects[O_DAMOCLES_SWORD]);
SetupMovableBlock(&Objects[O_MOVABLE_BLOCK]);
SetupMovableBlock(&Objects[O_MOVABLE_BLOCK2]);
SetupMovableBlock(&Objects[O_MOVABLE_BLOCK3]);
SetupMovableBlock(&Objects[O_MOVABLE_BLOCK4]);
SetupRollingBlock(&Objects[O_ROLLING_BLOCK]);
SetupLightningEmitter(&Objects[O_LIGHTNING_EMITTER]);
SetupThorsHandle(&Objects[O_THORS_HANDLE]);
SetupThorsHead(&Objects[O_THORS_HEAD]);
SetupMidasTouch(&Objects[O_MIDAS_TOUCH]);
SetupDartEmitter(&Objects[O_DART_EMITTER]);
SetupDart(&Objects[O_DARTS]);
SetupDartEffect(&Objects[O_DART_EFFECT]);
SetupFlameEmitter(&Objects[O_FLAME_EMITTER]);
SetupFlame(&Objects[O_FLAME]);
SetupLavaEmitter(&Objects[O_LAVA_EMITTER]);
SetupLava(&Objects[O_LAVA]);
SetupLavaWedge(&Objects[O_LAVA_WEDGE]);
}
void ObjectObjects()
@ -405,17 +312,8 @@ void ObjectObjects()
Objects[O_DOOR_TYPE8].save_anim = 1;
Objects[O_DOOR_TYPE8].save_flags = 1;
Objects[O_TRAPDOOR].control = TrapDoorControl;
Objects[O_TRAPDOOR].floor = TrapDoorFloor;
Objects[O_TRAPDOOR].ceiling = TrapDoorCeiling;
Objects[O_TRAPDOOR].save_anim = 1;
Objects[O_TRAPDOOR].save_flags = 1;
Objects[O_TRAPDOOR2].control = TrapDoorControl;
Objects[O_TRAPDOOR2].floor = TrapDoorFloor;
Objects[O_TRAPDOOR2].ceiling = TrapDoorCeiling;
Objects[O_TRAPDOOR2].save_anim = 1;
Objects[O_TRAPDOOR2].save_flags = 1;
SetupTrapDoor(&Objects[O_TRAPDOOR]);
SetupTrapDoor(&Objects[O_TRAPDOOR2]);
Objects[O_COG_1].control = CogControl;
Objects[O_COG_1].save_flags = 1;

View file

@ -1,865 +0,0 @@
#include "3dsystem/phd_math.h"
#include "game/collide.h"
#include "game/control.h"
#include "game/effects.h"
#include "game/game.h"
#include "game/items.h"
#include "game/sphere.h"
#include "game/traps.h"
#include "game/vars.h"
#include "specific/init.h"
#include "util.h"
#define ROLLINGBALL_DAMAGE_AIR 100
#define SPIKE_DAMAGE 15
#define PENDULUM_DAMAGE 100
#define TEETH_TRAP_DAMAGE 400
#define FALLING_CEILING_DAMAGE 300
#define DAMOCLES_SWORD_ACTIVATE_DIST ((WALL_L * 3) / 2)
#define DAMOCLES_SWORD_DAMAGE 100
#define FLAME_ONFIRE_DAMAGE 5
#define FLAME_TOONEAR_DAMAGE 3
#define LAVA_GLOB_DAMAGE 10
#define LAVA_WEDGE_SPEED 25
typedef enum {
TT_NICE = 0,
TT_NASTY = 1,
} TEETH_TRAP_STATE;
typedef enum {
DE_IDLE = 0,
DE_FIRE = 1,
} DART_EMITTER_STATE;
static BITE_INFO Teeth1A = { -23, 0, -1718, 0 };
static BITE_INFO Teeth1B = { 71, 0, -1718, 1 };
static BITE_INFO Teeth2A = { -23, 10, -1718, 0 };
static BITE_INFO Teeth2B = { 71, 10, -1718, 1 };
static BITE_INFO Teeth3A = { -23, -10, -1718, 0 };
static BITE_INFO Teeth3B = { 71, -10, -1718, 1 };
void InitialiseRollingBall(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
GAME_VECTOR *old = game_malloc(sizeof(GAME_VECTOR), GBUF_ROLLINGBALL_STUFF);
item->data = old;
old->x = item->pos.x;
old->y = item->pos.y;
old->z = item->pos.z;
old->room_number = item->room_number;
}
void RollingBallControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
if (item->status == IS_ACTIVE) {
if (item->pos.y < item->floor) {
if (!item->gravity_status) {
item->gravity_status = 1;
item->fall_speed = -10;
}
} else if (item->current_anim_state == TRAP_SET) {
item->goal_anim_state = TRAP_ACTIVATE;
}
int32_t oldx = item->pos.x;
int32_t oldz = item->pos.z;
AnimateItem(item);
int16_t room_num = item->room_number;
FLOOR_INFO *floor =
GetFloor(item->pos.x, item->pos.y, item->pos.z, &room_num);
if (item->room_number != room_num) {
ItemNewRoom(item_num, room_num);
}
item->floor = GetHeight(floor, item->pos.x, item->pos.y, item->pos.z);
TestTriggers(TriggerIndex, 1);
if (item->pos.y >= item->floor - STEP_L) {
item->gravity_status = 0;
item->fall_speed = 0;
item->pos.y = item->floor;
}
int32_t x = item->pos.x
+ (((WALL_L / 2) * phd_sin(item->pos.y_rot)) >> W2V_SHIFT);
int32_t z = item->pos.z
+ (((WALL_L / 2) * phd_cos(item->pos.y_rot)) >> W2V_SHIFT);
floor = GetFloor(x, item->pos.y, z, &room_num);
if (GetHeight(floor, x, item->pos.y, z) < item->pos.y) {
item->status = IS_DEACTIVATED;
item->pos.x = oldx;
item->pos.y = item->floor;
item->pos.z = oldz;
item->speed = 0;
item->fall_speed = 0;
item->touch_bits = 0;
}
} else if (item->status == IS_DEACTIVATED && !TriggerActive(item)) {
item->status = IS_NOT_ACTIVE;
GAME_VECTOR *old = item->data;
item->pos.x = old->x;
item->pos.y = old->y;
item->pos.z = old->z;
if (item->room_number != old->room_number) {
RemoveDrawnItem(item_num);
ROOM_INFO *r = &RoomInfo[old->room_number];
item->next_item = r->item_number;
r->item_number = item_num;
item->room_number = old->room_number;
}
item->current_anim_state = TRAP_SET;
item->goal_anim_state = TRAP_SET;
item->anim_number = Objects[item->object_number].anim_index;
item->frame_number = Anims[item->anim_number].frame_base;
item->current_anim_state = Anims[item->anim_number].current_anim_state;
item->goal_anim_state = item->current_anim_state;
item->required_anim_state = TRAP_SET;
RemoveActiveItem(item_num);
}
}
void RollingBallCollision(
int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll)
{
ITEM_INFO *item = &Items[item_num];
if (item->status != IS_ACTIVE) {
if (item->status != IS_INVISIBLE) {
ObjectCollision(item_num, lara_item, coll);
}
return;
}
if (!TestBoundsCollide(item, lara_item, coll->radius)) {
return;
}
if (!TestCollision(item, lara_item)) {
return;
}
int32_t x, y, z, d;
if (lara_item->gravity_status) {
if (coll->enable_baddie_push) {
ItemPushLara(item, lara_item, coll, coll->enable_spaz, 1);
}
lara_item->hit_points -= ROLLINGBALL_DAMAGE_AIR;
x = lara_item->pos.x - item->pos.x;
z = lara_item->pos.z - item->pos.z;
y = (lara_item->pos.y - 350) - (item->pos.y - WALL_L / 2);
d = phd_sqrt(SQUARE(x) + SQUARE(y) + SQUARE(z));
if (d < WALL_L / 2) {
d = WALL_L / 2;
}
x = item->pos.x + (x << WALL_SHIFT) / 2 / d;
z = item->pos.z + (z << WALL_SHIFT) / 2 / d;
y = item->pos.y - WALL_L / 2 + (y << WALL_SHIFT) / 2 / d;
DoBloodSplat(x, y, z, item->speed, item->pos.y_rot, item->room_number);
} else {
lara_item->hit_status = 1;
if (lara_item->hit_points > 0) {
lara_item->hit_points = -1;
if (lara_item->room_number != item->room_number) {
ItemNewRoom(Lara.item_number, item->room_number);
}
lara_item->pos.x_rot = 0;
lara_item->pos.z_rot = 0;
lara_item->pos.y_rot = item->pos.y_rot;
lara_item->current_anim_state = AS_SPECIAL;
lara_item->goal_anim_state = AS_SPECIAL;
lara_item->anim_number = AA_RBALL_DEATH;
lara_item->frame_number = AF_RBALL_DEATH;
Camera.flags = FOLLOW_CENTRE;
Camera.target_angle = 170 * PHD_DEGREE;
Camera.target_elevation = -25 * PHD_DEGREE;
for (int i = 0; i < 15; i++) {
x = lara_item->pos.x + (GetRandomControl() - 0x4000) / 256;
z = lara_item->pos.z + (GetRandomControl() - 0x4000) / 256;
y = lara_item->pos.y - GetRandomControl() / 64;
d = item->pos.y_rot + (GetRandomControl() - 0x4000) / 8;
DoBloodSplat(x, y, z, item->speed * 2, d, item->room_number);
}
}
}
}
void SpikeCollision(int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll)
{
ITEM_INFO *item = &Items[item_num];
if (lara_item->hit_points < 0) {
return;
}
if (!TestBoundsCollide(item, lara_item, coll->radius)) {
return;
}
if (!TestCollision(item, lara_item)) {
return;
}
int32_t num = GetRandomControl() / 24576;
if (lara_item->gravity_status) {
if (lara_item->fall_speed > 0) {
lara_item->hit_points = -1;
num = 20;
}
} else if (lara_item->speed < 30) {
return;
}
lara_item->hit_points -= SPIKE_DAMAGE;
while (num > 0) {
int32_t x = lara_item->pos.x + (GetRandomControl() - 0x4000) / 256;
int32_t z = lara_item->pos.z + (GetRandomControl() - 0x4000) / 256;
int32_t y = lara_item->pos.y - GetRandomControl() / 64;
DoBloodSplat(x, y, z, 20, GetRandomControl(), item->room_number);
num--;
}
if (lara_item->hit_points <= 0) {
lara_item->current_anim_state = AS_DEATH;
lara_item->goal_anim_state = AS_DEATH;
lara_item->anim_number = AA_SPIKE_DEATH;
lara_item->frame_number = AF_SPIKE_DEATH;
lara_item->pos.y = item->pos.y;
lara_item->gravity_status = 0;
}
}
void TrapDoorControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
if (TriggerActive(item)) {
if (item->current_anim_state == DOOR_CLOSED) {
item->goal_anim_state = DOOR_OPEN;
}
} else if (item->current_anim_state == DOOR_OPEN) {
item->goal_anim_state = DOOR_CLOSED;
}
AnimateItem(item);
}
void TrapDoorFloor(
ITEM_INFO *item, int32_t x, int32_t y, int32_t z, int16_t *height)
{
if (!OnTrapDoor(item, x, z)) {
return;
}
if (y <= item->pos.y && item->current_anim_state == DOOR_CLOSED
&& item->pos.y < *height) {
*height = item->pos.y;
}
}
void TrapDoorCeiling(
ITEM_INFO *item, int32_t x, int32_t y, int32_t z, int16_t *height)
{
if (!OnTrapDoor(item, x, z)) {
return;
}
if (y > item->pos.y && item->current_anim_state == DOOR_CLOSED
&& item->pos.y > *height) {
*height = (int16_t)item->pos.y + STEP_L;
}
}
int32_t OnTrapDoor(ITEM_INFO *item, int32_t x, int32_t z)
{
x >>= WALL_SHIFT;
z >>= WALL_SHIFT;
int32_t tx = item->pos.x >> WALL_SHIFT;
int32_t tz = item->pos.z >> WALL_SHIFT;
if (item->pos.y_rot == 0 && x == tx && (z == tz || z == tz + 1)) {
return 1;
} else if (
item->pos.y_rot == -PHD_180 && x == tx && (z == tz || z == tz - 1)) {
return 1;
} else if (
item->pos.y_rot == PHD_90 && z == tz && (x == tx || x == tx + 1)) {
return 1;
} else if (
item->pos.y_rot == -PHD_90 && z == tz && (x == tx || x == tx - 1)) {
return 1;
}
return 0;
}
// original name: Pendulum
void PendulumControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
if (TriggerActive(item)) {
if (item->current_anim_state == TRAP_SET) {
item->goal_anim_state = TRAP_WORKING;
}
} else {
if (item->current_anim_state == TRAP_WORKING) {
item->goal_anim_state = TRAP_SET;
}
}
if (item->current_anim_state == TRAP_WORKING && item->touch_bits) {
LaraItem->hit_points -= PENDULUM_DAMAGE;
LaraItem->hit_status = 1;
int32_t x = LaraItem->pos.x + (GetRandomControl() - 0x4000) / 256;
int32_t z = LaraItem->pos.z + (GetRandomControl() - 0x4000) / 256;
int32_t y = LaraItem->pos.y - GetRandomControl() / 44;
int32_t d = LaraItem->pos.y_rot + (GetRandomControl() - 0x4000) / 8;
DoBloodSplat(x, y, z, LaraItem->speed, d, LaraItem->room_number);
}
FLOOR_INFO *floor =
GetFloor(item->pos.x, item->pos.y, item->pos.z, &item->room_number);
item->floor = GetHeight(floor, item->pos.x, item->pos.y, item->pos.z);
AnimateItem(item);
}
// original name: FallingBlock
void FallingBlockControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
switch (item->current_anim_state) {
case TRAP_SET:
if (LaraItem->pos.y == item->pos.y - STEP_L * 2) {
item->goal_anim_state = TRAP_ACTIVATE;
} else {
item->status = IS_NOT_ACTIVE;
RemoveActiveItem(item_num);
return;
}
break;
case TRAP_ACTIVATE:
item->goal_anim_state = TRAP_WORKING;
break;
case TRAP_WORKING:
if (item->goal_anim_state != TRAP_FINISHED) {
item->gravity_status = 1;
}
break;
}
AnimateItem(item);
if (item->status == IS_DEACTIVATED) {
RemoveActiveItem(item_num);
return;
}
int16_t room_num = item->room_number;
FLOOR_INFO *floor =
GetFloor(item->pos.x, item->pos.y, item->pos.z, &room_num);
if (item->room_number != room_num) {
ItemNewRoom(item_num, room_num);
}
item->floor = GetHeight(floor, item->pos.x, item->pos.y, item->pos.z);
if (item->current_anim_state == TRAP_WORKING
&& item->pos.y >= item->floor) {
item->goal_anim_state = TRAP_FINISHED;
item->pos.y = item->floor;
item->fall_speed = 0;
item->gravity_status = 0;
}
}
void FallingBlockFloor(
ITEM_INFO *item, int32_t x, int32_t y, int32_t z, int16_t *height)
{
if (y <= item->pos.y - STEP_L * 2
&& (item->current_anim_state == TRAP_SET
|| item->current_anim_state == TRAP_ACTIVATE)) {
*height = item->pos.y - STEP_L * 2;
}
}
void FallingBlockCeiling(
ITEM_INFO *item, int32_t x, int32_t y, int32_t z, int16_t *height)
{
if (y > item->pos.y - STEP_L * 2
&& (item->current_anim_state == TRAP_SET
|| item->current_anim_state == TRAP_ACTIVATE)) {
*height = item->pos.y - STEP_L;
}
}
// original name: TeethTrap
void TeethTrapControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
if (TriggerActive(item)) {
item->goal_anim_state = TT_NASTY;
if (item->touch_bits && item->current_anim_state == TT_NASTY) {
LaraItem->hit_points -= TEETH_TRAP_DAMAGE;
LaraItem->hit_status = 1;
BaddieBiteEffect(item, &Teeth1A);
BaddieBiteEffect(item, &Teeth1B);
BaddieBiteEffect(item, &Teeth2A);
BaddieBiteEffect(item, &Teeth2B);
BaddieBiteEffect(item, &Teeth3A);
BaddieBiteEffect(item, &Teeth3B);
}
} else {
item->goal_anim_state = TT_NICE;
}
AnimateItem(item);
}
// original name: FallingCeiling
void FallingCeilingControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
if (item->current_anim_state == TRAP_SET) {
item->goal_anim_state = TRAP_ACTIVATE;
item->gravity_status = 1;
} else if (item->current_anim_state == TRAP_ACTIVATE && item->touch_bits) {
LaraItem->hit_points -= FALLING_CEILING_DAMAGE;
LaraItem->hit_status = 1;
}
AnimateItem(item);
if (item->status == IS_DEACTIVATED) {
RemoveActiveItem(item_num);
} else if (
item->current_anim_state == TRAP_ACTIVATE
&& item->pos.y >= item->floor) {
item->goal_anim_state = TRAP_WORKING;
item->pos.y = item->floor;
item->fall_speed = 0;
item->gravity_status = 0;
}
}
void InitialiseDamoclesSword(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
item->pos.y_rot = GetRandomControl();
item->required_anim_state = (GetRandomControl() - 0x4000) / 16;
item->fall_speed = 50;
}
void DamoclesSwordControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
if (item->gravity_status) {
item->pos.y_rot += item->required_anim_state;
item->fall_speed += item->fall_speed < FASTFALL_SPEED ? GRAVITY : 1;
item->pos.y += item->fall_speed;
item->pos.x += item->current_anim_state;
item->pos.z += item->goal_anim_state;
if (item->pos.y > item->floor) {
SoundEffect(SFX_DAMOCLES_SWORD, &item->pos, SPM_NORMAL);
item->pos.y = item->floor + 10;
item->gravity_status = 0;
item->status = IS_DEACTIVATED;
RemoveActiveItem(item_num);
}
} else if (item->pos.y != item->floor) {
item->pos.y_rot += item->required_anim_state;
int32_t x = LaraItem->pos.x - item->pos.x;
int32_t y = LaraItem->pos.y - item->pos.y;
int32_t z = LaraItem->pos.z - item->pos.z;
if (ABS(x) <= DAMOCLES_SWORD_ACTIVATE_DIST
&& ABS(z) <= DAMOCLES_SWORD_ACTIVATE_DIST && y > 0
&& y < WALL_L * 3) {
item->current_anim_state = x / 32;
item->goal_anim_state = z / 32;
item->gravity_status = 1;
}
}
}
void DamoclesSwordCollision(
int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll)
{
ITEM_INFO *item = &Items[item_num];
if (!TestBoundsCollide(item, lara_item, coll->radius)) {
return;
}
if (coll->enable_baddie_push) {
ItemPushLara(item, lara_item, coll, 0, 1);
}
if (item->gravity_status) {
lara_item->hit_points -= DAMOCLES_SWORD_DAMAGE;
int32_t x = lara_item->pos.x + (GetRandomControl() - 0x4000) / 256;
int32_t z = lara_item->pos.z + (GetRandomControl() - 0x4000) / 256;
int32_t y = lara_item->pos.y - GetRandomControl() / 44;
int32_t d = lara_item->pos.y_rot + (GetRandomControl() - 0x4000) / 8;
DoBloodSplat(x, y, z, lara_item->speed, d, lara_item->room_number);
}
}
void DartEmitterControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
if (TriggerActive(item)) {
if (item->current_anim_state == DE_IDLE) {
item->goal_anim_state = DE_FIRE;
}
} else {
if (item->current_anim_state == DE_FIRE) {
item->goal_anim_state = DE_IDLE;
}
}
if (item->current_anim_state == DE_FIRE
&& item->frame_number == Anims[item->anim_number].frame_base) {
int16_t dart_item_num = CreateItem();
if (dart_item_num != NO_ITEM) {
ITEM_INFO *dart = &Items[dart_item_num];
dart->object_number = O_DARTS;
dart->room_number = item->room_number;
dart->shade = -1;
dart->pos.y_rot = item->pos.y_rot;
dart->pos.y = item->pos.y - WALL_L / 2;
int32_t x = 0;
int32_t z = 0;
switch (dart->pos.y_rot) {
case 0:
z = -WALL_L / 2 + 100;
break;
case PHD_90:
x = -WALL_L / 2 + 100;
break;
case -PHD_180:
z = WALL_L / 2 - 100;
break;
case -PHD_90:
x = WALL_L / 2 - 100;
break;
}
dart->pos.x = item->pos.x + x;
dart->pos.z = item->pos.z + z;
InitialiseItem(dart_item_num);
AddActiveItem(dart_item_num);
dart->status = IS_ACTIVE;
int16_t fx_num = CreateEffect(dart->room_number);
if (fx_num != NO_ITEM) {
FX_INFO *fx = &Effects[fx_num];
fx->pos = dart->pos;
fx->speed = 0;
fx->frame_number = 0;
fx->counter = 0;
fx->object_number = O_DART_EFFECT;
SoundEffect(SFX_DARTS, &fx->pos, SPM_NORMAL);
}
}
}
AnimateItem(item);
}
void DartsControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
if (item->touch_bits) {
LaraItem->hit_points -= 50;
LaraItem->hit_status = 1;
DoBloodSplat(
item->pos.x, item->pos.y, item->pos.z, LaraItem->speed,
LaraItem->pos.y_rot, LaraItem->room_number);
}
AnimateItem(item);
int16_t room_num = item->room_number;
FLOOR_INFO *floor =
GetFloor(item->pos.x, item->pos.y, item->pos.z, &room_num);
if (item->room_number != room_num) {
ItemNewRoom(item_num, room_num);
}
item->floor = GetHeight(floor, item->pos.x, item->pos.y, item->pos.z);
if (item->pos.y >= item->floor) {
KillItem(item_num);
int16_t fx_num = CreateEffect(item->room_number);
if (fx_num != NO_ITEM) {
FX_INFO *fx = &Effects[fx_num];
fx->pos = item->pos;
fx->speed = 0;
fx->counter = 6;
fx->frame_number = -3 * GetRandomControl() / 0x8000;
fx->object_number = O_RICOCHET1;
}
}
}
void DartEffectControl(int16_t fx_num)
{
FX_INFO *fx = &Effects[fx_num];
fx->counter++;
if (fx->counter >= 3) {
fx->counter = 0;
fx->frame_number--;
if (fx->frame_number <= Objects[fx->object_number].nmeshes) {
KillEffect(fx_num);
}
}
}
void FlameEmitterControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
if (TriggerActive(item)) {
if (!item->data) {
int16_t fx_num = CreateEffect(item->room_number);
if (fx_num != NO_ITEM) {
FX_INFO *fx = &Effects[fx_num];
fx->pos.x = item->pos.x;
fx->pos.y = item->pos.y;
fx->pos.z = item->pos.z;
fx->frame_number = 0;
fx->object_number = O_FLAME;
fx->counter = 0;
}
item->data = (void *)(fx_num + 1);
}
} else if (item->data) {
StopSoundEffect(SFX_FIRE, NULL);
KillEffect((int16_t)(size_t)item->data - 1);
item->data = NULL;
}
}
void FlameControl(int16_t fx_num)
{
FX_INFO *fx = &Effects[fx_num];
fx->frame_number--;
if (fx->frame_number <= Objects[O_FLAME].nmeshes) {
fx->frame_number = 0;
}
if (fx->counter < 0) {
if (Lara.water_status == LWS_CHEAT) {
fx->counter = 0;
StopSoundEffect(SFX_FIRE, NULL);
KillEffect(fx_num);
}
fx->pos.x = 0;
fx->pos.y = 0;
if (fx->counter == -1) {
fx->pos.z = -100;
} else {
fx->pos.z = 0;
}
GetJointAbsPosition(LaraItem, (PHD_VECTOR *)&fx->pos, -1 - fx->counter);
int32_t y = GetWaterHeight(
LaraItem->pos.x, LaraItem->pos.y, LaraItem->pos.z,
LaraItem->room_number);
if (y != NO_HEIGHT && fx->pos.y > y) {
fx->counter = 0;
StopSoundEffect(SFX_FIRE, NULL);
KillEffect(fx_num);
} else {
SoundEffect(SFX_FIRE, &fx->pos, SPM_NORMAL);
LaraItem->hit_points -= FLAME_ONFIRE_DAMAGE;
LaraItem->hit_status = 1;
}
return;
}
SoundEffect(SFX_FIRE, &fx->pos, SPM_NORMAL);
if (fx->counter) {
fx->counter--;
} else if (ItemNearLara(&fx->pos, 600)) {
if (Lara.water_status == LWS_CHEAT) {
return;
}
int32_t x = LaraItem->pos.x - fx->pos.x;
int32_t z = LaraItem->pos.z - fx->pos.z;
int32_t distance = SQUARE(x) + SQUARE(z);
LaraItem->hit_points -= FLAME_TOONEAR_DAMAGE;
LaraItem->hit_status = 1;
if (distance < SQUARE(300)) {
fx->counter = 100;
fx_num = CreateEffect(LaraItem->room_number);
if (fx_num != NO_ITEM) {
fx = &Effects[fx_num];
fx->frame_number = 0;
fx->object_number = O_FLAME;
fx->counter = -1;
}
}
}
}
void LavaBurn(ITEM_INFO *item)
{
if (Lara.water_status == LWS_CHEAT) {
return;
}
if (item->hit_points < 0) {
return;
}
int16_t room_num = item->room_number;
FLOOR_INFO *floor = GetFloor(item->pos.x, 32000, item->pos.z, &room_num);
if (item->floor != GetHeight(floor, item->pos.x, 32000, item->pos.z)) {
return;
}
item->hit_points = -1;
item->hit_status = 1;
for (int i = 0; i < 10; i++) {
int16_t fx_num = CreateEffect(item->room_number);
if (fx_num != NO_ITEM) {
FX_INFO *fx = &Effects[fx_num];
fx->object_number = O_FLAME;
fx->frame_number =
(Objects[O_FLAME].nmeshes * GetRandomControl()) / 0x7FFF;
fx->counter = -1 - GetRandomControl() * 24 / 0x7FFF;
}
}
}
// original name: LavaSpray
void LavaEmitterControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
int16_t fx_num = CreateEffect(item->room_number);
if (fx_num != NO_ITEM) {
FX_INFO *fx = &Effects[fx_num];
fx->pos.x = item->pos.x;
fx->pos.y = item->pos.y;
fx->pos.z = item->pos.z;
fx->pos.y_rot = (GetRandomControl() - 0x4000) * 2;
fx->speed = GetRandomControl() >> 10;
fx->fall_speed = -GetRandomControl() / 200;
fx->frame_number = -4 * GetRandomControl() / 0x7FFF;
fx->object_number = O_LAVA;
SoundEffect(SFX_LAVA_FOUNTAIN, &item->pos, SPM_NORMAL);
}
}
// original name: ControlLavaBlob
void LavaControl(int16_t fx_num)
{
FX_INFO *fx = &Effects[fx_num];
fx->pos.z += (fx->speed * phd_cos(fx->pos.y_rot)) >> W2V_SHIFT;
fx->pos.x += (fx->speed * phd_sin(fx->pos.y_rot)) >> W2V_SHIFT;
fx->fall_speed += GRAVITY;
fx->pos.y += fx->fall_speed;
int16_t room_num = fx->room_number;
FLOOR_INFO *floor = GetFloor(fx->pos.x, fx->pos.y, fx->pos.z, &room_num);
if (fx->pos.y >= GetHeight(floor, fx->pos.x, fx->pos.y, fx->pos.z)
|| fx->pos.y < GetCeiling(floor, fx->pos.x, fx->pos.y, fx->pos.z)) {
KillEffect(fx_num);
} else if (ItemNearLara(&fx->pos, 200)) {
LaraItem->hit_points -= LAVA_GLOB_DAMAGE;
LaraItem->hit_status = 1;
KillEffect(fx_num);
} else if (room_num != fx->room_number) {
EffectNewRoom(fx_num, room_num);
}
}
// original name: LavaWedge
void LavaWedgeControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
int16_t room_num = item->room_number;
GetFloor(item->pos.x, item->pos.y, item->pos.z, &room_num);
if (room_num != item->room_number) {
ItemNewRoom(item_num, room_num);
}
if (item->status != IS_DEACTIVATED) {
int32_t x = item->pos.x;
int32_t z = item->pos.z;
switch (item->pos.y_rot) {
case 0:
item->pos.z += LAVA_WEDGE_SPEED;
z += 2 * WALL_L;
break;
case -PHD_180:
item->pos.z -= LAVA_WEDGE_SPEED;
z -= 2 * WALL_L;
break;
case PHD_90:
item->pos.x += LAVA_WEDGE_SPEED;
x += 2 * WALL_L;
break;
default:
item->pos.x -= LAVA_WEDGE_SPEED;
x -= 2 * WALL_L;
break;
}
FLOOR_INFO *floor = GetFloor(x, item->pos.y, z, &room_num);
if (GetHeight(floor, x, item->pos.y, z) != item->pos.y) {
item->status = IS_DEACTIVATED;
}
}
if (Lara.water_status == LWS_CHEAT) {
item->touch_bits = 0;
}
if (item->touch_bits) {
if (LaraItem->hit_points > 0) {
LavaBurn(LaraItem);
}
Camera.item = item;
Camera.flags = CHASE_OBJECT;
Camera.type = CAM_FIXED;
Camera.target_angle = -PHD_180;
Camera.target_distance = WALL_L * 3;
}
}
void T1MInjectGameTraps()
{
INJECT(0x0043A010, InitialiseRollingBall);
INJECT(0x0043A050, RollingBallControl);
INJECT(0x0043A2B0, RollingBallCollision);
INJECT(0x0043A520, SpikeCollision);
INJECT(0x0043A670, TrapDoorControl);
INJECT(0x0043A6D0, TrapDoorFloor);
INJECT(0x0043A720, TrapDoorCeiling);
INJECT(0x0043A770, OnTrapDoor);
INJECT(0x0043A820, PendulumControl);
INJECT(0x0043A970, FallingBlockControl);
INJECT(0x0043AA70, FallingBlockFloor);
INJECT(0x0043AAB0, FallingBlockCeiling);
INJECT(0x0043AAF0, TeethTrapControl);
INJECT(0x0043ABC0, FallingCeilingControl);
INJECT(0x0043AC60, InitialiseDamoclesSword);
INJECT(0x0043ACA0, DamoclesSwordControl);
INJECT(0x0043ADD0, DamoclesSwordCollision);
INJECT(0x0043AEC0, DartEmitterControl);
INJECT(0x0043B060, DartsControl);
INJECT(0x0043B1A0, DartEffectControl);
INJECT(0x0043B1F0, FlameEmitterControl);
INJECT(0x0043B2A0, FlameControl);
INJECT(0x0043B430, LavaBurn);
INJECT(0x0043B520, LavaEmitterControl);
INJECT(0x0043B5F0, LavaControl);
INJECT(0x0043B710, LavaWedgeControl);
}

View file

@ -1,42 +0,0 @@
#ifndef T1M_GAME_TRAPS_H
#define T1M_GAME_TRAPS_H
#include "game/types.h"
#include <stdint.h>
void InitialiseRollingBall(int16_t item_num);
void RollingBallControl(int16_t item_num);
void RollingBallCollision(
int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll);
void SpikeCollision(int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll);
void TrapDoorControl(int16_t item_num);
void TrapDoorFloor(
ITEM_INFO *item, int32_t x, int32_t y, int32_t z, int16_t *height);
void TrapDoorCeiling(
ITEM_INFO *item, int32_t x, int32_t y, int32_t z, int16_t *height);
int32_t OnTrapDoor(ITEM_INFO *item, int32_t x, int32_t z);
void PendulumControl(int16_t item_num);
void FallingBlockControl(int16_t item_num);
void FallingBlockFloor(
ITEM_INFO *item, int32_t x, int32_t y, int32_t z, int16_t *height);
void FallingBlockCeiling(
ITEM_INFO *item, int32_t x, int32_t y, int32_t z, int16_t *height);
void TeethTrapControl(int16_t item_num);
void FallingCeilingControl(int16_t item_num);
void InitialiseDamoclesSword(int16_t item_num);
void DamoclesSwordControl(int16_t item_num);
void DamoclesSwordCollision(
int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll);
void DartEmitterControl(int16_t item_num);
void DartsControl(int16_t item_num);
void DartEffectControl(int16_t fx_num);
void FlameEmitterControl(int16_t item_num);
void FlameControl(int16_t fx_num);
void LavaBurn(ITEM_INFO *item);
void LavaEmitterControl(int16_t item_num);
void LavaControl(int16_t fx_num);
void LavaWedgeControl(int16_t item_num);
void T1MInjectGameTraps();
#endif

View file

@ -0,0 +1,80 @@
#include "game/collide.h"
#include "game/effects.h"
#include "game/game.h"
#include "game/items.h"
#include "game/traps/damocles_sword.h"
#include "game/vars.h"
#define DAMOCLES_SWORD_ACTIVATE_DIST ((WALL_L * 3) / 2)
#define DAMOCLES_SWORD_DAMAGE 100
void SetupDamoclesSword(OBJECT_INFO *obj)
{
obj->initialise = InitialiseDamoclesSword;
obj->control = DamoclesSwordControl;
obj->collision = DamoclesSwordCollision;
obj->shadow_size = UNIT_SHADOW;
obj->save_position = 1;
obj->save_anim = 1;
obj->save_flags = 1;
}
void InitialiseDamoclesSword(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
item->pos.y_rot = GetRandomControl();
item->required_anim_state = (GetRandomControl() - 0x4000) / 16;
item->fall_speed = 50;
}
void DamoclesSwordControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
if (item->gravity_status) {
item->pos.y_rot += item->required_anim_state;
item->fall_speed += item->fall_speed < FASTFALL_SPEED ? GRAVITY : 1;
item->pos.y += item->fall_speed;
item->pos.x += item->current_anim_state;
item->pos.z += item->goal_anim_state;
if (item->pos.y > item->floor) {
SoundEffect(SFX_DAMOCLES_SWORD, &item->pos, SPM_NORMAL);
item->pos.y = item->floor + 10;
item->gravity_status = 0;
item->status = IS_DEACTIVATED;
RemoveActiveItem(item_num);
}
} else if (item->pos.y != item->floor) {
item->pos.y_rot += item->required_anim_state;
int32_t x = LaraItem->pos.x - item->pos.x;
int32_t y = LaraItem->pos.y - item->pos.y;
int32_t z = LaraItem->pos.z - item->pos.z;
if (ABS(x) <= DAMOCLES_SWORD_ACTIVATE_DIST
&& ABS(z) <= DAMOCLES_SWORD_ACTIVATE_DIST && y > 0
&& y < WALL_L * 3) {
item->current_anim_state = x / 32;
item->goal_anim_state = z / 32;
item->gravity_status = 1;
}
}
}
void DamoclesSwordCollision(
int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll)
{
ITEM_INFO *item = &Items[item_num];
if (!TestBoundsCollide(item, lara_item, coll->radius)) {
return;
}
if (coll->enable_baddie_push) {
ItemPushLara(item, lara_item, coll, 0, 1);
}
if (item->gravity_status) {
lara_item->hit_points -= DAMOCLES_SWORD_DAMAGE;
int32_t x = lara_item->pos.x + (GetRandomControl() - 0x4000) / 256;
int32_t z = lara_item->pos.z + (GetRandomControl() - 0x4000) / 256;
int32_t y = lara_item->pos.y - GetRandomControl() / 44;
int32_t d = lara_item->pos.y_rot + (GetRandomControl() - 0x4000) / 8;
DoBloodSplat(x, y, z, lara_item->speed, d, lara_item->room_number);
}
}

View file

@ -0,0 +1,12 @@
#ifndef T1M_GAME_TRAPS_DAMOCLES_SWORD_H
#define T1M_GAME_TRAPS_DAMOCLES_SWORD_H
#include "game/types.h"
void SetupDamoclesSword(OBJECT_INFO *obj);
void InitialiseDamoclesSword(int16_t item_num);
void DamoclesSwordControl(int16_t item_num);
void DamoclesSwordCollision(
int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll);
#endif

69
src/game/traps/dart.c Normal file
View file

@ -0,0 +1,69 @@
#include "game/collide.h"
#include "game/control.h"
#include "game/draw.h"
#include "game/effects.h"
#include "game/game.h"
#include "game/items.h"
#include "game/traps/dart.h"
#include "game/vars.h"
void SetupDart(OBJECT_INFO *obj)
{
obj->collision = ObjectCollision;
obj->control = DartsControl;
obj->shadow_size = UNIT_SHADOW / 2;
obj->save_flags = 1;
}
void SetupDartEffect(OBJECT_INFO *obj)
{
obj->control = DartEffectControl;
obj->draw_routine = DrawSpriteItem;
}
void DartsControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
if (item->touch_bits) {
LaraItem->hit_points -= 50;
LaraItem->hit_status = 1;
DoBloodSplat(
item->pos.x, item->pos.y, item->pos.z, LaraItem->speed,
LaraItem->pos.y_rot, LaraItem->room_number);
}
AnimateItem(item);
int16_t room_num = item->room_number;
FLOOR_INFO *floor =
GetFloor(item->pos.x, item->pos.y, item->pos.z, &room_num);
if (item->room_number != room_num) {
ItemNewRoom(item_num, room_num);
}
item->floor = GetHeight(floor, item->pos.x, item->pos.y, item->pos.z);
if (item->pos.y >= item->floor) {
KillItem(item_num);
int16_t fx_num = CreateEffect(item->room_number);
if (fx_num != NO_ITEM) {
FX_INFO *fx = &Effects[fx_num];
fx->pos = item->pos;
fx->speed = 0;
fx->counter = 6;
fx->frame_number = -3 * GetRandomControl() / 0x8000;
fx->object_number = O_RICOCHET1;
}
}
}
void DartEffectControl(int16_t fx_num)
{
FX_INFO *fx = &Effects[fx_num];
fx->counter++;
if (fx->counter >= 3) {
fx->counter = 0;
fx->frame_number--;
if (fx->frame_number <= Objects[fx->object_number].nmeshes) {
KillEffect(fx_num);
}
}
}

12
src/game/traps/dart.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef T1M_GAME_TRAPS_DART_H
#define T1M_GAME_TRAPS_DART_H
#include "game/types.h"
#include <stdint.h>
void SetupDart(OBJECT_INFO *obj);
void SetupDartEffect(OBJECT_INFO *obj);
void DartsControl(int16_t item_num);
void DartEffectControl(int16_t fx_num);
#endif

View file

@ -0,0 +1,73 @@
#include "game/control.h"
#include "game/effects.h"
#include "game/items.h"
#include "game/traps/dart_emitter.h"
#include "game/vars.h"
void SetupDartEmitter(OBJECT_INFO *obj)
{
obj->control = DartEmitterControl;
}
void DartEmitterControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
if (TriggerActive(item)) {
if (item->current_anim_state == DART_EMITTER_IDLE) {
item->goal_anim_state = DART_EMITTER_FIRE;
}
} else {
if (item->current_anim_state == DART_EMITTER_FIRE) {
item->goal_anim_state = DART_EMITTER_IDLE;
}
}
if (item->current_anim_state == DART_EMITTER_FIRE
&& item->frame_number == Anims[item->anim_number].frame_base) {
int16_t dart_item_num = CreateItem();
if (dart_item_num != NO_ITEM) {
ITEM_INFO *dart = &Items[dart_item_num];
dart->object_number = O_DARTS;
dart->room_number = item->room_number;
dart->shade = -1;
dart->pos.y_rot = item->pos.y_rot;
dart->pos.y = item->pos.y - WALL_L / 2;
int32_t x = 0;
int32_t z = 0;
switch (dart->pos.y_rot) {
case 0:
z = -WALL_L / 2 + 100;
break;
case PHD_90:
x = -WALL_L / 2 + 100;
break;
case -PHD_180:
z = WALL_L / 2 - 100;
break;
case -PHD_90:
x = WALL_L / 2 - 100;
break;
}
dart->pos.x = item->pos.x + x;
dart->pos.z = item->pos.z + z;
InitialiseItem(dart_item_num);
AddActiveItem(dart_item_num);
dart->status = IS_ACTIVE;
int16_t fx_num = CreateEffect(dart->room_number);
if (fx_num != NO_ITEM) {
FX_INFO *fx = &Effects[fx_num];
fx->pos = dart->pos;
fx->speed = 0;
fx->frame_number = 0;
fx->counter = 0;
fx->object_number = O_DART_EFFECT;
SoundEffect(SFX_DARTS, &fx->pos, SPM_NORMAL);
}
}
}
AnimateItem(item);
}

View file

@ -0,0 +1,15 @@
#ifndef T1M_GAME_TRAPS_DART_EMITTER_H
#define T1M_GAME_TRAPS_DART_EMITTER_H
#include "game/types.h"
#include <stdint.h>
typedef enum {
DART_EMITTER_IDLE = 0,
DART_EMITTER_FIRE = 1,
} DART_EMITTER_STATE;
void SetupDartEmitter(OBJECT_INFO *obj);
void DartEmitterControl(int16_t item_num);
#endif

View file

@ -0,0 +1,85 @@
#include "game/traps/falling_block.h"
#include "game/control.h"
#include "game/items.h"
#include "game/vars.h"
void SetupFallingBlock(OBJECT_INFO *obj)
{
obj->control = FallingBlockControl;
obj->floor = FallingBlockFloor;
obj->ceiling = FallingBlockCeiling;
obj->save_position = 1;
obj->save_anim = 1;
obj->save_flags = 1;
}
// original name: FallingBlock
void FallingBlockControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
switch (item->current_anim_state) {
case TRAP_SET:
if (LaraItem->pos.y == item->pos.y - STEP_L * 2) {
item->goal_anim_state = TRAP_ACTIVATE;
} else {
item->status = IS_NOT_ACTIVE;
RemoveActiveItem(item_num);
return;
}
break;
case TRAP_ACTIVATE:
item->goal_anim_state = TRAP_WORKING;
break;
case TRAP_WORKING:
if (item->goal_anim_state != TRAP_FINISHED) {
item->gravity_status = 1;
}
break;
}
AnimateItem(item);
if (item->status == IS_DEACTIVATED) {
RemoveActiveItem(item_num);
return;
}
int16_t room_num = item->room_number;
FLOOR_INFO *floor =
GetFloor(item->pos.x, item->pos.y, item->pos.z, &room_num);
if (item->room_number != room_num) {
ItemNewRoom(item_num, room_num);
}
item->floor = GetHeight(floor, item->pos.x, item->pos.y, item->pos.z);
if (item->current_anim_state == TRAP_WORKING
&& item->pos.y >= item->floor) {
item->goal_anim_state = TRAP_FINISHED;
item->pos.y = item->floor;
item->fall_speed = 0;
item->gravity_status = 0;
}
}
void FallingBlockFloor(
ITEM_INFO *item, int32_t x, int32_t y, int32_t z, int16_t *height)
{
if (y <= item->pos.y - STEP_L * 2
&& (item->current_anim_state == TRAP_SET
|| item->current_anim_state == TRAP_ACTIVATE)) {
*height = item->pos.y - STEP_L * 2;
}
}
void FallingBlockCeiling(
ITEM_INFO *item, int32_t x, int32_t y, int32_t z, int16_t *height)
{
if (y > item->pos.y - STEP_L * 2
&& (item->current_anim_state == TRAP_SET
|| item->current_anim_state == TRAP_ACTIVATE)) {
*height = item->pos.y - STEP_L;
}
}

View file

@ -0,0 +1,14 @@
#ifndef T1M_GAME_TRAPS_FALLING_BLOCK_H
#define T1M_GAME_TRAPS_FALLING_BLOCK_H
#include "game/types.h"
#include <stdint.h>
void SetupFallingBlock(OBJECT_INFO *obj);
void FallingBlockControl(int16_t item_num);
void FallingBlockFloor(
ITEM_INFO *item, int32_t x, int32_t y, int32_t z, int16_t *height);
void FallingBlockCeiling(
ITEM_INFO *item, int32_t x, int32_t y, int32_t z, int16_t *height);
#endif

View file

@ -0,0 +1,38 @@
#include "game/collide.h"
#include "game/control.h"
#include "game/items.h"
#include "game/traps/falling_ceiling.h"
#include "game/vars.h"
void SetupFallingCeilling(OBJECT_INFO *obj)
{
obj->control = FallingCeilingControl;
obj->collision = TrapCollision;
obj->save_position = 1;
obj->save_anim = 1;
obj->save_flags = 1;
}
// original name: FallingCeiling
void FallingCeilingControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
if (item->current_anim_state == TRAP_SET) {
item->goal_anim_state = TRAP_ACTIVATE;
item->gravity_status = 1;
} else if (item->current_anim_state == TRAP_ACTIVATE && item->touch_bits) {
LaraItem->hit_points -= FALLING_CEILING_DAMAGE;
LaraItem->hit_status = 1;
}
AnimateItem(item);
if (item->status == IS_DEACTIVATED) {
RemoveActiveItem(item_num);
} else if (
item->current_anim_state == TRAP_ACTIVATE
&& item->pos.y >= item->floor) {
item->goal_anim_state = TRAP_WORKING;
item->pos.y = item->floor;
item->fall_speed = 0;
item->gravity_status = 0;
}
}

View file

@ -0,0 +1,12 @@
#ifndef T1M_GAME_TRAPS_FALLING_CEILING_H
#define T1M_GAME_TRAPS_FALLING_CEILING_H
#include "game/types.h"
#include <stdint.h>
#define FALLING_CEILING_DAMAGE 300
void SetupFallingCeilling(OBJECT_INFO *obj);
void FallingCeilingControl(int16_t item_num);
#endif

113
src/game/traps/flame.c Normal file
View file

@ -0,0 +1,113 @@
#include "game/control.h"
#include "game/draw.h"
#include "game/effects.h"
#include "game/items.h"
#include "game/sphere.h"
#include "game/traps/flame.h"
#include "game/vars.h"
void SetupFlameEmitter(OBJECT_INFO *obj)
{
obj->control = FlameEmitterControl;
obj->draw_routine = DrawDummyItem;
}
void SetupFlame(OBJECT_INFO *obj)
{
obj->control = FlameControl;
}
void FlameEmitterControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
if (TriggerActive(item)) {
if (!item->data) {
int16_t fx_num = CreateEffect(item->room_number);
if (fx_num != NO_ITEM) {
FX_INFO *fx = &Effects[fx_num];
fx->pos.x = item->pos.x;
fx->pos.y = item->pos.y;
fx->pos.z = item->pos.z;
fx->frame_number = 0;
fx->object_number = O_FLAME;
fx->counter = 0;
}
item->data = (void *)(fx_num + 1);
}
} else if (item->data) {
StopSoundEffect(SFX_FIRE, NULL);
KillEffect((int16_t)(size_t)item->data - 1);
item->data = NULL;
}
}
void FlameControl(int16_t fx_num)
{
FX_INFO *fx = &Effects[fx_num];
fx->frame_number--;
if (fx->frame_number <= Objects[O_FLAME].nmeshes) {
fx->frame_number = 0;
}
if (fx->counter < 0) {
if (Lara.water_status == LWS_CHEAT) {
fx->counter = 0;
StopSoundEffect(SFX_FIRE, NULL);
KillEffect(fx_num);
}
fx->pos.x = 0;
fx->pos.y = 0;
if (fx->counter == -1) {
fx->pos.z = -100;
} else {
fx->pos.z = 0;
}
GetJointAbsPosition(LaraItem, (PHD_VECTOR *)&fx->pos, -1 - fx->counter);
int32_t y = GetWaterHeight(
LaraItem->pos.x, LaraItem->pos.y, LaraItem->pos.z,
LaraItem->room_number);
if (y != NO_HEIGHT && fx->pos.y > y) {
fx->counter = 0;
StopSoundEffect(SFX_FIRE, NULL);
KillEffect(fx_num);
} else {
SoundEffect(SFX_FIRE, &fx->pos, SPM_NORMAL);
LaraItem->hit_points -= FLAME_ONFIRE_DAMAGE;
LaraItem->hit_status = 1;
}
return;
}
SoundEffect(SFX_FIRE, &fx->pos, SPM_NORMAL);
if (fx->counter) {
fx->counter--;
} else if (ItemNearLara(&fx->pos, 600)) {
if (Lara.water_status == LWS_CHEAT) {
return;
}
int32_t x = LaraItem->pos.x - fx->pos.x;
int32_t z = LaraItem->pos.z - fx->pos.z;
int32_t distance = SQUARE(x) + SQUARE(z);
LaraItem->hit_points -= FLAME_TOONEAR_DAMAGE;
LaraItem->hit_status = 1;
if (distance < SQUARE(300)) {
fx->counter = 100;
fx_num = CreateEffect(LaraItem->room_number);
if (fx_num != NO_ITEM) {
fx = &Effects[fx_num];
fx->frame_number = 0;
fx->object_number = O_FLAME;
fx->counter = -1;
}
}
}
}

15
src/game/traps/flame.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef T1M_GAME_TRAPS_FLAME_H
#define T1M_GAME_TRAPS_FLAME_H
#include "game/types.h"
#include <stdint.h>
#define FLAME_ONFIRE_DAMAGE 5
#define FLAME_TOONEAR_DAMAGE 3
void SetupFlameEmitter(OBJECT_INFO *obj);
void SetupFlame(OBJECT_INFO *obj);
void FlameEmitterControl(int16_t item_num);
void FlameControl(int16_t fx_num);
#endif

160
src/game/traps/lava.c Normal file
View file

@ -0,0 +1,160 @@
#include "3dsystem/phd_math.h"
#include "game/collide.h"
#include "game/control.h"
#include "game/draw.h"
#include "game/effects.h"
#include "game/game.h"
#include "game/items.h"
#include "game/traps/lava.h"
#include "game/vars.h"
void SetupLavaEmitter(OBJECT_INFO *obj)
{
obj->control = LavaEmitterControl;
obj->draw_routine = DrawDummyItem;
obj->collision = ObjectCollision;
}
void SetupLava(OBJECT_INFO *obj)
{
obj->control = LavaControl;
}
void SetupLavaWedge(OBJECT_INFO *obj)
{
obj->control = LavaWedgeControl;
obj->collision = CreatureCollision;
obj->save_position = 1;
obj->save_anim = 1;
obj->save_flags = 1;
}
void LavaBurn(ITEM_INFO *item)
{
if (Lara.water_status == LWS_CHEAT) {
return;
}
if (item->hit_points < 0) {
return;
}
int16_t room_num = item->room_number;
FLOOR_INFO *floor = GetFloor(item->pos.x, 32000, item->pos.z, &room_num);
if (item->floor != GetHeight(floor, item->pos.x, 32000, item->pos.z)) {
return;
}
item->hit_points = -1;
item->hit_status = 1;
for (int i = 0; i < 10; i++) {
int16_t fx_num = CreateEffect(item->room_number);
if (fx_num != NO_ITEM) {
FX_INFO *fx = &Effects[fx_num];
fx->object_number = O_FLAME;
fx->frame_number =
(Objects[O_FLAME].nmeshes * GetRandomControl()) / 0x7FFF;
fx->counter = -1 - GetRandomControl() * 24 / 0x7FFF;
}
}
}
// original name: LavaSpray
void LavaEmitterControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
int16_t fx_num = CreateEffect(item->room_number);
if (fx_num != NO_ITEM) {
FX_INFO *fx = &Effects[fx_num];
fx->pos.x = item->pos.x;
fx->pos.y = item->pos.y;
fx->pos.z = item->pos.z;
fx->pos.y_rot = (GetRandomControl() - 0x4000) * 2;
fx->speed = GetRandomControl() >> 10;
fx->fall_speed = -GetRandomControl() / 200;
fx->frame_number = -4 * GetRandomControl() / 0x7FFF;
fx->object_number = O_LAVA;
SoundEffect(SFX_LAVA_FOUNTAIN, &item->pos, SPM_NORMAL);
}
}
// original name: ControlLavaBlob
void LavaControl(int16_t fx_num)
{
FX_INFO *fx = &Effects[fx_num];
fx->pos.z += (fx->speed * phd_cos(fx->pos.y_rot)) >> W2V_SHIFT;
fx->pos.x += (fx->speed * phd_sin(fx->pos.y_rot)) >> W2V_SHIFT;
fx->fall_speed += GRAVITY;
fx->pos.y += fx->fall_speed;
int16_t room_num = fx->room_number;
FLOOR_INFO *floor = GetFloor(fx->pos.x, fx->pos.y, fx->pos.z, &room_num);
if (fx->pos.y >= GetHeight(floor, fx->pos.x, fx->pos.y, fx->pos.z)
|| fx->pos.y < GetCeiling(floor, fx->pos.x, fx->pos.y, fx->pos.z)) {
KillEffect(fx_num);
} else if (ItemNearLara(&fx->pos, 200)) {
LaraItem->hit_points -= LAVA_GLOB_DAMAGE;
LaraItem->hit_status = 1;
KillEffect(fx_num);
} else if (room_num != fx->room_number) {
EffectNewRoom(fx_num, room_num);
}
}
// original name: LavaWedge
void LavaWedgeControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
int16_t room_num = item->room_number;
GetFloor(item->pos.x, item->pos.y, item->pos.z, &room_num);
if (room_num != item->room_number) {
ItemNewRoom(item_num, room_num);
}
if (item->status != IS_DEACTIVATED) {
int32_t x = item->pos.x;
int32_t z = item->pos.z;
switch (item->pos.y_rot) {
case 0:
item->pos.z += LAVA_WEDGE_SPEED;
z += 2 * WALL_L;
break;
case -PHD_180:
item->pos.z -= LAVA_WEDGE_SPEED;
z -= 2 * WALL_L;
break;
case PHD_90:
item->pos.x += LAVA_WEDGE_SPEED;
x += 2 * WALL_L;
break;
default:
item->pos.x -= LAVA_WEDGE_SPEED;
x -= 2 * WALL_L;
break;
}
FLOOR_INFO *floor = GetFloor(x, item->pos.y, z, &room_num);
if (GetHeight(floor, x, item->pos.y, z) != item->pos.y) {
item->status = IS_DEACTIVATED;
}
}
if (Lara.water_status == LWS_CHEAT) {
item->touch_bits = 0;
}
if (item->touch_bits) {
if (LaraItem->hit_points > 0) {
LavaBurn(LaraItem);
}
Camera.item = item;
Camera.flags = CHASE_OBJECT;
Camera.type = CAM_FIXED;
Camera.target_angle = -PHD_180;
Camera.target_distance = WALL_L * 3;
}
}

18
src/game/traps/lava.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef T1M_GAME_TRAPS_LAVA_H
#define T1M_GAME_TRAPS_LAVA_H
#include "game/types.h"
#include <stdint.h>
#define LAVA_GLOB_DAMAGE 10
#define LAVA_WEDGE_SPEED 25
void SetupLavaEmitter(OBJECT_INFO *obj);
void SetupLava(OBJECT_INFO *obj);
void SetupLavaWedge(OBJECT_INFO *obj);
void LavaBurn(ITEM_INFO *item);
void LavaEmitterControl(int16_t item_num);
void LavaControl(int16_t fx_num);
void LavaWedgeControl(int16_t item_num);
#endif

View file

@ -1,42 +1,144 @@
#include "3dsystem/3d_gen.h"
#include "game/collide.h"
#include "game/const.h"
#include "3dsystem/phd_math.h"
#include "game/control.h"
#include "game/draw.h"
#include "game/effects.h"
#include "game/game.h"
#include "game/items.h"
#include "game/lightning.h"
#include "game/moveblock.h"
#include "game/sphere.h"
#include "game/traps/lightning_emitter.h"
#include "game/vars.h"
#include "specific/init.h"
#include "specific/output.h"
#include "util.h"
#define LIGHTNING_DAMAGE 400
#define LIGHTNING_STEPS 8
#define LIGHTNING_RND ((64 << W2V_SHIFT) / 0x8000) // = 32
#define LIGHTNING_SHOOTS 2
void SetupLightningEmitter(OBJECT_INFO *obj)
{
obj->initialise = InitialiseLightning;
obj->control = LightningControl;
obj->draw_routine = DrawLightning;
obj->collision = LightningCollision;
obj->save_flags = 1;
}
typedef struct {
int32_t onstate;
int32_t count;
int32_t zapped;
int32_t notarget;
PHD_VECTOR target;
PHD_VECTOR main[LIGHTNING_STEPS], wibble[LIGHTNING_STEPS];
int start[LIGHTNING_SHOOTS];
PHD_VECTOR end[LIGHTNING_SHOOTS];
PHD_VECTOR shoot[LIGHTNING_SHOOTS][LIGHTNING_STEPS];
} LIGHTNING;
void InitialiseLightning(int16_t item_num)
{
LIGHTNING *l = game_malloc(sizeof(LIGHTNING), 0);
Items[item_num].data = l;
typedef enum {
THS_SET = 0,
THS_TEASE = 1,
THS_ACTIVE = 2,
THS_DONE = 3,
} THOR_HAMMER_STATE;
if (Objects[Items[item_num].object_number].nmeshes > 1) {
Items[item_num].mesh_bits = 1;
l->notarget = 0;
} else {
l->notarget = 1;
}
l->onstate = 0;
l->count = 1;
l->zapped = 0;
}
void LightningControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
LIGHTNING *l = item->data;
if (!TriggerActive(item)) {
l->count = 1;
l->onstate = 0;
l->zapped = 0;
if (FlipStatus) {
FlipMap();
}
RemoveActiveItem(item_num);
item->status = IS_NOT_ACTIVE;
return;
}
l->count--;
if (l->count > 0) {
return;
}
if (l->onstate) {
l->onstate = 0;
l->count = 35 + (GetRandomControl() * 45) / 0x8000;
l->zapped = 0;
if (FlipStatus) {
FlipMap();
}
} else {
l->onstate = 1;
l->count = 20;
for (int i = 0; i < LIGHTNING_STEPS; i++) {
l->wibble[i].x = 0;
l->wibble[i].y = 0;
l->wibble[i].z = 0;
}
int32_t radius = l->notarget ? WALL_L : WALL_L * 5 / 2;
if (ItemNearLara(&item->pos, radius)) {
l->target.x = LaraItem->pos.x;
l->target.y = LaraItem->pos.y;
l->target.z = LaraItem->pos.z;
LaraItem->hit_points -= LIGHTNING_DAMAGE;
LaraItem->hit_status = 1;
l->zapped = 1;
} else if (l->notarget) {
FLOOR_INFO *floor = GetFloor(
item->pos.x, item->pos.y, item->pos.z, &item->room_number);
int32_t h = GetHeight(floor, item->pos.x, item->pos.y, item->pos.z);
l->target.x = item->pos.x;
l->target.y = h;
l->target.z = item->pos.z;
l->zapped = 0;
} else {
l->target.x = 0;
l->target.y = 0;
l->target.z = 0;
GetJointAbsPosition(
item, &l->target, 1 + (GetRandomControl() * 5) / 0x7FFF);
l->zapped = 0;
}
for (int i = 0; i < LIGHTNING_SHOOTS; i++) {
l->start[i] = GetRandomControl() * (LIGHTNING_STEPS - 1) / 0x7FFF;
l->end[i].x = l->target.x + (GetRandomControl() * WALL_L) / 0x7FFF;
l->end[i].y = l->target.y;
l->end[i].z = l->target.z + (GetRandomControl() * WALL_L) / 0x7FFF;
for (int j = 0; j < LIGHTNING_STEPS; j++) {
l->shoot[i][j].x = 0;
l->shoot[i][j].y = 0;
l->shoot[i][j].z = 0;
}
}
if (!FlipStatus) {
FlipMap();
}
}
SoundEffect(SFX_THUNDER, &item->pos, SPM_NORMAL);
}
void LightningCollision(int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll)
{
LIGHTNING *l = Items[item_num].data;
if (!l->zapped) {
return;
}
Lara.hit_direction = 1 + (GetRandomControl() * 4) / (PHD_180 - 1);
Lara.hit_frame++;
if (Lara.hit_frame > 34) {
Lara.hit_frame = 34;
}
}
void DrawLightning(ITEM_INFO *item)
{
@ -165,280 +267,3 @@ void DrawLightning(ITEM_INFO *item)
phd_PopMatrix();
}
void InitialiseLightning(int16_t item_num)
{
LIGHTNING *l = game_malloc(sizeof(LIGHTNING), 0);
Items[item_num].data = l;
if (Objects[Items[item_num].object_number].nmeshes > 1) {
Items[item_num].mesh_bits = 1;
l->notarget = 0;
} else {
l->notarget = 1;
}
l->onstate = 0;
l->count = 1;
l->zapped = 0;
}
void LightningControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
LIGHTNING *l = item->data;
if (!TriggerActive(item)) {
l->count = 1;
l->onstate = 0;
l->zapped = 0;
if (FlipStatus) {
FlipMap();
}
RemoveActiveItem(item_num);
item->status = IS_NOT_ACTIVE;
return;
}
l->count--;
if (l->count > 0) {
return;
}
if (l->onstate) {
l->onstate = 0;
l->count = 35 + (GetRandomControl() * 45) / 0x8000;
l->zapped = 0;
if (FlipStatus) {
FlipMap();
}
} else {
l->onstate = 1;
l->count = 20;
for (int i = 0; i < LIGHTNING_STEPS; i++) {
l->wibble[i].x = 0;
l->wibble[i].y = 0;
l->wibble[i].z = 0;
}
int32_t radius = l->notarget ? WALL_L : WALL_L * 5 / 2;
if (ItemNearLara(&item->pos, radius)) {
l->target.x = LaraItem->pos.x;
l->target.y = LaraItem->pos.y;
l->target.z = LaraItem->pos.z;
LaraItem->hit_points -= LIGHTNING_DAMAGE;
LaraItem->hit_status = 1;
l->zapped = 1;
} else if (l->notarget) {
FLOOR_INFO *floor = GetFloor(
item->pos.x, item->pos.y, item->pos.z, &item->room_number);
int32_t h = GetHeight(floor, item->pos.x, item->pos.y, item->pos.z);
l->target.x = item->pos.x;
l->target.y = h;
l->target.z = item->pos.z;
l->zapped = 0;
} else {
l->target.x = 0;
l->target.y = 0;
l->target.z = 0;
GetJointAbsPosition(
item, &l->target, 1 + (GetRandomControl() * 5) / 0x7FFF);
l->zapped = 0;
}
for (int i = 0; i < LIGHTNING_SHOOTS; i++) {
l->start[i] = GetRandomControl() * (LIGHTNING_STEPS - 1) / 0x7FFF;
l->end[i].x = l->target.x + (GetRandomControl() * WALL_L) / 0x7FFF;
l->end[i].y = l->target.y;
l->end[i].z = l->target.z + (GetRandomControl() * WALL_L) / 0x7FFF;
for (int j = 0; j < LIGHTNING_STEPS; j++) {
l->shoot[i][j].x = 0;
l->shoot[i][j].y = 0;
l->shoot[i][j].z = 0;
}
}
if (!FlipStatus) {
FlipMap();
}
}
SoundEffect(SFX_THUNDER, &item->pos, SPM_NORMAL);
}
void LightningCollision(int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll)
{
LIGHTNING *l = Items[item_num].data;
if (!l->zapped) {
return;
}
Lara.hit_direction = 1 + (GetRandomControl() * 4) / (PHD_180 - 1);
Lara.hit_frame++;
if (Lara.hit_frame > 34) {
Lara.hit_frame = 34;
}
}
void InitialiseThorsHandle(int16_t item_num)
{
ITEM_INFO *hand_item = &Items[item_num];
int16_t head_item_num = CreateItem();
ITEM_INFO *head_item = &Items[head_item_num];
head_item->object_number = O_THORS_HEAD;
head_item->room_number = hand_item->room_number;
head_item->pos = hand_item->pos;
head_item->shade = hand_item->shade;
InitialiseItem(head_item_num);
hand_item->data = head_item;
LevelItemCount++;
}
void ThorsHandleControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
switch (item->current_anim_state) {
case THS_SET:
if (TriggerActive(item)) {
item->goal_anim_state = THS_TEASE;
} else {
RemoveActiveItem(item_num);
item->status = IS_NOT_ACTIVE;
}
break;
case THS_TEASE:
if (TriggerActive(item)) {
item->goal_anim_state = THS_ACTIVE;
} else {
item->goal_anim_state = THS_SET;
}
break;
case THS_ACTIVE: {
int32_t frm = item->frame_number - Anims[item->anim_number].frame_base;
if (frm > 30) {
int32_t x = item->pos.x;
int32_t z = item->pos.z;
switch (item->pos.y_rot) {
case 0:
z += WALL_L * 3;
break;
case PHD_90:
x += WALL_L * 3;
break;
case -PHD_90:
x -= WALL_L * 3;
break;
case -PHD_180:
z -= WALL_L * 3;
break;
}
if (LaraItem->hit_points >= 0 && LaraItem->pos.x > x - 520
&& LaraItem->pos.x < x + 520 && LaraItem->pos.z > z - 520
&& LaraItem->pos.z < z + 520) {
LaraItem->hit_points = -1;
LaraItem->pos.y = item->pos.y;
LaraItem->gravity_status = 0;
LaraItem->current_anim_state = AS_SPECIAL;
LaraItem->goal_anim_state = AS_SPECIAL;
LaraItem->anim_number = AA_RBALL_DEATH;
LaraItem->frame_number = AF_RBALL_DEATH;
}
}
break;
}
case THS_DONE: {
int32_t x = item->pos.x;
int32_t z = item->pos.z;
int32_t old_x = x;
int32_t old_z = z;
int16_t room_num = item->room_number;
FLOOR_INFO *floor = GetFloor(x, item->pos.y, z, &room_num);
GetHeight(floor, x, item->pos.y, z);
TestTriggers(TriggerIndex, 1);
switch (item->pos.y_rot) {
case 0:
z += WALL_L * 3;
break;
case PHD_90:
x += WALL_L * 3;
break;
case -PHD_90:
x -= WALL_L * 3;
break;
case -PHD_180:
z -= WALL_L * 3;
break;
}
item->pos.x = x;
item->pos.z = z;
if (LaraItem->hit_points >= 0) {
AlterFloorHeight(item, -2 * WALL_L);
}
item->pos.x = old_x;
item->pos.z = old_z;
RemoveActiveItem(item_num);
item->status = IS_DEACTIVATED;
break;
}
}
AnimateItem(item);
ITEM_INFO *head_item = item->data;
int32_t anim = item->anim_number - Objects[O_THORS_HANDLE].anim_index;
int32_t frm = item->frame_number - Anims[item->anim_number].frame_base;
head_item->anim_number = Objects[O_THORS_HEAD].anim_index + anim;
head_item->frame_number = Anims[head_item->anim_number].frame_base + frm;
head_item->current_anim_state = item->current_anim_state;
}
void ThorsHandleCollision(
int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll)
{
ITEM_INFO *item = &Items[item_num];
if (!TestBoundsCollide(item, lara_item, coll->radius)) {
return;
}
if (coll->enable_baddie_push) {
ItemPushLara(item, lara_item, coll, 0, 1);
}
}
void ThorsHeadCollision(int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll)
{
ITEM_INFO *item = &Items[item_num];
if (!TestBoundsCollide(item, lara_item, coll->radius)) {
return;
}
if (coll->enable_baddie_push && item->current_anim_state != THS_ACTIVE) {
ItemPushLara(item, lara_item, coll, 0, 1);
}
}
void T1MInjectGameLightning()
{
INJECT(0x00429620, DrawLightning);
INJECT(0x00429B00, InitialiseLightning);
INJECT(0x00429B80, LightningControl);
INJECT(0x00429E30, LightningCollision);
INJECT(0x00429EA0, InitialiseThorsHandle);
INJECT(0x00429F30, ThorsHandleControl);
INJECT(0x0042A1F0, ThorsHandleCollision);
INJECT(0x0042A240, ThorsHeadCollision);
}

View file

@ -0,0 +1,30 @@
#ifndef T1M_GAME_TRAPS_LIGHTNING_EMITTER_H
#define T1M_GAME_TRAPS_LIGHTNING_EMITTER_H
#include "game/types.h"
#define LIGHTNING_DAMAGE 400
#define LIGHTNING_STEPS 8
#define LIGHTNING_RND ((64 << W2V_SHIFT) / 0x8000) // = 32
#define LIGHTNING_SHOOTS 2
typedef struct {
int32_t onstate;
int32_t count;
int32_t zapped;
int32_t notarget;
PHD_VECTOR target;
PHD_VECTOR main[LIGHTNING_STEPS], wibble[LIGHTNING_STEPS];
int start[LIGHTNING_SHOOTS];
PHD_VECTOR end[LIGHTNING_SHOOTS];
PHD_VECTOR shoot[LIGHTNING_SHOOTS][LIGHTNING_STEPS];
} LIGHTNING;
void SetupLightningEmitter(OBJECT_INFO *obj);
void InitialiseLightning(int16_t item_num);
void LightningControl(int16_t item_num);
void LightningCollision(
int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll);
void DrawLightning(ITEM_INFO *item);
#endif

View file

@ -0,0 +1,91 @@
#include "game/collide.h"
#include "game/draw.h"
#include "game/inv.h"
#include "game/traps/midas_touch.h"
#include "game/vars.h"
int16_t MidasBounds[12] = {
-700,
+700,
+384 - 100,
+384 + 100 + 512,
-700,
+700,
-10 * PHD_DEGREE,
+10 * PHD_DEGREE,
-30 * PHD_DEGREE,
+30 * PHD_DEGREE,
-10 * PHD_DEGREE,
+10 * PHD_DEGREE,
};
void SetupMidasTouch(OBJECT_INFO *obj)
{
obj->collision = MidasCollision;
obj->draw_routine = DrawDummyItem;
}
void MidasCollision(int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll)
{
ITEM_INFO *item = &Items[item_num];
if (!lara_item->gravity_status && lara_item->current_anim_state == AS_STOP
&& lara_item->pos.x > item->pos.x - 512
&& lara_item->pos.x < item->pos.x + 512
&& lara_item->pos.z > item->pos.z - 512
&& lara_item->pos.z < item->pos.z + 512) {
lara_item->current_anim_state = AS_DIEMIDAS;
lara_item->goal_anim_state = AS_DIEMIDAS;
lara_item->anim_number = Objects[O_LARA_EXTRA].anim_index + 1;
lara_item->frame_number = Anims[lara_item->anim_number].frame_base;
lara_item->hit_points = -1;
lara_item->gravity_status = 0;
Lara.air = -1;
Lara.gun_status = LGS_HANDSBUSY;
Lara.gun_type = LGT_UNARMED;
Camera.type = CAM_CINEMATIC;
CineFrame = 0;
CinematicPosition = lara_item->pos;
return;
}
if ((InventoryChosen == -1 && !CHK_ANY(Input, IN_ACTION))
|| Lara.gun_status != LGS_ARMLESS || lara_item->gravity_status
|| lara_item->current_anim_state != AS_STOP) {
return;
}
uint16_t quadrant = (uint16_t)(lara_item->pos.y_rot + PHD_45) / PHD_90;
switch (quadrant) {
case DIR_NORTH:
item->pos.y_rot = 0;
break;
case DIR_EAST:
item->pos.y_rot = PHD_90;
break;
case DIR_SOUTH:
item->pos.y_rot = -PHD_180;
break;
case DIR_WEST:
item->pos.y_rot = -PHD_90;
break;
}
if (!TestLaraPosition(MidasBounds, item, lara_item)) {
return;
}
if (InventoryChosen == -1) {
Display_Inventory(INV_KEYS_MODE);
}
if (InventoryChosen == O_LEADBAR_OPTION) {
Inv_RemoveItem(O_LEADBAR_OPTION);
Inv_AddItem(O_PUZZLE_ITEM1);
lara_item->current_anim_state = AS_USEMIDAS;
lara_item->goal_anim_state = AS_USEMIDAS;
lara_item->anim_number = Objects[O_LARA_EXTRA].anim_index;
lara_item->frame_number = Anims[item->anim_number].frame_base;
Lara.gun_status = LGS_HANDSBUSY;
}
}

View file

@ -0,0 +1,12 @@
#ifndef T1M_GAME_TRAPS_MIDAS_TOUCH_H
#define T1M_GAME_TRAPS_MIDAS_TOUCH_H
#include "game/types.h"
#include <stdint.h>
extern int16_t MidasBounds[12];
void SetupMidasTouch(OBJECT_INFO *obj);
void MidasCollision(int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll);
#endif

View file

@ -4,30 +4,19 @@
#include "game/effects.h"
#include "game/items.h"
#include "game/lara.h"
#include "game/moveblock.h"
#include "game/traps/movable_block.h"
#include "game/vars.h"
#include "util.h"
typedef enum {
MBS_STILL = 1,
MBS_PUSH = 2,
MBS_PULL = 3,
} MOVABLE_BLOCK_STATE;
static int16_t MovingBlockBounds[12] = {
-300,
+300,
0,
0,
-WALL_L / 2 - (LARA_RAD + 80),
-WALL_L / 2,
-10 * PHD_DEGREE,
+10 * PHD_DEGREE,
-30 * PHD_DEGREE,
+30 * PHD_DEGREE,
-10 * PHD_DEGREE,
+10 * PHD_DEGREE,
};
void SetupMovableBlock(OBJECT_INFO *obj)
{
obj->initialise = InitialiseMovableBlock;
obj->control = MovableBlockControl;
obj->draw_routine = DrawMovableBlock;
obj->collision = MovableBlockCollision;
obj->save_position = 1;
obj->save_anim = 1;
obj->save_flags = 1;
}
// original name: InitialiseMovingBlock
void InitialiseMovableBlock(int16_t item_num)
@ -178,6 +167,15 @@ void MovableBlockCollision(
}
}
void DrawMovableBlock(ITEM_INFO *item)
{
if (item->status == IS_ACTIVE) {
DrawUnclippedItem(item);
} else {
DrawAnimatingItem(item);
}
}
int32_t TestBlockMovable(ITEM_INFO *item, int32_t blockhite)
{
int16_t room_num = item->room_number;
@ -313,44 +311,6 @@ int32_t TestBlockPull(ITEM_INFO *item, int32_t blockhite, uint16_t quadrant)
return 1;
}
void InitialiseRollingBlock(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
AlterFloorHeight(item, -2048);
}
// original name: RollingBlock
void RollingBlockControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
if (TriggerActive(item)) {
if (item->current_anim_state == RBS_START) {
item->goal_anim_state = RBS_END;
AlterFloorHeight(item, 2048);
}
} else if (item->current_anim_state == RBS_END) {
item->goal_anim_state = RBS_START;
AlterFloorHeight(item, 2048);
}
AnimateItem(item);
int16_t room_num = item->room_number;
GetFloor(item->pos.x, item->pos.y, item->pos.z, &room_num);
if (item->room_number != room_num) {
ItemNewRoom(item_num, room_num);
}
if (item->status == IS_DEACTIVATED) {
item->status = IS_ACTIVE;
AlterFloorHeight(item, -2048);
item->pos.x &= -WALL_L;
item->pos.x += WALL_L / 2;
item->pos.z &= -WALL_L;
item->pos.z += WALL_L / 2;
}
}
void AlterFloorHeight(ITEM_INFO *item, int32_t height)
{
int16_t room_num = item->room_number;
@ -376,25 +336,3 @@ void AlterFloorHeight(ITEM_INFO *item, int32_t height)
}
}
}
void DrawMovableBlock(ITEM_INFO *item)
{
if (item->status == IS_ACTIVE) {
DrawUnclippedItem(item);
} else {
DrawAnimatingItem(item);
}
}
void T1MInjectGameMoveBlock()
{
INJECT(0x0042B430, InitialiseMovableBlock);
INJECT(0x0042B460, MovableBlockControl);
INJECT(0x0042B5B0, MovableBlockCollision);
INJECT(0x0042B7E0, TestBlockPush);
INJECT(0x0042B940, TestBlockPull);
INJECT(0x0042BB90, InitialiseRollingBlock);
INJECT(0x0042BBC0, RollingBlockControl);
INJECT(0x0042BCA0, AlterFloorHeight);
INJECT(0x0042BD60, DrawMovableBlock);
}

View file

@ -1,27 +1,28 @@
#ifndef T1M_GAME_MOVEBLOCK_H
#define T1M_GAME_MOVEBLOCK_H
#ifndef T1M_GAME_TRAPS_MOVABLE_BLOCK_H
#define T1M_GAME_TRAPS_MOVABLE_BLOCK_H
#include "game/types.h"
#include <stdint.h>
// clang-format off
// clang-format on
typedef enum {
MBS_STILL = 1,
MBS_PUSH = 2,
MBS_PULL = 3,
} MOVABLE_BLOCK_STATE;
extern int16_t MovingBlockBounds[12];
void SetupMovableBlock(OBJECT_INFO *obj);
void InitialiseMovableBlock(int16_t item_num);
void MovableBlockControl(int16_t item_num);
void MovableBlockCollision(
int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll);
void DrawMovableBlock(ITEM_INFO *item);
int32_t TestBlockMovable(ITEM_INFO *item, int32_t blockhite);
int32_t TestBlockPush(ITEM_INFO *item, int32_t blokhite, uint16_t quadrant);
int32_t TestBlockPull(ITEM_INFO *item, int32_t blokhite, uint16_t quadrant);
void InitialiseRollingBlock(int16_t item_num);
void RollingBlockControl(int16_t item_num);
void AlterFloorHeight(ITEM_INFO *item, int32_t height);
void DrawMovableBlock(ITEM_INFO *item);
void T1MInjectGameMoveBlock();
#endif

47
src/game/traps/pendulum.c Normal file
View file

@ -0,0 +1,47 @@
#include "game/collide.h"
#include "game/control.h"
#include "game/effects.h"
#include "game/game.h"
#include "game/traps/pendulum.h"
#include "game/vars.h"
void SetupPendulum(OBJECT_INFO *obj)
{
obj->control = PendulumControl;
obj->collision = TrapCollision;
obj->shadow_size = UNIT_SHADOW / 2;
obj->save_flags = 1;
obj->save_anim = 1;
}
// original name: Pendulum
void PendulumControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
if (TriggerActive(item)) {
if (item->current_anim_state == TRAP_SET) {
item->goal_anim_state = TRAP_WORKING;
}
} else {
if (item->current_anim_state == TRAP_WORKING) {
item->goal_anim_state = TRAP_SET;
}
}
if (item->current_anim_state == TRAP_WORKING && item->touch_bits) {
LaraItem->hit_points -= PENDULUM_DAMAGE;
LaraItem->hit_status = 1;
int32_t x = LaraItem->pos.x + (GetRandomControl() - 0x4000) / 256;
int32_t z = LaraItem->pos.z + (GetRandomControl() - 0x4000) / 256;
int32_t y = LaraItem->pos.y - GetRandomControl() / 44;
int32_t d = LaraItem->pos.y_rot + (GetRandomControl() - 0x4000) / 8;
DoBloodSplat(x, y, z, LaraItem->speed, d, LaraItem->room_number);
}
FLOOR_INFO *floor =
GetFloor(item->pos.x, item->pos.y, item->pos.z, &item->room_number);
item->floor = GetHeight(floor, item->pos.x, item->pos.y, item->pos.z);
AnimateItem(item);
}

12
src/game/traps/pendulum.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef T1M_GAME_TRAPS_PENDULUM_H
#define T1M_GAME_TRAPS_PENDULUM_H
#include "game/types.h"
#include <stdint.h>
#define PENDULUM_DAMAGE 100
void SetupPendulum(OBJECT_INFO *obj);
void PendulumControl(int16_t item_num);
#endif

View file

@ -0,0 +1,170 @@
#include "3dsystem/phd_math.h"
#include "game/collide.h"
#include "game/control.h"
#include "game/effects.h"
#include "game/game.h"
#include "game/items.h"
#include "game/sphere.h"
#include "game/traps/rolling_ball.h"
#include "game/vars.h"
#include "specific/init.h"
void SetupRollingBall(OBJECT_INFO *obj)
{
obj->initialise = InitialiseRollingBall;
obj->control = RollingBallControl;
obj->collision = RollingBallCollision;
obj->save_position = 1;
obj->save_anim = 1;
obj->save_flags = 1;
}
void InitialiseRollingBall(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
GAME_VECTOR *old = game_malloc(sizeof(GAME_VECTOR), GBUF_ROLLINGBALL_STUFF);
item->data = old;
old->x = item->pos.x;
old->y = item->pos.y;
old->z = item->pos.z;
old->room_number = item->room_number;
}
void RollingBallControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
if (item->status == IS_ACTIVE) {
if (item->pos.y < item->floor) {
if (!item->gravity_status) {
item->gravity_status = 1;
item->fall_speed = -10;
}
} else if (item->current_anim_state == TRAP_SET) {
item->goal_anim_state = TRAP_ACTIVATE;
}
int32_t oldx = item->pos.x;
int32_t oldz = item->pos.z;
AnimateItem(item);
int16_t room_num = item->room_number;
FLOOR_INFO *floor =
GetFloor(item->pos.x, item->pos.y, item->pos.z, &room_num);
if (item->room_number != room_num) {
ItemNewRoom(item_num, room_num);
}
item->floor = GetHeight(floor, item->pos.x, item->pos.y, item->pos.z);
TestTriggers(TriggerIndex, 1);
if (item->pos.y >= item->floor - STEP_L) {
item->gravity_status = 0;
item->fall_speed = 0;
item->pos.y = item->floor;
}
int32_t x = item->pos.x
+ (((WALL_L / 2) * phd_sin(item->pos.y_rot)) >> W2V_SHIFT);
int32_t z = item->pos.z
+ (((WALL_L / 2) * phd_cos(item->pos.y_rot)) >> W2V_SHIFT);
floor = GetFloor(x, item->pos.y, z, &room_num);
if (GetHeight(floor, x, item->pos.y, z) < item->pos.y) {
item->status = IS_DEACTIVATED;
item->pos.x = oldx;
item->pos.y = item->floor;
item->pos.z = oldz;
item->speed = 0;
item->fall_speed = 0;
item->touch_bits = 0;
}
} else if (item->status == IS_DEACTIVATED && !TriggerActive(item)) {
item->status = IS_NOT_ACTIVE;
GAME_VECTOR *old = item->data;
item->pos.x = old->x;
item->pos.y = old->y;
item->pos.z = old->z;
if (item->room_number != old->room_number) {
RemoveDrawnItem(item_num);
ROOM_INFO *r = &RoomInfo[old->room_number];
item->next_item = r->item_number;
r->item_number = item_num;
item->room_number = old->room_number;
}
item->current_anim_state = TRAP_SET;
item->goal_anim_state = TRAP_SET;
item->anim_number = Objects[item->object_number].anim_index;
item->frame_number = Anims[item->anim_number].frame_base;
item->current_anim_state = Anims[item->anim_number].current_anim_state;
item->goal_anim_state = item->current_anim_state;
item->required_anim_state = TRAP_SET;
RemoveActiveItem(item_num);
}
}
void RollingBallCollision(
int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll)
{
ITEM_INFO *item = &Items[item_num];
if (item->status != IS_ACTIVE) {
if (item->status != IS_INVISIBLE) {
ObjectCollision(item_num, lara_item, coll);
}
return;
}
if (!TestBoundsCollide(item, lara_item, coll->radius)) {
return;
}
if (!TestCollision(item, lara_item)) {
return;
}
int32_t x, y, z, d;
if (lara_item->gravity_status) {
if (coll->enable_baddie_push) {
ItemPushLara(item, lara_item, coll, coll->enable_spaz, 1);
}
lara_item->hit_points -= ROLLINGBALL_DAMAGE_AIR;
x = lara_item->pos.x - item->pos.x;
z = lara_item->pos.z - item->pos.z;
y = (lara_item->pos.y - 350) - (item->pos.y - WALL_L / 2);
d = phd_sqrt(SQUARE(x) + SQUARE(y) + SQUARE(z));
if (d < WALL_L / 2) {
d = WALL_L / 2;
}
x = item->pos.x + (x << WALL_SHIFT) / 2 / d;
z = item->pos.z + (z << WALL_SHIFT) / 2 / d;
y = item->pos.y - WALL_L / 2 + (y << WALL_SHIFT) / 2 / d;
DoBloodSplat(x, y, z, item->speed, item->pos.y_rot, item->room_number);
} else {
lara_item->hit_status = 1;
if (lara_item->hit_points > 0) {
lara_item->hit_points = -1;
if (lara_item->room_number != item->room_number) {
ItemNewRoom(Lara.item_number, item->room_number);
}
lara_item->pos.x_rot = 0;
lara_item->pos.z_rot = 0;
lara_item->pos.y_rot = item->pos.y_rot;
lara_item->current_anim_state = AS_SPECIAL;
lara_item->goal_anim_state = AS_SPECIAL;
lara_item->anim_number = AA_RBALL_DEATH;
lara_item->frame_number = AF_RBALL_DEATH;
Camera.flags = FOLLOW_CENTRE;
Camera.target_angle = 170 * PHD_DEGREE;
Camera.target_elevation = -25 * PHD_DEGREE;
for (int i = 0; i < 15; i++) {
x = lara_item->pos.x + (GetRandomControl() - 0x4000) / 256;
z = lara_item->pos.z + (GetRandomControl() - 0x4000) / 256;
y = lara_item->pos.y - GetRandomControl() / 64;
d = item->pos.y_rot + (GetRandomControl() - 0x4000) / 8;
DoBloodSplat(x, y, z, item->speed * 2, d, item->room_number);
}
}
}
}

View file

@ -0,0 +1,14 @@
#ifndef T1M_GAME_TRAPS_ROLLING_BALL_H
#define T1M_GAME_TRAPS_ROLLING_BALL_H
#include "game/types.h"
#define ROLLINGBALL_DAMAGE_AIR 100
void SetupRollingBall(OBJECT_INFO *obj);
void InitialiseRollingBall(int16_t item_num);
void RollingBallControl(int16_t item_num);
void RollingBallCollision(
int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll);
#endif

View file

@ -0,0 +1,67 @@
#include "game/control.h"
#include "game/items.h"
#include "game/traps/movable_block.h"
#include "game/traps/rolling_block.h"
#include "game/vars.h"
int16_t MovingBlockBounds[12] = {
-300,
+300,
0,
0,
-WALL_L / 2 - (LARA_RAD + 80),
-WALL_L / 2,
-10 * PHD_DEGREE,
+10 * PHD_DEGREE,
-30 * PHD_DEGREE,
+30 * PHD_DEGREE,
-10 * PHD_DEGREE,
+10 * PHD_DEGREE,
};
void SetupRollingBlock(OBJECT_INFO *obj)
{
obj->initialise = InitialiseRollingBlock;
obj->control = RollingBlockControl;
obj->save_position = 1;
obj->save_anim = 1;
obj->save_flags = 1;
}
void InitialiseRollingBlock(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
AlterFloorHeight(item, -2048);
}
// original name: RollingBlock
void RollingBlockControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
if (TriggerActive(item)) {
if (item->current_anim_state == RBS_START) {
item->goal_anim_state = RBS_END;
AlterFloorHeight(item, 2048);
}
} else if (item->current_anim_state == RBS_END) {
item->goal_anim_state = RBS_START;
AlterFloorHeight(item, 2048);
}
AnimateItem(item);
int16_t room_num = item->room_number;
GetFloor(item->pos.x, item->pos.y, item->pos.z, &room_num);
if (item->room_number != room_num) {
ItemNewRoom(item_num, room_num);
}
if (item->status == IS_DEACTIVATED) {
item->status = IS_ACTIVE;
AlterFloorHeight(item, -2048);
item->pos.x &= -WALL_L;
item->pos.x += WALL_L / 2;
item->pos.z &= -WALL_L;
item->pos.z += WALL_L / 2;
}
}

View file

@ -0,0 +1,11 @@
#ifndef T1M_GAME_TRAPS_ROLLING_BLOCK_H
#define T1M_GAME_TRAPS_ROLLING_BLOCK_H
#include "game/types.h"
#include <stdint.h>
void SetupRollingBlock(OBJECT_INFO *obj);
void InitialiseRollingBlock(int16_t item_num);
void RollingBlockControl(int16_t item_num);
#endif

54
src/game/traps/spikes.c Normal file
View file

@ -0,0 +1,54 @@
#include "game/collide.h"
#include "game/effects.h"
#include "game/game.h"
#include "game/sphere.h"
#include "game/traps/spikes.h"
#include "game/vars.h"
void SetupSpikes(OBJECT_INFO *obj)
{
obj->collision = SpikeCollision;
}
void SpikeCollision(int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll)
{
ITEM_INFO *item = &Items[item_num];
if (lara_item->hit_points < 0) {
return;
}
if (!TestBoundsCollide(item, lara_item, coll->radius)) {
return;
}
if (!TestCollision(item, lara_item)) {
return;
}
int32_t num = GetRandomControl() / 24576;
if (lara_item->gravity_status) {
if (lara_item->fall_speed > 0) {
lara_item->hit_points = -1;
num = 20;
}
} else if (lara_item->speed < 30) {
return;
}
lara_item->hit_points -= SPIKE_DAMAGE;
while (num > 0) {
int32_t x = lara_item->pos.x + (GetRandomControl() - 0x4000) / 256;
int32_t z = lara_item->pos.z + (GetRandomControl() - 0x4000) / 256;
int32_t y = lara_item->pos.y - GetRandomControl() / 64;
DoBloodSplat(x, y, z, 20, GetRandomControl(), item->room_number);
num--;
}
if (lara_item->hit_points <= 0) {
lara_item->current_anim_state = AS_DEATH;
lara_item->goal_anim_state = AS_DEATH;
lara_item->anim_number = AA_SPIKE_DEATH;
lara_item->frame_number = AF_SPIKE_DEATH;
lara_item->pos.y = item->pos.y;
lara_item->gravity_status = 0;
}
}

11
src/game/traps/spikes.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef T1M_GAME_TRAPS_SPIKES_H
#define T1M_GAME_TRAPS_SPIKES_H
#include "game/types.h"
#define SPIKE_DAMAGE 15
void SetupSpikes(OBJECT_INFO *obj);
void SpikeCollision(int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll);
#endif

View file

@ -0,0 +1,42 @@
#include "game/collide.h"
#include "game/control.h"
#include "game/sphere.h"
#include "game/traps/teeth_trap.h"
#include "game/vars.h"
BITE_INFO Teeth1A = { -23, 0, -1718, 0 };
BITE_INFO Teeth1B = { 71, 0, -1718, 1 };
BITE_INFO Teeth2A = { -23, 10, -1718, 0 };
BITE_INFO Teeth2B = { 71, 10, -1718, 1 };
BITE_INFO Teeth3A = { -23, -10, -1718, 0 };
BITE_INFO Teeth3B = { 71, -10, -1718, 1 };
void SetupTeethTrap(OBJECT_INFO *obj)
{
obj->control = TeethTrapControl;
obj->collision = TrapCollision;
obj->save_flags = 1;
obj->save_anim = 1;
}
// original name: TeethTrap
void TeethTrapControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
if (TriggerActive(item)) {
item->goal_anim_state = TT_NASTY;
if (item->touch_bits && item->current_anim_state == TT_NASTY) {
LaraItem->hit_points -= TEETH_TRAP_DAMAGE;
LaraItem->hit_status = 1;
BaddieBiteEffect(item, &Teeth1A);
BaddieBiteEffect(item, &Teeth1B);
BaddieBiteEffect(item, &Teeth2A);
BaddieBiteEffect(item, &Teeth2B);
BaddieBiteEffect(item, &Teeth3A);
BaddieBiteEffect(item, &Teeth3B);
}
} else {
item->goal_anim_state = TT_NICE;
}
AnimateItem(item);
}

View file

@ -0,0 +1,23 @@
#ifndef T1M_GAME_TRAPS_TEETH_TRAP_H
#define T1M_GAME_TRAPS_TEETH_TRAP_H
#include "game/types.h"
#define TEETH_TRAP_DAMAGE 400
typedef enum {
TT_NICE = 0,
TT_NASTY = 1,
} TEETH_TRAP_STATE;
extern BITE_INFO Teeth1A;
extern BITE_INFO Teeth1B;
extern BITE_INFO Teeth2A;
extern BITE_INFO Teeth2B;
extern BITE_INFO Teeth3A;
extern BITE_INFO Teeth3B;
void SetupTeethTrap(OBJECT_INFO *obj);
void TeethTrapControl(int16_t item_num);
#endif

View file

@ -0,0 +1,169 @@
#include "game/collide.h"
#include "game/control.h"
#include "game/draw.h"
#include "game/items.h"
#include "game/traps/movable_block.h"
#include "game/traps/thors_hammer.h"
#include "game/vars.h"
void SetupThorsHandle(OBJECT_INFO *obj)
{
obj->initialise = InitialiseThorsHandle;
obj->control = ThorsHandleControl;
obj->draw_routine = DrawUnclippedItem;
obj->collision = ThorsHandleCollision;
obj->save_flags = 1;
obj->save_anim = 1;
}
void SetupThorsHead(OBJECT_INFO *obj)
{
obj->collision = ThorsHeadCollision;
obj->draw_routine = DrawUnclippedItem;
obj->save_flags = 1;
obj->save_anim = 1;
}
void InitialiseThorsHandle(int16_t item_num)
{
ITEM_INFO *hand_item = &Items[item_num];
int16_t head_item_num = CreateItem();
ITEM_INFO *head_item = &Items[head_item_num];
head_item->object_number = O_THORS_HEAD;
head_item->room_number = hand_item->room_number;
head_item->pos = hand_item->pos;
head_item->shade = hand_item->shade;
InitialiseItem(head_item_num);
hand_item->data = head_item;
LevelItemCount++;
}
void ThorsHandleControl(int16_t item_num)
{
ITEM_INFO *item = &Items[item_num];
switch (item->current_anim_state) {
case THS_SET:
if (TriggerActive(item)) {
item->goal_anim_state = THS_TEASE;
} else {
RemoveActiveItem(item_num);
item->status = IS_NOT_ACTIVE;
}
break;
case THS_TEASE:
if (TriggerActive(item)) {
item->goal_anim_state = THS_ACTIVE;
} else {
item->goal_anim_state = THS_SET;
}
break;
case THS_ACTIVE: {
int32_t frm = item->frame_number - Anims[item->anim_number].frame_base;
if (frm > 30) {
int32_t x = item->pos.x;
int32_t z = item->pos.z;
switch (item->pos.y_rot) {
case 0:
z += WALL_L * 3;
break;
case PHD_90:
x += WALL_L * 3;
break;
case -PHD_90:
x -= WALL_L * 3;
break;
case -PHD_180:
z -= WALL_L * 3;
break;
}
if (LaraItem->hit_points >= 0 && LaraItem->pos.x > x - 520
&& LaraItem->pos.x < x + 520 && LaraItem->pos.z > z - 520
&& LaraItem->pos.z < z + 520) {
LaraItem->hit_points = -1;
LaraItem->pos.y = item->pos.y;
LaraItem->gravity_status = 0;
LaraItem->current_anim_state = AS_SPECIAL;
LaraItem->goal_anim_state = AS_SPECIAL;
LaraItem->anim_number = AA_RBALL_DEATH;
LaraItem->frame_number = AF_RBALL_DEATH;
}
}
break;
}
case THS_DONE: {
int32_t x = item->pos.x;
int32_t z = item->pos.z;
int32_t old_x = x;
int32_t old_z = z;
int16_t room_num = item->room_number;
FLOOR_INFO *floor = GetFloor(x, item->pos.y, z, &room_num);
GetHeight(floor, x, item->pos.y, z);
TestTriggers(TriggerIndex, 1);
switch (item->pos.y_rot) {
case 0:
z += WALL_L * 3;
break;
case PHD_90:
x += WALL_L * 3;
break;
case -PHD_90:
x -= WALL_L * 3;
break;
case -PHD_180:
z -= WALL_L * 3;
break;
}
item->pos.x = x;
item->pos.z = z;
if (LaraItem->hit_points >= 0) {
AlterFloorHeight(item, -2 * WALL_L);
}
item->pos.x = old_x;
item->pos.z = old_z;
RemoveActiveItem(item_num);
item->status = IS_DEACTIVATED;
break;
}
}
AnimateItem(item);
ITEM_INFO *head_item = item->data;
int32_t anim = item->anim_number - Objects[O_THORS_HANDLE].anim_index;
int32_t frm = item->frame_number - Anims[item->anim_number].frame_base;
head_item->anim_number = Objects[O_THORS_HEAD].anim_index + anim;
head_item->frame_number = Anims[head_item->anim_number].frame_base + frm;
head_item->current_anim_state = item->current_anim_state;
}
void ThorsHandleCollision(
int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll)
{
ITEM_INFO *item = &Items[item_num];
if (!TestBoundsCollide(item, lara_item, coll->radius)) {
return;
}
if (coll->enable_baddie_push) {
ItemPushLara(item, lara_item, coll, 0, 1);
}
}
void ThorsHeadCollision(int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll)
{
ITEM_INFO *item = &Items[item_num];
if (!TestBoundsCollide(item, lara_item, coll->radius)) {
return;
}
if (coll->enable_baddie_push && item->current_anim_state != THS_ACTIVE) {
ItemPushLara(item, lara_item, coll, 0, 1);
}
}

View file

@ -0,0 +1,22 @@
#ifndef T1M_GAME_TRAPS_THORS_HAMMER_H
#define T1M_GAME_TRAPS_THORS_HAMMER_H
#include "game/types.h"
typedef enum {
THS_SET = 0,
THS_TEASE = 1,
THS_ACTIVE = 2,
THS_DONE = 3,
} THOR_HAMMER_STATE;
void SetupThorsHandle(OBJECT_INFO *obj);
void SetupThorsHead(OBJECT_INFO *obj);
void InitialiseThorsHandle(int16_t item_num);
void ThorsHandleControl(int16_t item_num);
void ThorsHandleCollision(
int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll);
void ThorsHeadCollision(
int16_t item_num, ITEM_INFO *lara_item, COLL_INFO *coll);
#endif

View file

@ -15,9 +15,7 @@
#include "game/inv.h"
#include "game/items.h"
#include "game/lara.h"
#include "game/lightning.h"
#include "game/lot.h"
#include "game/moveblock.h"
#include "game/objects.h"
#include "game/option.h"
#include "game/pickup.h"
@ -25,7 +23,6 @@
#include "game/setup.h"
#include "game/sphere.h"
#include "game/text.h"
#include "game/traps.h"
#include "specific/display.h"
#include "specific/file.h"
#include "specific/frontend.h"
@ -60,8 +57,6 @@ void T1MInject()
T1MInjectGameLaraMisc();
T1MInjectGameLaraSurf();
T1MInjectGameLaraSwim();
T1MInjectGameLightning();
T1MInjectGameMoveBlock();
T1MInjectGameObjects();
T1MInjectGameOption();
T1MInjectGamePickup();
@ -69,7 +64,6 @@ void T1MInject()
T1MInjectGameSetup();
T1MInjectGameSphere();
T1MInjectGameText();
T1MInjectGameTraps();
T1MInjectSpecificDisplay();
T1MInjectSpecificFile();
T1MInjectSpecificFrontend();