From 1ec80a01cb746e142b6befac00fa51d037fa2fe5 Mon Sep 17 00:00:00 2001 From: Leonid Pershin Date: Fri, 31 Oct 2025 10:07:39 +0300 Subject: [PATCH] Refactor skin tone description logic in AIImages mod to prioritize gene-based descriptions over color fallback. Update ColorDescriptionService to include new methods for gene skin tone extraction. Modify related services and UI components to utilize the updated skin tone logic. Update AIImages.dll to reflect these changes. --- Assemblies/AIImages.dll | Bin 101376 -> 104448 bytes .../Services/AdvancedPromptGenerator.cs | 21 ++- .../Services/ColorDescriptionService.cs | 162 +++++++++++++++++- .../Services/PawnDescriptionService.cs | 8 +- Source/AIImages/Window_AIImage.cs | 45 ++++- 5 files changed, 215 insertions(+), 21 deletions(-) diff --git a/Assemblies/AIImages.dll b/Assemblies/AIImages.dll index 31c2c5c2abec4efe17fd75936a7682a83a6c9bdf..d3306cda103a93363cf9de6b80da613ea069631c 100644 GIT binary patch delta 36670 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 Sy+UvFf4j5(G5SQ~ZN@Jkr|QH2 delta 33198 zcmcJ&349b)vo>Dcv(IFinapJ0*9jqHg(R#&5CIWEKm}0=s|Y$W0TjbH2_SBuKm!qQ z0mTKy_eD_=MFd3@1r@g!6)`9(qNuoU;P+H@XF8I$aN#{mA38s#;vR+0Wx)=Gt}-pnii>Jd zC&WU8po{t}@M26#wR@%{M5@TfQ!!_5F0v0*lrrsF$8052JK-o&%C$6Su~MO(uw`zZ z=FCx)tj)K%W-CgzW{ti{$uQk)Y+AD~5Yw80O#^mqpYLp#Ci!bY$N2LURcrL; zgMYw(8)#MhIMCbUuLQLvWP%0~5Xa3!5?o4|SsL#=79|;+Kq|qVgsnEy^@#*{@X-j0c8y4#8qpQq+ zlP-o7?s_G4Rk~^QNtY|VwL?k$l)hSa^4SV)zA|~Ws`SzvX+xCfwDZ$Sl%3kbv_jI}KJFq_-PaQJB+d4t@rsKn?i#Q%aoEdiecESz@#V13Z_krr=SuBi%x#;BU0~ksg?5$Fyg9rUbr%>7p5} zgO~%#wI33|C=PzjIv(KW;J4bTo+(-1vEN*nwA#%TJFJaXe;0)LC#`$012HDL1>*-D z>_KUJwA$Wj1^SSLnagU^qhbx6Dr}EXa1VPPyLmxxjL(DGzCH=ogDk1jj`hjRIKXVj zj>#pDP4!rVq8O_c)}~qC)*TF~-J-^g2OnoG%CZI~fQz=<0u#0Pe(6c*4#ME@klGNX z@N|g=y-;n4(QfMZsm)A}KwqUDJ|j;1V^C~g@nWlPgwSvldcZ_i#hGo{t5>b+eaakX z_t-l-Lj5aPSmd{5@7p`1&nY#|;c;}fg@#pVLk1`3Ucy>Sk>B2`b$MLSUM^xR&t^v; zR=as{a->=+mR(U%-{+JCBhYE>Y!6)vGgr}Ns-Bs}=uUfRp@@g8s7R7-9qoYl4iR@} z>%G0jNu1eZhT?uvWQiL?fzb%X)1t74_Eum4bQO^e^NrX1OK}CP(Yl_UG3WqWR96A3 z*`NQuq1P!hYTydBh&WTks05;c8n{9~iP$0HvA3PULE;*?Lgq^C&a)Fzyp`R@|Q-&lY4r6`MY&CoGduWrS91RY} zb*PTfJLqB5S-R$Fv6;etc`!uTli=VD5su*ceFmZQ$|V)r!66ytheU-EiE4S2=pFE# zNbNGRjQFRNn(0!^gVNXKL_3 z8r)$3FM~KH&l{2_Fl!rpl2g1iU^#IHcXiMP{cOLxgQOu|spX>d3?n(i%crZ`wc_rT z4%%P>yW6X|hUUlfGG}U#Dm=;c*ut(7wX=qv75NmZJdd^EHI_>eZ;6vuk@$Vb5CxMu zG(e0ol+b!C1sye#=e<@93U>xSJk4oxo14+jKnmA$BO86xnkAJ*hg(q^qfZ!N`L%lO zfpiFDmV2-cdF=HWZ14daU{k?swZ|6B)Fz+X`>a0bM_ie)5Eh$!MMeyKrxa{J{2@2G zPp;d6o+v%4+6QC(T4W6kfKKnz_&}DT4Ih>eV-3v}q29Nedss#?_b0Y97-q#}4Q&*) z-qG6G!!n8`;?k}82{I4MNbd!a1;(MKaTaUnGvxDFv>S${rN-+HWm3+7%gkaZ4UO%l*@lmCtwlz?Z7*oI4vW|34Ntef3z^3i%+?+p zURo1XMD|XkU}LG$4@zmS8jD#*DWxXD!cPcDd(3ccKr4CW^M_ixX>sTERNYnD@bePY z0aef2riMyQ7^u>}uY3vEL{ z90^+mwmw1>YYog1$8W$f%(P!d=HQkmbyTVkHQ>u9+?x?gwWvf5T%!#cm919RXjhHu z9BHhft3s56>f=rW)eqp#!f6h40uA@)k{Xx>a1+71EVzh)HxYG)D4*2&Vx*=(7tl=Zj9c8V2}oni@Pr|)v&4`YpmQ?`K9EOE*p z(Cc)k=onA^IeJCKXA9?3!=G?s3Loag9R8RSfA}L#=C)8ooMQN+@ofKBr)RR$VI7=e z3(8Kh|7WMiIWdQ^_hhGEax#}KP|+Om$)Me*iI9(@>Y@6{7}$BCNF#<{a0(CdywKq8 z?fm&2_)9wQmv!Jn9r(r${K^jegB|#79r)LDJ|YDl?Vvc-fsgOeUZL_1{P`XD*&X=X zJMj0k@y;ULYhgT@XvAMy|9Fm;KH6EnvCT9uw5JjC zwOC2?TmL@ViqSokv$XxAb0fLv0IbACO1#Tfvj8PiXee@6WqZ=$F1Q}oC~F=TDR_#q z`+|Lu(sk%0vo&}I_*q@B)JHq8B*|qdn;iCFKeh=y_)qSrD3Lpb7h1mwdZ`QWLla$*XbIPr&xlew(I9LoHH#0Va17$a zv>(EWKa4fUX`Ra!a2d%LpNtHjvXYKM2OZW;qy4Lgt2@( ztuf~CNKXCXQJl=>3@D>OieS)Mgv_oolrf})3prmFEK~ST3}RCCEu31EsN(SK0;pK; z41jY6FVs@&mXA9JnOg1K6dJ(83SqO7FRG|i4dAL<mmv*gM*HTS*E~s?cPkmSoRt! zt8Fzhbto)!AH@2>*dpvLI-YD%Q96ZAaxU4*^6o+VW4t{PgTP7{HM|&M7r|$*sNj^o z+PC99Yt-F}@|~gW{j@(P_;pA6 zSp=GrOCfK6woMaTUsUx`R0}6H7zWtgU|XI?q09Pn&RC8&Tetxu|yr}6o*cA571nb zQgBvTFez`4jFi&{hm)*6z5k`d6vCM*oyUz1xVRuSfO8S6zPMp8uF@9hM`$Z1U6RRT zOzv47SXglfYQ;rBzjr5(1x~fN$#tV~OXi_?r)>IE+4Q+=t$RImh}jxlG@Zy63Jt&z zzeHN?F<*zfF>_vVT)yv=H5!iVarofOYh-DlP^QUs1GIgUlhwTgv@a%CrDEP=2df6^ zU`7efL)k70bvX+IC^Yjdt>=_lB}NNRNf>)Ro2h~EY^CB98ST1m0zd+`ox&vImLha5 zXKdi>RO{XKMDU_tvv!D;Z^xu~OL zI!lr|O0MAATnQrE4h*6hxNru6^Fmh+!YJy&OIuHn@Kqwb{dD0B7UqRsgES!!0tnZ$ zL@(i#6*th<`XQWqrZ#k1mJ+XBHSO&9SunXaU2Q<{%(4&ahc=Ja_D}QqI2aW!H9pLZ zSDi(+_$EI8?(VFey3}WA+0$>X7=vimV|=zH$y#k@fQU`_Bg1KbbL;A6=#NPkQld?rQK-z*v>5@m5ptyN|VU!O<0=3(rP><*Q51Mj=UF z!?pO(cP!fWP<(=53kDm7e(O+@_GKtTEg!aXq2H0n1|{@EtG`fSsFpbM z%!K)fC>`>t8K?A6&qZ6!fd$&knVXc0wY*tzC$Xa8aiLFu1|MT-@?WJeu!d9q zD#fnB8cu~YG+-!QmAu%GOH*FF$|rN?AiH0LVXw&5sLi)*BXBKJ2kU0+*^ps{6*G3L z=M3D4b{etG`~d?=ZP*Ooftw%>b{KrG&CbCS>+fb4`sZ={cvWXl>RhqDSu4FdC;n+v zQROpUa}e8V{TMEwYE!RH?HF_k)LaCCgMP===WCs=kBXQGD>7YzWl(M4gAbgvt3_&2 zG^(?mEpJ4H@xKVqF@z0Roe^0+E(zYk)m;R_Gi@=_;(ls8CKLNo?cwJ+iB|Q~6xC}A zluLhN2EiAU7xFx0qf`Ex)((}d@OB%#g?F$6wSklHbIkj6Q3HeE5}3FS^^Y^F9&>mn zBouO<%dyz0Ip(D0i6oc|4^C@BH;zCND)-BwUgL!p7?Ai)(Np+lSx`w5(J zqMvYGT?rn`Yg_hUGX%WgisV)}4Bp;RvVJH1Cq;wcXt%6Wuvt$3BQass}Tv3jELYmh}8xWH|*ws+yg=IUXWpkwYEY=#}1k8ti{OT@7<%zx;6>YU_NL#mgIZ@#=<<8%})9I@dlc&WtBHtt$4Tvu!5ugrEr{2p_jRlc|1x(-G=jM7iFBTT*ML?!jaI& z?b@F(t>f&f#~ywS{wNf69v94fhjpow`0V{pD!mM>t`z4`J&y3};$@bE+O^_zm%~S9~xpK0;|K=Mx;@6|<0uUbD4wHET1~L#De-hD$6T(ls(@ zJ6^NE2@PPW`a+$=pZ;$0NLx1pHXlN zls@Z`Mv0e;?0MWtnnp2UDP?sP6 z0RPrqEY!Q}88}oMJ_ZhM<7Pbz!riqUsnK2R5Z!f*6LeP#Qt7U4(p?uycd?SYi&L4% z`g$i>;q5ti3xCEA)CNw%N0|5NBE7plWl00eTaS5XOJA`hxP$Y54z8#S9+(O4WYJM@ z=qo+%xr~C(L*CvwEHW}k=RDuqIqZWwM|`z)4kHRJlIVZRoimwTyABQ2JLd~gzanbp zJIv@j?q9V*qP>t8n?uRSgXtzAkf5F3eeH7YzIF4aM8-?^eF?uEy6+pnzjYrA_3nEC ztyLSo=DO_ShQA2H-M1U5(S7U?-G|jpy6-Eb(tX&1;+8`1K2~z~aeB&sR_kn&tnl^{ zyoJAG2WkT+;cuDu=_0-RPOzkb<)?QaOM)+R{_nv__c0UP!=fL+A!vHua~TC+fxNx@ zSfn;chSR%`McjR&YU@5m6pA0obL)h3AG>brz8^(>p{SYvd-qASZ|K;45(0Ukbb9x- z%k}Q7iSLcJ4TMVr-zU%5tmx%vA*xD#JPYIGtyL?@o& z1at5gq|%Ai(uoUDa71ljEjp2tQ~tACJ5jR2+Z*r}{(~K;4V;93XWl2G`fX@4_H8T* z?&mr@3IXrrMDiviydQ}#vIO2@?dHF0Bf9!+R%46bp7|Y?Z0RWB0&-+62I-dAp;$xu zEncy~d0}vC$6W8SpJ!O&`mhlh^=

)EJL}Mp6WQ&fu?|syD5zIHO_lMib(Vy0+`} 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≥9pIT(b)zX=XV2*G|;(uq4>=-R#0T2eN5gp zfRhYmM%*{*<8+0A3UFWWIL$VYFJU!3LDv~5E5QwPgMo4b$E{D&Z3Ze2MB<;M+glMT zvxU|gs1}vkLK}1xvD@QU(^K@Qp-hZ-13lep3a4A?c>@iF)2;NXfdZuqk+vlxd);sQ0rJFwiX2 z`&lY8Py+I8ry2w0BHwm8!$5B#-*YtBK%XPub2P$04_7}Hzk@C^(3VK`vw#x~NNDd) znr3Iqp$co@UPYYY~)qJDAK(`twwnm{BsM$d2(CwnT4O9xF z8!PZTM=#PI9ZG0kq&E#^RJYa8y>Fn5Zf>AY48*J6Zu-(dyz1?y9}L8+-b?g{fq2z> zi7awKTxjQ2?`4WM5Ei|N@-oF6kXOAulx`qi_4ZJKfq2z>g-Q&>tKKVAZ6IFtUZq+C z@v8SK4Kfg~dV6WOfq2#1OJfYgi(X_OjW-~#di!Xafq2z>jp_}=tKMrg*Fa6^-`8n@ zfmWb@U#BHHk{G^0iP!M(T1j^}_QbzI6Wh>%_&4dPHuQb`I}u8i-N8!ADo;#!pT-(! zb?OTIAkU2k`XyxreMpZRC=ysfhp5Fs^|_e|A5pdJDpu0Ov_L`&ePy6oX(b6C)653F zGX9FL37?QzHXJMINO_NhBNUm-4|P#fQ$@doPieh@t|%Rp@EPqAw3MDMJw~6?dfA&S zr7JoOO8A_H$(3U%-R1j^j?!A=I&wzZYWjj6G|-4NH_)R7@>B%q80`|Yn~q~siaX9o z6Bn=VQ;t#eX-J-6(|j6;!-Hcqy-kN>SGrNqVPzRM7+=y619h(o04OGx(AU z1nJfOl1c^5r>V-t$X9Kk8k&&s71egIJWhj7L+34!>)(88QLJ>FEDC&$P0GXO<8M_?qGjq?l$W zd_yS)%C>|PzNLVHJl2H?C#cjw>#d6uzN2abjiuQM-&3uDR;mjVexQMZ^w$4KBLzhc zE8VNC^dm(r=Hd@4Z{w}!A1OwVZu%1?8alT8iN3n6-SQ{;T99t}GyP)d*z#wpT-t8= zGj$WBTmC||x-KHc|3U*-wwwM!g9YiPztTuU$4-Bx8*gv7{FQDNq+9+*%MBe{{zltY zw_E;3+Xd;CzthWxF2bh2)3Ac~pLWolqHm3S?Bx{gSZ8>NAl#?ud4al{KWVR_WYa(C;Jxhy{z-=f>6WA%HFRuA zO8@)YElC+5NVim!VTO(^6=l-{t(K9IfR72(O;u%^p=484DSf!rbfml=gCo^serEhr zCDTo1Oz*A0yE8c1Z(=xVN!DjwR0* zv;F<0Y(EB6!MQQhO%Vy;QK8R);_MO+74fX*FA@_yu!6P{4|5MI&)FtD(v}-d_e5>XBeCEFcZMF1DUOm_K zsFp&M%JeBzNbmL5anMoHB?0Rn9x0$T3SA>%c^~gnDYVtkG!W19N^#eb>H~11gq?Yn zY!U-K)E#NZ!t@q*lziRI?T)DE3AekoKQg-`GUjdh!2?yZ_JL zF#i9k;1LcU2fbwgj*uRGqQvbs{evVNaJ$WT#Nu{a46PS@Yu;Dl*ndabK4Mh5K264d zyQp=!&?WjX(dkA^zt)OoCNjTPR)|+}r2wHRGL2VAr45?G+7&w0<-#8ko++OHw1fYe zzp#oO{nwT;)E{q5){>83KEdyj`H^PhE#_>TjAdh~$`;&2rL+@A`#W)HzmqEPsf>Vh z#ituSRru84(;c54`1Hc3H$D#PQHY0epjJu(by6Xy8;+RP2<b3wbC3= zKaOpf-w&EX?}291VUqLTUy0A@@B`)8K1b26%1ZE;V1ukEyRa|zk-xA%c@%%)P)btR z#Z=I2njw6XY+#yX-?S5wi>R;Kqp*%y_0_mtg69@8%o z+}U_c&&RF6N$pKI-B?NkJgY^07vy}W(kPzj8bE|FFp~H8JTI2tg9}7!jvb>T`V=T=ofyTv(D zNtNPtlrrqrMk*Fe(fT%+V7at|t}@oPu(`CHKr|PnBA>%c56>YBK*eKQe5s7oFK2#$UX++m=)Ldyn zuGG3v+2brT%@h|KOj#AfOphW$7nqVvrz)SMT#6~4Zpt-svD2-lw=%9VWht-c++L=wte2CSFg0uS z?)5nykHeIog*~dwMjt;ahsiA82Kg&xFM#qxwJhaW)jrU5HTxh5XW}Ir(@_7nre96J z75`+KD_yWakCt+xIL@q?_Z26a7m0j1MR>IDp;=wZ%?@)*TmUyCUz=;qchEB#>g_H67+MD2Ly~Js_sitD4ImtXFezAF#(vr{&dR@0WK^^H2 zo3qS)yS{ENGhLScu6Ymr;QYwEUwJ=yH6gl@icifP-mjo8OaIBd&a}1aB{U^DF7ESpSfK zo3Wx)Qk`im4!Y`0H>Z3bv1XaCE&s)8))ybteXCMqzB~|TJE4>(CgT+b9-gTpA8xv? z>zTG(;s1~U7^Qq2S4mCgHF+!0;tPB$Y+2@y3hn?sR&WpK@th5|RrD5~FLG42+R97^ za{U&EslxLe6{;U5{Ai05s$+4mR;b>ao1_-1^SdyOs^TSRN19?^W!}&w)$TCmRA+%+ zmr-EPr8nbx+c%(nR$6B^rw_E(sQiGf2J_oW!-YCbFS#4+!`1(|n~Z4HuT*9yAGLRu2yp>; z#9;a$F4@sjEc=V)3FX7;9*+KEv(;SWxzNFMyrUBBw&I1JM&||Q6Uq#Gz2k&3qHv$- zgmOnJ(@42vpNUuF@s9nbML6->LzD8}bnKyD^Zw)5V_t@{yg}wJ2?rg6%zVN-$UHga zFnIhPCVs<UpWq&pDH-vs5AXi`i)v=vX*_Lo-n^q{j*~TDzQfC ziAtnw8>ew}5mg4b3et_5PWKw+Z=VzfYv z7AXAo$^wPoURfX+7H|gFBG_+LMq7$2ess-IHmCjWsLb_2vq^YN>pYwI+I%vK;*5l53mf+9vjV zy?85nj$*5RKYFQhA#%-8Z*lw?y-O_jDiL-xQ3}{A8JbjoHA~p(L^xf8Y00y8k7Z`Y z&=`kldg{oSMKzlBe~_gna!d%s2XjfvTB;iK#Q7CxljZyACI8v8AL@Vwu$ z!FegPu1Z3mFf3~WnSOKStqv?jD*Sn01Rje;LCdc|z?ub+gcq#&3Nx9;pv$)u)@`I*1YDUSs zu@372$HCZ2vF|DNJ;lDi*bfo=J%;^rC1<$t*w{HR;vOj(#!7~^<>Fzv+#a3LXQjmQRqpb7WG|E3>B*%z@{sBFD^_>`wAT-bhyybpfMCV z(?s4F8V>5Ei%o1=2O2|@M1F-S&Rc-5C>%)Zf^R$IC3eAGP8ZM=ItMg|&Ic``^`I5> z7-$cA7PKF|0(!Q{M}YRjD=j5S{ct~2k~Bg12?jqQLXV{0OVgk*DfRSr>JFuWP9^S8 z=0oy=T2H;wa?Fxh=meqjh2AUl1)-k^HCfm)M`%Bx6NENdzQ-3a<_o`0_;rj|- zCw!goO~N+`A6X}0oq(Of?-c&9@P~z0oKk>O3J^X^_`bsT6~0dRI^mmyZxVi;@au%% zDf~|14-0=dB0zCT0WK*(_$=Z33g1`wI^pYtZxX&q_;tds6Mm=gJB2?i{9)mhDDfX9 z{)NvHzHd~76@3NNiK0&UCgGceUnl%J;dctZQ~1Ne9~NGTmI9)s0O7NQ?<;&?;p>F2 z6TV6Krs&@z=;L())`?=L@H>S+Ec{{Nl^7`?MhXx2T@0MIE{5bIQBFWo28p)EownKRT19VfI==vtvWgtiE!6mc!IR_HjPjY8K7-66C^ zD5YK$;r>gN0)&nexq>VOxPq>ku1420u1{T2Q5jMBQC*^{qQ*vzi<%p?A?n{z&qw_jl^UHL z-6gtD^t$Nd(Zw64aqFopUk=Div0!gY=24Kx1dFFY?+t9l5T;YK>PcdPmPao za-N7rl>Pz!&2$@1uyGg!K2ux-g#S`9?5XxZJ5lVN;;yQOT~`X-RKcwr_djoa{=1!! zp=0Y;Nio-?aq<2NZjD-*iXwYgW@%;b^oh*I>9tB%9>eg8G7gf+GAq z-zTw$#rJqXRlJUNCitzOD!zEhU&wt1RK>esgTQYGRq=k;+2D78syMJe2mJG(Dqh1n z7yK?z6>m@R*LQb=s(2%61o)RhRh+nt0{;rAiWiqI;3tB6@fBJXFC&cx{~D-@7mO|f z{{|=?G~H>210c{5zm3y-RiA{{yPh0sMfPf>Ztp;NQo$fff1yRK+_*Q^0=+ zs^T4@so*~XRjGyeTfv7x@kH=rx&q)6P?e5Q5cD(omhk7G_@_##9@;NJRlJBZ3;dU$ zDt(19qu`y7tHFPbF{9vL2$}=_TYRlop%b8ZW{T$^_#O=?{`E0=`12#Einl77ApaQ@ zPXvF#TObPFbeIptZ*)EQ-$7M;ChRL~ND3R(ufl2(GR zq}#!Fr8~fPrMtj)qkF)2qxImc=t1yR^bq(OdJKFGJr2G*Jq5lyJq^AGZ3o|jc7X3i zyTJFN-QauEE8u(6Uhti%m-fYhGb3->TkJ)S3Ww^v&$-We*!hEVl|L+w?^5b z$3#z$elmJ{baYI7Ohe3qnDsFa$C&W1l9tDIkDU{HL+pdGn_|C-JsF$s&Uc^hzSRAU z`vvzK?gQ@M+$Y@`o@&ns<}d&jTKFBR|#Z`1etv{F(=z3L1aAJOMoZV>2tQ$<04Y z7thD@w!i+phbMIW=$F_1*1s;*%$Zvu(p{cjSaAOO_pRh@x0}R<`j_+-xU;m`50cFI zt;06SK9BYfmDwo{+l+*9bJQq&5?v9sx2uae*gPVEt~iM`f&7? zr8XsC-tvM=`NO$oXS~wCV$0~E$}>4`=ZE*du)FWNGgjWUp$ADcFI*;Az}vD^(N)zinZ0 z!f=NrlUmJpiDcK7!?TqKO>V!YX>0$rYS` zUN2^62s;ZuL8^M29(8+~%Is*-1_ex#EegKW7*&mFo;_EY7FiKv%~ZVeRvC%imZ<{S z?d+ndmsEbQ&F^VCQ}K?&BoZ!8ukl_-Ci%Th#R@RD`JiDpQEGosWG`DKhbp3%Mf8SC zL=xf|uYd$GADqLdBYC;9fl&Aj*E<{i9#6-O~D7xtsn z_(q{WNWFg${ukkY;hsC}v)SxC{9Z%@F(#TfN0eTM8# zra|7uz0Kluy^U`)4{1^cD{nM6Hz}Qzx0|15^mcRfJfH*3 z)$@Q3G|!)>WGM%m@0+J|Me@NsB`@!YcTj5;j>Or_dX3`{F!WX&c?aqJl{a7MrW|b^ zJ7396{|a)|J4j^>^KPeJJIVA_^XmCZa>WlY;C?JtR17dgOLZAmX!j4rHoIO9Jgib; z5Cw1JFU_CNS87$Hg$tBlV;Ar+XuMwW&Oz847d4k%uO#}HFn>FfjZ7YAvaR`&>y`P< zpIxu~6tmW56vm46TaGQnvazM|Mx|a!iSbUtkWjsoY{b1TNbyd>b;Q19=S|9uO2Opn z$>lY5RTC$SFRh+5VPa|dgvxH+O6w++Pp;@%U0P9BGr4Z^_zB~;Ty=}`mAU-T(wLV? zIcFGOBd)<``8tJ`&u_mdF^AVuunWa6Tiv5j)Pm+)mnhlp^w;Tf_hd`I?P(8RGuFB2 zwdNg5lxgLLbpCaQ6y67Za*_Ykg`;mg^X;#luU-TXt$(wa&s>@nuTHtAdDc>8)t1ba zSZ=n&EK}ZA&zX!X$z)t*YOq18qKVj=jmNd88r!l7K&8-3z_q6v{wsyW1mMY3fh$op ga0Mhaz;*bH=bX(YE0p)t8_TzNRw~~pOG|D42l?bpY5)KL diff --git a/Source/AIImages/Services/AdvancedPromptGenerator.cs b/Source/AIImages/Services/AdvancedPromptGenerator.cs index 6c44372..d519026 100644 --- a/Source/AIImages/Services/AdvancedPromptGenerator.cs +++ b/Source/AIImages/Services/AdvancedPromptGenerator.cs @@ -79,12 +79,13 @@ namespace AIImages.Services prompt.Append(", "); } - // 7. Цвет кожи - string skinTone = ColorDescriptionService.GetSkinToneDescription( - appearanceData.SkinColor - ); - prompt.Append(skinTone); - prompt.Append(", "); + // 7. Цвет кожи (сначала проверяем гены, затем используем цвет как fallback) + string skinTone = GetSkinToneDescription(appearanceData); + if (!string.IsNullOrEmpty(skinTone)) + { + prompt.Append(skinTone); + prompt.Append(", "); + } // 8. Волосы string hairDescription = GetHairDescription(appearanceData); @@ -200,6 +201,14 @@ namespace AIImages.Services }; } + private string GetSkinToneDescription(PawnAppearanceData data) + { + // Этот метод будет использоваться в контексте генерации промптов + // где у нас есть только данные внешности, но не сам Pawn + // Поэтому используем fallback к определению по цвету + return ColorDescriptionService.GetSkinToneDescription(data.SkinColor); + } + private string GetHairDescription(PawnAppearanceData data) { if (string.IsNullOrEmpty(data.HairDefName)) diff --git a/Source/AIImages/Services/ColorDescriptionService.cs b/Source/AIImages/Services/ColorDescriptionService.cs index 5e1c5c7..9cb6b90 100644 --- a/Source/AIImages/Services/ColorDescriptionService.cs +++ b/Source/AIImages/Services/ColorDescriptionService.cs @@ -1,4 +1,7 @@ +using System.Linq; +using RimWorld; using UnityEngine; +using Verse; namespace AIImages.Services { @@ -31,7 +34,23 @@ namespace AIImages.Services } ///

- /// Получает текстовое описание цвета кожи + /// Получает текстовое описание цвета кожи, сначала проверяя гены, затем используя цвет как fallback + /// + public static string GetSkinToneDescription(Pawn pawn) + { + // Сначала проверяем гены цвета кожи + string geneSkinTone = GetSkinToneFromGenes(pawn); + if (!string.IsNullOrEmpty(geneSkinTone)) + { + return geneSkinTone; + } + + // Fallback к определению по цвету + return GetSkinToneDescription(pawn.story.SkinColor); + } + + /// + /// Получает текстовое описание цвета кожи по RGB цвету (fallback метод) /// public static string GetSkinToneDescription(Color color) { @@ -59,6 +78,147 @@ namespace AIImages.Services return "very dark skin"; } + /// + /// Получает текстовое описание цвета кожи по генам + /// + public static string GetSkinToneFromGenes(Pawn pawn) + { + if (pawn?.genes?.GenesListForReading == null) + return null; + + // Ищем активные гены цвета кожи + var skinColorGenes = pawn + .genes.GenesListForReading.Where(gene => + gene.Active && IsSkinColorGene(gene.def.defName) + ) + .ToList(); + + if (!skinColorGenes.Any()) + return null; + + // Берем первый найденный ген (обычно у персонажа один ген цвета кожи) + var skinGene = skinColorGenes[0]; + return GetSkinToneDescriptionFromGene(skinGene.def.defName); + } + + /// + /// Проверяет, является ли ген геном цвета кожи + /// + private static bool IsSkinColorGene(string geneDefName) + { + return geneDefName.StartsWith("Skin_") + || geneDefName.Contains("SkinColor") + || geneDefName.Contains("SkinTone"); + } + + /// + /// Получает описание цвета кожи по названию гена + /// + private static string GetSkinToneDescriptionFromGene(string geneDefName) + { + // Проверяем стандартные гены + string standardGene = GetStandardGeneSkinTone(geneDefName); + if (!string.IsNullOrEmpty(standardGene)) + return standardGene; + + // Проверяем дополнительные гены + string additionalGene = GetAdditionalGeneSkinTone(geneDefName); + if (!string.IsNullOrEmpty(additionalGene)) + return additionalGene; + + // Пытаемся извлечь информацию из названия + return ExtractSkinToneFromGeneName(geneDefName); + } + + /// + /// Получает описание для стандартных генов цвета кожи + /// + private static string GetStandardGeneSkinTone(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: + return null; + } + } + + /// + /// Получает описание для дополнительных генов цвета кожи + /// + private static string GetAdditionalGeneSkinTone(string geneDefName) + { + switch (geneDefName) + { + case "Skin_Dark": + return "dark skin"; + case "Skin_Light": + return "light skin"; + case "Skin_Medium": + return "medium skin"; + case "Skin_Fair": + return "fair skin"; + case "Skin_Tan": + return "tan skin"; + case "Skin_Olive": + return "olive skin"; + case "Skin_Brown": + return "brown skin"; + default: + return null; + } + } + + /// + /// Извлекает описание цвета кожи из названия гена + /// + private static string ExtractSkinToneFromGeneName(string geneDefName) + { + if (geneDefName.Contains("Black")) + return "black skin"; + if (geneDefName.Contains("White")) + return "white skin"; + if (geneDefName.Contains("Gray") || geneDefName.Contains("Grey")) + return "gray skin"; + if (geneDefName.Contains("Blue")) + return "blue skin"; + if (geneDefName.Contains("Red")) + return "red skin"; + if (geneDefName.Contains("Green")) + return "green skin"; + if (geneDefName.Contains("Yellow")) + return "yellow skin"; + if (geneDefName.Contains("Purple")) + return "purple skin"; + if (geneDefName.Contains("Orange")) + return "orange skin"; + + return null; // Неизвестный ген + } + /// /// Получает описание цвета одежды /// diff --git a/Source/AIImages/Services/PawnDescriptionService.cs b/Source/AIImages/Services/PawnDescriptionService.cs index 18492d8..0062420 100644 --- a/Source/AIImages/Services/PawnDescriptionService.cs +++ b/Source/AIImages/Services/PawnDescriptionService.cs @@ -85,12 +85,10 @@ namespace AIImages.Services ); } - // Цвет кожи (с умным описанием) - if (pawn.story.SkinColor != null) + // Цвет кожи (с умным описанием, сначала проверяем гены) + string skinDescription = ColorDescriptionService.GetSkinToneDescription(pawn); + if (!string.IsNullOrEmpty(skinDescription)) { - string skinDescription = ColorDescriptionService.GetSkinToneDescription( - pawn.story.SkinColor - ); sb.AppendLine("AIImages.Appearance.SkinTone".Translate(skinDescription)); } diff --git a/Source/AIImages/Window_AIImage.cs b/Source/AIImages/Window_AIImage.cs index 269542c..0dc845c 100644 --- a/Source/AIImages/Window_AIImage.cs +++ b/Source/AIImages/Window_AIImage.cs @@ -585,7 +585,7 @@ namespace AIImages ("AIImages.Info.BodyType".Translate(), appearanceData.BodyType), ( "AIImages.Info.SkinTone".Translate(), - ColorDescriptionService.GetSkinToneDescription(appearanceData.SkinColor) + ColorDescriptionService.GetSkinToneDescription(pawn) ), ("AIImages.Info.Hair".Translate(), appearanceData.HairStyle), ( @@ -653,16 +653,29 @@ namespace AIImages contentY += lineHeight + 2f; Text.Font = GameFont.Tiny; - var geneLabels = pawn - .genes.GenesListForReading.Where(gene => gene.Active) - .Select(gene => gene.def.LabelCap); - foreach (var geneLabel in geneLabels) + 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 - 20f, lineHeight), - "• " + geneLabel + new Rect(parentRect.x + 15f, contentY, parentRect.width - 25f, textHeight), + "• " + geneInfo ); - contentY += lineHeight; + contentY += textHeight; } } @@ -823,7 +836,21 @@ namespace AIImages height += 15f; // Отступ height += 22f; // Заголовок "Гены" height += 2f; // Отступ - height += pawn.genes.GenesListForReading.Count(gene => gene.Active) * 22f; // Каждый активный ген + + // Рассчитываем высоту для каждого гена с учетом описания + 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); + } } // Хедифы (если есть)