Животные: сериализация — сейв/лоад популяции и трупов
Закрывает сквозное требование плана (сейв/лоад данных каждой фазы). WorldSave получил Animals (AnimalSave: геном+пол, поколение, стадия/возраст, нужды, здоровье — кровь/HP частей/хедифы, настроение+мысли, беременность+геном отца) и Corpses (CorpseSave). SaveAnimals снимает популяцию (Health/Mood/Pregnant через entity); RestoreAnimals/RestoreAnimalState собирают особь фабрикой из генома + накладывают состояние (ref-правки до AddComponent(Pregnant); труп пере-тинтится через Stage=-1). Corpse получил Species; CreateCorpse принимает индекс вида + HealthState.AddHediff(def,severity,immunity). На загрузке стадо не пересыпается при наличии животных в сейве; старый/пустой сейв регенерируется из сида. Сборка + --check-content чистые. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
003f235440
commit
4b53eb8984
+14
-3
@@ -1,8 +1,19 @@
|
|||||||
# Животные (зоология)
|
# Животные (зоология)
|
||||||
|
|
||||||
> Статус: **A1–A8 реализованы целиком** — базовый план зоологии закрыт; дальше экологический горизонт
|
> Статус: **A1–A8 реализованы целиком + сериализация животных** — базовый план зоологии и его сквозное
|
||||||
> (хищники, опека, эпидемии, миграция) и бэклог реализма. Это живой план — стиль и правила как в
|
> требование сейв/лоада закрыты; дальше экологический горизонт (хищники, опека, эпидемии, миграция) и
|
||||||
> [концепте](concept.md) и [модах](mods.md).
|
> бэклог реализма. Это живой план — стиль и правила как в [концепте](concept.md) и [модах](mods.md).
|
||||||
|
>
|
||||||
|
> **Сериализация животных (готово): сейв/лоад популяции и трупов.** `WorldSave` получил `Animals`
|
||||||
|
> (`AnimalSave`: геном→признаки+пол, поколение, стадия/возраст, нужды+истощение, здоровье — кровь/HP
|
||||||
|
> частей/хедифы тяжесть+иммунитет, настроение+мысли, беременность+геном отца) и `Corpses` (`CorpseSave`:
|
||||||
|
> вид/позиция/таймер-стадия разложения/мясо). `SaveAnimals` снимает популяцию (Health/Mood/Pregnant — через
|
||||||
|
> entity, т.к. запрос ≤5 типов); `RestoreAnimals`/`RestoreAnimalState` собирают особь фабрикой из генома и
|
||||||
|
> накладывают динамическое состояние (ref-правки до структурного `AddComponent(Pregnant)`; труп
|
||||||
|
> пере-тинтится через `Stage=-1`). `Corpse` получил поле `Species` (для спрайта/разделки); `CreateCorpse`
|
||||||
|
> теперь принимает индекс вида. На загрузке стадо НЕ пересыпается, если в сейве есть животные; старый/пустой
|
||||||
|
> сейв — регенерируется из сида (не крашит). Эволюция/болезни/беременности переживают сейв/лоад. Сборка +
|
||||||
|
> `--check-content` чистые.
|
||||||
>
|
>
|
||||||
> **A8 часть 2 (готово): инспектор животных.** `InspectPanel` теперь осматривает и животных (не только
|
> **A8 часть 2 (готово): инспектор животных.** `InspectPanel` теперь осматривает и животных (не только
|
||||||
> растения): вкладки **Обзор** (стадия/возраст/пол/поколение/беременность), **Нужды** (значения нужд %),
|
> растения): вкладки **Обзор** (стадия/возраст/пол/поколение/беременность), **Нужды** (значения нужд %),
|
||||||
|
|||||||
@@ -62,6 +62,117 @@ public sealed class PawnSave
|
|||||||
public float ChangeIn { get; set; }
|
public float ChangeIn { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Сериализуемый хедиф особи (фаза A6): деф (по имени), тяжесть и набранный иммунитет.</summary>
|
||||||
|
public sealed class HediffSave
|
||||||
|
{
|
||||||
|
/// <summary>Имя дефа хедифа (гон/болезнь).</summary>
|
||||||
|
public string DefName { get; set; } = "";
|
||||||
|
|
||||||
|
/// <summary>Текущая тяжесть.</summary>
|
||||||
|
public float Severity { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Набранный иммунитет [0,1].</summary>
|
||||||
|
public float Immunity { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Сериализуемая событийная мысль (фаза A8): деф (по имени) и остаток времени до угасания.</summary>
|
||||||
|
public sealed class ThoughtSave
|
||||||
|
{
|
||||||
|
/// <summary>Имя дефа мысли.</summary>
|
||||||
|
public string DefName { get; set; } = "";
|
||||||
|
|
||||||
|
/// <summary>Сколько игровых дней мысль ещё действует.</summary>
|
||||||
|
public float RemainingDays { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Сериализуемое состояние одного животного (фазы A1–A8): вид, позиция, геном (источник признаков и
|
||||||
|
/// пола), поколение, стадия/возраст, нужды, здоровье (кровь, HP частей, хедифы), настроение и
|
||||||
|
/// беременность. Спрайт пересобирается фабрикой из дефа. Чтобы популяция (эволюция/состояние)
|
||||||
|
/// переживала сейв/лоад, а не пересыпалась заново из сида.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class AnimalSave
|
||||||
|
{
|
||||||
|
/// <summary>Имя дефа вида — по нему берётся индекс/стадии/текстуры/тело.</summary>
|
||||||
|
public string Species { get; set; } = "";
|
||||||
|
|
||||||
|
/// <summary>Позиция X в мировых координатах.</summary>
|
||||||
|
public float X { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Позиция Y в мировых координатах.</summary>
|
||||||
|
public float Y { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Номер поколения (для popstats/дрейфа).</summary>
|
||||||
|
public int Generation { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Текущая стадия роста.</summary>
|
||||||
|
public int Stage { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Накопленный возраст в игровых днях.</summary>
|
||||||
|
public float AgeDays { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Геном особи: аллели по id генов (переменного состава; несёт и пол через GeneSex).</summary>
|
||||||
|
public Dictionary<string, Allele> Genome { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>Значения нужд по индексам NeedSet.</summary>
|
||||||
|
public float[] Needs { get; set; } = [];
|
||||||
|
|
||||||
|
/// <summary>Накоплено дней истощения.</summary>
|
||||||
|
public float Starve { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Уровень крови [0,1].</summary>
|
||||||
|
public float BloodLevel { get; set; } = 1f;
|
||||||
|
|
||||||
|
/// <summary>HP частей тела по порядку анатомии вида (пусто — у вида нет тела).</summary>
|
||||||
|
public float[] PartHp { get; set; } = [];
|
||||||
|
|
||||||
|
/// <summary>Активные хедифы (гон/болезни).</summary>
|
||||||
|
public List<HediffSave> Hediffs { get; set; } = [];
|
||||||
|
|
||||||
|
/// <summary>Текущее настроение [0,1].</summary>
|
||||||
|
public float Mood { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Активно ли настроение (тир 4+).</summary>
|
||||||
|
public bool MoodActive { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Активные событийные мысли.</summary>
|
||||||
|
public List<ThoughtSave> Thoughts { get; set; } = [];
|
||||||
|
|
||||||
|
/// <summary>Беременна ли самка.</summary>
|
||||||
|
public bool Pregnant { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Геном отца (если беременна) — «слепок» на момент зачатия.</summary>
|
||||||
|
public Dictionary<string, Allele> FatherGenome { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>Остаток срока вынашивания (игровых дней).</summary>
|
||||||
|
public float DueInDays { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Размер помёта.</summary>
|
||||||
|
public int Litter { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Сериализуемый труп (фаза A5): вид (для спрайта), позиция, таймер/стадия разложения, мясо.</summary>
|
||||||
|
public sealed class CorpseSave
|
||||||
|
{
|
||||||
|
/// <summary>Имя дефа вида — по нему берётся спрайт трупа.</summary>
|
||||||
|
public string Species { get; set; } = "";
|
||||||
|
|
||||||
|
/// <summary>Позиция X в мировых координатах.</summary>
|
||||||
|
public float X { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Позиция Y в мировых координатах.</summary>
|
||||||
|
public float Y { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Накоплено игровых дней разложения.</summary>
|
||||||
|
public float RotDays { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Размер тела (для масштаба спрайта).</summary>
|
||||||
|
public float BodySize { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Доступное мясо.</summary>
|
||||||
|
public float Meat { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Полное состояние мира для сохранения/загрузки: конфиг мира (имя/размер/сид/сглаживание),
|
/// Полное состояние мира для сохранения/загрузки: конфиг мира (имя/размер/сид/сглаживание),
|
||||||
/// прошедшее время симуляции и снимок всех жителей. Рельеф не сохраняется — он
|
/// прошедшее время симуляции и снимок всех жителей. Рельеф не сохраняется — он
|
||||||
@@ -99,6 +210,12 @@ public sealed class WorldSave
|
|||||||
/// <summary>Снимок всех растений (геномы, позиции, возраст, стадия).</summary>
|
/// <summary>Снимок всех растений (геномы, позиции, возраст, стадия).</summary>
|
||||||
public List<PlantSave> Plants { get; set; } = [];
|
public List<PlantSave> Plants { get; set; } = [];
|
||||||
|
|
||||||
|
/// <summary>Снимок всех животных (геном, стадия/возраст, нужды, здоровье, настроение, беременность).</summary>
|
||||||
|
public List<AnimalSave> Animals { get; set; } = [];
|
||||||
|
|
||||||
|
/// <summary>Снимок трупов (вид, позиция, таймер/стадия разложения, мясо).</summary>
|
||||||
|
public List<CorpseSave> Corpses { get; set; } = [];
|
||||||
|
|
||||||
/// <summary>Конфиг мира для пересоздания сцены.</summary>
|
/// <summary>Конфиг мира для пересоздания сцены.</summary>
|
||||||
public WorldConfig ToConfig() =>
|
public WorldConfig ToConfig() =>
|
||||||
new()
|
new()
|
||||||
|
|||||||
@@ -126,9 +126,16 @@ public sealed class WorldScene : Scene
|
|||||||
RestorePlants(content);
|
RestorePlants(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Животные: детерминированный начальный спавн по данным (плотность из дефов). Пока без сейва —
|
// Животные: из сейва (сохранённая популяция — эволюция/состояние не теряются) либо
|
||||||
// регенерируются из сида и для нового, и для загруженного мира.
|
// детерминированный спавн из сида (новый мир или старый сейв без животных).
|
||||||
SpawnAnimals();
|
if (_save?.Animals is { Count: > 0 })
|
||||||
|
{
|
||||||
|
RestoreAnimals(content);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SpawnAnimals();
|
||||||
|
}
|
||||||
|
|
||||||
// Освещение: лайтмап (день/ночь × окклюзия от гор/крон + точечные) множится поверх мира,
|
// Освещение: лайтмап (день/ночь × окклюзия от гор/крон + точечные) множится поверх мира,
|
||||||
// а Lighting.SampleAt даёт локальный свет системе роста (подлесок под кронами растёт хуже).
|
// а Lighting.SampleAt даёт локальный свет системе роста (подлесок под кронами растёт хуже).
|
||||||
@@ -501,11 +508,108 @@ public sealed class WorldScene : Scene
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
SaveAnimals(save);
|
||||||
|
|
||||||
new SaveStore().Write(save);
|
new SaveStore().Write(save);
|
||||||
Log.Info($"World '{_config.Name}' saved ({save.Plants.Count} plants)");
|
Log.Info(
|
||||||
|
$"World '{_config.Name}' saved ({save.Plants.Count} plants, "
|
||||||
|
+ $"{save.Animals.Count} animals, {save.Corpses.Count} corpses)"
|
||||||
|
);
|
||||||
return _config.Name;
|
return _config.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Снимок популяции животных и трупов: всё нужное, чтобы эволюция/состояние пережили сейв/лоад
|
||||||
|
// (а не пересыпались из сида). Health/Mood/Pregnant берём через entity — запрос ограничен 5 типами.
|
||||||
|
private void SaveAnimals(WorldSave save)
|
||||||
|
{
|
||||||
|
Store
|
||||||
|
.Query<AnimalOrganism, AnimalGrowth, AnimalNeeds, Transform2D>()
|
||||||
|
.ForEachEntity(
|
||||||
|
(
|
||||||
|
ref AnimalOrganism org,
|
||||||
|
ref AnimalGrowth grow,
|
||||||
|
ref AnimalNeeds needs,
|
||||||
|
ref Transform2D transform,
|
||||||
|
Entity entity
|
||||||
|
) =>
|
||||||
|
{
|
||||||
|
var record = new AnimalSave
|
||||||
|
{
|
||||||
|
Species = _animals[org.Species].Def.DefName,
|
||||||
|
X = transform.Position.X,
|
||||||
|
Y = transform.Position.Y,
|
||||||
|
Generation = org.Generation,
|
||||||
|
Stage = grow.Stage,
|
||||||
|
AgeDays = grow.AgeDays,
|
||||||
|
Genome = org.Genome.ToDictionary(),
|
||||||
|
Needs = needs.Values,
|
||||||
|
Starve = needs.Starve,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (entity.GetComponent<Health>().State is { } health)
|
||||||
|
{
|
||||||
|
record.BloodLevel = health.BloodLevel;
|
||||||
|
record.PartHp = health.Parts.Select(p => p.Hp).ToArray();
|
||||||
|
foreach (var hediff in health.Hediffs)
|
||||||
|
{
|
||||||
|
record.Hediffs.Add(
|
||||||
|
new HediffSave
|
||||||
|
{
|
||||||
|
DefName = hediff.Def.DefName,
|
||||||
|
Severity = hediff.Severity,
|
||||||
|
Immunity = hediff.Immunity,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var mood = entity.GetComponent<Mood>();
|
||||||
|
record.Mood = mood.Value;
|
||||||
|
record.MoodActive = mood.Active;
|
||||||
|
if (mood.Thoughts is not null)
|
||||||
|
{
|
||||||
|
foreach (var thought in mood.Thoughts)
|
||||||
|
{
|
||||||
|
record.Thoughts.Add(
|
||||||
|
new ThoughtSave
|
||||||
|
{
|
||||||
|
DefName = thought.Def.DefName,
|
||||||
|
RemainingDays = thought.RemainingDays,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity.TryGetComponent<Pregnant>(out var preg))
|
||||||
|
{
|
||||||
|
record.Pregnant = true;
|
||||||
|
record.FatherGenome = preg.FatherGenome.ToDictionary();
|
||||||
|
record.DueInDays = preg.DueInDays;
|
||||||
|
record.Litter = preg.Litter;
|
||||||
|
}
|
||||||
|
|
||||||
|
save.Animals.Add(record);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Store
|
||||||
|
.Query<Corpse, Transform2D>()
|
||||||
|
.ForEachEntity(
|
||||||
|
(ref Corpse corpse, ref Transform2D transform, Entity _) =>
|
||||||
|
save.Corpses.Add(
|
||||||
|
new CorpseSave
|
||||||
|
{
|
||||||
|
Species = _animals[corpse.Species].Def.DefName,
|
||||||
|
X = transform.Position.X,
|
||||||
|
Y = transform.Position.Y,
|
||||||
|
RotDays = corpse.RotDays,
|
||||||
|
BodySize = corpse.Meat / AnimalFactory.MeatPerBodySize,
|
||||||
|
Meat = corpse.Meat,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private void RestorePlants(GameContent content)
|
private void RestorePlants(GameContent content)
|
||||||
{
|
{
|
||||||
var fallback = new Random(_config.Seed); // для старых/битых сейвов без генома
|
var fallback = new Random(_config.Seed); // для старых/битых сейвов без генома
|
||||||
@@ -533,6 +637,122 @@ public sealed class WorldScene : Scene
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Восстанавливает популяцию животных и трупы из сейва: фабрика собирает особь из генома (геном
|
||||||
|
// несёт и пол), затем динамическое состояние (нужды/стадия/здоровье/настроение/беременность)
|
||||||
|
// накладывается поверх. Старый/битый сейв без генома — особь регенерируется из шаблона вида.
|
||||||
|
private void RestoreAnimals(GameContent content)
|
||||||
|
{
|
||||||
|
var fallback = new Random(_config.Seed);
|
||||||
|
foreach (var saved in _save!.Animals)
|
||||||
|
{
|
||||||
|
if (!content.Defs.TryGet<AnimalDef>(saved.Species, out var def))
|
||||||
|
{
|
||||||
|
continue; // вид пропал (мод убрали) — пропускаем особь
|
||||||
|
}
|
||||||
|
|
||||||
|
var index = _animals.IndexOf(def);
|
||||||
|
var genome = saved.Genome is { Count: > 0 }
|
||||||
|
? new Genome(saved.Genome)
|
||||||
|
: _animals.GenerateGenome(index, fallback);
|
||||||
|
var entity = AnimalFactory.Create(
|
||||||
|
Store,
|
||||||
|
_animals,
|
||||||
|
_needs,
|
||||||
|
index,
|
||||||
|
new Vector2(saved.X, saved.Y),
|
||||||
|
saved.AgeDays,
|
||||||
|
genome,
|
||||||
|
saved.Generation,
|
||||||
|
CellSize
|
||||||
|
);
|
||||||
|
RestoreAnimalState(entity, saved, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var saved in _save.Corpses)
|
||||||
|
{
|
||||||
|
if (!content.Defs.TryGet<AnimalDef>(saved.Species, out var def))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var corpse = AnimalFactory.CreateCorpse(
|
||||||
|
Store,
|
||||||
|
_animals,
|
||||||
|
_animals.IndexOf(def),
|
||||||
|
new Vector2(saved.X, saved.Y),
|
||||||
|
saved.BodySize,
|
||||||
|
CellSize
|
||||||
|
);
|
||||||
|
ref var data = ref corpse.GetComponent<Corpse>();
|
||||||
|
data.RotDays = saved.RotDays;
|
||||||
|
data.Stage = -1; // форсируем пере-тинт стадии в CorpseSystem на следующем тике
|
||||||
|
data.Meat = saved.Meat;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Info(
|
||||||
|
$"Restored {_save.Animals.Count} animals, {_save.Corpses.Count} corpses from save"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Накладывает на свежесозданную особь сохранённое динамическое состояние. Ref-компоненты правим до
|
||||||
|
// AddComponent(Pregnant) (структурное изменение инвалидирует ссылки); Health — managed, безопасен.
|
||||||
|
private void RestoreAnimalState(Entity entity, AnimalSave saved, GameContent content)
|
||||||
|
{
|
||||||
|
ref var needs = ref entity.GetComponent<AnimalNeeds>();
|
||||||
|
if (saved.Needs is { Length: > 0 } && saved.Needs.Length == _needs.Count)
|
||||||
|
{
|
||||||
|
needs.Values = saved.Needs; // состав совпал — иначе остаются свежие из фабрики
|
||||||
|
}
|
||||||
|
|
||||||
|
needs.Starve = saved.Starve;
|
||||||
|
entity.GetComponent<AnimalGrowth>().Stage = saved.Stage;
|
||||||
|
|
||||||
|
ref var mood = ref entity.GetComponent<Mood>();
|
||||||
|
mood.Value = saved.Mood;
|
||||||
|
mood.Active = saved.MoodActive;
|
||||||
|
mood.Thoughts.Clear();
|
||||||
|
foreach (var thought in saved.Thoughts)
|
||||||
|
{
|
||||||
|
if (content.Defs.TryGet<ThoughtDef>(thought.DefName, out var tdef))
|
||||||
|
{
|
||||||
|
mood.Thoughts.Add(
|
||||||
|
new ThoughtInstance { Def = tdef, RemainingDays = thought.RemainingDays }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity.GetComponent<Health>().State is { } health)
|
||||||
|
{
|
||||||
|
health.BloodLevel = saved.BloodLevel;
|
||||||
|
for (var i = 0; i < health.Parts.Length && i < saved.PartHp.Length; i++)
|
||||||
|
{
|
||||||
|
health.Parts[i].Hp = saved.PartHp[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var hediff in saved.Hediffs)
|
||||||
|
{
|
||||||
|
if (content.Defs.TryGet<HediffDef>(hediff.DefName, out var hdef))
|
||||||
|
{
|
||||||
|
health.AddHediff(hdef, hediff.Severity, hediff.Immunity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
health.RecomputeCapacities();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (saved.Pregnant && saved.FatherGenome is { Count: > 0 })
|
||||||
|
{
|
||||||
|
entity.AddComponent(
|
||||||
|
new Pregnant
|
||||||
|
{
|
||||||
|
FatherGenome = new Genome(saved.FatherGenome),
|
||||||
|
DueInDays = saved.DueInDays,
|
||||||
|
Litter = saved.Litter,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Детерминированный начальный спавн животных по данным: каждый вид с SpawnPer1000Cells > 0
|
// Детерминированный начальный спавн животных по данным: каждый вид с SpawnPer1000Cells > 0
|
||||||
// рассыпается по клеткам суши с плотностью из дефа; геном и возраст особи — из шаблона вида.
|
// рассыпается по клеткам суши с плотностью из дефа; геном и возраст особи — из шаблона вида.
|
||||||
private void SpawnAnimals()
|
private void SpawnAnimals()
|
||||||
|
|||||||
@@ -84,12 +84,14 @@ public static class AnimalFactory
|
|||||||
/// <summary>Создаёт сущность-труп после смерти животного: спрайт-падаль, запас мяса (∝ размер тела).</summary>
|
/// <summary>Создаёт сущность-труп после смерти животного: спрайт-падаль, запас мяса (∝ размер тела).</summary>
|
||||||
public static Entity CreateCorpse(
|
public static Entity CreateCorpse(
|
||||||
EntityStore store,
|
EntityStore store,
|
||||||
AnimalSet.Species sp,
|
AnimalSet animals,
|
||||||
|
int species,
|
||||||
Vector2 position,
|
Vector2 position,
|
||||||
float bodySize,
|
float bodySize,
|
||||||
int cellSize
|
int cellSize
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
var sp = animals[species];
|
||||||
var region = sp.Corpse;
|
var region = sp.Corpse;
|
||||||
var sprite = new Sprite(region, GameLayers.Beings);
|
var sprite = new Sprite(region, GameLayers.Beings);
|
||||||
sprite.CenterOrigin();
|
sprite.CenterOrigin();
|
||||||
@@ -100,6 +102,7 @@ public static class AnimalFactory
|
|||||||
sprite,
|
sprite,
|
||||||
new Corpse
|
new Corpse
|
||||||
{
|
{
|
||||||
|
Species = species,
|
||||||
RotDays = 0f,
|
RotDays = 0f,
|
||||||
Stage = 0,
|
Stage = 0,
|
||||||
Meat = bodySize * MeatPerBodySize,
|
Meat = bodySize * MeatPerBodySize,
|
||||||
|
|||||||
@@ -286,6 +286,22 @@ public sealed class HealthState
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Восстанавливает хедиф с заданной тяжестью и иммунитетом (для загрузки сейва).</summary>
|
||||||
|
public void AddHediff(HediffDef def, float severity, float immunity)
|
||||||
|
{
|
||||||
|
if (!Has(def.DefName))
|
||||||
|
{
|
||||||
|
_hediffs.Add(
|
||||||
|
new Hediff
|
||||||
|
{
|
||||||
|
Def = def,
|
||||||
|
Severity = severity,
|
||||||
|
Immunity = immunity,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Снимает хедиф по имени дефа; возвращает, был ли он.</summary>
|
/// <summary>Снимает хедиф по имени дефа; возвращает, был ли он.</summary>
|
||||||
public bool Remove(string defName)
|
public bool Remove(string defName)
|
||||||
{
|
{
|
||||||
@@ -316,6 +332,9 @@ public struct Health : IComponent
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public struct Corpse : IComponent
|
public struct Corpse : IComponent
|
||||||
{
|
{
|
||||||
|
/// <summary>Индекс вида в <see cref="Content.AnimalSet"/> (для спрайта, разделки, сейва).</summary>
|
||||||
|
public int Species;
|
||||||
|
|
||||||
/// <summary>Накоплено игровых дней разложения.</summary>
|
/// <summary>Накоплено игровых дней разложения.</summary>
|
||||||
public float RotDays;
|
public float RotDays;
|
||||||
|
|
||||||
|
|||||||
@@ -994,7 +994,8 @@ public sealed class AnimalMortalitySystem : BaseSystem
|
|||||||
var position = dead.GetComponent<Transform2D>().Position;
|
var position = dead.GetComponent<Transform2D>().Position;
|
||||||
AnimalFactory.CreateCorpse(
|
AnimalFactory.CreateCorpse(
|
||||||
_store,
|
_store,
|
||||||
_animals[org.Species],
|
_animals,
|
||||||
|
org.Species,
|
||||||
position,
|
position,
|
||||||
org.Traits.BodySize,
|
org.Traits.BodySize,
|
||||||
_cellSize
|
_cellSize
|
||||||
@@ -1317,7 +1318,8 @@ public sealed class AnimalHealthSystem : BaseSystem
|
|||||||
var position = dead.GetComponent<Transform2D>().Position;
|
var position = dead.GetComponent<Transform2D>().Position;
|
||||||
AnimalFactory.CreateCorpse(
|
AnimalFactory.CreateCorpse(
|
||||||
_store,
|
_store,
|
||||||
_animals[org.Species],
|
_animals,
|
||||||
|
org.Species,
|
||||||
position,
|
position,
|
||||||
org.Traits.BodySize,
|
org.Traits.BodySize,
|
||||||
_cellSize
|
_cellSize
|
||||||
|
|||||||
Reference in New Issue
Block a user