Parameterize surface interactions

This commit is contained in:
2026-05-10 18:07:16 +02:00
parent 9cd9defc0b
commit 3c5fc60ffe
7 changed files with 150 additions and 113 deletions

View File

@@ -37,6 +37,76 @@ public abstract class Balancing
return ratios[Math.Clamp(mode, 0, ratios.Count - 1)].Weights;
}
public SurfaceInteractionEffect SameCellInteraction(ECarrierType? rowCarrier, EBand rowBand, ECarrierType? colCarrier, EBand colBand)
{
if (rowBand == EBand.Safe && colBand == EBand.Safe)
return SurfaceInteractionEffect.Hold;
if (rowCarrier == ECarrierType.Fuel && colCarrier == ECarrierType.Electricity)
return Ignite(rowBand, colBand);
if (rowCarrier == ECarrierType.Fuel && colCarrier is null)
return rowBand == EBand.Critical || colBand == EBand.Critical ? Ignite(rowBand, colBand) : Warm(rowBand, colBand);
if (rowCarrier == ECarrierType.Coolant && colCarrier == ECarrierType.Electricity)
return Short(rowBand, colBand);
if (rowCarrier == ECarrierType.Coolant && colCarrier is null)
return Quench(rowBand, colBand);
return SurfaceInteractionEffect.Hold;
}
public SurfaceInteractionEffect FlowInteraction(ESurfaceQuantity quantity)
{
return new() { Verb = ESurfaceInteractionVerb.Flow, Quantity = quantity, Amount = FlowTransferRatio };
}
private SurfaceInteractionEffect Warm(EBand rowBand, EBand colBand)
{
return new() {
Verb = ESurfaceInteractionVerb.Warm,
Quantity = ESurfaceQuantity.Heat,
Amount = Strongest(rowBand, colBand) == EBand.Critical ? WarmCriticalAmount : WarmCautionAmount
};
}
private SurfaceInteractionEffect Quench(EBand rowBand, EBand colBand)
{
return new() {
Verb = ESurfaceInteractionVerb.Quench,
Quantity = ESurfaceQuantity.Heat,
Amount = Strongest(rowBand, colBand) == EBand.Critical ? QuenchCriticalAmount : QuenchCautionAmount
};
}
private SurfaceInteractionEffect Short(EBand rowBand, EBand colBand)
{
var critical = Strongest(rowBand, colBand) == EBand.Critical;
return new() {
Verb = ESurfaceInteractionVerb.Short,
Quantity = ESurfaceQuantity.Electricity,
Amount = critical ? ShortCriticalHeat : ShortCautionHeat,
SecondaryAmount = critical ? ShortCriticalDischarge : ShortCautionDischarge
};
}
private SurfaceInteractionEffect Ignite(EBand rowBand, EBand colBand)
{
var critical = Strongest(rowBand, colBand) == EBand.Critical;
return new() {
Verb = ESurfaceInteractionVerb.Ignite,
Quantity = ESurfaceQuantity.Fuel,
Amount = critical ? IgniteCriticalHeat : IgniteCautionHeat,
SecondaryAmount = critical ? IgniteCriticalFuelConsumption : IgniteCautionFuelConsumption
};
}
private static EBand Strongest(EBand a, EBand b)
{
return a > b ? a : b;
}
public abstract int DefaultLevelWidth { get; }
public abstract int DefaultLevelHeight { get; }
public abstract int MinimumLevelSize { get; }
@@ -73,19 +143,18 @@ public abstract class Balancing
public abstract float LeakAmountScale { get; }
public abstract float LeakIntensityScale { get; }
public abstract float FlowTransferRatio { get; }
public abstract float StrongFlowTransferRatio { get; }
public abstract float Warm1Amount { get; }
public abstract float Warm2Amount { get; }
public abstract float Quench1Amount { get; }
public abstract float Quench2Amount { get; }
public abstract float Short1Heat { get; }
public abstract float Short1Discharge { get; }
public abstract float Short2Heat { get; }
public abstract float Short2Discharge { get; }
public abstract float Ignite1Heat { get; }
public abstract float Ignite1FuelConsumption { get; }
public abstract float Ignite2Heat { get; }
public abstract float Ignite2FuelConsumption { get; }
public abstract float WarmCautionAmount { get; }
public abstract float WarmCriticalAmount { get; }
public abstract float QuenchCautionAmount { get; }
public abstract float QuenchCriticalAmount { get; }
public abstract float ShortCautionHeat { get; }
public abstract float ShortCautionDischarge { get; }
public abstract float ShortCriticalHeat { get; }
public abstract float ShortCriticalDischarge { get; }
public abstract float IgniteCautionHeat { get; }
public abstract float IgniteCautionFuelConsumption { get; }
public abstract float IgniteCriticalHeat { get; }
public abstract float IgniteCriticalFuelConsumption { get; }
public abstract int RemedyBlockTurns { get; }
public abstract int HeatShieldSteps { get; }
public abstract int InventoryCapacityPerRemedy { get; }

