Животные A7: мозг → интеллект → гейт нужд/действий
Эффективный интеллект = 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>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
9f8ff93591
commit
26bf83db64
@@ -2,15 +2,19 @@
|
|||||||
"type": "Need",
|
"type": "Need",
|
||||||
// Нужды как данные (фаза A2, рефактор расширяемости): добавить нужду виду = добавить запись здесь.
|
// Нужды как данные (фаза A2, рефактор расширяемости): добавить нужду виду = добавить запись здесь.
|
||||||
// kind=deplete убывает и утоляется действием; kind=drive растёт под хедифом (гон) и сбрасывается им.
|
// kind=deplete убывает и утоляется действием; kind=drive растёт под хедифом (гон) и сбрасывается им.
|
||||||
// action — id поведения-исполнителя (реестр в коде); minBrain — гейт интеллектом (включится в A7).
|
// action — id поведения-исполнителя (реестр в коде). minBrain — гейт интеллектом (активен с A7):
|
||||||
|
// нужда, чей minBrain выше эффективного интеллекта особи (brainSize × Consciousness), в выбор ИИ не
|
||||||
|
// входит. Пороги — тиры мозга: 0.0 голод-рефлекс, 0.25 жажда (низший позвоночный), 0.40 сон/секс
|
||||||
|
// (зверь). У оленя мозг ~0.45: здоров — весь набор; повреждение мозга/болезнь роняют сознание →
|
||||||
|
// эффективный интеллект падает → первыми отключаются сон/спаривание (обратная связь A7).
|
||||||
"defs": [
|
"defs": [
|
||||||
{ "defName": "Hunger", "label": "need.hunger", "kind": "deplete", "action": "Eat",
|
{ "defName": "Hunger", "label": "need.hunger", "kind": "deplete", "action": "Eat",
|
||||||
"decayPerDay": 0.55, "feedPerDay": 4, "lethal": true, "minBrain": 0.25 },
|
"decayPerDay": 0.55, "feedPerDay": 4, "lethal": true, "minBrain": 0.0 },
|
||||||
{ "defName": "Thirst", "label": "need.thirst", "kind": "deplete", "action": "Drink",
|
{ "defName": "Thirst", "label": "need.thirst", "kind": "deplete", "action": "Drink",
|
||||||
"decayPerDay": 0.9, "feedPerDay": 8, "lethal": true, "minBrain": 0.2 },
|
"decayPerDay": 0.9, "feedPerDay": 8, "lethal": true, "minBrain": 0.25 },
|
||||||
{ "defName": "Rest", "label": "need.rest", "kind": "deplete", "action": "Sleep",
|
{ "defName": "Rest", "label": "need.rest", "kind": "deplete", "action": "Sleep",
|
||||||
"decayPerDay": 0.7, "feedPerDay": 3, "lethal": false, "minBrain": 0.45 },
|
"decayPerDay": 0.7, "feedPerDay": 3, "lethal": false, "minBrain": 0.40 },
|
||||||
{ "defName": "Mating", "label": "need.mating", "kind": "drive", "action": "Mate",
|
{ "defName": "Mating", "label": "need.mating", "kind": "drive", "action": "Mate",
|
||||||
"decayPerDay": 1.0, "risePerDay": 1.2, "risesUnder": "Rut", "minBrain": 0.45 }
|
"decayPerDay": 1.0, "risePerDay": 1.2, "risesUnder": "Rut", "minBrain": 0.40 }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-1
@@ -1,8 +1,16 @@
|
|||||||
# Животные (зоология)
|
# Животные (зоология)
|
||||||
|
|
||||||
> Статус: **A1–A4 + рефактор расширяемости + A5(труп) реализованы**, остальное по плану. Это живой
|
> Статус: **A1–A7 + рефактор расширяемости реализованы**, остальное (A8) по плану. Это живой
|
||||||
> план — правится по мере реализации фаз A1–A8. Стиль и правила — как в [концепте](concept.md) и [модах](mods.md).
|
> план — правится по мере реализации фаз A1–A8. Стиль и правила — как в [концепте](concept.md) и [модах](mods.md).
|
||||||
>
|
>
|
||||||
|
> **A7 (готово): мозг → интеллект → гейт нужд/действий.** Эффективный интеллект = `brainSize` (ген) ×
|
||||||
|
> `Consciousness` (capacity из здоровья) — `AnimalFactory.Intelligence`. `AnimalContext` гейтит выбор ИИ:
|
||||||
|
> нужда с `minBrain` выше интеллекта особи в выбор не входит (`AnimalDecisionSystem` читает `Health`
|
||||||
|
> поэлементно). Пороги в `needs.json` — тиры мозга (голод 0.0, жажда 0.25, сон/секс 0.40; у оленя мозг
|
||||||
|
> ~0.45 → здоров весь набор). **Обратная связь от повреждения мозга**: болезнь/боль/кровопотеря роняют
|
||||||
|
> сознание → эффективный интеллект падает → первыми отключаются сон/спаривание (лихорадящий олень
|
||||||
|
> сводится к еде/питью). Команда `intel <species> [consciousness]`. Сборка + `--check-content` чистые.
|
||||||
|
>
|
||||||
> **A5 часть 1 (готово): смерть → труп → разложение.** `Corpse`-компонент + `CorpseSystem`
|
> **A5 часть 1 (готово): смерть → труп → разложение.** `Corpse`-компонент + `CorpseSystem`
|
||||||
> (Fresh→Rotting→Skeleton→исчезает, скорость от температуры, тинт по стадии); смерть теперь оставляет
|
> (Fresh→Rotting→Skeleton→исчезает, скорость от температуры, тинт по стадии); смерть теперь оставляет
|
||||||
> труп (`AnimalFactory.CreateCorpse`, мясо ∝ размер тела) вместо деспавна; `AnimalDef.CorpseTexture` +
|
> труп (`AnimalFactory.CreateCorpse`, мясо ∝ размер тела) вместо деспавна; `AnimalDef.CorpseTexture` +
|
||||||
|
|||||||
@@ -215,7 +215,9 @@ public sealed class WorldScene : Scene
|
|||||||
// нужду (еда выедает растения — контур ёмкости среды). Внешний вид тускнеет с острой нуждой.
|
// нужду (еда выедает растения — контур ёмкости среды). Внешний вид тускнеет с острой нуждой.
|
||||||
var shore = ComputeShore();
|
var shore = ComputeShore();
|
||||||
UpdateSystems.Add(new AnimalNeedsSystem(Context.Clock, SecondsPerDay, _needs));
|
UpdateSystems.Add(new AnimalNeedsSystem(Context.Clock, SecondsPerDay, _needs));
|
||||||
UpdateSystems.Add(new AnimalRutSystem(_animals, climate, content.Defs.Get<HediffDef>("Rut")));
|
UpdateSystems.Add(
|
||||||
|
new AnimalRutSystem(_animals, climate, content.Defs.Get<HediffDef>("Rut"))
|
||||||
|
);
|
||||||
UpdateSystems.Add(
|
UpdateSystems.Add(
|
||||||
new AnimalHealthSystem(
|
new AnimalHealthSystem(
|
||||||
Store,
|
Store,
|
||||||
@@ -547,7 +549,8 @@ public sealed class WorldScene : Scene
|
|||||||
|
|
||||||
var count = Math.Max(1, (int)MathF.Round(landCells / 1000f * def.SpawnPer1000Cells));
|
var count = Math.Max(1, (int)MathF.Round(landCells / 1000f * def.SpawnPer1000Cells));
|
||||||
var maxAge =
|
var maxAge =
|
||||||
(def.Genome.TryGetValue("GeneLifespan", out var lifespan) ? lifespan : 160f) * 0.85f;
|
(def.Genome.TryGetValue("GeneLifespan", out var lifespan) ? lifespan : 160f)
|
||||||
|
* 0.85f;
|
||||||
var placed = 0;
|
var placed = 0;
|
||||||
var attempts = 0;
|
var attempts = 0;
|
||||||
while (placed < count && attempts < count * 50)
|
while (placed < count && attempts < count * 50)
|
||||||
@@ -730,6 +733,11 @@ public sealed class WorldScene : Scene
|
|||||||
"infect [hediff] — give every animal a disease (default Fever) to test the health system",
|
"infect [hediff] — give every animal a disease (default Fever) to test the health system",
|
||||||
(c, args) => RunInfect(c, content, args)
|
(c, args) => RunInfect(c, content, args)
|
||||||
);
|
);
|
||||||
|
console.Register(
|
||||||
|
"intel",
|
||||||
|
"intel <species> [consciousness] — effective intelligence (brain x consciousness) and which needs it gates",
|
||||||
|
(c, args) => RunIntel(c, content, args)
|
||||||
|
);
|
||||||
console.Register(
|
console.Register(
|
||||||
"menu",
|
"menu",
|
||||||
"menu — return to the main menu",
|
"menu — return to the main menu",
|
||||||
@@ -914,7 +922,10 @@ public sealed class WorldScene : Scene
|
|||||||
var name = _animals[s].Def.DefName;
|
var name = _animals[s].Def.DefName;
|
||||||
if (
|
if (
|
||||||
count[s] == 0
|
count[s] == 0
|
||||||
|| (filter is not null && !string.Equals(name, filter, StringComparison.OrdinalIgnoreCase))
|
|| (
|
||||||
|
filter is not null
|
||||||
|
&& !string.Equals(name, filter, StringComparison.OrdinalIgnoreCase)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -960,10 +971,18 @@ public sealed class WorldScene : Scene
|
|||||||
console.WriteLine($"{def.DefName} body '{body.DefName}': {body.Parts.Length} parts");
|
console.WriteLine($"{def.DefName} body '{body.DefName}': {body.Parts.Length} parts");
|
||||||
foreach (var part in body.Parts)
|
foreach (var part in body.Parts)
|
||||||
{
|
{
|
||||||
var caps = part.Capacities.Count > 0
|
var caps =
|
||||||
? " [" + string.Join(", ", part.Capacities.Select(kv => $"{kv.Key} {kv.Value:0.##}")) + "]"
|
part.Capacities.Count > 0
|
||||||
: "";
|
? " ["
|
||||||
console.WriteLine($" {part.Name}{(part.Vital ? " *vital" : "")} hp{part.MaxHp:0}{caps}");
|
+ string.Join(
|
||||||
|
", ",
|
||||||
|
part.Capacities.Select(kv => $"{kv.Key} {kv.Value:0.##}")
|
||||||
|
)
|
||||||
|
+ "]"
|
||||||
|
: "";
|
||||||
|
console.WriteLine(
|
||||||
|
$" {part.Name}{(part.Vital ? " *vital" : "")} hp{part.MaxHp:0}{caps}"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
var state = HealthState.Create(body, 1f);
|
var state = HealthState.Create(body, 1f);
|
||||||
@@ -999,6 +1018,59 @@ public sealed class WorldScene : Scene
|
|||||||
console.WriteLine($"infected {count} animals with {def.DefName}");
|
console.WriteLine($"infected {count} animals with {def.DefName}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Наблюдаемость интеллекта (фаза A7): мозг особи (ген) × сознание = эффективный интеллект, который
|
||||||
|
// гейтит набор нужд/действий. Показывает активные/отключённые нужды при заданном уровне сознания
|
||||||
|
// (по умолчанию 1 — здоров; меньше — имитация повреждения мозга/болезни/боли).
|
||||||
|
private void RunIntel(DevConsole console, GameContent content, string[] args)
|
||||||
|
{
|
||||||
|
var species = content.Defs.NamesOf("Animal");
|
||||||
|
if (args.Length == 0)
|
||||||
|
{
|
||||||
|
console.WriteLine(
|
||||||
|
"usage: intel <species> [consciousness 0..1] [seed] e.g. intel Deer 0.6"
|
||||||
|
);
|
||||||
|
console.WriteLine($"species: {string.Join(", ", species)}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!content.Defs.TryGet<AnimalDef>(args[0], out var def))
|
||||||
|
{
|
||||||
|
console.WriteLine($"no animal '{args[0]}'; species: {string.Join(", ", species)}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var consciousness =
|
||||||
|
args.Length > 1
|
||||||
|
? Math.Clamp(
|
||||||
|
float.Parse(args[1], System.Globalization.CultureInfo.InvariantCulture),
|
||||||
|
0f,
|
||||||
|
1f
|
||||||
|
)
|
||||||
|
: 1f;
|
||||||
|
var seed = args.Length > 2 ? int.Parse(args[2]) : Random.Shared.Next();
|
||||||
|
var index = _animals.IndexOf(def);
|
||||||
|
var genome = _animals.GenerateGenome(index, new Random(seed));
|
||||||
|
var traits = AnimalPhenotype.FromTraits(Phenotype.Compute(genome, _animals.GeneRegistry));
|
||||||
|
var intelligence = traits.BrainSize * consciousness;
|
||||||
|
|
||||||
|
console.WriteLine(
|
||||||
|
$"{def.DefName} (seed {seed}): brain {traits.BrainSize:0.##} x consciousness {consciousness:0.##} "
|
||||||
|
+ $"= intelligence {intelligence:0.###}"
|
||||||
|
);
|
||||||
|
var active = new List<string>();
|
||||||
|
var gated = new List<string>();
|
||||||
|
for (var k = 0; k < _needs.Count; k++)
|
||||||
|
{
|
||||||
|
var need = _needs[k];
|
||||||
|
(need.MinBrain > intelligence ? gated : active).Add(
|
||||||
|
$"{need.DefName}({need.MinBrain:0.##})"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.WriteLine($" active: {(active.Count > 0 ? string.Join(", ", active) : "—")}");
|
||||||
|
console.WriteLine($" gated: {(gated.Count > 0 ? string.Join(", ", gated) : "—")}");
|
||||||
|
}
|
||||||
|
|
||||||
private static string ProductLabel(GameContent content, string productDefName) =>
|
private static string ProductLabel(GameContent content, string productDefName) =>
|
||||||
content.Defs.TryGet<ProductDef>(productDefName, out var product)
|
content.Defs.TryGet<ProductDef>(productDefName, out var product)
|
||||||
? content.Languages.Get(product.Label)
|
? content.Languages.Get(product.Label)
|
||||||
|
|||||||
@@ -42,7 +42,10 @@ public static class AnimalFactory
|
|||||||
sprite.Color = FurTint(traits);
|
sprite.Color = FurTint(traits);
|
||||||
|
|
||||||
return store.CreateEntity(
|
return store.CreateEntity(
|
||||||
new Transform2D(position, scale: new Vector2(Scale(sp, traits, stage, region, cellSize))),
|
new Transform2D(
|
||||||
|
position,
|
||||||
|
scale: new Vector2(Scale(sp, traits, stage, region, cellSize))
|
||||||
|
),
|
||||||
sprite,
|
sprite,
|
||||||
new AnimalOrganism
|
new AnimalOrganism
|
||||||
{
|
{
|
||||||
@@ -97,12 +100,31 @@ public static class AnimalFactory
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Эффективный интеллект особи (фаза A7): размер мозга (ген) × сознание (capacity из здоровья).
|
||||||
|
/// Повреждение мозга/болезнь/боль/кровопотеря снижают Consciousness → динамически роняют интеллект,
|
||||||
|
/// что гейтит набор доступных нужд/действий (см. <see cref="AnimalContext"/>). Вид без частей тела
|
||||||
|
/// (сознание не вычисляется) считается полностью сознательным — чтобы не отключить ему всё.
|
||||||
|
/// </summary>
|
||||||
|
public static float Intelligence(in AnimalPhenotype traits, HealthState? health)
|
||||||
|
{
|
||||||
|
var consciousness = health is { Parts.Length: > 0 }
|
||||||
|
? health.Capacity(AnimalCapacities.Consciousness)
|
||||||
|
: 1f;
|
||||||
|
return traits.BrainSize * consciousness;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Пол из локуса GeneSex: наличие аллеля Y (значение ≈1) → самец; иначе самка (XX).</summary>
|
/// <summary>Пол из локуса GeneSex: наличие аллеля Y (значение ≈1) → самец; иначе самка (XX).</summary>
|
||||||
public static bool IsMaleGenome(Genome genome) =>
|
public static bool IsMaleGenome(Genome genome) =>
|
||||||
genome.Has("GeneSex") && (genome["GeneSex"].A > 0.5f || genome["GeneSex"].B > 0.5f);
|
genome.Has("GeneSex") && (genome["GeneSex"].A > 0.5f || genome["GeneSex"].B > 0.5f);
|
||||||
|
|
||||||
/// <summary>Индекс стадии по возрасту: последняя стадия, чей возраст входа (EnterAt × якорь) ≤ возраст.</summary>
|
/// <summary>Индекс стадии по возрасту: последняя стадия, чей возраст входа (EnterAt × якорь) ≤ возраст.</summary>
|
||||||
public static int StageAt(float ageDays, float maturity, float lifespan, AnimalStageDef[] stages)
|
public static int StageAt(
|
||||||
|
float ageDays,
|
||||||
|
float maturity,
|
||||||
|
float lifespan,
|
||||||
|
AnimalStageDef[] stages
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var stage = 0;
|
var stage = 0;
|
||||||
for (var i = 1; i < stages.Length; i++)
|
for (var i = 1; i < stages.Length; i++)
|
||||||
|
|||||||
@@ -61,13 +61,36 @@ public struct AnimalBrain : IComponent
|
|||||||
public float DecideIn;
|
public float DecideIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Снимок нужд зверя для соображений utility-выбора (доступ по индексу нужды).</summary>
|
/// <summary>
|
||||||
public readonly struct AnimalContext(float[] values)
|
/// Снимок нужд зверя для соображений utility-выбора (доступ по индексу нужды) с гейтом интеллектом
|
||||||
|
/// (фаза A7): нужда, чей <see cref="NeedDef.MinBrain"/> выше эффективного интеллекта особи
|
||||||
|
/// (brainSize × Consciousness), в выбор не входит.
|
||||||
|
/// </summary>
|
||||||
|
public readonly struct AnimalContext(float[] values, NeedSet needs, float intelligence)
|
||||||
{
|
{
|
||||||
private readonly float[] _values = values;
|
private readonly float[] _values = values;
|
||||||
|
private readonly NeedSet _needs = needs;
|
||||||
|
private readonly float _intelligence = intelligence;
|
||||||
|
|
||||||
/// <summary>Значение нужды по индексу (0, если индекс вне диапазона).</summary>
|
/// <summary>
|
||||||
public float Get(int index) => index < _values.Length ? _values[index] : 0f;
|
/// Значение нужды по индексу. Если её порог мозга выше интеллекта особи — нужда недоступна и
|
||||||
|
/// возвращается её «не-срочный» край (deplete → 1 «сыта», drive → 0 «без влечения»), чтобы
|
||||||
|
/// соображение дало ~0 и действие не выбралось. Индекс вне диапазона → 0.
|
||||||
|
/// </summary>
|
||||||
|
public float Get(int index)
|
||||||
|
{
|
||||||
|
if (index >= _values.Length)
|
||||||
|
{
|
||||||
|
return 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_needs[index].MinBrain > _intelligence)
|
||||||
|
{
|
||||||
|
return _needs.IsDrive(index) ? 0f : 1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _values[index];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -112,7 +135,11 @@ public sealed class AnimalNeedsSystem(GameClock clock, float secondsPerDay, Need
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
values[k] = Math.Clamp(values[k] - def.DecayPerDay * metabolism * days, 0f, 1f);
|
values[k] = Math.Clamp(
|
||||||
|
values[k] - def.DecayPerDay * metabolism * days,
|
||||||
|
0f,
|
||||||
|
1f
|
||||||
|
);
|
||||||
if (def.Lethal && values[k] <= 0f)
|
if (def.Lethal && values[k] <= 0f)
|
||||||
{
|
{
|
||||||
lethalEmpty = true;
|
lethalEmpty = true;
|
||||||
@@ -174,6 +201,7 @@ public sealed class AnimalDecisionSystem : BaseSystem
|
|||||||
private readonly UtilityAi<AnimalContext> _brain;
|
private readonly UtilityAi<AnimalContext> _brain;
|
||||||
private readonly GameClock _clock;
|
private readonly GameClock _clock;
|
||||||
private readonly AnimalSet _animalSet;
|
private readonly AnimalSet _animalSet;
|
||||||
|
private readonly NeedSet _needs;
|
||||||
private readonly int _cellSize;
|
private readonly int _cellSize;
|
||||||
private readonly Vector2[] _shore;
|
private readonly Vector2[] _shore;
|
||||||
private readonly Random _rng;
|
private readonly Random _rng;
|
||||||
@@ -199,10 +227,17 @@ public sealed class AnimalDecisionSystem : BaseSystem
|
|||||||
_brain = BuildBrain(needs);
|
_brain = BuildBrain(needs);
|
||||||
_clock = clock;
|
_clock = clock;
|
||||||
_animalSet = animals;
|
_animalSet = animals;
|
||||||
|
_needs = needs;
|
||||||
_cellSize = cellSize;
|
_cellSize = cellSize;
|
||||||
_shore = shore;
|
_shore = shore;
|
||||||
_rng = new Random(seed);
|
_rng = new Random(seed);
|
||||||
_animals = store.Query<AnimalNeeds, AnimalBrain, AnimalOrganism, AnimalGrowth, Transform2D>();
|
_animals = store.Query<
|
||||||
|
AnimalNeeds,
|
||||||
|
AnimalBrain,
|
||||||
|
AnimalOrganism,
|
||||||
|
AnimalGrowth,
|
||||||
|
Transform2D
|
||||||
|
>();
|
||||||
_plants = store.Query<Transform2D, PlantGrowth>();
|
_plants = store.Query<Transform2D, PlantGrowth>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,7 +272,9 @@ public sealed class AnimalDecisionSystem : BaseSystem
|
|||||||
protected override void OnUpdateGroup()
|
protected override void OnUpdateGroup()
|
||||||
{
|
{
|
||||||
var delta = _clock.DeltaTime;
|
var delta = _clock.DeltaTime;
|
||||||
foreach (var (needsChunk, brains, organisms, growths, transforms, _) in _animals.Chunks)
|
foreach (
|
||||||
|
var (needsChunk, brains, organisms, growths, transforms, entities) in _animals.Chunks
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var n = needsChunk.Span;
|
var n = needsChunk.Span;
|
||||||
var b = brains.Span;
|
var b = brains.Span;
|
||||||
@@ -257,8 +294,15 @@ public sealed class AnimalDecisionSystem : BaseSystem
|
|||||||
var pos = t[i].Position;
|
var pos = t[i].Position;
|
||||||
var adult = AnimalFactory.IsAdult(_animalSet[o[i].Species], gr[i].Stage);
|
var adult = AnimalFactory.IsAdult(_animalSet[o[i].Species], gr[i].Stage);
|
||||||
var radius = VisionRadius(o[i].Species, o[i].Traits.Vision);
|
var radius = VisionRadius(o[i].Species, o[i].Traits.Vision);
|
||||||
|
// Эффективный интеллект (мозг × сознание) гейтит доступные нужды/действия (фаза A7):
|
||||||
|
// больной/раненый зверь с упавшим сознанием теряет высшие нужды (сон/секс) → рефлексы.
|
||||||
|
var intelligence = AnimalFactory.Intelligence(
|
||||||
|
o[i].Traits,
|
||||||
|
entities.EntityAt(i).GetComponent<Health>().State
|
||||||
|
);
|
||||||
var name =
|
var name =
|
||||||
_brain.Select(new AnimalContext(n[i].Values))?.Name ?? AnimalActions.Wander;
|
_brain.Select(new AnimalContext(n[i].Values, _needs, intelligence))?.Name
|
||||||
|
?? AnimalActions.Wander;
|
||||||
|
|
||||||
switch (name)
|
switch (name)
|
||||||
{
|
{
|
||||||
@@ -280,7 +324,13 @@ public sealed class AnimalDecisionSystem : BaseSystem
|
|||||||
break;
|
break;
|
||||||
case AnimalActions.Mate
|
case AnimalActions.Mate
|
||||||
when adult
|
when adult
|
||||||
&& TryFindMate(pos, o[i].IsMale, radius, out var mateId, out var matePos):
|
&& TryFindMate(
|
||||||
|
pos,
|
||||||
|
o[i].IsMale,
|
||||||
|
radius,
|
||||||
|
out var mateId,
|
||||||
|
out var matePos
|
||||||
|
):
|
||||||
brain.Action = AnimalActions.Mate;
|
brain.Action = AnimalActions.Mate;
|
||||||
brain.TargetPlant = -1;
|
brain.TargetPlant = -1;
|
||||||
brain.TargetMate = mateId;
|
brain.TargetMate = mateId;
|
||||||
@@ -388,7 +438,10 @@ public sealed class AnimalDecisionSystem : BaseSystem
|
|||||||
var tt = transforms.Span;
|
var tt = transforms.Span;
|
||||||
for (var i = 0; i < tt.Length; i++)
|
for (var i = 0; i < tt.Length; i++)
|
||||||
{
|
{
|
||||||
if (oo[i].IsMale == selfMale || !AnimalFactory.IsAdult(_animalSet[oo[i].Species], gg[i].Stage))
|
if (
|
||||||
|
oo[i].IsMale == selfMale
|
||||||
|
|| !AnimalFactory.IsAdult(_animalSet[oo[i].Species], gg[i].Stage)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
continue; // тот же пол / не взрослый (self отсеивается по полу)
|
continue; // тот же пол / не взрослый (self отсеивается по полу)
|
||||||
}
|
}
|
||||||
@@ -475,7 +528,9 @@ public sealed class AnimalActionSystem : BaseSystem
|
|||||||
_eaten.Clear();
|
_eaten.Clear();
|
||||||
_matings.Clear();
|
_matings.Clear();
|
||||||
|
|
||||||
foreach (var (brains, needsChunk, organisms, transforms, healths, entities) in _query.Chunks)
|
foreach (
|
||||||
|
var (brains, needsChunk, organisms, transforms, healths, entities) in _query.Chunks
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var b = brains.Span;
|
var b = brains.Span;
|
||||||
var n = needsChunk.Span;
|
var n = needsChunk.Span;
|
||||||
@@ -744,7 +799,9 @@ public sealed class AnimalGrowthSystem(
|
|||||||
ref var sprite = ref s[i];
|
ref var sprite = ref s[i];
|
||||||
sprite.Region = region;
|
sprite.Region = region;
|
||||||
sprite.Origin = new Vector2(region.Width / 2f, region.Height / 2f);
|
sprite.Origin = new Vector2(region.Width / 2f, region.Height / 2f);
|
||||||
t[i].Scale = new Vector2(AnimalFactory.Scale(sp, org.Traits, stage, region, cellSize));
|
t[i].Scale = new Vector2(
|
||||||
|
AnimalFactory.Scale(sp, org.Traits, stage, region, cellSize)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1082,7 +1139,10 @@ public sealed class AnimalHealthSystem : BaseSystem
|
|||||||
|
|
||||||
foreach (var disease in _ambient)
|
foreach (var disease in _ambient)
|
||||||
{
|
{
|
||||||
if (!state.Has(disease.DefName) && _rng.NextSingle() < disease.AmbientPerDay * days)
|
if (
|
||||||
|
!state.Has(disease.DefName)
|
||||||
|
&& _rng.NextSingle() < disease.AmbientPerDay * days
|
||||||
|
)
|
||||||
{
|
{
|
||||||
state.Add(disease);
|
state.Add(disease);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user