2020-05-27 09:21:20 +02:00
|
|
|
#include "framework.h"
|
2021-12-24 03:32:19 +03:00
|
|
|
#include "Objects/TR3/Vehicles/minecart.h"
|
2021-12-24 11:08:16 +03:00
|
|
|
|
|
|
|
#include "Game/animation.h"
|
|
|
|
#include "Game/camera.h"
|
|
|
|
#include "Game/collision/sphere.h"
|
2021-12-22 16:23:57 +03:00
|
|
|
#include "Game/collision/collide_item.h"
|
|
|
|
#include "Game/effects/effects.h"
|
|
|
|
#include "Game/items.h"
|
2021-12-24 11:08:16 +03:00
|
|
|
#include "Game/Lara/lara.h"
|
|
|
|
#include "Game/Lara/lara_flare.h"
|
|
|
|
#include "Objects/TR3/Vehicles/minecart_info.h"
|
|
|
|
#include "Sound/sound.h"
|
|
|
|
#include "Specific/input.h"
|
2021-12-22 16:23:57 +03:00
|
|
|
#include "Specific/level.h"
|
|
|
|
#include "Specific/setup.h"
|
2021-09-25 11:27:47 +02:00
|
|
|
|
2020-06-20 23:39:08 +02:00
|
|
|
using std::vector;
|
2021-08-26 15:54:52 +03:00
|
|
|
|
2022-01-09 13:44:37 +11:00
|
|
|
enum MinecartState
|
|
|
|
{
|
2019-11-30 13:51:37 +01:00
|
|
|
CART_GETIN,
|
|
|
|
CART_GETOUT,
|
|
|
|
CART_GETOUTL,
|
|
|
|
CART_GETOUTR,
|
|
|
|
CART_STILL,
|
|
|
|
CART_DUCK,
|
|
|
|
CART_MOVE,
|
|
|
|
CART_RIGHT,
|
|
|
|
CART_HARDLEFT,
|
|
|
|
CART_LEFT,
|
|
|
|
CART_HARDRIGHT,
|
|
|
|
CART_BRAKE,
|
|
|
|
CART_FWD,
|
|
|
|
CART_BACK,
|
|
|
|
CART_TURNDEATH,
|
|
|
|
CART_FALLDEATH,
|
|
|
|
CART_WALLDEATH,
|
|
|
|
CART_HIT,
|
|
|
|
CART_USE,
|
|
|
|
CART_BRAKING
|
|
|
|
};
|
|
|
|
|
2022-02-20 00:43:58 +11:00
|
|
|
enum MinecartFlags
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2022-02-20 00:43:58 +11:00
|
|
|
CART_FLAG_MESH = 1,
|
|
|
|
CART_FLAG_TURNINGL = 2,
|
|
|
|
CART_FLAG_TURNINGR = 4,
|
|
|
|
CART_FLAG_RDIR = 8,
|
|
|
|
CART_FLAG_CONTROL = 16,
|
|
|
|
CART_FLAG_STOPPED = 32,
|
|
|
|
CART_FLAG_NOANIM = 64,
|
|
|
|
CART_FLAG_DEAD = 128
|
2019-11-30 13:51:37 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
#define GETOFF_DIST 330
|
|
|
|
#define CART_DEC -1536
|
|
|
|
#define CART_MIN_SPEED 2560
|
|
|
|
#define CART_MIN_VEL 32
|
|
|
|
#define TURN_DEATH_VEL 128
|
|
|
|
#define CART_FWD_GRAD -128
|
|
|
|
#define CART_BACK_GRAD 128
|
|
|
|
#define CART_JUMP_VEL 64512
|
|
|
|
#define CART_GRAVITY (WALL_SIZE + 1)
|
|
|
|
#define MAX_CART_YVEL 16128
|
|
|
|
#define TERMINAL_ANGLE (WALL_SIZE * 4)
|
|
|
|
#define CART_RADIUS 100
|
|
|
|
#define CART_HEIGHT (STEP_SIZE * 3)
|
|
|
|
#define CART_NHITS 25
|
|
|
|
#define CART_BADDIE_RADIUS STEP_SIZE
|
|
|
|
|
2020-05-27 09:21:20 +02:00
|
|
|
static int TestMinecartHeight(ITEM_INFO* v, int x, int z)
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
|
|
|
PHD_VECTOR pos;
|
|
|
|
FLOOR_INFO* floor;
|
2020-10-05 22:24:57 -03:00
|
|
|
float s, c;
|
2020-04-09 14:19:18 +02:00
|
|
|
short roomNumber;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
c = phd_cos(v->Position.yRot);
|
|
|
|
s = phd_sin(v->Position.yRot);
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
pos.x = v->Position.xPos + z * s + x * c;
|
|
|
|
pos.y = v->Position.yPos - z * phd_sin(v->Position.xRot) + x * phd_sin(v->Position.zRot);
|
|
|
|
pos.z = v->Position.zPos + z * c - x * s;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
roomNumber = v->RoomNumber;
|
2020-04-09 14:19:18 +02:00
|
|
|
floor = GetFloor(pos.x, pos.y, pos.z, &roomNumber);
|
2019-11-30 13:51:37 +01:00
|
|
|
return GetFloorHeight(floor, pos.x, pos.y, pos.z);
|
|
|
|
}
|
|
|
|
|
|
|
|
static short GetCollision(ITEM_INFO* v, short ang, int dist, short* ceiling)
|
|
|
|
{
|
|
|
|
FLOOR_INFO* floor;
|
|
|
|
int x, y, z, height, cheight;
|
2020-04-09 14:19:18 +02:00
|
|
|
short roomNumber;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
x = v->Position.xPos + phd_sin(ang) * dist;
|
|
|
|
y = v->Position.yPos - LARA_HEIGHT;
|
|
|
|
z = v->Position.zPos + phd_cos(ang) * dist;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
roomNumber = v->RoomNumber;
|
2020-04-09 14:19:18 +02:00
|
|
|
floor = GetFloor(x, y, z, &roomNumber);
|
2019-11-30 13:51:37 +01:00
|
|
|
height = GetFloorHeight(floor, x, y, z);
|
|
|
|
cheight = GetCeiling(floor, x, y, z);
|
|
|
|
|
|
|
|
*ceiling = ((short)cheight);
|
|
|
|
|
|
|
|
if (height != NO_HEIGHT)
|
2022-02-09 16:55:46 +11:00
|
|
|
height -= v->Position.yPos;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
|
|
|
return short(height);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool GetInMineCart(ITEM_INFO* v, ITEM_INFO* l, COLL_INFO* coll)
|
|
|
|
{
|
|
|
|
int dist;
|
|
|
|
int x, z;
|
|
|
|
FLOOR_INFO* floor;
|
2020-04-09 14:19:18 +02:00
|
|
|
short roomNumber;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-11 01:31:54 +11:00
|
|
|
if (!(TrInput & IN_ACTION) || Lara.Control.HandStatus != HandStatus::Free || l->Airborne)
|
2019-11-30 13:51:37 +01:00
|
|
|
return 0;
|
|
|
|
|
2021-09-10 00:20:59 +03:00
|
|
|
if (!TestBoundsCollide(v, l, coll->Setup.Radius))
|
2019-11-30 13:51:37 +01:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!TestCollision(v, l))
|
|
|
|
return false;
|
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
x = l->Position.xPos - v->Position.xPos;
|
|
|
|
z = l->Position.zPos - v->Position.zPos;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
|
|
|
dist = SQUARE(x) + SQUARE(z);
|
|
|
|
|
|
|
|
if (dist > SQUARE(WALL_SIZE/2))
|
|
|
|
return false;
|
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
roomNumber = v->RoomNumber;
|
|
|
|
floor = GetFloor(v->Position.xPos, v->Position.yPos, v->Position.zPos, &roomNumber);
|
|
|
|
if (GetFloorHeight(floor, v->Position.xPos, v->Position.yPos, v->Position.zPos) < -32000)
|
2019-11-30 13:51:37 +01:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool CanGetOut(int direction)
|
|
|
|
{
|
2021-08-24 16:54:26 +03:00
|
|
|
auto v = &g_Level.Items[Lara.Vehicle];
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2021-08-24 16:54:26 +03:00
|
|
|
short angle;
|
2019-11-30 13:51:37 +01:00
|
|
|
if (direction < 0)
|
2022-02-09 16:55:46 +11:00
|
|
|
angle = v->Position.yRot + 0x4000;
|
2019-11-30 13:51:37 +01:00
|
|
|
else
|
2022-02-09 16:55:46 +11:00
|
|
|
angle = v->Position.yRot - 0x4000;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
int x = v->Position.xPos - GETOFF_DIST * phd_sin(angle);
|
|
|
|
int y = v->Position.yPos;
|
|
|
|
int z = v->Position.zPos - GETOFF_DIST * phd_cos(angle);
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
auto collResult = GetCollisionResult(x, y, z, v->RoomNumber);
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-01-18 16:52:52 +11:00
|
|
|
if (collResult.Position.FloorSlope || collResult.Position.Floor == NO_HEIGHT)
|
2019-11-30 13:51:37 +01:00
|
|
|
return false;
|
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
if (abs(collResult.Position.Floor - v->Position.yPos) > WALL_SIZE / 2)
|
2019-11-30 13:51:37 +01:00
|
|
|
return false;
|
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
if ((collResult.Position.Ceiling - v->Position.yPos > -LARA_HEIGHT) || (collResult.Position.Floor - collResult.Position.Ceiling < LARA_HEIGHT))
|
2019-11-30 13:51:37 +01:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void CartToBaddieCollision(ITEM_INFO* v)
|
|
|
|
{
|
|
|
|
vector<short> roomsList;
|
|
|
|
short* door, numDoors;
|
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
roomsList.push_back(v->RoomNumber);
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
ROOM_INFO* room = &g_Level.Rooms[v->RoomNumber];
|
2020-06-26 07:06:18 +02:00
|
|
|
for (int i = 0; i < room->doors.size(); i++)
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2020-06-26 07:06:18 +02:00
|
|
|
roomsList.push_back(room->doors[i].room);
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < roomsList.size(); i++)
|
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
short itemNum = g_Level.Rooms[roomsList[i]].itemNumber;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
|
|
|
while (itemNum != NO_ITEM)
|
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
ITEM_INFO* item = &g_Level.Items[itemNum];
|
2022-02-09 16:55:46 +11:00
|
|
|
if (item->Collidable && item->Status != ITEM_INVISIBLE && item != LaraItem && item != v)
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
OBJECT_INFO* object = &Objects[item->ObjectNumber];
|
|
|
|
if (object->collision && (object->intelligent || item->ObjectNumber == ID_ROLLINGBALL || item->ObjectNumber == ID_ANIMATING2))
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
int x = v->Position.xPos - item->Position.xPos;
|
|
|
|
int y = v->Position.yPos - item->Position.yPos;
|
|
|
|
int z = v->Position.zPos - item->Position.zPos;
|
2019-11-30 13:51:37 +01:00
|
|
|
if (x > -2048 && x < 2048 && z > -2048 && z < 2048 && y > -2048 && y < 2048)
|
|
|
|
{
|
|
|
|
if (TestBoundsCollide(item, LaraItem, CART_BADDIE_RADIUS))
|
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
if (item->ObjectNumber == ID_ANIMATING2)
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
if ((item->FrameNumber == g_Level.Anims[item->AnimNumber].frameBase) && (LaraItem->ActiveState == CART_USE) && (LaraItem->AnimNumber == Objects[ID_MINECART_LARA_ANIMS].animIndex + 6))
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
|
|
|
FLOOR_INFO* floor;
|
2020-04-09 14:19:18 +02:00
|
|
|
short frame, roomNumber;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
frame = LaraItem->FrameNumber - g_Level.Anims[LaraItem->AnimNumber].frameBase;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
|
|
|
if ((frame >= 12) && (frame <= 22))
|
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
SoundEffect(220, &item->Position, 2);
|
2021-09-15 16:58:53 +03:00
|
|
|
TestTriggers(item, true);
|
2022-02-09 16:55:46 +11:00
|
|
|
item->FrameNumber++;
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-02-09 16:55:46 +11:00
|
|
|
else if (item->ObjectNumber == ID_ROLLINGBALL)
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2021-03-24 12:49:36 -05:00
|
|
|
/*code, kill lara and stop both the boulder and the minecart*/
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
DoLotsOfBlood(item->Position.xPos, v->Position.yPos - STEP_SIZE, item->Position.zPos, GetRandomControl() & 3, v->Position.yRot, item->RoomNumber, 3);
|
|
|
|
item->HitPoints = 0;
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-02-09 16:55:46 +11:00
|
|
|
itemNum = item->NextItem;
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-20 00:43:58 +11:00
|
|
|
static void MoveCart(ITEM_INFO* v, ITEM_INFO* l, MinecartInfo* cart)
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
|
|
|
short val;
|
|
|
|
if (cart->StopDelay)
|
|
|
|
cart->StopDelay--;
|
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
if (((Lara.mineL) && (Lara.mineR) && (!cart->StopDelay)) && (((v->Position.xPos & 0x380) == 512) || ((v->Position.zRot & 0x380) == 512)))
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2021-03-24 12:49:36 -05:00
|
|
|
if (cart->Speed < 0xf000)
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2022-02-20 00:43:58 +11:00
|
|
|
cart->Flags |= CART_FLAG_STOPPED | CART_FLAG_CONTROL;
|
2022-02-09 13:20:57 +11:00
|
|
|
cart->Speed = v->Velocity = 0;
|
2019-11-30 13:51:37 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
cart->StopDelay = 16;
|
|
|
|
}
|
|
|
|
|
2022-02-20 00:43:58 +11:00
|
|
|
if ((Lara.mineL || Lara.mineR) && (!(Lara.mineL && Lara.mineR)) && (!cart->StopDelay) && (!(cart->Flags & (CART_FLAG_TURNINGL | CART_FLAG_TURNINGR))))
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
|
|
|
short ang;
|
2022-02-09 16:55:46 +11:00
|
|
|
unsigned short rot = (((unsigned short)v->Position.yRot) / 16384) | (Lara.mineL * 4);
|
2019-11-30 13:51:37 +01:00
|
|
|
|
|
|
|
switch (rot)
|
|
|
|
{
|
|
|
|
case 0:
|
2022-02-09 16:55:46 +11:00
|
|
|
cart->TurnX = (v->Position.xPos + 4096) & ~1023;
|
|
|
|
cart->TurnZ = v->Position.zPos & ~1023;
|
2019-11-30 13:51:37 +01:00
|
|
|
break;
|
|
|
|
case 1:
|
2022-02-09 16:55:46 +11:00
|
|
|
cart->TurnX = v->Position.xPos & ~1023;
|
|
|
|
cart->TurnZ = (v->Position.zPos - 4096) | 1023;
|
2019-11-30 13:51:37 +01:00
|
|
|
break;
|
|
|
|
case 2:
|
2022-02-09 16:55:46 +11:00
|
|
|
cart->TurnX = (v->Position.xPos - 4096) | 1023;
|
|
|
|
cart->TurnZ = v->Position.zPos | 1023;
|
2019-11-30 13:51:37 +01:00
|
|
|
break;
|
|
|
|
case 3:
|
2022-02-09 16:55:46 +11:00
|
|
|
cart->TurnX = v->Position.xPos | 1023;
|
|
|
|
cart->TurnZ = (v->Position.zPos + 4096) & ~1023;
|
2019-11-30 13:51:37 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 4:
|
2022-02-09 16:55:46 +11:00
|
|
|
cart->TurnX = (v->Position.xPos - 4096) | 1023;
|
|
|
|
cart->TurnZ = v->Position.zPos & ~1023;
|
2019-11-30 13:51:37 +01:00
|
|
|
break;
|
|
|
|
case 5:
|
2022-02-09 16:55:46 +11:00
|
|
|
cart->TurnX = v->Position.xPos & ~1023;
|
|
|
|
cart->TurnZ = (v->Position.zPos + 4096) & ~1023;
|
2019-11-30 13:51:37 +01:00
|
|
|
break;
|
|
|
|
case 6:
|
2022-02-09 16:55:46 +11:00
|
|
|
cart->TurnX = (v->Position.xPos + 4096) & ~1023;
|
|
|
|
cart->TurnZ = v->Position.zPos | 1023;
|
2019-11-30 13:51:37 +01:00
|
|
|
break;
|
|
|
|
case 7:
|
2022-02-09 16:55:46 +11:00
|
|
|
cart->TurnX = v->Position.xPos | 1023;
|
|
|
|
cart->TurnZ = (v->Position.zPos - 4096) | 1023;
|
2019-11-30 13:51:37 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
ang = mGetAngle(v->Position.xPos, v->Position.zPos, cart->TurnX, cart->TurnZ) & 0x3fff;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
|
|
|
if (rot < 4)
|
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
cart->TurnRot = v->Position.yRot;
|
2019-11-30 13:51:37 +01:00
|
|
|
cart->TurnLen = ang;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
cart->TurnRot = v->Position.yRot;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
|
|
|
if (ang)
|
|
|
|
ang = 16384 - ang;
|
|
|
|
|
|
|
|
cart->TurnLen = ang;
|
|
|
|
}
|
|
|
|
|
2022-02-20 00:43:58 +11:00
|
|
|
cart->Flags |= (Lara.mineL) ? CART_FLAG_TURNINGL : CART_FLAG_TURNINGR;
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (cart->Speed < CART_MIN_SPEED)
|
|
|
|
cart->Speed = CART_MIN_SPEED;
|
|
|
|
|
2020-10-06 10:36:30 -05:00
|
|
|
cart->Speed += (-cart->Gradient * 4);
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-09 13:20:57 +11:00
|
|
|
if ((v->Velocity = cart->Speed / 256) < CART_MIN_VEL)
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2022-02-09 13:20:57 +11:00
|
|
|
v->Velocity = CART_MIN_VEL;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
|
|
|
StopSoundEffect(209);
|
|
|
|
|
|
|
|
if (cart->YVel)
|
|
|
|
StopSoundEffect(210);
|
|
|
|
else
|
2022-02-09 16:55:46 +11:00
|
|
|
SoundEffect(210, &v->Position, 2);
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
StopSoundEffect(210);
|
|
|
|
|
|
|
|
if (cart->YVel)
|
|
|
|
StopSoundEffect(209);
|
|
|
|
else
|
2022-02-09 16:55:46 +11:00
|
|
|
SoundEffect(209, &v->Position, (2 | 4) + 0x1000000 + (v->Velocity * 32768));
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
|
2022-02-20 00:43:58 +11:00
|
|
|
if (cart->Flags & (CART_FLAG_TURNINGL | CART_FLAG_TURNINGR))
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2020-10-05 22:24:57 -03:00
|
|
|
float x, z;
|
2019-11-30 13:51:37 +01:00
|
|
|
unsigned short quad, deg;
|
|
|
|
|
2022-02-09 13:20:57 +11:00
|
|
|
if ((cart->TurnLen += (v->Velocity * 3)) > ANGLE(90))
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2022-02-20 00:43:58 +11:00
|
|
|
if (cart->Flags & CART_FLAG_TURNINGL)
|
2022-02-09 16:55:46 +11:00
|
|
|
v->Position.yRot = cart->TurnRot - 16384;
|
2019-11-30 13:51:37 +01:00
|
|
|
else
|
2022-02-09 16:55:46 +11:00
|
|
|
v->Position.yRot = cart->TurnRot + 16384;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-20 00:43:58 +11:00
|
|
|
cart->Flags &= ~(CART_FLAG_TURNINGL | CART_FLAG_TURNINGR);
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-02-20 00:43:58 +11:00
|
|
|
if (cart->Flags & CART_FLAG_TURNINGL)
|
2022-02-09 16:55:46 +11:00
|
|
|
v->Position.yRot = cart->TurnRot - cart->TurnLen;
|
2019-11-30 13:51:37 +01:00
|
|
|
else
|
2022-02-09 16:55:46 +11:00
|
|
|
v->Position.yRot = cart->TurnRot + cart->TurnLen;
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
|
2022-02-20 00:43:58 +11:00
|
|
|
if (cart->Flags & (CART_FLAG_TURNINGL | CART_FLAG_TURNINGR))
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
quad = ((unsigned short)v->Position.yRot) / 16384;
|
|
|
|
deg = v->Position.yRot & 16383;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
|
|
|
switch (quad)
|
|
|
|
{
|
|
|
|
case 0:
|
2020-04-25 16:23:53 +02:00
|
|
|
x = -phd_cos(deg);
|
|
|
|
z = phd_sin(deg);
|
2019-11-30 13:51:37 +01:00
|
|
|
break;
|
|
|
|
case 1:
|
2020-04-25 16:23:53 +02:00
|
|
|
x = phd_sin(deg);
|
|
|
|
z = phd_cos(deg);
|
2019-11-30 13:51:37 +01:00
|
|
|
break;
|
|
|
|
case 2:
|
2020-04-25 16:23:53 +02:00
|
|
|
x = phd_cos(deg);
|
|
|
|
z = -phd_sin(deg);
|
2019-11-30 13:51:37 +01:00
|
|
|
break;
|
|
|
|
default:
|
2020-04-25 16:23:53 +02:00
|
|
|
x = -phd_sin(deg);
|
|
|
|
z = -phd_cos(deg);
|
2019-11-30 13:51:37 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-02-20 00:43:58 +11:00
|
|
|
if (cart->Flags & CART_FLAG_TURNINGL)
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
|
|
|
x = -x;
|
|
|
|
z = -z;
|
|
|
|
}
|
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
v->Position.xPos = cart->TurnX + x * 3584;
|
|
|
|
v->Position.zPos = cart->TurnZ + z * 3584;
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
v->Position.xPos += v->Velocity * phd_sin(v->Position.yRot);
|
|
|
|
v->Position.zPos += v->Velocity * phd_cos(v->Position.yRot);
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
|
2020-05-27 09:21:20 +02:00
|
|
|
cart->MidPos = TestMinecartHeight(v, 0, 0);
|
2019-11-30 13:51:37 +01:00
|
|
|
|
|
|
|
if (!cart->YVel)
|
|
|
|
{
|
2020-05-27 09:21:20 +02:00
|
|
|
cart->FrontPos = TestMinecartHeight(v, 0, 256);
|
2019-11-30 13:51:37 +01:00
|
|
|
cart->Gradient = cart->MidPos - cart->FrontPos;
|
2022-02-09 16:55:46 +11:00
|
|
|
v->Position.yPos = cart->MidPos;
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
if (v->Position.yPos > cart->MidPos)
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
|
|
|
if (cart->YVel > 0)
|
2022-02-09 16:55:46 +11:00
|
|
|
SoundEffect(202, &v->Position, 2);
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
v->Position.yPos = cart->MidPos;
|
2019-11-30 13:51:37 +01:00
|
|
|
cart->YVel = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cart->YVel += CART_GRAVITY;
|
|
|
|
|
|
|
|
if (cart->YVel > MAX_CART_YVEL)
|
|
|
|
cart->YVel = MAX_CART_YVEL;
|
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
v->Position.yPos += (cart->YVel / 256);
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
v->Position.xRot = cart->Gradient * 32;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
val = v->Position.yRot & 16383;
|
2022-02-20 00:43:58 +11:00
|
|
|
if (cart->Flags & (CART_FLAG_TURNINGL | CART_FLAG_TURNINGR))
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2022-02-20 00:43:58 +11:00
|
|
|
if (cart->Flags & CART_FLAG_TURNINGR)
|
2022-02-09 16:55:46 +11:00
|
|
|
v->Position.zRot = -(val * v->Velocity) / 512;
|
2019-11-30 13:51:37 +01:00
|
|
|
else
|
2022-02-09 16:55:46 +11:00
|
|
|
v->Position.zRot = ((0x4000 - val) * v->Velocity) / 512;
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
v->Position.zRot -= (v->Position.zRot / 8);
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-20 00:43:58 +11:00
|
|
|
static void DoUserInput(ITEM_INFO* v, ITEM_INFO* l, MinecartInfo* cart)
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
|
|
|
short fh, ch;
|
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
switch (l->ActiveState)
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
|
|
|
case CART_MOVE:
|
|
|
|
if (TrInput & IN_ACTION)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_USE;
|
2022-02-02 18:32:52 +11:00
|
|
|
else if (TrInput & IN_CROUCH)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_DUCK;
|
2019-11-30 13:51:37 +01:00
|
|
|
else if (TrInput & IN_JUMP)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_BRAKE;
|
2022-02-20 00:43:58 +11:00
|
|
|
else if ((cart->Speed == CART_MIN_VEL) || (cart->Flags & CART_FLAG_STOPPED))
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_STILL;
|
2019-11-30 13:51:37 +01:00
|
|
|
else if (cart->Gradient < CART_FWD_GRAD)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_FWD;
|
2019-11-30 13:51:37 +01:00
|
|
|
else if (cart->Gradient > CART_BACK_GRAD)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_BACK;
|
2019-11-30 13:51:37 +01:00
|
|
|
else if (TrInput & IN_LEFT)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_LEFT;
|
2019-11-30 13:51:37 +01:00
|
|
|
else if (TrInput & IN_RIGHT)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_RIGHT;
|
2019-11-30 13:51:37 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CART_FWD:
|
|
|
|
if (TrInput & IN_ACTION)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_USE;
|
2022-02-02 18:32:52 +11:00
|
|
|
else if (TrInput & IN_CROUCH)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_DUCK;
|
2019-11-30 13:51:37 +01:00
|
|
|
else if (TrInput & IN_JUMP)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_BRAKE;
|
2019-11-30 13:51:37 +01:00
|
|
|
else if (cart->Gradient > CART_FWD_GRAD)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_MOVE;
|
2019-11-30 13:51:37 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CART_BACK:
|
|
|
|
if (TrInput & IN_ACTION)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_USE;
|
2022-02-02 18:32:52 +11:00
|
|
|
else if (TrInput & IN_CROUCH)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_DUCK;
|
2019-11-30 13:51:37 +01:00
|
|
|
else if (TrInput & IN_JUMP)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_BRAKE;
|
2019-11-30 13:51:37 +01:00
|
|
|
else if (cart->Gradient < CART_BACK_GRAD)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_MOVE;
|
2019-11-30 13:51:37 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CART_LEFT:
|
|
|
|
if (TrInput & IN_ACTION)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_USE;
|
2022-02-02 18:32:52 +11:00
|
|
|
else if (TrInput & IN_CROUCH)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_DUCK;
|
2019-11-30 13:51:37 +01:00
|
|
|
else if (TrInput & IN_JUMP)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_BRAKE;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
|
|
|
if (!(TrInput & IN_LEFT))
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_MOVE;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CART_RIGHT:
|
|
|
|
if (TrInput & IN_ACTION)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_USE;
|
2022-02-02 18:32:52 +11:00
|
|
|
else if (TrInput & IN_CROUCH)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_DUCK;
|
2019-11-30 13:51:37 +01:00
|
|
|
else if (TrInput & IN_JUMP)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_BRAKE;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
|
|
|
if (!(TrInput & IN_RIGHT))
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_MOVE;
|
2019-11-30 13:51:37 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CART_STILL:
|
2022-02-20 00:43:58 +11:00
|
|
|
if (!(cart->Flags & CART_FLAG_CONTROL))
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
SoundEffect(211, &v->Position, 2);
|
2022-02-20 00:43:58 +11:00
|
|
|
cart->Flags |= CART_FLAG_CONTROL;
|
2019-11-30 13:51:37 +01:00
|
|
|
cart->StopDelay = 64;
|
|
|
|
}
|
|
|
|
|
2022-02-20 00:43:58 +11:00
|
|
|
if (TrInput & IN_ROLL && (cart->Flags & CART_FLAG_STOPPED))
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
|
|
|
if ((TrInput & IN_LEFT) && (CanGetOut(-1)))
|
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_GETOUT;
|
2022-02-20 00:43:58 +11:00
|
|
|
cart->Flags &= ~CART_FLAG_RDIR;
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
else if ((TrInput & IN_RIGHT) && (CanGetOut(1)))
|
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_GETOUT;
|
2022-02-20 00:43:58 +11:00
|
|
|
cart->Flags |= CART_FLAG_RDIR;
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-02 18:32:52 +11:00
|
|
|
if (TrInput & IN_CROUCH)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_DUCK;
|
2019-11-30 13:51:37 +01:00
|
|
|
else if (cart->Speed > CART_MIN_VEL)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_MOVE;
|
2019-11-30 13:51:37 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CART_DUCK:
|
|
|
|
if (TrInput & IN_ACTION)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_USE;
|
2019-11-30 13:51:37 +01:00
|
|
|
else if (TrInput & IN_JUMP)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_BRAKE;
|
2022-02-02 18:32:52 +11:00
|
|
|
else if (!(TrInput & IN_CROUCH))
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_STILL;
|
2019-11-30 13:51:37 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CART_USE:
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_MOVE;
|
2019-11-30 13:51:37 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CART_BRAKING:
|
2022-02-02 18:32:52 +11:00
|
|
|
if (TrInput & IN_CROUCH)
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_DUCK;
|
2019-11-30 13:51:37 +01:00
|
|
|
StopSoundEffect(219);
|
|
|
|
}
|
2022-02-20 00:43:58 +11:00
|
|
|
else if ((!(TrInput & IN_JUMP)) || (cart->Flags & CART_FLAG_STOPPED))
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_MOVE;
|
2019-11-30 13:51:37 +01:00
|
|
|
StopSoundEffect(219);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cart->Speed += CART_DEC;
|
2022-02-09 16:55:46 +11:00
|
|
|
SoundEffect(219, &l->Position, 2);
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CART_BRAKE:
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_BRAKING;
|
2019-11-30 13:51:37 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CART_GETOUT:
|
2022-02-09 16:55:46 +11:00
|
|
|
if (l->AnimNumber == Objects[ID_MINECART_LARA_ANIMS].animIndex + 7)
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2022-02-20 00:43:58 +11:00
|
|
|
if ((l->FrameNumber == GetFrameNumber(v, 20)) && (cart->Flags & CART_FLAG_MESH))
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2020-07-03 07:05:33 +02:00
|
|
|
Lara.meshPtrs[LM_RHAND] = Objects[ID_MINECART_LARA_ANIMS].meshIndex + LM_RHAND;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-20 00:43:58 +11:00
|
|
|
cart->Flags &= ~CART_FLAG_MESH;
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
|
2022-02-20 00:43:58 +11:00
|
|
|
if (cart->Flags & CART_FLAG_RDIR)
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_GETOUTR;
|
2019-11-30 13:51:37 +01:00
|
|
|
else
|
2022-02-09 16:55:46 +11:00
|
|
|
l->TargetState = CART_GETOUTL;
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CART_GETOUTL:
|
2022-02-09 16:55:46 +11:00
|
|
|
if ((l->AnimNumber == Objects[ID_MINECART_LARA_ANIMS].animIndex + 1) && (l->FrameNumber == g_Level.Anims[l->AnimNumber].frameEnd))
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
|
|
|
PHD_VECTOR vec = { 0, 640, 0 };
|
|
|
|
|
2019-12-15 16:19:01 +01:00
|
|
|
GetLaraJointPosition(&vec, LM_HIPS);
|
2022-02-09 16:55:46 +11:00
|
|
|
l->Position.xPos = vec.x;
|
|
|
|
l->Position.yPos = vec.y;
|
|
|
|
l->Position.zPos = vec.z;
|
|
|
|
l->Position.xRot = 0;
|
|
|
|
l->Position.yRot = v->Position.yRot + 0x4000;
|
|
|
|
l->Position.zRot = 0;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2021-11-10 02:41:59 +03:00
|
|
|
SetAnimation(l, LA_STAND_SOLID);
|
2020-04-27 14:01:00 +02:00
|
|
|
Lara.Vehicle = NO_ITEM;
|
2022-02-11 01:31:54 +11:00
|
|
|
Lara.Control.HandStatus = HandStatus::Free;
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CART_GETOUTR:
|
2022-02-09 16:55:46 +11:00
|
|
|
if ((l->AnimNumber == Objects[ID_MINECART_LARA_ANIMS].animIndex + 47) && (l->FrameNumber == g_Level.Anims[l->AnimNumber].frameEnd))
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
|
|
|
PHD_VECTOR vec = { 0, 640, 0 };
|
|
|
|
|
2019-12-15 16:19:01 +01:00
|
|
|
GetLaraJointPosition(&vec, LM_HIPS);
|
2022-02-09 16:55:46 +11:00
|
|
|
l->Position.xPos = vec.x;
|
|
|
|
l->Position.yPos = vec.y;
|
|
|
|
l->Position.zPos = vec.z;
|
|
|
|
l->Position.xRot = 0;
|
|
|
|
l->Position.yRot = v->Position.yRot - 0x4000;
|
|
|
|
l->Position.zRot = 0;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2021-11-10 02:41:59 +03:00
|
|
|
SetAnimation(l, LA_STAND_SOLID);
|
2020-04-27 14:01:00 +02:00
|
|
|
Lara.Vehicle = NO_ITEM;
|
2022-02-11 01:31:54 +11:00
|
|
|
Lara.Control.HandStatus = HandStatus::Free;
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CART_GETIN:
|
2022-02-20 00:43:58 +11:00
|
|
|
if ((l->AnimNumber == Objects[ID_MINECART_LARA_ANIMS].animIndex + 5) && (l->FrameNumber == GetFrameNumber(v, 20)) && (!cart->Flags & CART_FLAG_MESH))
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
MESH tmp = g_Level.Meshes[Lara.meshPtrs[LM_RHAND]];
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2020-07-03 07:05:33 +02:00
|
|
|
Lara.meshPtrs[LM_RHAND] = Objects[ID_MINECART_LARA_ANIMS].meshIndex + LM_RHAND;
|
2020-07-21 09:56:47 +02:00
|
|
|
g_Level.Meshes[Objects[ID_MINECART_LARA_ANIMS].meshIndex + LM_RHAND] = tmp;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-20 00:43:58 +11:00
|
|
|
cart->Flags |= CART_FLAG_MESH;
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CART_WALLDEATH:
|
|
|
|
Camera.targetElevation = -ANGLE(25);
|
|
|
|
Camera.targetDistance = WALL_SIZE * 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CART_TURNDEATH:
|
|
|
|
Camera.targetElevation = -ANGLE(45);
|
|
|
|
Camera.targetDistance = WALL_SIZE * 2;
|
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
fh = GetCollision(v, v->Position.yRot, 512, &ch);
|
2019-11-30 13:51:37 +01:00
|
|
|
|
|
|
|
if ((fh > -STEP_SIZE) && (fh < STEP_SIZE))
|
|
|
|
{
|
|
|
|
if ((Wibble & 7) == 0)
|
2022-02-09 16:55:46 +11:00
|
|
|
SoundEffect(SFX_TR3_QUAD_FRONT_IMPACT, &v->Position, 2);
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
v->Position.xPos += TURN_DEATH_VEL * phd_sin(v->Position.yRot);
|
|
|
|
v->Position.zPos += TURN_DEATH_VEL * phd_cos(v->Position.yRot);
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
if (l->AnimNumber == Objects[ID_MINECART_LARA_ANIMS].animIndex + 30)
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2022-02-20 00:43:58 +11:00
|
|
|
cart->Flags |= CART_FLAG_NOANIM;
|
2022-02-09 16:55:46 +11:00
|
|
|
l->HitPoints = -1;
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CART_HIT:
|
2022-02-09 16:55:46 +11:00
|
|
|
if ((l->HitPoints <= 0) && (l->FrameNumber == GetFrameNumber(v, 34) + 28))
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
l->FrameNumber = GetFrameNumber(v, 34) + 28;
|
2022-02-20 00:43:58 +11:00
|
|
|
cart->Flags = (cart->Flags & ~CART_FLAG_CONTROL) | (CART_FLAG_NOANIM);
|
2022-02-09 13:20:57 +11:00
|
|
|
cart->Speed = v->Velocity = 0;
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-02-20 00:43:58 +11:00
|
|
|
if ((Lara.Vehicle != NO_ITEM) && (!(cart->Flags & CART_FLAG_NOANIM)))
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
|
|
|
AnimateItem(l);
|
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
v->AnimNumber = Objects[ID_MINECART].animIndex + (l->AnimNumber - Objects[ID_MINECART_LARA_ANIMS].animIndex);
|
|
|
|
v->FrameNumber = g_Level.Anims[v->AnimNumber].frameBase + (l->FrameNumber - g_Level.Anims[l->AnimNumber].frameBase);
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
2022-02-09 16:55:46 +11:00
|
|
|
if ((l->ActiveState != CART_TURNDEATH) && (l->ActiveState != CART_WALLDEATH) && (l->HitPoints > 0))
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
if ((v->Position.zRot > TERMINAL_ANGLE) || (v->Position.zRot < -TERMINAL_ANGLE))
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
l->AnimNumber = Objects[ID_MINECART_LARA_ANIMS].animIndex + 31;
|
|
|
|
l->FrameNumber = g_Level.Anims[l->AnimNumber].frameBase;
|
|
|
|
l->ActiveState = l->TargetState = CART_TURNDEATH;
|
2022-02-20 00:43:58 +11:00
|
|
|
cart->Flags = (cart->Flags & ~CART_FLAG_CONTROL) | CART_FLAG_STOPPED | CART_FLAG_DEAD;
|
2022-02-09 13:20:57 +11:00
|
|
|
cart->Speed = v->Velocity = 0;
|
2019-11-30 13:51:37 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
fh = GetCollision(v, v->Position.yRot, 512, &ch);
|
2019-11-30 13:51:37 +01:00
|
|
|
if (fh < -(STEP_SIZE * 2))
|
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
l->AnimNumber = Objects[ID_MINECART_LARA_ANIMS].animIndex + 23;
|
|
|
|
l->FrameNumber = g_Level.Anims[l->AnimNumber].frameBase;
|
|
|
|
l->ActiveState = l->TargetState = CART_WALLDEATH;
|
2022-02-20 00:43:58 +11:00
|
|
|
cart->Flags = (cart->Flags & ~CART_FLAG_CONTROL) | (CART_FLAG_STOPPED | CART_FLAG_DEAD);
|
2022-02-09 13:20:57 +11:00
|
|
|
cart->Speed = v->Velocity = 0;
|
2022-02-09 16:55:46 +11:00
|
|
|
l->HitPoints = -1;
|
2019-11-30 13:51:37 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
if ((l->ActiveState != CART_DUCK) && (l->ActiveState != CART_HIT))
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
|
|
|
COLL_INFO coll;
|
2021-09-10 00:20:59 +03:00
|
|
|
coll.Setup.Radius = CART_RADIUS;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2021-09-02 11:20:41 +03:00
|
|
|
DoObjectCollision(v, &coll);
|
|
|
|
|
2021-09-10 00:18:47 +03:00
|
|
|
if (coll.HitStatic)
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
|
|
|
int hits;
|
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
l->AnimNumber = Objects[ID_MINECART_LARA_ANIMS].animIndex + 34;
|
|
|
|
l->FrameNumber = g_Level.Anims[l->AnimNumber].frameBase;
|
|
|
|
l->ActiveState = l->TargetState = CART_HIT;
|
|
|
|
DoLotsOfBlood(l->Position.xPos, l->Position.yPos - 768, l->Position.zPos, v->Velocity, v->Position.yRot, l->RoomNumber, 3);
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2020-10-06 10:36:30 -05:00
|
|
|
hits = (CART_NHITS * short((cart->Speed) / 2048));
|
2019-11-30 13:51:37 +01:00
|
|
|
if (hits < 20)
|
|
|
|
hits = 20;
|
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
l->HitPoints -= hits;
|
2019-11-30 13:51:37 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fh > 512 + 64) && (!cart->YVel))
|
|
|
|
cart->YVel = CART_JUMP_VEL;
|
|
|
|
|
|
|
|
CartToBaddieCollision(v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InitialiseMineCart(short itemNum)
|
|
|
|
{
|
|
|
|
ITEM_INFO* v;
|
2022-02-20 00:43:58 +11:00
|
|
|
MinecartInfo* cart;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
v = &g_Level.Items[itemNum];
|
2022-02-20 00:43:58 +11:00
|
|
|
v->Data = MinecartInfo();
|
2022-02-09 16:55:46 +11:00
|
|
|
cart = v->Data;
|
2019-11-30 13:51:37 +01:00
|
|
|
cart->Flags = NULL;
|
|
|
|
cart->Speed = 0;
|
|
|
|
cart->YVel = 0;
|
|
|
|
cart->Gradient = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MineCartCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll)
|
|
|
|
{
|
|
|
|
ITEM_INFO* v;
|
2022-02-20 00:43:58 +11:00
|
|
|
MinecartInfo* cart;
|
2019-11-30 13:51:37 +01:00
|
|
|
int geton;
|
|
|
|
short ang;
|
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
if ((l->HitPoints < 0) || (Lara.Vehicle != NO_ITEM))
|
2019-11-30 13:51:37 +01:00
|
|
|
return;
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
v = &g_Level.Items[itemNum];
|
2019-11-30 13:51:37 +01:00
|
|
|
|
|
|
|
if ((geton = GetInMineCart(v, l, coll)))
|
|
|
|
{
|
2020-04-27 14:01:00 +02:00
|
|
|
Lara.Vehicle = itemNum;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-11 01:31:54 +11:00
|
|
|
if (Lara.Control.WeaponControl.GunType == WEAPON_FLARE)
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2021-11-12 19:52:48 +11:00
|
|
|
CreateFlare(LaraItem, ID_FLARE_ITEM, FALSE);
|
2021-12-09 00:48:55 +11:00
|
|
|
UndrawFlareMeshes(l);
|
2022-02-10 01:38:32 +11:00
|
|
|
Lara.Flare.ControlLeft = false;
|
2022-02-11 01:31:54 +11:00
|
|
|
Lara.Control.WeaponControl.RequestGunType = Lara.Control.WeaponControl.GunType = WEAPON_NONE;
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
|
2022-02-11 01:31:54 +11:00
|
|
|
Lara.Control.HandStatus = HandStatus::Busy;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
ang = short(mGetAngle(v->Position.xPos, v->Position.zPos, l->Position.xPos, l->Position.zPos) - v->Position.yRot);
|
2019-11-30 13:51:37 +01:00
|
|
|
|
|
|
|
if ((ang > -ANGLE(45)) && (ang < ANGLE(135)))
|
2022-02-09 16:55:46 +11:00
|
|
|
l->AnimNumber = Objects[ID_MINECART_LARA_ANIMS].animIndex + 46;
|
2019-11-30 13:51:37 +01:00
|
|
|
else
|
2022-02-09 16:55:46 +11:00
|
|
|
l->AnimNumber = Objects[ID_MINECART_LARA_ANIMS].animIndex + 0;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
l->FrameNumber = g_Level.Anims[l->AnimNumber].frameBase;
|
|
|
|
l->ActiveState = l->TargetState = CART_GETIN;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
l->Position.xPos = v->Position.xPos;
|
|
|
|
l->Position.yPos = v->Position.yPos;
|
|
|
|
l->Position.zPos = v->Position.zPos;
|
|
|
|
l->Position.xRot = v->Position.xRot;
|
|
|
|
l->Position.yRot = v->Position.yRot;
|
|
|
|
l->Position.zRot = v->Position.zRot;
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ObjectCollision(itemNum, l, coll);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-27 09:21:20 +02:00
|
|
|
int MineCartControl(void)
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2022-02-20 00:43:58 +11:00
|
|
|
MinecartInfo* cart;
|
2019-11-30 13:51:37 +01:00
|
|
|
ITEM_INFO* v;
|
|
|
|
FLOOR_INFO* floor;
|
2020-04-09 14:19:18 +02:00
|
|
|
short roomNumber;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
v = &g_Level.Items[Lara.Vehicle];
|
2021-10-31 10:50:36 +03:00
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
if (!v->Data)
|
2021-10-31 10:50:36 +03:00
|
|
|
{
|
|
|
|
TENLog("Minecart data is nullptr!", LogLevel::Error);
|
|
|
|
return 0;
|
|
|
|
}
|
2022-02-09 16:55:46 +11:00
|
|
|
cart = v->Data;
|
2019-11-30 13:51:37 +01:00
|
|
|
|
|
|
|
DoUserInput(v, LaraItem, cart);
|
|
|
|
|
2022-02-20 00:43:58 +11:00
|
|
|
if (cart->Flags & CART_FLAG_CONTROL)
|
2019-11-30 13:51:37 +01:00
|
|
|
MoveCart(v, LaraItem, cart);
|
|
|
|
|
2020-04-27 14:01:00 +02:00
|
|
|
if (Lara.Vehicle != NO_ITEM)
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
LaraItem->Position.xPos = v->Position.xPos;
|
|
|
|
LaraItem->Position.yPos = v->Position.yPos;
|
|
|
|
LaraItem->Position.zPos = v->Position.zPos;
|
|
|
|
LaraItem->Position.xRot = v->Position.xRot;
|
|
|
|
LaraItem->Position.yRot = v->Position.yRot;
|
|
|
|
LaraItem->Position.zRot = v->Position.zRot;
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
roomNumber = v->RoomNumber;
|
|
|
|
floor = GetFloor(v->Position.xPos, v->Position.yPos, v->Position.zPos, &roomNumber);
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
if (roomNumber != v->RoomNumber)
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
2020-04-27 14:01:00 +02:00
|
|
|
ItemNewRoom(Lara.Vehicle, roomNumber);
|
2022-02-12 16:25:59 +11:00
|
|
|
ItemNewRoom(Lara.ItemNumber, roomNumber);
|
2019-11-30 13:51:37 +01:00
|
|
|
}
|
|
|
|
|
2021-09-15 16:58:53 +03:00
|
|
|
TestTriggers(v, false);
|
2019-11-30 13:51:37 +01:00
|
|
|
|
2022-02-20 00:43:58 +11:00
|
|
|
if (!(cart->Flags & CART_FLAG_DEAD))
|
2019-11-30 13:51:37 +01:00
|
|
|
{
|
|
|
|
Camera.targetElevation = -ANGLE(45);
|
|
|
|
Camera.targetDistance = WALL_SIZE * 2;
|
|
|
|
}
|
|
|
|
|
2020-04-27 14:01:00 +02:00
|
|
|
return (Lara.Vehicle == NO_ITEM) ? 0 : 1;
|
2021-08-31 17:37:15 +02:00
|
|
|
}
|