diff --git a/Mods/Core/Defs/animals.json b/Mods/Core/Defs/animals.json index b7edc6d..695e406 100644 --- a/Mods/Core/Defs/animals.json +++ b/Mods/Core/Defs/animals.json @@ -12,20 +12,19 @@ "maleTexture": "things/pawn/animal/deer/DeerMale_east", "babyTexture": "things/pawn/animal/deer/DeerBaby_east", "genome": { - "bodySize": 1.5, - "metabolism": 1.0, - "moveSpeed": 1.2, - "bloodVolume": 1.4, - "vision": 1.3, - "brainSize": 0.45, - "insulation": 0.55, - "furColor": 0.45, - "maturityAge": 90, - "lifespan": 360, - "breedingSeason": 2, - "gestationDays": 30, - "litterSize": 1, - "spread": 0.08 + "GeneMaxBodySize": 1.5, + "GeneMetabolism": 1.0, + "GeneMoveSpeed": 1.2, + "GeneBloodVolume": 1.4, + "GeneVision": 1.3, + "GeneBrainSize": 0.45, + "GeneInsulation": 0.55, + "GeneFurColor": 0.45, + "GeneMaturityAge": 90, + "GeneLifespan": 360, + "GeneBreedingSeason": 2, + "GeneGestationDays": 30, + "GeneLitterSize": 1 } } ] diff --git a/Mods/Core/Defs/genes.json b/Mods/Core/Defs/genes.json index c0a8f2f..e5bd7d5 100644 --- a/Mods/Core/Defs/genes.json +++ b/Mods/Core/Defs/genes.json @@ -91,7 +91,7 @@ "default": 1.0, "min": 0.2, "max": 3.0, "tags": ["animal", "senses"], "effects": { "vision": "value" } }, { "defName": "GeneBrainSize", "parent": "BaseNumericGene", "label": "gene.brainSize", - "default": 0.45, "min": 0.0, "max": 1.0, "tags": ["animal", "brain"], + "default": 0.45, "min": 0.0, "max": 1.0, "spread": 0.03, "tags": ["animal", "brain"], "effects": { "brainSize": "value" } }, { "defName": "GeneInsulation", "parent": "BaseNumericGene", "label": "gene.insulation", "default": 0.5, "min": 0.0, "max": 1.0, "tags": ["animal", "temperature"], diff --git a/src/LittleSim/Content/AnimalSet.cs b/src/LittleSim/Content/AnimalSet.cs index f028eeb..569f6f1 100644 --- a/src/LittleSim/Content/AnimalSet.cs +++ b/src/LittleSim/Content/AnimalSet.cs @@ -88,39 +88,28 @@ public sealed class AnimalSet return genome; } - // Переводит базовый геном вида (числа из animals.json) в набор генов: каждое число — центр - // аллелей соответствующего общего GeneDef. Зеркало PlantSet.BuildTemplate. + // Строит шаблон генома вида из ДАННЫХ (geneId→base из animals.json) generically: разброс берётся из + // самого гена. Состав открыт — модер добавляет ген строкой JSON, без правки кода. Дискретные гены + // (база/разброс не нужны — варианты из GeneDef) тоже поддержаны. private static GenomeTemplate BuildTemplate( - AnimalGenomeDef g, + IReadOnlyDictionary genome, IReadOnlyDictionary genes ) { - GeneDef Gene(string id) => - genes.TryGetValue(id, out var def) - ? def - : throw new KeyNotFoundException( - $"Gene def '{id}' not found — is Mods/Core/Defs/genes.json loaded?" + var entries = new List(genome.Count); + foreach (var (geneId, baseValue) in genome) + { + if (!genes.TryGetValue(geneId, out var gene)) + { + throw new KeyNotFoundException( + $"Animal genome references unknown gene '{geneId}' — check genes.json." ); + } - GenomeTemplate.Entry Numeric(string id, float baseValue) => - new(Gene(id), baseValue, g.Spread); + var spread = gene.Kind == GeneKind.Discrete ? 0f : gene.Spread; + entries.Add(new GenomeTemplate.Entry(gene, baseValue, spread)); + } - return new GenomeTemplate( - [ - Numeric("GeneMaxBodySize", g.BodySize), - Numeric("GeneMetabolism", g.Metabolism), - Numeric("GeneMoveSpeed", g.MoveSpeed), - Numeric("GeneBloodVolume", g.BloodVolume), - Numeric("GeneVision", g.Vision), - new GenomeTemplate.Entry(Gene("GeneBrainSize"), g.BrainSize, 0.03f), - Numeric("GeneInsulation", g.Insulation), - new GenomeTemplate.Entry(Gene("GeneFurColor"), g.FurColor, 0.06f), - Numeric("GeneMaturityAge", g.MaturityAge), - Numeric("GeneLifespan", g.Lifespan), - new GenomeTemplate.Entry(Gene("GeneBreedingSeason"), g.BreedingSeason, 0f), - Numeric("GeneGestationDays", g.GestationDays), - Numeric("GeneLitterSize", g.LitterSize), - ] - ); + return new GenomeTemplate(entries); } } diff --git a/src/LittleSim/Content/GameDefs.cs b/src/LittleSim/Content/GameDefs.cs index a7340c7..51062f6 100644 --- a/src/LittleSim/Content/GameDefs.cs +++ b/src/LittleSim/Content/GameDefs.cs @@ -210,60 +210,9 @@ public class PawnDef : Def } /// -/// Базовый геном вида-животного (вложенный объект ): центры аллелей -/// животных генов (см. genes.json). Особь при спавне получает аллели рядом с этими базами -/// (разброс — ), а фенотип считается формулами генов над аллелями. Зеркало -/// растительного , только для зверя. -/// -public sealed class AnimalGenomeDef -{ - /// Размер тела в клетках — масштаб спрайта и (позже) HP/расхода энергии. - public float BodySize { get; init; } = 1f; - - /// Скорость обмена веществ — множитель расхода нужд (голод/жажда). - public float Metabolism { get; init; } = 1f; - - /// Скорость передвижения (множитель). - public float MoveSpeed { get; init; } = 1f; - - /// Объём крови (множитель) — масштаб скорости кровопотери в системе здоровья. - public float BloodVolume { get; init; } = 1f; - - /// Дальность зрения (множитель радиуса поиска корма/воды/партнёра). - public float Vision { get; init; } = 1f; - - /// Размер мозга (0..1) — основа интеллекта (гейт нужд/действий). - public float BrainSize { get; init; } = 0.45f; - - /// Теплоизоляция мехом (0..1) — терморегуляция. - public float Insulation { get; init; } = 0.5f; - - /// Оттенок меха (0..1) — сдвиг тинта спрайта (как leafHue у растений). - public float FurColor { get; init; } = 0.5f; - - /// Возраст полового созревания (игровых дней) — порог стадии Adult. - public float MaturityAge { get; init; } = 90f; - - /// Продолжительность жизни (игровых дней) до смерти от старости. - public float Lifespan { get; init; } = 160f; - - /// Сезон гона (0 весна, 1 лето, 2 осень, 3 зима) — фиксирован по виду. - public float BreedingSeason { get; init; } = 2f; - - /// Срок вынашивания (игровых дней). - public float GestationDays { get; init; } = 30f; - - /// Размер помёта (число детёнышей за роды). - public float LitterSize { get; init; } = 1f; - - /// Доля разброса аллелей вокруг базы при генерации особи. - public float Spread { get; init; } = 0.08f; -} - -/// -/// Вид-животное (Defs/animals.json): подтип (текстура/размер/вид) плюс базовый -/// геном вида. Поведение, здоровье и стадии живут на компонентах сущности (фазы A2+), а не на типе -/// дефа — существующие 9 животных- остаются валидными. +/// Вид-животное (Defs/animals.json): подтип (текстура/размер/вид) плюс геном +/// вида. Поведение, здоровье и стадии живут на компонентах сущности (фазы A2+), а не на типе дефа — +/// существующие 9 животных- остаются валидными. /// public sealed class AnimalDef : PawnDef { @@ -273,8 +222,13 @@ public sealed class AnimalDef : PawnDef /// Текстура детёныша/подростка (фаза A3); пусто — берётся . public string BabyTexture { get; init; } = ""; - /// Базовый геном вида: центры аллелей животных генов. - public AnimalGenomeDef Genome { get; init; } = new(); + /// + /// Геном вида как ДАННЫЕ: ключ — id гена (), значение — + /// центр аллелей особи. Состав открыт — модер добавляет/убирает ген одной строкой JSON, без правки + /// кода; разброс берётся из самого гена (GeneDef.Spread). Дискретные гены (напр. пол) сюда + /// не пишутся — назначаются генерацией. + /// + public Dictionary Genome { get; init; } = new(); } /// diff --git a/src/LittleSim/Scenes/WorldScene.cs b/src/LittleSim/Scenes/WorldScene.cs index 0268584..bb38554 100644 --- a/src/LittleSim/Scenes/WorldScene.cs +++ b/src/LittleSim/Scenes/WorldScene.cs @@ -503,7 +503,9 @@ public sealed class WorldScene : Scene } var species = _animals.IndexOf(deerDef); - var maxAge = deerDef.Genome.Lifespan * 0.85f; // разновозрастное стадо, но не у самой смерти + // Разновозрастное стадо, но не у самой смерти; продолжительность жизни — из данных генома вида. + var maxAge = + (deerDef.Genome.TryGetValue("GeneLifespan", out var lifespan) ? lifespan : 160f) * 0.85f; var random = new Random(_config.Seed + 0x5EED); var landCells = 0;