2020-05-27 09:21:20 +02:00
|
|
|
#include "framework.h"
|
|
|
|
#include "quad.h"
|
|
|
|
#include "lara.h"
|
|
|
|
#include "effect2.h"
|
|
|
|
#include "items.h"
|
|
|
|
#include "sphere.h"
|
|
|
|
#include "collide.h"
|
|
|
|
#include "camera.h"
|
|
|
|
#include "tomb4fx.h"
|
|
|
|
#include "effect.h"
|
2020-08-09 22:09:14 -03:00
|
|
|
#include "lara_flare.h"
|
|
|
|
#include "lara_one_gun.h"
|
2020-05-27 09:21:20 +02:00
|
|
|
#include "misc.h"
|
|
|
|
#include "setup.h"
|
|
|
|
#include "level.h"
|
|
|
|
#include "input.h"
|
|
|
|
#include "sound.h"
|
2020-06-20 23:39:08 +02:00
|
|
|
using std::vector;
|
2019-12-05 17:35:57 +01:00
|
|
|
typedef enum QUAD_EFFECTS_POSITIONS {
|
|
|
|
EXHAUST_LEFT = 0,
|
|
|
|
EXHAUST_RIGHT,
|
|
|
|
BACKLEFT_TYRE,
|
|
|
|
BACKRIGHT_TYRE,
|
|
|
|
FRONTRIGHT_TYRE,
|
|
|
|
FRONTLEFT_TYRE
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef enum QUAD_FLAGS {
|
|
|
|
QUAD_FLAGS_DEAD = 0x80,
|
|
|
|
QUAD_FLAGS_IS_FALLING = 0x40
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef enum QUAD_ANIM_STATES {
|
|
|
|
QUAD_STATE_DRIVE = 1,
|
|
|
|
QUAD_STATE_TURNL = 2,
|
|
|
|
QUAD_STATE_SLOW = 5,
|
|
|
|
QUAD_STATE_BRAKE = 6,
|
|
|
|
QUAD_STATE_BIKEDEATH = 7,
|
|
|
|
QUAD_STATE_FALL = 8,
|
|
|
|
QUAD_STATE_GETONR = 9,
|
|
|
|
QUAD_STATE_GETOFFR = 10,
|
|
|
|
QUAD_STATE_HITBACK = 11,
|
|
|
|
QUAD_STATE_HITFRONT = 12,
|
|
|
|
QUAD_STATE_HITLEFT = 13,
|
|
|
|
QUAD_STATE_HITRIGHT = 14,
|
|
|
|
QUAD_STATE_STOP = 15,
|
|
|
|
QUAD_STATE_LAND = 17,
|
|
|
|
QUAD_STATE_STOPSLOWLY = 18,
|
|
|
|
QUAD_STATE_FALLDEATH = 19,
|
|
|
|
QUAD_STATE_FALLOFF = 20,
|
|
|
|
QUAD_STATE_WHEELIE = 21,
|
|
|
|
QUAD_STATE_TURNR = 22,
|
|
|
|
QUAD_STATE_GETONL = 23,
|
|
|
|
QUAD_STATE_GETOFFL = 24,
|
|
|
|
};
|
|
|
|
|
|
|
|
#define MAX_VELOCITY 0xA000
|
|
|
|
#define MIN_HANDBRAKE_SPEED 0x3000
|
|
|
|
|
|
|
|
#define BRAKE 0x0280
|
|
|
|
|
|
|
|
#define REVERSE_ACC -0x0300
|
|
|
|
#define MAX_BACK -0x3000
|
|
|
|
|
|
|
|
#define MAX_REVS 0xa000
|
|
|
|
|
|
|
|
#define TERMINAL_FALLSPEED 240
|
|
|
|
#define QUAD_SLIP 100
|
|
|
|
#define QUAD_SLIP_SIDE 50
|
|
|
|
|
|
|
|
#define QUAD_FRONT 550
|
|
|
|
#define QUAD_BACK -550
|
|
|
|
#define QUAD_SIDE 260
|
|
|
|
#define QUAD_RADIUS 500
|
|
|
|
#define QUAD_HEIGHT 512
|
|
|
|
|
|
|
|
#define QUAD_HIT_LEFT 11
|
|
|
|
#define QUAD_HIT_RIGHT 12
|
|
|
|
#define QUAD_HIT_FRONT 13
|
|
|
|
#define QUAD_HIT_BACK 14
|
|
|
|
|
|
|
|
#define SMAN_SHOT_DAMAGE 10
|
|
|
|
#define SMAN_LARA_DAMAGE 50
|
|
|
|
|
|
|
|
#define DAMAGE_START 140
|
|
|
|
#define DAMAGE_LENGTH 14
|
|
|
|
|
|
|
|
#define GETOFF_DISTANCE 512
|
|
|
|
|
|
|
|
#define QUAD_UNDO_TURN ANGLE(2)
|
2019-12-17 21:46:50 -03:00
|
|
|
#define QUAD_TURN (ANGLE(0.5) + QUAD_UNDO_TURN)
|
2019-12-05 17:35:57 +01:00
|
|
|
#define QUAD_MAX_TURN ANGLE(5)
|
2019-12-17 21:46:50 -03:00
|
|
|
#define QUAD_HTURN (ANGLE(0.75) + QUAD_UNDO_TURN)
|
2019-12-05 17:35:57 +01:00
|
|
|
#define QUAD_MAX_HTURN ANGLE(8)
|
|
|
|
|
|
|
|
#define MIN_MOMENTUM_TURN ANGLE(3)
|
2019-12-17 21:46:50 -03:00
|
|
|
#define MAX_MOMENTUM_TURN ANGLE(1.5)
|
2019-12-05 17:35:57 +01:00
|
|
|
#define QUAD_MAX_MOM_TURN ANGLE(150)
|
|
|
|
|
|
|
|
#define QUAD_FRONT 550
|
|
|
|
#define QUAD_SIDE 260
|
|
|
|
#define QUAD_RADIUS 500
|
|
|
|
#define QUAD_SNOW 500
|
|
|
|
|
|
|
|
#define QUAD_MAX_HEIGHT (STEP_SIZE)
|
|
|
|
#define QUAD_MIN_BOUNCE ((MAX_VELOCITY/2)>>8)
|
|
|
|
|
|
|
|
#define QUADBIKE_TURNL_A 3
|
2020-05-27 09:21:20 +02:00
|
|
|
#define QUADBIKE_TURNL_F GF2(ID_QUAD, QUADBIKE_TURNL_A, 0)
|
2019-12-05 17:35:57 +01:00
|
|
|
#define QUADBIKE_TURNR_A 20
|
2020-05-27 09:21:20 +02:00
|
|
|
#define QUADBIKE_TURNR_F GF2(ID_QUAD, QUADBIKE_TURNR_A, 0)
|
2019-12-05 17:35:57 +01:00
|
|
|
|
|
|
|
#define QUADBIKE_FALLSTART_A 6
|
2020-05-27 09:21:20 +02:00
|
|
|
#define QUADBIKE_FALLSTART_F GF2(ID_QUAD, QUADBIKE_FALLSTART_A, 0)
|
2019-12-05 17:35:57 +01:00
|
|
|
#define QUADBIKE_FALL_A 7
|
2020-05-27 09:21:20 +02:00
|
|
|
#define QUADBIKE_FALL_F GF2(ID_QUAD, QUADBIKE_FALL_A, 0)
|
2019-12-05 17:35:57 +01:00
|
|
|
#define QUADBIKE_GETONR_A 9
|
2020-05-27 09:21:20 +02:00
|
|
|
#define QUADBIKE_GETONR_F GF2(ID_QUAD, QUADBIKE_GETONR_A, 0)
|
2019-12-05 17:35:57 +01:00
|
|
|
#define Q_HITB_A 11
|
|
|
|
#define Q_HITF_A 12
|
|
|
|
#define Q_HITL_A 14
|
|
|
|
#define Q_HITR_A 13
|
|
|
|
#define QUADBIKE_GETONL_A 23
|
2020-05-27 09:21:20 +02:00
|
|
|
#define QUADBIKE_GETONL_F GF2(ID_QUAD, QUADBIKE_GETONL_A, 0)
|
2019-12-05 17:35:57 +01:00
|
|
|
#define QUADBIKE_FALLSTART2_A 25
|
|
|
|
|
|
|
|
BITE_INFO quadEffectsPositions[6] = {
|
|
|
|
{ -56, -32, -380, 0 }, // Left smoke
|
|
|
|
{ 56, -32, -380, 0 }, // Right smoke
|
|
|
|
{ -8, 180, -48, 3 }, // Left back
|
|
|
|
{ 8, 180, -48, 4 }, // Right back
|
|
|
|
{ 90, 180, -32, 6 }, // Right front
|
|
|
|
{ -90, 180, -32, 7 } // Left front
|
|
|
|
};
|
|
|
|
|
|
|
|
bool QuadHandbrakeStarting;
|
|
|
|
bool QuadCanHandbrakeStart;
|
|
|
|
int QuadSmokeStart;
|
|
|
|
bool QuadNoGetOff;
|
|
|
|
|
2020-05-27 09:21:20 +02:00
|
|
|
static void QuadbikeExplode(ITEM_INFO* item)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
if (g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_WATER)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
2020-08-10 18:17:59 +02:00
|
|
|
TriggerUnderwaterExplosion(item, 1);
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TriggerExplosionSparks(item->pos.xPos, item->pos.yPos, item->pos.zPos, 3, -2, 0, item->roomNumber);
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
|
|
TriggerExplosionSparks(item->pos.xPos, item->pos.yPos, item->pos.zPos, 3, -1, 0, item->roomNumber);
|
|
|
|
}
|
2020-09-16 13:03:30 -05:00
|
|
|
TriggerShockwave(&PHD_3DPOS(item->pos.xPos, item->pos.yPos - 128, item->pos.zPos, 0, item->pos.yRot, 0), 50, 180, 40, frandMinMax(160, 200), 60, 60, 64, frandMinMax(0, 359), 0);
|
2020-09-10 15:56:58 -05:00
|
|
|
// KillItem(Lara.Vehicle);
|
2020-06-04 12:49:08 +02:00
|
|
|
item->status = ITEM_DEACTIVATED;
|
2019-12-05 17:35:57 +01:00
|
|
|
|
|
|
|
SoundEffect(SFX_EXPLOSION1, NULL, 0);
|
|
|
|
SoundEffect(SFX_EXPLOSION2, NULL, 0);
|
|
|
|
|
2020-04-27 14:01:00 +02:00
|
|
|
Lara.Vehicle = NO_ITEM;
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
|
|
|
|
2020-05-27 09:21:20 +02:00
|
|
|
static int CanQuadbikeGetOff(int direction)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
|
|
|
short angle;
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
ITEM_INFO* item = &g_Level.Items[Lara.Vehicle];
|
2019-12-05 17:35:57 +01:00
|
|
|
|
|
|
|
if (direction < 0)
|
|
|
|
angle = item->pos.yRot - ANGLE(90);
|
|
|
|
else
|
|
|
|
angle = item->pos.yRot + ANGLE(90);
|
|
|
|
|
2020-04-25 16:23:53 +02:00
|
|
|
int x = item->pos.xPos + (512 * phd_sin(angle) >> W2V_SHIFT);
|
2019-12-05 17:35:57 +01:00
|
|
|
int y = item->pos.yPos;
|
2020-04-25 16:23:53 +02:00
|
|
|
int z = item->pos.zPos + (512 * phd_cos(angle) >> W2V_SHIFT);
|
2019-12-05 17:35:57 +01:00
|
|
|
|
|
|
|
short roomNumber = item->roomNumber;
|
|
|
|
FLOOR_INFO* floor = GetFloor(x, y, z, &roomNumber);
|
|
|
|
int height = GetFloorHeight(floor, x, y, z);
|
|
|
|
|
|
|
|
if ((HeightType == BIG_SLOPE) || (HeightType == DIAGONAL) || (height == NO_HEIGHT))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (abs(height - item->pos.yPos) > 512)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
int ceiling = GetCeiling(floor, x, y, z);
|
|
|
|
|
|
|
|
if ((ceiling - item->pos.yPos > -LARA_HITE) || (height - ceiling < LARA_HITE))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-05-27 09:21:20 +02:00
|
|
|
static int QuadCheckGetOff()
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
2020-09-12 07:52:47 +02:00
|
|
|
if (Lara.Vehicle == NO_ITEM)
|
|
|
|
return true;
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
ITEM_INFO* item = &g_Level.Items[Lara.Vehicle];
|
2019-12-05 17:35:57 +01:00
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
if (((LaraItem->currentAnimState == 10) || (LaraItem->currentAnimState == 24)) && (LaraItem->frameNumber == g_Level.Anims[LaraItem->animNumber].frameEnd))
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
2020-09-10 15:56:58 -05:00
|
|
|
ITEM_INFO* item = &g_Level.Items[Lara.Vehicle];
|
2019-12-05 17:35:57 +01:00
|
|
|
|
2020-09-10 15:56:58 -05:00
|
|
|
if (((LaraItem->currentAnimState == 10) || (LaraItem->currentAnimState == 24)) && (LaraItem->frameNumber == g_Level.Anims[LaraItem->animNumber].frameEnd))
|
|
|
|
{
|
|
|
|
if (LaraItem->currentAnimState == QUAD_STATE_GETOFFL)
|
|
|
|
LaraItem->pos.yRot += ANGLE(90);
|
|
|
|
else
|
|
|
|
LaraItem->pos.yRot -= ANGLE(90);
|
|
|
|
|
|
|
|
LaraItem->animNumber = LA_STAND_SOLID;
|
|
|
|
LaraItem->frameNumber = GF(LaraItem->animNumber, 0);
|
|
|
|
LaraItem->currentAnimState = LaraItem->goalAnimState = LS_STOP;
|
|
|
|
LaraItem->pos.xPos -= GETOFF_DISTANCE * phd_sin(LaraItem->pos.yRot) >> W2V_SHIFT;
|
|
|
|
LaraItem->pos.zPos -= GETOFF_DISTANCE * phd_cos(LaraItem->pos.yRot) >> W2V_SHIFT;
|
|
|
|
LaraItem->pos.xRot = LaraItem->pos.zRot = 0;
|
|
|
|
Lara.Vehicle = NO_ITEM;
|
|
|
|
Lara.gunStatus = LG_NO_ARMS;
|
|
|
|
}
|
|
|
|
else if (LaraItem->frameNumber == g_Level.Anims[LaraItem->animNumber].frameEnd)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
2020-09-10 15:56:58 -05:00
|
|
|
QUAD_INFO* quad;
|
2019-12-05 17:35:57 +01:00
|
|
|
|
2020-09-10 15:56:58 -05:00
|
|
|
quad = (QUAD_INFO *)item->data;
|
|
|
|
if (LaraItem->currentAnimState == QUAD_STATE_FALLOFF)
|
|
|
|
{
|
|
|
|
PHD_VECTOR pos = { 0, 0, 0 };
|
2019-12-05 17:35:57 +01:00
|
|
|
|
2020-09-10 15:56:58 -05:00
|
|
|
LaraItem->animNumber = LA_FREEFALL;
|
|
|
|
LaraItem->frameNumber = GF(LA_FREEFALL, 0);
|
|
|
|
LaraItem->currentAnimState = LS_FREEFALL;
|
2019-12-05 17:35:57 +01:00
|
|
|
|
2020-09-10 15:56:58 -05:00
|
|
|
GetJointAbsPosition(LaraItem, &pos, LM_HIPS);
|
2019-12-05 17:35:57 +01:00
|
|
|
|
2020-09-10 15:56:58 -05:00
|
|
|
LaraItem->pos.xPos = pos.x;
|
|
|
|
LaraItem->pos.yPos = pos.y;
|
|
|
|
LaraItem->pos.zPos = pos.z;
|
|
|
|
LaraItem->fallspeed = item->fallspeed;
|
|
|
|
LaraItem->gravityStatus = true;
|
|
|
|
LaraItem->pos.xRot = 0;
|
|
|
|
LaraItem->pos.zRot = 0;
|
|
|
|
LaraItem->hitPoints = 0;
|
|
|
|
Lara.gunStatus = LG_NO_ARMS;
|
|
|
|
item->flags |= ONESHOT;
|
2019-12-05 17:35:57 +01:00
|
|
|
|
2020-09-10 15:56:58 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else if (LaraItem->currentAnimState == QUAD_STATE_FALLDEATH)
|
|
|
|
{
|
|
|
|
LaraItem->goalAnimState = LS_DEATH;
|
|
|
|
LaraItem->fallspeed = DAMAGE_START + DAMAGE_LENGTH;
|
|
|
|
LaraItem->speed = 0;
|
|
|
|
quad->flags |= QUAD_FLAGS_DEAD;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
|
|
|
|
2020-09-10 15:56:58 -05:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
|
|
|
|
2020-05-27 09:21:20 +02:00
|
|
|
static int GetOnQuadBike(short itemNumber, COLL_INFO* coll)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
ITEM_INFO* item = &g_Level.Items[itemNumber];
|
2019-12-05 17:35:57 +01:00
|
|
|
|
|
|
|
if ((!(TrInput & IN_ACTION)) || (item->flags & ONESHOT) || (Lara.gunStatus != LG_NO_ARMS) || (LaraItem->gravityStatus)
|
|
|
|
|| ((abs(item->pos.yPos - LaraItem->pos.yPos)) > 256))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
int dx = LaraItem->pos.xPos - item->pos.xPos;
|
|
|
|
int dz = LaraItem->pos.zPos - item->pos.zPos;
|
|
|
|
|
|
|
|
int distance = dx * dx + dz * dz;
|
|
|
|
|
|
|
|
if (distance > 170000)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
short roomNumber = item->roomNumber;
|
|
|
|
FLOOR_INFO* floor = GetFloor(item->pos.xPos, item->pos.yPos, item->pos.zPos, &roomNumber);
|
|
|
|
if (GetFloorHeight(floor, item->pos.xPos, item->pos.yPos, item->pos.zPos) < -32000)
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
{
|
2020-04-25 16:23:53 +02:00
|
|
|
short angle = phd_atan(item->pos.zPos - LaraItem->pos.zPos, item->pos.xPos - LaraItem->pos.xPos);
|
2019-12-05 17:35:57 +01:00
|
|
|
angle -= item->pos.yRot;
|
|
|
|
|
|
|
|
if ((angle > -ANGLE(45)) && (angle < ANGLE(135)))
|
|
|
|
{
|
|
|
|
int tempAngle = LaraItem->pos.yRot - item->pos.yRot;
|
|
|
|
if (tempAngle > ANGLE(45) && tempAngle < ANGLE(135))
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int tempAngle = LaraItem->pos.yRot - item->pos.yRot;
|
|
|
|
if (tempAngle > ANGLE(225) && tempAngle < ANGLE(315))
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-05-27 09:21:20 +02:00
|
|
|
static void QuadBaddieCollision(ITEM_INFO* quad)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
|
|
|
vector<short> roomsList;
|
|
|
|
|
|
|
|
roomsList.push_back(quad->roomNumber);
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
ROOM_INFO* room = &g_Level.Rooms[quad->roomNumber];
|
2020-06-26 07:06:18 +02:00
|
|
|
for (int i = 0; i < room->doors.size(); i++)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
2020-06-26 07:06:18 +02:00
|
|
|
roomsList.push_back(room->doors[i].room);
|
2019-12-05 17:35:57 +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-12-05 17:35:57 +01:00
|
|
|
|
|
|
|
while (itemNum != NO_ITEM)
|
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
ITEM_INFO* item = &g_Level.Items[itemNum];
|
2019-12-05 17:35:57 +01:00
|
|
|
if (item->collidable && item->status != ITEM_INVISIBLE && item != LaraItem && item != quad)
|
|
|
|
{
|
2020-07-07 07:32:33 +02:00
|
|
|
OBJECT_INFO* object = &Objects[item->objectNumber];
|
2019-12-05 17:35:57 +01:00
|
|
|
if (object->collision && object->intelligent)
|
|
|
|
{
|
|
|
|
int x = quad->pos.xPos - item->pos.xPos;
|
|
|
|
int y = quad->pos.yPos - item->pos.yPos;
|
|
|
|
int z = quad->pos.zPos - item->pos.zPos;
|
|
|
|
if (x > -4096 && x < 4096 && z > -4096 && z < 4096 && y > -4096 && y < 4096)
|
|
|
|
{
|
|
|
|
if (TestBoundsCollide(item, quad, QUAD_RADIUS))
|
|
|
|
{
|
|
|
|
DoLotsOfBlood(item->pos.xPos, quad->pos.yPos - STEP_SIZE, item->pos.zPos, quad->speed, quad->pos.yRot, item->roomNumber, 3);
|
|
|
|
item->hitPoints = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
itemNum = item->nextItem;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-27 09:21:20 +02:00
|
|
|
static int GetQuadCollisionAnim(ITEM_INFO* item, PHD_VECTOR* p)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
|
|
|
p->x = item->pos.xPos - p->x;
|
|
|
|
p->z = item->pos.zPos - p->z;
|
|
|
|
|
|
|
|
if (p->x || p->z)
|
|
|
|
{
|
2020-04-25 16:23:53 +02:00
|
|
|
int c = phd_cos(item->pos.yRot);
|
|
|
|
int s = phd_sin(item->pos.yRot);
|
2019-12-05 17:35:57 +01:00
|
|
|
int front = ((p->z * c) + (p->x * s)) >> W2V_SHIFT;
|
|
|
|
int side = ((-p->z * s) + (p->x * c)) >> W2V_SHIFT;
|
|
|
|
|
|
|
|
if (abs(front) > abs(side))
|
|
|
|
{
|
|
|
|
if (front > 0)
|
|
|
|
return QUAD_HIT_BACK;
|
|
|
|
else
|
|
|
|
return QUAD_HIT_FRONT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (side > 0)
|
|
|
|
return QUAD_HIT_LEFT;
|
|
|
|
else
|
|
|
|
return QUAD_HIT_RIGHT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-27 09:21:20 +02:00
|
|
|
static int TestQuadHeight(ITEM_INFO* item, int dz, int dx, PHD_VECTOR* pos)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
2020-04-25 16:23:53 +02:00
|
|
|
pos->y = item->pos.yPos - (dz * phd_sin(item->pos.xRot) >> W2V_SHIFT) + (dx * phd_sin(item->pos.zRot) >> W2V_SHIFT);
|
2019-12-05 17:35:57 +01:00
|
|
|
|
2020-04-25 16:23:53 +02:00
|
|
|
int c = phd_cos(item->pos.yRot);
|
|
|
|
int s = phd_sin(item->pos.yRot);
|
2019-12-05 17:35:57 +01:00
|
|
|
|
|
|
|
pos->z = item->pos.zPos + ((dz * c - dx * s) >> W2V_SHIFT);
|
|
|
|
pos->x = item->pos.xPos + ((dz * s + dx * c) >> W2V_SHIFT);
|
|
|
|
|
|
|
|
short roomNumber = item->roomNumber;
|
|
|
|
FLOOR_INFO* floor = GetFloor(pos->x, pos->y, pos->z, &roomNumber);
|
|
|
|
int ceiling = GetCeiling(floor, pos->x, pos->y, pos->z);
|
|
|
|
if (pos->y < ceiling || ceiling == NO_HEIGHT)
|
|
|
|
return NO_HEIGHT;
|
|
|
|
|
|
|
|
return GetFloorHeight(floor, pos->x, pos->y, pos->z);
|
|
|
|
}
|
|
|
|
|
2020-05-27 09:21:20 +02:00
|
|
|
static int DoQuadShift(ITEM_INFO* quad, PHD_VECTOR* pos, PHD_VECTOR* old)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
|
|
|
int x = pos->x >> WALL_SHIFT;
|
|
|
|
int z = pos->z >> WALL_SHIFT;
|
|
|
|
|
|
|
|
int oldX= old->x >> WALL_SHIFT;
|
|
|
|
int oldZ = old->z >> WALL_SHIFT;
|
|
|
|
|
|
|
|
int shiftX = pos->x & (WALL_SIZE - 1);
|
|
|
|
int shiftZ = pos->z & (WALL_SIZE - 1);
|
|
|
|
|
|
|
|
if (x == oldX)
|
|
|
|
{
|
|
|
|
if (z == oldZ)
|
|
|
|
{
|
|
|
|
quad->pos.zPos += (old->z - pos->z);
|
|
|
|
quad->pos.xPos += (old->x - pos->x);
|
|
|
|
}
|
|
|
|
else if (z > oldZ)
|
|
|
|
{
|
|
|
|
quad->pos.zPos -= shiftZ + 1;
|
|
|
|
return (pos->x - quad->pos.xPos);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
quad->pos.zPos += WALL_SIZE - shiftZ;
|
|
|
|
return (quad->pos.xPos - pos->x);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (z == oldZ)
|
|
|
|
{
|
|
|
|
if (x > oldX)
|
|
|
|
{
|
|
|
|
quad->pos.xPos -= shiftX + 1;
|
|
|
|
return (quad->pos.zPos - pos->z);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
quad->pos.xPos += WALL_SIZE - shiftX;
|
|
|
|
return (pos->z - quad->pos.zPos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
x = 0;
|
|
|
|
z = 0;
|
|
|
|
|
|
|
|
short roomNumber = quad->roomNumber;
|
|
|
|
FLOOR_INFO* floor = GetFloor(old->x, pos->y, pos->z, &roomNumber);
|
|
|
|
int height = GetFloorHeight(floor, old->x, pos->y, pos->z);
|
|
|
|
if (height < old->y - STEP_SIZE)
|
|
|
|
{
|
|
|
|
if (pos->z > old->z)
|
|
|
|
z = -shiftZ - 1;
|
|
|
|
else
|
|
|
|
z = WALL_SIZE - shiftZ;
|
|
|
|
}
|
|
|
|
|
|
|
|
roomNumber = quad->roomNumber;
|
|
|
|
floor = GetFloor(pos->x, pos->y, old->z, &roomNumber);
|
|
|
|
height = GetFloorHeight(floor, pos->x, pos->y, old->z);
|
|
|
|
if (height < old->y - STEP_SIZE)
|
|
|
|
{
|
|
|
|
if (pos->x > old->x)
|
|
|
|
x = -shiftX - 1;
|
|
|
|
else
|
|
|
|
x = WALL_SIZE - shiftX;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x && z)
|
|
|
|
{
|
|
|
|
quad->pos.zPos += z;
|
|
|
|
quad->pos.xPos += x;
|
|
|
|
}
|
|
|
|
else if (z)
|
|
|
|
{
|
|
|
|
quad->pos.zPos += z;
|
|
|
|
if (z > 0)
|
|
|
|
return (quad->pos.xPos - pos->x);
|
|
|
|
else
|
|
|
|
return (pos->x - quad->pos.xPos);
|
|
|
|
}
|
|
|
|
else if (x)
|
|
|
|
{
|
|
|
|
quad->pos.xPos += x;
|
|
|
|
if (x > 0)
|
|
|
|
return (pos->z - quad->pos.zPos);
|
|
|
|
else
|
|
|
|
return (quad->pos.zPos - pos->z);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
quad->pos.zPos += (old->z - pos->z);
|
|
|
|
quad->pos.xPos += (old->x - pos->x);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-27 09:21:20 +02:00
|
|
|
static int DoQuadDynamics(int height, int fallspeed, int *y)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
|
|
|
if (height > *y)
|
|
|
|
{
|
|
|
|
*y += fallspeed;
|
|
|
|
if (*y > height - QUAD_MIN_BOUNCE)
|
|
|
|
{
|
|
|
|
*y = height;
|
|
|
|
fallspeed = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
fallspeed += 6;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int kick = (height - *y) << 2;
|
|
|
|
|
|
|
|
if (kick < -80)
|
|
|
|
kick = -80;
|
|
|
|
|
|
|
|
fallspeed += ((kick - fallspeed) >> 3);
|
|
|
|
|
|
|
|
if (*y > height)
|
|
|
|
*y = height;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fallspeed;
|
|
|
|
}
|
|
|
|
|
2020-05-27 09:21:20 +02:00
|
|
|
static int QuadDynamics(ITEM_INFO* item)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
|
|
|
/* Does all skidoo movement and collision and returns if collide value */
|
|
|
|
PHD_VECTOR moved, fl, fr, br, bl, mtl, mbl, mtr, mbr, mml, mmr;
|
|
|
|
PHD_VECTOR old, oldFrontLeft, oldFrontRight, oldBottomLeft, oldBottomRight, mtl_old, moldBottomLeft, mtr_old, moldBottomRight, mml_old, mmr_old;
|
|
|
|
int hfl, hfr, hbr, hbl, hmtl, hmbl, hmtr, hmbr, hmml, hmmr;
|
|
|
|
int holdFrontRight, holdFrontLeft, holdBottomRight, holdBottomLeft, hmtl_old, hmoldBottomLeft, hmtr_old, hmoldBottomRight, hmml_old, hmmr_old;
|
|
|
|
int slip, collide;
|
|
|
|
short rot, rotadd;
|
|
|
|
int newspeed;
|
|
|
|
|
|
|
|
QuadNoGetOff = false;
|
|
|
|
|
|
|
|
QUAD_INFO* quad = (QUAD_INFO*)item->data;
|
|
|
|
|
|
|
|
/* First get positions and heights of skidoo's corners + centre */
|
|
|
|
holdFrontLeft = TestQuadHeight(item, QUAD_FRONT, -QUAD_SIDE, &oldFrontLeft);
|
|
|
|
holdFrontRight = TestQuadHeight(item, QUAD_FRONT, QUAD_SIDE, &oldFrontRight);
|
|
|
|
holdBottomLeft = TestQuadHeight(item, -QUAD_FRONT, -QUAD_SIDE, &oldBottomLeft);
|
|
|
|
holdBottomRight = TestQuadHeight(item, -QUAD_FRONT, QUAD_SIDE, &oldBottomRight);
|
|
|
|
hmml_old = TestQuadHeight(item, 0, -QUAD_SIDE, &mml_old);
|
|
|
|
hmmr_old = TestQuadHeight(item, 0, QUAD_SIDE, &mmr_old);
|
|
|
|
hmtl_old = TestQuadHeight(item, QUAD_FRONT >> 1, -QUAD_SIDE, &mtl_old);
|
|
|
|
hmtr_old = TestQuadHeight(item, QUAD_FRONT >> 1, QUAD_SIDE, &mtr_old);
|
|
|
|
hmoldBottomLeft = TestQuadHeight(item, -QUAD_FRONT >> 1, -QUAD_SIDE, &moldBottomLeft);
|
|
|
|
hmoldBottomRight = TestQuadHeight(item, -QUAD_FRONT >> 1, QUAD_SIDE, &moldBottomRight);
|
|
|
|
|
|
|
|
old.x = item->pos.xPos;
|
|
|
|
old.y = item->pos.yPos;
|
|
|
|
old.z = item->pos.zPos;
|
|
|
|
|
|
|
|
if (oldBottomLeft.y > holdBottomLeft)
|
|
|
|
oldBottomLeft.y = holdBottomLeft;
|
|
|
|
if (oldBottomRight.y > holdBottomRight)
|
|
|
|
oldBottomRight.y = holdBottomRight;
|
|
|
|
if (oldFrontLeft.y > holdFrontLeft)
|
|
|
|
oldFrontLeft.y = holdFrontLeft;
|
|
|
|
if (oldFrontRight.y > holdFrontRight)
|
|
|
|
oldFrontRight.y = holdFrontRight;
|
|
|
|
if (moldBottomLeft.y > hmoldBottomLeft)
|
|
|
|
moldBottomLeft.y = hmoldBottomLeft;
|
|
|
|
if (moldBottomRight.y > hmoldBottomRight)
|
|
|
|
moldBottomRight.y = hmoldBottomRight;
|
|
|
|
if (mtl_old.y > hmtl_old)
|
|
|
|
mtl_old.y = hmtl_old;
|
|
|
|
if (mtr_old.y > hmtr_old)
|
|
|
|
mtr_old.y = hmtr_old;
|
|
|
|
if (mml_old.y > hmml_old)
|
|
|
|
mml_old.y = hmml_old;
|
|
|
|
if (mmr_old.y > hmmr_old)
|
|
|
|
mmr_old.y = hmmr_old;
|
|
|
|
|
|
|
|
|
|
|
|
if (item->pos.yPos > (item->floor - STEP_SIZE))
|
|
|
|
{
|
|
|
|
short momentum;
|
|
|
|
|
|
|
|
if (quad->skidooTurn < -QUAD_UNDO_TURN)
|
|
|
|
quad->skidooTurn += QUAD_UNDO_TURN;
|
|
|
|
|
|
|
|
else if (quad->skidooTurn > QUAD_UNDO_TURN)
|
|
|
|
quad->skidooTurn -= QUAD_UNDO_TURN;
|
|
|
|
|
|
|
|
else
|
|
|
|
quad->skidooTurn = 0;
|
|
|
|
|
|
|
|
item->pos.yRot += quad->skidooTurn + quad->extraRotation;
|
|
|
|
|
|
|
|
rot = item->pos.yRot - quad->momentumAngle;
|
|
|
|
|
|
|
|
momentum = MIN_MOMENTUM_TURN - (((((MIN_MOMENTUM_TURN - MAX_MOMENTUM_TURN) << 8) / MAX_VELOCITY) * quad->velocity) >> 8);
|
|
|
|
if (!(TrInput & IN_ACTION) && quad->velocity > 0)
|
|
|
|
momentum += momentum >> 2;
|
|
|
|
|
|
|
|
if (rot < -MAX_MOMENTUM_TURN)
|
|
|
|
{
|
|
|
|
if (rot < -QUAD_MAX_MOM_TURN)
|
|
|
|
{
|
|
|
|
rot = -QUAD_MAX_MOM_TURN;
|
|
|
|
quad->momentumAngle = item->pos.yRot - rot;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
quad->momentumAngle -= momentum;
|
|
|
|
}
|
|
|
|
else if (rot > MAX_MOMENTUM_TURN)
|
|
|
|
{
|
|
|
|
if (rot > QUAD_MAX_MOM_TURN)
|
|
|
|
{
|
|
|
|
rot = QUAD_MAX_MOM_TURN;
|
|
|
|
quad->momentumAngle = item->pos.yRot - rot;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
quad->momentumAngle += momentum;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
quad->momentumAngle = item->pos.yRot;
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
item->pos.yRot += quad->skidooTurn + quad->extraRotation;
|
|
|
|
|
|
|
|
short roomNumber = item->roomNumber;
|
|
|
|
FLOOR_INFO* floor = GetFloor(item->pos.xPos, item->pos.yPos, item->pos.zPos, &roomNumber);
|
|
|
|
int height = GetFloorHeight(floor, item->pos.xPos, item->pos.yPos, item->pos.zPos);
|
|
|
|
int speed = 0;
|
|
|
|
if (item->pos.yPos >= height)
|
2020-04-25 16:23:53 +02:00
|
|
|
speed = (item->speed * phd_cos(item->pos.xRot)) >> W2V_SHIFT;
|
2019-12-05 17:35:57 +01:00
|
|
|
else
|
|
|
|
speed = item->speed;
|
|
|
|
|
2020-04-25 16:23:53 +02:00
|
|
|
item->pos.zPos += (speed * phd_cos(quad->momentumAngle)) >> W2V_SHIFT;
|
|
|
|
item->pos.xPos += (speed * phd_sin(quad->momentumAngle)) >> W2V_SHIFT;
|
2019-12-05 17:35:57 +01:00
|
|
|
|
2020-04-25 16:23:53 +02:00
|
|
|
slip = QUAD_SLIP * phd_sin(item->pos.xRot) >> W2V_SHIFT;
|
2019-12-05 17:35:57 +01:00
|
|
|
if (abs(slip) > QUAD_SLIP / 2)
|
|
|
|
{
|
|
|
|
if (slip > 0)
|
|
|
|
slip -= 10;
|
|
|
|
else
|
|
|
|
slip += 10;
|
2020-04-25 16:23:53 +02:00
|
|
|
item->pos.zPos -= slip * phd_cos(item->pos.yRot) >> W2V_SHIFT;
|
|
|
|
item->pos.xPos -= slip * phd_sin(item->pos.yRot) >> W2V_SHIFT;
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
|
|
|
|
2020-04-25 16:23:53 +02:00
|
|
|
slip = QUAD_SLIP_SIDE * phd_sin(item->pos.zRot) >> W2V_SHIFT;
|
2019-12-05 17:35:57 +01:00
|
|
|
if (abs(slip) > QUAD_SLIP_SIDE / 2)
|
|
|
|
{
|
2020-04-25 16:23:53 +02:00
|
|
|
item->pos.zPos -= slip * phd_sin(item->pos.yRot) >> W2V_SHIFT;
|
|
|
|
item->pos.xPos += slip * phd_cos(item->pos.yRot) >> W2V_SHIFT;
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
moved.x = item->pos.xPos;
|
|
|
|
moved.z = item->pos.zPos;
|
|
|
|
|
|
|
|
if (!(item->flags & ONESHOT))
|
|
|
|
QuadBaddieCollision(item);
|
|
|
|
|
|
|
|
rot = 0;
|
|
|
|
|
|
|
|
hfl = TestQuadHeight(item, QUAD_FRONT, -QUAD_SIDE, &fl);
|
|
|
|
if (hfl < oldFrontLeft.y - STEP_SIZE)
|
|
|
|
rot = DoQuadShift(item, &fl, &oldFrontLeft);
|
|
|
|
|
|
|
|
hmtl = TestQuadHeight(item, QUAD_FRONT >> 1, -QUAD_SIDE, &mtl);
|
|
|
|
if (hmtl < mtl_old.y - STEP_SIZE)
|
|
|
|
DoQuadShift(item, &mtl, &mtl_old);
|
|
|
|
|
|
|
|
hmml = TestQuadHeight(item, 0, -QUAD_SIDE, &mml);
|
|
|
|
if (hmml < mml_old.y - STEP_SIZE)
|
|
|
|
DoQuadShift(item, &mml, &mml_old);
|
|
|
|
|
|
|
|
hmbl = TestQuadHeight(item, -QUAD_FRONT >> 1, -QUAD_SIDE, &mbl);
|
|
|
|
if (hmbl < moldBottomLeft.y - STEP_SIZE)
|
|
|
|
DoQuadShift(item, &mbl, &moldBottomLeft);
|
|
|
|
|
|
|
|
hbl = TestQuadHeight(item, -QUAD_FRONT, -QUAD_SIDE, &bl);
|
|
|
|
if (hbl < oldBottomLeft.y - STEP_SIZE)
|
|
|
|
{
|
|
|
|
rotadd = DoQuadShift(item, &bl, &oldBottomLeft);
|
|
|
|
if ((rotadd > 0 && rot >= 0) || (rotadd < 0 && rot <= 0))
|
|
|
|
rot += rotadd;
|
|
|
|
}
|
|
|
|
|
|
|
|
hfr = TestQuadHeight(item, QUAD_FRONT, QUAD_SIDE, &fr);
|
|
|
|
if (hfr < oldFrontRight.y - STEP_SIZE)
|
|
|
|
{
|
|
|
|
rotadd = DoQuadShift(item, &fr, &oldFrontRight);
|
|
|
|
if ((rotadd > 0 && rot >= 0) || (rotadd < 0 && rot <= 0))
|
|
|
|
rot += rotadd;
|
|
|
|
}
|
|
|
|
|
|
|
|
hmtr = TestQuadHeight(item, QUAD_FRONT >> 1, QUAD_SIDE, &mtr);
|
|
|
|
if (hmtr < mtr_old.y - STEP_SIZE)
|
|
|
|
DoQuadShift(item, &mtr, &mtr_old);
|
|
|
|
|
|
|
|
hmmr = TestQuadHeight(item, 0, QUAD_SIDE, &mmr);
|
|
|
|
if (hmmr < mmr_old.y - STEP_SIZE)
|
|
|
|
DoQuadShift(item, &mmr, &mmr_old);
|
|
|
|
|
|
|
|
hmbr = TestQuadHeight(item, -QUAD_FRONT >> 1, QUAD_SIDE, &mbr);
|
|
|
|
if (hmbr < moldBottomRight.y - STEP_SIZE)
|
|
|
|
DoQuadShift(item, &mbr, &moldBottomRight);
|
|
|
|
|
|
|
|
hbr = TestQuadHeight(item, -QUAD_FRONT, QUAD_SIDE, &br);
|
|
|
|
if (hbr < oldBottomRight.y - STEP_SIZE)
|
|
|
|
{
|
|
|
|
rotadd = DoQuadShift(item, &br, &oldBottomRight);
|
|
|
|
if ((rotadd > 0 && rot >= 0) || (rotadd < 0 && rot <= 0))
|
|
|
|
rot += rotadd;
|
|
|
|
}
|
|
|
|
|
|
|
|
roomNumber = item->roomNumber;
|
|
|
|
floor = GetFloor(item->pos.xPos, item->pos.yPos, item->pos.zPos, &roomNumber);
|
|
|
|
|
|
|
|
height = GetFloorHeight(floor, item->pos.xPos, item->pos.yPos, item->pos.zPos);
|
|
|
|
if (height < item->pos.yPos - STEP_SIZE)
|
|
|
|
DoQuadShift(item, (PHD_VECTOR *)&item->pos, &old);
|
|
|
|
|
|
|
|
quad->extraRotation = rot;
|
|
|
|
|
|
|
|
collide = GetQuadCollisionAnim(item, &moved);
|
|
|
|
|
|
|
|
if (collide)
|
|
|
|
{
|
2020-04-25 16:23:53 +02:00
|
|
|
newspeed = ((item->pos.zPos - old.z) * phd_cos(quad->momentumAngle) + (item->pos.xPos - old.x) * phd_sin(quad->momentumAngle)) >> W2V_SHIFT;
|
2019-12-05 17:35:57 +01:00
|
|
|
|
|
|
|
newspeed <<= 8;
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
if ((&g_Level.Items[Lara.Vehicle] == item)
|
2019-12-05 17:35:57 +01:00
|
|
|
&& (quad->velocity == MAX_VELOCITY)
|
|
|
|
&& (newspeed < (quad->velocity - 10)))
|
|
|
|
{
|
|
|
|
LaraItem->hitPoints -= (quad->velocity - newspeed) >> 7;
|
|
|
|
LaraItem->hitStatus = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (quad->velocity > 0 && newspeed < quad->velocity)
|
|
|
|
quad->velocity = (newspeed < 0) ? 0 : newspeed;
|
|
|
|
|
|
|
|
else if (quad->velocity < 0 && newspeed > quad->velocity)
|
|
|
|
quad->velocity = (newspeed > 0) ? 0 : newspeed;
|
|
|
|
|
|
|
|
if (quad->velocity < MAX_BACK)
|
|
|
|
quad->velocity = MAX_BACK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return collide;
|
|
|
|
}
|
|
|
|
|
2020-05-27 09:21:20 +02:00
|
|
|
static void AnimateQuadBike(ITEM_INFO* item, int collide, int dead)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
|
|
|
QUAD_INFO* quad = (QUAD_INFO *)item->data;
|
|
|
|
|
|
|
|
if ((item->pos.yPos != item->floor)
|
|
|
|
&& (LaraItem->currentAnimState != QUAD_STATE_FALL)
|
|
|
|
&& (LaraItem->currentAnimState != QUAD_STATE_LAND)
|
|
|
|
&& (LaraItem->currentAnimState != QUAD_STATE_FALLOFF)
|
|
|
|
&& (!dead))
|
|
|
|
{
|
|
|
|
if (quad->velocity < 0)
|
2019-12-31 14:56:02 +01:00
|
|
|
LaraItem->animNumber = Objects[ID_QUAD_LARA_ANIMS].animIndex + QUADBIKE_FALLSTART_A;
|
2019-12-05 17:35:57 +01:00
|
|
|
else
|
2019-12-31 14:56:02 +01:00
|
|
|
LaraItem->animNumber = Objects[ID_QUAD_LARA_ANIMS].animIndex + QUADBIKE_FALLSTART2_A;
|
2019-12-05 17:35:57 +01:00
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
LaraItem->frameNumber = g_Level.Anims[LaraItem->animNumber].frameBase;
|
2019-12-05 17:35:57 +01:00
|
|
|
LaraItem->currentAnimState = LaraItem->goalAnimState = QUAD_STATE_FALL;
|
|
|
|
}
|
|
|
|
else if ((collide)
|
|
|
|
&& (LaraItem->currentAnimState != QUAD_STATE_HITFRONT)
|
|
|
|
&& (LaraItem->currentAnimState != QUAD_STATE_HITBACK)
|
|
|
|
&& (LaraItem->currentAnimState != QUAD_STATE_HITLEFT)
|
|
|
|
&& (LaraItem->currentAnimState != QUAD_STATE_HITRIGHT)
|
|
|
|
&& (LaraItem->currentAnimState != QUAD_STATE_FALLOFF)
|
|
|
|
&& (quad->velocity > (MAX_VELOCITY / 3))
|
|
|
|
&& (!dead))
|
|
|
|
{
|
|
|
|
if (collide == QUAD_HIT_FRONT)
|
|
|
|
{
|
2019-12-31 14:56:02 +01:00
|
|
|
LaraItem->animNumber = Objects[ID_QUAD_LARA_ANIMS].animIndex + Q_HITF_A;
|
2019-12-05 17:35:57 +01:00
|
|
|
LaraItem->currentAnimState = LaraItem->goalAnimState = QUAD_STATE_HITFRONT;
|
|
|
|
}
|
|
|
|
else if (collide == QUAD_HIT_BACK)
|
|
|
|
{
|
2019-12-31 14:56:02 +01:00
|
|
|
LaraItem->animNumber = Objects[ID_QUAD_LARA_ANIMS].animIndex + Q_HITB_A;
|
2019-12-05 17:35:57 +01:00
|
|
|
LaraItem->currentAnimState = LaraItem->goalAnimState = QUAD_STATE_HITBACK;
|
|
|
|
}
|
|
|
|
else if (collide == QUAD_HIT_LEFT)
|
|
|
|
{
|
2019-12-31 14:56:02 +01:00
|
|
|
LaraItem->animNumber = Objects[ID_QUAD_LARA_ANIMS].animIndex + Q_HITL_A;
|
2019-12-05 17:35:57 +01:00
|
|
|
LaraItem->currentAnimState = LaraItem->goalAnimState = QUAD_STATE_HITLEFT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-12-31 14:56:02 +01:00
|
|
|
LaraItem->animNumber = Objects[ID_QUAD_LARA_ANIMS].animIndex + Q_HITR_A;
|
2019-12-05 17:35:57 +01:00
|
|
|
LaraItem->currentAnimState = LaraItem->goalAnimState = QUAD_STATE_HITRIGHT;
|
|
|
|
}
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
LaraItem->frameNumber = g_Level.Anims[LaraItem->animNumber].frameBase;
|
2020-09-10 13:31:35 +02:00
|
|
|
SoundEffect(SFX_TR3_QUAD_FRONT_IMPACT, &item->pos, 0);
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (LaraItem->currentAnimState)
|
|
|
|
{
|
|
|
|
case QUAD_STATE_STOP:
|
|
|
|
if (dead)
|
|
|
|
LaraItem->goalAnimState = QUAD_STATE_BIKEDEATH;
|
|
|
|
|
|
|
|
else if (TrInput & IN_ROLL && quad->velocity == 0 && !QuadNoGetOff)
|
|
|
|
{
|
|
|
|
if ((TrInput & IN_RIGHT) && CanQuadbikeGetOff(1))
|
|
|
|
LaraItem->goalAnimState = QUAD_STATE_GETOFFR;
|
|
|
|
else if ((TrInput & IN_LEFT) && CanQuadbikeGetOff(-1))
|
|
|
|
LaraItem->goalAnimState = QUAD_STATE_GETOFFL;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (TrInput & (IN_ACTION | IN_JUMP))
|
|
|
|
{
|
|
|
|
LaraItem->goalAnimState = QUAD_STATE_DRIVE;
|
|
|
|
//slowdamp = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QUAD_STATE_DRIVE:
|
|
|
|
if (dead)
|
|
|
|
{
|
|
|
|
if (quad->velocity > (MAX_VELOCITY / 2))
|
|
|
|
LaraItem->goalAnimState = QUAD_STATE_FALLDEATH;
|
|
|
|
else
|
|
|
|
LaraItem->goalAnimState = QUAD_STATE_BIKEDEATH;
|
|
|
|
}
|
|
|
|
else if (((quad->velocity >> 8) == 0)
|
|
|
|
&& (!(TrInput & (IN_ACTION | IN_JUMP))))
|
|
|
|
LaraItem->goalAnimState = QUAD_STATE_STOP;
|
|
|
|
|
|
|
|
else if (TrInput & IN_LEFT && !QuadHandbrakeStarting)
|
|
|
|
LaraItem->goalAnimState = QUAD_STATE_TURNL;
|
|
|
|
|
|
|
|
else if (TrInput & IN_RIGHT && !QuadHandbrakeStarting)
|
|
|
|
LaraItem->goalAnimState = QUAD_STATE_TURNR;
|
|
|
|
|
|
|
|
else if (TrInput & IN_JUMP)
|
|
|
|
{
|
|
|
|
if (quad->velocity > ((MAX_VELOCITY / 3) * 2))
|
|
|
|
LaraItem->goalAnimState = QUAD_STATE_BRAKE;
|
|
|
|
else
|
|
|
|
LaraItem->goalAnimState = QUAD_STATE_SLOW;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QUAD_STATE_BRAKE:
|
|
|
|
case QUAD_STATE_SLOW:
|
|
|
|
case QUAD_STATE_STOPSLOWLY:
|
|
|
|
if ((quad->velocity >> 8) == 0)
|
|
|
|
LaraItem->goalAnimState = QUAD_STATE_STOP;
|
|
|
|
|
|
|
|
else if (TrInput & IN_LEFT)
|
|
|
|
LaraItem->goalAnimState = QUAD_STATE_TURNL;
|
|
|
|
|
|
|
|
else if (TrInput & IN_RIGHT)
|
|
|
|
LaraItem->goalAnimState = QUAD_STATE_TURNR;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QUAD_STATE_TURNL:
|
|
|
|
if ((quad->velocity >> 8) == 0)
|
|
|
|
LaraItem->goalAnimState = QUAD_STATE_STOP;
|
|
|
|
else if (TrInput & IN_RIGHT)
|
|
|
|
{
|
2019-12-31 14:56:02 +01:00
|
|
|
LaraItem->animNumber = Objects[ID_QUAD_LARA_ANIMS].animIndex + QUADBIKE_TURNR_A;
|
2020-07-21 09:56:47 +02:00
|
|
|
LaraItem->frameNumber = g_Level.Anims[LaraItem->animNumber].frameBase;
|
2019-12-05 17:35:57 +01:00
|
|
|
LaraItem->currentAnimState = LaraItem->goalAnimState = QUAD_STATE_TURNR;
|
|
|
|
}
|
|
|
|
else if (!(TrInput & IN_LEFT))
|
|
|
|
{
|
|
|
|
LaraItem->goalAnimState = QUAD_STATE_DRIVE;
|
|
|
|
//slowdamp = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QUAD_STATE_TURNR:
|
|
|
|
if ((quad->velocity >> 8) == 0)
|
|
|
|
LaraItem->goalAnimState = QUAD_STATE_STOP;
|
|
|
|
else if (TrInput & IN_LEFT)
|
|
|
|
{
|
2019-12-31 14:56:02 +01:00
|
|
|
LaraItem->animNumber = Objects[ID_QUAD_LARA_ANIMS].animIndex + QUADBIKE_TURNL_A;
|
2020-07-21 09:56:47 +02:00
|
|
|
LaraItem->frameNumber = g_Level.Anims[LaraItem->animNumber].frameBase;
|
2019-12-05 17:35:57 +01:00
|
|
|
LaraItem->currentAnimState = LaraItem->goalAnimState = QUAD_STATE_TURNL;
|
|
|
|
}
|
|
|
|
else if (!(TrInput & IN_RIGHT))
|
|
|
|
{
|
|
|
|
LaraItem->goalAnimState = QUAD_STATE_DRIVE;
|
|
|
|
//slowdamp = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QUAD_STATE_FALL:
|
|
|
|
if (item->pos.yPos == item->floor)
|
|
|
|
LaraItem->goalAnimState = QUAD_STATE_LAND;
|
|
|
|
|
|
|
|
else if (item->fallspeed > TERMINAL_FALLSPEED)
|
|
|
|
quad->flags |= QUAD_FLAGS_IS_FALLING;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QUAD_STATE_FALLOFF:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QUAD_STATE_HITFRONT:
|
|
|
|
case QUAD_STATE_HITBACK:
|
|
|
|
case QUAD_STATE_HITLEFT:
|
|
|
|
case QUAD_STATE_HITRIGHT:
|
|
|
|
if (TrInput & (IN_ACTION | IN_JUMP))
|
|
|
|
LaraItem->goalAnimState = QUAD_STATE_DRIVE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
if (g_Level.Rooms[item->roomNumber].flags & (ENV_FLAG_WATER | ENV_FLAG_SWAMP))
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
|
|
|
LaraItem->goalAnimState = QUAD_STATE_FALLOFF;
|
2020-09-10 15:56:58 -05:00
|
|
|
LaraItem->pos.yPos = item->pos.yPos + 700;
|
|
|
|
LaraItem->roomNumber = item->roomNumber;
|
2019-12-05 17:35:57 +01:00
|
|
|
LaraItem->hitPoints = 0;
|
|
|
|
QuadbikeExplode(item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-27 09:21:20 +02:00
|
|
|
static int QuadUserControl(ITEM_INFO* item, int height, int* pitch)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
|
|
|
bool drive = false;
|
|
|
|
int revs = 0;
|
|
|
|
|
|
|
|
QUAD_INFO* quad = (QUAD_INFO *)item->data;
|
|
|
|
|
2020-09-10 23:43:44 -05:00
|
|
|
if (!quad->velocity && !(TrInput & (IN_DUCK | IN_SPRINT)) && !QuadCanHandbrakeStart)
|
2019-12-05 17:35:57 +01:00
|
|
|
QuadCanHandbrakeStart = true;
|
|
|
|
else if (quad->velocity)
|
|
|
|
QuadCanHandbrakeStart = false;
|
|
|
|
|
2020-09-10 23:43:44 -05:00
|
|
|
if (!(TrInput & (IN_DUCK | IN_SPRINT)))
|
2019-12-05 17:35:57 +01:00
|
|
|
QuadHandbrakeStarting = false;
|
|
|
|
|
|
|
|
if (!QuadHandbrakeStarting)
|
|
|
|
{
|
|
|
|
if (quad->revs > 0x10)
|
|
|
|
{
|
|
|
|
quad->velocity += quad->revs >> 4;
|
|
|
|
quad->revs -= quad->revs >> 3;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
quad->revs = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (item->pos.yPos >= (height - STEP_SIZE))
|
|
|
|
{
|
|
|
|
if ((!quad->velocity) && (TrInput & IN_LOOK))
|
|
|
|
LookUpDown();
|
|
|
|
|
|
|
|
if (quad->velocity > 0)
|
|
|
|
{
|
2020-09-10 23:43:44 -05:00
|
|
|
if ((TrInput & (IN_DUCK | IN_SPRINT)) && !QuadHandbrakeStarting && quad->velocity > MIN_HANDBRAKE_SPEED)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
|
|
|
if (TrInput & IN_LEFT)
|
|
|
|
{
|
|
|
|
quad->skidooTurn -= QUAD_HTURN;
|
|
|
|
if (quad->skidooTurn < -QUAD_MAX_HTURN)
|
|
|
|
quad->skidooTurn = -QUAD_MAX_HTURN;
|
|
|
|
}
|
|
|
|
else if (TrInput & IN_RIGHT)
|
|
|
|
{
|
|
|
|
quad->skidooTurn += QUAD_HTURN;
|
|
|
|
if (quad->skidooTurn > QUAD_MAX_HTURN)
|
|
|
|
quad->skidooTurn = QUAD_MAX_HTURN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (TrInput & IN_LEFT)
|
|
|
|
{
|
|
|
|
quad->skidooTurn -= QUAD_TURN;
|
|
|
|
if (quad->skidooTurn < -QUAD_MAX_TURN)
|
|
|
|
quad->skidooTurn = -QUAD_MAX_TURN;
|
|
|
|
}
|
|
|
|
else if (TrInput & IN_RIGHT)
|
|
|
|
{
|
|
|
|
quad->skidooTurn += QUAD_TURN;
|
|
|
|
if (quad->skidooTurn > QUAD_MAX_TURN)
|
|
|
|
quad->skidooTurn = QUAD_MAX_TURN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (quad->velocity < 0)
|
|
|
|
{
|
2020-09-10 23:43:44 -05:00
|
|
|
if ((TrInput & (IN_DUCK | IN_SPRINT)) && !QuadHandbrakeStarting && quad->velocity < -MIN_HANDBRAKE_SPEED + 0x800)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
|
|
|
if (TrInput & IN_RIGHT)
|
|
|
|
{
|
|
|
|
quad->skidooTurn -= QUAD_HTURN;
|
|
|
|
if (quad->skidooTurn < -QUAD_MAX_HTURN)
|
|
|
|
quad->skidooTurn = -QUAD_MAX_HTURN;
|
|
|
|
}
|
|
|
|
else if (TrInput & IN_LEFT)
|
|
|
|
{
|
|
|
|
quad->skidooTurn += QUAD_HTURN;
|
|
|
|
if (quad->skidooTurn > QUAD_MAX_HTURN)
|
|
|
|
quad->skidooTurn = QUAD_MAX_HTURN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (TrInput & IN_RIGHT)
|
|
|
|
{
|
|
|
|
quad->skidooTurn -= QUAD_TURN;
|
|
|
|
if (quad->skidooTurn < -QUAD_MAX_TURN)
|
|
|
|
quad->skidooTurn = -QUAD_MAX_TURN;
|
|
|
|
}
|
|
|
|
else if (TrInput & IN_LEFT)
|
|
|
|
{
|
|
|
|
quad->skidooTurn += QUAD_TURN;
|
|
|
|
if (quad->skidooTurn > QUAD_MAX_TURN)
|
|
|
|
quad->skidooTurn = QUAD_MAX_TURN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TrInput & IN_JUMP)
|
|
|
|
{
|
2020-09-10 23:43:44 -05:00
|
|
|
if ((TrInput & (IN_DUCK|IN_SPRINT)) && (QuadCanHandbrakeStart || QuadHandbrakeStarting))
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
|
|
|
QuadHandbrakeStarting = true;
|
|
|
|
quad->revs -= 0x200;
|
|
|
|
if (quad->revs < MAX_BACK)
|
|
|
|
quad->revs = MAX_BACK;
|
|
|
|
}
|
|
|
|
else if (quad->velocity > 0)
|
|
|
|
quad->velocity -= BRAKE;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (quad->velocity > MAX_BACK)
|
|
|
|
quad->velocity += REVERSE_ACC;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -------- accelerate */
|
|
|
|
|
|
|
|
else if (TrInput & IN_ACTION)
|
|
|
|
{
|
2020-09-10 23:43:44 -05:00
|
|
|
if ((TrInput & (IN_DUCK | IN_SPRINT)) && (QuadCanHandbrakeStart || QuadHandbrakeStarting))
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
|
|
|
QuadHandbrakeStarting = true;
|
|
|
|
quad->revs += 0x200;
|
|
|
|
if (quad->revs >= MAX_VELOCITY)
|
|
|
|
quad->revs = MAX_VELOCITY;
|
|
|
|
}
|
|
|
|
else if (quad->velocity < MAX_VELOCITY)
|
|
|
|
{
|
|
|
|
if (quad->velocity < 0x4000)
|
|
|
|
quad->velocity += 8 + ((0x4000 + 0x800 - quad->velocity) >> 3);
|
|
|
|
else if (quad->velocity < 0x7000)
|
|
|
|
quad->velocity += 4 + ((0x7000 + 0x800 - quad->velocity) >> 4);
|
|
|
|
else if (quad->velocity < MAX_VELOCITY)
|
|
|
|
quad->velocity += 2 + ((MAX_VELOCITY - quad->velocity) >> 3);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
quad->velocity = MAX_VELOCITY;
|
|
|
|
|
|
|
|
quad->velocity -= (abs(item->pos.yRot - quad->momentumAngle)) >> 6;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (quad->velocity > 0x0100)
|
|
|
|
{
|
|
|
|
quad->velocity -= 0x0100;
|
|
|
|
}
|
|
|
|
else if (quad->velocity < -0x0100)
|
|
|
|
{
|
|
|
|
quad->velocity += 0x0100;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
quad->velocity = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (QuadHandbrakeStarting && quad->revs && !(TrInput & (IN_ACTION | IN_JUMP)))
|
|
|
|
{
|
|
|
|
if (quad->revs > 0x8)
|
|
|
|
quad->revs -= quad->revs >> 3;
|
|
|
|
else
|
|
|
|
quad->revs = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
item->speed = quad->velocity >> 8;
|
|
|
|
|
|
|
|
if (quad->engineRevs > 0x7000)
|
|
|
|
quad->engineRevs = -0x2000;
|
|
|
|
|
|
|
|
if (quad->velocity < 0)
|
|
|
|
revs = abs(quad->velocity >> 1);
|
|
|
|
else if (quad->velocity < 0x7000)
|
|
|
|
revs = -0x2000 + ((quad->velocity * (0x6800 - -0x2000)) / 0x7000);
|
|
|
|
else if (quad->velocity <= MAX_VELOCITY)
|
|
|
|
revs = -0x2800 + (((quad->velocity - 0x7000) * (0x7000 - -0x2800)) / (MAX_VELOCITY - 0x7000));
|
|
|
|
|
|
|
|
revs += abs(quad->revs);
|
|
|
|
quad->engineRevs += (revs - quad->engineRevs) >> 3;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (quad->engineRevs < 0xA000)
|
|
|
|
quad->engineRevs += (0xA000 - quad->engineRevs) >> 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
*pitch = quad->engineRevs;
|
|
|
|
|
|
|
|
return drive;
|
|
|
|
}
|
|
|
|
|
|
|
|
void InitialiseQuadBike(short itemNumber)
|
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
ITEM_INFO* item = &g_Level.Items[itemNumber];
|
2019-12-05 17:35:57 +01:00
|
|
|
|
2020-07-05 22:19:06 +02:00
|
|
|
item->data = game_malloc<QUAD_INFO>();
|
2019-12-05 17:35:57 +01:00
|
|
|
QUAD_INFO* quad = (QUAD_INFO *)item->data;
|
|
|
|
|
|
|
|
quad->velocity = 0;
|
|
|
|
|
|
|
|
quad->skidooTurn = 0;
|
|
|
|
quad->leftFallspeed = quad->rightFallspeed = 0;
|
|
|
|
quad->momentumAngle = item->pos.yRot;
|
|
|
|
quad->extraRotation = 0;
|
|
|
|
quad->trackMesh = 0;
|
|
|
|
quad->pitch = 0;
|
|
|
|
quad->flags = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QuadBikeCollision(short itemNumber, ITEM_INFO* l, COLL_INFO* coll)
|
|
|
|
{
|
|
|
|
int geton;
|
|
|
|
|
|
|
|
if ((LaraItem->hitPoints < 0)
|
2020-04-27 14:01:00 +02:00
|
|
|
|| (Lara.Vehicle != NO_ITEM))
|
2019-12-05 17:35:57 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
if ((geton = GetOnQuadBike(itemNumber, coll)))
|
|
|
|
{
|
|
|
|
short ang;
|
|
|
|
|
2020-04-27 14:01:00 +02:00
|
|
|
Lara.Vehicle = itemNumber;
|
2019-12-05 17:35:57 +01:00
|
|
|
|
|
|
|
if (Lara.gunType == WEAPON_FLARE)
|
|
|
|
{
|
|
|
|
CreateFlare(ID_FLARE_ITEM, 0);
|
|
|
|
undraw_flare_meshes();
|
|
|
|
Lara.flareControlLeft = 0;
|
2020-06-05 14:01:22 +02:00
|
|
|
Lara.requestGunType = Lara.gunType = WEAPON_NONE;
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Lara.gunStatus = LG_HANDS_BUSY;
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
ITEM_INFO* item = &g_Level.Items[itemNumber];
|
2019-12-05 17:35:57 +01:00
|
|
|
|
2020-04-25 16:23:53 +02:00
|
|
|
ang = phd_atan(item->pos.zPos - LaraItem->pos.zPos, item->pos.xPos - LaraItem->pos.xPos);
|
2019-12-05 17:35:57 +01:00
|
|
|
ang -= item->pos.yRot;
|
|
|
|
|
|
|
|
if ((ang > -(ONE_DEGREE * 45)) && (ang < (ONE_DEGREE * 135)))
|
|
|
|
{
|
2019-12-31 14:56:02 +01:00
|
|
|
LaraItem->animNumber = Objects[ID_QUAD_LARA_ANIMS].animIndex + QUADBIKE_GETONL_A;
|
2019-12-05 17:35:57 +01:00
|
|
|
LaraItem->currentAnimState = LaraItem->goalAnimState = QUAD_STATE_GETONL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-12-31 14:56:02 +01:00
|
|
|
LaraItem->animNumber = Objects[ID_QUAD_LARA_ANIMS].animIndex + QUADBIKE_GETONR_A;
|
2019-12-05 17:35:57 +01:00
|
|
|
LaraItem->currentAnimState = LaraItem->goalAnimState = QUAD_STATE_GETONR;
|
|
|
|
}
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
LaraItem->frameNumber = g_Level.Anims[LaraItem->animNumber].frameBase;
|
2019-12-05 17:35:57 +01:00
|
|
|
|
|
|
|
item->hitPoints = 1;
|
|
|
|
LaraItem->pos.xPos = item->pos.xPos;
|
|
|
|
LaraItem->pos.yPos = item->pos.yPos;
|
|
|
|
LaraItem->pos.zPos = item->pos.zPos;
|
|
|
|
LaraItem->pos.yRot = item->pos.yRot;
|
|
|
|
Lara.headXrot = Lara.headYrot = 0;
|
|
|
|
Lara.torsoXrot = Lara.torsoYrot = 0;
|
|
|
|
Lara.hitDirection = -1;
|
|
|
|
|
|
|
|
AnimateItem(l);
|
|
|
|
|
|
|
|
QUAD_INFO* quad = (QUAD_INFO*)item->data;
|
|
|
|
quad->revs = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ObjectCollision(itemNumber, l, coll);
|
|
|
|
}
|
|
|
|
|
2020-05-27 09:21:20 +02:00
|
|
|
static void TriggerQuadExhaustSmoke(int x, int y, int z, short angle, int speed, int moving)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
|
|
|
SPARKS* spark = &Sparks[GetFreeSpark()];
|
|
|
|
|
|
|
|
spark->on = true;
|
|
|
|
spark->sR = 0;
|
|
|
|
spark->sG = 0;
|
|
|
|
spark->sB = 0;
|
|
|
|
|
|
|
|
spark->dR = 96;
|
|
|
|
spark->dG = 96;
|
|
|
|
spark->dB = 128;
|
|
|
|
|
|
|
|
if (moving)
|
|
|
|
{
|
|
|
|
spark->dR = (spark->dR * speed) >> 5;
|
|
|
|
spark->dG = (spark->dG * speed) >> 5;
|
|
|
|
spark->dB = (spark->dB * speed) >> 5;
|
|
|
|
}
|
|
|
|
|
|
|
|
spark->colFadeSpeed = 4;
|
|
|
|
spark->fadeToBlack = 4;
|
|
|
|
spark->sLife = spark->life = (GetRandomControl() & 3) + 20 - (speed >> 12);
|
|
|
|
if (spark->sLife < 9)
|
|
|
|
spark->sLife = spark->life = 9;
|
|
|
|
|
|
|
|
spark->extras = 0;
|
|
|
|
spark->dynamic = -1;
|
|
|
|
|
|
|
|
spark->x = x + ((GetRandomControl() & 15) - 8);
|
|
|
|
spark->y = y + ((GetRandomControl() & 15) - 8);
|
|
|
|
spark->z = z + ((GetRandomControl() & 15) - 8);
|
2020-04-25 16:23:53 +02:00
|
|
|
int zv = (speed * phd_cos(angle)) >> (W2V_SHIFT + 2);
|
|
|
|
int xv = (speed * phd_sin(angle)) >> (W2V_SHIFT + 2);
|
2019-12-05 17:35:57 +01:00
|
|
|
spark->xVel = xv + ((GetRandomControl() & 255) - 128);
|
|
|
|
spark->yVel = -(GetRandomControl() & 7) - 8;
|
|
|
|
spark->zVel = zv + ((GetRandomControl() & 255) - 128);
|
|
|
|
spark->friction = 4;
|
|
|
|
|
|
|
|
if (GetRandomControl() & 1)
|
|
|
|
{
|
|
|
|
spark->flags = SP_SCALE | SP_DEF | SP_ROTATE | SP_EXPDEF;
|
|
|
|
spark->rotAng = GetRandomControl() & 4095;
|
|
|
|
if (GetRandomControl() & 1)
|
|
|
|
spark->rotAdd = -(GetRandomControl() & 7) - 24;
|
|
|
|
else
|
|
|
|
spark->rotAdd = (GetRandomControl() & 7) + 24;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
spark->flags = SP_SCALE | SP_DEF | SP_EXPDEF;
|
|
|
|
|
|
|
|
spark->def = Objects[ID_DEFAULT_SPRITES].meshIndex;
|
|
|
|
spark->scalar = 2;
|
|
|
|
spark->gravity = -(GetRandomControl() & 3) - 4;
|
|
|
|
spark->maxYvel = -(GetRandomControl() & 7) - 8;
|
2020-09-12 13:49:09 +02:00
|
|
|
int size = (GetRandomControl() & 7) + 64 + (speed >> 7);
|
2019-12-05 17:35:57 +01:00
|
|
|
spark->dSize = size;
|
2020-09-12 13:49:09 +02:00
|
|
|
spark->size = spark->sSize = size / 2;
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
|
|
|
|
2020-05-27 09:21:20 +02:00
|
|
|
int QuadBikeControl(void)
|
2019-12-05 17:35:57 +01:00
|
|
|
{
|
|
|
|
short xRot, zRot, rotadd;
|
|
|
|
int pitch, dead = 0;
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
ITEM_INFO* item = &g_Level.Items[Lara.Vehicle];
|
2019-12-05 17:35:57 +01:00
|
|
|
QUAD_INFO* quad = (QUAD_INFO *)item->data;
|
|
|
|
|
|
|
|
GAME_VECTOR oldpos;
|
|
|
|
oldpos.x = item->pos.xPos;
|
|
|
|
oldpos.y = item->pos.yPos;
|
|
|
|
oldpos.z = item->pos.zPos;
|
|
|
|
oldpos.roomNumber = item->roomNumber;
|
|
|
|
|
|
|
|
bool collide = QuadDynamics(item);
|
|
|
|
|
|
|
|
short roomNumber = item->roomNumber;
|
|
|
|
FLOOR_INFO* floor = GetFloor(item->pos.xPos, item->pos.yPos, item->pos.zPos, &roomNumber);
|
|
|
|
int height = GetFloorHeight(floor, item->pos.xPos, item->pos.yPos, item->pos.zPos);
|
|
|
|
int ceiling = GetCeiling(floor, item->pos.xPos, item->pos.yPos, item->pos.zPos);
|
|
|
|
|
|
|
|
PHD_VECTOR fl;
|
|
|
|
PHD_VECTOR fr;
|
|
|
|
int hfl = TestQuadHeight(item, QUAD_FRONT, -QUAD_SIDE, &fl);
|
|
|
|
int hfr = TestQuadHeight(item, QUAD_FRONT, QUAD_SIDE, &fr);
|
|
|
|
|
|
|
|
roomNumber = item->roomNumber;
|
|
|
|
floor = GetFloor(item->pos.xPos, item->pos.yPos, item->pos.zPos, &roomNumber);
|
|
|
|
height = GetFloorHeight(floor, item->pos.xPos, item->pos.yPos, item->pos.zPos);
|
|
|
|
|
|
|
|
TestTriggers(TriggerIndex, 0, 0);
|
|
|
|
|
|
|
|
if (LaraItem->hitPoints <= 0)
|
|
|
|
{
|
|
|
|
TrInput &= ~(IN_LEFT | IN_RIGHT | IN_BACK | IN_FORWARD);
|
|
|
|
dead = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int drive = -1;
|
|
|
|
|
|
|
|
if (quad->flags)
|
|
|
|
collide = false;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (LaraItem->currentAnimState)
|
|
|
|
{
|
|
|
|
case QUAD_STATE_GETONL:
|
|
|
|
case QUAD_STATE_GETONR:
|
|
|
|
case QUAD_STATE_GETOFFL:
|
|
|
|
case QUAD_STATE_GETOFFR:
|
|
|
|
drive = -1;
|
|
|
|
collide = false;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
drive = QuadUserControl(item, height, &pitch);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (quad->velocity || quad->revs)
|
|
|
|
{
|
|
|
|
int absvel = abs(quad->velocity) + 1;
|
|
|
|
quad->pitch = pitch;
|
|
|
|
if (quad->pitch < -0x8000)
|
|
|
|
quad->pitch = -0x8000;
|
|
|
|
else if (quad->pitch > 0xa000)
|
|
|
|
quad->pitch = 0xa000;
|
2020-09-10 13:31:35 +02:00
|
|
|
SoundEffect(SFX_TR3_QUAD_MOVE, &item->pos, PITCH_SHIFT + ((0x10000 + quad->pitch) << 8));
|
2019-12-05 17:35:57 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (drive != -1)
|
2020-09-10 13:31:35 +02:00
|
|
|
SoundEffect(SFX_TR3_QUAD_IDLE, &item->pos, 0);
|
2019-12-05 17:35:57 +01:00
|
|
|
quad->pitch = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
item->floor = height;
|
|
|
|
|
|
|
|
rotadd = quad->velocity >> 2;
|
|
|
|
quad->rearRot -= rotadd;
|
|
|
|
quad->rearRot -= (quad->revs >> 3);
|
|
|
|
quad->frontRot -= rotadd;
|
|
|
|
|
|
|
|
quad->leftFallspeed = DoQuadDynamics(hfl, quad->leftFallspeed, (int *)&fl.y);
|
|
|
|
quad->rightFallspeed = DoQuadDynamics(hfr, quad->rightFallspeed, (int *)&fr.y);
|
|
|
|
item->fallspeed = DoQuadDynamics(height, item->fallspeed, (int *)&item->pos.yPos);
|
|
|
|
|
|
|
|
height = (fl.y + fr.y) >> 1;
|
2020-04-25 16:23:53 +02:00
|
|
|
xRot = phd_atan(QUAD_FRONT, item->pos.yPos - height);
|
|
|
|
zRot = phd_atan(QUAD_SIDE, height - fl.y);
|
2019-12-05 17:35:57 +01:00
|
|
|
|
|
|
|
item->pos.xRot += (xRot - item->pos.xRot) >> 1;
|
|
|
|
item->pos.zRot += (zRot - item->pos.zRot) >> 1;
|
|
|
|
|
|
|
|
if (!(quad->flags & QUAD_FLAGS_DEAD))
|
|
|
|
{
|
|
|
|
if (roomNumber != item->roomNumber)
|
|
|
|
{
|
2020-04-27 14:01:00 +02:00
|
|
|
ItemNewRoom(Lara.Vehicle, roomNumber);
|
2019-12-05 17:35:57 +01:00
|
|
|
ItemNewRoom(Lara.itemNumber, roomNumber);
|
|
|
|
}
|
|
|
|
|
|
|
|
LaraItem->pos.xPos = item->pos.xPos;
|
|
|
|
LaraItem->pos.yPos = item->pos.yPos;
|
|
|
|
LaraItem->pos.zPos = item->pos.zPos;
|
|
|
|
LaraItem->pos.xRot = item->pos.xRot;
|
|
|
|
LaraItem->pos.yRot = item->pos.yRot;
|
|
|
|
LaraItem->pos.zRot = item->pos.zRot;
|
|
|
|
|
|
|
|
AnimateQuadBike(item, collide, dead);
|
|
|
|
AnimateItem(LaraItem);
|
|
|
|
|
2019-12-31 14:56:02 +01:00
|
|
|
item->animNumber = Objects[ID_QUAD].animIndex + (LaraItem->animNumber - Objects[ID_QUAD_LARA_ANIMS].animIndex);
|
2020-07-21 09:56:47 +02:00
|
|
|
item->frameNumber = g_Level.Anims[item->animNumber].frameBase + (LaraItem->frameNumber - g_Level.Anims[LaraItem->animNumber].frameBase);
|
2019-12-05 17:35:57 +01:00
|
|
|
|
|
|
|
Camera.targetElevation = -30 * ONE_DEGREE;
|
|
|
|
|
|
|
|
if (quad->flags & QUAD_FLAGS_IS_FALLING)
|
|
|
|
{
|
|
|
|
if (item->pos.yPos == item->floor)
|
|
|
|
{
|
|
|
|
ExplodingDeath(Lara.itemNumber, 0xffffffff, 1);
|
|
|
|
LaraItem->hitPoints = 0;
|
|
|
|
LaraItem->flags |= ONESHOT;
|
|
|
|
QuadbikeExplode(item);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (LaraItem->currentAnimState != QUAD_STATE_GETONR && LaraItem->currentAnimState != QUAD_STATE_GETONL &&
|
|
|
|
LaraItem->currentAnimState != QUAD_STATE_GETOFFR && LaraItem->currentAnimState != QUAD_STATE_GETOFFL)
|
|
|
|
{
|
|
|
|
PHD_VECTOR pos;
|
|
|
|
int speed = 0;
|
|
|
|
short angle = 0;
|
|
|
|
|
|
|
|
// Do smoke
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
|
|
{
|
|
|
|
pos.x = quadEffectsPositions[i].x;
|
|
|
|
pos.y = quadEffectsPositions[i].y;
|
|
|
|
pos.z = quadEffectsPositions[i].z;
|
|
|
|
GetJointAbsPosition(item, &pos, quadEffectsPositions[i].meshNum);
|
|
|
|
angle = item->pos.yRot + ((i == 0) ? 0x9000 : 0x7000);
|
|
|
|
if (item->speed > 32)
|
|
|
|
{
|
|
|
|
if (item->speed < 64)
|
|
|
|
{
|
|
|
|
speed = 64 - item->speed;
|
|
|
|
TriggerQuadExhaustSmoke(pos.x, pos.y, pos.z, angle, speed, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (QuadSmokeStart < 16)
|
|
|
|
{
|
|
|
|
speed = ((QuadSmokeStart << 1) + (GetRandomControl() & 7) + (GetRandomControl() & 16)) << 7;
|
|
|
|
QuadSmokeStart++;
|
|
|
|
}
|
|
|
|
else if (QuadHandbrakeStarting)
|
|
|
|
speed = (abs(quad->revs) >> 2) + ((GetRandomControl() & 7) << 7);
|
|
|
|
else if ((GetRandomControl() & 3) == 0)
|
|
|
|
speed = ((GetRandomControl() & 15) + (GetRandomControl() & 16)) << 7;
|
|
|
|
else
|
|
|
|
speed = 0;
|
|
|
|
TriggerQuadExhaustSmoke(pos.x, pos.y, pos.z, angle, speed, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2020-05-27 09:21:20 +02:00
|
|
|
{
|
2019-12-05 17:35:57 +01:00
|
|
|
QuadSmokeStart = 0;
|
2020-05-27 09:21:20 +02:00
|
|
|
}
|
2019-12-05 17:35:57 +01:00
|
|
|
|
|
|
|
return QuadCheckGetOff();
|
2020-06-28 20:30:56 +02:00
|
|
|
}
|