using System.Collections.Generic; using System.Linq; using Verse; using RimWorld; using Verse.AI.Group; 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.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 RJWPreferenceSettings.Clothing GetClothingPreference(Pawn pawn) { var clothingPreference = pawn.IsInBed(out Building bed) ? RJWPreferenceSettings.sex_wear : ApparelSettings.apparelWornForQuickies; if (xxx.has_quirk(pawn, "Endytophile")) { clothingPreference = RJWPreferenceSettings.Clothing.Clothed; } return clothingPreference; } public static void DetermineApparelToKeepOn(Pawn pawn) { if (pawn?.apparel?.WornApparel == null) return; foreach (Apparel apparel in pawn.apparel.WornApparel) { CompApparelVisibility comp = apparel.TryGetComp(); if (comp != null) comp.isBeingWorn = true; } ActorAnimationData animData = pawn.GetAnimationData(); var clothingPreference = GetClothingPreference(pawn); // Get naked for rituals and parties bool undressForRitual = pawn.GetLord() != null && pawn.GetLord().LordJob is LordJob_Ritual; bool undressForParty = pawn.GetLord() != null && pawn.GetLord().LordJob is LordJob_Joinable_Party; // 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 (ApparelSettingsUtility.GetRimNudeData(apparel)?.sexWear == true) continue; if (clothingPreference == RJWPreferenceSettings.Clothing.Nude || undressForRitual || undressForParty) { 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 (animData != null && ApparelCoversPawnRequiredBodyParts(pawn, apparel, animData.animationDef, animData.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.ContainsAny("mouth", "teeth", "jaw", "beak", "Mouth", "Teeth", "Jaw", "Beak"))); } return bodyPartCovered; } } }