View File

@@ -49,19 +49,18 @@ public class NormalBalancing : Balancing
public override float LeakAmountScale => 0.15f;
public override float LeakIntensityScale => 0.1f;
public override float FlowTransferRatio => 0.05f;
public override float StrongFlowTransferRatio => 0.1f;
public override float Warm1Amount => 0.5f;
public override float Warm2Amount => 1.0f;
public override float Quench1Amount => 0.6f;
public override float Quench2Amount => 1.2f;
public override float Short1Heat => 0.8f;
public override float Short1Discharge => 0.8f;
public override float Short2Heat => 1.6f;
public override float Short2Discharge => 1.5f;
public override float Ignite1Heat => 1.2f;
public override float Ignite1FuelConsumption => 0.4f;
public override float Ignite2Heat => 2.4f;
public override float Ignite2FuelConsumption => 0.8f;
public override float WarmCautionAmount => 0.5f;
public override float WarmCriticalAmount => 1.0f;
public override float QuenchCautionAmount => 0.6f;
public override float QuenchCriticalAmount => 1.2f;
public override float ShortCautionHeat => 0.8f;
public override float ShortCautionDischarge => 0.8f;
public override float ShortCriticalHeat => 1.6f;
public override float ShortCriticalDischarge => 1.5f;
public override float IgniteCautionHeat => 1.2f;
public override float IgniteCautionFuelConsumption => 0.4f;
public override float IgniteCriticalHeat => 2.4f;
public override float IgniteCriticalFuelConsumption => 0.8f;
public override int RemedyBlockTurns => 2;
public override int HeatShieldSteps => 3;
public override int InventoryCapacityPerRemedy => 3;

View File

@@ -1,19 +0,0 @@
namespace ReactorMaintenance.Simulation;
public enum EPairEffect
{
Hold,
FuelFlow,
CoolFlow,
ChargeFlow,
HeatFlow,
HeatFlow2,
Warm1,
Warm2,
Quench1,
Quench2,
Short1,
Short2,
Ignite1,
Ignite2
}

View File

@@ -0,0 +1,11 @@
namespace ReactorMaintenance.Simulation;
public enum ESurfaceInteractionVerb
{
Hold,
Flow,
Warm,
Quench,
Short,
Ignite
}

View File

@@ -0,0 +1,9 @@
namespace ReactorMaintenance.Simulation;
public enum ESurfaceQuantity
{
Fuel,
Coolant,
Electricity,
Heat
}

View File

