Files
LittleSim/docs/животные.md
T
Leonid PershinandClaude Opus 4.8 9db12273c9 Животные A5 (часть 2): части тела, кровь, capacities
BodyDef/BodyPartDef + bodies.json (Quadruped — данные: иерархия органов, вклады в способности). AnimalDef.Body. HealthState расширен Parts/BloodLevel/Pain/Capacities; CapacityCalc обобщённо считает способности по зависимостям (кровь->сердце/лёгкие->сознание->движение/зрение), модовые проходят сырыми. Фабрика строит части (HP x размер тела) и начальные способности. Источников урона нет -> всё на полном HP, способности=1 (каркас под болезни/хищников). Команда body <species>.

Сборка чистая, --check-content (10 типов дефов).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 05:36:34 +03:00

46 KiB
Raw Blame History

Животные (зоология)

Статус: A1–A4 + рефактор расширяемости + A5(труп) реализованы, остальное по плану. Это живой план — правится по мере реализации фаз A1–A8. Стиль и правила — как в концепте и модах.

A5 часть 1 (готово): смерть → труп → разложение. Corpse-компонент + CorpseSystem (Fresh→Rotting→Skeleton→исчезает, скорость от температуры, тинт по стадии); смерть теперь оставляет труп (AnimalFactory.CreateCorpse, мясо ∝ размер тела) вместо деспавна; AnimalDef.CorpseTexture + corpseTexture оленя (Dessicated_*, скелет — бледный тинт, своего спрайта пока нет). Продукты ProductMeat/Bone/Leather в products.json (разделка/падальщики — позже). Сборка/линт чистые. A5 часть 2 (готово): части тела, кровь, capacities. BodyDef/BodyPartDef + bodies.json (Quadruped — данные: иерархия органов, вклады в способности); AnimalDef.Body; HealthState расширен Parts/BloodLevel/Pain/Capacities; CapacityCalc (обобщённый расчёт по зависимостям кровь→сердце/лёгкие→сознание→движение/зрение, модовые способности — сырыми); фабрика строит части (HP × размер тела) и считает способности. Источников урона ещё нет → всё на полном HP, способности = 1 (каркас под болезни A6/хищников). Команда body <species>. Сборка/линт чистые (10 типов дефов). Осталось в A5: смерть через здоровье (vital-часть/кровь) + истощение как hediff — когда появятся раны.

A4 (готово): нужда Mating; лёгкий hediff-каркас (HediffDef, hediffs.json с Rut, компонент Health/HealthState); гены GeneBreedingSeason/GeneGestationDays/GeneLitterSize; AnimalRutSystem (сезонный гон-хедиф поднимает влечение — вне сезона зачатия нет); действие Mate (поиск партнёра, сближение); Pregnant + AnimalPregnancySystem (вынашивание → роды через Genome.Breed, наследование пола без YY, поколение+1, потолок численности). Сборка чистая, --check-content (33 гена).

Рефактор расширяемости (готово): устранены хардкод-блокеры — данными стали: геном вида (AnimalDef.Genome = словарь geneId→base, шаблон строится generically); нужды (NeedDef/needs.json + NeedSet + динамический AnimalNeeds.Values + реестр поведений по id); диета (AnimalDef.Diet); стадии роста (AnimalStageDef/AnimalDef.Stages — возраст входа, масштаб, текстуры, флаг «взрослая»; пусто → встроенный дефолт); спавн (AnimalDef.SpawnPer1000Cells — все виды рассыпаются по суше из данных, не только олень). Добавить ген/нужду/рацион/стадию/спавн виду = правка JSON без кода. Остаются как известные: реестр действий-кода (новое поведение = код, сознательная граница), часть глобальных баланс-констант (скорость/выпас/потолок).

A3 (готово): компонент AnimalGrowth (стадия + возраст); ген пола GeneSex (XX/XY, генерация основателя без YY через AnimalSet.GenerateGenome) и ген GeneMaturityAge; стадии Baby→Juvenile→Adult→Senior с порогами из генов; AnimalGrowthSystem (смена спрайта детёныш/самец/самка и размера по стадии) + AnimalMortalitySystem (смерть от старости и от истощения → деспавн, замыкает контур ёмкости среды). Спавн стада — разновозрастный; команда animal показывает пол/созревание. Сборка чистая, --check-content (30 генов).

