diff --git a/Assemblies/AIImages.dll b/Assemblies/AIImages.dll index d3306cd..26489bc 100644 Binary files a/Assemblies/AIImages.dll and b/Assemblies/AIImages.dll differ diff --git a/Source/AIImages/Window_AIImage.cs b/Source/AIImages/Window_AIImage.cs index 0dc845c..293c55c 100644 --- a/Source/AIImages/Window_AIImage.cs +++ b/Source/AIImages/Window_AIImage.cs @@ -572,12 +572,25 @@ namespace AIImages { float contentY = startY; float lineHeight = 22f; + + contentY = DrawBasicInfo(parentRect, contentY, lineHeight); + contentY = DrawTraits(parentRect, contentY, lineHeight); + contentY = DrawGenes(parentRect, contentY, lineHeight); + contentY = DrawHediffs(parentRect, contentY, lineHeight); + DrawApparel(parentRect, contentY, lineHeight); + } + + /// + /// Отрисовывает базовую информацию о персонаже + /// + private float DrawBasicInfo(Rect parentRect, float startY, float lineHeight) + { + float contentY = startY; float labelWidth = parentRect.width * 0.45f; float valueWidth = parentRect.width * 0.50f; Text.Font = GameFont.Tiny; - // Базовая информация var info = new[] { ("AIImages.Info.Gender".Translate(), appearanceData.Gender.ToString()), @@ -618,123 +631,161 @@ namespace AIImages contentY += lineHeight; } - // Черты характера - if (pawn.story?.traits?.allTraits != null && pawn.story.traits.allTraits.Any()) - { - contentY += 15f; - Text.Font = GameFont.Small; - Widgets.Label( - new Rect(parentRect.x + 5f, contentY, parentRect.width - 10f, lineHeight), - "AIImages.Info.Traits".Translate() + ":" - ); - contentY += lineHeight + 2f; + return contentY; + } - Text.Font = GameFont.Tiny; - var traitLabels = pawn.story.traits.allTraits.Select(trait => trait.LabelCap); - foreach (var traitLabel in traitLabels) - { - Widgets.Label( - new Rect(parentRect.x + 15f, contentY, parentRect.width - 20f, lineHeight), - "• " + traitLabel - ); - contentY += lineHeight; - } + /// + /// Отрисовывает черты характера персонажа + /// + private float DrawTraits(Rect parentRect, float startY, float lineHeight) + { + float contentY = startY; + + if (pawn.story?.traits?.allTraits == null || !pawn.story.traits.allTraits.Any()) + return contentY; + + contentY += 15f; + Text.Font = GameFont.Small; + Widgets.Label( + new Rect(parentRect.x + 5f, contentY, parentRect.width - 10f, lineHeight), + "AIImages.Info.Traits".Translate() + ":" + ); + contentY += lineHeight + 2f; + + Text.Font = GameFont.Tiny; + var traitLabels = pawn.story.traits.allTraits.Select(trait => trait.LabelCap); + foreach (var traitLabel in traitLabels) + { + Widgets.Label( + new Rect(parentRect.x + 15f, contentY, parentRect.width - 20f, lineHeight), + "• " + traitLabel + ); + contentY += lineHeight; } - // Гены - if (pawn.genes?.GenesListForReading != null && pawn.genes.GenesListForReading.Any()) - { - contentY += 15f; - Text.Font = GameFont.Small; - Widgets.Label( - new Rect(parentRect.x + 5f, contentY, parentRect.width - 10f, lineHeight), - "AIImages.Info.Genes".Translate() + ":" - ); - contentY += lineHeight + 2f; + return contentY; + } - Text.Font = GameFont.Tiny; - var activeGenes = pawn.genes.GenesListForReading.Where(gene => gene.Active).ToList(); - foreach (var gene in activeGenes) - { - // Получаем лейбл гена (предпочитаем Label, если доступен, иначе LabelCap) - string geneLabel = gene.Label ?? gene.def.LabelCap; - - // Собираем дополнительную информацию - string geneInfo = geneLabel; - - // Добавляем описание, если оно есть и не слишком длинное - if (!string.IsNullOrEmpty(gene.def.description) && gene.def.description.Length < 100) - { - geneInfo += " - " + gene.def.description; - } - - // Рассчитываем высоту текста - float textHeight = Text.CalcHeight(geneInfo, parentRect.width - 25f); - - Widgets.Label( - new Rect(parentRect.x + 15f, contentY, parentRect.width - 25f, textHeight), - "• " + geneInfo - ); - contentY += textHeight; - } + /// + /// Отрисовывает гены персонажа + /// + private float DrawGenes(Rect parentRect, float startY, float lineHeight) + { + float contentY = startY; + + if (pawn.genes?.GenesListForReading == null || !pawn.genes.GenesListForReading.Any()) + return contentY; + + contentY += 15f; + Text.Font = GameFont.Small; + Widgets.Label( + new Rect(parentRect.x + 5f, contentY, parentRect.width - 10f, lineHeight), + "AIImages.Info.Genes".Translate() + ":" + ); + contentY += lineHeight + 2f; + + Text.Font = GameFont.Tiny; + var activeGenes = pawn.genes.GenesListForReading.Where(gene => gene.Active).ToList(); + foreach (var gene in activeGenes) + { + string geneInfo = BuildGeneInfo(gene); + float textHeight = Text.CalcHeight(geneInfo, parentRect.width - 25f); + + Widgets.Label( + new Rect(parentRect.x + 15f, contentY, parentRect.width - 25f, textHeight), + "• " + geneInfo + ); + contentY += textHeight; } - // Хедифы (состояния) - if (pawn.health?.hediffSet?.hediffs != null && pawn.health.hediffSet.hediffs.Any()) - { - contentY += 15f; - Text.Font = GameFont.Small; - Widgets.Label( - new Rect(parentRect.x + 5f, contentY, parentRect.width - 10f, lineHeight), - "AIImages.Info.Hediffs".Translate() + ":" - ); - contentY += lineHeight + 2f; + return contentY; + } - Text.Font = GameFont.Tiny; - var hediffLabels = pawn - .health.hediffSet.hediffs.Where(hediff => hediff.Visible) - .Select(hediff => hediff.LabelCap); - foreach (var hediffLabel in hediffLabels) + /// + /// Строит информационную строку для гена + /// + private string BuildGeneInfo(Gene gene) + { + string geneLabel = gene.Label ?? gene.def.LabelCap; + string geneInfo = geneLabel; + + if (!string.IsNullOrEmpty(gene.def.description)) + { + string description = gene.def.description; + if (description.Length > 200) { - Widgets.Label( - new Rect(parentRect.x + 15f, contentY, parentRect.width - 20f, lineHeight), - "• " + hediffLabel - ); - contentY += lineHeight; + description = description.Substring(0, 197) + "..."; } + geneInfo += " - " + description; } - // Одежда + return geneInfo; + } + + /// + /// Отрисовывает хедифы (состояния здоровья) персонажа + /// + private float DrawHediffs(Rect parentRect, float startY, float lineHeight) + { + float contentY = startY; + + if (pawn.health?.hediffSet?.hediffs == null || !pawn.health.hediffSet.hediffs.Any()) + return contentY; + + contentY += 15f; + Text.Font = GameFont.Small; + Widgets.Label( + new Rect(parentRect.x + 5f, contentY, parentRect.width - 10f, lineHeight), + "AIImages.Info.Hediffs".Translate() + ":" + ); + contentY += lineHeight + 2f; + + Text.Font = GameFont.Tiny; + var hediffLabels = pawn + .health.hediffSet.hediffs.Where(hediff => hediff.Visible) + .Select(hediff => hediff.LabelCap); + foreach (var hediffLabel in hediffLabels) + { + Widgets.Label( + new Rect(parentRect.x + 15f, contentY, parentRect.width - 20f, lineHeight), + "• " + hediffLabel + ); + contentY += lineHeight; + } + + return contentY; + } + + /// + /// Отрисовывает одежду персонажа + /// + private void DrawApparel(Rect parentRect, float startY, float lineHeight) + { + float contentY = startY; var apparel = pawn.apparel?.WornApparel; - if (apparel != null && apparel.Any()) - { - contentY += 15f; - Text.Font = GameFont.Small; - Widgets.Label( - new Rect(parentRect.x + 5f, contentY, parentRect.width - 10f, lineHeight), - "AIImages.Info.Apparel".Translate() + ":" - ); - contentY += lineHeight + 2f; - Text.Font = GameFont.Tiny; - foreach (var item in apparel) - { - var colorDesc = ColorDescriptionService.GetApparelColorDescription( - item.DrawColor - ); - string apparelLabel = $"• {colorDesc} {item.def.label}"; - float apparelHeight = Text.CalcHeight(apparelLabel, parentRect.width - 25f); - Widgets.Label( - new Rect( - parentRect.x + 15f, - contentY, - parentRect.width - 25f, - apparelHeight - ), - apparelLabel - ); - contentY += apparelHeight; - } + if (apparel == null || !apparel.Any()) + return; + + contentY += 15f; + Text.Font = GameFont.Small; + Widgets.Label( + new Rect(parentRect.x + 5f, contentY, parentRect.width - 10f, lineHeight), + "AIImages.Info.Apparel".Translate() + ":" + ); + contentY += lineHeight + 2f; + + Text.Font = GameFont.Tiny; + foreach (var item in apparel) + { + var colorDesc = ColorDescriptionService.GetApparelColorDescription(item.DrawColor); + string apparelLabel = $"• {colorDesc} {item.def.label}"; + float apparelHeight = Text.CalcHeight(apparelLabel, parentRect.width - 25f); + Widgets.Label( + new Rect(parentRect.x + 15f, contentY, parentRect.width - 25f, apparelHeight), + apparelLabel + ); + contentY += apparelHeight; } } @@ -803,79 +854,110 @@ namespace AIImages private float CalculateContentHeight() { - float height = 0f; + float height = CalculatePortraitHeight(); + height += CalculateBasicInfoHeight(); + height += CalculateTraitsHeight(); + height += CalculateGenesHeight(); + height += CalculateHediffsHeight(); + height += CalculateApparelHeight(); + height += 50f; // Дополнительный отступ + return height; + } - // Портрет персонажа (если есть) + /// + /// Рассчитывает высоту портрета персонажа + /// + private float CalculatePortraitHeight() + { if (generatedImage != null) { float portraitSize = 250f; // Максимальный размер портрета - height += portraitSize + 15f; + return portraitSize + 15f; } + return 0f; + } - // Заголовок "Информация о персонаже" - height += 35f; + /// + /// Рассчитывает высоту базовой информации + /// + private float CalculateBasicInfoHeight() + { + float height = 35f; // Заголовок "Информация о персонаже" + height += 10f; // Разделитель + height += 6 * 22f; // Базовая информация (6 строк по 22px) + return height; + } - // Разделитель - height += 10f; + /// + /// Рассчитывает высоту секции черт характера + /// + private float CalculateTraitsHeight() + { + if (pawn.story?.traits?.allTraits == null || !pawn.story.traits.allTraits.Any()) + return 0f; - // Базовая информация (6 строк по 22px) - height += 6 * 22f; + float height = 15f; // Отступ + height += 22f; // Заголовок "Черты характера" + height += 2f; // Отступ + height += pawn.story.traits.allTraits.Count * 22f; // Каждая черта + return height; + } - // Черты характера (если есть) - if (pawn.story?.traits?.allTraits != null && pawn.story.traits.allTraits.Any()) + /// + /// Рассчитывает высоту секции генов + /// + private float CalculateGenesHeight() + { + if (pawn.genes?.GenesListForReading == null || !pawn.genes.GenesListForReading.Any()) + return 0f; + + float height = 15f; // Отступ + height += 22f; // Заголовок "Гены" + height += 2f; // Отступ + + // Рассчитываем высоту для каждого гена с учетом описания + Text.Font = GameFont.Tiny; + var activeGenes = pawn.genes.GenesListForReading.Where(gene => gene.Active).ToList(); + float approximateColumnWidth = 900f * 0.35f; // Примерная ширина левой колонки + float labelWidth = approximateColumnWidth - 25f; + + foreach (var gene in activeGenes) { - height += 15f; // Отступ - height += 22f; // Заголовок "Черты характера" - height += 2f; // Отступ - height += pawn.story.traits.allTraits.Count * 22f; // Каждая черта + string geneInfo = BuildGeneInfo(gene); + height += Text.CalcHeight("• " + geneInfo, labelWidth); } - // Гены (если есть) - if (pawn.genes?.GenesListForReading != null && pawn.genes.GenesListForReading.Any()) - { - height += 15f; // Отступ - height += 22f; // Заголовок "Гены" - height += 2f; // Отступ - - // Рассчитываем высоту для каждого гена с учетом описания - Text.Font = GameFont.Tiny; - var activeGenes = pawn.genes.GenesListForReading.Where(gene => gene.Active).ToList(); - float labelWidth = parentRect.width - 25f; - foreach (var gene in activeGenes) - { - string geneLabel = gene.Label ?? gene.def.LabelCap; - string geneInfo = geneLabel; - if (!string.IsNullOrEmpty(gene.def.description) && gene.def.description.Length < 100) - { - geneInfo += " - " + gene.def.description; - } - height += Text.CalcHeight("• " + geneInfo, labelWidth); - } - } + return height; + } - // Хедифы (если есть) - if (pawn.health?.hediffSet?.hediffs != null && pawn.health.hediffSet.hediffs.Any()) - { - height += 15f; // Отступ - height += 22f; // Заголовок "Хедифы" - height += 2f; // Отступ - height += pawn.health.hediffSet.hediffs.Count(hediff => hediff.Visible) * 22f; // Каждый видимый хедиф - } + /// + /// Рассчитывает высоту секции хедифов + /// + private float CalculateHediffsHeight() + { + if (pawn.health?.hediffSet?.hediffs == null || !pawn.health.hediffSet.hediffs.Any()) + return 0f; - // Одежда (если есть) + float height = 15f; // Отступ + height += 22f; // Заголовок "Хедифы" + height += 2f; // Отступ + height += pawn.health.hediffSet.hediffs.Count(hediff => hediff.Visible) * 22f; // Каждый видимый хедиф + return height; + } + + /// + /// Рассчитывает высоту секции одежды + /// + private float CalculateApparelHeight() + { var apparel = pawn.apparel?.WornApparel; - if (apparel != null && apparel.Any()) - { - height += 15f; // Отступ - height += 22f; // Заголовок "Одежда" - height += 2f; // Отступ - // Примерно по 22-30px на предмет одежды - height += apparel.Count * 26f; - } - - // Дополнительный отступ - height += 50f; + if (apparel == null || !apparel.Any()) + return 0f; + float height = 15f; // Отступ + height += 22f; // Заголовок "Одежда" + height += 2f; // Отступ + height += apparel.Count * 26f; // Примерно по 22-30px на предмет одежды return height; }