Животные 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
@@ -61,13 +61,36 @@ public struct AnimalBrain : IComponent
|
||||
public float DecideIn;
|
||||
}
|
||||
|
||||
/// <summary>Снимок нужд зверя для соображений utility-выбора (доступ по индексу нужды).</summary>
|
||||
public readonly struct AnimalContext(float[] values)
|
||||
/// <summary>
|
||||
/// Снимок нужд зверя для соображений 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 NeedSet _needs = needs;
|
||||
private readonly float _intelligence = intelligence;
|
||||
|
||||
/// <summary>Значение нужды по индексу (0, если индекс вне диапазона).</summary>
|
||||
public float Get(int index) => index < _values.Length ? _values[index] : 0f;
|
||||
/// <summary>
|
||||
/// Значение нужды по индексу. Если её порог мозга выше интеллекта особи — нужда недоступна и
|
||||
/// возвращается её «не-срочный» край (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>
|
||||
@@ -112,7 +135,11 @@ public sealed class AnimalNeedsSystem(GameClock clock, float secondsPerDay, Need
|
||||
}
|
||||
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)
|
||||
{
|
||||
lethalEmpty = true;
|
||||
@@ -174,6 +201,7 @@ public sealed class AnimalDecisionSystem : BaseSystem
|
||||
private readonly UtilityAi<AnimalContext> _brain;
|
||||
private readonly GameClock _clock;
|
||||
private readonly AnimalSet _animalSet;
|
||||
private readonly NeedSet _needs;
|
||||
private readonly int _cellSize;
|
||||
private readonly Vector2[] _shore;
|
||||
private readonly Random _rng;
|
||||
@@ -199,10 +227,17 @@ public sealed class AnimalDecisionSystem : BaseSystem
|
||||
_brain = BuildBrain(needs);
|
||||
_clock = clock;
|
||||
_animalSet = animals;
|
||||
_needs = needs;
|
||||
_cellSize = cellSize;
|
||||
_shore = shore;
|
||||
_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>();
|
||||
}
|
||||
|
||||
@@ -237,7 +272,9 @@ public sealed class AnimalDecisionSystem : BaseSystem
|
||||
protected override void OnUpdateGroup()
|
||||
{
|
||||
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 b = brains.Span;
|
||||
@@ -257,8 +294,15 @@ public sealed class AnimalDecisionSystem : BaseSystem
|
||||
var pos = t[i].Position;
|
||||
var adult = AnimalFactory.IsAdult(_animalSet[o[i].Species], gr[i].Stage);
|
||||
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 =
|
||||
_brain.Select(new AnimalContext(n[i].Values))?.Name ?? AnimalActions.Wander;
|
||||
_brain.Select(new AnimalContext(n[i].Values, _needs, intelligence))?.Name
|
||||
?? AnimalActions.Wander;
|
||||
|
||||
switch (name)
|
||||
{
|
||||
@@ -280,7 +324,13 @@ public sealed class AnimalDecisionSystem : BaseSystem
|
||||
break;
|
||||
case AnimalActions.Mate
|
||||
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.TargetPlant = -1;
|
||||
brain.TargetMate = mateId;
|
||||
@@ -388,7 +438,10 @@ public sealed class AnimalDecisionSystem : BaseSystem
|
||||
var tt = transforms.Span;
|
||||
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 отсеивается по полу)
|
||||
}
|
||||
@@ -475,7 +528,9 @@ public sealed class AnimalActionSystem : BaseSystem
|
||||
_eaten.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 n = needsChunk.Span;
|
||||
@@ -744,7 +799,9 @@ public sealed class AnimalGrowthSystem(
|
||||
ref var sprite = ref s[i];
|
||||
sprite.Region = region;
|
||||
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)
|
||||
{
|
||||
if (!state.Has(disease.DefName) && _rng.NextSingle() < disease.AmbientPerDay * days)
|
||||
if (
|
||||
!state.Has(disease.DefName)
|
||||
&& _rng.NextSingle() < disease.AmbientPerDay * days
|
||||
)
|
||||
{
|
||||
state.Add(disease);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user