2020-05-27 09:21:20 +02:00
|
|
|
#include "framework.h"
|
2021-09-08 18:07:48 +03:00
|
|
|
#include "effects\tomb4fx.h"
|
2019-12-22 00:20:10 +01:00
|
|
|
#include "lara.h"
|
2021-09-08 18:07:48 +03:00
|
|
|
#include "effects\effects.h"
|
2021-09-16 05:06:03 +03:00
|
|
|
#include "animation.h"
|
2020-05-27 09:21:20 +02:00
|
|
|
#include "setup.h"
|
|
|
|
#include "level.h"
|
2021-09-09 13:30:49 +03:00
|
|
|
#include "gameflow.h"
|
2021-09-08 18:19:06 +03:00
|
|
|
#include "Sound\sound.h"
|
2021-09-08 18:07:48 +03:00
|
|
|
#include "effects\bubble.h"
|
2021-09-08 18:31:35 +03:00
|
|
|
#include "Specific\trmath.h"
|
2020-05-30 15:55:23 +02:00
|
|
|
#include "GameFlowScript.h"
|
2020-05-28 16:48:36 +02:00
|
|
|
#include "smoke.h"
|
2020-06-18 14:24:52 +02:00
|
|
|
#include "drip.h"
|
2020-08-09 20:29:31 +02:00
|
|
|
#include <effects.h>
|
|
|
|
#include "Renderer11.h"
|
2021-09-15 11:13:47 +03:00
|
|
|
#include "effects/effects.h"
|
|
|
|
#include "effects/weather.h"
|
2021-09-16 05:06:03 +03:00
|
|
|
#include "animation.h"
|
2021-09-25 16:00:30 +03:00
|
|
|
#include "items.h"
|
2021-09-25 11:27:47 +02:00
|
|
|
|
2020-08-09 20:29:31 +02:00
|
|
|
using std::vector;
|
2021-08-30 18:03:21 +03:00
|
|
|
using TEN::Renderer::g_Renderer;
|
2021-09-15 11:13:47 +03:00
|
|
|
using namespace TEN::Effects::Environment;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
char LaserSightActive = 0;
|
|
|
|
char LaserSightCol = 0;
|
|
|
|
int NextGunshell = 0;
|
|
|
|
|
|
|
|
int LaserSightX;
|
|
|
|
int LaserSightY;
|
|
|
|
int LaserSightZ;
|
|
|
|
|
|
|
|
int NextFireSpark = 1;
|
|
|
|
int NextSmokeSpark = 0;
|
|
|
|
int NextBubble = 0;
|
|
|
|
int NextDrip = 0;
|
|
|
|
int NextBlood = 0;
|
|
|
|
int NextGunShell = 0;
|
|
|
|
|
2019-12-27 10:50:59 +01:00
|
|
|
GUNFLASH_STRUCT Gunflashes[MAX_GUNFLASH];
|
|
|
|
FIRE_SPARKS FireSparks[MAX_SPARKS_FIRE];
|
|
|
|
SMOKE_SPARKS SmokeSparks[MAX_SPARKS_SMOKE];
|
|
|
|
GUNSHELL_STRUCT Gunshells[MAX_GUNSHELL];
|
|
|
|
BLOOD_STRUCT Blood[MAX_SPARKS_BLOOD];
|
|
|
|
DRIP_STRUCT Drips[MAX_DRIPS];
|
|
|
|
SHOCKWAVE_STRUCT ShockWaves[MAX_SHOCKWAVE];
|
2020-03-16 12:36:29 +01:00
|
|
|
FIRE_LIST Fires[MAX_FIRE_LIST];
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
int GetFreeFireSpark()
|
|
|
|
{
|
|
|
|
int sparkNum = NextFireSpark;
|
|
|
|
int minIndex = 0;
|
|
|
|
int minLife = 4095;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
FIRE_SPARKS* spark = &FireSparks[NextFireSpark];
|
|
|
|
while (spark->on)
|
|
|
|
{
|
|
|
|
if (spark->life < minLife)
|
|
|
|
{
|
|
|
|
minIndex = sparkNum;
|
|
|
|
minLife = spark->life;
|
|
|
|
}
|
2019-12-27 10:50:59 +01:00
|
|
|
if (sparkNum == MAX_SPARKS_FIRE - 1)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
spark = &FireSparks[1];
|
|
|
|
sparkNum = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sparkNum++;
|
|
|
|
spark++;
|
|
|
|
}
|
|
|
|
|
2019-12-26 19:19:20 +01:00
|
|
|
if (++i >= MAX_SPARKS_FIRE)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
NextFireSpark = minIndex + 1;
|
2019-12-26 19:19:20 +01:00
|
|
|
if (NextFireSpark >= MAX_SPARKS_FIRE)
|
2019-12-22 00:20:10 +01:00
|
|
|
NextFireSpark = 1;
|
|
|
|
return minIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NextFireSpark = sparkNum + 1;
|
2019-12-26 19:19:20 +01:00
|
|
|
if (sparkNum + 1 >= MAX_SPARKS_FIRE)
|
2019-12-22 00:20:10 +01:00
|
|
|
NextFireSpark = 1;
|
|
|
|
|
|
|
|
return sparkNum;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TriggerGlobalStaticFlame()
|
|
|
|
{
|
2019-12-22 07:35:22 +01:00
|
|
|
FIRE_SPARKS* spark = &FireSparks[0];
|
|
|
|
|
|
|
|
spark->on = true;
|
|
|
|
spark->dR = spark->sR = (GetRandomControl() & 0x3F) - 64;
|
|
|
|
spark->dB = 64;
|
|
|
|
spark->sB = 64;
|
|
|
|
spark->dG = (GetRandomControl() & 0x3F) + 96;
|
|
|
|
spark->sG = (GetRandomControl() & 0x3F) + 96;
|
|
|
|
spark->colFadeSpeed = 1;
|
|
|
|
spark->fadeToBlack = 0;
|
|
|
|
spark->life = 8;
|
|
|
|
spark->sLife = 8;
|
|
|
|
spark->y = 0;
|
|
|
|
spark->x = (GetRandomControl() & 7) - 4;
|
|
|
|
spark->maxYvel = 0;
|
|
|
|
spark->gravity = 0;
|
|
|
|
spark->z = (GetRandomControl() & 7) - 4;
|
|
|
|
spark->friction = 0;
|
|
|
|
spark->xVel = 0;
|
|
|
|
spark->yVel = 0;
|
|
|
|
spark->zVel = 0;
|
2020-05-30 15:55:23 +02:00
|
|
|
spark->flags = SP_NONE;
|
2019-12-22 07:35:22 +01:00
|
|
|
spark->dSize = spark->sSize = spark->size = (GetRandomControl() & 0x1F) + -128;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void TriggerGlobalFireSmoke()
|
|
|
|
{
|
|
|
|
FIRE_SPARKS* spark = &FireSparks[GetFreeFireSpark()];
|
|
|
|
|
|
|
|
spark->on = 1;
|
|
|
|
spark->sR = 0;
|
|
|
|
spark->sG = 0;
|
|
|
|
spark->sB = 0;
|
|
|
|
spark->dR = 32;
|
|
|
|
spark->dG = 32;
|
|
|
|
spark->dB = 32;
|
|
|
|
spark->fadeToBlack = 16;
|
|
|
|
spark->colFadeSpeed = (GetRandomControl() & 7) + 32;
|
|
|
|
spark->life = spark->sLife = (GetRandomControl() & 0xF) + 57;
|
|
|
|
spark->x = (GetRandomControl() & 0xF) - 8;
|
|
|
|
spark->y = -256 - (GetRandomControl() & 0x7F);
|
|
|
|
spark->z = (GetRandomControl() & 0xF) - 8;
|
2019-12-22 07:35:22 +01:00
|
|
|
spark->xVel = (GetRandomControl() & 0xFF) - 128;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->yVel = -16 - (GetRandomControl() & 0xF);
|
2019-12-22 07:35:22 +01:00
|
|
|
spark->zVel = (GetRandomControl() & 0xFF) - 128;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->friction = 4;
|
|
|
|
|
|
|
|
if (GetRandomControl() & 1)
|
|
|
|
{
|
|
|
|
spark->flags = 16;
|
|
|
|
spark->rotAng = GetRandomControl() & 0xFFF;
|
|
|
|
if (GetRandomControl() & 1)
|
|
|
|
spark->rotAdd = -16 - (GetRandomControl() & 0xF);
|
|
|
|
else
|
|
|
|
spark->rotAdd = (GetRandomControl() & 0xF) + 16;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-05-30 15:55:23 +02:00
|
|
|
spark->flags = SP_NONE;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
spark->gravity = -16 - (GetRandomControl() & 0xF);
|
|
|
|
spark->maxYvel = -8 - (GetRandomControl() & 7);
|
|
|
|
spark->dSize = spark->sSize = spark->size = (GetRandomControl() & 0x7F) + 128;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TriggerGlobalFireFlame()
|
|
|
|
{
|
|
|
|
FIRE_SPARKS* spark = &FireSparks[GetFreeFireSpark()];
|
|
|
|
|
2019-12-22 07:35:22 +01:00
|
|
|
spark->on = true;
|
|
|
|
spark->sR = 255;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->sB = 48;
|
|
|
|
spark->sG = (GetRandomControl() & 0x1F) + 48;
|
|
|
|
spark->dR = (GetRandomControl() & 0x3F) - 64;
|
|
|
|
spark->dB = 32;
|
|
|
|
spark->dG = (GetRandomControl() & 0x3F) + -128;
|
|
|
|
spark->fadeToBlack = 8;
|
|
|
|
spark->colFadeSpeed = (GetRandomControl() & 3) + 8;
|
|
|
|
spark->life = spark->sLife = (GetRandomControl() & 7) + 32;
|
|
|
|
spark->y = 0;
|
|
|
|
spark->x = 4 * (GetRandomControl() & 0x1F) - 64;
|
|
|
|
spark->z = 4 * (GetRandomControl() & 0x1F) - 64;
|
2019-12-22 07:35:22 +01:00
|
|
|
spark->xVel = 2 * (GetRandomControl() & 0xFF) - 256;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->yVel = -16 - (GetRandomControl() & 0xF);
|
2019-12-22 07:35:22 +01:00
|
|
|
spark->zVel = 2 * (GetRandomControl() & 0xFF) - 256;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->friction = 5;
|
|
|
|
spark->gravity = -32 - (GetRandomControl() & 0x1F);
|
|
|
|
spark->maxYvel = -16 - (GetRandomControl() & 7);
|
|
|
|
|
|
|
|
if (GetRandomControl() & 1)
|
|
|
|
{
|
|
|
|
spark->flags = 16;
|
|
|
|
spark->rotAng = GetRandomControl() & 0xFFF;
|
|
|
|
if (GetRandomControl() & 1)
|
|
|
|
spark->rotAdd = -16 - (GetRandomControl() & 0xF);
|
|
|
|
else
|
|
|
|
spark->rotAdd = (GetRandomControl() & 0xF) + 16;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-05-30 15:55:23 +02:00
|
|
|
spark->flags = SP_NONE;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
spark->sSize = spark->size = (GetRandomControl() & 0x1F) + 128;
|
2020-05-27 17:19:16 +02:00
|
|
|
spark->dSize = spark->size;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void keep_those_fires_burning()
|
|
|
|
{
|
|
|
|
TriggerGlobalStaticFlame();
|
|
|
|
if (!(Wibble & 0xF))
|
|
|
|
{
|
|
|
|
TriggerGlobalFireFlame();
|
|
|
|
if (!(Wibble & 0x1F))
|
|
|
|
TriggerGlobalFireSmoke();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddFire(int x, int y, int z, char size, short roomNum, short on)
|
|
|
|
{
|
|
|
|
FIRE_LIST* fptr = &Fires[0];
|
|
|
|
int i = 0;
|
|
|
|
while (fptr->on)
|
|
|
|
{
|
|
|
|
fptr++;
|
2019-12-26 19:19:20 +01:00
|
|
|
if (++i >= MAX_FIRE_LIST)
|
2019-12-22 00:20:10 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (on)
|
|
|
|
fptr->on = on;
|
|
|
|
else
|
2020-08-21 10:56:03 +02:00
|
|
|
fptr->on = 1;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
fptr->x = x;
|
|
|
|
fptr->y = y;
|
|
|
|
fptr->z = z;
|
|
|
|
fptr->roomNumber = roomNum;
|
2021-08-02 19:42:07 +03:00
|
|
|
|
|
|
|
switch (size)
|
|
|
|
{
|
|
|
|
case SP_NORMALFIRE:
|
|
|
|
fptr->size = 1;
|
|
|
|
break;
|
|
|
|
case SP_SMALLFIRE:
|
|
|
|
fptr->size = 2;
|
|
|
|
break;
|
|
|
|
case SP_BIGFIRE:
|
|
|
|
fptr->size = 3;
|
|
|
|
break;
|
|
|
|
}
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void ClearFires()
|
|
|
|
{
|
2019-12-26 19:19:20 +01:00
|
|
|
for (int i = 0; i < MAX_FIRE_LIST; i++)
|
2019-12-22 00:20:10 +01:00
|
|
|
Fires[i].on = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void UpdateFireSparks()
|
|
|
|
{
|
|
|
|
keep_those_fires_burning();
|
|
|
|
|
2019-12-26 19:19:20 +01:00
|
|
|
for (int i = 0; i < MAX_SPARKS_FIRE; i++)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
FIRE_SPARKS* spark = &FireSparks[i];
|
|
|
|
|
|
|
|
if (spark->on)
|
|
|
|
{
|
|
|
|
spark->life--;
|
|
|
|
|
|
|
|
if (!spark->life)
|
|
|
|
{
|
|
|
|
spark->on = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (spark->sLife - spark->life < spark->colFadeSpeed)
|
|
|
|
{
|
2021-08-30 15:13:18 -05:00
|
|
|
int dl = ((spark->sLife - spark->life) << 16) / spark->colFadeSpeed;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
2021-08-30 15:13:18 -05:00
|
|
|
spark->r = spark->sR + (dl * (spark->dR - spark->sR) >> 16);
|
|
|
|
spark->g = spark->sG + (dl * (spark->dG - spark->sG) >> 16);
|
|
|
|
spark->b = spark->sB + (dl * (spark->dB - spark->sB) >> 16);
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
else if (spark->life >= spark->fadeToBlack)
|
|
|
|
{
|
|
|
|
spark->r = spark->dR;
|
|
|
|
spark->g = spark->dG;
|
|
|
|
spark->b = spark->dB;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-08-30 15:13:18 -05:00
|
|
|
int dl = ((spark->life - spark->fadeToBlack) << 16) / spark->fadeToBlack + 0x10000;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
2021-08-30 15:13:18 -05:00
|
|
|
spark->r = dl * spark->dR >> 16;
|
|
|
|
spark->g = dl * spark->dG >> 16;
|
|
|
|
spark->b = dl * spark->dB >> 16;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
2019-12-22 07:35:22 +01:00
|
|
|
if (spark->r < 8 && spark->g < 8 && spark->b < 8)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
spark->on = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (spark->flags & SP_ROTATE)
|
|
|
|
spark->rotAng = (spark->rotAng + spark->rotAdd) & 0xFFF;
|
2020-05-27 17:19:16 +02:00
|
|
|
float alpha = fmin(1, fmax(0, 1 - (spark->life / (float)spark->sLife)));
|
|
|
|
int sprite = lerp(Objects[ID_FIRE_SPRITES].meshIndex, Objects[ID_FIRE_SPRITES].meshIndex+ (-Objects[ID_FIRE_SPRITES].nmeshes) - 1, alpha);
|
|
|
|
spark->def = sprite;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
2021-08-30 15:13:18 -05:00
|
|
|
int dl = ((spark->sLife - spark->life) << 16) / spark->sLife;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->yVel += spark->gravity;
|
|
|
|
if (spark->maxYvel)
|
|
|
|
{
|
2021-08-30 15:13:18 -05:00
|
|
|
if ((spark->yVel < 0 && spark->yVel < (spark->maxYvel << 5)) ||
|
|
|
|
(spark->yVel > 0 && spark->yVel > (spark->maxYvel << 5)))
|
|
|
|
spark->yVel = spark->maxYvel << 5;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (spark->friction)
|
|
|
|
{
|
|
|
|
spark->xVel -= spark->xVel >> spark->friction;
|
|
|
|
spark->zVel -= spark->zVel >> spark->friction;
|
|
|
|
}
|
|
|
|
|
2021-08-02 19:42:07 +03:00
|
|
|
spark->x += spark->xVel / 48;
|
|
|
|
spark->y += spark->yVel / 48;
|
|
|
|
spark->z += spark->zVel / 48;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
2020-10-16 12:06:33 -05:00
|
|
|
spark->size = spark->sSize + ((dl * (spark->dSize - spark->sSize)) / 65536);
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-27 10:50:59 +01:00
|
|
|
int GetFreeSmokeSpark()
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
SMOKE_SPARKS* spark = &SmokeSparks[NextSmokeSpark];
|
|
|
|
int sparkNum = NextSmokeSpark;
|
|
|
|
short minLife = 4095;
|
|
|
|
short minIndex = 0;
|
|
|
|
short count = 0;
|
|
|
|
while (spark->on)
|
|
|
|
{
|
|
|
|
if (spark->life < minLife)
|
|
|
|
{
|
|
|
|
minIndex = sparkNum;
|
|
|
|
minLife = spark->life;
|
|
|
|
}
|
|
|
|
|
2019-12-27 10:50:59 +01:00
|
|
|
if (sparkNum == MAX_SPARKS_SMOKE - 1)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
spark = &SmokeSparks[0];
|
|
|
|
sparkNum = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sparkNum++;
|
|
|
|
spark++;
|
|
|
|
}
|
|
|
|
|
2019-12-26 19:19:20 +01:00
|
|
|
if (++count >= MAX_SPARKS_SMOKE)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
2019-12-26 19:19:20 +01:00
|
|
|
NextSmokeSpark = (minIndex + 1) % MAX_SPARKS_SMOKE;
|
2019-12-22 00:20:10 +01:00
|
|
|
return minIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-26 19:19:20 +01:00
|
|
|
NextSmokeSpark = (sparkNum + 1) % MAX_SPARKS_SMOKE;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
return sparkNum;
|
|
|
|
}
|
|
|
|
|
|
|
|
void UpdateSmoke()
|
|
|
|
{
|
2019-12-26 19:19:20 +01:00
|
|
|
for (int i = 0; i < MAX_SPARKS_SMOKE; i++)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
SMOKE_SPARKS* spark = &SmokeSparks[i];
|
|
|
|
|
|
|
|
if (spark->on)
|
|
|
|
{
|
2019-12-27 10:50:59 +01:00
|
|
|
spark->life -= 2;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
if (spark->life <= 0)
|
|
|
|
{
|
|
|
|
spark->on = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (spark->sLife - spark->life >= spark->colFadeSpeed)
|
|
|
|
{
|
|
|
|
if (spark->life >= spark->fadeToBlack)
|
|
|
|
{
|
|
|
|
spark->shade = spark->dShade;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-08-30 15:13:18 -05:00
|
|
|
spark->shade = spark->dShade * (((spark->life - spark->fadeToBlack) << 16) / spark->fadeToBlack + 0x10000) >> 16;
|
2019-12-22 00:20:10 +01:00
|
|
|
if (spark->shade < 8)
|
|
|
|
{
|
|
|
|
spark->on = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-08-30 15:13:18 -05:00
|
|
|
spark->shade = spark->sShade + ((spark->dShade - spark->sShade) * (((spark->sLife - spark->life) << 16) / spark->colFadeSpeed) >> 16);
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (spark->shade >= 24)
|
|
|
|
{
|
|
|
|
if (spark->shade >= 80)
|
2020-03-27 07:17:05 +01:00
|
|
|
spark->def = Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_FIRE0;
|
2019-12-22 00:20:10 +01:00
|
|
|
else
|
2020-03-27 07:17:05 +01:00
|
|
|
spark->def = Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_FIRE1;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-03-27 07:17:05 +01:00
|
|
|
spark->def = Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_FIRE2;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (spark->flags & SP_ROTATE)
|
|
|
|
spark->rotAng = (spark->rotAng + spark->rotAdd) & 0xFFF;
|
|
|
|
|
2021-08-30 15:13:18 -05:00
|
|
|
int dl = ((spark->sLife - spark->life) << 16) / spark->sLife;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
2020-03-27 07:17:05 +01:00
|
|
|
spark->yVel += spark->gravity;
|
2019-12-28 00:12:38 +01:00
|
|
|
|
|
|
|
if (spark->maxYvel != 0)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
2020-03-27 07:17:05 +01:00
|
|
|
if (spark->yVel < 0)
|
|
|
|
{
|
|
|
|
if (spark->yVel < spark->maxYvel)
|
|
|
|
{
|
|
|
|
spark->yVel = spark->maxYvel;
|
2019-12-28 00:12:38 +01:00
|
|
|
}
|
|
|
|
}
|
2020-03-27 07:17:05 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (spark->yVel > spark->maxYvel)
|
|
|
|
{
|
|
|
|
spark->yVel = spark->maxYvel;
|
2019-12-28 00:12:38 +01:00
|
|
|
}
|
|
|
|
}
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
|
2020-03-27 07:17:05 +01:00
|
|
|
if (spark->friction & 0xF)
|
|
|
|
{
|
|
|
|
spark->xVel -= spark->xVel >> (spark->friction & 0xF);
|
|
|
|
spark->zVel -= spark->zVel >> (spark->friction & 0xF);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (spark->friction & 0xF0)
|
|
|
|
{
|
2021-08-30 15:13:18 -05:00
|
|
|
spark->yVel -= spark->yVel >> (spark->friction >> 4);
|
2020-03-27 07:17:05 +01:00
|
|
|
}
|
|
|
|
|
2021-08-30 15:13:18 -05:00
|
|
|
spark->x += spark->xVel >> 5;
|
|
|
|
spark->y += spark->yVel >> 5;
|
|
|
|
spark->z += spark->zVel >> 5;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
if (spark->flags & SP_WIND)
|
|
|
|
{
|
2021-09-15 11:13:47 +03:00
|
|
|
spark->x += Weather.Wind().x;
|
|
|
|
spark->z += Weather.Wind().z;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
|
2021-08-30 15:13:18 -05:00
|
|
|
spark->size = spark->sSize + (dl * (spark->dSize - spark->sSize) >> 16);
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
byte TriggerGunSmoke_SubFunction(int weaponType)
|
|
|
|
{
|
|
|
|
switch (weaponType)
|
|
|
|
{
|
|
|
|
case WEAPON_HK:
|
|
|
|
case WEAPON_ROCKET_LAUNCHER:
|
|
|
|
case WEAPON_GRENADE_LAUNCHER:
|
2020-05-30 15:55:23 +02:00
|
|
|
return 24; //(12) Rocket and Grenade value for TriggerGunSmoke in TR3 have the value 12 ! (the HK is not included there)
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
// other weapon
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TriggerGunSmoke(int x, int y, int z, short xv, short yv, short zv, byte initial, int weaponType, byte count)
|
|
|
|
{
|
2020-05-28 16:48:36 +02:00
|
|
|
/*
|
2019-12-22 00:20:10 +01:00
|
|
|
SMOKE_SPARKS* spark;
|
2019-12-27 10:50:59 +01:00
|
|
|
|
2019-12-22 00:20:10 +01:00
|
|
|
spark = &SmokeSparks[GetFreeSmokeSpark()];
|
|
|
|
spark->on = true;
|
|
|
|
spark->sShade = 0;
|
|
|
|
spark->dShade = (count << 2);
|
|
|
|
spark->colFadeSpeed = 4;
|
|
|
|
spark->fadeToBlack = 32 - (initial << 4);
|
|
|
|
spark->life = (GetRandomControl() & 3) + 40;
|
|
|
|
spark->sLife = spark->life;
|
|
|
|
|
|
|
|
if (weaponType == WEAPON_PISTOLS || weaponType == WEAPON_REVOLVER || weaponType == WEAPON_UZI)
|
|
|
|
{
|
|
|
|
if (spark->dShade > 64)
|
|
|
|
spark->dShade = 64;
|
|
|
|
}
|
|
|
|
|
2021-10-27 19:00:30 +03:00
|
|
|
spark->transType = TransTypeEnum::COLADD;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->x = x + (GetRandomControl() & 31) - 16;
|
|
|
|
spark->y = y + (GetRandomControl() & 31) - 16;
|
|
|
|
spark->z = z + (GetRandomControl() & 31) - 16;
|
|
|
|
|
|
|
|
if (initial)
|
|
|
|
{
|
|
|
|
spark->xVel = ((GetRandomControl() & 1023) - 512) + xv;
|
|
|
|
spark->yVel = ((GetRandomControl() & 1023) - 512) + yv;
|
|
|
|
spark->zVel = ((GetRandomControl() & 1023) - 512) + zv;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-12-28 00:12:38 +01:00
|
|
|
float f = (frand() * 6) - 3;
|
|
|
|
spark->xVel = (frand() * 6) - 3;
|
|
|
|
spark->yVel = (frand() * 6) - 3;
|
|
|
|
spark->zVel = (frand() * 6) - 3;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
spark->friction = 4;
|
|
|
|
|
|
|
|
if (GetRandomControl() & 1)
|
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
if (g_Level.Rooms[LaraItem->roomNumber].flags & ENV_FLAG_WIND)
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->flags = SP_ROTATE | SP_WIND;
|
|
|
|
else
|
|
|
|
spark->flags = SP_ROTATE;
|
|
|
|
|
2019-12-27 10:50:59 +01:00
|
|
|
spark->rotAng = GetRandomControl() & 0xFFF;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
if (GetRandomControl() & 1)
|
2019-12-27 10:50:59 +01:00
|
|
|
spark->rotAdd = -(GetRandomControl() & 0x0F) - 16;
|
2019-12-22 00:20:10 +01:00
|
|
|
else
|
2019-12-27 10:50:59 +01:00
|
|
|
spark->rotAdd = (GetRandomControl() & 0x0F) + 16;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
2020-07-21 09:56:47 +02:00
|
|
|
else if (g_Level.Rooms[LaraItem->roomNumber].flags & ENV_FLAG_WIND)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
spark->flags = SP_WIND;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-05-30 15:55:23 +02:00
|
|
|
spark->flags = SP_NONE;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
2019-12-28 00:12:38 +01:00
|
|
|
float gravity = frand() * 1.25f;
|
|
|
|
spark->gravity = gravity;
|
|
|
|
spark->maxYvel = frand() * 16;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
2019-12-27 10:50:59 +01:00
|
|
|
byte size = ((GetRandomControl() & 0x0F) + 24); // -TriggerGunSmoke_SubFunction(weaponType);
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
if (initial)
|
|
|
|
{
|
|
|
|
spark->sSize = size >> 1;
|
|
|
|
spark->size = size >> 1;
|
|
|
|
spark->dSize = (size << 1) + 8;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
spark->sSize = size >> 2;
|
|
|
|
spark->size = size >> 2;
|
|
|
|
spark->dSize = size;
|
|
|
|
}
|
|
|
|
|
2020-04-09 14:19:18 +02:00
|
|
|
/*if (gfLevelFlags & 0x20 && LaraItem->roomNumber == gfMirrorRoom) // 0x20 = GF_MIRROR_ENABLED
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
spark->mirror = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
spark->mirror = 0;
|
|
|
|
}*/
|
2021-08-30 18:03:21 +03:00
|
|
|
TEN::Effects::Smoke::TriggerGunSmokeParticles(x, y, z, xv, yv, zv, initial, weaponType, count);
|
2020-05-28 16:48:36 +02:00
|
|
|
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void TriggerShatterSmoke(int x, int y, int z)
|
|
|
|
{
|
|
|
|
SMOKE_SPARKS* spark = &SmokeSparks[GetFreeSmokeSpark()];
|
|
|
|
|
|
|
|
spark->on = true;
|
|
|
|
spark->sShade = 0;
|
|
|
|
spark->colFadeSpeed = 4;
|
|
|
|
spark->dShade = (GetRandomControl() & 0x1F) + 64;
|
|
|
|
spark->fadeToBlack = 24 - (GetRandomControl() & 7);
|
2021-10-27 19:00:30 +03:00
|
|
|
spark->transType = TransTypeEnum::COLADD;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->life = spark->sLife = (GetRandomControl() & 7) + 48;
|
|
|
|
spark->x = (GetRandomControl() & 0x1F) + x - 16;
|
|
|
|
spark->y = (GetRandomControl() & 0x1F) + y - 16;
|
|
|
|
spark->z = (GetRandomControl() & 0x1F) + z - 16;
|
|
|
|
spark->xVel = 2 * (GetRandomControl() & 0x1FF) - 512;
|
|
|
|
spark->yVel = 2 * (GetRandomControl() & 0x1FF) - 512;
|
|
|
|
spark->zVel = 2 * (GetRandomControl() & 0x1FF) - 512;
|
|
|
|
spark->friction = 7;
|
|
|
|
|
|
|
|
if (GetRandomControl() & 1)
|
|
|
|
{
|
|
|
|
spark->flags = SP_ROTATE;
|
|
|
|
spark->rotAng = GetRandomControl() & 0xFFF;
|
|
|
|
if (GetRandomControl() & 1)
|
|
|
|
spark->rotAdd = -64 - (GetRandomControl() & 0x3F);
|
|
|
|
else
|
|
|
|
spark->rotAdd = (GetRandomControl() & 0x3F) + 64;
|
|
|
|
}
|
2020-07-21 09:56:47 +02:00
|
|
|
else if (g_Level.Rooms[LaraItem->roomNumber].flags & ENV_FLAG_WIND)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
spark->flags = SP_WIND;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-05-30 15:55:23 +02:00
|
|
|
spark->flags = SP_NONE;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
spark->gravity = -4 - (GetRandomControl() & 3);
|
|
|
|
spark->maxYvel = -4 - (GetRandomControl() & 3);
|
|
|
|
spark->dSize = (GetRandomControl() & 0x3F) + 64;
|
2021-08-30 15:13:18 -05:00
|
|
|
spark->sSize = spark->dSize >> 3;
|
|
|
|
spark->size = spark->dSize >> 3;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
|
2021-02-03 01:50:59 -03:00
|
|
|
int GetFreeBlood()
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
BLOOD_STRUCT* blood = &Blood[NextBlood];
|
|
|
|
int bloodNum = NextBlood;
|
|
|
|
int minLife = 4095;
|
|
|
|
int minIndex = 0;
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
while (blood->on)
|
|
|
|
{
|
|
|
|
if (blood->life < minLife)
|
|
|
|
{
|
|
|
|
minIndex = bloodNum;
|
|
|
|
minLife = blood->life;
|
|
|
|
}
|
|
|
|
|
2019-12-27 10:50:59 +01:00
|
|
|
if (bloodNum == MAX_SPARKS_BLOOD - 1)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
blood = &Blood[0];
|
|
|
|
bloodNum = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
blood++;
|
|
|
|
bloodNum++;
|
|
|
|
}
|
|
|
|
|
2019-12-26 19:19:20 +01:00
|
|
|
if (++count >= MAX_SPARKS_BLOOD)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
NextBlood = (minIndex + 1) & 31;
|
|
|
|
return minIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NextBlood = (bloodNum + 1) & 31;
|
|
|
|
return bloodNum;
|
|
|
|
}
|
|
|
|
|
2021-02-03 01:50:59 -03:00
|
|
|
void TriggerBlood(int x, int y, int z, int unk, int num)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
for (int i = 0; i < num; i++)
|
|
|
|
{
|
|
|
|
BLOOD_STRUCT* blood = &Blood[GetFreeBlood()];
|
|
|
|
blood->on = 1;
|
|
|
|
blood->sShade = 0;
|
|
|
|
blood->colFadeSpeed = 4;
|
|
|
|
blood->fadeToBlack = 8;
|
|
|
|
blood->dShade = (GetRandomControl() & 0x3F) + 48;
|
|
|
|
blood->life = blood->sLife = (GetRandomControl() & 7) + 24;
|
|
|
|
blood->x = (GetRandomControl() & 0x1F) + x - 16;
|
|
|
|
blood->y = (GetRandomControl() & 0x1F) + y - 16;
|
|
|
|
blood->z = (GetRandomControl() & 0x1F) + z - 16;
|
2020-09-30 12:37:06 -03:00
|
|
|
int a = (unk == -1 ? GetRandomControl() : (GetRandomControl() & 0x1F) + unk - 16) & 0xFFF;
|
2019-12-22 00:20:10 +01:00
|
|
|
int b = GetRandomControl() & 0xF;
|
2021-08-30 15:13:18 -05:00
|
|
|
blood->zVel = b * phd_cos(a << 4) * 32;
|
|
|
|
blood->xVel = -b * phd_sin(a << 4) * 32;
|
2019-12-22 00:20:10 +01:00
|
|
|
blood->friction = 4;
|
|
|
|
blood->yVel = -((GetRandomControl() & 0xFF) + 128);
|
|
|
|
blood->rotAng = GetRandomControl() & 0xFFF;
|
|
|
|
blood->rotAdd = (GetRandomControl() & 0x3F) + 64;
|
|
|
|
if (GetRandomControl() & 1)
|
|
|
|
blood->rotAdd = -blood->rotAdd;
|
|
|
|
blood->gravity = (GetRandomControl() & 0x1F) + 31;
|
|
|
|
int size = (GetRandomControl() & 7) + 8;
|
|
|
|
blood->sSize = blood->size = size;
|
2021-08-30 15:13:18 -05:00
|
|
|
blood->dSize = size >> 2;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UpdateBlood()
|
|
|
|
{
|
2019-12-26 19:19:20 +01:00
|
|
|
for (int i = 0; i < MAX_SPARKS_BLOOD; i++)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
BLOOD_STRUCT* blood = &Blood[i];
|
|
|
|
|
|
|
|
if (blood->on)
|
|
|
|
{
|
|
|
|
blood->life--;
|
|
|
|
|
|
|
|
if (blood->life <= 0)
|
|
|
|
{
|
|
|
|
blood->on = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (blood->sLife - blood->life >= blood->colFadeSpeed)
|
|
|
|
{
|
|
|
|
if (blood->life >= blood->fadeToBlack)
|
|
|
|
{
|
|
|
|
blood->shade = blood->dShade;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-08-30 15:13:18 -05:00
|
|
|
blood->shade = blood->dShade * (((blood->life - blood->fadeToBlack) << 16) / blood->fadeToBlack + 0x10000) >> 16;
|
2019-12-22 00:20:10 +01:00
|
|
|
if (blood->shade < 8)
|
|
|
|
{
|
|
|
|
blood->on = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-08-30 15:13:18 -05:00
|
|
|
blood->shade = blood->sShade + ((blood->dShade - blood->sShade) * (((blood->sLife - blood->life) << 16) / blood->colFadeSpeed) >> 16);
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
blood->rotAng = (blood->rotAng + blood->rotAdd) & 0xFFF;
|
|
|
|
blood->yVel += blood->gravity;
|
|
|
|
|
|
|
|
if (blood->friction & 0xF)
|
|
|
|
{
|
|
|
|
blood->xVel -= blood->xVel >> (blood->friction & 0xF);
|
|
|
|
blood->zVel -= blood->zVel >> (blood->friction & 0xF);
|
|
|
|
}
|
|
|
|
|
2021-08-30 15:13:18 -05:00
|
|
|
int dl = ((blood->sLife - blood->life) << 16) / blood->sLife;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
2021-08-30 15:13:18 -05:00
|
|
|
blood->x += blood->xVel >> 5;
|
|
|
|
blood->y += blood->yVel >> 5;
|
|
|
|
blood->z += blood->zVel >> 5;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
2021-08-30 15:13:18 -05:00
|
|
|
blood->size = blood->sSize + (dl * (blood->dSize - blood->sSize) >> 16);
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int GetFreeGunshell()
|
|
|
|
{
|
|
|
|
int gsNum = NextGunShell;
|
|
|
|
int minLife = 4095;
|
|
|
|
int minIndex = 0;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
GUNSHELL_STRUCT* gs = &Gunshells[NextGunShell];
|
|
|
|
|
|
|
|
if (!gs->counter)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (gs->counter < minLife)
|
|
|
|
{
|
|
|
|
minLife = gs->counter;
|
|
|
|
minIndex = gsNum;
|
|
|
|
}
|
2019-12-27 10:50:59 +01:00
|
|
|
if (gsNum == MAX_GUNSHELL - 1)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
gs = &Gunshells[0];
|
|
|
|
gsNum = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gsNum++;
|
|
|
|
gs++;
|
|
|
|
}
|
|
|
|
|
2019-12-26 19:19:20 +01:00
|
|
|
if (++i >= MAX_GUNSHELL)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
NextGunShell = minIndex + 1;
|
2019-12-26 19:19:20 +01:00
|
|
|
if (minIndex + 1 >= MAX_GUNSHELL)
|
2019-12-22 00:20:10 +01:00
|
|
|
NextGunShell = 0;
|
|
|
|
return minIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NextGunShell = gsNum + 1;
|
2019-12-26 19:19:20 +01:00
|
|
|
if (gsNum + 1 >= MAX_GUNSHELL)
|
2019-12-22 00:20:10 +01:00
|
|
|
NextGunShell = 0;
|
|
|
|
|
|
|
|
return gsNum;
|
|
|
|
}
|
|
|
|
|
2021-08-11 15:18:22 +03:00
|
|
|
void TriggerGunShell(short hand, short objNum, LARA_WEAPON_TYPE weaponType)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
PHD_VECTOR pos;
|
|
|
|
|
|
|
|
if (hand)
|
|
|
|
{
|
|
|
|
switch (weaponType)
|
|
|
|
{
|
|
|
|
case WEAPON_PISTOLS:
|
|
|
|
pos.x = 8;
|
|
|
|
pos.y = 48;
|
|
|
|
pos.z = 40;
|
|
|
|
break;
|
|
|
|
case WEAPON_UZI:
|
|
|
|
pos.x = 8;
|
|
|
|
pos.y = 35;
|
|
|
|
pos.z = 48;
|
|
|
|
break;
|
|
|
|
case WEAPON_SHOTGUN:
|
|
|
|
pos.x = 16;
|
|
|
|
pos.y = 114;
|
|
|
|
pos.z = 32;
|
|
|
|
break;
|
|
|
|
case WEAPON_HK:
|
|
|
|
pos.x = 16;
|
|
|
|
pos.y = 114;
|
|
|
|
pos.z = 96;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-04-29 06:43:53 +02:00
|
|
|
GetLaraJointPosition(&pos, LM_RHAND);
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (weaponType == WEAPON_PISTOLS)
|
|
|
|
{
|
|
|
|
pos.x = -12;
|
|
|
|
pos.y = 48;
|
|
|
|
pos.z = 40;
|
|
|
|
|
2020-04-29 06:43:53 +02:00
|
|
|
GetLaraJointPosition(&pos, LM_LHAND);
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
else if (weaponType == WEAPON_UZI)
|
|
|
|
{
|
|
|
|
pos.x = -16;
|
|
|
|
pos.y = 35;
|
|
|
|
pos.z = 48;
|
|
|
|
|
2020-04-29 06:43:53 +02:00
|
|
|
GetLaraJointPosition(&pos, LM_LHAND);
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GUNSHELL_STRUCT* gshell = &Gunshells[GetFreeGunshell()];
|
|
|
|
|
|
|
|
gshell->pos.xPos = pos.x;
|
|
|
|
gshell->pos.yPos = pos.y;
|
|
|
|
gshell->pos.zPos = pos.z;
|
|
|
|
gshell->pos.xRot = 0;
|
|
|
|
gshell->pos.yRot = 0;
|
|
|
|
gshell->pos.zRot = GetRandomControl();
|
|
|
|
gshell->roomNumber = LaraItem->roomNumber;
|
|
|
|
gshell->speed = (GetRandomControl() & 0x1F) + 16;
|
|
|
|
gshell->fallspeed = -48 - (GetRandomControl() & 7);
|
|
|
|
gshell->objectNumber = objNum;
|
|
|
|
gshell->counter = (GetRandomControl() & 0x1F) + 60;
|
|
|
|
if (hand)
|
|
|
|
{
|
|
|
|
if (weaponType == WEAPON_SHOTGUN)
|
|
|
|
{
|
|
|
|
gshell->dirXrot = Lara.leftArm.yRot
|
|
|
|
+ Lara.torsoYrot
|
|
|
|
+ LaraItem->pos.yRot
|
|
|
|
- (GetRandomControl() & 0xFFF)
|
|
|
|
+ 10240;
|
|
|
|
gshell->pos.yRot += Lara.leftArm.yRot
|
|
|
|
+ Lara.torsoYrot
|
|
|
|
+ LaraItem->pos.yRot;
|
|
|
|
if (gshell->speed < 24)
|
|
|
|
gshell->speed += 24;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gshell->dirXrot = Lara.leftArm.yRot
|
|
|
|
+ LaraItem->pos.yRot
|
|
|
|
- (GetRandomControl() & 0xFFF)
|
|
|
|
+ 18432;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gshell->dirXrot = Lara.leftArm.yRot
|
|
|
|
+ LaraItem->pos.yRot
|
|
|
|
+ (GetRandomControl() & 0xFFF)
|
|
|
|
- 18432;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (LaraItem->meshBits)
|
|
|
|
{
|
|
|
|
if (weaponType == WEAPON_SHOTGUN)
|
|
|
|
TriggerGunSmoke(pos.x, pos.y, pos.z, 0, 0, 0, 0, WEAPON_SHOTGUN, 24);
|
|
|
|
else
|
|
|
|
TriggerGunSmoke(pos.x, pos.y, pos.z, 0, 0, 0, 0, weaponType, 16);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UpdateGunShells()
|
|
|
|
{
|
2019-12-26 19:19:20 +01:00
|
|
|
for (int i = 0; i < MAX_GUNSHELL; i++)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
GUNSHELL_STRUCT* gs = &Gunshells[i];
|
|
|
|
|
|
|
|
if (gs->counter)
|
|
|
|
{
|
|
|
|
int oldX = gs->pos.xPos;
|
|
|
|
int oldY = gs->pos.yPos;
|
|
|
|
int oldZ = gs->pos.zPos;
|
|
|
|
|
|
|
|
gs->counter--;
|
|
|
|
|
|
|
|
short oldRoomNumber = gs->roomNumber;
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
if (g_Level.Rooms[gs->roomNumber].flags & ENV_FLAG_WATER)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
gs->fallspeed++;
|
|
|
|
|
|
|
|
if (gs->fallspeed <= 8)
|
|
|
|
{
|
|
|
|
if (gs->fallspeed < 0)
|
2021-08-30 15:13:18 -05:00
|
|
|
gs->fallspeed >>= 1;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gs->fallspeed = 8;
|
|
|
|
}
|
2021-08-30 15:13:18 -05:00
|
|
|
gs->speed -= gs->speed >> 1;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gs->fallspeed += 6;
|
|
|
|
}
|
|
|
|
|
2021-08-30 15:13:18 -05:00
|
|
|
gs->pos.xRot += (gs->speed >> 1 + 7) * ANGLE(1);
|
2019-12-22 00:20:10 +01:00
|
|
|
gs->pos.yRot += gs->speed * ANGLE(1);
|
|
|
|
gs->pos.zRot += ANGLE(23);
|
|
|
|
|
2020-10-05 22:24:57 -03:00
|
|
|
gs->pos.xPos += gs->speed * phd_sin(gs->dirXrot);
|
2019-12-22 00:20:10 +01:00
|
|
|
gs->pos.yPos += gs->fallspeed;
|
2020-10-05 22:24:57 -03:00
|
|
|
gs->pos.zPos += gs->speed * phd_cos(gs->dirXrot);
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
FLOOR_INFO* floor = GetFloor(gs->pos.xPos, gs->pos.yPos, gs->pos.zPos, &gs->roomNumber);
|
2020-07-21 09:56:47 +02:00
|
|
|
if (g_Level.Rooms[gs->roomNumber].flags & ENV_FLAG_WATER
|
|
|
|
&& !(g_Level.Rooms[oldRoomNumber].flags & ENV_FLAG_WATER))
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
2020-06-18 14:24:52 +02:00
|
|
|
|
2021-08-30 18:03:21 +03:00
|
|
|
TEN::Effects::Drip::SpawnGunshellDrips(Vector3(gs->pos.xPos, g_Level.Rooms[gs->roomNumber].maxceiling, gs->pos.zPos), gs->roomNumber);
|
2020-07-21 09:56:47 +02:00
|
|
|
//AddWaterSparks(gs->pos.xPos, g_Level.Rooms[gs->roomNumber].maxceiling, gs->pos.zPos, 8);
|
2020-09-21 15:20:51 +02:00
|
|
|
SetupRipple(gs->pos.xPos, g_Level.Rooms[gs->roomNumber].maxceiling, gs->pos.zPos, (GetRandomControl() & 3) + 8, 2, Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_RIPPLES);
|
2021-08-30 15:13:18 -05:00
|
|
|
gs->fallspeed >>= 5;
|
2019-12-22 00:20:10 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ceiling = GetCeiling(floor, gs->pos.xPos, gs->pos.yPos, gs->pos.zPos);
|
|
|
|
if (gs->pos.yPos < ceiling)
|
|
|
|
{
|
2021-05-26 06:04:32 +02:00
|
|
|
SoundEffect(SFX_TR4_LARA_SHOTGUN_SHELL, &gs->pos, 0);
|
2019-12-22 00:20:10 +01:00
|
|
|
gs->speed -= 4;
|
|
|
|
|
|
|
|
if (gs->speed < 8)
|
|
|
|
{
|
|
|
|
gs->counter = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
gs->pos.yPos = ceiling;
|
|
|
|
gs->fallspeed = -gs->fallspeed;
|
|
|
|
}
|
|
|
|
|
|
|
|
int height = GetFloorHeight(floor, gs->pos.xPos, gs->pos.yPos, gs->pos.zPos);
|
|
|
|
if (gs->pos.yPos >= height)
|
|
|
|
{
|
2021-05-26 06:04:32 +02:00
|
|
|
SoundEffect(SFX_TR4_LARA_SHOTGUN_SHELL, &gs->pos, 0);
|
2019-12-22 00:20:10 +01:00
|
|
|
gs->speed -= 8;
|
|
|
|
if (gs->speed >= 8)
|
|
|
|
{
|
|
|
|
if (oldY <= height)
|
|
|
|
{
|
2021-08-30 15:13:18 -05:00
|
|
|
gs->fallspeed = -gs->fallspeed >> 1;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gs->dirXrot += -ANGLE(180);
|
|
|
|
gs->pos.xPos = oldX;
|
|
|
|
gs->pos.zPos = oldZ;
|
|
|
|
}
|
|
|
|
gs->pos.yPos = oldY;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gs->counter = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddWaterSparks(int x, int y, int z, int num)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < num; i++)
|
|
|
|
{
|
|
|
|
SPARKS* spark = &Sparks[GetFreeSpark()];
|
|
|
|
|
|
|
|
spark->on = 1;
|
|
|
|
spark->sR = 64;
|
|
|
|
spark->sG = 64;
|
|
|
|
spark->sB = 64;
|
|
|
|
spark->dR = 32;
|
|
|
|
spark->dG = 32;
|
|
|
|
spark->dB = 32;
|
|
|
|
spark->colFadeSpeed = 4;
|
|
|
|
spark->fadeToBlack = 8;
|
|
|
|
spark->life = 24;
|
|
|
|
spark->sLife = 24;
|
2021-10-27 19:00:30 +03:00
|
|
|
spark->transType = TransTypeEnum::COLADD;
|
2020-09-30 12:37:06 -03:00
|
|
|
int random = GetRandomControl() & 0xFFF;
|
2021-08-30 15:13:18 -05:00
|
|
|
spark->xVel = -phd_sin(random << 4) * 128;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->yVel = -640 - GetRandomControl();
|
2021-08-30 15:13:18 -05:00
|
|
|
spark->zVel = phd_cos(random << 4) * 128;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->friction = 5;
|
2020-05-30 15:55:23 +02:00
|
|
|
spark->flags = SP_NONE;
|
2021-08-30 15:13:18 -05:00
|
|
|
spark->x = x + (spark->xVel >> 3);
|
|
|
|
spark->y = y - (spark->yVel >> 5);
|
|
|
|
spark->z = z + (spark->zVel >> 3);
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->maxYvel = 0;
|
|
|
|
spark->gravity = (GetRandomControl() & 0xF) + 64;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-03 01:50:59 -03:00
|
|
|
void LaraBubbles(ITEM_INFO* item)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
PHD_VECTOR pos;
|
|
|
|
int num, i;
|
|
|
|
|
2021-05-26 06:04:32 +02:00
|
|
|
SoundEffect(SFX_TR4_LARA_BUBBLES, &item->pos, 1);
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
pos.x = 0;
|
|
|
|
|
2021-11-11 01:16:27 +03:00
|
|
|
auto level = g_GameFlow->GetLevel(CurrentLevel);
|
|
|
|
|
|
|
|
if (level->LaraType == LaraType::Divesuit)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
pos.y = -192;
|
|
|
|
pos.z = -160;
|
|
|
|
|
2020-04-29 06:43:53 +02:00
|
|
|
GetLaraJointPosition(&pos, LM_TORSO);
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pos.y = -4;
|
|
|
|
pos.z = 64;
|
|
|
|
|
2020-04-29 06:43:53 +02:00
|
|
|
GetLaraJointPosition(&pos, LM_HEAD);
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
num = (GetRandomControl() & 1) + 2;
|
|
|
|
|
|
|
|
for (i = 0; i < num; i++)
|
|
|
|
{
|
|
|
|
CreateBubble(&pos, item->roomNumber, 8, 7, 0, 0, 0, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int GetFreeDrip()
|
|
|
|
{
|
|
|
|
DRIP_STRUCT* drip = &Drips[NextDrip];
|
|
|
|
int dripNum = NextDrip;
|
|
|
|
short minLife = 4095;
|
|
|
|
short minIndex = 0;
|
|
|
|
short count = 0;
|
|
|
|
|
|
|
|
while (drip->on)
|
|
|
|
{
|
|
|
|
if (drip->life < minLife)
|
|
|
|
{
|
|
|
|
minIndex = dripNum;
|
|
|
|
minLife = drip->life;
|
|
|
|
}
|
|
|
|
|
2019-12-27 10:50:59 +01:00
|
|
|
if (dripNum == MAX_DRIPS - 1)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
drip = &Drips[0];
|
|
|
|
dripNum = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dripNum++;
|
|
|
|
drip++;
|
|
|
|
}
|
|
|
|
|
2019-12-26 19:19:20 +01:00
|
|
|
if (++count >= MAX_DRIPS)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
2019-12-26 19:19:20 +01:00
|
|
|
NextDrip = (minIndex + 1) % MAX_DRIPS;
|
2019-12-22 00:20:10 +01:00
|
|
|
return minIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-26 19:19:20 +01:00
|
|
|
NextDrip = (dripNum + 1) % MAX_DRIPS;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
return dripNum;
|
|
|
|
}
|
|
|
|
|
|
|
|
void UpdateDrips()
|
|
|
|
{
|
2019-12-26 19:19:20 +01:00
|
|
|
for (int i = 0; i < MAX_DRIPS; i++)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
DRIP_STRUCT* drip = &Drips[i];
|
|
|
|
|
|
|
|
if (drip->on)
|
|
|
|
{
|
|
|
|
drip->life--;
|
|
|
|
if (!drip->life)
|
|
|
|
{
|
|
|
|
drip->on = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (drip->life < 16)
|
|
|
|
{
|
2021-08-30 15:13:18 -05:00
|
|
|
drip->r -= drip->r >> 3;
|
|
|
|
drip->g -= drip->g >> 3;
|
|
|
|
drip->b -= drip->b >> 3;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
drip->yVel += drip->gravity;
|
|
|
|
|
2020-07-21 09:56:47 +02:00
|
|
|
if (g_Level.Rooms[drip->roomNumber].flags & ENV_FLAG_WIND)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
2021-09-15 11:13:47 +03:00
|
|
|
drip->x += Weather.Wind().x;
|
|
|
|
drip->z += Weather.Wind().z;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
|
2021-08-30 15:13:18 -05:00
|
|
|
drip->y += drip->yVel >> 5;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
FLOOR_INFO* floor = GetFloor(drip->x, drip->y, drip->z, &drip->roomNumber);
|
2020-07-21 09:56:47 +02:00
|
|
|
if (g_Level.Rooms[drip->roomNumber].flags & ENV_FLAG_WATER)
|
2019-12-22 00:20:10 +01:00
|
|
|
drip->on = false;
|
|
|
|
|
|
|
|
int height = GetFloorHeight(floor, drip->x, drip->y, drip->z);
|
|
|
|
if (drip->y > height)
|
|
|
|
{
|
|
|
|
if (i % 2 == 0)
|
|
|
|
AddWaterSparks(drip->x, drip->y, drip->z, 1);
|
|
|
|
drip->on = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-03 01:50:59 -03:00
|
|
|
void TriggerLaraDrips()
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
PHD_VECTOR pos;
|
|
|
|
|
|
|
|
if (!(Wibble & 0xF))
|
|
|
|
{
|
|
|
|
for (int i = 14; i >= 0; i--)
|
|
|
|
{
|
|
|
|
if (Lara.wet[i]
|
|
|
|
&& !LaraNodeUnderwater[14 - i]
|
|
|
|
&& (GetRandomControl() & 0x1FF) < Lara.wet[i])
|
|
|
|
{
|
|
|
|
|
|
|
|
pos.x = (GetRandomControl() & 0x1F) - 16;
|
|
|
|
pos.y = (GetRandomControl() & 0xF) + 16;
|
|
|
|
pos.z = (GetRandomControl() & 0x1F) - 16;
|
|
|
|
|
|
|
|
DRIP_STRUCT* dptr = &Drips[GetFreeDrip()];
|
|
|
|
GetLaraJointPosition(&pos, i);
|
|
|
|
dptr->x = pos.x;
|
|
|
|
dptr->y = pos.y;
|
|
|
|
dptr->z = pos.z;
|
|
|
|
dptr->on = 1;
|
|
|
|
dptr->r = (GetRandomControl() & 7) + 16;
|
|
|
|
dptr->g = (GetRandomControl() & 7) + 24;
|
|
|
|
dptr->b = (GetRandomControl() & 7) + 32;
|
|
|
|
dptr->yVel = (GetRandomControl() & 0x1F) + 32;
|
|
|
|
dptr->gravity = (GetRandomControl() & 0x1F) + 32;
|
|
|
|
dptr->life = (GetRandomControl() & 0x1F) + 8;
|
|
|
|
dptr->roomNumber = LaraItem->roomNumber;
|
|
|
|
|
|
|
|
Lara.wet[i] -= 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-27 09:21:20 +02:00
|
|
|
int ExplodingDeath(short itemNumber, int meshBits, short flags)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
2020-07-21 09:56:47 +02:00
|
|
|
ITEM_INFO* item = &g_Level.Items[itemNumber];
|
2020-07-07 07:32:33 +02:00
|
|
|
OBJECT_INFO* obj = &Objects[item->objectNumber];
|
2019-12-22 00:20:10 +01:00
|
|
|
|
2020-07-25 18:02:35 +02:00
|
|
|
ANIM_FRAME* frame = GetBestFrame(item);
|
2019-12-22 00:20:10 +01:00
|
|
|
|
2020-04-22 14:12:10 +02:00
|
|
|
Matrix world = Matrix::CreateFromYawPitchRoll(
|
2020-04-25 16:23:53 +02:00
|
|
|
TO_RAD(item->pos.yRot),
|
|
|
|
TO_RAD(item->pos.xRot),
|
|
|
|
TO_RAD(item->pos.zRot)
|
2020-04-22 14:12:10 +02:00
|
|
|
);
|
|
|
|
|
2020-08-09 20:29:31 +02:00
|
|
|
int bit = 1;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
2020-08-09 20:29:31 +02:00
|
|
|
if ((bit & meshBits) && (bit & item->meshBits))
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
2020-08-09 20:29:31 +02:00
|
|
|
if ((GetRandomControl() & 3) == 0)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
2020-08-09 20:29:31 +02:00
|
|
|
short fxNumber = CreateNewEffect(item->roomNumber);
|
2019-12-22 00:20:10 +01:00
|
|
|
if (fxNumber != NO_ITEM)
|
|
|
|
{
|
2020-08-09 20:29:31 +02:00
|
|
|
FX_INFO* fx = &EffectList[fxNumber];
|
|
|
|
|
|
|
|
Matrix boneMatrix;
|
|
|
|
g_Renderer.getBoneMatrix(itemNumber, 0, &boneMatrix);
|
|
|
|
boneMatrix = world * boneMatrix;
|
|
|
|
|
|
|
|
fx->pos.xPos = boneMatrix.Translation().x + item->pos.xPos;
|
|
|
|
fx->pos.yPos = boneMatrix.Translation().y + item->pos.yPos;
|
|
|
|
fx->pos.zPos = boneMatrix.Translation().z + item->pos.zPos;
|
|
|
|
|
2019-12-22 00:20:10 +01:00
|
|
|
fx->roomNumber = item->roomNumber;
|
|
|
|
fx->pos.xRot = 0;
|
2020-08-09 20:29:31 +02:00
|
|
|
fx->pos.yRot = GetRandomControl() * 2;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
2020-08-09 20:29:31 +02:00
|
|
|
if (!(flags & 0x10))
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
2020-05-27 09:21:20 +02:00
|
|
|
if (flags & 0x20)
|
2019-12-22 00:20:10 +01:00
|
|
|
fx->speed = GetRandomControl() >> 12;
|
|
|
|
else
|
|
|
|
fx->speed = GetRandomControl() >> 8;
|
|
|
|
}
|
2020-08-09 20:29:31 +02:00
|
|
|
|
2020-05-27 09:21:20 +02:00
|
|
|
if (flags & 0x40)
|
2019-12-22 00:20:10 +01:00
|
|
|
fx->fallspeed = 0;
|
|
|
|
else
|
|
|
|
{
|
2020-08-09 20:29:31 +02:00
|
|
|
if ((flags & 0x80) == 0)
|
2019-12-22 00:20:10 +01:00
|
|
|
fx->fallspeed = -(GetRandomControl() >> 8);
|
|
|
|
else
|
|
|
|
fx->fallspeed = -(GetRandomControl() >> 12);
|
|
|
|
}
|
|
|
|
fx->objectNumber = ID_BODY_PART;
|
2020-08-09 20:29:31 +02:00
|
|
|
fx->frameNumber = obj->meshIndex;
|
2019-12-22 00:20:10 +01:00
|
|
|
fx->shade = 16912;
|
2020-08-09 20:29:31 +02:00
|
|
|
fx->flag2 = flags;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
2020-08-09 20:29:31 +02:00
|
|
|
|
|
|
|
item->meshBits -= bit;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-09 20:29:31 +02:00
|
|
|
for (int i = 1; i < obj->nmeshes; i++)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
2020-08-09 20:29:31 +02:00
|
|
|
Matrix boneMatrix;
|
|
|
|
g_Renderer.getBoneMatrix(itemNumber, i, &boneMatrix);
|
|
|
|
boneMatrix = world * boneMatrix;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
2021-08-30 15:13:18 -05:00
|
|
|
bit <<= 1;
|
2020-08-09 20:29:31 +02:00
|
|
|
if ((bit & meshBits) && (bit & item->meshBits))
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
2020-08-09 20:29:31 +02:00
|
|
|
if ((GetRandomControl() & 3) == 0 && (flags & 0x100))
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
2020-08-09 20:29:31 +02:00
|
|
|
short fxNumber = CreateNewEffect(item->roomNumber);
|
|
|
|
if (fxNumber != NO_ITEM)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
2020-08-09 20:29:31 +02:00
|
|
|
FX_INFO* fx = &EffectList[fxNumber];
|
|
|
|
|
|
|
|
fx->pos.xPos = boneMatrix.Translation().x + item->pos.xPos;
|
|
|
|
fx->pos.yPos = boneMatrix.Translation().y + item->pos.yPos;
|
|
|
|
fx->pos.zPos = boneMatrix.Translation().z + item->pos.zPos;
|
|
|
|
|
|
|
|
fx->roomNumber = item->roomNumber;
|
|
|
|
fx->pos.xRot = 0;
|
|
|
|
fx->pos.yRot = GetRandomControl() * 2;
|
|
|
|
|
|
|
|
if (!(flags & 0x10))
|
|
|
|
{
|
|
|
|
if (flags & 0x20)
|
|
|
|
fx->speed = GetRandomControl() >> 12;
|
|
|
|
else
|
|
|
|
fx->speed = GetRandomControl() >> 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & 0x40)
|
|
|
|
fx->fallspeed = 0;
|
2019-12-22 00:20:10 +01:00
|
|
|
else
|
2020-08-09 20:29:31 +02:00
|
|
|
{
|
|
|
|
if ((flags & 0x80) == 0)
|
|
|
|
fx->fallspeed = -(GetRandomControl() >> 8);
|
|
|
|
else
|
|
|
|
fx->fallspeed = -(GetRandomControl() >> 12);
|
|
|
|
}
|
|
|
|
|
|
|
|
fx->objectNumber = ID_BODY_PART;
|
|
|
|
fx->shade = 16912;
|
|
|
|
fx->flag2 = flags;
|
|
|
|
fx->frameNumber = obj->meshIndex + i;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
|
2020-08-09 20:29:31 +02:00
|
|
|
item->meshBits -= bit;
|
|
|
|
}
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
2020-08-09 20:29:31 +02:00
|
|
|
}
|
2019-12-22 00:20:10 +01:00
|
|
|
|
2020-08-09 20:29:31 +02:00
|
|
|
return item->meshBits == 0;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
|
2021-02-03 01:50:59 -03:00
|
|
|
int GetFreeShockwave()
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
2019-12-26 19:19:20 +01:00
|
|
|
for (int i = 0; i < MAX_SHOCKWAVE; i++)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
if (!ShockWaves[i].life)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2021-02-03 01:50:59 -03:00
|
|
|
void TriggerShockwave(PHD_3DPOS* pos, short innerRad, short outerRad, int speed, char r, char g, char b, char life, short angle, short flags)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
int s = GetFreeShockwave();
|
|
|
|
SHOCKWAVE_STRUCT* sptr;
|
|
|
|
|
|
|
|
if (s != -1)
|
|
|
|
{
|
|
|
|
sptr = &ShockWaves[s];
|
|
|
|
|
|
|
|
sptr->x = pos->xPos;
|
|
|
|
sptr->y = pos->yPos;
|
|
|
|
sptr->z = pos->zPos;
|
|
|
|
sptr->innerRad = innerRad;
|
|
|
|
sptr->outerRad = outerRad;
|
|
|
|
sptr->xRot = angle;
|
|
|
|
sptr->flags = flags;
|
|
|
|
sptr->speed = speed;
|
|
|
|
sptr->r = r;
|
|
|
|
sptr->g = g;
|
|
|
|
sptr->b = b;
|
|
|
|
sptr->life = life;
|
2020-04-05 08:15:56 +02:00
|
|
|
|
2021-05-26 06:04:32 +02:00
|
|
|
SoundEffect(SFX_TR5_IMP_STONE_HIT, pos, 0);
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-21 19:14:28 +01:00
|
|
|
void TriggerShockwaveHitEffect(int x, int y, int z, byte r, byte g, byte b, short rot, int vel)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
int dx = LaraItem->pos.xPos - x;
|
|
|
|
int dz = LaraItem->pos.zPos - z;
|
|
|
|
|
|
|
|
if (dx >= -16384 && dx <= 16384 && dz >= -16384 && dz <= 16384)
|
|
|
|
{
|
|
|
|
SPARKS* spark = &Sparks[GetFreeSpark()];
|
2020-03-21 19:14:28 +01:00
|
|
|
spark->dB = b;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->on = true;
|
|
|
|
spark->sR = 0;
|
|
|
|
spark->sG = 0;
|
|
|
|
spark->sB = 0;
|
2020-03-21 19:14:28 +01:00
|
|
|
spark->dG = g;
|
|
|
|
spark->dR = r;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->colFadeSpeed = 4;
|
|
|
|
spark->fadeToBlack = 8;
|
2021-10-27 19:00:30 +03:00
|
|
|
spark->transType = TransTypeEnum::COLADD;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->life = spark->sLife = (GetRandomControl() & 3) + 16;
|
|
|
|
|
|
|
|
int speed = (GetRandomControl() & 0xF) + vel;
|
2020-10-05 22:24:57 -03:00
|
|
|
spark->xVel = speed * 16 * phd_sin(rot);
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->yVel = -512 - (GetRandomControl() & 0x1FF);
|
2020-10-05 22:24:57 -03:00
|
|
|
spark->zVel = speed * 16 * phd_cos(rot);
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
short angle;
|
|
|
|
if (GetRandomControl() & 1)
|
|
|
|
angle = rot + ANGLE(90);
|
|
|
|
else
|
|
|
|
angle = rot - ANGLE(90);
|
|
|
|
|
|
|
|
int shift = (GetRandomControl() & 0x1FF) - 256;
|
2020-10-05 22:24:57 -03:00
|
|
|
x += shift * phd_sin(angle);
|
|
|
|
z += shift * phd_cos(angle);
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
spark->x = (GetRandomControl() & 0x1F) + x - 16;
|
|
|
|
spark->y = (GetRandomControl() & 0x1F) + y - 16;
|
|
|
|
spark->z = (GetRandomControl() & 0x1F) + z - 16;
|
|
|
|
|
|
|
|
spark->friction = 3;
|
2020-03-25 12:52:02 +01:00
|
|
|
spark->flags = SP_EXPDEF | SP_ROTATE | SP_DEF | SP_SCALE;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->rotAng = GetRandomControl() & 0xFFF;
|
|
|
|
if (GetRandomControl() & 1)
|
|
|
|
spark->rotAdd = -16 - (GetRandomControl() & 0xF);
|
|
|
|
else
|
|
|
|
spark->rotAdd = (GetRandomControl() & 0xF) + 16;
|
|
|
|
|
|
|
|
spark->scalar = 1;
|
2020-03-25 12:52:02 +01:00
|
|
|
spark->def = Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_UNDERWATERDUST;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->maxYvel = 0;
|
|
|
|
spark->gravity = (GetRandomControl() & 0x3F) + 64;
|
|
|
|
spark->sSize = spark->size = (GetRandomControl() & 0x1F) + 32;
|
2020-09-12 13:49:09 +02:00
|
|
|
spark->dSize = spark->size / 4;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UpdateShockwaves()
|
|
|
|
{
|
2019-12-26 19:19:20 +01:00
|
|
|
for (int i = 0; i < MAX_SHOCKWAVE; i++)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
SHOCKWAVE_STRUCT* sw = &ShockWaves[i];
|
|
|
|
|
|
|
|
if (sw->life)
|
|
|
|
{
|
|
|
|
sw->life--;
|
|
|
|
|
|
|
|
if (sw->life)
|
|
|
|
{
|
|
|
|
sw->outerRad += sw->speed;
|
2021-08-30 15:13:18 -05:00
|
|
|
sw->speed -= (sw->speed >> 4);
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
if (LaraItem->hitPoints > 0)
|
|
|
|
{
|
|
|
|
if (sw->flags & 3)
|
|
|
|
{
|
2020-07-25 18:02:35 +02:00
|
|
|
ANIM_FRAME* frame = GetBestFrame(LaraItem);
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
int dx = LaraItem->pos.xPos - sw->x;
|
|
|
|
int dz = LaraItem->pos.zPos - sw->z;
|
2020-04-20 14:17:01 +02:00
|
|
|
int distance = sqrt(SQUARE(dx) + SQUARE(dz));
|
2019-12-22 00:20:10 +01:00
|
|
|
|
2020-07-25 18:02:35 +02:00
|
|
|
if (sw->y <= LaraItem->pos.yPos + frame->boundingBox.Y1
|
|
|
|
|| sw->y >= LaraItem->pos.yPos + frame->boundingBox.Y2 + 256
|
2019-12-22 00:20:10 +01:00
|
|
|
|| distance <= sw->innerRad
|
|
|
|
|| distance >= sw->outerRad)
|
|
|
|
{
|
|
|
|
sw->temp = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-04-25 16:23:53 +02:00
|
|
|
short angle = phd_atan(dz, dx);
|
2019-12-22 00:20:10 +01:00
|
|
|
TriggerShockwaveHitEffect(LaraItem->pos.xPos,
|
|
|
|
sw->y,
|
|
|
|
LaraItem->pos.zPos,
|
2020-03-21 19:14:28 +01:00
|
|
|
sw->r, sw->g, sw->b,
|
2019-12-22 00:20:10 +01:00
|
|
|
angle,
|
|
|
|
sw->speed);
|
2021-08-30 15:13:18 -05:00
|
|
|
LaraItem->hitPoints -= sw->speed >> (((sw->flags >> 1) & 1) + 2);
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-03 01:50:59 -03:00
|
|
|
void TriggerExplosionBubble(int x, int y, int z, short roomNum)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
int dx = LaraItem->pos.xPos - x;
|
|
|
|
int dz = LaraItem->pos.zPos - z;
|
|
|
|
|
|
|
|
if (dx >= -16384 && dx <= 16384 && dz >= -16384 && dz <= 16384)
|
|
|
|
{
|
|
|
|
SPARKS* spark = &Sparks[GetFreeSpark()];
|
|
|
|
spark->sR = 128;
|
|
|
|
spark->dR = 128;
|
|
|
|
spark->dG = 128;
|
|
|
|
spark->dB = 128;
|
|
|
|
spark->on = 1;
|
|
|
|
spark->life = 24;
|
|
|
|
spark->sLife = 24;
|
|
|
|
spark->sG = 64;
|
|
|
|
spark->sB = 0;
|
|
|
|
spark->colFadeSpeed = 8;
|
|
|
|
spark->fadeToBlack = 12;
|
2021-10-27 19:00:30 +03:00
|
|
|
spark->transType = TransTypeEnum::COLADD;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->x = x;
|
|
|
|
spark->y = y;
|
|
|
|
spark->z = z;
|
|
|
|
spark->xVel = 0;
|
|
|
|
spark->yVel = 0;
|
|
|
|
spark->zVel = 0;
|
|
|
|
spark->friction = 0;
|
|
|
|
spark->flags = 2058;
|
|
|
|
spark->scalar = 3;
|
|
|
|
spark->gravity = 0;
|
|
|
|
spark->def = Objects[ID_DEFAULT_SPRITES].meshIndex + 13;
|
|
|
|
spark->maxYvel = 0;
|
|
|
|
int size = (GetRandomControl() & 7) + 63;
|
2021-08-30 15:13:18 -05:00
|
|
|
spark->sSize = size >> 1;
|
|
|
|
spark->size = size >> 1;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->dSize = 2 * size;
|
|
|
|
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
|
|
{
|
|
|
|
PHD_VECTOR pos;
|
|
|
|
pos.x = (GetRandomControl() & 0x1FF) + x - 256;
|
|
|
|
pos.y = (GetRandomControl() & 0x7F) + y - 64;
|
|
|
|
pos.z = (GetRandomControl() & 0x1FF) + z - 256;
|
2020-04-13 13:36:23 +02:00
|
|
|
CreateBubble(&pos, roomNum, 6, 15, BUBBLE_FLAG_CLUMP | BUBBLE_FLAG_BIG_SIZE | BUBBLE_FLAG_HIGH_AMPLITUDE, 0, 0, 0);
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-03 01:50:59 -03:00
|
|
|
/*void TriggerExplosionSmokeEnd(int x, int y, int z, int unk)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
SPARKS* spark = &Sparks[GetFreeSpark()];
|
|
|
|
|
|
|
|
spark->on = 1;
|
|
|
|
if (unk)
|
|
|
|
{
|
|
|
|
spark->sR = 0;
|
|
|
|
spark->sG = 0;
|
|
|
|
spark->sB = 0;
|
|
|
|
spark->dR = 192;
|
|
|
|
spark->dG = 192;
|
|
|
|
spark->dB = 208;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
spark->dR = 64;
|
|
|
|
spark->sR = 144;
|
|
|
|
spark->sG = 144;
|
|
|
|
spark->sB = 144;
|
|
|
|
spark->dG = 64;
|
|
|
|
spark->dB = 64;
|
|
|
|
}
|
|
|
|
|
|
|
|
spark->colFadeSpeed = 8;
|
|
|
|
spark->fadeToBlack = 64;
|
|
|
|
spark->life = spark->sLife = (GetRandomControl() & 0x1F) + 96;
|
|
|
|
if (unk)
|
2021-10-27 19:00:30 +03:00
|
|
|
spark->transType = TransTypeEnum::COLADD;
|
2019-12-22 00:20:10 +01:00
|
|
|
else
|
|
|
|
spark->transType = 3;
|
|
|
|
spark->x = (GetRandomControl() & 0x1F) + x - 16;
|
|
|
|
spark->y = (GetRandomControl() & 0x1F) + y - 16;
|
|
|
|
spark->z = (GetRandomControl() & 0x1F) + z - 16;
|
|
|
|
spark->xVel = ((GetRandomControl() & 0xFFF) - 2048) >> 2;
|
|
|
|
spark->yVel = (GetRandomControl() & 0xFF) - 128;
|
|
|
|
spark->zVel = ((GetRandomControl() & 0xFFF) - 2048) >> 2;
|
|
|
|
if (unk)
|
|
|
|
{
|
|
|
|
spark->friction = 20;
|
|
|
|
spark->yVel >>= 4;
|
|
|
|
spark->y += 32;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
spark->friction = 6;
|
|
|
|
}
|
|
|
|
spark->flags = 538;
|
|
|
|
spark->rotAng = GetRandomControl() & 0xFFF;
|
|
|
|
if (GetRandomControl() & 1)
|
|
|
|
spark->rotAdd = -((GetRandomControl() & 0xF) + 16);
|
|
|
|
else
|
|
|
|
spark->rotAdd = (GetRandomControl() & 0xF) + 16;
|
|
|
|
spark->scalar = 3;
|
|
|
|
if (unk)
|
|
|
|
{
|
|
|
|
spark->maxYvel = 0;
|
|
|
|
spark->gravity = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
spark->gravity = -3 - (GetRandomControl() & 3);
|
|
|
|
spark->maxYvel = -4 - (GetRandomControl() & 3);
|
|
|
|
}
|
|
|
|
int size = (GetRandomControl() & 0x1F) + 128;
|
|
|
|
spark->dSize = size;
|
|
|
|
spark->sSize = size >> 2;
|
|
|
|
spark->size = size >> 2;
|
|
|
|
}
|
|
|
|
*/
|
2021-02-03 01:50:59 -03:00
|
|
|
/*void DrawLensFlares(ITEM_INFO* item)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
GAME_VECTOR pos;
|
|
|
|
|
2020-08-09 20:29:31 +02:00
|
|
|
pos.x = item->pos.xPos;
|
|
|
|
pos.y = item->pos.yPos;
|
|
|
|
pos.z = item->pos.zPos;
|
2020-04-09 14:19:18 +02:00
|
|
|
pos.roomNumber = item->roomNumber;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
SetUpLensFlare(0, 0, 0, &pos);
|
|
|
|
}*/
|
|
|
|
|
2021-02-03 01:50:59 -03:00
|
|
|
void TriggerFenceSparks(int x, int y, int z, int kill, int crane)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
SPARKS* spark = &Sparks[GetFreeSpark()];
|
|
|
|
spark->on = 1;
|
|
|
|
spark->sR = (GetRandomControl() & 0x3F) - 0x40;
|
|
|
|
spark->sG = (GetRandomControl() & 0x3F) - 0x40;
|
|
|
|
spark->sB = (GetRandomControl() & 0x3F) - 0x40;
|
|
|
|
|
|
|
|
spark->dR = GetRandomControl() | 0xC0;
|
|
|
|
spark->colFadeSpeed = 16;
|
|
|
|
spark->g = 8;
|
2021-08-30 15:13:18 -05:00
|
|
|
spark->dG = spark->sR >> 1;
|
|
|
|
spark->dB = spark->sR >> 2;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
spark->life = (GetRandomControl() & 7) + 24;
|
|
|
|
spark->sLife = (GetRandomControl() & 7) + 24;
|
2021-10-27 19:00:30 +03:00
|
|
|
spark->transType = TransTypeEnum::COLADD;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->dynamic = -1;
|
|
|
|
|
|
|
|
spark->x = x;
|
|
|
|
spark->y = y;
|
|
|
|
spark->z = z;
|
|
|
|
|
2021-08-30 15:13:18 -05:00
|
|
|
spark->xVel = ((GetRandomControl() & 0xFF) - 128) << 2;
|
|
|
|
spark->yVel = (GetRandomControl() & 0xF) - ((kill << 5) + 8) + (crane << 4);
|
|
|
|
spark->zVel = ((GetRandomControl() & 0xFF) - 128) << 2;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
if (crane != 0)
|
|
|
|
{
|
|
|
|
spark->friction = 5;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
spark->friction = 4;
|
|
|
|
}
|
|
|
|
|
2020-05-30 15:55:23 +02:00
|
|
|
spark->flags = SP_NONE;
|
2021-08-30 15:13:18 -05:00
|
|
|
spark->gravity = (GetRandomControl() & 0xF) + ((crane << 4) + 16);
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->maxYvel = 0;
|
|
|
|
}
|
|
|
|
|
2020-02-14 07:42:20 +01:00
|
|
|
void TriggerSmallSplash(int x, int y, int z, int num)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int angle;
|
|
|
|
|
|
|
|
for (i = 0; i < num; i++)
|
|
|
|
{
|
|
|
|
SPARKS* sptr = &Sparks[GetFreeSpark()];
|
|
|
|
|
|
|
|
sptr->on = 1;
|
|
|
|
|
|
|
|
sptr->sR = 64;
|
|
|
|
sptr->sG = 64;
|
|
|
|
sptr->sB = 64;
|
|
|
|
|
|
|
|
sptr->dR = 32;
|
|
|
|
sptr->dG = 32;
|
|
|
|
sptr->dB = 32;
|
|
|
|
|
|
|
|
sptr->colFadeSpeed = 4;
|
|
|
|
sptr->fadeToBlack = 8;
|
|
|
|
|
|
|
|
sptr->life = 24;
|
|
|
|
sptr->sLife = 24;
|
|
|
|
|
2021-10-27 19:00:30 +03:00
|
|
|
sptr->transType = TransTypeEnum::COLADD;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
angle = GetRandomControl() << 3;
|
|
|
|
|
2020-10-05 22:24:57 -03:00
|
|
|
sptr->xVel = -phd_sin(angle) * 512;
|
2019-12-22 00:20:10 +01:00
|
|
|
sptr->yVel = -640 - (GetRandomControl() & 0xFF);
|
2020-10-05 22:24:57 -03:00
|
|
|
sptr->zVel = phd_cos(angle) * 512;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
sptr->friction = 5;
|
|
|
|
sptr->flags = 0;
|
|
|
|
|
2021-08-30 15:13:18 -05:00
|
|
|
sptr->x = x + (sptr->xVel >> 3);
|
|
|
|
sptr->y = y - (sptr->yVel >> 5);
|
|
|
|
sptr->z = z + (sptr->zVel >> 3);
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
sptr->maxYvel = 0;
|
2020-03-23 06:59:21 +01:00
|
|
|
sptr->gravity = (GetRandomControl() & 0xF) + 64;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
2021-09-22 05:51:25 +02:00
|
|
|
}
|