2020-05-27 09:21:20 +02:00
|
|
|
#include "framework.h"
|
2019-12-22 00:20:10 +01:00
|
|
|
#include "tomb4fx.h"
|
|
|
|
#include "lara.h"
|
|
|
|
#include "effect2.h"
|
|
|
|
#include "draw.h"
|
2020-05-27 09:21:20 +02:00
|
|
|
#include "setup.h"
|
|
|
|
#include "level.h"
|
2020-04-24 19:15:05 +02:00
|
|
|
#include "sound.h"
|
2020-04-13 13:36:23 +02:00
|
|
|
#include "bubble.h"
|
2020-05-30 15:55:23 +02:00
|
|
|
#include "trmath.h"
|
|
|
|
#include "GameFlowScript.h"
|
2020-05-28 16:48:36 +02:00
|
|
|
#include "smoke.h"
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
char FlareTable[121] =
|
|
|
|
{
|
|
|
|
0x60, 0x50, 0x00, 0x06, 0x00, 0x1F, 0x30, 0x20, 0x20, 0x0A, 0xFA, 0x1F, 0x20, 0x18,
|
|
|
|
0x18, 0x12, 0xFF, 0x1F, 0x50, 0x68, 0x40, 0x05, 0xFD, 0x1E, 0x40, 0x40, 0x40, 0x14,
|
|
|
|
0x00, 0x20, 0x60, 0x38, 0x38, 0x0E, 0x00, 0x0B, 0x50, 0x28, 0x20, 0x09, 0x00, 0x1D,
|
|
|
|
0x10, 0x18, 0x28, 0x02, 0x05, 0x1F, 0x08, 0x08, 0x18, 0x07, 0x08, 0x1F, 0x08, 0x10,
|
|
|
|
0x20, 0x04, 0x0A, 0x1F, 0x30, 0x18, 0x00, 0x02, 0x0D, 0x1F, 0x28, 0x60, 0x48, 0x01,
|
|
|
|
0x10, 0x0B, 0x28, 0x60, 0x48, 0x03, 0x14, 0x0B, 0x20, 0x10, 0x00, 0x06, 0x16, 0x1F,
|
|
|
|
0x20, 0x10, 0x00, 0x09, 0x17, 0x1E, 0x20, 0x10, 0x00, 0x03, 0x18, 0x1F, 0x20, 0x30,
|
|
|
|
0x18, 0x04, 0x1A, 0x1F, 0x08, 0x28, 0x70, 0x03, 0x1B, 0x0B, 0x08, 0x10, 0x00, 0x0A,
|
|
|
|
0x1D, 0x1E, 0x10, 0x10, 0x18, 0x11, 0x1F, 0x1D, 0xFF
|
|
|
|
};
|
|
|
|
|
|
|
|
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];
|
2020-05-30 15:55:23 +02:00
|
|
|
ENERGY_ARC EnergyArcs[MAX_ENERGYARCS];
|
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
|
|
|
|
fptr->on = true;
|
|
|
|
|
|
|
|
fptr->x = x;
|
|
|
|
fptr->y = y;
|
|
|
|
fptr->z = z;
|
|
|
|
fptr->size = size;
|
|
|
|
fptr->roomNumber = roomNum;
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
int dl = ((spark->sLife - spark->life) << 16) / spark->colFadeSpeed;
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
else if (spark->life >= spark->fadeToBlack)
|
|
|
|
{
|
|
|
|
spark->r = spark->dR;
|
|
|
|
spark->g = spark->dG;
|
|
|
|
spark->b = spark->dB;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int dl = ((spark->life - spark->fadeToBlack) << 16) / spark->fadeToBlack + 0x10000;
|
|
|
|
|
|
|
|
spark->r = dl * spark->dR >> 16;
|
|
|
|
spark->g = dl * spark->dG >> 16;
|
|
|
|
spark->b = dl * spark->dB >> 16;
|
|
|
|
|
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
|
|
|
|
|
|
|
int dl = ((spark->sLife - spark->life) << 16) / spark->sLife;
|
|
|
|
spark->yVel += spark->gravity;
|
|
|
|
if (spark->maxYvel)
|
|
|
|
{
|
|
|
|
if ((spark->yVel < 0 && spark->yVel < (spark->maxYvel << 5)) ||
|
|
|
|
(spark->yVel > 0 && spark->yVel > (spark->maxYvel << 5)))
|
|
|
|
spark->yVel = spark->maxYvel << 5;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (spark->friction)
|
|
|
|
{
|
|
|
|
spark->xVel -= spark->xVel >> spark->friction;
|
|
|
|
spark->zVel -= spark->zVel >> spark->friction;
|
|
|
|
}
|
|
|
|
|
|
|
|
spark->x += spark->xVel >> 5;
|
|
|
|
spark->y += spark->yVel >> 5;
|
|
|
|
spark->z += spark->zVel >> 5;
|
|
|
|
|
|
|
|
spark->size = spark->sSize + (dl * (spark->dSize - spark->sSize) >> 16);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-16 12:36:29 +01:00
|
|
|
void UpdateEnergyArcs()
|
|
|
|
{
|
2020-05-30 15:55:23 +02:00
|
|
|
for (int i = 0; i < MAX_ENERGYARCS; i++)
|
2020-03-16 12:36:29 +01:00
|
|
|
{
|
|
|
|
ENERGY_ARC* arc = &EnergyArcs[i];
|
|
|
|
|
|
|
|
if (arc->life > 0)
|
|
|
|
{
|
|
|
|
arc->life--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
spark->shade = spark->dShade * (((spark->life - spark->fadeToBlack) << 16) / spark->fadeToBlack + 0x10000) >> 16;
|
|
|
|
if (spark->shade < 8)
|
|
|
|
{
|
|
|
|
spark->on = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
spark->shade = spark->sShade + ((spark->dShade - spark->sShade) * (((spark->sLife - spark->life) << 16) / spark->colFadeSpeed) >> 16);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
int dl = ((spark->sLife - spark->life) << 16) / spark->sLife;
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
spark->yVel -= spark->yVel >> (spark->friction >> 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
spark->x += SmokeWindX >> 1;
|
2020-03-27 07:17:05 +01:00
|
|
|
spark->z += SmokeWindZ >> 1;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
spark->size = spark->sSize + (dl * (spark->dSize - spark->sSize) >> 16);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-05-30 15:55:23 +02:00
|
|
|
spark->transType = 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)
|
|
|
|
{
|
|
|
|
if (Rooms[LaraItem->roomNumber].flags & ENV_FLAG_WIND)
|
|
|
|
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
|
|
|
}
|
|
|
|
else if (Rooms[LaraItem->roomNumber].flags & ENV_FLAG_WIND)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}*/
|
2020-05-28 16:48:36 +02:00
|
|
|
T5M::Effects::Smoke::TriggerGunSmokeParticles(x, y, z, xv, yv, zv, initial, weaponType, count);
|
|
|
|
|
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);
|
2020-05-30 15:55:23 +02:00
|
|
|
spark->transType = 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;
|
|
|
|
}
|
|
|
|
else if (Rooms[LaraItem->roomNumber].flags & ENV_FLAG_WIND)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
spark->sSize = spark->dSize >> 3;
|
|
|
|
spark->size = spark->dSize >> 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
int GetFreeBlood()// (F)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TriggerBlood(int x, int y, int z, int unk, int num)// (F)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
int a = (unk == -1
|
|
|
|
? GetRandomControl() & 0xFFFF
|
|
|
|
: (GetRandomControl() & 0x1F) + unk - 16) & 0xFFF;
|
|
|
|
int b = GetRandomControl() & 0xF;
|
|
|
|
blood->zVel = b * rcossin_tbl[2 * a + 1] >> 7;
|
|
|
|
blood->xVel = -(b * rcossin_tbl[2 * a]) >> 7;
|
|
|
|
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;
|
|
|
|
blood->dSize = size >> 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
blood->shade = blood->dShade * (((blood->life - blood->fadeToBlack) << 16) / blood->fadeToBlack + 0x10000) >> 16;
|
|
|
|
if (blood->shade < 8)
|
|
|
|
{
|
|
|
|
blood->on = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
blood->shade = blood->sShade + ((blood->dShade - blood->sShade) * (((blood->sLife - blood->life) << 16) / blood->colFadeSpeed) >> 16);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
int dl = ((blood->sLife - blood->life) << 16) / blood->sLife;
|
|
|
|
|
|
|
|
blood->x += blood->xVel >> 5;
|
|
|
|
blood->y += blood->yVel >> 5;
|
|
|
|
blood->z += blood->zVel >> 5;
|
|
|
|
|
|
|
|
blood->size = blood->sSize + (dl * (blood->dSize - blood->sSize) >> 16);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TriggerGunShell(short hand, short objNum, int weaponType)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
if (Rooms[gs->roomNumber].flags & ENV_FLAG_WATER)
|
|
|
|
{
|
|
|
|
gs->fallspeed++;
|
|
|
|
|
|
|
|
if (gs->fallspeed <= 8)
|
|
|
|
{
|
|
|
|
if (gs->fallspeed < 0)
|
|
|
|
gs->fallspeed = gs->fallspeed >> 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gs->fallspeed = 8;
|
|
|
|
}
|
|
|
|
gs->speed -= gs->speed >> 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gs->fallspeed += 6;
|
|
|
|
}
|
|
|
|
|
|
|
|
gs->pos.xRot += (gs->speed >> 1 + 7) * ANGLE(1);
|
|
|
|
gs->pos.yRot += gs->speed * ANGLE(1);
|
|
|
|
gs->pos.zRot += ANGLE(23);
|
|
|
|
|
2020-04-25 16:23:53 +02:00
|
|
|
gs->pos.xPos += gs->speed * phd_sin(gs->dirXrot) >> W2V_SHIFT;
|
2019-12-22 00:20:10 +01:00
|
|
|
gs->pos.yPos += gs->fallspeed;
|
2020-04-25 16:23:53 +02:00
|
|
|
gs->pos.zPos += gs->speed * phd_cos(gs->dirXrot) >> W2V_SHIFT;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
FLOOR_INFO* floor = GetFloor(gs->pos.xPos, gs->pos.yPos, gs->pos.zPos, &gs->roomNumber);
|
|
|
|
if (Rooms[gs->roomNumber].flags & ENV_FLAG_WATER
|
|
|
|
&& !(Rooms[oldRoomNumber].flags & ENV_FLAG_WATER))
|
|
|
|
{
|
|
|
|
AddWaterSparks(gs->pos.xPos, Rooms[gs->roomNumber].maxceiling, gs->pos.zPos, 8);
|
|
|
|
SetupRipple(gs->pos.xPos, Rooms[gs->roomNumber].maxceiling, gs->pos.zPos, (GetRandomControl() & 3) + 8, 2);
|
|
|
|
gs->fallspeed >>= 5;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ceiling = GetCeiling(floor, gs->pos.xPos, gs->pos.yPos, gs->pos.zPos);
|
|
|
|
if (gs->pos.yPos < ceiling)
|
|
|
|
{
|
|
|
|
SoundEffect(SFX_LARA_SHOTGUN_SHELL, &gs->pos, 0);
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
SoundEffect(SFX_LARA_SHOTGUN_SHELL, &gs->pos, 0);
|
|
|
|
gs->speed -= 8;
|
|
|
|
if (gs->speed >= 8)
|
|
|
|
{
|
|
|
|
if (oldY <= height)
|
|
|
|
{
|
|
|
|
gs->fallspeed = -gs->fallspeed >> 1;
|
|
|
|
}
|
|
|
|
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;
|
2020-05-30 15:55:23 +02:00
|
|
|
spark->transType = COLADD;
|
2019-12-22 00:20:10 +01:00
|
|
|
int random = GetRandomControl();
|
|
|
|
spark->xVel = -rcossin_tbl[2 * random] >> 5;
|
|
|
|
spark->yVel = -640 - GetRandomControl();
|
|
|
|
spark->zVel = rcossin_tbl[2 * random & 0xFFF + 1] >> 5;
|
|
|
|
spark->friction = 5;
|
2020-05-30 15:55:23 +02:00
|
|
|
spark->flags = SP_NONE;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->x = x + (spark->xVel >> 3);
|
|
|
|
spark->y = y - (spark->yVel >> 5);
|
|
|
|
spark->z = z + (spark->zVel >> 3);
|
|
|
|
spark->maxYvel = 0;
|
|
|
|
spark->gravity = (GetRandomControl() & 0xF) + 64;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LaraBubbles(ITEM_INFO* item)// (F)
|
|
|
|
{
|
|
|
|
PHD_VECTOR pos;
|
|
|
|
int num, i;
|
|
|
|
|
|
|
|
SoundEffect(SFX_LARA_BUBBLES, &item->pos, 1);
|
|
|
|
|
|
|
|
pos.x = 0;
|
|
|
|
|
|
|
|
if (LaraDrawType == LARA_DIVESUIT)
|
|
|
|
{
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
drip->r -= drip->r >> 3;
|
|
|
|
drip->g -= drip->g >> 3;
|
|
|
|
drip->b -= drip->b >> 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
drip->yVel += drip->gravity;
|
|
|
|
|
|
|
|
if (Rooms[drip->roomNumber].flags & ENV_FLAG_WIND)
|
|
|
|
{
|
|
|
|
drip->x += SmokeWindX >> 1;
|
|
|
|
drip->z += SmokeWindZ >> 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
drip->y += drip->yVel >> 5;
|
|
|
|
|
|
|
|
FLOOR_INFO* floor = GetFloor(drip->x, drip->y, drip->z, &drip->roomNumber);
|
|
|
|
if (Rooms[drip->roomNumber].flags & ENV_FLAG_WATER)
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TriggerLaraDrips()// (F)
|
|
|
|
{
|
|
|
|
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
|
|
|
{
|
|
|
|
ITEM_INFO* item = &Items[itemNumber];
|
2020-04-27 15:28:54 +02:00
|
|
|
ObjectInfo* obj = &Objects[item->objectNumber];
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
short* frame = GetBestFrame(item);
|
|
|
|
|
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
|
|
|
);
|
|
|
|
|
|
|
|
// PHD_MATH:
|
2020-04-24 19:15:05 +02:00
|
|
|
/*phd_PushUnitMatrix();
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
MatrixPtr[M03] = 0;
|
|
|
|
MatrixPtr[M13] = 0;
|
|
|
|
MatrixPtr[M23] = 0;
|
|
|
|
|
2020-04-22 14:12:10 +02:00
|
|
|
phd_RotYXZ(item->pos.yRot, item->pos.xRot, item->pos.zRot);
|
2019-12-22 00:20:10 +01:00
|
|
|
phd_TranslateRel(frame[6], frame[7], frame[8]);
|
|
|
|
|
|
|
|
short* rotation = &frame[9];
|
|
|
|
gar_RotYXZsuperpack(&rotation, 0);
|
|
|
|
|
|
|
|
short* extraRotation = (short*)item->data;
|
|
|
|
|
|
|
|
int* bone = &Bones[obj->boneIndex];
|
|
|
|
|
|
|
|
int bits = 1;
|
|
|
|
if (meshBits & 1 && item->meshBits & 1)
|
|
|
|
{
|
2020-05-27 09:21:20 +02:00
|
|
|
if (flags & 0x100 || !(GetRandomControl() & 3))
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
2020-04-22 14:12:10 +02:00
|
|
|
Matrix boneMatrix = g_Renderer->GetBoneMatrix(item, 0);
|
|
|
|
|
2019-12-22 00:20:10 +01:00
|
|
|
int fxNumber = CreateNewEffect(item->roomNumber);
|
|
|
|
if (fxNumber != NO_ITEM)
|
|
|
|
{
|
|
|
|
FX_INFO* fx = &Effects[fxNumber];
|
2020-04-22 14:12:10 +02:00
|
|
|
fx->pos.xPos = item->pos.xPos + boneMatrix.Translation().x; // (MatrixPtr[M03] >> W2V_SHIFT);
|
|
|
|
fx->pos.yPos = item->pos.yPos + boneMatrix.Translation().y; // (MatrixPtr[M13] >> W2V_SHIFT);
|
|
|
|
fx->pos.zPos = item->pos.zPos + boneMatrix.Translation().z; // (MatrixPtr[M23] >> W2V_SHIFT);
|
2019-12-22 00:20:10 +01:00
|
|
|
fx->roomNumber = item->roomNumber;
|
|
|
|
fx->pos.yRot = 0;
|
|
|
|
fx->pos.zRot = 0;
|
|
|
|
fx->pos.xRot = 0;
|
|
|
|
|
2020-05-27 09:21:20 +02:00
|
|
|
if (flags & 0x10)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
fx->speed = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
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-05-27 09:21:20 +02:00
|
|
|
if (flags & 0x40)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
fx->fallspeed = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-05-27 09:21:20 +02:00
|
|
|
if ((flags & 0x80u) == 0)
|
2019-12-22 00:20:10 +01:00
|
|
|
fx->fallspeed = -(GetRandomControl() >> 8);
|
|
|
|
else
|
|
|
|
fx->fallspeed = -(GetRandomControl() >> 12);
|
|
|
|
}
|
|
|
|
fx->frameNumber = obj->meshIndex;
|
|
|
|
fx->objectNumber = ID_BODY_PART;
|
|
|
|
fx->shade = 16912;
|
|
|
|
fx->flag2 = damage;
|
|
|
|
|
|
|
|
if (item->objectNumber == ID_CRUMBLING_FLOOR)
|
|
|
|
{
|
|
|
|
fx->speed = 0;
|
|
|
|
fx->fallspeed = 0;
|
|
|
|
fx->counter = 61;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fx->counter = 0;
|
|
|
|
}
|
|
|
|
fx->flag1 = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
item->meshBits--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 1; i < obj->nmeshes; i++, bone += 3)
|
|
|
|
{
|
|
|
|
bits <<= 1;
|
|
|
|
|
|
|
|
if (bits & meshBits && bits & item->meshBits && (damage & 0x100 || !(GetRandomControl() & 3)))
|
|
|
|
{
|
2020-04-22 14:12:10 +02:00
|
|
|
Matrix boneMatrix = g_Renderer->GetBoneMatrix(item, i);
|
|
|
|
Matrix matrix = boneMatrix * world;
|
|
|
|
|
2019-12-22 00:20:10 +01:00
|
|
|
int fxNumber = CreateNewEffect(item->roomNumber);
|
|
|
|
if (fxNumber != NO_ITEM)
|
|
|
|
{
|
|
|
|
FX_INFO* fx = &Effects[fxNumber];
|
2020-04-22 14:12:10 +02:00
|
|
|
fx->pos.xPos = item->pos.xPos + matrix.Translation().x; // (MatrixPtr[3] >> 14);
|
|
|
|
fx->pos.yPos = item->pos.yPos + matrix.Translation().y; // (MatrixPtr[7] >> 14);
|
|
|
|
fx->pos.zPos = item->pos.zPos + matrix.Translation().z; // (MatrixPtr[11] >> 14);
|
2019-12-22 00:20:10 +01:00
|
|
|
fx->roomNumber = item->roomNumber;
|
|
|
|
fx->pos.yRot = 0;
|
|
|
|
fx->pos.zRot = 0;
|
|
|
|
fx->pos.xRot = 0;
|
|
|
|
if (damage & 0x10)
|
|
|
|
{
|
|
|
|
fx->speed = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (damage & 0x20)
|
|
|
|
fx->speed = GetRandomControl() >> 12;
|
|
|
|
else
|
|
|
|
fx->speed = GetRandomControl() >> 8;
|
|
|
|
}
|
|
|
|
if (damage & 0x40)
|
|
|
|
{
|
|
|
|
fx->fallspeed = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ((damage & 0x80u) == 0)
|
|
|
|
fx->fallspeed = -(GetRandomControl() >> 8);
|
|
|
|
else
|
|
|
|
fx->fallspeed = -(GetRandomControl() >> 12);
|
|
|
|
}
|
|
|
|
fx->objectNumber = ID_BODY_PART;
|
|
|
|
fx->shade = 16912;
|
|
|
|
fx->flag2 = damage;
|
|
|
|
fx->frameNumber = obj->meshIndex + 2 * i;
|
|
|
|
|
|
|
|
if (item->objectNumber == ID_CRUMBLING_FLOOR)
|
|
|
|
{
|
|
|
|
fx->speed = 0;
|
|
|
|
fx->fallspeed = 0;
|
|
|
|
fx->counter = 61;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fx->counter = 0;
|
|
|
|
}
|
|
|
|
fx->flag1 = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
item->meshBits -= bits;
|
|
|
|
}
|
2020-04-24 19:15:05 +02:00
|
|
|
}*/
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
return (item->meshBits == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int GetFreeShockwave()// (F)
|
|
|
|
{
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TriggerShockwave(PHD_3DPOS* pos, short innerRad, short outerRad, int speed, char r, char g, char b, char life, short angle, short flags)// (F)
|
|
|
|
{
|
|
|
|
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
|
|
|
|
2019-12-22 00:20:10 +01:00
|
|
|
SoundEffect(SFX_IMP_STONE_HIT, pos, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
2020-03-25 12:52:02 +01:00
|
|
|
spark->transType = COLADD;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->life = spark->sLife = (GetRandomControl() & 3) + 16;
|
|
|
|
|
|
|
|
int speed = (GetRandomControl() & 0xF) + vel;
|
2020-04-25 16:23:53 +02:00
|
|
|
spark->xVel = speed * 16 * phd_sin(rot) >> W2V_SHIFT;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->yVel = -512 - (GetRandomControl() & 0x1FF);
|
2020-04-25 16:23:53 +02:00
|
|
|
spark->zVel = speed * 16 * phd_cos(rot) >> W2V_SHIFT;
|
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-04-25 16:23:53 +02:00
|
|
|
x += (shift * phd_sin(angle) >> W2V_SHIFT);
|
|
|
|
z += (shift * phd_cos(angle) >> W2V_SHIFT);
|
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;
|
|
|
|
spark->dSize = spark->size >> 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
sw->speed -= (sw->speed >> 4);
|
|
|
|
|
|
|
|
if (LaraItem->hitPoints > 0)
|
|
|
|
{
|
|
|
|
if (sw->flags & 3)
|
|
|
|
{
|
|
|
|
short* frame = GetBestFrame(LaraItem);
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
if (sw->y <= LaraItem->pos.yPos + frame[2]
|
|
|
|
|| sw->y >= LaraItem->pos.yPos + frame[3] + 256
|
|
|
|
|| 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);
|
|
|
|
LaraItem->hitPoints -= sw->speed >> (((sw->flags >> 1) & 1) + 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TriggerExplosionBubble(int x, int y, int z, short roomNum)// (F)
|
|
|
|
{
|
|
|
|
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;
|
2020-05-30 15:55:23 +02:00
|
|
|
spark->transType = 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;
|
|
|
|
spark->sSize = size >> 1;
|
|
|
|
spark->size = size >> 1;
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*void TriggerExplosionSmokeEnd(int x, int y, int z, int unk)// (F)
|
|
|
|
{
|
|
|
|
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)
|
2020-05-30 15:55:23 +02:00
|
|
|
spark->transType = 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;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
/*void DrawLensFlares(ITEM_INFO* item)// (F)
|
|
|
|
{
|
|
|
|
GAME_VECTOR pos;
|
|
|
|
|
|
|
|
pos.x = item->pos.x_pos;
|
|
|
|
pos.y = item->pos.y_pos;
|
|
|
|
pos.z = item->pos.z_pos;
|
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);
|
|
|
|
}*/
|
|
|
|
|
2020-03-21 19:14:28 +01:00
|
|
|
void TriggerLightningGlow(int x, int y, int z, byte size, byte r, byte g, byte b)// (F)
|
2019-12-22 00:20:10 +01:00
|
|
|
{
|
|
|
|
SPARKS* spark = &Sparks[GetFreeSpark()];
|
|
|
|
|
2020-03-21 19:14:28 +01:00
|
|
|
spark->dG = g;
|
|
|
|
spark->sG = g;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->life = 4;
|
|
|
|
spark->sLife = 4;
|
2020-03-21 19:14:28 +01:00
|
|
|
spark->dR = r;
|
|
|
|
spark->sR = r;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->colFadeSpeed = 2;
|
2020-05-30 15:55:23 +02:00
|
|
|
spark->transType = COLADD;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->on = 1;
|
2020-03-21 19:14:28 +01:00
|
|
|
spark->dB = b;
|
|
|
|
spark->sB = b;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->fadeToBlack = 0;
|
2020-03-28 07:45:33 +01:00
|
|
|
spark->x = x;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->y = y;
|
|
|
|
spark->z = z;
|
|
|
|
spark->xVel = 0;
|
2020-03-28 07:45:33 +01:00
|
|
|
spark->yVel = 0;
|
|
|
|
spark->zVel = 0;
|
|
|
|
spark->flags = SP_DEF | SP_SCALE;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->scalar = 3;
|
|
|
|
spark->maxYvel = 0;
|
2020-03-21 19:14:28 +01:00
|
|
|
spark->def = Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_BLOOD;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->gravity = 0;
|
2020-03-21 19:14:28 +01:00
|
|
|
spark->dSize = spark->sSize = spark->size = size + (GetRandomControl() & 3);
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void TriggerFenceSparks(int x, int y, int z, int kill, int crane)//(F)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
spark->dG = spark->sR >> 1;
|
|
|
|
spark->dB = spark->sR >> 2;
|
|
|
|
|
|
|
|
spark->life = (GetRandomControl() & 7) + 24;
|
|
|
|
spark->sLife = (GetRandomControl() & 7) + 24;
|
2020-05-30 15:55:23 +02:00
|
|
|
spark->transType = COLADD;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->dynamic = -1;
|
|
|
|
|
|
|
|
spark->x = x;
|
|
|
|
spark->y = y;
|
|
|
|
spark->z = z;
|
|
|
|
|
|
|
|
spark->xVel = ((GetRandomControl() & 0xFF) - 128) << 2;
|
|
|
|
spark->yVel = (GetRandomControl() & 0xF) - ((kill << 5) + 8) + (crane << 4);
|
|
|
|
spark->zVel = ((GetRandomControl() & 0xFF) - 128) << 2;
|
|
|
|
|
|
|
|
if (crane != 0)
|
|
|
|
{
|
|
|
|
spark->friction = 5;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
spark->friction = 4;
|
|
|
|
}
|
|
|
|
|
2020-05-30 15:55:23 +02:00
|
|
|
spark->flags = SP_NONE;
|
2019-12-22 00:20:10 +01:00
|
|
|
spark->gravity = (GetRandomControl() & 0xF) + ((crane << 4) + 16);
|
|
|
|
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;
|
|
|
|
|
2020-05-30 15:55:23 +02:00
|
|
|
sptr->transType = COLADD;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
angle = GetRandomControl() << 3;
|
|
|
|
|
2020-04-25 16:23:53 +02:00
|
|
|
sptr->xVel = -phd_sin(angle) >> 5;
|
2019-12-22 00:20:10 +01:00
|
|
|
sptr->yVel = -640 - (GetRandomControl() & 0xFF);
|
2020-04-25 16:23:53 +02:00
|
|
|
sptr->zVel = phd_cos(angle) >> 5;
|
2019-12-22 00:20:10 +01:00
|
|
|
|
|
|
|
sptr->friction = 5;
|
|
|
|
sptr->flags = 0;
|
|
|
|
|
2020-03-23 06:59:21 +01:00
|
|
|
sptr->x = x + (sptr->xVel >> 3);
|
2019-12-22 00:20:10 +01:00
|
|
|
sptr->y = y - (sptr->yVel >> 5);
|
|
|
|
sptr->z = z + (sptr->zVel >> 3);
|
|
|
|
|
|
|
|
sptr->maxYvel = 0;
|
2020-03-23 06:59:21 +01:00
|
|
|
sptr->gravity = (GetRandomControl() & 0xF) + 64;
|
2019-12-22 00:20:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-22 12:27:12 +01:00
|
|
|
ENERGY_ARC* TriggerEnergyArc(PHD_VECTOR* start, PHD_VECTOR* end, byte r, byte g, byte b, short segmentSize, short life, short amplitude, byte flags, byte type)
|
2020-03-16 12:36:29 +01:00
|
|
|
{
|
|
|
|
ENERGY_ARC* arc = NULL;
|
|
|
|
|
2020-05-30 15:55:23 +02:00
|
|
|
for (int i = 0; i < MAX_ENERGYARCS; i++)
|
2020-03-16 12:36:29 +01:00
|
|
|
{
|
|
|
|
arc = &EnergyArcs[i];
|
|
|
|
if (arc->life == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arc == NULL)
|
2020-03-21 19:14:28 +01:00
|
|
|
return NULL;
|
2020-03-16 12:36:29 +01:00
|
|
|
|
|
|
|
arc->pos1 = *start;
|
2020-04-05 08:15:56 +02:00
|
|
|
arc->pos2.x = (end->x + 3 * start->x) >> 2;
|
|
|
|
arc->pos2.y = (end->y + 3 * start->y) >> 2;
|
|
|
|
arc->pos2.z = (end->z + 3 * start->z) >> 2;
|
|
|
|
arc->pos3.x = (start->x + 3 * end->x) >> 2;
|
|
|
|
arc->pos3.y = (start->y + 3 * end->y) >> 2;
|
|
|
|
arc->pos3.z = (start->z + 3 * end->z) >> 2;
|
2020-03-16 12:36:29 +01:00
|
|
|
arc->pos4 = *end;
|
2020-03-18 20:22:58 +01:00
|
|
|
arc->sLife = life;
|
2020-03-16 12:36:29 +01:00
|
|
|
arc->life = life;
|
2020-03-19 20:15:15 +01:00
|
|
|
arc->sAmplitude = amplitude;
|
2020-03-18 20:22:58 +01:00
|
|
|
arc->segmentSize = segmentSize;
|
2020-03-19 20:15:15 +01:00
|
|
|
arc->amplitude = 0;
|
2020-03-16 12:36:29 +01:00
|
|
|
arc->r = r;
|
|
|
|
arc->g = g;
|
|
|
|
arc->b = b;
|
2020-03-19 20:15:15 +01:00
|
|
|
arc->type = type;
|
2020-03-22 12:27:12 +01:00
|
|
|
arc->flags = flags;
|
2020-03-19 20:15:15 +01:00
|
|
|
arc->direction = 1;
|
|
|
|
arc->rotation = GetRandomControl();
|
2020-03-21 19:14:28 +01:00
|
|
|
|
|
|
|
return arc;
|
2020-03-16 12:36:29 +01:00
|
|
|
}
|