Files
LittleSim/src/LittleSim/Sim/CapacityCalc.cs
T
Leonid Pershin ba8e590941 Refactor game settings and remove unused files
- Removed the GameSettingsStore class and its associated methods for loading and saving game settings, streamlining the GameSettings class.
- Deleted obsolete files related to world saving, game definitions, network smoothing, and content helpers, which were no longer in use, reducing code complexity and improving maintainability.
- Updated the WorldScene class to reflect changes in the GameSettings structure, ensuring compatibility with the new settings management approach.

This update enhances the overall codebase by eliminating redundancy and focusing on essential components.
2026-06-17 08:13:52 +03:00

105 lines
6.0 KiB
C#

using System.Collections.Generic;
namespace LittleSim.Sim;
/// <summary>
/// Обобщённый расчёт способностей (capacities) из частей тела и крови (фаза A5). Сырой вклад способности
/// = Σ(доля части × доля её HP). Затем известные способности домножаются по зависимостям (кровь →
/// сердце/лёгкие → сознание → движение/зрение), как в модели RimWorld; неизвестные (модовые) проходят
/// сырыми. У здоровой особи (полное HP, кровь 1, боль 0) все способности = 1.
/// </summary>
public static class CapacityCalc
{
// Переиспользуемые scratch-буферы: пересчёт способностей идёт на каждое животное на тик здоровья и на
// каждую травму — раньше это аллоцировало 4 словаря + HashSet за вызов (главный аллокатор сим-части).
// [ThreadStatic] — безопасно и при возможном распараллеливании (свой буфер на поток).
[ThreadStatic]
private static Dictionary<string, float>? _raw;
[ThreadStatic]
private static HashSet<string>? _declared;
[ThreadStatic]
private static Dictionary<string, float>? _computed;
/// <summary>Считает способности из инстансов частей, уровня крови (0..1) и боли (0..1) в переданный
/// <paramref name="result"/> (очищается и заполняется заново — без аллокаций); <paramref name="capacityScale"/>
/// — общий множитель (старение), применяется к итогу.</summary>
public static void Compute(
PartInstance[] parts,
float blood,
float pain,
float capacityScale,
Dictionary<string, float> result
)
{
// Сырой вклад каждой способности (Σ доля·HP) и НАБОР объявленных телом способностей: вид имеет
// только те, к которым его части вообще причастны (у оленя нет манипуляции). Объявленность —
// статична (по дефам частей), поэтому уничтоженный орган всё равно покажет способность на 0%.
var raw = _raw ??= new Dictionary<string, float>(System.StringComparer.Ordinal);
var declared = _declared ??= new HashSet<string>(System.StringComparer.Ordinal);
raw.Clear();
declared.Clear();
foreach (var part in parts)
{
if (part.Def is null)
{
continue;
}
var fraction = part.Fraction;
foreach (var (capacity, contribution) in part.Def.Capacities)
{
declared.Add(capacity);
raw[capacity] = raw.GetValueOrDefault(capacity) + contribution * fraction;
}
}
float Raw(string id) => raw.GetValueOrDefault(id);
static float Clamp01(float v) =>
v < 0f ? 0f
: v > 1f ? 1f
: v;
// Базовые (независимые) способности: кровоснабжение/дыхание/фильтрация × уровень крови.
var bloodLevel = Clamp01(blood);
var bloodPumping = Raw(AnimalCapacities.BloodPumping) * bloodLevel;
var breathing = Raw(AnimalCapacities.Breathing) * bloodLevel;
var bloodFiltration = Raw(AnimalCapacities.BloodFiltration) * bloodLevel;
// Сознание зависит от кровоснабжения, дыхания и боли (модель RimWorld).
var consciousness =
Raw(AnimalCapacities.Consciousness)
* Clamp01(bloodPumping)
* Clamp01(breathing)
* (1f - Clamp01(pain));
var cons = Clamp01(consciousness);
var pump = Clamp01(bloodPumping);
// Производные способности зависят от сознания (и кровоснабжения для движения/пищеварения).
var computed = _computed ??= new Dictionary<string, float>(System.StringComparer.Ordinal);
computed.Clear();
computed[AnimalCapacities.BloodPumping] = bloodPumping;
computed[AnimalCapacities.Breathing] = breathing;
computed[AnimalCapacities.BloodFiltration] = bloodFiltration;
computed[AnimalCapacities.Consciousness] = consciousness;
computed[AnimalCapacities.Moving] = Raw(AnimalCapacities.Moving) * cons * pump;
computed[AnimalCapacities.Sight] = Raw(AnimalCapacities.Sight) * cons;
computed[AnimalCapacities.Hearing] = Raw(AnimalCapacities.Hearing) * cons;
computed[AnimalCapacities.Smell] = Raw(AnimalCapacities.Smell) * cons;
computed[AnimalCapacities.Touch] = Raw(AnimalCapacities.Touch) * cons;
computed[AnimalCapacities.Talking] = Raw(AnimalCapacities.Talking) * cons;
computed[AnimalCapacities.Eating] = Raw(AnimalCapacities.Eating) * cons;
computed[AnimalCapacities.Digestion] = Raw(AnimalCapacities.Digestion) * pump;
// В результат — только объявленные телом способности: известные по формуле зависимостей, прочие
// (модовые) — сырым вкладом. Так у вида видны ровно его способности, а не весь каталог.
var scale = Clamp01(capacityScale);
result.Clear();
foreach (var capacity in declared)
{
var value = computed.TryGetValue(capacity, out var v) ? v : Raw(capacity);
result[capacity] = scale < 1f ? value * scale : value;
}
}
}