Predator/prey detection now uses three senses instead of one radius. Per observer,
SenseRanges = sight (vision gene x Sight capacity), hearing (x1.4, Hearing gene/cap),
smell (x1.8, Smell gene/cap). Detect(): sight beats the target''s camouflage and
hearing scales with its noise (both give exact position); smell reaches furthest but
only a COARSE zone -- the position snaps to a smell cell, so a predator tracking by
scent heads roughly toward prey until sight takes over. Damaged eyes/ears/nose or
hediff capMods shrink the matching sense; detectability genes (camouflage/scent/noise)
ride in the animal grid entry. Deterministic (snap, not noise). Mate/forage stay on
sight for now. Build + --check-content clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Foundation for the perception system. Adds Smell and Touch capacities (CapacityCalc
dependency chain x consciousness) with organs on the Quadruped body (nose->Smell,
skin->Touch; eyes/ears already give Sight/Hearing) so hediffs and organ damage
reduce them for free. New genes: acuity GeneHearing/GeneSmell/GeneTouch (radius
multipliers, default 1 if a species omits them) and detectability GeneCamouflage
(lower sight), GeneScent (raise smell), GeneNoise (raise hearing) on AnimalPhenotype.
Deer/wolf/boar/chicken get sensible values (wolf smells well, deer is alert +
dappled). cap.smell/cap.touch localized. Build + --check-content clean
(48 genes, 47 traits). Multi-sense detection + memory come next.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
AnimalBobSystem tilts a moving animal side-to-side via Transform2D.Rotation (a
gentle waddle) and eases it upright when standing. Phase runs on game time (frozen
on pause, faster when sped up) and is offset per entity id so animals sway out of
sync. Purely presentational -- the simulation ignores rotation, and the facing
system writes scale (not rotation), so no conflict. Corpses/eggs have no brain so
they stay still. Build + --check-content clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Dropped the Mountain terrain def and extended Forest to maxHeight 1.01, so the
former mountain elevations generate forest instead. No terrain blocks light now;
the occluder mechanism stays generic (mature trees still cast shadows) -- updated
the stale "mountain" comments. Removed the unused terrain.mountain localization.
Build + --check-content clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Animals had a single east-facing sprite and never turned. AnimalSet now loads a
directional set per look (female/male/baby): east from the def texture, north/south
by the _east->_north/_south naming convention (falls back to east if absent), with
west rendered as a horizontal flip of east. New AnimalFacingSystem orients each
animal toward its brain Target (dominant axis of travel), updating sprite region +
flip and recomputing origin/scale when the region changes; a standing animal keeps
its facing. ModAtlases gained TryGetRegion for the optional directional lookups.
Build + --check-content clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
World generation (WorldScene.OnLoad: terrain, atlases, spawn) runs synchronously
and blocks the frame; previously only a blank fade covered it, with no feedback.
New WorldLoadingScene shows a "Generating world" label, lets it draw, then switches
to WorldScene WITHOUT a transition so its last drawn frame (the label) stays on
screen during the blocking generation. Both New World and Load Game route through
it. Localized loading.world ru/en. Build + --check-content clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Generalized the plant grid into SpatialGrid<T> (PlantGrid.cs -> SpatialGrid.cs)
and added an animal grid. AnimalDecisionSystem rebuilds both once per frame; the
animal grid entry precomputes the fields the AI needs (species, body size, eats-meat,
sex, adult) so queries do not refetch components. Threat / prey / mate / herd scans
now gather only neighbours from cells overlapping the vision radius instead of
iterating every animal per decision. IsThreatTo/IsPreyFor take precomputed values;
dead MateNeedIndex removed. Mate stays species-agnostic (unchanged behaviour).
Added id tie-breaks to threat/mate selection so results are order-invariant ->
fully deterministic regardless of grid iteration order. Build + check clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Plants vastly outnumber animals, and every herbivore forage decision scanned ALL
plants — the dominant per-decision cost. New PlantGrid (uniform cell grid, cell
lists pooled so rebuild is alloc-free) is rebuilt once per frame from plant
positions; TryFindPlant/TryFindBestPlant now gather only candidates from cells
overlapping the vision radius instead of iterating every plant. The entry carries
position/id/toxicity/palatability so no component refetch is needed. Selection is
unchanged (nearest / max-attractiveness, id tie-break), and since the result is
order-invariant the behaviour is identical and deterministic. Build + check clean.
Note: the animal-side neighbour scans (threat/prey/mate/herd) are still O(animals)
per decision — animals are far fewer than plants, and an animal grid is a riskier
change best done with a GUI run; deferred.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- AnimalNeedsSystem (per-frame, every animal): drop the string-keyed genome lookup
and Mass.OfAnimal call; Kleiber factor is now (size/refBody)^2.25 using a
precomputed AnimalSet.Species.RefBodySize. No dict probe per animal per frame.
- AnimalActionSystem: fetch the Skills component ONCE per acting animal instead of
twice per action (SkillFactor + GrantXp took in Skills now).
- RecomputeCapacities: apply the senescence scale inside CapacityCalc.Compute
instead of a second pass that allocated a List<string> of keys every recompute
(per animal per health tick, and per injury in combat).
- AnimalFactory.SkillSeed: iterate genome.Alleles (IReadOnlyDictionary, no copy)
instead of ToDictionary() which allocated a dict per spawn.
Behaviour-preserving (same numbers). Build + --check-content clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A side panel (F9, only when developer mode is on) lists entries by category:
animals and plants are auto-populated from their defs (so modded content shows up
automatically), plus action tools. Spawn entries arm a "tool in hand" — left-click
the world to spawn at the cursor (right-click clears); action tools (injure/kill/
infect) apply to the currently selected creature, so you can line up entities and
damage them to compare. Moddable via a new DevToolDef def type: mods add buttons
referencing a code handler kind (spawn-animal/plant/infect/damage/kill) + target,
without touching code. Localized dev.* ru/en. Build + --check-content clean
(13 def types).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Generic data-driven skills (SkillDef + skills.json: Foraging, Hunting, Evasion),
mirroring the needs registry. Skills component (per-skill level [0..1] + passion)
on every animal, built by AnimalFactory; passion is rolled deterministically from
the genome (no RNG param threaded). Levels grow from PRACTICE (XP on the matching
action, scaled by passion''s learn-rate) and slowly decay toward a floor when
unused (AnimalSkillSystem), so animals specialize.
Effects wired now: Foraging -> satiety from grazing, Hunting -> attack damage,
Evasion -> flee speed. A missing skill def -> factor 1 (no effect), so it is safe
to mod the set. Inspector gains a Skills tab (level% + passion stars); `skills`
console command shows live mean levels; skills are saved/loaded (levels+passions).
Same model will carry to future humans. Build + --check-content clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GameSettings.DeveloperMode (default ON) + a toggle in the settings panel. WorldScene
only stands up the dev console (and, later, the dev spawner) when it is enabled, so
without dev mode the backtick key does nothing. GodCameraSystem''s console arg is now
nullable (no console when dev mode off). Localized settings.devmode ru/en. Build clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mass is derived by a cubic law: mass = BaseMassKg * (size / reference)^3, so a
juvenile/seedling weighs far less than an adult/mature and the size gene moves
mass too. New Mass helper + BaseMassKg on AnimalDef/PlantDef (deer 70, wolf 45,
boar 80, chicken 2.5; trees ~450, grass 0.4, etc.) and MassKg per unit on
ProductDef (foundation for hauling/inventory).
Wired into the sim (as chosen):
- Corpse meat is now proportional to body mass (Mass.MeatFraction), not raw
bodySize; Corpse gained a BodySize field so sprite scale stays independent of
meat (save/load updated).
- Kleiber metabolism: need decay x= (mass/refMass)^0.75, normalized per species,
so juveniles are cheaper to feed and heavier individuals eat a bit more,
without cross-species balance blowups (adults of typical size are unchanged).
- Carry capacity = mass x fraction x carry capability (Moving for quadrupeds;
Manipulation for future humans), shown in inspector/console. A dormant Carrier
component + Mass.LoadSpeedFactor hook slow an overloaded animal — the
foundation for item hauling.
Inspector shows body/plant weight (+carry); `animal`/`plant` console print mass.
Build + --check-content clean (42 genes, 41 traits). Not GUI-verified.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Social species (deer 0.8, wolf 0.6, chicken 0.55, boar 0.3) now school together:
AnimalDecisionSystem scans nearby same-species neighbours (HerdScan) and, when
wandering, a lone social animal steers toward the herd centroid (cohesion) while
close members just mill about (separation). "Safety in numbers" shrinks the
threat-detection radius in a group, so herded prey are calmer and scatter less.
Asocial animals (sociability < 0.3) keep the old random wander. GeneSociability
+ trait; `animal` console prints insulation/sociability. Build + --check-content
clean (42 genes, 41 traits). Not GUI-verified.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Eating a mature plant has a chance to lodge a seed in the herbivore's gut
(GutSeed component, cloned plant genome). SeedDispersalSystem ticks the timer and
plants a seedling of that species wherever the animal has wandered to (if the
cell is land), then drops the component. Herbivores become agents of plant
spread — flora follows grazing routes — closing a plant<->animal loop on top of
the existing Fruiting/PlantFactory machinery. GutSeed is transient (not
serialized), like AI targets. Build clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
GeneEggLaying (species-fixed) selects the conception cycle: viviparous animals
carry to a live birth (existing path); oviparous animals, after the same gravid
period, LAY eggs instead. New Egg entity (carries the already-bred offspring
genome) + EggSystem incubates and hatches it into a baby. AnimalPregnancySystem
branches on the mother's birth type. Adds an oviparous showcase species, Chicken.
Eggs are serialized (WorldSave.Eggs) like corpses, so clutches survive save/load.
Also lays the foundation for creating any species or hybrid (full command/UI
deferred): AnimalSet.HybridGenome(base, other) produces a cross anchored to a
base species' body/gene-set with shared genes blended Mendelian-style — so
Create(species, GenerateGenome) makes any species and Create(species,
HybridGenome) makes any hybrid.
EggTexture on AnimalDef (defaults to the seed dot placeholder); reproduction line
added to the `animal` console command. Build + --check-content clean (41 genes,
40 traits). Not GUI-verified.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GeneLifespan already set the moment of death from old age; now aging actually
manifests before it. RecomputeCapacities takes a capacityScale; AnimalHealthSystem
applies SenescenceFactor(age, lifespan) — capacities fade from 60% of lifespan to
~0.55× near the end, so old animals move/see/filter blood worse and are frailer.
Fertility falls with the same factor (smaller litters), and past 90% of lifespan
females no longer conceive (post-reproductive). Makes GeneLifespan and the Senior
stage meaningful. Build clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Eating (jaw) scales graze bite and Digestion×Eating scales satiety gained from
food (plant grazing and corpse scavenging via Refill efficiency). A damaged jaw
or sick gut means less nutrition per feeding, so the animal must eat more often.
Completes wiring the new health capacities to behaviour; Talking remains an
indicator (no social system yet). Build clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The expanded capacities were mostly display-only; make two of them affect the
simulation (Moving→speed and Consciousness→intelligence gating already existed):
- Blood filtration → toxin/disease clearance: AdvanceHediffs takes an immunity
scale (default 1); AnimalHealthSystem passes the BloodFiltration capacity, so
damaged kidneys/liver clear Poisoned and diseases slower (RimWorld model).
Ties the new capacities to the coevolution work — weak filtration makes toxic
plants deadlier.
- Sight/hearing → perception radius: foraging, hunting and mate search scale by
Sight; threat detection (flee) scales by max(Sight, Hearing) — you see or hear
a predator. Injured eyes/ears shrink awareness.
Eating/Talking/Digestion remain indicators for now. Build + --check-content
clean. Not GUI-verified.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds the first plant↔animal coupling beyond "herbivore eats plant": a toxin/
thorns ↔ tolerance arms race built on the existing gene + hediff engines, plus
the fuller RimWorld capacity set on the health scaffold.
Coevolution C1 — plant defense → poisons/injures the eater:
- Plant genes GeneToxicity/GeneThorns/GenePalatability (GenomeDef + PlantSet
template + PlantPhenotype); animal gene GeneToxinTolerance.
- Hediff Poisoned (non-progressing; grows from eating via HealthState.Intensify,
immunity heals it, overdose is lethal).
- AnimalActionSystem.ApplyPlantDefense on each bite: poison dose =
toxicity × (1 − tolerance); thorns → ApplyInjury (reuses predator-cluster).
- Cost of defense: PlantGrowthSystem growth ×= DefenseGrowthFactor()
(1 − 0.4·toxicity − 0.3·thorns) — without a cost defense would max out and
coevolution would stall.
- Showcase: cactus thorns, poisonous mushroom; grass starts clean so toxicity
can evolve on the staple. Deer/boar get small starting tolerance.
Coevolution C2 — discrimination + the other half of the arms race:
- Smart foraging (reuses A7 intelligence gating): herbivores with effective
intelligence ≥ tier-4 weigh plants by palatability − perceived-toxin −
distance; reflex grazers (or sick animals with dropped consciousness) eat the
nearest plant and risk poison.
- Cost of tolerance: detox raises metabolism (need decay ×= 1 + 0.5·tolerance),
closing the arms race so tolerance doesn't fix at 1.
- popstats reports mean toxinTolerance and a plants line (mean toxicity/thorns/
palatability) to watch the drift.
Health capacities (RimWorld parity, user-requested):
- New capacities BloodFiltration/Hearing/Talking/Eating; CapacityCalc rewritten
to emit only capacities the body declares (a destroyed organ still shows 0%)
with the full dependency chain (blood → pumping/breathing/filtration →
consciousness → moving/sight/hearing/talking/eating, digestion).
- Quadruped body gains kidneys + liver (filtration), ears (hearing), jaw/tongue
(eating/talking). Inspector health tab lists all of a body's capacities.
Localization (ru/en) for new genes' defense line, Poisoned, and the new
capacity labels. Build + --check-content clean (11 def types, 40 genes,
39 traits). Not GUI-verified (headless can't render the world scene).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Brings the full animal foundation onto main and folds its new defs into the
Defs/ subfolder layout introduced on main:
- animal genes -> Defs/Genes/Animal.json (split out of genes.json)
- animals/bodies/hediffs/needs/thoughts -> own Defs/<Type>/ subfolders
- ProductMeat/Bone/Leather + bigger world presets auto-merged via rename detection
- PawnDef un-sealed (AnimalDef : PawnDef); def-location doc comments updated to subfolders
- engine pointer kept at main's newer 96e19c7 (only adds directional sun shadows)
Build + --check-content clean: 11 def types, 33 genes, 35 plants, 32 traits.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Закрывает сквозное требование плана (сейв/лоад данных каждой фазы). 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>
Эффективный интеллект = brainSize (ген) × Consciousness (capacity из здоровья), AnimalFactory.Intelligence. AnimalContext гейтит выбор ИИ: нужда с minBrain выше интеллекта особи в выбор не входит (AnimalDecisionSystem читает Health поэлементно). Пороги в needs.json — тиры мозга (голод 0.0, жажда 0.25, сон/секс 0.40; у оленя мозг ~0.45). Обратная связь от повреждения мозга: болезнь/боль/кровопотеря роняют сознание → интеллект падает → первыми отключаются сон/спаривание. Команда intel <species> [consciousness]. Сборка + --check-content чистые.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>
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>
Компонент Corpse + CorpseSystem: после смерти животное оставляет труп (AnimalFactory.CreateCorpse, мясо ∝ размер тела) вместо деспавна; труп разлагается Fresh→Rotting→Skeleton→исчезает со скоростью от температуры, тинтуясь по стадии. AnimalDef.CorpseTexture + спрайт трупа в AnimalSet; смертность спавнит труп. Продукты мясо/кости/шкура заданы (разделка/падальщики — позже).
Сборка чистая, --check-content (9 типов дефов). Части тела/кровь/capacities — часть 2 A5.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Завершает вынос баланса в данные: AnimalDecisionSystem.VisionRadius берёт дальность из AnimalDef.VisionCells (× ген), TryFindPlant/TryFindMate принимают готовый радиус; AnimalActionSystem берёт BaseSpeed и ForageBiteDays из дефа вида (через AnimalSet). Убраны хардкод-константы скорости/зрения/выедания.
Сборка чистая, --check-content (9 типов дефов).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Стадии стали данными: AnimalStageDef + AnimalDef.Stages (возраст входа = EnterAt x якорь maturity/lifespan, масштаб, набор текстур baby/adult, флаг adult для размножения); пусто -> встроенный дефолт Baby/Juvenile/Adult/Senior. AnimalFactory.StageAt/RegionFor/Scale/IsAdult работают по данным стадий; системы роста/решения/гона используют флаг adult вместо индекса. Спавн стал данными: AnimalDef.SpawnPer1000Cells — WorldScene рассыпает ВСЕ виды по плотности, не только захардкоженного оленя. Устраняет блокеры расширяемости #5 и #7.
Сборка чистая, --check-content (9 типов дефов).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Нужды стали данными: NeedDef + needs.json (Hunger/Thirst/Rest/Mating), NeedSet (реестр: индексы, тип deplete/drive, поведение-исполнитель по id), динамический AnimalNeeds.Values (managed-массив — новая нужда не меняет структуру). AnimalNeedsSystem универсально считает убывание/рост по NeedDef; UtilityAi строится из NeedSet; действия исполняются по строковому id (реестр поведений) с восполнением нужды через NeedSet. Диета — AnimalDef.Diet (поиск корма гейтится). Добавить нужду/рацион виду = JSON без кода. Устраняет блокеры расширяемости #2 и #4.
Сборка чистая, --check-content (9 типов дефов).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
AnimalGenomeDef (фикс. поля) убран; AnimalDef.Genome теперь словарь geneId->base. AnimalSet.BuildTemplate строит шаблон generically по реестру генов (разброс из самого GeneDef, дискретные поддержаны). Модер добавляет ген особи одной строкой JSON в animals.json — без правки кода. Устраняет блокер расширяемости #1.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Нужда Mating + лёгкий hediff-каркас (HediffDef, hediffs.json с Rut, Health/HealthState). Гены GeneBreedingSeason/GeneGestationDays/GeneLitterSize. AnimalRutSystem навешивает сезонный гон-хедиф взрослым и поднимает влечение (вне сезона зачатия нет). Действие Mate ищет партнёра противоположного пола и сближается; при контакте самка получает Pregnant (геном отца). AnimalPregnancySystem тикает срок и рожает помёт через Genome.Breed (пол наследуется без YY, поколение+1), с потолком численности.
Сборка чистая, --check-content (8 типов дефов, 33 гена, 32 признака).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Компонент AnimalGrowth (стадия + возраст). Ген пола GeneSex (локус XX/XY; генерация основателя задаёт пол явно через AnimalSet.GenerateGenome, исключая невозможный YY) и GeneMaturityAge. Стадии Baby->Juvenile->Adult->Senior с порогами из генов. AnimalGrowthSystem меняет спрайт (детёныш/самец/самка) и размер по стадии; AnimalMortalitySystem — смерть от старости и истощения (деспавн), замыкает контур ёмкости среды. Стадо спавнится разновозрастным.
Сборка чистая, --check-content (30 генов, 29 признаков).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
AnimalNeeds (голод/жажда/отдых) падают по гену метаболизма. Два слоя ИИ: AnimalDecisionSystem (движковый UtilityAi выбирает действие и ищет ближайшую еду/воду) и AnimalActionSystem (движение к цели со скоростью по гену + утоление: выедание растений с гибелью выеденной травы, питьё у кромки воды, сон). AnimalAppearanceSystem тускнеет с острой нуждой. Кромка воды считается из террейна; команда popstats для наблюдаемости дрейфа генов.
Сборка чистая. Контур ёмкости среды частичный — смерть от голода придёт в A3.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Новый тип дефа Animal (AnimalDef : PawnDef) + animals.json (Deer). 8 организм-агностичных животных генов в genes.json. AnimalPhenotype/AnimalOrganism, AnimalSet (шаблон генома вида) и AnimalFactory — зеркала растительных PlantSet/PlantFactory. Детерминированный спавн стада оленей по суше в WorldScene с рендером и тинтом меха по гену; консольная команда 'animal <species>'.
Проверено: сборка чистая, --check-content (7 типов дефов, 28 генов).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Main independently adopted the engine Core/Host split in G1, so the
scene adaptations conflicted with identical changes here — resolved in
main's favor (its scenes also carry the gene-driven world). Kept from
this branch: BootScene's --connect path into MultiplayerScene, the
buildAtlases switch in GameContent.Load (with the Task.Run lambda fix
its optional parameter requires), net.* localization keys, and the
Net/Server/Web projects in the solution. Program.cs now has both CLI
modes: --check-content (main) and --connect (here). The engine pointer
lands on d044caf, which linearly contains both lines of work.
Verified on the merged tree: 366 engine tests pass, --check-content
reports genes/traits intact, and a live --listen server replicates
moving pawns to the probe.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Engine pointer -> d044caf (formula gene grouping, content patches, def
field validation). Game-side demonstration of all three:
- genes.json: GeneHardiness whose effect is gsum('Gene.*Tolerance') — a
derived trait summing all tolerance genes via regex grouping.
- patches.json: a content patch giving every Bush* plant a wood harvest
product, applied to Core's own defs at load.
- GameContent registers load-time validators: Gene/Product defNames must
carry their type prefix.
- Program: a --check-content headless mode that loads all mod defs (running
patches + validators) and computes a sample genome's traits (compiling
every gene formula, grouping included) — a CI-friendly content lint.
Verified: --check-content reports 6 def types, 18 genes, 8 plants, 18
traits with hardiness computed from the gene group. Full suite green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New plant content, all driven by genes through the trait layer (no engine
change — the genetics machinery already supports it).
- ProductDef + products.json (wood, grass, berries, acorn) — what plants
yield; localized labels (ru/en).
- New numeric genes (genes.json): GeneFruitYield, GeneFruitSeason,
GeneHarvestAmount, GeneLeafHue, each declaring its trait via formula.
GenomeDef carries the per-species bases (PlantSet maps them into the
species template); PlantDef gains harvestProduct / fruitProduct.
- PlantPhenotype gains FruitYield/FruitSeason/HarvestAmount/LeafHue.
PlantFactory tints the sprite from the leaf-hue gene (combined with the
morph variant). Plants carry a Fruiting component; PlantFruitingSystem
ripens fruit on mature plants during their gene-chosen season and drops
it off-season.
- plants.json: trees give wood + acorns (autumn), bushes berries (summer),
grass gives grass — amounts/season/hue from genes.
- 'plant <species> [seed]' console command samples a species genome and
prints its gene-driven traits and products.
Build clean; def JSON validated; boot smoke loads the new content.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
LittleSim.Web (Blazor WASM + KNI/WebGL) is a real network client now: it
connects to the dedicated server over WebSocket (ClientWebSocket maps to
the browser socket), applies MrGameEng.Net delta snapshots into its
EntityStore and draws pawns through SpriteBatch — fatigue dims them just
like on desktop. The server address comes from ?server=ws://host:port
in the page URL, defaulting to the page's host on port 9050. The net
contract is mirrored in NetContract.cs (KNI and DesktopGL assemblies
can't mix until the graphics libraries build per platform) with loud
keep-in-sync comments on both sides.
Both clients now smooth replicated positions between 10 Hz snapshots:
NetLerp + NetSmoothingSystem lerp the visual position toward the latest
server position every frame (exponential, ~0.25 s to converge).
Verified against a live LittleSim.Server --listen: the browser client
connects (server log), draws ~3.3k lit pixels of pawns whose layout
changes between samples, and survives 400+ ticks without errors. Found
along the way: requestAnimationFrame freezes in hidden windows — the
game loop only runs while the tab is visible.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Plants now carry a managed Genome and read formula-computed traits
instead of the hardcoded PlantGenome struct. Engine pointer -> ead2251
(GenomeTemplate + Breed mutationChance override).
- PlantOrganism { Genome; PlantPhenotype Traits } replaces PlantGenome.
Traits (optima/tolerances, vigor, lifespan, dispersal, reproduce
interval, self-pollination, mutation rate, morph variant) come from
Phenotype.Compute over the gene effect formulas in genes.json.
- PlantSet builds a per-species GenomeTemplate by mapping each species'
existing plants.json genome numbers onto the shared GeneDefs, and
exposes the gene registry. Species values unchanged — only reinterpreted
through genes now.
- Growth and lifecycle systems read PlantOrganism.Traits; breeding goes
through Genome.Breed with the registry and a mutation chance averaged
from the parents' evolvable mutationRate trait. Scatter generates from
the species template.
- Save stores the genome as a geneId->Allele map; load rebuilds it
(empty/legacy saves regenerate from the template — dev saves disposable).
Behaviour matches phases A-D, now fully data-driven through genes and
formulas. Full suite green; boot smoke test loads genes + plants cleanly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Engine bump brings MrGameEng.Net (WebSocket transport, RFC 6455 server,
delta component replication) — this commit is its showcase.
LittleSim.Server --listen runs the world online: 24 pawns wander, tire
and rest on the engine's fixed-tick HeadlessHost (the same Wander/
Needs/Decision systems the windowed world uses), a WebSocketServer
accepts clients and a ReplicationServer ships Transform2D + PawnNeeds
deltas at 10 snapshots/s per the shared NetSchema. --probe is the CLI
check: it connects, listens for a second and prints replicated pawns
with positions sampled twice to show the world is alive.
The game gains MultiplayerScene (dotnet run --project src/LittleSim --
--connect [ws://host:port]): simulation stays on the server, the client
applies snapshots into its scene store, decorates spawned entities with
sprites and reuses PawnAppearanceSystem so replicated fatigue darkens
pawns locally. HUD strings go through ru/en localization; the `net`
console command reports connection state and entity count. Esc returns
to the main menu.
Verified end to end: probe sees 24 pawns moving between samples; the
windowed client connects and runs against a live local server.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>