A1 (готово): тип дефа Animal (AnimalDef : PawnDef) + animals.json (олень); 8 животных генов в genes.json; AnimalPhenotype/AnimalOrganism; AnimalSet (шаблон генома вида) + AnimalFactory; детерминированный спавн стада оленей по суше в WorldScene с рендером и тинтом меха по гену; консольная команда animal <species>.

A2 (готово): нужды AnimalNeeds (голод/жажда/отдых) с падением по гену метаболизма; два слоя ИИ — AnimalDecisionSystem (движковый UtilityAi, выбор + поиск ближайшей еды/воды) и AnimalActionSystem (движение к цели + утоление: выедание растений, питьё у кромки воды, сон); AnimalAppearanceSystem (яркость по острой нужде); кромка воды из террейна; команда popstats [species] (средние признаков + размах поколений). Контур ёмкости среды частичный (трава выедается, но смерть от голода — в A3). Сборка чистая; визуальная проверка (олени ищут корм/воду, пасутся) — вручную: «Новый мир».

Видение

Животные — следующая большая система после генов. Главный принцип: животное живёт по тем же законам, что и растение — гены → признаки (фенотип) → поведение систем, — но разворачивает их в полноценную зоологию: двуполое размножение с вынашиванием, здоровье по модели RimWorld (части тела, органы, кровь, болезни), мозг и интеллект, нужды и настроение. Цель прежняя: эмерджентность (динамика популяций, отбор, пищевые цепи складываются из правил, а не скриптуются) и наблюдаемость (всё видно в мире, HUD, инспекторе, консоли).

Первое показательное животное — олень (богатый набор текстур: ♂/♀/детёныш/труп).

Опора на существующий фундамент

Ничего из перечисленного не строим заново — переиспользуем:

  • организм-агностичный GeneDef, управляемый Genome (диплоидные аллели), Genome.Breed(мать, отец, mutationChance), Phenotype.Compute, GenomeTemplate (шаблон вида, ср. PlantSet.BuildTemplate);
  • формульный движок и regex-группы (gsum('Gene.*')) для производных признаков;
  • движковый UtilityAi<TContext>, ResponseCurve, Suitability.Trapezoid;
  • день/ночь, сезоны, климат, террейн water, ProductDef;
  • паттерн компонентов растений: …Organism { Genome; Phenotype Traits }, …Growth { species, stage, ageDays }, …Needs, …Brain, AppearanceSystem (sim→Sprite).
  • Friflo допускает managed-ссылку в IComponent (доказано Genome/Tilemap) — поэтому Health/Pregnant несут managed-объекты.

Принцип моддинга: всё расширяется данными

Главное требование — система должна целиком модифицироваться через моды без правки кода. Для этого:

  1. Никаких C#-enum для видового контента. Виды, части тела, органы, способности (capacities), болезни, нужды, мысли — это дефы со строковыми id, интернируемые в int при загрузке (ровно как уже сделано с geneId). Enum нельзя расширить модом — строковый id можно.
  2. Формулы вместо констант везде, где можно (как effects у генов): модер меняет баланс формулой в дефе, а не пересборкой.
  3. Реестр поведенческих действий (actionId → исполнитель-код). Деф нужды/ИИ ссылается на actionId. Граница честная и в духе проекта (движок без сэмпла, фичи демонстрируются игрой): комбинировать готовые кирпичи — мод; принципиально новое поведение — код + деф.
  4. Patch-система (фаза G5) уже позволяет модеру менять чужие дефы по regex (например, «всем хищникам +агрессия»).
  5. Любой деф переопределяется одноимённым из позднего мода; локализация — в Languages.

Итог: модер добавляет новый вид зверя, орган, болезнь, нужду или мысль одними JSON-файлами.

Геном животного

Животные гены живут в genes.json рядом с растительными (один организм-агностичный тип Gene). Предлагаемый набор (числовые, если не сказано иное):

