Животные A6: болезни и иммунитет
HediffDef расширен (initialSeverity/severityPerDay/immunityPerDay/lethalSeverity/pain/ambientPerDay/capMods); хедифы стали инстансами (Hediff: тяжесть+иммунитет). AnimalHealthSystem (медленный тик ~час): фоновое заражение, гонка тяжесть<->иммунитет (выздоровление при иммунитете 1 / смерть при летальной тяжести), пересчёт способностей с болью и capMods; смерть по здоровью оставляет труп. Первый реальный источник урона: Moving подключён к скорости (больные медленнее). Болезнь Fever; команда infect для теста. Сборка чистая, --check-content (10 типов дефов). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
9db12273c9
commit
9f8ff93591
@@ -433,7 +433,13 @@ public sealed class AnimalActionSystem : BaseSystem
|
||||
private readonly GameClock _clock;
|
||||
private readonly float _secondsPerDay;
|
||||
private readonly RectF _bounds;
|
||||
private readonly ArchetypeQuery<AnimalBrain, AnimalNeeds, AnimalOrganism, Transform2D> _query;
|
||||
private readonly ArchetypeQuery<
|
||||
AnimalBrain,
|
||||
AnimalNeeds,
|
||||
AnimalOrganism,
|
||||
Transform2D,
|
||||
Health
|
||||
> _query;
|
||||
private readonly List<Entity> _eaten = [];
|
||||
private readonly List<(Entity Self, Entity Partner)> _matings = [];
|
||||
|
||||
@@ -454,7 +460,7 @@ public sealed class AnimalActionSystem : BaseSystem
|
||||
_clock = clock;
|
||||
_secondsPerDay = secondsPerDay;
|
||||
_bounds = bounds;
|
||||
_query = store.Query<AnimalBrain, AnimalNeeds, AnimalOrganism, Transform2D>();
|
||||
_query = store.Query<AnimalBrain, AnimalNeeds, AnimalOrganism, Transform2D, Health>();
|
||||
}
|
||||
|
||||
protected override void OnUpdateGroup()
|
||||
@@ -469,19 +475,22 @@ public sealed class AnimalActionSystem : BaseSystem
|
||||
_eaten.Clear();
|
||||
_matings.Clear();
|
||||
|
||||
foreach (var (brains, needsChunk, organisms, transforms, entities) in _query.Chunks)
|
||||
foreach (var (brains, needsChunk, organisms, transforms, healths, entities) in _query.Chunks)
|
||||
{
|
||||
var b = brains.Span;
|
||||
var n = needsChunk.Span;
|
||||
var o = organisms.Span;
|
||||
var t = transforms.Span;
|
||||
var hh = healths.Span;
|
||||
for (var i = 0; i < b.Length; i++)
|
||||
{
|
||||
ref var brain = ref b[i];
|
||||
var values = n[i].Values;
|
||||
ref var pos = ref t[i].Position;
|
||||
var def = _animalSet[o[i].Species].Def;
|
||||
var speed = def.BaseSpeed * MathF.Max(0.2f, o[i].Traits.MoveSpeed);
|
||||
// Способность Moving (падает от ран/болезней) — множитель к скорости: больные медленнее.
|
||||
var moving = hh[i].State.Capacity(AnimalCapacities.Moving);
|
||||
var speed = def.BaseSpeed * MathF.Max(0.2f, o[i].Traits.MoveSpeed) * moving;
|
||||
|
||||
switch (brain.Action)
|
||||
{
|
||||
@@ -1006,3 +1015,109 @@ public sealed class AnimalPregnancySystem : BaseSystem
|
||||
public Vector2 Position;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Здоровье и болезни (фаза A6): медленный тик (~игровой час). Фоновое заражение, прогресс болезней
|
||||
/// (гонка тяжесть↔иммунитет — выздоровление или смерть), пересчёт способностей с учётом хедифов. Смерть
|
||||
/// по здоровью (летальная болезнь / кровь на нуле / потеря сознания) оставляет труп. Первый реальный
|
||||
/// источник урона — оживляет каркас A5 (больные звери теряют Moving → медленнее).
|
||||
/// </summary>
|
||||
public sealed class AnimalHealthSystem : BaseSystem
|
||||
{
|
||||
private const float TickDays = 1f / 24f; // ~игровой час
|
||||
|
||||
private readonly EntityStore _store;
|
||||
private readonly AnimalSet _animals;
|
||||
private readonly int _cellSize;
|
||||
private readonly GameClock _clock;
|
||||
private readonly float _secondsPerDay;
|
||||
private readonly HediffDef[] _ambient;
|
||||
private readonly Random _rng;
|
||||
private readonly ArchetypeQuery<Health, AnimalOrganism> _query;
|
||||
private readonly List<Entity> _deaths = [];
|
||||
private float _accum;
|
||||
|
||||
public AnimalHealthSystem(
|
||||
EntityStore store,
|
||||
AnimalSet animals,
|
||||
int cellSize,
|
||||
GameClock clock,
|
||||
float secondsPerDay,
|
||||
HediffDef[] ambient,
|
||||
int seed
|
||||
)
|
||||
{
|
||||
_store = store;
|
||||
_animals = animals;
|
||||
_cellSize = cellSize;
|
||||
_clock = clock;
|
||||
_secondsPerDay = secondsPerDay;
|
||||
_ambient = ambient;
|
||||
_rng = new Random(seed);
|
||||
_query = store.Query<Health, AnimalOrganism>();
|
||||
}
|
||||
|
||||
protected override void OnUpdateGroup()
|
||||
{
|
||||
_accum += _clock.DeltaTime / _secondsPerDay;
|
||||
if (_accum < TickDays)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var days = _accum;
|
||||
_accum = 0f;
|
||||
_deaths.Clear();
|
||||
|
||||
foreach (var (healths, organisms, entities) in _query.Chunks)
|
||||
{
|
||||
var h = healths.Span;
|
||||
for (var i = 0; i < h.Length; i++)
|
||||
{
|
||||
var state = h[i].State;
|
||||
if (state is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var disease in _ambient)
|
||||
{
|
||||
if (!state.Has(disease.DefName) && _rng.NextSingle() < disease.AmbientPerDay * days)
|
||||
{
|
||||
state.Add(disease);
|
||||
}
|
||||
}
|
||||
|
||||
var lethal = state.AdvanceHediffs(days);
|
||||
state.RecomputeCapacities();
|
||||
if (
|
||||
lethal
|
||||
|| state.BloodLevel <= 0f
|
||||
|| state.Capacity(AnimalCapacities.Consciousness) <= 0.01f
|
||||
)
|
||||
{
|
||||
_deaths.Add(entities.EntityAt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var dead in _deaths)
|
||||
{
|
||||
if (dead.IsNull || !dead.HasComponent<AnimalOrganism>())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ref readonly var org = ref dead.GetComponent<AnimalOrganism>();
|
||||
var position = dead.GetComponent<Transform2D>().Position;
|
||||
AnimalFactory.CreateCorpse(
|
||||
_store,
|
||||
_animals[org.Species],
|
||||
position,
|
||||
org.Traits.BodySize,
|
||||
_cellSize
|
||||
);
|
||||
dead.DeleteEntity();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user