@@ -296,107 +296,64 @@ public sealed class SimulationEngine
{
var surfaceA = level.GetSurface(a);
var surfaceB = level.GetSurface(b);
FlowBetween(level, a, b, surfaceA.Fuel, surfaceB.Fuel, EPairEffect.FuelFlow, deltas);
FlowBetween(level, a, b, surfaceA.Coolant, surfaceB.Coolant, EPairEffect.CoolFlow, deltas);
FlowBetween(level, a, b, surfaceA.Electricity, surfaceB.Electricity, EPairEffect.ChargeFlow, deltas);
FlowBetween(level, a, b, surfaceA.Heat, surfaceB.Heat, EPairEffect.HeatFlow, deltas);
FlowBetween(level, a, b, surfaceA.Fuel, surfaceB.Fuel, Balancing.Current.FlowInteraction(ESurfaceQuantity.Fuel), deltas);
FlowBetween(level, a, b, surfaceA.Coolant, surfaceB.Coolant, Balancing.Current.FlowInteraction(ESurfaceQuantity.Coolant), deltas);
FlowBetween(level, a, b, surfaceA.Electricity, surfaceB.Electricity, Balancing.Current.FlowInteraction(ESurfaceQuantity.Electricity), deltas);
FlowBetween(level, a, b, surfaceA.Heat, surfaceB.Heat, Balancing.Current.FlowInteraction(ESurfaceQuantity.Heat), deltas);
}
private static void ApplyPair(LevelState level, GridPosition a, GridPosition b, ECarrierType? rowCarrier, EBand rowBand, ECarrierType? colCarrier, EBand colBand, SurfaceDelta[] deltas)
{
ApplyEffect(level, a, b, PairEffect(rowCarrier, rowBand, colCarrier, colBand), deltas);
ApplyEffect(level, a, Balancing.Current.SameCellInteraction(rowCarrier, rowBand, colCarrier, colBand), deltas);
}
private static EPairEffect PairEffect(ECarrierType? rowCarrier, EBand rowBand, ECarrierType? colCarrier, EBand colBand)
private static void ApplyEffect(LevelState level, GridPosition position, SurfaceInteractionEffect effect, SurfaceDelta[] deltas)
{
if (rowBand == EBand.Safe && colBand == EBand.Safe)
return EPairEffect.Hold;
if (rowCarrier == colCarrier)
return rowCarrier switch {
ECarrierType.Fuel => EPairEffect.FuelFlow,
ECarrierType.Coolant => EPairEffect.CoolFlow,
ECarrierType.Electricity => EPairEffect.ChargeFlow,
_ => EPairEffect.HeatFlow
};
if (rowCarrier == ECarrierType.Fuel && colCarrier == ECarrierType.Electricity)
return rowBand == EBand.Critical || colBand == EBand.Critical ? EPairEffect.Ignite2 : EPairEffect.Ignite1;
if (rowCarrier == ECarrierType.Fuel && colCarrier is null)
return rowBand == EBand.Critical || colBand == EBand.Critical ? EPairEffect.Ignite2 : EPairEffect.Warm1;
if (rowCarrier == ECarrierType.Coolant && colCarrier == ECarrierType.Electricity)
return rowBand == EBand.Critical || colBand == EBand.Critical ? EPairEffect.Short2 : EPairEffect.Short1;
if (rowCarrier == ECarrierType.Coolant && colCarrier is null)
return rowBand == EBand.Critical || colBand == EBand.Critical ? EPairEffect.Quench2 : EPairEffect.Quench1;
return EPairEffect.Hold;
}
private static void ApplyEffect(LevelState level, GridPosition a, GridPosition b, EPairEffect effect, SurfaceDelta[] deltas)
{
var index = level.Index(a);
switch (effect)
var index = level.Index(position);
switch (effect.Verb)
{
case EPairEffect.Warm1:
deltas[index].Heat += Balancing.Current.Warm1Amount;
case ESurfaceInteractionVerb.Warm:
deltas[index].Heat += effect.Amount;
break;
case EPairEffect.Warm2:
deltas[index].Heat += Balancing.Current.Warm2Amount;
case ESurfaceInteractionVerb.Quench:
deltas[index].Heat -= effect.Amount;
break;
case EPairEffect.Quench1:
deltas[index].Heat -= Balancing.Current.Quench1Amount;
case ESurfaceInteractionVerb.Short:
deltas[index].Heat += effect.Amount;
deltas[index].Electricity -= effect.SecondaryAmount;
break;
case EPairEffect.Quench2:
deltas[index].Heat -= Balancing.Current.Quench2Amount;
break;
case EPairEffect.Short1:
deltas[index].Heat += Balancing.Current.Short1Heat;
deltas[index].Electricity -= Balancing.Current.Short1Discharge;
break;
case EPairEffect.Short2:
deltas[index].Heat += Balancing.Current.Short2Heat;
deltas[index].Electricity -= Balancing.Current.Short2Discharge;
break;
case EPairEffect.Ignite1:
deltas[index].Heat += Balancing.Current.Ignite1Heat;
deltas[index].Fuel -= Balancing.Current.Ignite1FuelConsumption;
break;
case EPairEffect.Ignite2:
deltas[index].Heat += Balancing.Current.Ignite2Heat;
deltas[index].Fuel -= Balancing.Current.Ignite2FuelConsumption;
case ESurfaceInteractionVerb.Ignite:
deltas[index].Heat += effect.Amount;
deltas[index].Fuel -= effect.SecondaryAmount;
break;
}
}
private static void FlowBetween(LevelState level, GridPosition a, GridPosition b, float valueA, float valueB, EPairEffect effect, SurfaceDelta[] deltas)
private static void FlowBetween(LevelState level, GridPosition a, GridPosition b, float valueA, float valueB, SurfaceInteractionEffect effect, SurfaceDelta[] deltas)
{
var difference = valueA - valueB;
if (Math.Abs(difference) < 0.01f)
return;
var amount = difference * (effect == EPairEffect.HeatFlow2 ? Balancing.Current.StrongFlowTransferRatio : Balancing.Current.FlowTransferRatio);
var amount = difference * effect.Amount;
var indexA = level.Index(a);
var indexB = level.Index(b);
switch (effect)
switch (effect.Quantity)
{
case EPairEffect.FuelFlow:
case ESurfaceQuantity.Fuel:
deltas[indexA].Fuel -= amount;
deltas[indexB].Fuel += amount;
break;
case EPairEffect.CoolFlow:
case ESurfaceQuantity.Coolant:
deltas[indexA].Coolant -= amount;
deltas[indexB].Coolant += amount;
break;
case EPairEffect.ChargeFlow:
case ESurfaceQuantity.Electricity:
deltas[indexA].Electricity -= amount;
deltas[indexB].Electricity += amount;
break;
case EPairEffect.HeatFlow:
case EPairEffect.HeatFlow2:
case ESurfaceQuantity.Heat:
deltas[indexA].Heat -= amount;
deltas[indexB].Heat += amount;
break;

View File

@@ -0,0 +1,11 @@
namespace ReactorMaintenance.Simulation;
public sealed record SurfaceInteractionEffect
{
public static SurfaceInteractionEffect Hold { get; } = new();
public ESurfaceInteractionVerb Verb { get; init; }
public ESurfaceQuantity Quantity { get; init; }
public float Amount { get; init; }
public float SecondaryAmount { get; init; }
}