Группа Гены
Тело/метаболизм GeneMaxBodySize, GeneMetabolism, GeneMoveSpeed, GeneBloodVolume, GeneVision, GeneInsulation (мех/терморегуляция)
Жизненный цикл GeneMaturityAge, GeneLifespan (есть), GeneGestationDays, GeneLitterSize
Органы GeneHeartEfficiency, GeneLungCapacity, GeneImmunityGain, GeneHealRate, GenePainTolerance
Мозг GeneBrainSize → признак brainSize (см. «Мозг и интеллект»)
Поведение GeneAggression, GeneSociability, GeneActivityPattern (дневной/ночной/сумеречный)
Среда переиспользуем GeneOptimalTemperature/Tolerance/Cold/HeatHardiness — звери тоже мёрзнут/перегреваются через ту же трапецию
Морфология GeneFurColor (тинт спрайта, как leafHue), GeneSex (дискретный, см. ниже)

Пол выводится из диплоидности бесплатно. Локус с аллелями {X=0, Y=1}: самка = XX, самец = XY. При Genome.Breed мать может отдать только X (у неё нет Y), отец — X/Y поровну → потомок XX/XY ровно 50/50, без спец-кода в скрещивании. У гена пола mutationChance: 0 (как у GeneFruitSeason), чтобы X не мутировал в Y.

Тонкость генерации (не скрещивания): обычный Generate дискретного гена выбрал бы два аллеля независимо и мог бы выдать невозможный YY. Поэтому пол особи-основателя назначается явно — XX или XY (по 50/50) — а дальнейшее наследование корректно само.

Признаки собираются в AnimalPhenotype.FromTraits(traits) — зеркало PlantPhenotype. Организм: AnimalOrganism { Genome; AnimalPhenotype Traits; int Generation } (поколение = max(род.) + 1, у основателей 0 — для popstats и видимого дрейфа).

Жизненный цикл и стадии роста

Зеркало PlantGrowth: AnimalGrowth { species, stage, ageDays }. Стадии задаются данными в дефе вида: Embryo (в утробе) → BabyJuvenileAdultSenior, пороги из генов (MaturityAge, Lifespan). AnimalGrowthSystem двигает стадию, масштабирует sizeCells, меняет спрайт/набор текстур (Baby ↔ ♀/♂). Стадия Senior повышает шанс возрастных hediff и смерти — стык со здоровьем.

Путь смерти по фазам. Чтобы на A4 (размножение) популяция не взрывалась без убыли, простая смерть по старости и от голода/жажды (деспавн) появляется уже в A3. На A5 она «апгрейдится»: смерть идёт через здоровье (возрастные hediff, истощение, отказ органов) и оставляет труп вместо деспавна.

Нужды и ИИ

Обобщаем PawnNeeds (одна энергия) → AnimalNeeds: голод, жажда, сон, секс (0..1).

  • скорости падения из GeneMetabolism × размер (масштаб по Клайберу: ∝ size^0.75);
  • голод — ест растения/продукты. Поедание реально воздействует на сущность растения (важно для контура ёмкости среды): выедает накопленные плоды (Fruiting.RipeFruit) и/или убавляет биомассу/стадию растения; перевыпас может убить растение. Диета (AnimalDef.diet) — список съедобного: теги растений/ProductDef (для будущих хищников — живая добыча/мясо/трупы), плюс способ (выедание плодов vs выпас);
  • жажда — пьёт на клетках террейна water;
  • сон — спит в неактивную фазу суток (GeneActivityPattern): дневные ночью и т.д.;
  • секс — удовлетворяется размножением.

ИИ разбит на два слоя — выбор и исполнение:

  1. ВыборAnimalDecisionSystem на движковом UtilityAi: из активных нужд выбирает действие FindFood / FindWater / Sleep / SeekMate / Wander(default) (готовые ResponseCurve) и пишет его + цель в AnimalBrain { Action; Target; DecideIn }. Действия и нужды описаны дефами NeedDef (decay-формула, minBrain).
  2. Исполнение — отдельный слой систем (реестр actionId → исполнитель, см. «Принцип моддинга») доводит выбранное действие до результата по схеме найти цель → дойти → выполнить → удовлетворить нужду:
    • Eat: ближайшее съедобное (плод/биомасса) → подойти → съесть (убавить растение) → ↑ сытость;
    • Drink: ближайшая клетка water → подойти → попить → ↓ жажда;
    • Sleep: остановиться → спать → ↓ усталость;
    • Mate: подходящий партнёр → сблизиться → акт → Pregnant + сброс Mating;
    • Wander: движение по умолчанию. Без этого слоя нужда только падает, но не исполняется.

