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

175 lines
5.9 KiB
C#

using Sand.Core;
namespace Sand.ChunkPrototype;
public sealed partial class PrototypeSparseSandAdapter
{
private bool ApplyLocalReaction(int x, int y, PrototypeParticle particle, ref int seed)
{
Span<(int X, int Y)> neighbors = [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)];
for (var i = 0; i < neighbors.Length; i++)
{
var (nx, ny) = neighbors[i];
if (!TryGetParticle(nx, ny, out var neighbor))
{
continue;
}
if (particle.HasFlag(PrototypeParticleFlags.WaterLike) && neighbor.HydrateTargetTypeId != 0 && TryResolveProfile(neighbor.HydrateTargetTypeId, out var hydrated))
{
ReplaceParticle(nx, ny, hydrated);
RemoveParticle(x, y);
return true;
}
if (particle.HasFlag(PrototypeParticleFlags.FireLike) && neighbor.HasFlag(PrototypeParticleFlags.WaterLike))
{
RemoveParticle(x, y);
if (neighbor.EvaporateTypeId != 0 && TryResolveProfile(neighbor.EvaporateTypeId, out var steam))
{
ReplaceParticle(nx, ny, steam);
}
return true;
}
if (particle.HasFlag(PrototypeParticleFlags.HotSource) && neighbor.HasFlag(PrototypeParticleFlags.WaterLike))
{
if (particle.SolidifyTypeId != 0 && TryResolveProfile(particle.SolidifyTypeId, out var solidifiedSelf))
{
ReplaceParticle(x, y, solidifiedSelf);
}
if (neighbor.EvaporateTypeId != 0 && TryResolveProfile(neighbor.EvaporateTypeId, out var vaporizedNeighbor))
{
ReplaceParticle(nx, ny, vaporizedNeighbor);
}
else
{
RemoveParticle(nx, ny);
}
return true;
}
if (particle.HasFlag(PrototypeParticleFlags.Acidic) &&
!neighbor.IsStatic &&
!neighbor.HasFlag(PrototypeParticleFlags.Acidic) &&
NextChance(ref seed) <= 0.08f)
{
RemoveParticle(nx, ny);
if (NextChance(ref seed) <= 0.18f)
{
RemoveParticle(x, y);
return true;
}
}
}
return false;
}
private void ApplyPhaseTransition(int x, int y, ref PrototypeParticle particle)
{
var localTemperature = GetTemperatureAt(x, y);
var localPressure = GetPressureLoad(x, y);
var fieldForce = GetFieldForceMagnitude(x, y);
if (fieldForce > 0f)
{
localPressure += fieldForce * 0.2f;
}
var cellAge = GetCellAgeAt(x, y);
if (particle.PhaseTransitionHysteresis > 0f && cellAge < particle.PhaseTransitionHysteresis)
{
return;
}
if (particle.EvaporateTypeId != 0 &&
localTemperature >= particle.EvaporateTemperature &&
TryResolveProfile(particle.EvaporateTypeId, out var evaporated))
{
ReplaceParticle(x, y, evaporated);
particle = evaporated;
return;
}
if (particle.MeltTypeId != 0 &&
localTemperature >= particle.MeltTemperature &&
TryResolveProfile(particle.MeltTypeId, out var melted))
{
ReplaceParticle(x, y, melted);
particle = melted;
return;
}
if (particle.FreezeTypeId != 0 &&
localTemperature <= particle.FreezeTemperature &&
TryResolveProfile(particle.FreezeTypeId, out var frozen))
{
ReplaceParticle(x, y, frozen);
particle = frozen;
return;
}
if (particle.SolidifyTypeId != 0 &&
(localTemperature <= particle.SolidifyTemperature ||
(particle.MotionType == PrototypeParticleType.Steam && localPressure >= MathF.Max(0.9f, particle.PressureThreshold * 0.35f))) &&
TryResolveProfile(particle.SolidifyTypeId, out var condensed))
{
ReplaceParticle(x, y, condensed);
if (TryGetCellPage(x, y, out _, out var page, out var localX, out var localY))
{
page.SetTemperature(localX, localY, MathF.Max(condensed.InitialTemperature, MathF.Min(localTemperature, 95f)));
}
particle = condensed;
}
}
private float GetCellAgeAt(int x, int y)
{
if (!TryGetCellPage(x, y, out _, out var page, out var localX, out var localY))
{
return 0f;
}
return page.GetCellAge(localX, localY);
}
private bool HasPotentialReactiveNeighbor(int x, int y, PrototypeParticle particle)
{
Span<(int X, int Y)> neighbors = [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)];
for (var i = 0; i < neighbors.Length; i++)
{
var (nx, ny) = neighbors[i];
if (!TryGetParticle(nx, ny, out var neighbor))
{
continue;
}
if (particle.HasFlag(PrototypeParticleFlags.WaterLike) && neighbor.HydrateTargetTypeId != 0)
{
return true;
}
if (particle.HydrateTargetTypeId != 0 && neighbor.HasFlag(PrototypeParticleFlags.WaterLike))
{
return true;
}
if ((particle.HasFlag(PrototypeParticleFlags.FireLike) || particle.HasFlag(PrototypeParticleFlags.HotSource)) && neighbor.HasFlag(PrototypeParticleFlags.WaterLike))
{
return true;
}
if (particle.HasFlag(PrototypeParticleFlags.Acidic) && !neighbor.IsStatic && !neighbor.HasFlag(PrototypeParticleFlags.Acidic))
{
return true;
}
}
return false;
}
}