Животные A8 часть 2: инспектор животных (вкладки нужды/здоровье/настроение)
InspectPanel осматривает и животных: вкладки Обзор (стадия/возраст/пол/поколение/беременность), Нужды, Здоровье (кровь/боль, способности, хедифы), Настроение (значение + мысли). Набор вкладок по типу выбранного. SelectionSystem пикает и животных (запрос расширен PlantGrowth → +AnimalOrganism). Локализация inspect.*/need.*/hediff.*/cap.*/animalstage.* ru+en. Базовый план зоологии A1-A8 закрыт. Сборка + --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
1b12831817
commit
003f235440
@@ -10,6 +10,9 @@
|
||||
"inspect.tab.overview": "Overview",
|
||||
"inspect.tab.genes": "Genes",
|
||||
"inspect.tab.products": "Products",
|
||||
"inspect.tab.needs": "Needs",
|
||||
"inspect.tab.health": "Health",
|
||||
"inspect.tab.mood": "Mood",
|
||||
"inspect.stage": "Stage: {0} ({1}/{2})",
|
||||
"inspect.growing": "Growth: {0:0}% to next stage",
|
||||
"inspect.mature": "Fully grown",
|
||||
@@ -31,6 +34,35 @@
|
||||
"inspect.harvest": "Harvest: {0} ×{1:0.#}",
|
||||
"inspect.fruit": "Fruit: {0} ×{1:0.#} ({2}) · ripe {3:0.#}",
|
||||
"inspect.barren": "Bears no fruit",
|
||||
"inspect.sex.male": "male",
|
||||
"inspect.sex.female": "female",
|
||||
"inspect.animal.sex": "Sex: {0} · generation {1}",
|
||||
"inspect.animal.pregnant": "Pregnant: {0:0.0} d to birth",
|
||||
"inspect.needline": "{0}: {1:0}%",
|
||||
"inspect.health.blood": "Blood: {0:0}% · pain: {1:0}%",
|
||||
"inspect.health.caps": "— Capacities —",
|
||||
"inspect.health.cap": "{0}: {1:0}%",
|
||||
"inspect.health.hediffs": "— Conditions —",
|
||||
"inspect.health.hediffline": "{0}: severity {1:0}%",
|
||||
"inspect.health.none": "Healthy, no wounds or illness",
|
||||
"inspect.mood.value": "Mood: {0:0}%",
|
||||
"inspect.mood.none": "No mood (primitive brain)",
|
||||
"inspect.mood.thoughts": "— Thoughts —",
|
||||
"inspect.mood.thoughtline": "{0}: {1}",
|
||||
"inspect.mood.calm": "Calm, nothing on its mind",
|
||||
"animalstage.baby": "baby",
|
||||
"animalstage.juvenile": "juvenile",
|
||||
"animalstage.adult": "adult",
|
||||
"animalstage.senior": "senior",
|
||||
"need.hunger": "hunger",
|
||||
"need.thirst": "thirst",
|
||||
"need.rest": "rest",
|
||||
"need.mating": "mating",
|
||||
"cap.consciousness": "consciousness",
|
||||
"cap.moving": "moving",
|
||||
"cap.sight": "sight",
|
||||
"hediff.rut": "rut",
|
||||
"hediff.fever": "fever",
|
||||
"inspect.hint": "LMB — select · RMB/Esc — clear",
|
||||
"hud.paused": "PAUSED",
|
||||
"menu.title": "LittleSim",
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
"inspect.tab.overview": "Обзор",
|
||||
"inspect.tab.genes": "Гены",
|
||||
"inspect.tab.products": "Продукты",
|
||||
"inspect.tab.needs": "Нужды",
|
||||
"inspect.tab.health": "Здоровье",
|
||||
"inspect.tab.mood": "Настроение",
|
||||
"inspect.stage": "Стадия: {0} ({1}/{2})",
|
||||
"inspect.growing": "Рост: {0:0}% до следующей стадии",
|
||||
"inspect.mature": "Полностью выросло",
|
||||
@@ -31,6 +34,35 @@
|
||||
"inspect.harvest": "Сбор: {0} ×{1:0.#}",
|
||||
"inspect.fruit": "Плоды: {0} ×{1:0.#} ({2}) · зрелых {3:0.#}",
|
||||
"inspect.barren": "Не плодоносит",
|
||||
"inspect.sex.male": "самец",
|
||||
"inspect.sex.female": "самка",
|
||||
"inspect.animal.sex": "Пол: {0} · поколение {1}",
|
||||
"inspect.animal.pregnant": "Беременна: {0:0.0} дн до родов",
|
||||
"inspect.needline": "{0}: {1:0}%",
|
||||
"inspect.health.blood": "Кровь: {0:0}% · боль: {1:0}%",
|
||||
"inspect.health.caps": "— Способности —",
|
||||
"inspect.health.cap": "{0}: {1:0}%",
|
||||
"inspect.health.hediffs": "— Состояния —",
|
||||
"inspect.health.hediffline": "{0}: тяжесть {1:0}%",
|
||||
"inspect.health.none": "Здоров, ран и болезней нет",
|
||||
"inspect.mood.value": "Настроение: {0:0}%",
|
||||
"inspect.mood.none": "Настроения нет (примитивный мозг)",
|
||||
"inspect.mood.thoughts": "— Мысли —",
|
||||
"inspect.mood.thoughtline": "{0}: {1}",
|
||||
"inspect.mood.calm": "Спокоен, особых мыслей нет",
|
||||
"animalstage.baby": "детёныш",
|
||||
"animalstage.juvenile": "подросток",
|
||||
"animalstage.adult": "взрослый",
|
||||
"animalstage.senior": "старый",
|
||||
"need.hunger": "голод",
|
||||
"need.thirst": "жажда",
|
||||
"need.rest": "отдых",
|
||||
"need.mating": "влечение",
|
||||
"cap.consciousness": "сознание",
|
||||
"cap.moving": "движение",
|
||||
"cap.sight": "зрение",
|
||||
"hediff.rut": "гон",
|
||||
"hediff.fever": "лихорадка",
|
||||
"inspect.hint": "ЛКМ — выбрать · ПКМ/Esc — снять",
|
||||
"hud.paused": "ПАУЗА",
|
||||
"menu.title": "LittleSim",
|
||||
|
||||
+11
-2
@@ -1,7 +1,16 @@
|
||||
# Животные (зоология)
|
||||
|
||||
> Статус: **A1–A7 + A8 часть 1 (ядро настроения) реализованы**, осталось A8 часть 2 (инспектор). Это
|
||||
> живой план — правится по мере реализации фаз A1–A8. Стиль и правила — как в [концепте](concept.md) и [модах](mods.md).
|
||||
> Статус: **A1–A8 реализованы целиком** — базовый план зоологии закрыт; дальше экологический горизонт
|
||||
> (хищники, опека, эпидемии, миграция) и бэклог реализма. Это живой план — стиль и правила как в
|
||||
> [концепте](concept.md) и [модах](mods.md).
|
||||
>
|
||||
> **A8 часть 2 (готово): инспектор животных.** `InspectPanel` теперь осматривает и животных (не только
|
||||
> растения): вкладки **Обзор** (стадия/возраст/пол/поколение/беременность), **Нужды** (значения нужд %),
|
||||
> **Здоровье** (кровь/боль, способности Consciousness/Moving/Sight, активные хедифы с тяжестью),
|
||||
> **Настроение** (значение % + список мыслей с их сдвигом). Набор вкладок зависит от типа выбранного
|
||||
> (растение vs животное). `SelectionSystem` теперь пикает и животных (запрос расширен с `PlantGrowth` на
|
||||
> `AnimalOrganism`). Локализация `inspect.*`/`need.*`/`hediff.*`/`cap.*`/`animalstage.*` (ru/en). Сборка +
|
||||
> `--check-content` чистые.
|
||||
>
|
||||
> **A8 часть 1 (готово): настроение — ядро.** Тип дефа `ThoughtDef` + `thoughts.json` (мысли: роды/
|
||||
> спаривание/утоление жажды — сила и длительность данными); компонент `Mood` (значение 0..1, активность по
|
||||
|
||||
@@ -163,7 +163,16 @@ public sealed class WorldScene : Scene
|
||||
atlases.GetRegion(device, "ui/overlays/selectionbracket"),
|
||||
GameLayers.Selection
|
||||
);
|
||||
_inspect = new InspectPanel(Store, _plants, content, climate, _selection, brackets);
|
||||
_inspect = new InspectPanel(
|
||||
Store,
|
||||
_plants,
|
||||
_animals,
|
||||
_needs,
|
||||
content,
|
||||
climate,
|
||||
_selection,
|
||||
brackets
|
||||
);
|
||||
desktop.Root = Ui.Screen(hudLabel, _inspect.Panel, speedBar, _pause.Root);
|
||||
|
||||
this.UseInspector(renderer);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using Friflo.Engine.ECS;
|
||||
using Friflo.Engine.ECS.Systems;
|
||||
using Microsoft.Xna.Framework;
|
||||
@@ -74,41 +75,62 @@ public sealed class SelectionSystem(
|
||||
}
|
||||
}
|
||||
|
||||
// Ближайшее растение, чья ограничивающая окружность спрайта накрывает точку мира. Запрос
|
||||
// ограничен PlantGrowth — так из пикинга выпадают спрайты рамки выделения и прочий не-контент.
|
||||
// Ближайший осматриваемый объект (растение или животное), чья ограничивающая окружность спрайта
|
||||
// накрывает точку мира. Запросы ограничены PlantGrowth/AnimalOrganism — так из пикинга выпадают
|
||||
// спрайты рамки выделения, трупы и прочий не-контент. Из двух кандидатов берётся более близкий.
|
||||
private bool TryPick(Vector2 world, out int id)
|
||||
{
|
||||
id = -1;
|
||||
var bestDistance = float.MaxValue;
|
||||
var best = float.MaxValue;
|
||||
foreach (
|
||||
var (transforms, sprites, _, entities) in store
|
||||
.Query<Transform2D, Sprite, PlantGrowth>()
|
||||
.Chunks
|
||||
)
|
||||
{
|
||||
var t = transforms.Span;
|
||||
var s = sprites.Span;
|
||||
for (var i = 0; i < t.Length; i++)
|
||||
Scan(world, transforms.Span, sprites.Span, entities, ref id, ref best);
|
||||
}
|
||||
|
||||
foreach (
|
||||
var (transforms, sprites, _, entities) in store
|
||||
.Query<Transform2D, Sprite, AnimalOrganism>()
|
||||
.Chunks
|
||||
)
|
||||
{
|
||||
if (s[i].Region is not { } region)
|
||||
Scan(world, transforms.Span, sprites.Span, entities, ref id, ref best);
|
||||
}
|
||||
|
||||
return id >= 0;
|
||||
}
|
||||
|
||||
// Обновляет лучшего кандидата (id/дистанцию) по чанку спрайтов: точка должна попасть в окружность.
|
||||
private static void Scan(
|
||||
Vector2 world,
|
||||
Span<Transform2D> transforms,
|
||||
Span<Sprite> sprites,
|
||||
ChunkEntities entities,
|
||||
ref int id,
|
||||
ref float best
|
||||
)
|
||||
{
|
||||
for (var i = 0; i < transforms.Length; i++)
|
||||
{
|
||||
if (sprites[i].Region is not { } region)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var (center, radius) = CullingMath.SpriteBoundingCircle(
|
||||
in t[i],
|
||||
in transforms[i],
|
||||
region,
|
||||
s[i].Origin
|
||||
sprites[i].Origin
|
||||
);
|
||||
var distance = Vector2.DistanceSquared(center, world);
|
||||
if (distance <= radius * radius && distance < bestDistance)
|
||||
if (distance <= radius * radius && distance < best)
|
||||
{
|
||||
bestDistance = distance;
|
||||
best = distance;
|
||||
id = entities.EntityAt(i).Id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return id >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Friflo.Engine.ECS;
|
||||
@@ -16,10 +17,11 @@ namespace LittleSim.UI;
|
||||
|
||||
/// <summary>
|
||||
/// Панель осмотра выбранной сущности (инфо-карточка в стиле RimWorld): угловая рамка вокруг объекта
|
||||
/// (<see cref="SelectionBrackets"/>) и боковая панель в левом нижнем углу с вкладками — «Обзор»,
|
||||
/// «Гены», «Продукты». Источник выделения — <see cref="Selection"/>; панель только читает компоненты
|
||||
/// и обновляется каждый кадр (<see cref="Refresh"/>), оставаясь живой даже на паузе. Все строки идут
|
||||
/// через <see cref="LanguageManager"/> (ключи <c>inspect.*</c>).
|
||||
/// (<see cref="SelectionBrackets"/>) и боковая панель в левом нижнем углу с вкладками. Набор вкладок
|
||||
/// зависит от типа: растение — «Обзор/Гены/Продукты», животное — «Обзор/Нужды/Здоровье/Настроение».
|
||||
/// Источник выделения — <see cref="Selection"/>; панель только читает компоненты и обновляется каждый
|
||||
/// кадр (<see cref="Refresh"/>), оставаясь живой даже на паузе. Все строки идут через
|
||||
/// <see cref="LanguageManager"/> (ключи <c>inspect.*</c>).
|
||||
/// </summary>
|
||||
internal sealed class InspectPanel
|
||||
{
|
||||
@@ -28,10 +30,18 @@ internal sealed class InspectPanel
|
||||
Overview,
|
||||
Genes,
|
||||
Products,
|
||||
Needs,
|
||||
Health,
|
||||
Mood,
|
||||
}
|
||||
|
||||
private static readonly Tab[] PlantTabs = [Tab.Overview, Tab.Genes, Tab.Products];
|
||||
private static readonly Tab[] AnimalTabs = [Tab.Overview, Tab.Needs, Tab.Health, Tab.Mood];
|
||||
|
||||
private readonly EntityStore _store;
|
||||
private readonly PlantSet _plants;
|
||||
private readonly AnimalSet _animals;
|
||||
private readonly NeedSet _needs;
|
||||
private readonly GameContent _content;
|
||||
private readonly Climate _climate;
|
||||
private readonly Selection _selection;
|
||||
@@ -46,6 +56,8 @@ internal sealed class InspectPanel
|
||||
public InspectPanel(
|
||||
EntityStore store,
|
||||
PlantSet plants,
|
||||
AnimalSet animals,
|
||||
NeedSet needs,
|
||||
GameContent content,
|
||||
Climate climate,
|
||||
Selection selection,
|
||||
@@ -54,6 +66,8 @@ internal sealed class InspectPanel
|
||||
{
|
||||
_store = store;
|
||||
_plants = plants;
|
||||
_animals = animals;
|
||||
_needs = needs;
|
||||
_content = content;
|
||||
_climate = climate;
|
||||
_selection = selection;
|
||||
@@ -66,6 +80,9 @@ internal sealed class InspectPanel
|
||||
AddTab(tabBar, Tab.Overview, "inspect.tab.overview");
|
||||
AddTab(tabBar, Tab.Genes, "inspect.tab.genes");
|
||||
AddTab(tabBar, Tab.Products, "inspect.tab.products");
|
||||
AddTab(tabBar, Tab.Needs, "inspect.tab.needs");
|
||||
AddTab(tabBar, Tab.Health, "inspect.tab.health");
|
||||
AddTab(tabBar, Tab.Mood, "inspect.tab.mood");
|
||||
|
||||
_panel = new VerticalStackPanel
|
||||
{
|
||||
@@ -99,7 +116,7 @@ internal sealed class InspectPanel
|
||||
|
||||
/// <summary>
|
||||
/// Подтягивает выделение каждый кадр: проверяет, жива ли сущность (иначе снимает выбор), двигает
|
||||
/// рамку к объекту и пересобирает текст активной вкладки. Не-растения панель не показывает.
|
||||
/// рамку к объекту и пересобирает текст активной вкладки. Осматриваются растения и животные.
|
||||
/// </summary>
|
||||
public void Refresh()
|
||||
{
|
||||
@@ -107,19 +124,19 @@ internal sealed class InspectPanel
|
||||
!_selection.HasSelection
|
||||
|| !_store.TryGetEntityById(_selection.EntityId, out var entity)
|
||||
|| entity.IsNull
|
||||
|| !entity.HasComponent<PlantGrowth>()
|
||||
|| !entity.HasComponent<PlantOrganism>()
|
||||
|| !entity.HasComponent<Transform2D>()
|
||||
|| !entity.HasComponent<Sprite>()
|
||||
)
|
||||
{
|
||||
if (_selection.HasSelection)
|
||||
{
|
||||
_selection.Clear(); // сущность исчезла (растение погибло)
|
||||
ClearSelection();
|
||||
return;
|
||||
}
|
||||
|
||||
_panel.Visible = false;
|
||||
_brackets.Hide();
|
||||
var isPlant = entity.HasComponent<PlantGrowth>() && entity.HasComponent<PlantOrganism>();
|
||||
var isAnimal = entity.HasComponent<AnimalOrganism>();
|
||||
if (!isPlant && !isAnimal)
|
||||
{
|
||||
ClearSelection(); // не контент (труп/прочее) — пока не осматривается
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -135,10 +152,29 @@ internal sealed class InspectPanel
|
||||
_brackets.Show(center, radius);
|
||||
}
|
||||
|
||||
UpdateText(entity);
|
||||
if (isPlant)
|
||||
{
|
||||
UpdatePlant(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateAnimal(entity);
|
||||
}
|
||||
|
||||
_panel.Visible = true;
|
||||
}
|
||||
|
||||
private void ClearSelection()
|
||||
{
|
||||
if (_selection.HasSelection)
|
||||
{
|
||||
_selection.Clear(); // сущность исчезла (растение/зверь погибли) или не осматривается
|
||||
}
|
||||
|
||||
_panel.Visible = false;
|
||||
_brackets.Hide();
|
||||
}
|
||||
|
||||
private void AddTab(HorizontalStackPanel bar, Tab tab, string labelKey)
|
||||
{
|
||||
var button = new TextButton { Text = _content.Languages.Get(labelKey) };
|
||||
@@ -147,7 +183,23 @@ internal sealed class InspectPanel
|
||||
_tabs.Add((tab, button));
|
||||
}
|
||||
|
||||
private void UpdateText(Entity entity)
|
||||
// Показывает только вкладки текущего типа, подсвечивает активную; если активная не из набора —
|
||||
// откатывает на первую (Обзор) при смене типа выбранного объекта.
|
||||
private void ShowTabs(Tab[] valid)
|
||||
{
|
||||
if (Array.IndexOf(valid, _tab) < 0)
|
||||
{
|
||||
_tab = valid[0];
|
||||
}
|
||||
|
||||
foreach (var (tab, button) in _tabs)
|
||||
{
|
||||
button.Visible = Array.IndexOf(valid, tab) >= 0;
|
||||
button.TextColor = tab == _tab ? Ui.Accent : Ui.Muted;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePlant(Entity entity)
|
||||
{
|
||||
var languages = _content.Languages;
|
||||
ref readonly var grow = ref entity.GetComponent<PlantGrowth>();
|
||||
@@ -157,10 +209,7 @@ internal sealed class InspectPanel
|
||||
var traits = org.Traits;
|
||||
|
||||
_title.Text = languages.Get(def.Label) + (traits.IsVariant ? " *" : "");
|
||||
foreach (var (tab, button) in _tabs)
|
||||
{
|
||||
button.TextColor = tab == _tab ? Ui.Accent : Ui.Muted;
|
||||
}
|
||||
ShowTabs(PlantTabs);
|
||||
|
||||
var text = new StringBuilder();
|
||||
switch (_tab)
|
||||
@@ -179,6 +228,35 @@ internal sealed class InspectPanel
|
||||
_body.Text = text.ToString().TrimEnd();
|
||||
}
|
||||
|
||||
private void UpdateAnimal(Entity entity)
|
||||
{
|
||||
var languages = _content.Languages;
|
||||
ref readonly var org = ref entity.GetComponent<AnimalOrganism>();
|
||||
var sp = _animals[org.Species];
|
||||
|
||||
_title.Text = languages.Get(sp.Def.Label);
|
||||
ShowTabs(AnimalTabs);
|
||||
|
||||
var text = new StringBuilder();
|
||||
switch (_tab)
|
||||
{
|
||||
case Tab.Overview:
|
||||
BuildAnimalOverview(text, entity, org, sp);
|
||||
break;
|
||||
case Tab.Needs:
|
||||
BuildAnimalNeeds(text, entity);
|
||||
break;
|
||||
case Tab.Health:
|
||||
BuildAnimalHealth(text, entity);
|
||||
break;
|
||||
case Tab.Mood:
|
||||
BuildAnimalMood(text, entity);
|
||||
break;
|
||||
}
|
||||
|
||||
_body.Text = text.ToString().TrimEnd();
|
||||
}
|
||||
|
||||
private void BuildOverview(
|
||||
StringBuilder text,
|
||||
Entity entity,
|
||||
@@ -296,6 +374,146 @@ internal sealed class InspectPanel
|
||||
}
|
||||
}
|
||||
|
||||
// — Животное: Обзор — стадия, возраст, пол/поколение, беременность.
|
||||
private void BuildAnimalOverview(
|
||||
StringBuilder text,
|
||||
Entity entity,
|
||||
in AnimalOrganism org,
|
||||
AnimalSet.Species sp
|
||||
)
|
||||
{
|
||||
var languages = _content.Languages;
|
||||
var grow = entity.GetComponent<AnimalGrowth>();
|
||||
var stageName = languages.Get(
|
||||
"animalstage." + sp.Stages[grow.Stage].Name.ToLowerInvariant()
|
||||
);
|
||||
text.AppendLine(
|
||||
languages.Format("inspect.stage", stageName, grow.Stage + 1, sp.Stages.Length)
|
||||
);
|
||||
text.AppendLine(languages.Format("inspect.age", grow.AgeDays, org.Traits.Lifespan));
|
||||
var sex = languages.Get(org.IsMale ? "inspect.sex.male" : "inspect.sex.female");
|
||||
text.AppendLine(languages.Format("inspect.animal.sex", sex, org.Generation));
|
||||
if (entity.TryGetComponent<Pregnant>(out var preg))
|
||||
{
|
||||
text.AppendLine(languages.Format("inspect.animal.pregnant", preg.DueInDays));
|
||||
}
|
||||
}
|
||||
|
||||
// — Животное: Нужды — значение каждой нужды (голод/жажда/отдых/влечение) в процентах.
|
||||
private void BuildAnimalNeeds(StringBuilder text, Entity entity)
|
||||
{
|
||||
var languages = _content.Languages;
|
||||
var values = entity.GetComponent<AnimalNeeds>().Values;
|
||||
if (values is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (var k = 0; k < _needs.Count && k < values.Length; k++)
|
||||
{
|
||||
text.AppendLine(
|
||||
languages.Format(
|
||||
"inspect.needline",
|
||||
languages.Get(_needs[k].Label),
|
||||
values[k] * 100f
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// — Животное: Здоровье — кровь/боль, ключевые способности, активные хедифы (раны/болезни/гон).
|
||||
private void BuildAnimalHealth(StringBuilder text, Entity entity)
|
||||
{
|
||||
var languages = _content.Languages;
|
||||
var state = entity.GetComponent<Health>().State;
|
||||
if (state is null)
|
||||
{
|
||||
text.AppendLine(languages.Get("inspect.health.none"));
|
||||
return;
|
||||
}
|
||||
|
||||
text.AppendLine(
|
||||
languages.Format("inspect.health.blood", state.BloodLevel * 100f, state.Pain * 100f)
|
||||
);
|
||||
if (state.Parts.Length > 0)
|
||||
{
|
||||
text.AppendLine(languages.Get("inspect.health.caps"));
|
||||
AppendCapacity(text, state, AnimalCapacities.Consciousness, "cap.consciousness");
|
||||
AppendCapacity(text, state, AnimalCapacities.Moving, "cap.moving");
|
||||
AppendCapacity(text, state, AnimalCapacities.Sight, "cap.sight");
|
||||
}
|
||||
|
||||
if (state.Hediffs.Count > 0)
|
||||
{
|
||||
text.AppendLine(languages.Get("inspect.health.hediffs"));
|
||||
foreach (var hediff in state.Hediffs)
|
||||
{
|
||||
text.AppendLine(
|
||||
languages.Format(
|
||||
"inspect.health.hediffline",
|
||||
languages.Get(hediff.Def.Label),
|
||||
hediff.Severity * 100f
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
text.AppendLine(languages.Get("inspect.health.none"));
|
||||
}
|
||||
}
|
||||
|
||||
private void AppendCapacity(
|
||||
StringBuilder text,
|
||||
HealthState state,
|
||||
string capId,
|
||||
string labelKey
|
||||
)
|
||||
{
|
||||
var languages = _content.Languages;
|
||||
text.AppendLine(
|
||||
languages.Format(
|
||||
"inspect.health.cap",
|
||||
languages.Get(labelKey),
|
||||
state.Capacity(capId) * 100f
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// — Животное: Настроение — значение и активные событийные мысли с их сдвигом (тир 4+).
|
||||
private void BuildAnimalMood(StringBuilder text, Entity entity)
|
||||
{
|
||||
var languages = _content.Languages;
|
||||
var mood = entity.GetComponent<Mood>();
|
||||
if (!mood.Active)
|
||||
{
|
||||
text.AppendLine(languages.Get("inspect.mood.none"));
|
||||
return;
|
||||
}
|
||||
|
||||
text.AppendLine(languages.Format("inspect.mood.value", mood.Value * 100f));
|
||||
if (mood.Thoughts is { Count: > 0 })
|
||||
{
|
||||
text.AppendLine(languages.Get("inspect.mood.thoughts"));
|
||||
foreach (var thought in mood.Thoughts)
|
||||
{
|
||||
var pct = thought.Def.MoodOffset * 100f;
|
||||
var offset = (pct >= 0f ? "+" : "") + pct.ToString("0") + "%";
|
||||
text.AppendLine(
|
||||
languages.Format(
|
||||
"inspect.mood.thoughtline",
|
||||
languages.Get(thought.Def.Label),
|
||||
offset
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
text.AppendLine(languages.Get("inspect.mood.calm"));
|
||||
}
|
||||
}
|
||||
|
||||
private string StageLabel(PlantDef def, int stage) =>
|
||||
stage < def.Stages.Count && def.Stages[stage].Label is { } key
|
||||
? _content.Languages.Get(key)
|
||||
|
||||
Reference in New Issue
Block a user