Передвижение и поиск цели. Движение к цели — рулевое смещение к точке (реюз Transform2D + WanderSystem/SeparationSystem для обхода препятствий: стволы деревьев, другие звери), без полноценного A* на старте. Вода непроходима для сухопутных → Drink целит клетку суши у кромки воды. «Ближайшее съедобное/вода/партнёр» — пространственный запрос по сетке/тайлмапу с радиусом из Vision/Sight (не O(n²)); ничьи в «ближайшем» разрешаются детерминированно (по id сущности).

Порядок фаз: формальный гейтинг нужд интеллектом — фаза A7. В A2 у оленя просто полный набор нужд зверя (тир 4); поле minBrain уже пишем в дефы, но активируется оно на A7 (см. «Мозг и интеллект»).

Размножение (млекопитающие)

Главное отличие от растений — двуполость и отложенное во времени вынашивание:

  1. Влечение и гон (через хедиф). Нужда Mating есть круглый год на низком фоне. В брачный сезон вида на взрослых вешается хедиф Rut (гон), который поднимает влечение (множитель на рост Mating / снижение порога действия). Только под Rut влечение переходит порог SeekMate → вне сезона зачатия фактически нет, хотя нужда формально существует. Хедиф снимается с концом сезона и виден в инспекторе (как любой hediff). Это унифицирует сезонность с hediff-механизмом, а не городит спец-флаг.
  2. Спаривание → беременность. Два взрослых разного пола сближаются (действие Mate) → акт → у самки появляется Pregnant : IComponent { Genome FatherGenome; float ConceivedDay; float GestationDays; int LitterSize } — managed-ссылка на геном отца (оплодотворение = «слепок» отца). Беременность повышает метаболизм (голод) и снижает Moving. (Можно реализовать и как hediff, но держим компонентом ради managed-ссылки на геном отца.)
  3. Роды. По достижении срока спавним LitterSize детёнышей, каждому Genome.Breed(мать, отец, mutationRate), стадия Baby, рядом с матерью. Лактация/ опека — опционально после.

Стратегии r/K выводятся из генов: мелкие (заяц) — большой помёт, короткая жизнь; крупные (олень/медведь) — мало потомства, долгая жизнь.

Решённые параметры (A4):

  • Гон = хедиф Rut (а не «нужда растёт в сезон»): навешивается в брачный сезон GeneBreedingSeason (как fruitSeason, 0..3) — у оленя осень (→ роды весной к обилию корма); у r-стратегов (заяц) — круглогодично/частый гон. Под Rut влечение переходит порог действия; вне Rut зачатия нет.
  • Hediff-каркас рождается здесь (A4). Гон — первый хедиф, поэтому в A4 появляется лёгкий каркас: контейнер Health/HealthState со списком хедифов, HediffDef со стадиями и модификаторами, навешивание/снятие по триггеру. A5/A6 расширяют его частями тела, кровью, болезнями.
  • Триггер акта — взрослые, разный пол, у обоих Mating > 0.6, рядом (1–2 клетки), самка не беременна, оба не спят/не убегают.
  • Послеродовый кулдаун — самка не зачинает снова до родов + восстановления; самец восстанавливается быстро → полигиния (один самец кроет нескольких самок).
  • Выбор партнёра (половой отбор) — НЕ в A4: на старте берётся ближайший подходящий; предпочтение по размеру/здоровью/настроению добавим позже отдельной итерацией.

Здоровье — полная модель RimWorld

