TombEngine/TR5Main/Game/effects/weather.cpp

388 lines
10 KiB
C++
Raw Normal View History

2021-09-14 12:05:36 +03:00
#include "framework.h"
2021-11-08 10:55:12 +03:00
#include "camera.h"
2021-09-14 12:05:36 +03:00
#include "savegame.h"
2021-09-15 11:13:47 +03:00
#include "weather.h"
2021-11-08 21:25:52 +03:00
#include "collide.h"
#include "effects/effects.h"
#include "Sound/sound.h"
#include "Specific/prng.h"
#include "Specific/setup.h"
#include "Scripting/GameScriptLevel.h"
using namespace TEN::Math::Random;
2021-09-14 12:05:36 +03:00
namespace TEN {
namespace Effects {
2021-09-15 11:13:47 +03:00
namespace Environment
2021-09-14 12:05:36 +03:00
{
2021-09-15 11:13:47 +03:00
EnvironmentController Weather;
2021-09-14 12:05:36 +03:00
2021-11-10 20:37:27 +03:00
float WeatherParticle::Transparency() const
{
2021-11-10 16:32:07 +03:00
float result = WEATHER_PARTICLES_TRANSPARENCY;
if (Life <= WEATHER_PARTICLES_NEAR_DEATH_LIFE_VALUE)
2021-11-10 16:32:07 +03:00
result *= Life / (float)WEATHER_PARTICLES_NEAR_DEATH_LIFE_VALUE;
if ((StartLife - Life) < (float)WEATHER_PARTICLES_NEAR_DEATH_LIFE_VALUE)
2021-11-10 16:32:07 +03:00
result *= (StartLife - Life) / (float)WEATHER_PARTICLES_NEAR_DEATH_LIFE_VALUE;
2021-11-10 20:16:04 +03:00
if (Type == WeatherType::Rain)
result *= 0.4f;
2021-11-10 16:32:07 +03:00
return result;
}
2021-11-08 10:55:12 +03:00
EnvironmentController::EnvironmentController()
{
2021-11-10 18:27:16 +03:00
Particles.reserve(WEATHER_PARTICLES_MAX_COUNT);
2021-11-08 10:55:12 +03:00
}
2021-09-15 11:13:47 +03:00
void EnvironmentController::Update()
2021-09-14 12:05:36 +03:00
{
GameScriptLevel* level = g_GameFlow->GetLevel(CurrentLevel);
UpdateSky(level);
UpdateStorm(level);
UpdateWind(level);
UpdateFlash(level);
2021-11-08 10:55:12 +03:00
UpdateWeather(level);
2021-11-10 18:27:16 +03:00
SpawnWeatherParticles(level);
}
void EnvironmentController::Clear()
{
// Clear storm vars
StormTimer = 0;
StormSkyColor = 1;
StormSkyColor2 = 1;
// Clear wind vars
WindCurrent = WindFinalX = WindFinalZ = 0;
WindAngle = WindDAngle = 2048;
// Clear flash vars
FlashProgress = 0.0f;
2021-09-15 14:24:03 +03:00
FlashColorBase = Vector3::Zero;
2021-11-10 18:27:16 +03:00
2021-11-10 19:37:11 +03:00
// Clear weather
2021-11-10 18:27:16 +03:00
Particles.clear();
}
2021-09-15 11:13:47 +03:00
void EnvironmentController::Flash(int r, int g, int b, float speed)
{
FlashProgress = 1.0f;
2021-09-15 13:16:14 +03:00
FlashSpeed = std::clamp(speed, 0.005f, 1.0f);
2021-09-15 14:24:03 +03:00
FlashColorBase = Vector3(std::clamp(r, 0, UCHAR_MAX) / (float)UCHAR_MAX,
std::clamp(g, 0, UCHAR_MAX) / (float)UCHAR_MAX,
2021-09-15 14:24:03 +03:00
std::clamp(b, 0, UCHAR_MAX) / (float)UCHAR_MAX);
}
void EnvironmentController::UpdateSky(GameScriptLevel* level)
{
2021-09-14 12:05:36 +03:00
if (level->Layer1.Enabled)
{
SkyPosition1 += level->Layer1.CloudSpeed;
2021-11-10 20:16:04 +03:00
if (SkyPosition1 <= SKY_POSITION_LIMIT)
2021-09-14 12:05:36 +03:00
{
if (SkyPosition1 < 0)
2021-11-10 20:16:04 +03:00
SkyPosition1 += SKY_POSITION_LIMIT;
2021-09-14 12:05:36 +03:00
}
else
{
2021-11-10 20:16:04 +03:00
SkyPosition1 -= SKY_POSITION_LIMIT;
2021-09-14 12:05:36 +03:00
}
}
if (level->Layer2.Enabled)
{
SkyPosition2 += level->Layer2.CloudSpeed;
2021-11-10 20:16:04 +03:00
if (SkyPosition2 <= SKY_POSITION_LIMIT)
2021-09-14 12:05:36 +03:00
{
if (SkyPosition2 < 0)
2021-11-10 20:16:04 +03:00
SkyPosition2 += SKY_POSITION_LIMIT;
2021-09-14 12:05:36 +03:00
}
else
{
2021-11-10 20:16:04 +03:00
SkyPosition2 -= SKY_POSITION_LIMIT;
2021-09-14 12:05:36 +03:00
}
}
}
2021-09-14 12:05:36 +03:00
void EnvironmentController::UpdateStorm(GameScriptLevel* level)
{
2021-09-14 12:05:36 +03:00
auto color = Vector4(level->Layer1.R / 255.0f, level->Layer1.G / 255.0f, level->Layer1.B / 255.0f, 1.0f);
if (level->Storm)
{
if (StormCount || StormRand)
2021-09-14 12:05:36 +03:00
{
UpdateLightning();
2021-09-14 12:05:36 +03:00
if (StormTimer > -1)
StormTimer--;
if (!StormTimer)
SoundEffect(SFX_TR4_THUNDER_RUMBLE, NULL, 0);
}
else if (!(rand() & 0x7F))
{
StormCount = (rand() & 0x1F) + 16;
2021-09-14 12:05:36 +03:00
StormTimer = (rand() & 3) + 12;
}
auto flashBrightness = StormSkyColor / 255.0f;
2021-09-14 12:05:36 +03:00
auto r = std::clamp(color.x + flashBrightness, 0.0f, 1.0f);
auto g = std::clamp(color.y + flashBrightness, 0.0f, 1.0f);
auto b = std::clamp(color.z + flashBrightness, 0.0f, 1.0f);
SkyCurrentColor = Vector4(r, g, b, color.w);
2021-09-14 12:05:36 +03:00
}
else
SkyCurrentColor = color;
2021-09-14 12:05:36 +03:00
}
void EnvironmentController::UpdateLightning()
2021-09-14 16:00:06 +03:00
{
StormCount--;
2021-09-15 11:13:47 +03:00
if (StormCount <= 0)
2021-09-14 12:05:36 +03:00
{
StormSkyColor = 0;
StormRand = 0;
2021-09-14 12:05:36 +03:00
}
else if (StormCount < 5 && StormSkyColor < 50)
2021-09-14 12:05:36 +03:00
{
auto newColor = StormSkyColor - StormCount * 2;
2021-09-14 12:05:36 +03:00
if (newColor < 0)
newColor = 0;
StormSkyColor = newColor;
2021-09-14 12:05:36 +03:00
}
else if (StormCount)
2021-09-14 12:05:36 +03:00
{
StormRand = ((rand() & 0x1FF - StormRand) >> 1) + StormRand;
StormSkyColor2 += StormRand * StormSkyColor2 >> 8;
StormSkyColor = StormSkyColor2;
2021-11-10 21:04:03 +03:00
if (StormSkyColor > UCHAR_MAX)
StormSkyColor = UCHAR_MAX;
2021-09-14 12:05:36 +03:00
}
}
void EnvironmentController::UpdateWind(GameScriptLevel* level)
{
WindCurrent += (GetRandomControl() & 7) - 3;
if (WindCurrent <= -2)
WindCurrent++;
else if (WindCurrent >= 9)
WindCurrent--;
WindDAngle = (WindDAngle + 2 * (GetRandomControl() & 63) - 64) & 0x1FFE;
if (WindDAngle < 1024)
WindDAngle = 2048 - WindDAngle;
else if (WindDAngle > 3072)
WindDAngle += 6144 - 2 * WindDAngle;
WindAngle = (WindAngle + ((WindDAngle - WindAngle) >> 3)) & 0x1FFE;
WindFinalX = WindCurrent * phd_sin(WindAngle << 3);
WindFinalZ = WindCurrent * phd_cos(WindAngle << 3);
}
void EnvironmentController::UpdateFlash(GameScriptLevel* level)
{
if (FlashProgress > 0.0f)
{
FlashProgress -= FlashSpeed;
if (FlashProgress < 0.0f)
FlashProgress = 0.0f;
}
2021-09-15 14:24:03 +03:00
if (FlashProgress == 0.0f)
FlashColorBase = Vector3::Zero;
}
2021-11-08 10:55:12 +03:00
2021-11-10 18:27:16 +03:00
void EnvironmentController::UpdateWeather(GameScriptLevel* level)
{
2021-11-10 20:37:27 +03:00
for (auto& p : Particles)
2021-11-08 10:55:12 +03:00
{
auto oldPos = p.Position;
2021-11-08 21:25:52 +03:00
if (!p.Stopped)
{
p.Position.x += p.Velocity.x;
p.Position.y += ((int)p.Velocity.y & (~7)) >> 1;
p.Position.z += p.Velocity.z;
}
2021-11-08 10:55:12 +03:00
auto& r = g_Level.Rooms[p.Room];
if (p.Position.y <= r.maxceiling || p.Position.y >= r.minfloor ||
2021-11-08 21:25:52 +03:00
p.Position.z <= (r.z + WALL_SIZE) || p.Position.z >= (r.z + ((r.zSize - 1) << 10)) ||
p.Position.x <= (r.x + WALL_SIZE) || p.Position.x >= (r.x + ((r.xSize - 1) << 10)))
2021-11-08 10:55:12 +03:00
{
2021-11-08 21:25:52 +03:00
auto coll = GetCollisionResult(p.Position.x, p.Position.y, p.Position.z, p.Room);
bool inSubstance = g_Level.Rooms[coll.RoomNumber].flags & (ENV_FLAG_WATER | ENV_FLAG_SWAMP);
bool landed = coll.Position.Floor < p.Position.y;
2021-11-08 10:55:12 +03:00
2021-11-08 21:25:52 +03:00
if (coll.RoomNumber == p.Room)
2021-11-08 10:55:12 +03:00
{
2021-11-08 21:39:38 +03:00
p.Enabled = false; // Spawned in same room, needs to be on portal
2021-11-08 10:55:12 +03:00
continue;
}
2021-11-08 21:25:52 +03:00
else if (inSubstance || landed)
2021-11-08 10:55:12 +03:00
{
2021-11-08 21:25:52 +03:00
p.Stopped = true;
2021-11-08 10:55:12 +03:00
p.Position = oldPos;
p.Life = (p.Life > WEATHER_PARTICLES_NEAR_DEATH_LIFE_VALUE) ? WEATHER_PARTICLES_NEAR_DEATH_LIFE_VALUE : p.Life;
if (inSubstance)
{
SetupRipple(p.Position.x, p.Position.y, p.Position.z, GenerateFloat(16, 24),
RIPPLE_FLAG_SHORT_LIFE | RIPPLE_FLAG_RAND_ROT | RIPPLE_FLAG_LOW_OPACITY,
Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_RIPPLES);
}
2021-11-10 18:27:16 +03:00
if (p.Type == WeatherType::Rain)
p.Enabled = false;
2021-11-08 10:55:12 +03:00
}
else
2021-11-08 21:25:52 +03:00
p.Room = coll.RoomNumber;
2021-11-08 10:55:12 +03:00
}
2021-11-10 18:27:16 +03:00
if (p.Life <= 0 ||
abs(Camera.pos.x - p.Position.x) > COLLISION_CHECK_DISTANCE ||
abs(Camera.pos.z - p.Position.z) > COLLISION_CHECK_DISTANCE)
2021-11-08 10:55:12 +03:00
{
2021-11-10 18:27:16 +03:00
if (p.Life <= 0)
2021-11-08 10:55:12 +03:00
{
2021-11-08 21:25:52 +03:00
p.Enabled = false; // Turn it off.
2021-11-08 10:55:12 +03:00
continue;
}
else if (p.Life > WEATHER_PARTICLES_NEAR_DEATH_LIFE_VALUE)
p.Life = WEATHER_PARTICLES_NEAR_DEATH_LIFE_VALUE;
2021-11-08 10:55:12 +03:00
}
2021-11-08 21:25:52 +03:00
if (!p.Stopped)
{
2021-11-10 18:27:16 +03:00
switch (p.Type)
{
case WeatherType::Snow:
if (p.Velocity.x < (WindFinalX << 2))
p.Velocity.x += GenerateFloat(0.5f, 2.5f);
else if (p.Velocity.x > (WindFinalX << 2))
p.Velocity.x -= GenerateFloat(0.5f, 2.5f);
if (p.Velocity.z < (WindFinalZ << 2))
p.Velocity.z += GenerateFloat(0.5f, 2.5f);
else if (p.Velocity.z > (WindFinalZ << 2))
p.Velocity.z -= GenerateFloat(0.5f, 2.5f);
if (p.Velocity.y < p.Size / 2)
p.Velocity.y += p.Size / 10.0f;
2021-11-08 21:25:52 +03:00
2021-11-10 18:27:16 +03:00
break;
2021-11-08 21:25:52 +03:00
2021-11-10 18:27:16 +03:00
case WeatherType::Rain:
2021-11-10 16:21:41 +03:00
2021-11-10 18:27:16 +03:00
auto random = GetRandomDraw();
if ((random & 3) != 3)
{
p.Velocity.x += (float)((random & 3) - 1);
if (p.Velocity.x < -4)
p.Velocity.x = -4;
else if (p.Velocity.x > 4)
p.Velocity.x = 4;
}
random = (random >> 2) & 3;
if (random != 3)
{
p.Velocity.z += random - 1;
if (p.Velocity.z < -4)
p.Velocity.z = -4;
else if (p.Velocity.z > 4)
p.Velocity.z = 4;
}
if (p.Velocity.y < p.Size * 4)
2021-11-10 20:16:04 +03:00
p.Velocity.y += p.Size / 4.0f;
2021-11-10 18:27:16 +03:00
if (p.Life > 512)
p.Enabled = false;
}
2021-11-08 21:25:52 +03:00
}
2021-11-08 10:55:12 +03:00
p.Life -= 2;
}
}
2021-11-10 20:16:04 +03:00
void EnvironmentController::SpawnWeatherParticles(GameScriptLevel* level)
{
// Clean up dead particles
if (Particles.size() > 0)
Particles.erase(std::remove_if(Particles.begin(), Particles.end(), [](const WeatherParticle& part) { return !part.Enabled; }), Particles.end());
2021-11-11 01:16:27 +03:00
if (level->Weather == WeatherType::None || level->WeatherStrength == 0.0f)
2021-11-10 20:16:04 +03:00
return;
2021-11-11 01:16:27 +03:00
int spawnDensity = round((float)(level->Weather == WeatherType::Rain ? RAIN_SPAWN_DENSITY : SNOW_SPAWN_DENSITY) * level->WeatherStrength);
int maxCount = (level->Weather == WeatherType::Rain) ? WEATHER_PARTICLES_MAX_COUNT : WEATHER_PARTICLES_MAX_COUNT / SNOW_PARTICLES_COUNT_DIVIDER;
2021-11-10 20:16:04 +03:00
int newParticlesCount = 0;
2021-11-11 01:16:27 +03:00
if (level->Weather != WeatherType::None)
2021-11-10 20:16:04 +03:00
{
while (Particles.size() < maxCount)
{
if (newParticlesCount > spawnDensity)
break;
newParticlesCount++;
auto radius = (GetRandomDraw() & (WALL_SIZE * 8 - 1)) - WALL_SIZE * 4;
short angle = (GetRandomDraw() & 0xFFFF);
auto xPos = Camera.pos.x + ((int)(phd_cos(angle) * radius));
auto zPos = Camera.pos.z + ((int)(phd_sin(angle) * radius));
auto yPos = Camera.pos.y - (WALL_SIZE * 4 + GetRandomDraw() & (WALL_SIZE * 4 - 1));
if (IsRoomOutside(xPos, yPos, zPos) < 0)
continue;
if (g_Level.Rooms[IsRoomOutsideNo].flags & ENV_FLAG_WATER)
continue;
auto part = WeatherParticle();
2021-11-11 01:16:27 +03:00
switch (level->Weather)
2021-11-10 20:16:04 +03:00
{
case WeatherType::Snow:
part.Size = MAX_SNOW_SIZE + ((GetRandomDraw() & (MAX_SNOW_SIZE / 2)) - (MAX_SNOW_SIZE / 2));
part.Velocity.x = (GetRandomDraw() & 7) - 4;
part.Velocity.y = ((GetRandomDraw() & 15) + 8) << 3;
part.Velocity.z = (GetRandomDraw() & 7) - 4;
part.Life = 48 + (64 - ((int)part.Velocity.y >> 2));
break;
case WeatherType::Rain:
part.Size = MAX_RAIN_SIZE + GenerateInt(-MAX_RAIN_SIZE / 4, MAX_RAIN_SIZE / 4);
part.Velocity.x = (GetRandomDraw() & 7) - 4;
part.Velocity.y = ((GetRandomDraw() & 3) + 24);
part.Velocity.z = (GetRandomDraw() & 7) - 4;
part.Life = 256 - (int)part.Velocity.y;
break;
}
2021-11-11 01:16:27 +03:00
part.Type = level->Weather;
2021-11-10 20:16:04 +03:00
part.Room = IsRoomOutsideNo;
part.Position.x = xPos;
part.Position.y = yPos;
part.Position.z = zPos;
part.Stopped = false;
part.Enabled = true;
part.StartLife = part.Life;
Particles.push_back(part);
}
}
}
2021-09-14 12:05:36 +03:00
}}}