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(compApparelVisibility.rotation.ToString()); //DebugMode.Message("Drawing " + apparel.def.defName + " on ground"); } } } } public static bool BodyAddonCoveredByApparel(Apparel apparel, AlienPartGenerator.BodyAddon bodyAddon) { CompApparelVisibility comp = apparel.TryGetComp(); if (comp != null && comp.isBeingWorn == false) { return false; } RimNudeData rimNudeData = ApparelSettings.GetRimNudeData(apparel); if (rimNudeData != null && bodyAddon?.bodyPart != null) { if (bodyAddon.bodyPart == "Genitals" && rimNudeData.coversGroin == false) { return false; } if (bodyAddon.bodyPart == "Chest" && rimNudeData.coversChest == false) { return false; } if (bodyAddon.bodyPart == "Torso" && rimNudeData.coversBelly == false) { return false; } } if (apparel.def.apparel.bodyPartGroups.Any(x => bodyAddon.hiddenUnderApparelFor.Contains(x)) || apparel.def.apparel.tags.Any(x => bodyAddon.hiddenUnderApparelTag.Contains(x))) { return true; } return false; } public static bool BodyPartCoveredByApparel(Apparel apparel, BodyPartRecord bodyPart) { CompApparelVisibility comp = apparel.TryGetComp(); if (comp != null && comp.isBeingWorn == false) { return false; } RimNudeData rimNudeData = ApparelSettings.GetRimNudeData(apparel); if (rimNudeData != null) { if (bodyPart.def.defName == "Genitals" && rimNudeData.coversGroin == false) { return false; } if (bodyPart.def.defName == "Chest" && rimNudeData.coversChest == false) { return false; } if (bodyPart.def.defName == "Torso" && rimNudeData.coversBelly == false) { return false; } } if (apparel.def.apparel.CoversBodyPart(bodyPart)) { return true; } 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 || BodyPartCoveredByApparel(apparel, bodyParts.FirstOrDefault(x => x.def == xxx.genitalsDef)); } if (anim.actors[actorID].isFucked || requiredGenitals.Contains("Vagina")) { bodyPartCovered = bodyPartCovered || BodyPartCoveredByApparel(apparel, bodyParts.FirstOrDefault(x => x.def == xxx.genitalsDef)); } if (anim.actors[actorID].isFucked || requiredGenitals.Contains("Anus")) { bodyPartCovered = bodyPartCovered || BodyPartCoveredByApparel(apparel, bodyParts.FirstOrDefault(x => x.def == xxx.anusDef)); } if (requiredGenitals.Contains("Breasts")) { bodyPartCovered = bodyPartCovered || BodyPartCoveredByApparel(apparel, bodyParts.FirstOrDefault(x => x.def == xxx.breastsDef)); } if (requiredGenitals.Contains("Mouth")) { bodyPartCovered = bodyPartCovered || BodyPartCoveredByApparel(apparel, bodyParts.FirstOrDefault(x => x.def.defName.ToLower().ContainsAny("mouth", "teeth", "jaw", "beak"))); } return bodyPartCovered; } } }