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; } }