sandpypi/Sand.ChunkPrototype/PrototypeSparseSandAdapter.Runtime.Pressure.cs

126 lines
4.1 KiB
C#

using Sand.Core;
namespace Sand.ChunkPrototype;
public sealed partial class PrototypeSparseSandAdapter
{
private bool ApplyPressureResponse(int x, int y, PrototypeParticle particle)
{
if (!TryGetCellPage(x, y, out _, out var page, out var localX, out var localY))
{
return false;
}
var localPressure = GetLocalPressure(x, y);
var threshold = particle.PressureThreshold;
if (threshold <= 0f)
{
threshold = particle.IsStatic
? 2.5f + particle.PressureResistance + particle.PressureTolerance
: 1.4f + (particle.PressureResistance * 0.35f) + particle.PressureTolerance;
}
if (localPressure < threshold)
{
var reducedDuration = MathF.Max(0f, page.GetPressureDuration(localX, localY) - 1f);
page.SetPressureDuration(localX, localY, reducedDuration);
var maxIntegrity = particle.Durability;
if (page.GetIntegrity(localX, localY) < maxIntegrity)
{
page.SetIntegrity(localX, localY, MathF.Min(maxIntegrity, page.GetIntegrity(localX, localY) + MathF.Max(0.2f, particle.Hardness * 0.1f)));
}
return false;
}
var pressureDuration = page.GetPressureDuration(localX, localY) + 1f;
page.SetPressureDuration(localX, localY, pressureDuration);
var overload = MathF.Max(0f, localPressure - threshold);
var damageScale = 1f / MathF.Max(0.35f, 0.4f + particle.Hardness + (particle.PressureResistance * 0.1f));
page.SetIntegrity(localX, localY, page.GetIntegrity(localX, localY) - MathF.Max(0.15f, 0.45f + overload) * damageScale);
var requiredDuration = particle.PressureThresholdDuration > 0 ? particle.PressureThresholdDuration : (short)2;
if (pressureDuration < requiredDuration)
{
return false;
}
if (particle.BrokenTypeId != 0 && TryResolveProfile(particle.BrokenTypeId, out var broken))
{
ReplaceParticle(x, y, broken);
return true;
}
if (particle.Flamability > 0f && GetTemperatureAt(x, y) >= MathF.Max(60f, particle.BurnTemperature * 0.5f))
{
page.SetBurning(localX, localY, 1);
page.SetBurnTime(localX, localY, MathF.Max(1f, particle.BurnDuration));
return false;
}
if (page.GetIntegrity(localX, localY) <= 0f)
{
if (!particle.IsStatic && particle.Kind == ParticleKind.Solid)
{
RemoveParticle(x, y);
return true;
}
return false;
}
return false;
}
private float GetLocalPressure(int x, int y) => MathF.Abs(SamplePressure(x, y));
private float GetPressureLoad(int x, int y)
{
var local = GetLocalPressure(x, y);
var neighborLoad =
(MathF.Abs(SamplePressure(x - 1, y)) +
MathF.Abs(SamplePressure(x + 1, y)) +
MathF.Abs(SamplePressure(x, y - 1)) +
MathF.Abs(SamplePressure(x, y + 1))) * 0.5f;
return Math.Max(local, neighborLoad);
}
private float GetFieldForceMagnitude(int x, int y)
{
var wind = GetWindAtCell(x, y);
var force = GetForceAtCell(x, y);
var totalX = wind.X + force.X;
var totalY = wind.Y + force.Y;
return MathF.Sqrt((totalX * totalX) + (totalY * totalY));
}
private float SamplePressure(int x, int y)
{
if (!TryGetFieldPage(x, y, out _, out var page, out var localX, out var localY))
{
return 0f;
}
return page.GetCell(localX, localY).Pressure;
}
private float GetPressureDurationAt(int x, int y)
{
if (!TryGetCellPage(x, y, out _, out var page, out var localX, out var localY))
{
return 0f;
}
return page.GetPressureDuration(localX, localY);
}
private float GetIntegrityAt(int x, int y)
{
if (!TryGetCellPage(x, y, out _, out var page, out var localX, out var localY))
{
return 0f;
}
return page.GetIntegrity(localX, localY);
}
}