using System.Collections.Generic;
using System.Linq;
using System.Text;
using RimWorld;
using UnityEngine;
using Verse;
#pragma warning disable IDE1006 // Naming Styles
namespace AIImages
{
///
/// Empty window that opens when clicking the pawn button
///
[System.Diagnostics.CodeAnalysis.SuppressMessage(
"Style",
"IDE1006:Naming Styles",
Justification = "RimWorld Window naming convention"
)]
[System.Diagnostics.CodeAnalysis.SuppressMessage(
"Minor Code Smell",
"S101:Types should be named in PascalCase",
Justification = "RimWorld Window naming convention"
)]
public class Window_AIImage : Window
{
private Pawn pawn;
public Window_AIImage(Pawn pawn)
{
this.pawn = pawn;
this.doCloseX = true;
this.doCloseButton = true;
this.forcePause = false; // Не ставим игру на паузу
this.absorbInputAroundWindow = false; // Не блокируем клики вне окна
this.draggable = true; // Делаем окно перемещаемым
this.preventCameraMotion = false; // Не блокируем управление камерой
}
public override Vector2 InitialSize => new Vector2(700f, 600f);
private Vector2 scrollPosition = Vector2.zero;
///
/// Обновляет текущую пешку в окне
///
public void UpdatePawn(Pawn newPawn)
{
this.pawn = newPawn;
}
///
/// Получить текущую пешку
///
public Pawn CurrentPawn => pawn;
///
/// Вызывается каждый кадр для обновления окна
///
public override void WindowUpdate()
{
base.WindowUpdate();
// Проверяем, изменилась ли выбранная пешка
Pawn selectedPawn = Find.Selector.SelectedPawns.FirstOrDefault(p =>
p.IsColonist && p.Spawned && p.Faction == Faction.OfPlayer
);
// Если выбрана новая колонистская пешка, обновляем окно
if (selectedPawn != null && selectedPawn != pawn)
{
pawn = selectedPawn;
}
}
///
/// Получает описание внешности персонажа
///
private string GetAppearanceDescription()
{
if (pawn?.story == null)
return "Информация о внешности недоступна";
StringBuilder sb = new StringBuilder();
// Пол
sb.AppendLine($"Пол: {pawn.gender.GetLabel()}");
// Возраст
sb.AppendLine($"Возраст: {pawn.ageTracker.AgeBiologicalYears} лет");
// Тип тела
if (pawn.story.bodyType != null)
{
sb.AppendLine($"Тип тела: {pawn.story.bodyType.defName}");
}
// Цвет кожи
if (pawn.story.SkinColor != null)
{
Color skinColor = pawn.story.SkinColor;
sb.AppendLine(
$"Цвет кожи: RGB({skinColor.r:F2}, {skinColor.g:F2}, {skinColor.b:F2})"
);
}
// Волосы
if (pawn.story.hairDef != null)
{
sb.AppendLine($"Прическа: {pawn.story.hairDef.label}");
if (pawn.story.HairColor != null)
{
sb.AppendLine(
$"Цвет волос: RGB({pawn.story.HairColor.r:F2}, {pawn.story.HairColor.g:F2}, {pawn.story.HairColor.b:F2})"
);
}
}
// Черты характера
if (pawn.story.traits?.allTraits != null && pawn.story.traits.allTraits.Any())
{
sb.AppendLine("\nЧерты характера:");
foreach (var trait in pawn.story.traits.allTraits)
{
sb.AppendLine($" • {trait.LabelCap}");
}
}
return sb.ToString();
}
///
/// Получает описание одежды персонажа
///
private string GetApparelDescription()
{
if (pawn?.apparel == null)
return "Информация об одежде недоступна";
StringBuilder sb = new StringBuilder();
List wornApparel = pawn.apparel.WornApparel;
if (wornApparel == null || !wornApparel.Any())
{
sb.AppendLine("Персонаж ничего не носит");
}
else
{
sb.AppendLine($"Одежда ({wornApparel.Count} предметов):\n");
foreach (Apparel apparel in wornApparel)
{
FormatApparelItem(sb, apparel);
}
}
return sb.ToString();
}
///
/// Форматирует информацию об одном предмете одежды
///
private void FormatApparelItem(StringBuilder sb, Apparel apparel)
{
sb.AppendLine($"• {apparel.LabelCap}");
if (apparel.TryGetQuality(out QualityCategory quality))
{
sb.AppendLine($" Качество: {quality.GetLabel()}");
}
if (apparel.Stuff != null)
{
sb.AppendLine($" Материал: {apparel.Stuff.LabelCap}");
}
if (apparel.HitPoints < apparel.MaxHitPoints)
{
int percentage = (int)((float)apparel.HitPoints / apparel.MaxHitPoints * 100);
sb.AppendLine(
$" Прочность: {apparel.HitPoints}/{apparel.MaxHitPoints} ({percentage}%)"
);
}
if (apparel.DrawColor != Color.white)
{
sb.AppendLine(
$" Цвет: RGB({apparel.DrawColor.r:F2}, {apparel.DrawColor.g:F2}, {apparel.DrawColor.b:F2})"
);
}
sb.AppendLine();
}
public override void DoWindowContents(Rect inRect)
{
float curY = 0f;
// Заголовок
Text.Font = GameFont.Medium;
Widgets.Label(new Rect(0f, curY, inRect.width, 40f), "AI Image Window");
curY += 45f;
// Имя пешки
Text.Font = GameFont.Small;
Widgets.Label(
new Rect(0f, curY, inRect.width, 30f),
"Персонаж: " + pawn.NameShortColored.Resolve()
);
curY += 40f;
// Разделитель
Widgets.DrawLineHorizontal(0f, curY, inRect.width);
curY += 10f;
// Область для прокрутки контента
Rect scrollRect = new Rect(0f, curY, inRect.width, inRect.height - curY);
Rect scrollViewRect = new Rect(
0f,
0f,
scrollRect.width - 20f,
CalculateContentHeight()
);
Widgets.BeginScrollView(scrollRect, ref scrollPosition, scrollViewRect);
float contentY = 0f;
// Секция "Внешность"
Text.Font = GameFont.Medium;
Widgets.Label(new Rect(10f, contentY, scrollViewRect.width - 20f, 30f), "Внешность");
contentY += 35f;
Text.Font = GameFont.Small;
string appearanceText = GetAppearanceDescription();
float appearanceHeight = Text.CalcHeight(appearanceText, scrollViewRect.width - 30f);
Widgets.Label(
new Rect(20f, contentY, scrollViewRect.width - 30f, appearanceHeight),
appearanceText
);
contentY += appearanceHeight + 20f;
// Разделитель
Widgets.DrawLineHorizontal(10f, contentY, scrollViewRect.width - 20f);
contentY += 15f;
// Секция "Одежда"
Text.Font = GameFont.Medium;
Widgets.Label(new Rect(10f, contentY, scrollViewRect.width - 20f, 30f), "Одежда");
contentY += 35f;
Text.Font = GameFont.Small;
string apparelText = GetApparelDescription();
float apparelHeight = Text.CalcHeight(apparelText, scrollViewRect.width - 30f);
Widgets.Label(
new Rect(20f, contentY, scrollViewRect.width - 30f, apparelHeight),
apparelText
);
Widgets.EndScrollView();
}
///
/// Вычисляет высоту всего контента для прокрутки
///
private float CalculateContentHeight()
{
float height = 0f;
// Заголовок "Внешность"
height += 35f;
// Текст внешности
string appearanceText = GetAppearanceDescription();
height += Text.CalcHeight(appearanceText, 640f) + 20f;
// Разделитель
height += 15f;
// Заголовок "Одежда"
height += 35f;
// Текст одежды
string apparelText = GetApparelDescription();
height += Text.CalcHeight(apparelText, 640f) + 20f;
return height;
}
}
}