sizedapparel/1.3/source/SizedApparel/SizedApparelComp.cs

1930 lines
92 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using RimWorld;
using rjw;
using Verse;
namespace SizedApparel
{
[StaticConstructorOnStartup]
public class ApparelRecorderComp : ThingComp
{
Pawn pawn;// Parent Cache
public bool recentClothFlag = true;
public bool isDrawAge = true;
public bool testbool = false;
public ApparelRecorderCompProperties Props => (ApparelRecorderCompProperties)this.props;
public bool hasUpdateBefore = false;
public bool hasUpdateBeforeSuccess = false;
public bool hasGraphicUpdatedBefore = false; // not yet
public bool needToCheckApparelGraphicRecords = false;
public bool isDirty = true;
public bool isHediffDirty = true;
public bool isApparelDirty = true;
public bool isSkeletonDirty = true;
public bool isBodyAddonDirty = true; // reset all body addon graphics.
public bool hasUnsupportedApparel = true;
public bool havingSex = false;//Obsolete
public bool hasUpdateForSex = false;//Obsolete
string cachedBodytype;
public List<ApparelGraphicRecord> cachedApparelGraphicRecord = new List<ApparelGraphicRecord>();
public Hediff breastHediff = null;
public Hediff vaginaHediff = null;
public List<Hediff> penisHediffs = null; // RJW can attach multiple penis
public Hediff anusHediff = null;
public Hediff udderHediff = null;//RJW 4.6.8: Udder is not partof chest's breast. it attached to torso.
public Color? nippleColor; //for menstruation cycles Mod
//TODO Optimize Update Hediff Filter
private bool hasBreastsAddon = false;
private bool hasVaginaAddon = false;
private bool hasPenisAddon = false;
private bool hasAnusAddon = false;
private bool hasUdderAddon = false;
private bool hasPubicHairAddon = false;
public float breastSeverity = -1;
public float BreastSeverityCache = 0;
//public float BiggestBreastSeverityInAvailableTextures = 0;
//for breasts animation or something.
public bool ForceUpdateTickAnimation = false;
public bool ForceBlockTickAnimation = false; // useful when you have make fixed pose
public bool PrePositionCache;
public Vector3? prePositionCache;
public float? preAngleCache;
public int? preTickCache;
public Vector3 preVelocity = Vector3.zero;
public float preRotation = 0;
public Dictionary<string, int> tickCache = new Dictionary<string, int>();
public BodyDef bodyDef = null;
public List<SizedApparelBodyPart> bodyAddons = new List<SizedApparelBodyPart>(); // BodyParts Added form Defs
public SkeletonDef skeletonDef; // for rebuild Skeleton
public Skeleton skeleton;
public bool skipSkeleton = false;
//native BodyParts
public SizedApparelBodyPart bodyPartBreasts;//TODO: Make this as List
public SizedApparelBodyPart bodyPartNipple;//TODO
public List<SizedApparelBodyPart> bodyPartPenises = new List<SizedApparelBodyPart>();
public List<SizedApparelBodyPart> bodyPartBalls = new List<SizedApparelBodyPart>();
public SizedApparelBodyPart bodyPartVagina;
public SizedApparelBodyPart bodyPartAnus;
public SizedApparelBodyPart bodyPartBelly;
public SizedApparelBodyPart bodyPartMuscleOverlay;//TODO
public SizedApparelBodyPart bodyPartUdder;
public SizedApparelBodyPart bodyPartHips;
public List<SizedApparelBodyPart> bodyPartThighs = new List<SizedApparelBodyPart>();
public List<SizedApparelBodyPart> bodyPartHands = new List<SizedApparelBodyPart>();
public List<SizedApparelBodyPart> bodyPartFeet = new List<SizedApparelBodyPart>();
public PubicHairDef pubicHairDef = null;
public PubicHairDef initialPubicHairDef = null; // For StyleStaitionWork
public PubicHairDef nextPubicHairDef = null; // For StyleStaitionWork
public SizedApparelBodyPart bodyPartPubicHair;
public Graphic graphicSourceNaked = null; //original Graphic
public Graphic graphicSourceRotten = null; //original Graphic
public Graphic graphicSourceFurCovered = null; //original Graphic
public Graphic graphicbaseBodyNaked = null;
public SizedApparelTexturePointDef baseBodyNakedPoints;
public Graphic graphicbaseBodyCorpse = null;
public SizedApparelTexturePointDef baseBodyCorpsePoints;
public Graphic graphicbaseBodyRotten = null;
public SizedApparelTexturePointDef baseBodyRottenPoints;
public Graphic graphicbaseBodyFurCovered = null;
public SizedApparelTexturePointDef baseBodyFurCoveredPoints;
public AlienRaceSetting raceSetting = null;
public string customPose = null;
public SizedApparelPose currentCustomPose = null;
public bool forceHorny = false;
public bool canDrawBreasts = false;
public bool canDrawPenis = false;
public bool canDrawVaginaAndAnus = false;
public bool canDrawTorsoParts = false; //belly and udder
//this may reset skeleton animation. also little have process
public void InitSkeleton()
{
skeletonDef = DefDatabase<SkeletonDef>.GetNamedSilentFail(pawn.def.defName);
if (skeletonDef == null)
{
if (raceSetting != null && raceSetting.asHuman == true) //old: !SizedApparelSettings.UnsupportedRaceToUseHumanlike
{
skeletonDef = DefDatabase<SkeletonDef>.GetNamedSilentFail("Human");
}
}
if (skeletonDef != null)
{
if (this.pawn.story == null || this.pawn.story.bodyType == null)
{
foreach (Skeleton s in skeletonDef.skeletons)
{
if (s.bodyType == null)
{
this.skeleton = new Skeleton(s);
if (SizedApparelSettings.Debug)
Log.Message("[SizedApparel] Apply SkeletonDef: pawn withouth bodytype " + pawn.Name);
return;
}
}
}
else
{
//Setting Up Skeleton
foreach (Skeleton s in skeletonDef.skeletons)
{
if (s.bodyType == this.pawn.story.bodyType.defName)
{
this.skeleton = new Skeleton(s);
if (SizedApparelSettings.Debug)
Log.Message("[SizedApparel] Apply SkeletonDef: pawn with bodytype " + pawn.Name + " with SkeletonDef : " + this.pawn.story.bodyType.defName);
return;
}
}
}
this.skeleton = null;
}
if (SizedApparelSettings.Debug)
Log.Message("[SizedApparel] Apply SkeletonDef: No Skeleton Found for " + pawn.Name);
isSkeletonDirty = false;
}
public void InitBodyAddons()
{
bodyAddons.Clear();
//TODO
//bodyDef = DefDatabase<SizedApparelBodyDef>.GetNamed(pawn.def.defName);
bodyDef = DefDatabase<BodyDef>.GetNamedSilentFail(pawn.def.defName);
//bodyDef can be null
if (bodyDef == null)
{
if (raceSetting != null && raceSetting.asHuman) //old: !SizedApparelSettings.UnsupportedRaceToUseHumanlike
{
bodyDef = DefDatabase<BodyDef>.GetNamedSilentFail("Human");
}
}
if (bodyDef != null && bodyDef.bodies != null)
{
if (pawn.story?.bodyType == null)
{
if(SizedApparelSettings.Debug)
Log.Message("[SizedApparel] Apply BodyDef: pawn has no bodytype " + pawn.Name);
BodyWithBodyType body = null;
if(!bodyDef.bodies.NullOrEmpty())
body = bodyDef.bodies[0];
if (body != null && body.Addons != null)
{
foreach (var bodyaddon in body.Addons)
{
if (bodyaddon == null)
continue;
var a = new SizedApparelBodyPart(pawn, this, bodyaddon.partName, bodyaddon.bodyPartOf, bodyaddon.defaultHediffName, bodyaddon.isBreasts, false, bodyaddon.customPath, bodyaddon.colorType, bodyaddon.mustHaveBone);
a.SetDepthOffsets(bodyaddon.depthOffset.south, bodyaddon.depthOffset.north, bodyaddon.depthOffset.east, bodyaddon.depthOffset.west);
//a.SetDepthOffsets(bodyaddon.depthOffset);
a.SetCenteredTexture(bodyaddon.centeredTexture);
bodyAddons.Add(a);
break;
}
}
}
else
{
foreach (BodyWithBodyType body in bodyDef.bodies)
{
if (body.bodyType != null && body.bodyType == this.pawn.story.bodyType.defName)
{
if (SizedApparelSettings.Debug)
Log.Message("[SizedApparel] Apply BodyDef: matched BodyTyped Body for " + pawn.Name);
if (body != null && body.Addons != null)
{
foreach (var bodyaddon in body.Addons)
{
if (bodyaddon == null)
continue;
var a = new SizedApparelBodyPart(pawn, this, bodyaddon.partName, bodyaddon.bodyPartOf, bodyaddon.defaultHediffName, bodyaddon.isBreasts, false, bodyaddon.customPath, bodyaddon.colorType, bodyaddon.mustHaveBone);
a.SetDepthOffsets(bodyaddon.depthOffset.south, bodyaddon.depthOffset.north, bodyaddon.depthOffset.east, bodyaddon.depthOffset.west);
//a.SetDepthOffsets(bodyaddon.depthOffset);
a.SetCenteredTexture(bodyaddon.centeredTexture);
bodyAddons.Add(a);
}
}
break;
}
}
}
}
else
{
if (SizedApparelSettings.Debug)
Log.Message("[SizedApparel] Cannot find BodyDef for " + pawn.def.defName);
}
//bodyPartBreasts = new SizedApparelBodyPart(pawn, this, "Breasts", SizedApparelBodyPartOf.Breasts, "Breasts", true, false, null);
//bodyPartBreasts.SetDepthOffsets(0.0113f, 0.001f, 0.0113f, 0.0113f);
//bodyPartBreasts.SetPositionOffsets(Vector2.one, Vector2.one, Vector2.one, Vector2.one);
//bodyPartBreasts.scale = 2f;
//Nipple. should I separate from Breats?
//bodyPartNipple = new SizedApparelBodyPart(pawn, this, "Nippple", SizedApparelBodyPartOf.Breasts, "Breasts", true, false);
//bodyPartBreasts.SetDepthOffsets(0.0114f, 0.000f, 0.0114f, 0.0114f);
//bodyPartUdder = new SizedApparelBodyPart(pawn, this, "Udder", SizedApparelBodyPartOf.Udder, "UdderBreasts", true, false);
//bodyPartUdder.SetDepthOffsets(0.0112f, 0.0005f, 0.0112f, 0.0112f);
//UdderNipple...?
//bodyPartUdder = new SizedApparelBodyPart(p, "Udder", SizedApparelBodyPartOf.Udder, "UdderBreasts", true, false);
//bodyPartUdder.SetDepthOffsets(0.0112f, 0.0005f, 0.0112f, 0.0112f);\
//bodyPartVagina = new SizedApparelBodyPart(pawn, this, "Vagina", SizedApparelBodyPartOf.Vagina, "Vagina", false, false);
//bodyPartVagina.SetDepthOffsets(0.0088f, 0.0100f, 0.0088f, 0.0088f);
//bodyPartAnus = new SizedApparelBodyPart(pawn, this, "Anus", SizedApparelBodyPartOf.Anus, "Anus", false, false);
//bodyPartAnus.SetDepthOffsets(0.0093f, 0.0105f, 0.0093f, 0.0093f);
//bodyPartBelly = new SizedApparelBodyPart(pawn, this, "Belly", SizedApparelBodyPartOf.Belly, "BellyBulge", false, false);
//bodyPartBelly.SetDepthOffsets(0.0098f, 0.0002f, 0.0098f, 0.0098f);
//bodyPartPubicHair = new SizedApparelBodyPart(pawn, this, "PubicHair", SizedApparelBodyPartOf.PubicHair, "Default", false, false, null, ColorType.Hair);
//bodyPartPubicHair.SetDepthOffsets(0.0099f, 0.0099f, 0.0089f, 0.0089f);
}
public void ResetBodyAddonBoneLink()
{
string s;
foreach(var a in bodyAddons)
{
s = a.bone?.name;
if (s == null)
continue;
a.SetBone(skeleton.FindBone(s));
}
}
public override void Initialize(CompProperties props)
{
base.Initialize(props);
this.pawn = this.parent as Pawn;
}
public override void PostDeSpawn(Map map)
{
base.PostDeSpawn(map);
}
public override void PostSpawnSetup(bool respawningAfterLoad)
{
base.PostSpawnSetup(respawningAfterLoad);
UpdateRaceSettingData(); // include race Setting
InitSkeleton();
InitBodyAddons();
}
public override void PostExposeData()
{
base.PostExposeData();
Scribe_Values.Look<string>(ref customPose, "customPose"); // save pawn's custom pose. Each bodyparts will not saved.
Scribe_Defs.Look<PubicHairDef>(ref pubicHairDef, "PubicHairDef");
if (pubicHairDef == null)
{
pubicHairDef = SizedApparelUtility.GetRandomPubicHair();
}
//Scribe_Values.Look<>(); //TODO: save pubic hair data
}
/*
public override void CompTick()
{
if (PrePositionCache)
{
}
base.CompTick();
}*/
/*
public override void CompTickRare()
{
base.CompTickRare();
}*/
float penisAngle = 0;
public void SetPenisAngle(float angle)
{
penisAngle = angle;
if(this.skeleton != null)
{
Bone penisBone = skeleton.FindBone("Penis");
if (penisBone != null)
{
//Log.Message("SetPenisAngle : " + angle.ToString());
penisBone.SetAngle(angle);
}
}
bool penisDown = false;
if (angle >= 120 && angle <= 250)
penisDown = true;
foreach (var p in bodyPartPenises)
{
if (penisDown)
{
p.SetCustomPose("PenisDown");
}
else
{
p.SetCustomPose(null);
}
}
}
//do not call this in character creation from new game.
public void SetBreastJiggle(bool jiggle, int cooltime = 5, bool checkApparelForCanPose = false)
{
//SetJiggle has cooltime.
bool flag1 = true;
//should set apparels pose?
//Use First BodyAddon which is partof Breasts
foreach(var a in GetSizedApparelBodyParts(SizedApparelBodyPartOf.Breasts))
{
if (flag1)
{
if (Find.TickManager.TicksGame < a.lastPoseTick + cooltime)
return;
flag1 = false;
}
if (jiggle)
{
bool flag2 = true;
if (flag2 && checkApparelForCanPose)
{
if (!a.CheckCanPose("JiggleUp", true, false, true, true, false))
return;
flag2 = false;
}
//may need to check apparels for aply pose
//bodyPartBreasts.CheckCanPose("JiggleUp",)
a.SetCustomPose("JiggleUp");
}
else
{
//SetPoseFromPoseSet(null);
a.SetCustomPose(null);
}
}
}
string[] testPose = { null, "JiggleUp", "JiggleCenter" };
string[] testPose2 = { null, "PenisDown" };
public void UpdateTickAnim(Vector3 rootLoc, float angle) // call this in DrawPawnBody <- only called when it rendered
{
if (ForceBlockTickAnimation)// prevent breasts jiggle from other pose
return;
if (skeleton == null)
return;
if (Find.CameraDriver == null)
return;
//do not calculate physics camera is far
if (Find.CameraDriver.CurrentZoom >= CameraZoomRange.Furthest)
return;
//int IdTick = parent.thingIDNumber * 20; //hint from yayo animation mod
if (!SizedApparelUtility.CanApplySizedApparel(pawn))
return;
if (SizedApparelSettings.breastsPhysics || ForceUpdateTickAnimation)//SizedApparelSettings.autoJiggleBreasts
{
int tick;
if (this.preTickCache != null)
tick = Find.TickManager.TicksGame - this.preTickCache.Value;
else
tick = Find.TickManager.TicksGame;
//if tick is not updated, don't update animation.
if (tick == 0)
return;
Vector3 velocity;
if (this.prePositionCache != null)
velocity = (rootLoc - this.prePositionCache.Value);// /tick
else
velocity = Vector3.zero;
float rotation;
if (this.preAngleCache != null)
rotation = angle - this.preAngleCache.Value;
else
rotation = 0;
float rotAcc = rotation - preRotation;
//Log.Message(velocity.ToString() + " , " + preVelocity.ToString());
//UnityEngine's vector.normalize is safe for zero vector
//(Vector3.Dot(velocity.normalized, preVelocity.normalized)) < 0.2f
float dotV = Vector3.Dot(velocity.normalized, preVelocity.normalized);
float velocityOffset = (velocity - preVelocity).magnitude;
//Log.Message(pawn.ToString());
//Log.Message("rotAcc : " + rotAcc.ToString());
//Log.Message("Velocity.x : " + velocity.x.ToString());
//Log.Message("Velocity.z : " + velocity.z.ToString());
//Log.Message("dotV : " + dotV.ToString());
//Log.Message("velocityOffset : " + velocityOffset.ToString());
//&& dotV > 0.4f
if (((preVelocity != Vector3.zero && velocityOffset >= 0.02))|| Mathf.Abs(rotAcc) > 0.5) //(dotV == 0 ? 0:1), Mathf.Abs(dotV) // || Mathf.Abs(rotation) > 20
{
//tickCache.Add("BreastsJiggleUp", Find.TickManager.TicksGame);
SetBreastJiggle(true,10,true);
}
else
{
SetBreastJiggle(false,10, false);
}
//cache pre data
this.prePositionCache = rootLoc;
this.preAngleCache = angle;
this.preRotation = rotation;
this.preTickCache = Find.TickManager.TicksGame;
this.preVelocity = velocity;
}
//SetPoseFromPoseSet(testPose2.RandomElement());
}
public bool isApparelGraphicRecordChanged()
{
if (pawn == null)
return false;
var apparelGraphics = pawn.Drawer?.renderer?.graphics?.apparelGraphics;
if (apparelGraphics == null)
return false;
//return false; //since 1.3 broken. force to return false;
if (!apparelGraphics.SequenceEqual(cachedApparelGraphicRecord))
{
if (SizedApparelSettings.Debug)
Log.Message("[SizedApparel]:" + pawn + "'s apparel Record Changed! need to updating comp");
return true;
}
return false;
}
public void DrawAllBodyParts(Vector3 rootLoc, float angle, Rot4 facing, RotDrawMode bodyDrawType, PawnRenderFlags flags, Pawn ___pawn, Mesh bodyMesh)
{
if (this.isDrawAge && (!flags.FlagSet(PawnRenderFlags.Clothes) || !this.hasUnsupportedApparel || SizedApparelUtility.isPawnNaked(___pawn))) //TODO : Move it to CanDraw
{
if (bodyDrawType != RotDrawMode.Dessicated && SizedApparelSettings.drawVagina && SizedApparelUtility.CanDrawVagina(___pawn, flags))
{
//if (this.bodyPartVagina != null)
// this.bodyPartVagina.DrawBodyPart(rootLoc, angle, facing, bodyDrawType, flags, bodyMesh);
foreach (var b in GetSizedApparelBodyParts(SizedApparelBodyPartOf.Vagina))
{
b.DrawBodyPart(rootLoc, angle, facing, bodyDrawType, flags, bodyMesh);
}
}
if (bodyDrawType != RotDrawMode.Dessicated && SizedApparelSettings.drawAnus && SizedApparelUtility.CanDrawAnus(___pawn, flags))
{
//if (this.bodyPartAnus != null)
// this.bodyPartAnus.DrawBodyPart(rootLoc, angle, facing, bodyDrawType, flags, bodyMesh);
foreach (var b in GetSizedApparelBodyParts(SizedApparelBodyPartOf.Anus))
{
b.DrawBodyPart(rootLoc, angle, facing, bodyDrawType, flags, bodyMesh);
}
}
if (bodyDrawType != RotDrawMode.Dessicated && SizedApparelSettings.drawBelly && SizedApparelUtility.CanDrawBelly(___pawn, flags))
{
//if (this.bodyPartBelly != null)
// this.bodyPartBelly.DrawBodyPart(rootLoc, angle, facing, bodyDrawType, flags, bodyMesh);
foreach (var b in GetSizedApparelBodyParts(SizedApparelBodyPartOf.Belly))
{
b.DrawBodyPart(rootLoc, angle, facing, bodyDrawType, flags, bodyMesh);
}
}
//Draw Pubic Hair
if (bodyDrawType != RotDrawMode.Dessicated && SizedApparelSettings.drawPubicHair && SizedApparelUtility.CanDrawPubicHair(___pawn, flags))
{
if (this.bodyPartPubicHair != null)
this.bodyPartPubicHair.DrawBodyPart(rootLoc, angle, facing, bodyDrawType, flags, bodyMesh);
foreach (var b in GetSizedApparelBodyParts(SizedApparelBodyPartOf.PubicHair))
{
b.DrawBodyPart(rootLoc, angle, facing, bodyDrawType, flags, bodyMesh);
}
}
if (bodyDrawType != RotDrawMode.Dessicated && SizedApparelSettings.drawUdder && SizedApparelUtility.CanDrawUdder(___pawn, flags))
{
//if (this.bodyPartUdder != null)
// this.bodyPartUdder.DrawBodyPart(rootLoc, angle, facing, bodyDrawType, flags, bodyMesh);
foreach (var b in GetSizedApparelBodyParts(SizedApparelBodyPartOf.Udder))
{
b.DrawBodyPart(rootLoc, angle, facing, bodyDrawType, flags, bodyMesh);
}
}
if (bodyDrawType != RotDrawMode.Dessicated && SizedApparelSettings.drawBreasts && SizedApparelUtility.CanDrawBreasts(___pawn, flags) && (SizedApparelSettings.drawSizedApparelBreastsOnlyWorn ? !SizedApparelUtility.isPawnNaked(___pawn, flags) : true))
{
//if (this.bodyPartBreasts != null)
// this.bodyPartBreasts.DrawBodyPart(rootLoc, angle, facing, bodyDrawType, flags, bodyMesh);
foreach (var b in GetSizedApparelBodyParts(SizedApparelBodyPartOf.Breasts))
{
b.DrawBodyPart(rootLoc, angle, facing, bodyDrawType, flags, bodyMesh);
}
}
if (bodyDrawType != RotDrawMode.Dessicated && SizedApparelSettings.drawPenis && SizedApparelUtility.CanDrawPenis(___pawn, flags, true))
{
if (SizedApparelSettings.hideBallOfFuta ? !Genital_Helper.is_futa(___pawn) : true)
{
/*
foreach (SizedApparelBodyPart b in this.bodyPartBalls)
{
b.DrawBodyPart(rootLoc, angle, facing, bodyDrawType, flags, bodyMesh);
}*/
foreach (var b in GetSizedApparelBodyParts(SizedApparelBodyPartOf.Balls))
{
b.DrawBodyPart(rootLoc, angle, facing, bodyDrawType, flags, bodyMesh);
}
}
/*
foreach (SizedApparelBodyPart p in this.bodyPartPenises)
{
p.DrawBodyPart(rootLoc, angle, facing, bodyDrawType, flags, bodyMesh);
}*/
foreach (var b in GetSizedApparelBodyParts(SizedApparelBodyPartOf.Penis))
{
b.DrawBodyPart(rootLoc, angle, facing, bodyDrawType, flags, bodyMesh);
}
}//Draw BodyParts
//Draw Modular Apparel Parts... TODO...? Is it passible?
if (flags.FlagSet(PawnRenderFlags.Clothes))
{
}
}
}
//not working
public override void PostPostMake()
{
/*
Pawn pawn;
try
{
pawn = (Pawn)parent;
if (pawn != null)
{
if (!pawn.RaceProps.Humanlike)
return;
pawn.Drawer.renderer.graphics.ResolveAllGraphics();
if (SizedApparelSettings.Debug)
Log.Message("[SizedApparels] Component Inint And Resolve all Graphics for "+ pawn.Name);
}
}
catch
{
}
*/
}
public void ClearHediffs()
{
breastHediff = null;
vaginaHediff = null;
if(penisHediffs != null)
penisHediffs.Clear();
anusHediff = null;
udderHediff = null;
}
public void ClearBreastCacheValue()
{
breastHediff = null;
breastSeverity = -1;
BreastSeverityCache = 0;
}
public void ClearPenisCacheValue()
{
//TODO
}
public void ClearCanDraw()
{
canDrawBreasts = false;
canDrawPenis = false;
canDrawTorsoParts = false;
canDrawVaginaAndAnus = false;
}
public void ClearGraphics(bool clearBreasts = true)
{
//Since Injection of base body is now in Matarial. no need to keep
graphicSourceNaked = null;
graphicSourceFurCovered = null;
graphicSourceRotten = null;
hasGraphicUpdatedBefore = false;
graphicbaseBodyNaked = null;
graphicbaseBodyRotten = null;
graphicbaseBodyFurCovered = null;
return;
//Clear BodyParts
if (clearBreasts && bodyPartBreasts!= null)
bodyPartBreasts.Clear();
if(bodyPartAnus != null)
bodyPartAnus.Clear();
if (bodyPartBelly != null)
bodyPartBelly.Clear();
if (bodyPartVagina != null)
bodyPartVagina.Clear();
if (bodyPartPubicHair != null)
bodyPartPubicHair.Clear();
foreach(var a in bodyAddons)
{
a.Clear();
}
}
public void ClearAll(bool clearGraphics = true)
{
ClearBreastCacheValue();
if(clearGraphics)
ClearGraphics();
ClearHediffs();
ClearCanDraw();
hasUnsupportedApparel = false;
hasUpdateBefore = false;
hasUpdateBeforeSuccess = false;
needToCheckApparelGraphicRecords = false;
}
public void SetDirty(bool clearPawnGraphicSet = false, bool dirtyHediff = true, bool dirtyApparel = true, bool dirtySkeleton = false, bool dirtyBodyAddons = false)
{
this.isDirty = true;
this.isHediffDirty = dirtyHediff;
this.isApparelDirty = dirtyApparel;
this.isSkeletonDirty = dirtySkeleton;
this.isBodyAddonDirty = dirtyBodyAddons;
if (clearPawnGraphicSet)
{
if (pawn == null)
return;
if (pawn.Drawer == null)
return;
if (pawn.Drawer.renderer == null)
return;
pawn.Drawer.renderer.graphics.ClearCache();
}
}
public void UpdateRaceSettingData()
{
if (pawn == null)
return;
var loc_raceSetting = SizedApparelSettings.alienRaceSettings.FirstOrDefault((AlienRaceSetting s) => s.raceName == pawn.def.defName);
if (loc_raceSetting == null)
return;
raceSetting = loc_raceSetting;
}
public void CheckAgeChanged()
{
if (pawn == null)
return;
if (pawn.ageTracker == null)
return;
//TODO. Cleanup
UpdateRaceSettingData();
if (raceSetting == null)
return;
if (raceSetting.drawMinAge < 0 || pawn.ageTracker.AgeBiologicalYearsFloat >= raceSetting.drawMinAge)
isDrawAge = true;
else
isDrawAge = false;
}
public void FindAndApplyBodyGraphic(Pawn pawn, Graphic sourceGraphic, ref Graphic targetGraphicBaseBody, ref Graphic cachedSourceGraphic, string debugName)
{
const string baseBodyString = "_BaseBody";
string baseBodyStringWithSex;
if (SizedApparelSettings.useGenderSpecificTexture)
{
if (pawn.gender == Gender.Female)
{
baseBodyStringWithSex = baseBodyString + "F";
}
else if (pawn.gender == Gender.Male)
{
baseBodyStringWithSex = baseBodyString + "M";
}
else
{
baseBodyStringWithSex = baseBodyString; // + "N" //Does it need to add N?
}
}
else
baseBodyStringWithSex = baseBodyString;
string targetGraphicPath = null;
if (sourceGraphic != null)
{
//path = path.Insert(Math.Max(path.LastIndexOf('/'), 0), "/CustomPose/"+ customPose);
if (cachedSourceGraphic == null)
cachedSourceGraphic = sourceGraphic;
targetGraphicPath = cachedSourceGraphic.path;
if (customPose != null)
targetGraphicPath = targetGraphicPath.Insert(Math.Max(targetGraphicPath.LastIndexOf('/'), 0), "/CustomPose/" + customPose);
if (!targetGraphicPath.Contains(baseBodyString))
{
if (SizedApparelSettings.useGenderSpecificTexture && pawn.gender != Gender.None)
{
if (targetGraphicBaseBody == null)
{
if (ContentFinder<Texture2D>.Get((targetGraphicPath + baseBodyStringWithSex + "_south"), false) != null)
{
//cachedSourceGraphic = sourceGraphic;
Shader shader = sourceGraphic.Shader;
//if (!ShaderUtility.SupportsMaskTex(shader))
// shader = ShaderDatabase.CutoutSkinOverlay;
targetGraphicBaseBody = GraphicDatabase.Get<Graphic_Multi>(targetGraphicPath + baseBodyStringWithSex, shader, sourceGraphic.drawSize, sourceGraphic.color, sourceGraphic.colorTwo, sourceGraphic.data);
//sourceGraphic = targetGraphicBaseBody;
}
else if (customPose != null)
{
targetGraphicPath = sourceGraphic.path;
if (ContentFinder<Texture2D>.Get((targetGraphicPath + baseBodyStringWithSex + "_south"), false) != null)
{
//cachedSourceGraphic = sourceGraphic;
Shader shader = sourceGraphic.Shader;
//if (!ShaderUtility.SupportsMaskTex(shader))
// shader = ShaderDatabase.CutoutSkinOverlay;
targetGraphicBaseBody = GraphicDatabase.Get<Graphic_Multi>(targetGraphicPath + baseBodyStringWithSex, shader, sourceGraphic.drawSize, sourceGraphic.color, sourceGraphic.colorTwo, sourceGraphic.data);
//sourceGraphic = targetGraphicBaseBody;
}
else
{
if (SizedApparelSettings.Debug)
Log.Warning("[SizedApparel] Missing BaseBodyTexture for "+ debugName + " Graphic: " + targetGraphicPath + baseBodyStringWithSex + "_south");
}
}
}
}
if (targetGraphicBaseBody == null)
{
if (ContentFinder<Texture2D>.Get((targetGraphicPath + baseBodyString + "_south"), false) != null)
{
// cachedSourceGraphic = sourceGraphic;
Shader shader = sourceGraphic.Shader;
//if (!ShaderUtility.SupportsMaskTex(shader))
// shader = ShaderDatabase.CutoutSkinOverlay;
targetGraphicBaseBody = GraphicDatabase.Get<Graphic_Multi>(targetGraphicPath + baseBodyString, shader, sourceGraphic.drawSize, sourceGraphic.color, sourceGraphic.colorTwo, sourceGraphic.data);
//sourceGraphic = targetGraphicBaseBody;
}
else if (customPose != null)
{
targetGraphicPath = sourceGraphic.path;
if (ContentFinder<Texture2D>.Get((targetGraphicPath + baseBodyString + "_south"), false) != null)
{
//cachedSourceGraphic = sourceGraphic;
Shader shader = sourceGraphic.Shader;
//if (!ShaderUtility.SupportsMaskTex(shader))
// shader = ShaderDatabase.CutoutSkinOverlay;
targetGraphicBaseBody = GraphicDatabase.Get<Graphic_Multi>(targetGraphicPath + baseBodyString, shader, sourceGraphic.drawSize, sourceGraphic.color, sourceGraphic.colorTwo, sourceGraphic.data);
//sourceGraphic = targetGraphicBaseBody;
}
else
{
if (SizedApparelSettings.Debug)
Log.Warning("[SizedApparel] Missing BaseBodyTexture for " + debugName + " Graphic: " + targetGraphicPath + baseBodyString + "_south");
}
}
}
}
else
targetGraphicBaseBody = sourceGraphic;
}
}
public void Update(bool cache = true, bool fromGraphicRecord = true, bool updateGraphics = true, bool CheckApparel = true)
{
if (cache)
recentClothFlag = CheckApparel;
isDirty = false;
bool flag = fromGraphicRecord;
needToCheckApparelGraphicRecords = false;
//flag = false; //TODO:fromGraphicRecord is forced not to do for a while. it will update later
UpdateRaceSettingData();
if (!hasUpdateBefore)
{
InitSkeleton();
InitBodyAddons();
hasUpdateBefore = true;
}
else
{
//check is bodytype changed
if(cachedBodytype != pawn.story?.bodyType?.defName)
{
isSkeletonDirty = true;
}
if (isSkeletonDirty)
{
InitSkeleton();
if (isBodyAddonDirty)
InitBodyAddons();
else
ResetBodyAddonBoneLink();
}
else
{
if (isBodyAddonDirty)
InitBodyAddons();
}
}
if (skeleton == null)
{
if (Find.CurrentMap != null)
return;
}
if (!SizedApparelUtility.CanApplySizedApparel(pawn))
return;
if (pubicHairDef == null)
{
pubicHairDef = SizedApparelUtility.GetRandomPubicHair();
}
if (SizedApparelSettings.Debug)
Log.Message("[SizedApparel] Updating Component of " + pawn.Name);
if (updateGraphics)
{
ClearGraphics();
//ClearHediffs();
}
//float breastSeverityCapped = 1000;
string bodyTypeDefName = null;
if (pawn.story != null)
bodyTypeDefName = pawn.story.bodyType?.defName;
float bellySeverity = 0;
if (isHediffDirty) //Update Hediff Data
{
ClearHediffs();
if(SizedApparelSettings.drawPenis || SizedApparelSettings.drawVagina || SizedApparelSettings.drawAnus)
{
BodyPartRecord genitalPart = Genital_Helper.get_genitalsBPR(pawn);
if (genitalPart != null)
{
var genitalList = Genital_Helper.get_PartsHediffList(pawn, genitalPart);
if (!genitalList.NullOrEmpty())
{
if (SizedApparelSettings.Debug)
{
foreach (var g in genitalList)
{
Log.Message(" [SizedApparel] " + pawn.Name + "has hediff in genital (" + g.def.defName + ")");
}
}
//penisHediffs = genitalList.FindAll((Hediff h) => SizedApparelUtility.isPenis(h.def.defName));
penisHediffs = genitalList.FindAll((Hediff h) => Genital_Helper.is_penis(h));
//vaginaHediff = genitalList.FirstOrDefault((Hediff h) => SizedApparelUtility.isVagina(h.def.defName));
vaginaHediff = genitalList.FirstOrDefault((Hediff h) => Genital_Helper.is_vagina(h));
}
}
}
if (SizedApparelSettings.drawBelly)
{
//EggImplement as Pregnant
//need to Optimize... TODO...
List<Hediff> pregnancies = pawn.health?.hediffSet?.hediffs?.FindAll((Hediff h) => SizedApparelUtility.isPragnencyHediff(h) || SizedApparelUtility.isRJWEggHediff(h));//pregnancy and pregnant. has some issue with "pregnancy mood"
if (!pregnancies.NullOrEmpty())
{
foreach (Hediff h in pregnancies)
{
//Set Labor Belly as Big Belly.
//Code for 1.4
/*
if (h.def == HediffDefOf.PregnancyLabor || h.def == HediffDefOf.PregnancyLaborPushing)
bellySeverity = Math.Max(bellySeverity, 1f);
else
bellySeverity = Math.Max(bellySeverity, h.Severity);
*/
bellySeverity = Math.Max(bellySeverity, h.Severity);
}
}
//Licentia Lab Hediff
if (SizedApparelPatch.LicentiaActive)
{
Hediff cumflation = pawn.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("Cumflation"));
Hediff cumstuffed = pawn.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("Cumstuffed"));
bellySeverity += cumflation != null ? cumflation.Severity : 0;
bellySeverity += cumstuffed != null ? cumstuffed.Severity : 0;
}
}
}
CheckAgeChanged();
if (SizedApparelSettings.drawBreasts)
{
SizedApparelUtility.GetBreastSeverity(pawn, out breastSeverity, out breastHediff);
}
if (breastHediff != null)
{
//get nipple color from Menstruation.
if (SizedApparelPatch.MenstruationActive)
{
nippleColor = Patch_Menstruation.GetNippleColor(breastHediff);
}
if (pawn.gender == Gender.Male && !SizedApparelSettings.ApplyApparelPatchForMale)
{
CheckApparel = false;
}
if (CheckApparel || this.isApparelDirty)
{
hasUnsupportedApparel = SizedApparelUtility.hasUnSupportedApparelFromWornData(pawn, breastSeverity, breastHediff, true, flag);
}
else
{
hasUnsupportedApparel = false;
}
//float validBreastTextureSeverity = SizedApparelUtility.GetBreastSeverityValidTextures(pawn, breastHediff);
if (SizedApparelSettings.useBreastSizeCapForApparels) // && hasUnsupportedApparel
{
BreastSeverityCache = Math.Min(BreastSeverityCache, breastSeverity);
}
else
{
BreastSeverityCache = 1000;
}
//if (SizedApparelSettings.useBreastSizeCapForApparels) //SizedApparelSettings.useBreastSizeCapForApparels //wip
// breastSeverityCapped = Math.Min(BreastSeverityCache, breastSeverityCapped);
//float validBreastTextureSeverity = SizedApparelUtility.GetBreastSeverityValidTextures(pawn, breastHediff);
//breast cache forApparel brests Check. This ignore variation!
//SizedApparelMod.CheckAndLoadAlienRaces();
var key = new SizedApparelsDatabase.BodyPartDatabaseKey(pawn.def.defName, pawn.story?.bodyType?.defName, breastHediff.def.defName, "Breasts", pawn.gender ,SizedApparelUtility.BreastSeverityInt(breastHediff.Severity));
var raceSetting = SizedApparelSettings.alienRaceSettings.FirstOrDefault((AlienRaceSetting s) => s.raceName == key.raceName);
//TODO? Remove ValidBreastsTextureCheck...
float validBreastTextureSeverity = SizedApparelUtility.BreastSizeIndexToSeverity(SizedApparelsDatabase.GetSupportedBodyPartPath(key,true,"Breasts","Breasts").size);
//if (validBreastTextureSeverity < -5 && SizedApparelSettings.alienRaceSettings.settings[key.raceName].asHumanlike)//old: SizedApparelSettings.UnsupportedRaceToUseHumanlike
// validBreastTextureSeverity = SizedApparelUtility.GetBreastSeverityValidTextures(pawn, breastHediff, "Humanlike");
BreastSeverityCache = Math.Min(BreastSeverityCache, validBreastTextureSeverity);
if (SizedApparelSettings.Debug)
Log.Message("[Sized Apparel] cached Severity : " + BreastSeverityCache);
}
//penisHediff = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_genitalsBPR(pawn)).FirstOrDefault((Hediff h) => h.def.defName.ToLower().Contains("penis"));
//since rjw race support's part name are too variation, not handling it.
var anusList = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_anusBPR(pawn));
if(!anusList.NullOrEmpty())
anusHediff = anusList.FirstOrDefault((Hediff h) => h.def.defName.ToLower().Contains("anus"));
//udderHediff = Genital_Helper.get_PartsHediffList(pawn, pawn.RaceProps.body.AllParts.Find((BodyPartRecord bpr) => bpr.def.defName == "Torso")).FirstOrDefault((Hediff h) => h.def.defName.ToLower().Contains("anus")); //not yet supported
udderHediff = pawn.health?.hediffSet?.hediffs?.FirstOrDefault((Hediff h) => h.def.defName.ToLower().Contains("udder"));
var pawnRenderer = pawn.Drawer?.renderer?.graphics;
if (updateGraphics)
{
if (pawnRenderer != null)
{
//pawnRenderer.ResolveAllGraphics();
//TODO Use Function To Make Clear Code
/*
FindAndApplyBodyGraphic(pawn, pawnRenderer.nakedGraphic, ref graphicbaseBodyNaked, ref graphicSourceNaked,"Naked");
FindAndApplyBodyGraphic(pawn, pawnRenderer.rottingGraphic, ref graphicbaseBodyRotten, ref graphicSourceRotten, "Rotting");
FindAndApplyBodyGraphic(pawn, pawnRenderer.nakedGraphic, ref graphicbaseBodyFurCovered, ref graphicSourceFurCovered, "FurCuvered");
*/
const string baseBodyString = "_BaseBody";
string baseBodyStringWithSex;
if (SizedApparelSettings.useGenderSpecificTexture)
{
if (pawn.gender == Gender.Female)
{
baseBodyStringWithSex = baseBodyString + "F";
}
else if (pawn.gender == Gender.Male)
{
baseBodyStringWithSex = baseBodyString + "M";
}
else
{
baseBodyStringWithSex = baseBodyString; // + "N" //Does it need to add N?
}
}
else
baseBodyStringWithSex = baseBodyString;
string nakedGraphicPath = null;
if (pawnRenderer.nakedGraphic != null)
{
//path = path.Insert(Math.Max(path.LastIndexOf('/'), 0), "/CustomPose/"+ customPose);
if(graphicSourceNaked == null)
graphicSourceNaked = pawnRenderer.nakedGraphic;
nakedGraphicPath = graphicSourceNaked.path;
if (customPose != null)
nakedGraphicPath = nakedGraphicPath.Insert(Math.Max(nakedGraphicPath.LastIndexOf('/'), 0), "/CustomPose/" + customPose);
if (!nakedGraphicPath.Contains(baseBodyString))
{
if (SizedApparelSettings.useGenderSpecificTexture & pawn.gender != Gender.None)
{
if (graphicbaseBodyNaked == null)
{
if (ContentFinder<Texture2D>.Get((nakedGraphicPath + baseBodyStringWithSex + "_south"), false) != null)
{
//graphicSourceNaked = pawnRenderer.nakedGraphic;
Shader shader = pawnRenderer.nakedGraphic.Shader;
//if (!ShaderUtility.SupportsMaskTex(shader))
// shader = ShaderDatabase.CutoutSkinOverlay;
graphicbaseBodyNaked = GraphicDatabase.Get<Graphic_Multi>(nakedGraphicPath + baseBodyStringWithSex, shader, pawnRenderer.nakedGraphic.drawSize, pawnRenderer.nakedGraphic.color, pawnRenderer.nakedGraphic.colorTwo, pawnRenderer.nakedGraphic.data);
//pawnRenderer.nakedGraphic = graphicbaseBodyNaked;
}
else if (customPose != null)
{
nakedGraphicPath = pawnRenderer.nakedGraphic.path;
if (ContentFinder<Texture2D>.Get((nakedGraphicPath + baseBodyStringWithSex + "_south"), false) != null)
{
//graphicSourceNaked = pawnRenderer.nakedGraphic;
Shader shader = pawnRenderer.nakedGraphic.Shader;
//if (!ShaderUtility.SupportsMaskTex(shader))
// shader = ShaderDatabase.CutoutSkinOverlay;
graphicbaseBodyNaked = GraphicDatabase.Get<Graphic_Multi>(nakedGraphicPath + baseBodyStringWithSex, shader, pawnRenderer.nakedGraphic.drawSize, pawnRenderer.nakedGraphic.color, pawnRenderer.nakedGraphic.colorTwo, pawnRenderer.nakedGraphic.data);
//pawnRenderer.nakedGraphic = graphicbaseBodyNaked;
}
else
{
if (SizedApparelSettings.Debug)
Log.Warning("[SizedApparel] Missing BaseBodyTexture for naked Graphic: " + nakedGraphicPath + baseBodyStringWithSex + "_south");
}
}
}
}
if (graphicbaseBodyNaked == null)
{
if (ContentFinder<Texture2D>.Get((nakedGraphicPath + baseBodyString + "_south"), false) != null)
{
// graphicSourceNaked = pawnRenderer.nakedGraphic;
Shader shader = pawnRenderer.nakedGraphic.Shader;
//if (!ShaderUtility.SupportsMaskTex(shader))
// shader = ShaderDatabase.CutoutSkinOverlay;
graphicbaseBodyNaked = GraphicDatabase.Get<Graphic_Multi>(nakedGraphicPath + baseBodyString, shader, pawnRenderer.nakedGraphic.drawSize, pawnRenderer.nakedGraphic.color, pawnRenderer.nakedGraphic.colorTwo, pawnRenderer.nakedGraphic.data);
//pawnRenderer.nakedGraphic = graphicbaseBodyNaked;
}
else if (customPose != null)
{
nakedGraphicPath = pawnRenderer.nakedGraphic.path;
if (ContentFinder<Texture2D>.Get((nakedGraphicPath + baseBodyString + "_south"), false) != null)
{
//graphicSourceNaked = pawnRenderer.nakedGraphic;
Shader shader = pawnRenderer.nakedGraphic.Shader;
//if (!ShaderUtility.SupportsMaskTex(shader))
// shader = ShaderDatabase.CutoutSkinOverlay;
graphicbaseBodyNaked = GraphicDatabase.Get<Graphic_Multi>(nakedGraphicPath + baseBodyString, shader, pawnRenderer.nakedGraphic.drawSize, pawnRenderer.nakedGraphic.color, pawnRenderer.nakedGraphic.colorTwo, pawnRenderer.nakedGraphic.data);
//pawnRenderer.nakedGraphic = graphicbaseBodyNaked;
}
else
{
if (SizedApparelSettings.Debug)
Log.Warning("[SizedApparel] Missing BaseBodyTexture for naked Graphic: " + nakedGraphicPath + baseBodyString + "_south");
}
}
}
}
else
graphicbaseBodyNaked = pawnRenderer.nakedGraphic;
}
//Finding Texture Points
if (false && graphicbaseBodyNaked != null)
{
SizedApparelTexturePointDef PointsDef = DefDatabase<SizedApparelTexturePointDef>.AllDefs.FirstOrDefault((SizedApparelTexturePointDef s) => s.Path == graphicbaseBodyNaked.path);
if (SizedApparelSettings.Debug && PointsDef != null)
{
Log.Message("[SizedApparel] : NakedBaseBody Texture Points Def Found : " + PointsDef.defName);
}
baseBodyNakedPoints = PointsDef;
}
else
baseBodyNakedPoints = null;
string rottingGraphicPath = null;
if (pawnRenderer.rottingGraphic != null)
{
if (graphicSourceRotten == null)
graphicSourceRotten = pawnRenderer.rottingGraphic;
rottingGraphicPath = graphicSourceRotten.path;
if (customPose != null)
rottingGraphicPath = rottingGraphicPath.Insert(Math.Max(rottingGraphicPath.LastIndexOf('/'), 0), "/CustomPose/" + customPose);
if (!rottingGraphicPath.Contains(baseBodyString))
{
if (graphicbaseBodyRotten == null)
{
if (ContentFinder<Texture2D>.Get((rottingGraphicPath + baseBodyStringWithSex + "_south"), false) != null)
{
//graphicSourceRotten = pawnRenderer.rottingGraphic;
Shader shader = pawnRenderer.rottingGraphic.Shader;
//if (!ShaderUtility.SupportsMaskTex(shader))
// shader = ShaderDatabase.CutoutSkinOverlay;
graphicbaseBodyRotten = GraphicDatabase.Get<Graphic_Multi>(rottingGraphicPath + baseBodyStringWithSex, shader, pawnRenderer.rottingGraphic.drawSize, pawnRenderer.rottingGraphic.color, pawnRenderer.rottingGraphic.colorTwo, pawnRenderer.rottingGraphic.data);
//pawnRenderer.rottingGraphic = graphicbaseBodyRotten;
}
else if (customPose != null)
{
rottingGraphicPath = pawnRenderer.rottingGraphic.path;
if (ContentFinder<Texture2D>.Get((rottingGraphicPath + baseBodyStringWithSex + "_south"), false) != null)
{
graphicSourceRotten = pawnRenderer.rottingGraphic;
Shader shader = pawnRenderer.rottingGraphic.Shader;
//if (!ShaderUtility.SupportsMaskTex(shader))
// shader = ShaderDatabase.CutoutSkinOverlay;
graphicbaseBodyRotten = GraphicDatabase.Get<Graphic_Multi>(rottingGraphicPath + baseBodyStringWithSex, shader, pawnRenderer.rottingGraphic.drawSize, pawnRenderer.rottingGraphic.color, pawnRenderer.rottingGraphic.colorTwo, pawnRenderer.rottingGraphic.data);
//pawnRenderer.rottingGraphic = graphicbaseBodyRotten;
}
else
{
if (SizedApparelSettings.Debug)
Log.Warning("[SizedApparel] Missing BaseBodyTexture for rotting Graphic: " + rottingGraphicPath + baseBodyStringWithSex + "_south");
}
}
if (graphicbaseBodyRotten == null)
{
if (ContentFinder<Texture2D>.Get((rottingGraphicPath + baseBodyString + "_south"), false) != null)
{
//graphicSourceRotten = pawnRenderer.rottingGraphic;
Shader shader = pawnRenderer.rottingGraphic.Shader;
//if (!ShaderUtility.SupportsMaskTex(shader))
// shader = ShaderDatabase.CutoutSkinOverlay;
graphicbaseBodyRotten = GraphicDatabase.Get<Graphic_Multi>(rottingGraphicPath + baseBodyString, shader, pawnRenderer.rottingGraphic.drawSize, pawnRenderer.rottingGraphic.color, pawnRenderer.rottingGraphic.colorTwo, pawnRenderer.rottingGraphic.data);
//pawnRenderer.rottingGraphic = graphicbaseBodyRotten;
}
else if (customPose != null)
{
rottingGraphicPath = pawnRenderer.rottingGraphic.path;
if (ContentFinder<Texture2D>.Get((rottingGraphicPath + baseBodyString + "_south"), false) != null)
{
graphicSourceRotten = pawnRenderer.rottingGraphic;
Shader shader = pawnRenderer.rottingGraphic.Shader;
//if (!ShaderUtility.SupportsMaskTex(shader))
// shader = ShaderDatabase.CutoutSkinOverlay;
graphicbaseBodyRotten = GraphicDatabase.Get<Graphic_Multi>(rottingGraphicPath + baseBodyString, shader, pawnRenderer.rottingGraphic.drawSize, pawnRenderer.rottingGraphic.color, pawnRenderer.rottingGraphic.colorTwo, pawnRenderer.rottingGraphic.data);
//pawnRenderer.rottingGraphic = graphicbaseBodyRotten;
}
else
{
if (SizedApparelSettings.Debug)
Log.Warning("[SizedApparel] Missing BaseBodyTexture for rotting Graphic: " + rottingGraphicPath + baseBodyString + "_south");
}
}
}
}
}
else
graphicbaseBodyRotten = pawnRenderer.rottingGraphic;
}
//Finding Texture Points
if (false && graphicbaseBodyRotten != null)
{
SizedApparelTexturePointDef PointsDef = DefDatabase<SizedApparelTexturePointDef>.AllDefs.FirstOrDefault((SizedApparelTexturePointDef s) => s.Path == graphicbaseBodyRotten.path);
if (SizedApparelSettings.Debug && PointsDef != null)
{
Log.Message("[SizedApparel] : RottenBaseBody Texture Points Def Found : " + PointsDef.defName);
}
baseBodyRottenPoints = PointsDef;
}
else
baseBodyRottenPoints = null;
string furCoveredGraphicPath = null;
//Finding Texture Points
if (false && graphicbaseBodyFurCovered != null)
{
SizedApparelTexturePointDef PointsDef = DefDatabase<SizedApparelTexturePointDef>.AllDefs.FirstOrDefault((SizedApparelTexturePointDef s) => s.Path == graphicbaseBodyFurCovered.path);
if (SizedApparelSettings.Debug && PointsDef != null)
{
Log.Message("[SizedApparel] : FurCoveredBaseBody Texture Points Def Found : " + PointsDef.defName);
}
baseBodyFurCoveredPoints = PointsDef;
}
else
baseBodyFurCoveredPoints = null;
/*
//Try to find sized Body if it's valid
int offset = 9999;
int currentBreastSizeIndex = 0;
float currentBreastSeverity = 0;
bool validNakedTexture = false;
bool validRottingTexture = false;
Graphic nakedGraphic;
Graphic rottingGraphic;
while (offset < SizedApparelUtility.size.Length)
{
string breastSeverityStringCache = SizedApparelUtility.BreastSeverityString(breastSeverity, offset, true, ref currentBreastSizeIndex, ref currentBreastSeverity);
//search bigger
//SizedApparelSettings.matchBodyTextureToMinimumApparelSize? currentBreastSizeIndex <= minSupportedBreasSizeIndex:true
if (validNakedTexture == false && nakedGraphicPath !=null)
{
if ((ContentFinder<Texture2D>.Get((nakedGraphicPath + breastSeverityStringCache + "_south"), false) != null))
{
if (SizedApparelSettings.matchBodyTextureToMinimumApparelSize ? SizedApparelUtility.BreastSizeIndexToSeverity(currentBreastSizeIndex) <= breastSeverityCapToDraw : true)
{
nakedGraphic = GraphicDatabase.Get<Graphic_Multi>(nakedGraphicPath + breastSeverityStringCache, pawnRenderer.nakedGraphic.Shader, pawnRenderer.nakedGraphic.drawSize, pawnRenderer.nakedGraphic.color, pawnRenderer.nakedGraphic.colorTwo, pawnRenderer.nakedGraphic.data);
//newAgr.Add(new ApparelGraphicRecord(graphic, agr.sourceApparel));
//validTexture = true;
//Log.Message(path + BreastSeverityString(BreastSeverity, offset, !findBigger) + ":Texture Found");
pawnRenderer.nakedGraphic = nakedGraphic;
validNakedTexture = true;
}
}
}
if (validRottingTexture == false && rottingGraphicPath != null)
{
if ((ContentFinder<Texture2D>.Get((rottingGraphicPath + breastSeverityStringCache + "_south"), false) != null))
{
if (SizedApparelSettings.matchBodyTextureToMinimumApparelSize ? SizedApparelUtility.BreastSizeIndexToSeverity(currentBreastSizeIndex) <= breastSeverityCapToDraw : true)
{
rottingGraphic = GraphicDatabase.Get<Graphic_Multi>(rottingGraphicPath + breastSeverityStringCache, pawnRenderer.rottingGraphic.Shader, pawnRenderer.rottingGraphic.drawSize, pawnRenderer.rottingGraphic.color, pawnRenderer.rottingGraphic.colorTwo, pawnRenderer.rottingGraphic.data);
//newAgr.Add(new ApparelGraphicRecord(graphic, agr.sourceApparel));
//validTexture = true;
//Log.Message(path + BreastSeverityString(BreastSeverity, offset, !findBigger) + ":Texture Found");
pawnRenderer.rottingGraphic = rottingGraphic;
validRottingTexture = true;
}
}
}
//search smaller
breastSeverityStringCache = SizedApparelUtility.BreastSeverityString(breastSeverity, offset, false, ref currentBreastSizeIndex, ref currentBreastSeverity);
if (validNakedTexture == false)
{
if ((ContentFinder<Texture2D>.Get((nakedGraphicPath + breastSeverityStringCache + "_south"), false) != null))
{
if (SizedApparelSettings.matchBodyTextureToMinimumApparelSize ? SizedApparelUtility.BreastSizeIndexToSeverity(currentBreastSizeIndex) <= breastSeverityCapToDraw : true)
{
nakedGraphic = GraphicDatabase.Get<Graphic_Multi>(nakedGraphicPath + breastSeverityStringCache, pawnRenderer.nakedGraphic.Shader, pawnRenderer.nakedGraphic.drawSize, pawnRenderer.nakedGraphic.color, pawnRenderer.nakedGraphic.colorTwo, pawnRenderer.nakedGraphic.data);
//newAgr.Add(new ApparelGraphicRecord(graphic, agr.sourceApparel));
//validTexture = true;
//Log.Message(path + BreastSeverityString(BreastSeverity, offset, !findBigger) + ":Texture Found");
pawnRenderer.nakedGraphic = nakedGraphic;
validNakedTexture = true;
}
}
}
if (validRottingTexture == false)
{
if ((ContentFinder<Texture2D>.Get((rottingGraphicPath + breastSeverityStringCache + "_south"), false) != null))
{
if (SizedApparelSettings.matchBodyTextureToMinimumApparelSize ? SizedApparelUtility.BreastSizeIndexToSeverity(currentBreastSizeIndex) <= breastSeverityCapToDraw : true)
{
rottingGraphic = GraphicDatabase.Get<Graphic_Multi>(rottingGraphicPath + breastSeverityStringCache, pawnRenderer.rottingGraphic.Shader, pawnRenderer.rottingGraphic.drawSize, pawnRenderer.rottingGraphic.color, pawnRenderer.rottingGraphic.colorTwo, pawnRenderer.rottingGraphic.data);
//newAgr.Add(new ApparelGraphicRecord(graphic, agr.sourceApparel));
//validTexture = true;
//Log.Message(path + BreastSeverityString(BreastSeverity, offset, !findBigger) + ":Texture Found");
pawnRenderer.rottingGraphic = rottingGraphic;
validRottingTexture = true;
}
}
}
if (validNakedTexture == true && validRottingTexture == true)
{
if (SizedApparelSettings.Debug)
Log.Message("[Sized Apparel] " + pawn.Name + "'s body texture has changed.");
break;
}
offset++;
}
*/
}
//graphicBreasts = SizedApparelUtility.GetBodyPartGraphic(pawn, breastHediff, true, "Breasts", "Breasts");
//if(graphicBreasts == null && pawn.RaceProps.Humanlike && SizedApparelSettings.UnsupportedRaceToUseHumanlike)
// graphicBreasts = SizedApparelUtility.GetBodyPartGraphic(pawn, breastHediff, true, "Breasts", "Breasts", false, true, "Humanlike");
if (SizedApparelSettings.drawBodyParts)//body parts update
{
if (SizedApparelSettings.drawBreasts)
{
if (breastHediff != null)
{
var breastvar = breastHediff.TryGetComp<SizedApparelBodyPartDetail>();
foreach(var addon in bodyAddons)
{
if(addon.bodyPartOf == SizedApparelBodyPartOf.Breasts)
{
addon.SetHediffData(breastHediff.def.defName, SizedApparelUtility.BreastSeverityInt(breastHediff.Severity), SizedApparelUtility.BreastSeverityInt(BreastSeverityCache), breastvar?.variation);
addon.SetBone(skeleton?.FindBone("Breasts"));
addon.UpdateGraphic();
}
}
//bodyPartBreasts.SetHediffData(breastHediff.def.defName, SizedApparelUtility.BreastSeverityInt(breastHediff.Severity), SizedApparelUtility.BreastSeverityInt(breastSeverityCapped), breastvar?.variation);
//bodyPartBreasts.UpdateGraphic();
}
else
{
foreach (var addon in bodyAddons)
{
if (addon.bodyPartOf == SizedApparelBodyPartOf.Breasts)
{
addon.SetHediffData(null, -1);
}
}
}
}
if (SizedApparelSettings.drawUdder)
{
if (udderHediff != null)
{
var udderVar = udderHediff.TryGetComp<SizedApparelBodyPartDetail>();
foreach (var addon in bodyAddons)
{
if (addon.bodyPartOf == SizedApparelBodyPartOf.Udder)
{
addon.SetHediffData(udderHediff.def.defName, SizedApparelUtility.BreastSeverityInt(udderHediff.Severity), 1000, udderVar?.variation);
addon.SetBone(skeleton?.FindBone("Udder"));
addon.UpdateGraphic();
}
}
//bodyPartUdder.SetHediffData(udderHediff.def.defName, SizedApparelUtility.BreastSeverityInt(udderHediff.Severity), 1000, udderVar?.variation);
//bodyPartUdder.UpdateGraphic();
}
else
{
foreach (var addon in bodyAddons)
{
if (addon.bodyPartOf == SizedApparelBodyPartOf.Udder)
{
addon.SetHediffData(null, -1);
}
}
}
}
if (SizedApparelSettings.drawBelly)
{
if (bellySeverity >= 0)
{
//var bellyVar = breastHediff.GetComp<SizedApparelBodyPartDetail>();
string BellyVar = null;
foreach (var addon in bodyAddons)
{
if (addon.bodyPartOf == SizedApparelBodyPartOf.Belly)
{
addon.SetHediffData("BellyBulge", SizedApparelUtility.PrivatePartSeverityInt(bellySeverity), 1000, BellyVar);
addon.SetBone(skeleton?.FindBone("Belly"));
addon.UpdateGraphic();
}
}
//bodyPartBelly.SetHediffData("BellyBulge", SizedApparelUtility.PrivatePartSeverityInt(bellySeverity), 1000, BellyVar);
//bodyPartBelly.UpdateGraphic();
}
else
{
foreach (var addon in bodyAddons)
{
if (addon.bodyPartOf == SizedApparelBodyPartOf.Belly)
{
addon.SetHediffData(null, -1);
}
}
}
}
if (SizedApparelSettings.drawVagina)
{
if (vaginaHediff != null)
{
var vaginaVar = vaginaHediff.TryGetComp<SizedApparelBodyPartDetail>();
foreach (var addon in bodyAddons)
{
if (addon.bodyPartOf == SizedApparelBodyPartOf.Vagina)
{
addon.SetHediffData(vaginaHediff.def.defName, SizedApparelUtility.PrivatePartSeverityInt(vaginaHediff.Severity), 1000, vaginaVar?.variation);
addon.SetBone(skeleton?.FindBone("Vagina"));
addon.UpdateGraphic();
}
}
//bodyPartVagina.SetHediffData(vaginaHediff.def.defName, SizedApparelUtility.PrivatePartSeverityInt(vaginaHediff.Severity), 1000, vaginaVar?.variation);
//bodyPartVagina.UpdateGraphic();
}
else
{
foreach (var addon in bodyAddons)
{
if (addon.bodyPartOf == SizedApparelBodyPartOf.Vagina)
{
addon.SetHediffData(null, -1);
}
}
}
}
if (SizedApparelSettings.drawPubicHair)
{
if (pubicHairDef != null && pubicHairDef.defName != "None") // pubicHairDef != null // for testing
{
foreach (var addon in bodyAddons)
{
if (addon.bodyPartOf == SizedApparelBodyPartOf.PubicHair)
{
addon.SetHediffData(pubicHairDef.defName, 0, 1000, null);
addon.SetBone(skeleton?.FindBone("PubicHair"));
addon.UpdateGraphic();
}
}
//bodyPartPubicHair.SetHediffData(pubicHairDef.defName, 0, 1000, null);
//bodyPartPubicHair.UpdateGraphic();
}
else
{
foreach (var addon in bodyAddons)
{
if (addon.bodyPartOf == SizedApparelBodyPartOf.PubicHair)
{
addon.SetHediffData(null, -1);
}
}
}
}
if (SizedApparelSettings.drawPenis)
{
//TODO: Optimize.... memory leak issue?
//bodyPartPenises.Clear();
//bodyPartBalls.Clear();
if (!penisHediffs.NullOrEmpty())
{
var penisHediff = penisHediffs[0];
if (penisHediff != null)
{
var penisVar = penisHediff.TryGetComp<SizedApparelBodyPartDetail>();
foreach (var addon in bodyAddons)
{
if (addon.bodyPartOf == SizedApparelBodyPartOf.Penis)
{
addon.SetHediffData(penisHediff.def.defName, SizedApparelUtility.PrivatePartSeverityInt(penisHediff.Severity), 1000, penisVar?.variation);
addon.SetBone(skeleton?.FindBone("Penis"));
addon.UpdateGraphic();
}
if (addon.bodyPartOf == SizedApparelBodyPartOf.Balls)
{
addon.SetHediffData(penisHediff.def.defName, SizedApparelUtility.PrivatePartSeverityInt(penisHediff.Severity), 1000, penisVar?.variation);
addon.SetBone(skeleton?.FindBone("Balls"));
addon.UpdateGraphic();
}
}
}
else
{
foreach (var addon in bodyAddons)
{
if (addon.bodyPartOf == SizedApparelBodyPartOf.Penis)
{
addon.SetHediffData(null, -1);
}
if (addon.bodyPartOf == SizedApparelBodyPartOf.Balls)
{
addon.SetHediffData(null, -1);
}
}
}
// Multiple Penis Drawing. obsolte
/*
for (int i = 0; i < penisHediffs.Count; i++)
{
penisHediff = penisHediffs[i];
float offsetX = 0; // right and left
float offsetZ = 0; // up and down
float t = (i + 1f) / (penisHediffs.Count + 1);
offsetX = Mathf.Lerp(-0.05f, 0.05f, t);
offsetZ = Mathf.Lerp(-0.02f, 0.02f, t);
if (penisHediff == null)
continue;
Bone penisBone = null;
Bone ballsBone = null;
if(skeleton != null)
{
penisBone = skeleton.FindBone("Penis");
ballsBone = skeleton.FindBone("Balls");
if (ballsBone == null)
ballsBone = penisBone;
}
var penisVar = penisHediff.TryGetComp<SizedApparelBodyPartDetail>();
SizedApparelBodyPart penis = new SizedApparelBodyPart(pawn, this, "Penis", SizedApparelBodyPartOf.Penis, "Penis", false, false, null,ColorType.Skin, penisBone);
penis.SetDepthOffsets(0.0108f, 0.0025f, 0.0108f, 0.0108f);
penis.SetPositionOffsets(new Vector2(offsetX, 0), new Vector2(-offsetX, 0), new Vector2(offsetX, offsetZ), new Vector2(offsetX, -offsetZ));
penis.SetHediffData(penisHediff.def.defName, SizedApparelUtility.PrivatePartSeverityInt(penisHediff.Severity), 1000, penisVar?.variation);
penis.centeredTexture = true; // Test Bone
penis.UpdateGraphic();
bodyPartPenises.Add(penis);
SizedApparelBodyPart balls = new SizedApparelBodyPart(pawn, this, "Balls", SizedApparelBodyPartOf.Balls, "Penis", false, false, "Penis/Balls", ColorType.Skin, ballsBone);
balls.SetDepthOffsets(0.0096f, 0.0085f, 0.0096f, 0.0096f);
balls.SetPositionOffsets(new Vector2(offsetX, 0), new Vector2(-offsetX, 0), new Vector2(offsetX, offsetZ), new Vector2(offsetX, -offsetZ));
balls.SetHediffData(penisHediff.def.defName, SizedApparelUtility.PrivatePartSeverityInt(penisHediff.Severity), 1000, penisVar?.variation);
balls.centeredTexture = true; // Test Bone
balls.UpdateGraphic();
bodyPartBalls.Add(balls);
*/
}
}
else
{
bodyPartPenises.Clear();
bodyPartBalls.Clear();
}
if (SizedApparelSettings.drawAnus)
{
/*
graphicAnus = SizedApparelUtility.GetBodyPartGraphic(pawn, anusHediff, false, "Anus", "Anus");
if (graphicAnus == null && pawn.RaceProps.Humanlike && SizedApparelSettings.UnsupportedRaceToUseHumanlike)
graphicAnus = SizedApparelUtility.GetBodyPartGraphic(pawn, anusHediff, false, "Anus", "Anus", false, true, "Humanlike");
graphicAnus_horny = SizedApparelUtility.GetBodyPartGraphic(pawn, anusHediff, false, "Anus", "Anus", true);
if (graphicAnus_horny == null && pawn.RaceProps.Humanlike && SizedApparelSettings.UnsupportedRaceToUseHumanlike)
graphicAnus_horny = SizedApparelUtility.GetBodyPartGraphic(pawn, anusHediff, false, "Anus", "Anus", true, true, "Humanlike");
*/
if (anusHediff != null)
{
var anusVar = anusHediff.TryGetComp<SizedApparelBodyPartDetail>();
foreach (var addon in bodyAddons)
{
if (addon.bodyPartOf == SizedApparelBodyPartOf.Anus)
{
addon.SetHediffData(anusHediff.def.defName, SizedApparelUtility.PrivatePartSeverityInt(anusHediff.Severity), 1000, anusVar?.variation);
addon.SetBone(skeleton?.FindBone("Anus"));
addon.UpdateGraphic();
}
}
}
else
{
foreach (var addon in bodyAddons)
{
if (addon.bodyPartOf == SizedApparelBodyPartOf.Anus)
{
addon.SetHediffData(null, -1);
}
}
}
}
}
hasGraphicUpdatedBefore = true;
}
if(CheckApparel)
cachedApparelGraphicRecord = pawnRenderer.apparelGraphics.ToList();
else
cachedApparelGraphicRecord = new List<ApparelGraphicRecord>();
hasUpdateBeforeSuccess = true;
this.isHediffDirty = false;
this.isApparelDirty = false;
this.isSkeletonDirty = false;
}
//public bool hasUnsupportedApparel => Props.hasUnsupportedApparel;
//public bool hasUpdateBefore => Props.hasUpdateBefore;
/*
public void SetHasUnsupportedApparel(bool _hasUnsupportedApparel)
{
if(Props !=null)
Props.hasUnsupportedApparel = _hasUnsupportedApparel;
this.hasUnsupportedApparel = _hasUnsupportedApparel;
}
public void SetHasUpdateBefore(bool _hasUpdateBefore)
{
if (Props != null)
Props.hasUpdateBefore = _hasUpdateBefore;
this.hasUpdateBefore = _hasUpdateBefore;
}*/
public IEnumerable<SizedApparelBodyPart> GetAllSizedApparelBodyPart() // can return null bodyparts
{
yield return bodyPartBreasts;
yield return bodyPartNipple;
/*
foreach (SizedApparelBodyPart bp in bodyPartBreasts)
{
yield return bp;
}
foreach (SizedApparelBodyPart bp in bodyPartNipple)
{
yield return bp;
}*/
foreach (SizedApparelBodyPart bp in bodyPartPenises)
{
yield return bp;
}
foreach (SizedApparelBodyPart bp in bodyPartBalls)
{
yield return bp;
}
yield return bodyPartVagina;
yield return bodyPartAnus;
yield return bodyPartBelly;
yield return bodyPartMuscleOverlay;//TODO
yield return bodyPartUdder;
yield return bodyPartPubicHair; //TODO
yield return bodyPartHips;
foreach (SizedApparelBodyPart bp in bodyPartThighs)
{
yield return bp;
}
foreach (SizedApparelBodyPart bp in bodyPartHands)
{
yield return bp;
}
foreach (SizedApparelBodyPart bp in bodyPartFeet)
{
yield return bp;
}
foreach (SizedApparelBodyPart bp in bodyAddons)
{
yield return bp;
}
}
public IEnumerable<SizedApparelBodyPart> GetSizedApparelBodyParts(SizedApparelBodyPartOf targetPartOf, bool returnNullPart = false)
{
foreach(SizedApparelBodyPart bp in GetAllSizedApparelBodyPart())
{
if (bp == null)
{
if (returnNullPart)
yield return bp;
else
continue;
}
if (bp.bodyPartOf.IsPartOf(targetPartOf))
yield return bp;
}
}
public void SetPoseFromPoseSet(string poseSetName, bool autoUpdate = true, bool autoSetPawnGraphicDirty = false)
{
if (poseSetName.NullOrEmpty())
{
ClearAllPose(autoUpdate, autoSetPawnGraphicDirty);
return;
}
var poseSetDef = DefDatabase<SizedApparelPoseSetDef>.GetNamed(poseSetName,false);
if (poseSetDef == null)
return;
if (poseSetDef.poses.NullOrEmpty())
return;
foreach (SizedApparelPose pose in poseSetDef.poses)
{
var bodyParts = GetSizedApparelBodyParts(pose.targetBodyPart);
//if (bodyParts == null)
// continue;
if (bodyParts.EnumerableNullOrEmpty())
continue;
foreach (SizedApparelBodyPart bp in bodyParts.ToList())
{
if(bp != null)
bp.SetCustomPose(poseSetName, autoUpdate, autoSetPawnGraphicDirty);
}
}
}
public void ClearAllPose(bool autoUpdate = true, bool autoSetPawnGraphicDirty = false)
{
foreach (SizedApparelBodyPart bp in GetAllSizedApparelBodyPart())
{
if(bp != null)
bp.SetCustomPose(null, autoUpdate, autoSetPawnGraphicDirty);
}
}
public void ClearPose(SizedApparelBodyPartOf targetPartOf , bool autoUpdate = true, bool autoSetPawnGraphicDirty = false)
{
foreach (SizedApparelBodyPart bp in GetSizedApparelBodyParts(targetPartOf))
{
if(bp != null)
bp.SetCustomPose(null, autoUpdate, autoSetPawnGraphicDirty);
}
}
}
[StaticConstructorOnStartup]
public class ApparelRecorderCompProperties : CompProperties
{
public bool hasUnsupportedApparel = false;
public bool hasUpdateBefore = false;
public ApparelRecorderCompProperties()
{
this.compClass = typeof(ApparelRecorderComp);
}
public ApparelRecorderCompProperties(Type compClass) : base(compClass)
{
this.compClass = compClass;
}
}
}