Animal thermoregulation (insulation) + wound infection

Two health threads finished, both via the existing hediff engine in
AnimalHealthSystem (now also takes Climate + the new hediff defs):

- Thermoregulation revives the dead GeneInsulation. A comfort band is derived
  per animal: fur (insulation) widens cold tolerance but worsens heat tolerance,
  larger body resists cold. Outside it, Hypothermia/Heatstroke severity builds
  (Poisoned-pattern: Intensify zeroes immunity so it can't recover while still
  exposed), capacities drop, severity 1 = death; back in comfort it heals.
  Seasonal/climate mortality and a real cold↔heat adaptation tradeoff.
- Wound infection marries the injury and disease systems: while bleeding, a
  chance (∝ wound severity) to contract Infection, a progressing disease fought
  by immunity × blood filtration — weak kidneys/liver or many wounds = worse.

New hediffs Hypothermia/Heatstroke/Infection (+ru/en). Build + --check-content
clean. Not GUI-verified.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Leonid Pershin
2026-06-14 16:53:27 +03:00
co-authored by Claude Opus 4.8
parent 5b0cf1dd4a
commit 562e365be1
5 changed files with 97 additions and 1 deletions
+4
View File
@@ -242,7 +242,11 @@ public sealed class WorldScene : Scene
CellSize,
Context.Clock,
SecondsPerDay,
climate,
content.Defs.All<HediffDef>().Where(h => h.AmbientPerDay > 0f).ToArray(),
content.Defs.TryGet<HediffDef>("Hypothermia", out var hypo) ? hypo : null,
content.Defs.TryGet<HediffDef>("Heatstroke", out var heat) ? heat : null,
content.Defs.TryGet<HediffDef>("Infection", out var infe) ? infe : null,
_config.Seed + 0x3EAD
)
);
+64 -1
View File
@@ -1833,7 +1833,11 @@ public sealed class AnimalHealthSystem : BaseSystem
private readonly int _cellSize;
private readonly GameClock _clock;
private readonly float _secondsPerDay;
private readonly Climate _climate;
private readonly HediffDef[] _ambient;
private readonly HediffDef? _hypothermia;
private readonly HediffDef? _heatstroke;
private readonly HediffDef? _infection;
private readonly Random _rng;
private readonly ArchetypeQuery<Health, AnimalOrganism, AnimalGrowth> _query;
private readonly List<Entity> _deaths = [];
@@ -1844,13 +1848,28 @@ public sealed class AnimalHealthSystem : BaseSystem
private const float SenescenceStart = 0.6f;
private const float SenescenceMax = 0.45f;
// Термокомфорт (°C) при теплоизоляции 0.5 и размере тела 1; границы сдвигаются мехом и размером тела.
private const float ColdComfort = 2f; // ниже — мёрзнет
private const float HeatComfort = 30f; // выше — перегревается
private const float ColdInsulationBonus = 30f; // мех (insulation 0..1) расширяет холодоустойчивость
private const float HeatInsulationPenalty = 14f; // тот же мех ухудшает жароустойчивость
private const float ColdBodyBonus = 8f; // крупное тело (тепловая инерция) держит холод лучше
private const float ThermalRatePerDegree = 0.06f; // прирост тяжести за °C за пределом комфорта в день
// Заражение раны: шанс в день при кровотечении тяжести 1 подхватить инфекцию.
private const float InfectionChancePerDay = 0.25f;
public AnimalHealthSystem(
EntityStore store,
AnimalSet animals,
int cellSize,
GameClock clock,
float secondsPerDay,
Climate climate,
HediffDef[] ambient,
HediffDef? hypothermia,
HediffDef? heatstroke,
HediffDef? infection,
int seed
)
{
@@ -1859,7 +1878,11 @@ public sealed class AnimalHealthSystem : BaseSystem
_cellSize = cellSize;
_clock = clock;
_secondsPerDay = secondsPerDay;
_climate = climate;
_ambient = ambient;
_hypothermia = hypothermia;
_heatstroke = heatstroke;
_infection = infection;
_rng = new Random(seed);
_query = store.Query<Health, AnimalOrganism, AnimalGrowth>();
}
@@ -1912,8 +1935,48 @@ public sealed class AnimalHealthSystem : BaseSystem
}
}
// Терморегуляция: вне комфорта (зависит от GeneInsulation + размера тела) копится тяжесть
// гипотермии/теплового удара; в комфорте immunityPerDay их рассасывает. Мех расширяет
// холодоустойчивость, но ухудшает жароустойчивость; крупное тело держит холод.
var insul = Math.Clamp(o[i].Traits.Insulation, 0f, 1f);
var coldLimit =
ColdComfort
- ColdInsulationBonus * insul
- ColdBodyBonus * MathF.Max(0f, o[i].Traits.BodySize - 1f);
var heatLimit = HeatComfort - HeatInsulationPenalty * insul;
var temp = _climate.Temperature;
if (temp < coldLimit && _hypothermia is not null)
{
state.Intensify(_hypothermia, (coldLimit - temp) * ThermalRatePerDegree * days);
}
else if (temp > heatLimit && _heatstroke is not null)
{
state.Intensify(_heatstroke, (temp - heatLimit) * ThermalRatePerDegree * days);
}
// Заражение раны: пока есть кровотечение, шанс (∝ его тяжести) подхватить инфекцию.
if (_infection is not null && !state.Has(_infection.DefName))
{
var bleedSeverity = 0f;
foreach (var hd in state.Hediffs)
{
if (hd.Def.BloodLossPerDay > 0f && hd.Severity > bleedSeverity)
{
bleedSeverity = hd.Severity;
}
}
if (
bleedSeverity > 0f
&& _rng.NextSingle() < InfectionChancePerDay * bleedSeverity * days
)
{
state.Add(_infection);
}
}
// Фильтрация крови (почки/печень) ускоряет вывод токсинов и набор иммунитета: повреждённый
// орган → медленнее выздоровление от яда/болезни (для тела без неё Capacity вернёт 1).
// орган → медленнее выздоровление от яда/болезни/инфекции (для тела без неё Capacity вернёт 1).
var lethal = state.AdvanceHediffs(
days,
state.Capacity(AnimalCapacities.BloodFiltration)