using System.Collections.Generic; using System.Linq; using Verse; using RimWorld; using Rimworld_Animations; using UnityEngine; using AlienRace; using rjw; namespace Rimworld_Animations_Patch { public static class ApparelAnimationUtility { public static float apparelScale = 0.75f; public static void TryToDrawApparelOnFloor(Pawn pawn) { if (pawn?.apparel?.WornApparel != null) { CompBodyAnimator compBodyAnimator = pawn.TryGetComp(); if (ApparelSettings.clothesThrownOnGround == false || Find.CurrentMap != pawn.Map || compBodyAnimator == null || compBodyAnimator.isAnimating == false) { return; } foreach (Apparel apparel in pawn.apparel.WornApparel) { CompApparelVisibility compApparelVisibility = apparel.TryGetComp(); if (compApparelVisibility != null && compApparelVisibility.position != default && compApparelVisibility.isBeingWorn == false) { Graphic apparelGraphic = apparel.Graphic; apparelGraphic.drawSize.x *= apparelScale; apparelGraphic.drawSize.y *= apparelScale; GenDraw.DrawMeshNowOrLater(mesh: apparelGraphic.MeshAt(rot: apparel.Rotation), loc: compApparelVisibility.position, quat: Quaternion.AngleAxis(angle: compApparelVisibility.rotation, axis: Vector3.up), mat: apparelGraphic.MatAt(rot: apparel.Rotation), false); apparelGraphic.drawSize.x *= 1f / apparelScale; apparelGraphic.drawSize.y *= 1f / apparelScale; //DebugMode.Message("Drawing " + apparel.def.defName + " on ground"); } } } } public static bool PrivatePartCoveredByApparel(Apparel apparel, string bodyPart) { CompApparelVisibility comp = apparel.TryGetComp(); if (comp == null || comp.rimNudeDataStatus == RimNudeDataStatus.Unavailable) { return false; } if (comp.rimNudeDataStatus == RimNudeDataStatus.NotLoaded) { RimNudeData rimNudeData = ApparelSettings.GetRimNudeData(apparel); if (rimNudeData == null) { comp.rimNudeDataStatus = RimNudeDataStatus.Unavailable; return false; } comp.coversBelly = rimNudeData.coversBelly; comp.coversChest = rimNudeData.coversChest; comp.coversGroin = rimNudeData.coversGroin; comp.rimNudeDataStatus = RimNudeDataStatus.Loaded; } if (comp.isBeingWorn == false) { return false; } if (bodyPart == "Genitals") { return comp.coversGroin; } if (bodyPart == "Chest") { return comp.coversChest; } if (bodyPart == "Torso") { return comp.coversBelly; } return false; } public static void DetermineApparelToKeepOn(Pawn pawn) { JobDriver_Sex jobdriver = pawn.jobs.curDriver as JobDriver_Sex; if (pawn.RaceProps.Humanlike == false || pawn?.apparel?.WornApparel == null || jobdriver == null) { return; } foreach (Apparel apparel in pawn.apparel.WornApparel) { CompApparelVisibility comp = apparel.TryGetComp(); if (comp != null) { comp.isBeingWorn = true; } } ActorAnimationData animData = pawn.GetAnimationData(); if (animData == null) { return; } AnimationDef anim = animData.animationDef; int actorID = animData.actorID; var clothingPreference = pawn.IsInBed(out Building bed) ? RJWPreferenceSettings.sex_wear : ApparelSettings.apparelWornForQuickies; if (xxx.has_quirk(pawn, "Endytophile")) { clothingPreference = RJWPreferenceSettings.Clothing.Clothed; } // Determine any obstructing apparel that must be removed foreach (Apparel apparel in pawn.apparel.WornApparel) { CompApparelVisibility comp = apparel.TryGetComp(); if (comp == null) { continue; } if (apparel.def is bondage_gear_def) { continue; } if (ApparelSettings.GetRimNudeData(apparel) != null && ApparelSettings.GetRimNudeData(apparel).sexWear) { continue; } if (clothingPreference == RJWPreferenceSettings.Clothing.Nude) { comp.isBeingWorn = false; continue; } bool isHat = apparel.def.apparel.bodyPartGroups.NullOrEmpty() == false && (apparel.def.apparel.bodyPartGroups.Contains(BodyPartGroupDefOf.FullHead) || apparel.def.apparel.bodyPartGroups.Contains(BodyPartGroupDefOf.UpperHead)); if (clothingPreference == RJWPreferenceSettings.Clothing.Headgear && isHat == false) { comp.isBeingWorn = false; continue; } if (ApparelCoversPawnRequiredBodyParts(pawn, apparel, anim, actorID)) { comp.isBeingWorn = false; continue; } } } public static bool ApparelCoversPawnRequiredBodyParts(Pawn pawn, Apparel apparel, AnimationDef anim, int actorID) { bool bodyPartCovered = false; IEnumerable bodyParts = pawn.RaceProps.body.AllParts; var requiredGenitals = anim.actors[actorID].requiredGenitals; if (requiredGenitals.NullOrEmpty()) { requiredGenitals = new List(); } if (anim.actors[actorID].isFucking || requiredGenitals.Contains("Penis")) { bodyPartCovered = bodyPartCovered || PrivatePartCoveredByApparel(apparel, "Genitals"); } if (anim.actors[actorID].isFucked || requiredGenitals.Contains("Vagina")) { bodyPartCovered = bodyPartCovered || PrivatePartCoveredByApparel(apparel, "Genitals"); } if (anim.actors[actorID].isFucked || requiredGenitals.Contains("Anus")) { bodyPartCovered = bodyPartCovered || PrivatePartCoveredByApparel(apparel, "Genitals"); } if (requiredGenitals.Contains("Breasts")) { bodyPartCovered = bodyPartCovered || PrivatePartCoveredByApparel(apparel, "Chest"); } if (requiredGenitals.Contains("Mouth")) { bodyPartCovered = bodyPartCovered || apparel.def.apparel.CoversBodyPart(bodyParts.FirstOrDefault(x => x.def.defName.ToLower().ContainsAny("mouth", "teeth", "jaw", "beak"))); } return bodyPartCovered; } } }