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

187 lines
6.3 KiB
C#

using Sand.Core;
namespace Sand.ChunkPrototype;
public sealed partial class PrototypeSparseSandAdapter
{
private void TickCellAging(int x, int y, PrototypeParticle particle)
{
if (!TryGetCellPage(x, y, out _, out var page, out var localX, out var localY))
{
return;
}
page.SetCellAge(localX, localY, page.GetCellAge(localX, localY) + 1f);
if (page.GetIntegrity(localX, localY) < particle.Durability)
{
page.SetIntegrity(localX, localY, MathF.Min(particle.Durability, page.GetIntegrity(localX, localY) + MathF.Max(0.02f, particle.Hardness * 0.03f)));
}
}
private bool TickLifetime(int x, int y, ref PrototypeParticle particle)
{
if (!TryGetCellPage(x, y, out _, out var page, out var localX, out var localY))
{
return false;
}
var lifetime = page.GetLifetime(localX, localY);
if (lifetime > 0f)
{
lifetime -= 1f;
page.SetLifetime(localX, localY, lifetime);
}
if (lifetime <= 0f && particle.DefaultLifetime > 0f)
{
if (particle.MotionType == PrototypeParticleType.Steam && particle.SolidifyTypeId != 0 && TryResolveProfile(particle.SolidifyTypeId, out var condensed))
{
var currentTemperature = GetTemperatureAt(x, y);
ReplaceParticle(x, y, condensed);
if (TryGetCellPage(x, y, out _, out var targetPage, out var targetLocalX, out var targetLocalY))
{
targetPage.SetTemperature(targetLocalX, targetLocalY, MathF.Max(condensed.InitialTemperature, MathF.Min(currentTemperature, 95f)));
}
particle = condensed;
return false;
}
RemoveParticle(x, y);
return true;
}
return false;
}
private void AutoIgnite(int x, int y, PrototypeParticle particle)
{
if (!TryGetCellPage(x, y, out _, out var page, out var localX, out var localY))
{
return;
}
if (page.GetBurning(localX, localY) == 0 &&
particle.BurnTemperature > 0f &&
GetTemperatureAt(x, y) >= particle.BurnTemperature &&
particle.Flamability > 0f)
{
page.SetBurning(localX, localY, 1);
page.SetBurnTime(localX, localY, MathF.Max(particle.BurnDuration, 1f));
}
}
private void ApplyRuntimeEmissionAndProduction(int x, int y, PrototypeParticle particle, ref int seed)
{
var isEffectEmitter =
particle.BehaviorKind is ParticleBehaviorKind.Fire or ParticleBehaviorKind.BurningWood or ParticleBehaviorKind.Ember or ParticleBehaviorKind.Plasma;
var emission = particle.HeatEmission;
if (particle.BehaviorKind == ParticleBehaviorKind.Fire && emission <= 0f)
{
emission = 24f;
}
else if (particle.BehaviorKind == ParticleBehaviorKind.Plasma && emission <= 0f)
{
emission = 80f;
}
else if (particle.BehaviorKind == ParticleBehaviorKind.Ember && emission <= 0f)
{
emission = 12f;
}
else if (particle.IsMolten && emission <= 0f)
{
emission = particle.TypeId != 0 ? 28f : 0f;
}
if (emission > 0f)
{
ApplyHeatEmission(x, y, emission);
}
if ((isEffectEmitter || IsBurningAt(x, y)) && particle.ProduceTypeId != 0 && NextChance(ref seed) <= 0.08f)
{
TrySpawnAtOffset(x, y, 0, -1, particle.ProduceTypeId);
}
if (particle.SmokeSpawnChance > 0f && isEffectEmitter && TryFindProfileById("smoke", out var smoke) && NextChance(ref seed) <= particle.SmokeSpawnChance)
{
TrySpawnAtOffset(x, y, 0, -1, smoke.TypeId);
}
if (particle.EmberSpawnChance > 0f && isEffectEmitter && TryFindProfileById("ember", out var ember) && NextChance(ref seed) <= particle.EmberSpawnChance)
{
TrySpawnAtOffset(x, y, 0, -1, ember.TypeId);
}
}
private bool TickBurning(int x, int y, ref PrototypeParticle particle)
{
if (!TryGetCellPage(x, y, out _, out var page, out var localX, out var localY) || page.GetBurning(localX, localY) == 0)
{
return false;
}
page.SetTemperature(localX, localY, page.GetTemperature(localX, localY) + 1.5f + (particle.HeatEmission * 0.02f));
page.SetBurnTime(localX, localY, page.GetBurnTime(localX, localY) - MathF.Max(0.05f, particle.BurnRate));
if (page.GetBurnTime(localX, localY) > 0f)
{
return false;
}
RemoveParticle(x, y);
return true;
}
private bool TickSpecialBehavior(int x, int y, PrototypeParticle particle, ref int seed)
{
var temperature = GetTemperatureAt(x, y);
switch (particle.BehaviorKind)
{
case ParticleBehaviorKind.Fire:
if (temperature < 120f && NextChance(ref seed) <= 0.1f)
{
RemoveParticle(x, y);
return true;
}
break;
case ParticleBehaviorKind.Ember:
if (temperature < 60f && NextChance(ref seed) <= 0.1f)
{
RemoveParticle(x, y);
return true;
}
break;
case ParticleBehaviorKind.BurningWood:
if (particle.EmberSpawnChance > 0f && TryFindProfileById("ember", out var ember) && NextChance(ref seed) <= particle.EmberSpawnChance * 0.5f)
{
TrySpawnAtOffset(x, y, 0, -1, ember.TypeId);
}
break;
}
return false;
}
private bool IsBurningAt(int x, int y)
{
if (!TryGetCellPage(x, y, out _, out var page, out var localX, out var localY))
{
return false;
}
return page.GetBurning(localX, localY) != 0;
}
private bool TrySpawnAtOffset(int x, int y, int offsetX, int offsetY, ushort typeId)
{
var tx = x + offsetX;
var ty = y + offsetY;
if (!InBounds(tx, ty) || HasParticle(tx, ty) || !TryResolveProfile(typeId, out var particle))
{
return false;
}
return AddParticle(tx, ty, particle);
}
}