Данные (дефы)

  • BodyDef — дерево частей. У части: coverage (доля тела → вес попадания), parent, maxHp (масштаб от размера тела), флаги (vital, solid, skinCovered), вклады в capacities { breathing: 0.5, consciousness: 1.0, moving: 0.25, … }. Пример (олень): body → torso → (heart, lungs×2, liver, stomach, kidneys×2, spine), head → (brain, eyes×2, ears×2, jaw), legs×4 → hooves.
  • HediffDefвсё есть hediff (рана, потеря части, болезнь, имплант, можно и беременность): stages с порогами по severity; стадия задаёт capMods (offset/factor/setMax по capacity), painOffset/painFactor, bleedRate, для болезней — параметры иммунитета.
  • CapacityDef — общий каталог способностей строковыми id: Consciousness, Moving, Manipulation, Sight, Hearing, Breathing, BloodPumping, BloodFiltration, Digestion, Metabolism (расширяемо модом). Это каталог, а не обязательный набор: вид имеет лишь те способности, в которые вкладываются части его BodyDef (у копытного оленя нет Manipulation — некому вкладываться).

Компонент

Health : IComponent { HealthState State } — managed-класс (как Genome): List<PartInstance> (деф + текущий hp), List<Hediff> (severity, привязка к части, иммунитет), кэш Capacities, Pain, BloodLevel, Dead.

Контейнер растёт по фазам: рождается в A4 с одним лишь List<Hediff> (под гон-хедиф Rut); части тела, кровь, capacities и Dead добавляются в A5, болезни/иммунитет — A6.

Расчёт capacities (обобщённая дата-модель)

Способности зависят друг от друга, считаем в порядке зависимостей:

  1. BloodLevel (0..1) ← запас минус кровопотеря;
  2. BloodPumping ← сердце × BloodLevel; Breathing ← лёгкие × BloodLevel; BloodFiltration ← печень/почки;
  3. Consciousness ← мозг × BloodPumping × Breathing × (1 − болевой штраф);
  4. Moving ← ноги/позвоночник × Consciousness × BloodPumping; Sight ← глаза × Consciousness; Digestion и пр. — домножаются на вышестоящие.

Формула одна и общая: capacity = Σ(вклады работающих частей × partHp/maxHp) × вышестоящие capacity. Без хардкода на каждую способность — новую способность вводит деф. Каждая capacity — множитель на действия: Moving→скорость, Sight→радиус поиска, Digestion→скорость насыщения, Consciousness→интеллект и сам факт сознания.

Кровь — как hediff (реалистичная модель RW)

Кровопотеря = hediff BloodLoss (severity 0..1). Кровоточащие раны поднимают её через bleedRate; без кровотечения медленно рассасывается; severity = 1 → смерть; влияет на BloodPumping/Consciousness через capMods. GeneBloodVolume масштабирует скорость роста severity (больше крови → медленнее теряет).

Болезни и иммунитет (гонка)

severity болезни растёт за день; параллельно растёт иммунитет (0..1) со скоростью из стата (зависит от BloodFiltration, отдыха, сытости, GeneImmunityGain). Иммунитет→1 раньше = выздоровел; severity→летальный порог раньше = смерть. Голодный/раненый зверь борется с болезнью медленнее.

Смерть

Триггеры: разрушена vital-часть (мозг/сердце), Consciousness ≤ порога, BloodLevel = 0, летальная severity болезни, старость (возрастные hediff: катаракта, больная спина, деменция, закупорка артерий + шанс смерти от старости). На смерти: стоп-ИИ, переход в труп.

Тик

Медленный «health tick» раз в игровой час + событийный пересчёт при уроне. Детерминизм: привязка к игровому времени, не к FPS.

Источники урона в v1

Почти никаких. Строим весь каркас (части, кровь, capacities, hediff-framework, условия смерти), но не вводим травмирующих источников. На старте (A1–A2) смерть только от старости.

Порядок источников урона по фазам: истощение/обезвоживание — уже в A3 (простое правило «нужда=0 дольше N дней → смерть», замыкает контур ёмкости среды; в A5 переоформляется в hediff истощения) → температура (гипотермия/тепловой удар, hediff на той же трапеции, что у растений) → болезни (A6) → хищничество (горизонт).

Труп и разложение

Труп — отдельная сущность с Corpse { RotDays; Stage }. Конвейер (скорость зависит от температуры/сезона — реюз климата):

