diff --git a/TSOClient/tso.client/Rendering/City/Terrain.cs b/TSOClient/tso.client/Rendering/City/Terrain.cs
index 19d127b1..51265042 100644
--- a/TSOClient/tso.client/Rendering/City/Terrain.cs
+++ b/TSOClient/tso.client/Rendering/City/Terrain.cs
@@ -1212,9 +1212,11 @@ namespace FSO.Client.Rendering.City
public void SetTimeOfDay(double time)
{
time = Math.Min(0.999999999, time);
- Time = (float)time;
m_TintColor = TimeOfDayConfig.ColorFromTime(time);
+ Time = (float)time;
+ time = FinaleUtils.BiasSunTime(time);
+
if (Weather.Darken > 0)
{
//tint the outside colour, usually with some darkening effect.
@@ -1240,6 +1242,8 @@ namespace FSO.Client.Rendering.City
modTime = (time - DayOffset) * 0.5 / DayDuration;
}
+ modTime = FinaleUtils.BiasSunTime(modTime);
+
Transform *= Matrix.CreateRotationY((float)((modTime+0.5) * Math.PI * 2.0)); //Controls the rotation of the sun/moon around the city.
Transform *= Matrix.CreateRotationZ((float)(Math.PI*(45.0/180.0))); //Sun is at an angle of 45 degrees to horizon at it's peak. idk why, it's winter maybe? looks nice either way
Transform *= Matrix.CreateRotationY((float)(Math.PI * 0.3)); //Offset from front-back a little. This might need some adjusting for the nicest sunset/sunrise locations.
@@ -1820,7 +1824,9 @@ namespace FSO.Client.Rendering.City
VertexShader.CurrentTechnique = VertexShader.Techniques[1];
VertexShader.CurrentTechnique.Passes[passIndex].Apply();
- var night = Time < 0.25f || Time > 0.75f;
+
+ double biasTime = FinaleUtils.BiasSunTime(Time);
+ var night = biasTime < 0.25f || biasTime > 0.75f;
if (!useLocked || NearFacades == null)
{
diff --git a/TSOClient/tso.common/FSO.Common.csproj b/TSOClient/tso.common/FSO.Common.csproj
index 1d4973e3..02883c0c 100644
--- a/TSOClient/tso.common/FSO.Common.csproj
+++ b/TSOClient/tso.common/FSO.Common.csproj
@@ -162,6 +162,7 @@
+
diff --git a/TSOClient/tso.common/Rendering/FinaleUtils.cs b/TSOClient/tso.common/Rendering/FinaleUtils.cs
new file mode 100644
index 00000000..37ce3c67
--- /dev/null
+++ b/TSOClient/tso.common/Rendering/FinaleUtils.cs
@@ -0,0 +1,88 @@
+using Microsoft.Xna.Framework;
+using System;
+
+namespace FSO.Common.Rendering
+{
+ public static class FinaleUtils
+ {
+ private static Color[] FinaleColors = new Color[]
+ {
+ new Color(2, 2, 2),
+ new Color(2, 2, 2),
+ Color.Lerp(new Color(0, 0, 0), new Color(50, 70, 122)*1.25f, 0.5f),
+ new Color(70, 70, 70)*1.25f,
+ new Color(217, 109, 50), //sunrise
+ new Color(255, 255, 255),
+ new Color(255, 255, 255), //peak
+ new Color(255, 255, 255), //peak
+ new Color(255, 255, 255),
+ new Color(255, 255, 255),
+ Color.Lerp(new Color(255, 255, 255), new Color(217, 109, 50), 0.33f),
+ Color.Lerp(new Color(255, 255, 255), new Color(217, 109, 25), 0.66f),
+ new Color(225, 64, 0), //sunset
+ new Color(0, 0, 0)
+ };
+
+ private static double DayOffset = 0.25;
+ private static double DayDuration = 0.60;
+
+ private static double TargetEnd = 1.04;
+
+ public static double BiasSunTime(double modTime)
+ {
+ if (IsFinale())
+ {
+ double dayMid = DayOffset + DayDuration / 2;
+ double mainEnd = DayOffset + DayDuration;
+
+ double rescaleDay = (TargetEnd - dayMid) / (mainEnd - dayMid);
+
+ if (modTime > dayMid)
+ {
+ modTime = dayMid + (modTime - dayMid) / rescaleDay;
+ }
+ }
+
+ return modTime;
+ }
+
+ public static Vector3 BiasSunIntensity(Vector3 intensity, float time)
+ {
+ if (IsFinale())
+ {
+ if (time > 0.70)
+ {
+ intensity = Vector3.Lerp(new Vector3(0.6f), new Vector3(1, 0.2f, 0.1f), (time - 0.70f) / 0.25f);
+ }
+ else if (time > 0.5)
+ {
+ intensity = Vector3.Lerp(intensity, new Vector3(0.6f), (time - 0.5f) / 0.2f);
+ }
+
+ if (time > 0.995)
+ {
+ intensity *= (1f - time) * 200f;
+ }
+ }
+
+ return intensity;
+ }
+
+ public static bool IsFinale()
+ {
+ var time = DateTime.UtcNow;
+
+ return time.Year == 2024 && time.Month == 12 && ((time.Day == 8 && time.Hour == 23) || (time.Day == 9 && time.Hour == 0));
+ }
+
+ public static float GetDarkness()
+ {
+ return IsFinale() ? 1.0f : 0.8f;
+ }
+
+ public static Color[] SwapFinaleColors(Color[] colors)
+ {
+ return IsFinale() ? FinaleColors : colors;
+ }
+ }
+}
diff --git a/TSOClient/tso.common/Rendering/TimeOfDayConfig.cs b/TSOClient/tso.common/Rendering/TimeOfDayConfig.cs
index df317743..7c9a4ffb 100644
--- a/TSOClient/tso.common/Rendering/TimeOfDayConfig.cs
+++ b/TSOClient/tso.common/Rendering/TimeOfDayConfig.cs
@@ -54,14 +54,19 @@ namespace FSO.Common.Rendering
public static Color ColorFromTime(double time)
{
- Color col1 = m_TimeColors[(int)Math.Floor(time * (m_TimeColors.Length - 1))]; //first colour
- Color col2 = m_TimeColors[(int)Math.Floor(time * (m_TimeColors.Length - 1)) + 1]; //second colour
- if (DarknessMultiplier != 1.0)
+ Color[] colors = FinaleUtils.SwapFinaleColors(m_TimeColors);
+
+ Color col1 = colors[(int)Math.Floor(time * (colors.Length - 1))]; //first colour
+ Color col2 = colors[(int)Math.Floor(time * (colors.Length - 1)) + 1]; //second colour
+
+ float darkness = FinaleUtils.GetDarkness();
+
+ if (darkness != 1.0)
{
- col1 = Color.Lerp(Color.White, col1, DarknessMultiplier);
- col2 = Color.Lerp(Color.White, col2, DarknessMultiplier);
+ col1 = Color.Lerp(Color.White, col1, darkness);
+ col2 = Color.Lerp(Color.White, col2, darkness);
}
- double Progress = (time * (m_TimeColors.Length - 1)) % 1; //interpolation progress (mod 1)
+ double Progress = (time * (colors.Length - 1)) % 1; //interpolation progress (mod 1)
return PowColor(Color.Lerp(col1, col2, (float)Progress), 2.2f); //linearly interpolate between the two colours for this specific time.
}
diff --git a/TSOClient/tso.content/Content/DX/Effects/2DWorldBatch.xnb b/TSOClient/tso.content/Content/DX/Effects/2DWorldBatch.xnb
index 5ac15276..90102d54 100644
Binary files a/TSOClient/tso.content/Content/DX/Effects/2DWorldBatch.xnb and b/TSOClient/tso.content/Content/DX/Effects/2DWorldBatch.xnb differ
diff --git a/TSOClient/tso.content/Content/DX/Effects/GrassShader.xnb b/TSOClient/tso.content/Content/DX/Effects/GrassShader.xnb
index cec98caa..910a8910 100644
Binary files a/TSOClient/tso.content/Content/DX/Effects/GrassShader.xnb and b/TSOClient/tso.content/Content/DX/Effects/GrassShader.xnb differ
diff --git a/TSOClient/tso.content/Content/DX/Effects/GrassShaderiOS.xnb b/TSOClient/tso.content/Content/DX/Effects/GrassShaderiOS.xnb
index 5721e3c3..ab705baf 100644
Binary files a/TSOClient/tso.content/Content/DX/Effects/GrassShaderiOS.xnb and b/TSOClient/tso.content/Content/DX/Effects/GrassShaderiOS.xnb differ
diff --git a/TSOClient/tso.content/Content/DX/Effects/ParticleShader.xnb b/TSOClient/tso.content/Content/DX/Effects/ParticleShader.xnb
index 2d30a6f3..24347009 100644
Binary files a/TSOClient/tso.content/Content/DX/Effects/ParticleShader.xnb and b/TSOClient/tso.content/Content/DX/Effects/ParticleShader.xnb differ
diff --git a/TSOClient/tso.content/Content/DX/Effects/RCObject.xnb b/TSOClient/tso.content/Content/DX/Effects/RCObject.xnb
index dd79a8af..2e35d95d 100644
Binary files a/TSOClient/tso.content/Content/DX/Effects/RCObject.xnb and b/TSOClient/tso.content/Content/DX/Effects/RCObject.xnb differ
diff --git a/TSOClient/tso.content/Content/DX/Fonts/mobile.xnb b/TSOClient/tso.content/Content/DX/Fonts/mobile.xnb
index 17396d5a..ae59aefb 100644
Binary files a/TSOClient/tso.content/Content/DX/Fonts/mobile.xnb and b/TSOClient/tso.content/Content/DX/Fonts/mobile.xnb differ
diff --git a/TSOClient/tso.content/Content/DX/Fonts/simdialogue.xnb b/TSOClient/tso.content/Content/DX/Fonts/simdialogue.xnb
index 59f5fea0..43bd31df 100644
Binary files a/TSOClient/tso.content/Content/DX/Fonts/simdialogue.xnb and b/TSOClient/tso.content/Content/DX/Fonts/simdialogue.xnb differ
diff --git a/TSOClient/tso.content/Content/DX/Fonts/trebuchet.xnb b/TSOClient/tso.content/Content/DX/Fonts/trebuchet.xnb
index d57c32e5..a3b6a423 100644
Binary files a/TSOClient/tso.content/Content/DX/Fonts/trebuchet.xnb and b/TSOClient/tso.content/Content/DX/Fonts/trebuchet.xnb differ
diff --git a/TSOClient/tso.content/Content/OGL/Effects/2DWorldBatch.xnb b/TSOClient/tso.content/Content/OGL/Effects/2DWorldBatch.xnb
index 49a8fa46..ace9246b 100644
Binary files a/TSOClient/tso.content/Content/OGL/Effects/2DWorldBatch.xnb and b/TSOClient/tso.content/Content/OGL/Effects/2DWorldBatch.xnb differ
diff --git a/TSOClient/tso.content/Content/OGL/Effects/GrassShader.xnb b/TSOClient/tso.content/Content/OGL/Effects/GrassShader.xnb
index ac1668cd..0d90a4bd 100644
Binary files a/TSOClient/tso.content/Content/OGL/Effects/GrassShader.xnb and b/TSOClient/tso.content/Content/OGL/Effects/GrassShader.xnb differ
diff --git a/TSOClient/tso.content/Content/OGL/Effects/GrassShaderiOS.xnb b/TSOClient/tso.content/Content/OGL/Effects/GrassShaderiOS.xnb
index 2eb10796..3bc96be6 100644
Binary files a/TSOClient/tso.content/Content/OGL/Effects/GrassShaderiOS.xnb and b/TSOClient/tso.content/Content/OGL/Effects/GrassShaderiOS.xnb differ
diff --git a/TSOClient/tso.content/Content/OGL/Effects/ParticleShader.xnb b/TSOClient/tso.content/Content/OGL/Effects/ParticleShader.xnb
index 82931a85..97954255 100644
Binary files a/TSOClient/tso.content/Content/OGL/Effects/ParticleShader.xnb and b/TSOClient/tso.content/Content/OGL/Effects/ParticleShader.xnb differ
diff --git a/TSOClient/tso.content/Content/OGL/Effects/RCObject.xnb b/TSOClient/tso.content/Content/OGL/Effects/RCObject.xnb
index a25902ed..2fb294a0 100644
Binary files a/TSOClient/tso.content/Content/OGL/Effects/RCObject.xnb and b/TSOClient/tso.content/Content/OGL/Effects/RCObject.xnb differ
diff --git a/TSOClient/tso.content/Content/OGL/Effects/RCObjectiOS.xnb b/TSOClient/tso.content/Content/OGL/Effects/RCObjectiOS.xnb
index f95fea9c..a0b91a3d 100644
Binary files a/TSOClient/tso.content/Content/OGL/Effects/RCObjectiOS.xnb and b/TSOClient/tso.content/Content/OGL/Effects/RCObjectiOS.xnb differ
diff --git a/TSOClient/tso.content/Content/OGL/Fonts/mobile.xnb b/TSOClient/tso.content/Content/OGL/Fonts/mobile.xnb
index 01aa0dc3..62e5e2b3 100644
Binary files a/TSOClient/tso.content/Content/OGL/Fonts/mobile.xnb and b/TSOClient/tso.content/Content/OGL/Fonts/mobile.xnb differ
diff --git a/TSOClient/tso.content/Content/OGL/Fonts/simdialogue.xnb b/TSOClient/tso.content/Content/OGL/Fonts/simdialogue.xnb
index 7f84f704..8f890b24 100644
Binary files a/TSOClient/tso.content/Content/OGL/Fonts/simdialogue.xnb and b/TSOClient/tso.content/Content/OGL/Fonts/simdialogue.xnb differ
diff --git a/TSOClient/tso.content/Content/OGL/Fonts/trebuchet.xnb b/TSOClient/tso.content/Content/OGL/Fonts/trebuchet.xnb
index 502e5352..83a8e9a4 100644
Binary files a/TSOClient/tso.content/Content/OGL/Fonts/trebuchet.xnb and b/TSOClient/tso.content/Content/OGL/Fonts/trebuchet.xnb differ
diff --git a/TSOClient/tso.content/Content/Textures/skycolfinal.png b/TSOClient/tso.content/Content/Textures/skycolfinal.png
new file mode 100644
index 00000000..119f6aa1
Binary files /dev/null and b/TSOClient/tso.content/Content/Textures/skycolfinal.png differ
diff --git a/TSOClient/tso.content/ContentSrc/Effects/LightingCommon.fx b/TSOClient/tso.content/ContentSrc/Effects/LightingCommon.fx
index 96f0d259..25798772 100644
--- a/TSOClient/tso.content/ContentSrc/Effects/LightingCommon.fx
+++ b/TSOClient/tso.content/ContentSrc/Effects/LightingCommon.fx
@@ -35,14 +35,14 @@ float4 lightColorFloor(float4 intensities) {
float avg = (intensities.r + intensities.g + intensities.b) / 3;
//floor shadow is how much less than average the alpha component is
- float fshad = intensities.a / avg;
+ float fshad = intensities.a / max(0.0001, avg);
return lerp(OutsideDark, float4(intensities.rgb * LightingAdjust, 1), (fshad - MinAvg.x) * MinAvg.y);
}
float4 lightColorIAvg(float4 intensities, float i, float avg) {
- float fshad = intensities.a / avg;
+ float fshad = intensities.a / max(0.0001, avg);
fshad = lerp(fshad, 1, i);
return lerp(OutsideDark, float4(intensities.rgb * LightingAdjust, 1), (fshad - MinAvg.x) * MinAvg.y);
@@ -53,7 +53,7 @@ float4 lightColorI(float4 intensities, float i) {
float avg = (intensities.r + intensities.g + intensities.b) / 3;
//floor shadow is how much less than average the alpha component is
- float fshad = intensities.a / avg;
+ float fshad = intensities.a / max(0.0001, avg);
fshad = lerp(fshad, 1, i);
return lerp(OutsideDark, float4(intensities.rgb * LightingAdjust, 1), (fshad - MinAvg.x) * MinAvg.y);
diff --git a/TSOClient/tso.content/ContentSrc/test.png b/TSOClient/tso.content/ContentSrc/test.png
index b8e94727..398fdd1d 100644
Binary files a/TSOClient/tso.content/ContentSrc/test.png and b/TSOClient/tso.content/ContentSrc/test.png differ
diff --git a/TSOClient/tso.simantics/Primitives/VMBurn.cs b/TSOClient/tso.simantics/Primitives/VMBurn.cs
index cd0157e4..d1eba2ef 100644
--- a/TSOClient/tso.simantics/Primitives/VMBurn.cs
+++ b/TSOClient/tso.simantics/Primitives/VMBurn.cs
@@ -14,10 +14,12 @@ namespace FSO.SimAntics.Primitives
public override VMPrimitiveExitCode Execute(VMStackFrame context, VMPrimitiveOperand args)
{
var operand = (VMBurnOperand)args;
- if (!context.VM.TS1 && (context.VM.Tuning.GetTuning("special", 0, 0) != 1f || context.VM.TSOState.CommunityLot))
+ if (!context.VM.TS1 && (context.VM.Tuning.GetTuning("special", 0, 0) != 1f))
return VMPrimitiveExitCode.GOTO_FALSE; //fire disabled for now
- if ((int)context.VM.Context.NextRandom(10000) >= context.VM.Context.Clock.FirePercent)
+ bool isSpread = operand.Type != VMBurnType.StackObject;
+
+ if (isSpread && (int)context.VM.Context.NextRandom(10000) >= context.VM.Context.Clock.FirePercent)
{
return VMPrimitiveExitCode.GOTO_FALSE;
}
@@ -26,7 +28,7 @@ namespace FSO.SimAntics.Primitives
if (context.VM.Context.RoomInfo[myRoom].Room.IsPool) return VMPrimitiveExitCode.GOTO_FALSE;
//as fires burn, the chance they can spread lowers dramatically.
- context.VM.Context.Clock.FirePercent -= 500; // lower by 5% every spread. 40 spreads reaches 0.
+ if (isSpread) context.VM.Context.Clock.FirePercent -= 500; // lower by 5% every spread. 40 spreads reaches 0.
if (context.VM.Context.Clock.FirePercent < 0) context.VM.Context.Clock.FirePercent = 0;
//begin the burn setup.
diff --git a/TSOClient/tso.simantics/VMClock.cs b/TSOClient/tso.simantics/VMClock.cs
index 190d1de9..c8b5d974 100644
--- a/TSOClient/tso.simantics/VMClock.cs
+++ b/TSOClient/tso.simantics/VMClock.cs
@@ -15,7 +15,7 @@ namespace FSO.SimAntics
public int Month = 6;
public int Year = 1997;
- public int FirePercent;
+ public int FirePercent = 20000;
public long UTCStart = DateTime.UtcNow.Ticks;
public int TimeOfDay
diff --git a/TSOClient/tso.world/Components/AbstractSkyDome.cs b/TSOClient/tso.world/Components/AbstractSkyDome.cs
index 0f07ac7b..7d86a4d1 100644
--- a/TSOClient/tso.world/Components/AbstractSkyDome.cs
+++ b/TSOClient/tso.world/Components/AbstractSkyDome.cs
@@ -1,5 +1,6 @@
using FSO.Common;
using FSO.Common.Model;
+using FSO.Common.Rendering;
using FSO.Common.Utils;
using FSO.Files;
using FSO.LotView.Model;
@@ -14,6 +15,7 @@ namespace FSO.LotView.Components
public class AbstractSkyDome : IDisposable
{
private static string DefaultSkyCol = "Textures/skycol.png";
+ private static string FinalSkyCol = "Textures/skycolfinal.png";
private VertexBuffer Verts;
private IndexBuffer Indices;
@@ -24,6 +26,8 @@ namespace FSO.LotView.Components
private VertexPositionTexture[] VertexData;
private int[] IndexData;
+ private bool IsFinal;
+
public AbstractSkyDome(GraphicsDevice GD, float time)
{
float? customSky = DynamicTuning.Global?.GetTuning("city", 0, 2);
@@ -33,10 +37,27 @@ namespace FSO.LotView.Components
TryLoadSkyColor(GD, DefaultSkyCol);
}
+ LoadFinalIfNeeded(GD);
+
InitArrays();
BuildSkyDome(GD, time);
}
+ public void LoadFinalIfNeeded(GraphicsDevice GD)
+ {
+ bool needsFinal = FinaleUtils.IsFinale();
+
+ if (!IsFinal && needsFinal)
+ {
+ using (var file = File.OpenRead(Path.Combine(FSOEnvironment.ContentDir, FinalSkyCol)))
+ {
+ GradTex = ImageLoader.FromStream(GD, file);
+ };
+
+ IsFinal = true;
+ }
+ }
+
private bool TryLoadSkyColor(GraphicsDevice GD, string path)
{
try
@@ -111,6 +132,8 @@ namespace FSO.LotView.Components
public void BuildSkyDome(GraphicsDevice GD, float time)
{
+ LoadFinalIfNeeded(GD);
+
//generate sky dome geometry
var subdivs = 65;
VertexPositionTexture[] verts = VertexData;
@@ -224,7 +247,7 @@ namespace FSO.LotView.Components
}
gd.BlendState = BlendState.NonPremultiplied;
- var night = Night(time);
+ var night = Night((float)FinaleUtils.BiasSunTime(time));
//draw the sun or moon
var pos = sunVector;
var z = -pos.X;
@@ -241,7 +264,7 @@ namespace FSO.LotView.Components
effect.VertexColorEnabled = false;
effect.TextureEnabled = true;
effect.Texture = (night) ? TextureGenerator.GetMoon(gd) : TextureGenerator.GetSun(gd);
- effect.DiffuseColor = new Vector3(color.X, color.Y, color.Z) * ((night) ? 2f : 0.6f);
+ effect.DiffuseColor = FinaleUtils.BiasSunIntensity(new Vector3(color.X, color.Y, color.Z) * ((night) ? 2f : 0.6f), time);
gd.BlendState = (night) ? BlendState.NonPremultiplied : BlendState.Additive;
foreach (var pass in effect.CurrentTechnique.Passes)
diff --git a/TSOClient/tso.world/LMap/LMapBatch.cs b/TSOClient/tso.world/LMap/LMapBatch.cs
index 4b6fbae1..08881a93 100644
--- a/TSOClient/tso.world/LMap/LMapBatch.cs
+++ b/TSOClient/tso.world/LMap/LMapBatch.cs
@@ -1,4 +1,5 @@
using FSO.Common;
+using FSO.Common.Rendering;
using FSO.Common.Utils;
using FSO.LotView.Components;
using FSO.LotView.Effects;
@@ -375,6 +376,8 @@ namespace FSO.LotView.LMap
DayOffset = 0.25f;
DayDuration = 0.60f;
+ tod = FinaleUtils.BiasSunTime(tod);
+
bool night = false;
double modTime;
var offStart = 1 - (DayOffset + DayDuration);
diff --git a/TSOClient/tso.world/Model/WeatherController.cs b/TSOClient/tso.world/Model/WeatherController.cs
index 9aca056f..bfb2e77d 100644
--- a/TSOClient/tso.world/Model/WeatherController.cs
+++ b/TSOClient/tso.world/Model/WeatherController.cs
@@ -1,4 +1,5 @@
-using FSO.LotView.Components;
+using FSO.Common.Rendering;
+using FSO.LotView.Components;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
@@ -88,7 +89,7 @@ namespace FSO.LotView.Model
ParticleType ptype;
- if (IsManual)
+ if (IsManual && !FinaleUtils.IsFinale())
{
if (WeatherData == LastWeatherData && enabled == LastEnabled) return;
LastWeatherData = WeatherData;
@@ -167,6 +168,11 @@ namespace FSO.LotView.Model
private int GetAutoWeatherIntensity(DateTime time)
{
+ if (FinaleUtils.IsFinale())
+ {
+ return 0;
+ }
+
var distance = time - new DateTime(2019, 1, 26);
var halfDay = (int)distance.TotalHours;
diff --git a/TSOClient/tso.world/Platform/WorldPlatform3D.cs b/TSOClient/tso.world/Platform/WorldPlatform3D.cs
index c7a8036e..7eea1b3a 100644
--- a/TSOClient/tso.world/Platform/WorldPlatform3D.cs
+++ b/TSOClient/tso.world/Platform/WorldPlatform3D.cs
@@ -275,7 +275,7 @@ namespace FSO.LotView.Platform
obj.OnRotationChanged(state);
obj.OnZoomChanged(state);
obj.Container = null;
- obj.Position = tilePosition;
+ obj.UnmoddedPosition = tilePosition;
obj.Draw(gd, state);
var mat = obj.World * vp;