All checks were successful
SonarQube Analysis / Build and analyze (push) Successful in 1m57s
290 lines
11 KiB
C#
290 lines
11 KiB
C#
using System.Linq;
|
||
using RimWorld;
|
||
using UnityEngine;
|
||
using Verse;
|
||
|
||
namespace AIImages.Services
|
||
{
|
||
/// <summary>
|
||
/// Сервис для умного определения цветов (вместо RGB значений)
|
||
/// </summary>
|
||
public static class ColorDescriptionService
|
||
{
|
||
/// <summary>
|
||
/// Получает текстовое описание цвета волос
|
||
/// </summary>
|
||
public static string GetHairColorDescription(Color color)
|
||
{
|
||
float h,
|
||
s,
|
||
v;
|
||
Color.RGBToHSV(color, out h, out s, out v);
|
||
|
||
// Проверяем на оттенки серого
|
||
if (s < 0.15f)
|
||
{
|
||
return GetGrayscaleDescription(v);
|
||
}
|
||
|
||
// Определяем оттенок
|
||
string hueDescription = GetHueDescription(h);
|
||
string brightnessModifier = GetBrightnessModifier(v, s);
|
||
|
||
return $"{brightnessModifier}{hueDescription}".Trim();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Получает текстовое описание цвета кожи
|
||
/// Сначала проверяет специальные гены цвета кожи (зелёная, синяя и т.д.),
|
||
/// затем использует вычисленный RimWorld цвет кожи
|
||
/// </summary>
|
||
public static string GetSkinToneDescription(Pawn pawn)
|
||
{
|
||
if (pawn?.genes?.GenesListForReading == null)
|
||
return GetSkinToneDescription(pawn.story.SkinColor);
|
||
|
||
// Ищем активные гены цвета кожи (особенно специальные: зелёная, синяя, красная и т.д.)
|
||
var skinColorGenes = pawn
|
||
.genes.GenesListForReading.Where(gene =>
|
||
gene.Active && IsSpecialSkinColorGene(gene.def)
|
||
)
|
||
.ToList();
|
||
|
||
// Если есть специальные гены цвета кожи, используем их описание
|
||
if (skinColorGenes.Any())
|
||
{
|
||
var specialGene = skinColorGenes[0];
|
||
string geneDescription = GetSpecialGeneSkinTone(specialGene.def.defName);
|
||
if (!string.IsNullOrEmpty(geneDescription))
|
||
return geneDescription;
|
||
}
|
||
|
||
// Иначе RimWorld уже определил цвет текстуры пешки на основе генов (включая уровень мелатонина)
|
||
// Используем этот вычисленный цвет
|
||
return GetSkinToneDescription(pawn.story.SkinColor);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Проверяет, является ли ген специальным геном цвета кожи (зелёная, синяя, красная и т.д.)
|
||
/// </summary>
|
||
private static bool IsSpecialSkinColorGene(GeneDef geneDef)
|
||
{
|
||
if (geneDef == null)
|
||
return false;
|
||
|
||
string geneDefName = geneDef.defName;
|
||
|
||
// Специальные цвета: зелёная, синяя, красная, жёлтая, фиолетовая, оранжевая, чёрная, белая, серая
|
||
return geneDefName.StartsWith("Skin_")
|
||
&& (
|
||
geneDefName.Contains("Green")
|
||
|| geneDefName.Contains("Blue")
|
||
|| geneDefName.Contains("Red")
|
||
|| geneDefName.Contains("Yellow")
|
||
|| geneDefName.Contains("Purple")
|
||
|| geneDefName.Contains("Orange")
|
||
|| geneDefName.Contains("Black")
|
||
|| geneDefName.Contains("White")
|
||
|| geneDefName.Contains("Gray")
|
||
|| geneDefName.Contains("Grey")
|
||
|| geneDefName.Contains("Ink")
|
||
|| geneDefName.Contains("Slate")
|
||
|| geneDefName.Contains("Sheer")
|
||
|| geneDefName.Contains("Pale")
|
||
|| geneDefName.Contains("Deep")
|
||
);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Получает описание для специальных генов цвета кожи
|
||
/// </summary>
|
||
private static string GetSpecialGeneSkinTone(string geneDefName)
|
||
{
|
||
switch (geneDefName)
|
||
{
|
||
case "Skin_InkBlack":
|
||
return "ink black skin";
|
||
case "Skin_SlateGray":
|
||
return "slate gray skin";
|
||
case "Skin_LightGray":
|
||
return "light gray skin";
|
||
case "Skin_SheerWhite":
|
||
return "sheer white skin";
|
||
case "Skin_Blue":
|
||
return "blue skin";
|
||
case "Skin_Purple":
|
||
return "purple skin";
|
||
case "Skin_PaleRed":
|
||
return "pale red skin";
|
||
case "Skin_DeepRed":
|
||
return "deep red skin";
|
||
case "Skin_PaleYellow":
|
||
return "pale yellow skin";
|
||
case "Skin_DeepYellow":
|
||
return "deep yellow skin";
|
||
case "Skin_Orange":
|
||
return "orange skin";
|
||
case "Skin_Green":
|
||
return "green skin";
|
||
default:
|
||
// Пытаемся определить по названию
|
||
if (geneDefName.Contains("Green") || geneDefName.Contains("зел"))
|
||
return "green skin";
|
||
if (geneDefName.Contains("Blue") || geneDefName.Contains("син"))
|
||
return "blue skin";
|
||
if (geneDefName.Contains("Red") || geneDefName.Contains("красн"))
|
||
return "red skin";
|
||
if (geneDefName.Contains("Yellow") || geneDefName.Contains("жёлт"))
|
||
return "yellow skin";
|
||
if (geneDefName.Contains("Purple") || geneDefName.Contains("фиолет"))
|
||
return "purple skin";
|
||
if (geneDefName.Contains("Orange") || geneDefName.Contains("оранж"))
|
||
return "orange skin";
|
||
if (geneDefName.Contains("Black") || geneDefName.Contains("чёрн"))
|
||
return "black skin";
|
||
if (geneDefName.Contains("White") || geneDefName.Contains("бел"))
|
||
return "white skin";
|
||
if (
|
||
geneDefName.Contains("Gray")
|
||
|| geneDefName.Contains("Grey")
|
||
|| geneDefName.Contains("сер")
|
||
)
|
||
return "gray skin";
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Получает текстовое описание цвета кожи по RGB цвету (fallback метод)
|
||
/// </summary>
|
||
public static string GetSkinToneDescription(Color color)
|
||
{
|
||
// Вычисляем яркость
|
||
float brightness = (color.r + color.g + color.b) / 3f;
|
||
|
||
// Определяем оттенок кожи
|
||
if (brightness >= 0.85f)
|
||
return "very fair skin";
|
||
else if (brightness >= 0.75f)
|
||
return "fair skin";
|
||
else if (brightness >= 0.65f)
|
||
return "light skin";
|
||
else if (brightness >= 0.55f)
|
||
return "medium skin";
|
||
else if (brightness >= 0.45f)
|
||
return "olive skin";
|
||
else if (brightness >= 0.35f)
|
||
return "tan skin";
|
||
else if (brightness >= 0.25f)
|
||
return "brown skin";
|
||
else if (brightness >= 0.15f)
|
||
return "dark brown skin";
|
||
else
|
||
return "very dark skin";
|
||
}
|
||
|
||
/// <summary>
|
||
/// Получает описание цвета одежды
|
||
/// </summary>
|
||
public static string GetApparelColorDescription(Color color)
|
||
{
|
||
float h,
|
||
s,
|
||
v;
|
||
Color.RGBToHSV(color, out h, out s, out v);
|
||
|
||
// Проверяем на оттенки серого
|
||
if (s < 0.1f)
|
||
{
|
||
return GetGrayscaleDescription(v);
|
||
}
|
||
|
||
// Определяем оттенок
|
||
string hueDescription = GetHueDescription(h);
|
||
|
||
// Модификаторы насыщенности и яркости
|
||
string saturationModifier = "";
|
||
if (s < 0.3f)
|
||
saturationModifier = "pale ";
|
||
else if (s > 0.8f)
|
||
saturationModifier = "vivid ";
|
||
|
||
string brightnessModifier = "";
|
||
if (v < 0.3f)
|
||
brightnessModifier = "dark ";
|
||
else if (v > 0.8f)
|
||
brightnessModifier = "bright ";
|
||
|
||
return $"{brightnessModifier}{saturationModifier}{hueDescription}".Trim();
|
||
}
|
||
|
||
private static string GetGrayscaleDescription(float value)
|
||
{
|
||
if (value >= 0.95f)
|
||
return "white";
|
||
else if (value >= 0.8f)
|
||
return "light gray";
|
||
else if (value >= 0.6f)
|
||
return "gray";
|
||
else if (value >= 0.4f)
|
||
return "dark gray";
|
||
else if (value >= 0.2f)
|
||
return "charcoal";
|
||
else
|
||
return "black";
|
||
}
|
||
|
||
private static string GetHueDescription(float hue)
|
||
{
|
||
// Hue from 0 to 1
|
||
if (hue < 0.05f || hue >= 0.95f)
|
||
return "red";
|
||
if (hue < 0.083f)
|
||
return "orange-red";
|
||
if (hue < 0.15f)
|
||
return "orange";
|
||
if (hue < 0.19f)
|
||
return "golden";
|
||
if (hue < 0.22f)
|
||
return "yellow";
|
||
if (hue < 0.35f)
|
||
return "yellow-green";
|
||
if (hue < 0.45f)
|
||
return "green";
|
||
if (hue < 0.52f)
|
||
return "cyan";
|
||
if (hue < 0.58f)
|
||
return "light blue";
|
||
if (hue < 0.65f)
|
||
return "blue";
|
||
if (hue < 0.72f)
|
||
return "deep blue";
|
||
if (hue < 0.78f)
|
||
return "purple";
|
||
if (hue < 0.85f)
|
||
return "violet";
|
||
if (hue < 0.92f)
|
||
return "magenta";
|
||
|
||
return "pink";
|
||
}
|
||
|
||
private static string GetBrightnessModifier(float value, float saturation)
|
||
{
|
||
// Для волос используем специальные термины
|
||
if (value < 0.2f)
|
||
return "jet black ";
|
||
else if (value < 0.3f)
|
||
return "black ";
|
||
else if (value < 0.45f)
|
||
return "dark ";
|
||
else if (value > 0.85f && saturation < 0.3f)
|
||
return "platinum ";
|
||
else if (value > 0.75f)
|
||
return "light ";
|
||
else
|
||
return "";
|
||
}
|
||
}
|
||
}
|