Fresh ──→ Rotting ──→ Skeleton ──→ (исчезает)
  │          │            │
  │ разделка │ разделка    └─ остаётся ProductBone
  └──────────┴─→ ProductMeat (кол-во ∝ GeneBodySize) + опц. ProductLeather
  • свежий/гниющий можно разделать → мясо (объём от размера тела) + шкура; спрайт Dessicated_* (для оленя уже есть) на стадии Rotting;
  • скелет — финальная стадия разложения (как просили, скелет — часть процесса): мясо уже не получить, остаются кости (ProductBone);
  • после скелета труп исчезает в ничто. На будущее — возврат плодородия в почву (ниточка к растениям, опционально).
  • мясо/кости/падаль → кормовая база будущих хищников и падальщиков.

Новые продукты: ProductMeat, ProductBone, ProductLeather.

Спрайт скелета — нужен настоящий (решено). В проекте костяных/скелетных текстур нет (проверено) → это ассет-задача: создать/найти спрайт скелета (желательно универсальный + по-видовой при наличии), путь вида things/pawn/animal/deer/Skeleton_*. До появления ассета стадию Skeleton можно временно рисовать обработкой Dessicated_*, но финальная версия требует своего спрайта.

Мозг и интеллект

GeneBrainSize → признак brainSize. Эффективный интеллект = brainSize × Consciousness — т.е. повреждение/болезнь мозга, боль, кровопотеря динамически снижают интеллект (сильная связка со здоровьем).

Интеллект гейтит набор нужд и действий. У NeedDef/действия поле minBrain: активный набор особи = те, у кого minBrain ≤ brainSize. Без enum — шкала непрерывная, тиры ниже лишь ярлыки для авторов контента (числа порогов — контент, правятся модом). brainSize нормирован 0..1.

Тир minBrain Кто Что открывается
1 — рефлекс 0.00 губки, простейшие пассивный голод, реактивность
2 — примитив ~0.10 насекомые, черви голод; реактивное поведение
3 — низший позвоночный ~0.25 рыбы, рептилии, амфибии +жажда; простое избегание
4 — зверь ~0.45 млекопитающие, птицы (олень, заяц, волк) +сон, секс, Flee, SeekMate; настроение; факультативно стадность/память
5 — умный (на будущее) ~0.75 приматы, врановые, люди +социальные нужды, игра, любопытство, память о ресурсах, планирование, обучение, сложное настроение/отношения

Олень = тир 4. Настроение, сон и брачное поведение включаются с тира 4.

Настроение

Mood (0..1) собирается из двух источников (решено):

  1. Непрерывные состояния → в настроение напрямую по кривой ResponseCurve: уровни голода, жажды, усталости, боли (из здоровья), температуры вне комфорта. Это не дискретные мысли, а текущий вклад нужд/состояния.
  2. События → ThoughtDef { moodOffset, durationDays, trigger } (модель thoughts RimWorld, данными): «дала потомство», «спарилась», «напилась после долгой жажды», «потеряла детёныша» — временный сдвиг настроения с затуханием.

Настроение есть только с тира 4 (зверь) — гейт интеллектом; у примитивных его нет. Влияет на поведение (низкое → паника/бегство, не спаривается) и видно в инспекторе.

Ориентировочные числа для оленя (старт)

Шкала времени мира: год = 60 игровых дней, сезон = 15 дней (для справки растения живут ~160 дней). Числа — стартовая точка, балансируются при реализации; это значения по умолчанию генома вида (GenomeTemplate), вокруг которых идёт разброс и мутации.

Параметр Ген/поле Значение Заметка
Размер тела GeneMaxBodySize ♀ 1.4 / ♂ 1.6 sizeCells как в текущих DeerDoe/DeerBuck
Продолжительность жизни GeneLifespan ~360 дн (~6 лет) дольше растений, видно несколько поколений
Взросление (→Adult) GeneMaturityAge ~90 дн (~1.5 года) Baby 020, Juvenile 2090, Adult 90~290, Senior 290+
Срок беременности GeneGestationDays ~30 дн (2 сезона) гон осенью → роды весной
Помёт GeneLitterSize 1 (изредка 2) K-стратег
Сезон гона GeneBreedingSeason осень у зайца — круглый год
Размер мозга GeneBrainSize ~0.45 (тир 4) открывает сон/секс/настроение
Объём крови GeneBloodVolume ~1.0 (×размер) масштабирует скорость кровопотери
Скорость GeneMoveSpeed ~1.11.3 олень быстрый
Голод NeedDef decay полный голод за ~1.5 дн по Клайберу ∝ size^0.75
Жажда NeedDef decay полная жажда за ~0.75 дн быстрее голода
Сон NeedDef decay суточный цикл спит в неактивную фазу

