using System; using System.Collections.Generic; using System.Linq; using UnityEngine; using Verse; using RimWorld; using HarmonyLib; using Rimworld_Animations; namespace Rimworld_Animations_Patch { public static class HandAnimationUtility { public static BodyPartDef handDef; public static bool BodyPartIsBeingTouched(Pawn pawn, ActorAnimationData actorAnimationData, string bodypartFilePath, out List handAnimationData) { handAnimationData = new List(); HandAnimationDef handAnimationDef = pawn?.TryGetComp()?.handAnimationDef; if (handAnimationDef == null || actorAnimationData == null || bodypartFilePath.NullOrEmpty()) { return false; } foreach (HandAnimationData datum in handAnimationDef.handAnimationData) { if (datum.stageID != actorAnimationData.currentStage || datum.actorID != actorAnimationData.actorID) continue; if (datum.bodySide.NullOrEmpty() == false && bodypartFilePath.Contains(datum.bodySide, StringComparison.OrdinalIgnoreCase) == false) continue; if ((datum.targetBodyPart.NullOrEmpty() == false && bodypartFilePath.Contains(datum.targetBodyPart, StringComparison.OrdinalIgnoreCase)) || datum.targetBodyParts.Any(x => bodypartFilePath.Contains(x, StringComparison.OrdinalIgnoreCase))) { handAnimationData.Add(datum); } } return handAnimationData.NullOrEmpty() == false; } public static Vector3 GetHandPosition(Pawn pawn, HandAnimationData handAnimationData, Vector3 basePosition, float baseAngle) { Vector3 handPosition = handAnimationData.Motion.GetHandPosition(pawn, handAnimationData, baseAngle); return handPosition * pawn.RaceProps.baseBodySize + basePosition + new Vector3(0f, 0.3f, 0f); } public static float GetGenitalSize(Pawn pawn, string genitalName) { CompPawnSexData data = pawn?.TryGetComp(); if (data == null) return 0f; switch (genitalName) { case "penis": return data.sizeOfPenis; case "breasts": return data.sizeOfBreasts; case "Penis": return data.sizeOfPenis; case "Breasts": return data.sizeOfBreasts; } return 0.1f; } public static Graphic GetHandGraphic(Pawn touchingPawn) { CompPawnSexData comp = touchingPawn?.TryGetComp(); if (comp == null) return null; if (comp.handGraphic == null) { string handGraphicPath = "Hands/HandClean"; comp.handGraphic = GraphicDatabase.Get(handGraphicPath, ShaderDatabase.Cutout, new Vector2(0.6667f * touchingPawn.RaceProps.baseBodySize, 0.6667f * touchingPawn.RaceProps.baseBodySize), touchingPawn.story.SkinColor); } return comp.handGraphic; } public static bool TryToDrawHand(Pawn pawn, ActorAnimationData pawnAnimationData, string bodyAddonName, Vector3 bodyAddonPosition, float bodyAddonAngle, Rot4 bodyAddonRotation, PawnRenderFlags renderFlags) { if (BodyPartIsBeingTouched(pawn, pawnAnimationData, bodyAddonName, out List handAnimationData)) { foreach (HandAnimationData datum in handAnimationData) { Pawn touchingPawn = datum.touchingActorID >= 0 && pawn.GetAllSexParticipants().Count > datum.touchingActorID ? pawn.GetAllSexParticipants()[datum.touchingActorID] : pawn; Graphic handGraphic = GetHandGraphic(touchingPawn); if (handGraphic == null) return false; Vector3 handPosition = GetHandPosition(pawn, datum, bodyAddonPosition, bodyAddonAngle); GenDraw.DrawMeshNowOrLater(mesh: handGraphic.MeshAt(rot: bodyAddonRotation), loc: handPosition + new Vector3(0f, 0.022f, 0f), quat: Quaternion.identity, mat: handGraphic.MatAt(rot: bodyAddonRotation), renderFlags.FlagSet(PawnRenderFlags.DrawNow)); return true; } } return false; } } }