From 562e365be1af6e2a35fb13cfbce74d12ed0b3334 Mon Sep 17 00:00:00 2001 From: Leonid Pershin Date: Sun, 14 Jun 2026 16:53:27 +0300 Subject: [PATCH] Animal thermoregulation (insulation) + wound infection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- Mods/Core/Defs/Hediffs/Hediffs.json | 23 ++++++++++ Mods/Core/Languages/en/ui.json | 3 ++ Mods/Core/Languages/ru/ui.json | 3 ++ src/LittleSim/Scenes/WorldScene.cs | 4 ++ src/LittleSim/Sim/AnimalSystems.cs | 65 ++++++++++++++++++++++++++++- 5 files changed, 97 insertions(+), 1 deletion(-) diff --git a/Mods/Core/Defs/Hediffs/Hediffs.json b/Mods/Core/Defs/Hediffs/Hediffs.json index f684124..954059a 100644 --- a/Mods/Core/Defs/Hediffs/Hediffs.json +++ b/Mods/Core/Defs/Hediffs/Hediffs.json @@ -32,6 +32,29 @@ "defName": "Poisoned", "label": "hediff.poisoned", "initialSeverity": 0.0, "immunityPerDay": 0.65, "lethalSeverity": 1.0, "pain": 0.2, "capMods": { "Moving": 0.85, "Consciousness": 0.9, "Digestion": 0.7 } + }, + + // Терморегуляция (как Poisoned-паттерн): сами не прогрессируют — тяжесть копится, пока зверю + // холодно/жарко (см. AnimalHealthSystem, зависит от GeneInsulation + размера тела), а в комфорте + // immunityPerDay их рассасывает. Тяжесть 1 = смерть от переохлаждения/перегрева. + { + "defName": "Hypothermia", "label": "hediff.hypothermia", + "initialSeverity": 0.0, "immunityPerDay": 0.5, "lethalSeverity": 1.0, "pain": 0.15, + "capMods": { "Moving": 0.7, "Consciousness": 0.8 } + }, + { + "defName": "Heatstroke", "label": "hediff.heatstroke", + "initialSeverity": 0.0, "immunityPerDay": 0.5, "lethalSeverity": 1.0, "pain": 0.15, + "capMods": { "Moving": 0.75, "Consciousness": 0.8 } + }, + + // Заражение раны (предатор/шипы → кровотечение → инфекция): прогрессирует, иммунитет (× фильтрация + // крови) душит. Слабая фильтрация/много ран → выше риск и хуже исход. + { + "defName": "Infection", "label": "hediff.infection", + "initialSeverity": 0.08, "severityPerDay": 0.2, "immunityPerDay": 0.28, + "lethalSeverity": 1.0, "pain": 0.25, + "capMods": { "Moving": 0.8, "Consciousness": 0.85, "BloodFiltration": 0.8 } } ] } diff --git a/Mods/Core/Languages/en/ui.json b/Mods/Core/Languages/en/ui.json index a63e94b..2f0a270 100644 --- a/Mods/Core/Languages/en/ui.json +++ b/Mods/Core/Languages/en/ui.json @@ -73,6 +73,9 @@ "hediff.fever": "fever", "hediff.bleeding": "bleeding", "hediff.poisoned": "poisoned", + "hediff.hypothermia": "hypothermia", + "hediff.heatstroke": "heatstroke", + "hediff.infection": "infection", "inspect.hint": "LMB — select · RMB/Esc — clear", "hud.paused": "PAUSED", "menu.title": "LittleSim", diff --git a/Mods/Core/Languages/ru/ui.json b/Mods/Core/Languages/ru/ui.json index 8cb7bef..0d93144 100644 --- a/Mods/Core/Languages/ru/ui.json +++ b/Mods/Core/Languages/ru/ui.json @@ -73,6 +73,9 @@ "hediff.fever": "лихорадка", "hediff.bleeding": "кровотечение", "hediff.poisoned": "отравление", + "hediff.hypothermia": "переохлаждение", + "hediff.heatstroke": "тепловой удар", + "hediff.infection": "заражение", "inspect.hint": "ЛКМ — выбрать · ПКМ/Esc — снять", "hud.paused": "ПАУЗА", "menu.title": "LittleSim", diff --git a/src/LittleSim/Scenes/WorldScene.cs b/src/LittleSim/Scenes/WorldScene.cs index 8ecf0a0..5f5c7bd 100644 --- a/src/LittleSim/Scenes/WorldScene.cs +++ b/src/LittleSim/Scenes/WorldScene.cs @@ -242,7 +242,11 @@ public sealed class WorldScene : Scene CellSize, Context.Clock, SecondsPerDay, + climate, content.Defs.All().Where(h => h.AmbientPerDay > 0f).ToArray(), + content.Defs.TryGet("Hypothermia", out var hypo) ? hypo : null, + content.Defs.TryGet("Heatstroke", out var heat) ? heat : null, + content.Defs.TryGet("Infection", out var infe) ? infe : null, _config.Seed + 0x3EAD ) ); diff --git a/src/LittleSim/Sim/AnimalSystems.cs b/src/LittleSim/Sim/AnimalSystems.cs index 90d2974..2289e98 100644 --- a/src/LittleSim/Sim/AnimalSystems.cs +++ b/src/LittleSim/Sim/AnimalSystems.cs @@ -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 _query; private readonly List _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(); } @@ -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)