Идеи для реализма (бэклог)

Опционально, по мере фаз — каждая ложится на дата-модель:

  • Гон/брачный сезон — хедиф Rut, навешиваемый в сезон, поднимает влечение (реализовано в A4).
  • Терморегуляция мехомGeneInsulation сдвигает температурную трапецию; новорождённые мёрзнут сильнее.
  • Метаболизм по Клайберу — расход ∝ size^0.75 (крупные едят больше абсолютно, меньше на кг).
  • Циркадные ритмы — дневные/ночные/сумеречные виды (GeneActivityPattern).
  • СтадностьGeneSociability: стадные держатся группой (реюз SeparationSystem
    • когезия) → эмерджентные стада.
  • Сезонный окрас — арктические лиса/заяц/волк белеют зимой (текстуры *_arctic есть) — сезонный свитч спрайта/тинта.
  • Половой диморфизм — рога/размер у самцов (ген, проявляется при XY).
  • r/K-стратегии — выводятся из litterSize/gestation/lifespan.
  • Инбридинг-депрессия (продвинутое) — родственное скрещивание снижает fitness через накопление рецессивных аллелей.
  • Память о ресурсах/территория (для умных) — водопои, кормовые места.
  • Возврат нутриентов — полное разложение трупа повышает плодородие клетки.

Новые типы дефов (для модеров)

Тип Назначение
AnimalDef : PawnDef (подтип) вид: геном-шаблон (ссылки на гены), BodyDef, диета, текстуры по стадиям/полу, размеры. Наследник PawnDef — существующие 9 животных-PawnDef остаются валидными; поведение на компонентах, не на типе дефа
BodyDef дерево частей тела с coverage/parent/maxHp/флагами/вкладами в capacities
HediffDef раны/болезни/состояния: стадии, capMods, боль, кровотечение, иммунитет
CapacityDef именованная способность (строковый id)
NeedDef нужда: формула расхода, minBrain, привязка к действию
ThoughtDef мысль настроения: offset, длительность, условие-триггер
ProductDef (есть) + ProductMeat, ProductBone, ProductLeather

CLR-классы — src/LittleSim/Content/GameDefs.cs; новый тип = класс + RegisterType в GameContent.Load (см. mods.md).

Отбор, экология и наблюдаемость

Смысл генетики — чтобы за поколениями популяция реально адаптировалась к климату сида (дрейф признаков под отбором). Чтобы это было видно (столп «наблюдаемость»):

  • Команда popstats <species> — среднее и разброс ключевых признаков популяции + счётчик поколений. Без неё отбор «есть, но невидим». Появляется, как только в мире есть популяция (≈A1–A2), расширяется по мере добавления признаков.
  • Контур ёмкости среды (Лотка–Вольтерра через корм). Даже без хищников травоядные могут выесть растения → голод → крах популяции → восстановление флоры → новый рост. Это бесплатная эмерджентность уже на A2, если поедание реально уменьшает растения. Явно проверяем этот контур на A2 (поедание убавляет плод/растение, голод растёт при нехватке корма). Важно: полный «крах» популяции требует смерти от голода — она появляется в A3 (простое правило). На A2 контур наблюдается частично (звери голодают и тормозят, но не вымирают), полностью замыкается с A3.

