TombEngine/TR5Main/Game/Lara/lara_flare.cpp

461 lines
9.7 KiB
C++
Raw Normal View History

#include "framework.h"
2020-08-09 22:09:14 -03:00
#include "lara_flare.h"
#include "level.h"
#include "setup.h"
2020-04-24 19:15:05 +02:00
#include "sound.h"
2019-12-01 08:13:19 +01:00
#include "draw.h"
#include "items.h"
#include "sphere.h"
2020-08-09 22:09:14 -03:00
#include "lara_fire.h"
2019-12-01 08:13:19 +01:00
#include "Lara.h"
#include "collide.h"
#include "effect2.h"
2020-05-23 14:26:06 +02:00
#include "chaffFX.h"
2020-05-23 14:26:06 +02:00
constexpr std::array<float, 28> FlareFlickerTable = { 0.7590,0.9880,0.8790,0.920,0.8020,0.7610,0.97878,0.8978,0.9983,0.934763,0.8485,0.762573,0.84642,0.7896,0.817634,0.923424,0.7589,0.81399,0.92834,0.9978,0.7610,0.97878,0.8978,0.9983,0.934763,0.8485,0.762573,0.74642 };
constexpr DirectX::SimpleMath::Vector3 FlareMainColor = Vector3(1,0.52947, 0.3921);
constexpr std::array<float, 28> FlareFlickerTableLow = { 0.7590,0.1880,0.0790,0.920,0.8020,0.07610,0.197878,0.38978,0.09983,0.00934763,0.8485,0.0762573,0.84642,0.7896,0.517634,0.0923424,0.7589,0.081399,0.92834,0.01978,0.17610,0.497878,0.8978,0.69983,0.934763,0.28485,0.1762573,0.374642 };
void FlareControl(short itemNumber) // (AF) (D)
2019-11-21 07:43:34 +01:00
{
ITEM_INFO* item = &g_Level.Items[itemNumber];
if (g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_SWAMP)
{
KillItem(itemNumber);
return;
}
2019-12-01 08:13:19 +01:00
if (item->fallspeed)
{
item->pos.xRot += ANGLE(3);
item->pos.zRot += ANGLE(5);
2019-12-01 08:13:19 +01:00
}
else
{
item->pos.xRot = 0;
item->pos.zRot = 0;
}
2019-12-02 09:11:21 +01:00
int oldX = item->pos.xPos;
int oldY = item->pos.yPos;
int oldZ = item->pos.zPos;
2019-12-01 08:13:19 +01:00
2020-04-25 16:23:53 +02:00
int xv = item->speed * phd_sin(item->pos.yRot) >> W2V_SHIFT;
int zv = item->speed * phd_cos(item->pos.yRot) >> W2V_SHIFT;
2019-12-01 08:13:19 +01:00
item->pos.xPos += xv;
item->pos.zPos += zv;
2019-12-01 08:13:19 +01:00
if (g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_WATER)
2019-12-01 08:13:19 +01:00
{
item->fallspeed += (5 - item->fallspeed) / 2;
item->speed += (5 - item->speed) / 2;
}
else
item->fallspeed += 6;
2020-05-23 14:26:06 +02:00
2019-12-01 08:13:19 +01:00
item->pos.yPos += item->fallspeed;
DoProperDetection(itemNumber, oldX, oldY, oldZ, xv, item->fallspeed, zv);
2020-05-23 14:26:06 +02:00
2019-12-02 09:11:21 +01:00
short age = (short)(item->data) & 0x7FFF;
2019-12-01 08:13:19 +01:00
if (age >= 900)
{
if (!item->fallspeed && !item->speed)
{
KillItem(itemNumber);
return;
}
2019-12-01 08:13:19 +01:00
}
else
{
age++;
}
2020-05-23 14:26:06 +02:00
2019-12-01 08:13:19 +01:00
if (DoFlareLight((PHD_VECTOR*)&item->pos, age))
{
2020-05-23 14:26:06 +02:00
TriggerChaffEffects(item,age);
/* Hardcoded code */
2019-12-01 08:13:19 +01:00
age |= 0x8000;
}
item->data = (void*)age;
2019-11-21 07:43:34 +01:00
}
void ready_flare() // (F) (D)
2019-11-21 07:43:34 +01:00
{
2019-12-01 08:13:19 +01:00
Lara.gunStatus = LG_NO_ARMS;
Lara.leftArm.zRot = 0;
Lara.leftArm.yRot = 0;
Lara.leftArm.xRot = 0;
Lara.rightArm.zRot = 0;
Lara.rightArm.yRot = 0;
Lara.rightArm.xRot = 0;
Lara.rightArm.lock = false;
Lara.leftArm.lock = false;
2019-11-21 07:43:34 +01:00
Lara.target = NULL;
}
void undraw_flare_meshes() // (F) (D)
2019-11-21 07:43:34 +01:00
{
2020-07-03 07:05:33 +02:00
Lara.meshPtrs[LM_LHAND] = Objects[ID_LARA_SKIN].meshIndex + LM_LHAND;
2019-11-21 07:43:34 +01:00
}
2019-12-15 16:19:01 +01:00
void draw_flare_meshes() // (F) (D)
2019-11-21 07:43:34 +01:00
{
2020-07-03 07:05:33 +02:00
Lara.meshPtrs[LM_LHAND] = Objects[ID_LARA_FLARE_ANIM].meshIndex + LM_LHAND;
2019-11-21 07:43:34 +01:00
}
void undraw_flare() // (F) (D)
2019-11-21 07:43:34 +01:00
{
2019-12-01 08:13:19 +01:00
Lara.flareControlLeft = true;
2019-12-02 09:11:21 +01:00
short frame1 = Lara.flareFrame;
short frame2 = Lara.leftArm.frameNumber;
if (LaraItem->goalAnimState == LS_STOP
&& Lara.Vehicle == NO_ITEM)
2019-12-01 08:13:19 +01:00
{
if (LaraItem->animNumber == LA_STAND_IDLE)
2019-12-01 08:13:19 +01:00
{
LaraItem->animNumber = LA_DISCARD_FLARE;
frame1 = frame2 + g_Level.Anims[LaraItem->animNumber].frameBase;
2019-12-26 23:35:16 -03:00
Lara.flareFrame = frame1;
LaraItem->frameNumber = frame1;
2019-12-01 08:13:19 +01:00
}
if (LaraItem->animNumber == LA_DISCARD_FLARE)
2019-12-01 08:13:19 +01:00
{
Lara.flareControlLeft = false;
if (frame1 >= g_Level.Anims[LaraItem->animNumber].frameBase + 31)
2019-12-01 08:13:19 +01:00
{
Lara.requestGunType = Lara.lastGunType;
Lara.gunType = Lara.lastGunType;
Lara.gunStatus = LG_NO_ARMS;
InitialiseNewWeapon();
Lara.target = NULL;
Lara.rightArm.lock = false;
Lara.leftArm.lock = false;
LaraItem->animNumber = LA_STAND_SOLID;
Lara.flareFrame = g_Level.Anims[LaraItem->animNumber].frameBase;
LaraItem->frameNumber = g_Level.Anims[LaraItem->animNumber].frameBase;
LaraItem->currentAnimState = LS_STOP;
LaraItem->goalAnimState = LS_STOP;
2019-12-01 08:13:19 +01:00
return;
}
Lara.flareFrame++;
}
}
else if (LaraItem->currentAnimState == LS_STOP
&& Lara.Vehicle == NO_ITEM) /* @ORIGINAL_BUG: this code block makes flare cancels possible */
2019-12-01 08:13:19 +01:00
{
LaraItem->animNumber = LA_STAND_SOLID;
LaraItem->frameNumber = g_Level.Anims[LaraItem->animNumber].frameBase;
2019-12-01 08:13:19 +01:00
}
2019-12-26 23:35:16 -03:00
if (frame2 >= 33 && frame2 < 72)
{
frame2 = 2;
DoFlareInHand(Lara.flareAge);
}
else if (!frame2)
2019-12-01 08:13:19 +01:00
{
frame2 = 1;
DoFlareInHand(Lara.flareAge);
}
else if (frame2 >= 72 && frame2 < 95)
{
frame2++;
if (frame2 == 94)
{
frame2 = 1;
2019-12-26 23:35:16 -03:00
DoFlareInHand(Lara.flareAge);
2019-12-01 08:13:19 +01:00
}
}
2019-12-26 23:35:16 -03:00
else if (frame2 >= 1 && frame2 < 33)
2019-12-01 08:13:19 +01:00
{
frame2++;
if (frame2 == 21)
{
CreateFlare(ID_FLARE_ITEM, 1);
undraw_flare_meshes();
Lara.flareAge = 0;
}
else if (frame2 == 33)
{
frame2 = 0;
Lara.requestGunType = Lara.lastGunType;
Lara.gunType = Lara.lastGunType;
Lara.gunStatus = LG_NO_ARMS;
InitialiseNewWeapon();
Lara.flareControlLeft = false;
Lara.target = NULL;
Lara.rightArm.lock = false;
Lara.leftArm.lock = false;
2019-12-01 08:13:19 +01:00
Lara.flareFrame = 0;
}
2019-12-26 23:35:16 -03:00
else if (frame2 < 21)
{
DoFlareInHand(Lara.flareAge);
}
2019-12-01 08:13:19 +01:00
}
2019-12-26 23:35:16 -03:00
else if (frame2 >= 95 && frame2 < 110)
2019-12-01 08:13:19 +01:00
{
frame2++;
if (frame2 == 110)
2019-12-26 23:35:16 -03:00
{
2019-12-01 08:13:19 +01:00
frame2 = 1;
2019-12-26 23:35:16 -03:00
DoFlareInHand(Lara.flareAge);
}
2019-12-01 08:13:19 +01:00
}
Lara.leftArm.frameNumber = frame2;
set_flare_arm(Lara.leftArm.frameNumber);
2019-11-21 07:43:34 +01:00
}
void draw_flare() // (F) (D)
2019-11-21 07:43:34 +01:00
{
2019-12-02 09:11:21 +01:00
short frame;
2019-11-21 07:43:34 +01:00
if (LaraItem->currentAnimState == LS_PICKUP_FLARE ||
LaraItem->currentAnimState == LS_PICKUP)
2019-11-21 07:43:34 +01:00
{
2019-12-01 08:13:19 +01:00
DoFlareInHand(Lara.flareAge);
Lara.flareControlLeft = false;
2019-12-26 23:35:16 -03:00
Lara.leftArm.frameNumber = 93;
2019-12-01 08:13:19 +01:00
set_flare_arm(93);
2019-11-21 07:43:34 +01:00
}
else
{
2019-12-01 08:13:19 +01:00
frame = Lara.leftArm.frameNumber + 1;
Lara.flareControlLeft = true;
2019-11-21 07:43:34 +01:00
2019-12-01 08:13:19 +01:00
if (frame < 33 || frame > 94)
2019-11-21 07:43:34 +01:00
{
2019-12-01 08:13:19 +01:00
frame = 33;
2019-11-21 07:43:34 +01:00
}
2019-12-01 08:13:19 +01:00
else if (frame == 46)
2019-11-21 07:43:34 +01:00
{
draw_flare_meshes();
}
2019-12-01 08:13:19 +01:00
else if (frame >= 72 && frame <= 93)
2019-11-21 07:43:34 +01:00
{
2019-12-01 08:13:19 +01:00
if (frame == 72)
2019-11-21 07:43:34 +01:00
{
SoundEffect(SFX_RAVESTICK, &LaraItem->pos, g_Level.Rooms[LaraItem->roomNumber].flags & ENV_FLAG_WATER);
2019-12-01 08:13:19 +01:00
Lara.flareAge = 1;
2019-11-21 07:43:34 +01:00
}
2019-12-01 08:13:19 +01:00
DoFlareInHand(Lara.flareAge);
2019-11-21 07:43:34 +01:00
}
else
{
2019-12-01 08:13:19 +01:00
if (frame == 94)
2019-11-21 07:43:34 +01:00
{
ready_flare();
2019-12-01 08:13:19 +01:00
frame = 0;
DoFlareInHand(Lara.flareAge);
2019-11-21 07:43:34 +01:00
}
}
2019-12-01 08:13:19 +01:00
Lara.leftArm.frameNumber = frame;
set_flare_arm(frame);
}
2019-11-21 07:43:34 +01:00
}
void set_flare_arm(int frame) // (F) (D)
2019-11-21 07:43:34 +01:00
{
short anim = Objects[ID_LARA_FLARE_ANIM].animIndex;
2019-11-21 07:43:34 +01:00
if (frame >= 95)
{
2019-12-01 08:13:19 +01:00
anim += 4;
2019-11-21 07:43:34 +01:00
}
else if (frame >= 72)
{
2019-12-01 08:13:19 +01:00
anim += 3;
2019-11-21 07:43:34 +01:00
}
else if (frame >= 33)
{
2019-12-01 08:13:19 +01:00
anim += 2;
2019-11-21 07:43:34 +01:00
}
else if (frame >= 1)
{
2019-12-01 08:13:19 +01:00
anim += 1;
2019-11-21 07:43:34 +01:00
}
2019-12-01 08:13:19 +01:00
Lara.leftArm.animNumber = anim;
Lara.leftArm.frameBase = g_Level.Anims[anim].framePtr;
2019-11-21 07:43:34 +01:00
}
void CreateFlare(short objectNum, int thrown) // (F) (D)
2019-11-21 07:43:34 +01:00
{
2019-12-02 09:11:21 +01:00
short itemNum = CreateItem();
2019-12-01 08:13:19 +01:00
if (itemNum != NO_ITEM)
{
bool flag = false;
ITEM_INFO* item = &g_Level.Items[itemNum];
2019-12-01 08:13:19 +01:00
item->objectNumber = objectNum;
item->roomNumber = LaraItem->roomNumber;
2019-11-21 07:43:34 +01:00
2019-12-01 08:13:19 +01:00
PHD_VECTOR pos;
pos.x = -16;
pos.y = 32;
pos.z = 42;
GetLaraJointPosition(&pos, LM_LHAND);
2019-12-01 08:13:19 +01:00
item->pos.xPos = pos.x;
item->pos.yPos = pos.y;
item->pos.zPos = pos.z;
2019-12-02 09:11:21 +01:00
short roomNumber = LaraItem->roomNumber;
2019-12-01 08:13:19 +01:00
FLOOR_INFO* floor = GetFloor(pos.x, pos.y, pos.z, &roomNumber);
int collided = GetCollidedObjects(item, 0, 1, CollidedItems, CollidedMeshes, true);
2019-12-01 08:13:19 +01:00
if (collided || GetFloorHeight(floor, pos.x, pos.y, pos.z) < pos.y)
{
flag = true;
item->pos.yRot = LaraItem->pos.yRot + ANGLE(180);
2020-04-25 16:23:53 +02:00
item->pos.xPos = LaraItem->pos.xPos + (320 * phd_sin(item->pos.yRot) >> W2V_SHIFT);
item->pos.zPos = LaraItem->pos.zPos + (320 * phd_cos(item->pos.yRot) >> W2V_SHIFT);
2019-12-01 08:13:19 +01:00
item->roomNumber = LaraItem->roomNumber;
}
else
{
if (thrown)
item->pos.yRot = LaraItem->pos.yRot;
else
item->pos.yRot = LaraItem->pos.yRot - ANGLE(45);
2019-12-01 08:13:19 +01:00
item->roomNumber = roomNumber;
}
InitialiseItem(itemNum);
item->pos.zRot = 0;
item->pos.xRot = 0;
item->shade = -1;
2020-05-23 14:26:06 +02:00
2019-12-01 08:13:19 +01:00
if (thrown)
{
item->speed = LaraItem->speed + 50;
item->fallspeed = LaraItem->fallspeed - 50;
}
else
{
item->speed = LaraItem->speed + 10;
item->fallspeed = LaraItem->fallspeed + 50;
}
2020-05-23 14:26:06 +02:00
2019-12-01 08:13:19 +01:00
if (flag)
item->speed >>= 1;
if (objectNum == ID_FLARE_ITEM)
{
if (DoFlareLight((PHD_VECTOR*)&item->pos, Lara.flareAge))
item->data = (void*)(Lara.flareAge | 0x8000);
else
item->data = (void*)(Lara.flareAge & 0x7FFF);
}
else
{
item->itemFlags[3] = Lara.litTorch;
2019-12-01 08:13:19 +01:00
}
AddActiveItem(itemNum);
item->status = ITEM_ACTIVE;
}
2019-11-21 07:43:34 +01:00
}
void DrawFlareInAir(ITEM_INFO* item)
{
printf("DrawFlareInAir() not implemented !");
}
void DoFlareInHand(int flare_age) // (AF) (D)
2019-11-21 07:43:34 +01:00
{
2019-12-01 08:13:19 +01:00
PHD_VECTOR pos;
2019-11-21 07:43:34 +01:00
pos.x = 11;
pos.y = 32;
pos.z = 41;
GetLaraJointPosition(&pos, LM_LHAND);
2020-05-23 14:26:06 +02:00
if (DoFlareLight(&pos, flare_age))
TriggerChaffEffects(flare_age);
2019-11-21 07:43:34 +01:00
/* Hardcoded code */
2019-11-21 07:43:34 +01:00
2019-12-01 08:13:19 +01:00
if (Lara.flareAge >= 900)
2019-11-21 07:43:34 +01:00
{
2019-12-01 08:13:19 +01:00
if (Lara.gunStatus == LG_NO_ARMS)
Lara.gunStatus = LG_UNDRAW_GUNS;
2019-11-21 07:43:34 +01:00
}
2019-12-01 08:13:19 +01:00
else if (Lara.flareAge != 0)
2019-11-21 07:43:34 +01:00
{
2019-12-01 08:13:19 +01:00
Lara.flareAge++;
2019-11-21 07:43:34 +01:00
}
}
2019-12-02 09:11:21 +01:00
int DoFlareLight(PHD_VECTOR* pos, int age)//49708, 49B6C (F)
2019-11-21 07:43:34 +01:00
{
2019-12-02 09:11:21 +01:00
int x, y, z;
int r, g, b;
2020-05-23 14:26:06 +02:00
float random;
2019-12-02 09:11:21 +01:00
int falloff;
2019-12-01 08:13:19 +01:00
if (age >= 900 || age == 0)
2019-11-21 07:43:34 +01:00
return 0;
2020-05-23 14:26:06 +02:00
random = frand();
2019-11-21 07:43:34 +01:00
2020-05-23 14:26:06 +02:00
x = pos->x + (random* 120);
y = pos->y + (random * 120) - 256;
z = pos->z + (random * 120);
2019-11-21 07:43:34 +01:00
2019-12-01 08:13:19 +01:00
if (age < 4)
2019-11-21 07:43:34 +01:00
{
2020-05-23 14:26:06 +02:00
falloff = 12 + ((1-(age / 4.0f))*16);
r = FlareMainColor.x*255;
g = FlareMainColor.y * 255;
b = FlareMainColor.z * 255;
2019-11-21 07:43:34 +01:00
2019-12-01 08:13:19 +01:00
TriggerDynamicLight(x, y, z, falloff, r, g, b);
2020-05-23 14:26:06 +02:00
return (random < 0.9f);
2019-11-21 07:43:34 +01:00
}
2020-05-23 14:26:06 +02:00
else if (age < 810)
2019-11-21 07:43:34 +01:00
{
2020-05-23 14:26:06 +02:00
float multiplier = FlareFlickerTable[age % FlareFlickerTable.size()];
falloff = 12*multiplier;
2019-11-21 07:43:34 +01:00
2020-05-23 14:26:06 +02:00
r = FlareMainColor.x * 255 * multiplier;
g = FlareMainColor.y * 255 * multiplier;
b = FlareMainColor.z * 255 * multiplier;
2019-12-01 08:13:19 +01:00
TriggerDynamicLight(x, y, z, falloff, r, g, b);
2020-05-23 14:26:06 +02:00
return (random < 0.4f);
2019-11-21 07:43:34 +01:00
}
2020-05-23 14:26:06 +02:00
else
2019-11-21 07:43:34 +01:00
{
2020-05-23 14:26:06 +02:00
float multiplier = FlareFlickerTableLow[age % FlareFlickerTableLow.size()];
falloff = 12* (1.0f - ((age-810) / (900-810)));
r = FlareMainColor.x * 255 * multiplier;
g = FlareMainColor.y * 255 * multiplier;
b = FlareMainColor.z * 255 * multiplier;
TriggerDynamicLight(x, y, z, falloff, r, g, b);
return (random < .3f);
}
2019-11-21 07:43:34 +01:00
}