Сквозные требования (каждая фаза)

  • Детерминизм. Любая случайность (спавн, выбор партнёра, мутации, выбор части под урон, шанс инфекции) — из seeded Random, выведенного из сида мира (+ id сущности), никогда Random.Shared. Один сид = воспроизводимый мир. Ничьи в пространственных запросах («ближайший корм/вода/партнёр») разрешаются по id сущности, не по порядку обхода.
  • Сериализация — чек-лист по каждой фазе. Каждая фаза сразу делает сейв/лоад своих данных: A1 геном (уже умеет, geneId→Allele) → A3 стадия/возраст/пол → A4 беременность (срок + геном отца) + список хедифов (гон Rut) → A5 здоровье (части тела, кровь, capacities) + труп (стадия/таймер разложения) → A8 настроение/мысли. Пустой/старый сейв — регенерируется, не крашит.
  • Sim/presentation split. Системы симуляции пишут только компоненты; спрайт/тинт (пол, стадия, мех, гниль) ставит AppearanceSystem. Никаких draw/UI из симуляции.

План реализации (фазы A1–A8)

По аналогии с фазами генов G1–G5. Каждая фаза — отдельный коммит, дев-команда для проверки, проверка через --check-content (где можно), и пункты сквозных требований выше. Вкладки инспектора добавляются по мере появления данных: needs@A2, health@A5, mood@A8.

  1. A1 — фундамент. AnimalDef + животные гены + AnimalPhenotype/AnimalOrganism
    • per-species GenomeTemplate + спавн оленя в WorldScene + рендер + команда animal <species>.
  2. A2 — нужды + ИИ (выбор + исполнение). AnimalNeeds + AnimalDecisionSystem (выбор) + слой исполнения (Eat/Drink/Sleep: найти→дойти→выполнить→удовлетворить) + еда-растения / вода-террейн / сон по фазе суток + AppearanceSystem. Проверить контур ёмкости среды (поедание убавляет растения → колебания). Команда popstats.
  3. A3 — жизненный цикл. Стадии Baby→Adult→Senior, ген пола (XX/XY, генерация без YY), спрайт по стадии/полу, простая смерть по старости и от голода/жажды (деспавн) — последняя замыкает контур ёмкости среды.
  4. A4 — размножение. Нужда Mating + лёгкий hediff-каркас + гон-хедиф Rut (сезон) + исполнение MatePregnant → роды через Genome.Breed.
  5. A5 — здоровье I. BodyDef, части тела, кровь (hediff), capacities, апгрейд смерти: через здоровье + труп с разложением до скелета (вместо деспавна A3).
  6. A6 — здоровье II. Болезни/HediffDef с иммунитетом, боль.
  7. A7 — мозг/интеллект. Ген→интеллект→гейт нужд/действий + обратная связь от повреждения мозга.
  8. A8 — настроение. Mood + ThoughtDef + вкладки инспектора (needs/health/mood — InspectPanel уже умеет вкладки overview/genes/products).

После A8 — экологический горизонт

То, ради чего вся глубина: превращает «зоопарк» в живую экосистему. Каждая фича опирается на уже построенные системы.

  • Хищный кластер. Хищничество (волк→олень): диета = живая добыча; действие Hunt (выследить → преследовать → атака → урон через здоровье A5 → добить → съесть труп). Это первый «активный» (травмирующий) источник урона для системы здоровья и полноценная Лотка–Вольтерра с хищником. Рядом: падальщики (едят трупы Fresh/Rotting) и угроза/бегство (хищник в радиусе Sight → страх → действие Flee, удар по настроению; стадо снижает страх).
  • Родительская опека / импринтинг. Детёныш ходит за матерью, голод гасится близостью к лактирующей матери до ювенильной стадии; мать ведёт/защищает. Реализм + детёныши не мрут от голода в одиночку.
  • Эпидемии. Болезни (A6) распространяются по контакту/плотности → плотностно-зависимый регулятор популяции (вспышки-крахи). Исход решает иммунитет (GeneImmunityGain).
  • Миграция. При локальном истощении корма / некомфортном климате — уход к лучшим клеткам (концепт: «голод+неурожай→миграция»). Эмерджентно из нужд + пространственного поиска с большим радиусом.

Сюда же тяготеют пункты бэклога: половой отбор (выбор партнёра), сезонный окрас, инбридинг-депрессия, возврат нутриентов в почву.

Открытые вопросы

  • Конкретный список ThoughtDef-событий для оленя (набор и величины offset/длительности) — детализируется при реализации A8.
  • Ассет: создать/найти спрайт скелета (things/pawn/animal/deer/Skeleton_*) к фазе A5.