2022-09-10 01:22:08 +00:00
|
|
|
|
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, string bodypartFilePath, out List<HandAnimationData> handAnimationData)
|
|
|
|
|
{
|
|
|
|
|
handAnimationData = new List<HandAnimationData>();
|
|
|
|
|
ActorAnimationData actorAnimationData = pawn.GetAnimationData();
|
2022-09-11 06:05:16 +00:00
|
|
|
|
|
|
|
|
|
if (actorAnimationData == null)
|
|
|
|
|
{ return false; }
|
|
|
|
|
|
2022-09-10 01:22:08 +00:00
|
|
|
|
HandAnimationDef handAnimationDef = DefDatabase<HandAnimationDef>.AllDefs.FirstOrDefault(x => x.animationDefName == actorAnimationData.animationDef.defName);
|
|
|
|
|
|
|
|
|
|
if (handAnimationDef == null)
|
|
|
|
|
{ return false; }
|
|
|
|
|
|
|
|
|
|
foreach (HandAnimationData datum in handAnimationDef.handAnimationData)
|
|
|
|
|
{
|
|
|
|
|
if (datum.stageID != actorAnimationData.currentStage || datum.actorID != actorAnimationData.actorID)
|
|
|
|
|
{ continue; }
|
|
|
|
|
|
|
|
|
|
if (datum.bodySide.NullOrEmpty() == false && bodypartFilePath.ToLower().Contains(datum.bodySide) == false)
|
|
|
|
|
{ continue; }
|
|
|
|
|
|
|
|
|
|
if (datum.targetBodyPart.NullOrEmpty() == false && bodypartFilePath.ToLower().Contains(datum.targetBodyPart.ToLower()))
|
|
|
|
|
{ handAnimationData.Add(datum); }
|
|
|
|
|
|
|
|
|
|
else if (datum.targetBodyParts.Any(x => bodypartFilePath.ToLower().Contains(x.ToLower())))
|
|
|
|
|
{ handAnimationData.Add(datum); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return handAnimationData.NullOrEmpty() == false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Vector3 GetHandPosition(Pawn pawn, HandAnimationData handAnimationData, Vector3 basePosition, float baseAngle)
|
|
|
|
|
{
|
|
|
|
|
var methodInfo = AccessTools.Method(typeof(HandAnimationUtility), handAnimationData.motion, null, null);
|
|
|
|
|
|
|
|
|
|
if (methodInfo == null)
|
|
|
|
|
{
|
2022-09-11 06:05:16 +00:00
|
|
|
|
Debug.LogWarning("Hand animation motion '" + handAnimationData.motion + "' was not found");
|
2022-09-10 01:22:08 +00:00
|
|
|
|
return default;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Vector3 handPosition = (Vector3)methodInfo.Invoke(null, new object[] { pawn, handAnimationData, baseAngle });
|
|
|
|
|
|
2022-09-11 06:05:16 +00:00
|
|
|
|
return handPosition * pawn.RaceProps.baseBodySize + basePosition + new Vector3(0f, 0.3f, 0f);
|
2022-09-10 01:22:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static float GetGenitalSize(Pawn pawn, string genitalName)
|
|
|
|
|
{
|
|
|
|
|
switch(genitalName.ToLower())
|
|
|
|
|
{
|
|
|
|
|
case "penis": return pawn.health.hediffSet.hediffs.First(x => x.def.defName.ToLower().Contains("penis")).Severity;
|
|
|
|
|
case "breasts": return pawn.health.hediffSet.hediffs.First(x => x.def.defName.ToLower().Contains("breasts")).Severity;
|
|
|
|
|
case "vagina": return 0.1f;
|
|
|
|
|
case "anus": return 0.1f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0.1f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Vector3 Motion_StrokeGenitalsUpAndDownShort_FacingNS(Pawn pawn, HandAnimationData handAnimationData, float baseAngle)
|
|
|
|
|
{
|
|
|
|
|
Vector3 handPosition = new Vector3();
|
|
|
|
|
ActorAnimationData data = pawn.GetAnimationData();
|
|
|
|
|
|
|
|
|
|
float p = (Mathf.PingPong(data.stageTicks, handAnimationData.cycleTime) / handAnimationData.cycleTime);
|
|
|
|
|
float length = 0.035f;
|
|
|
|
|
|
|
|
|
|
handPosition.x = 0;
|
|
|
|
|
handPosition.z = length * p;
|
|
|
|
|
|
|
|
|
|
handPosition = handPosition.RotatedBy(baseAngle);
|
|
|
|
|
|
|
|
|
|
return handPosition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Vector3 Motion_StrokeGenitalsUpAndDown_FacingNS(Pawn pawn, HandAnimationData handAnimationData, float baseAngle)
|
|
|
|
|
{
|
|
|
|
|
Vector3 handPosition = new Vector3();
|
|
|
|
|
ActorAnimationData data = pawn.GetAnimationData();
|
|
|
|
|
|
|
|
|
|
float p = (Mathf.PingPong(data.stageTicks, handAnimationData.cycleTime) / handAnimationData.cycleTime);
|
|
|
|
|
float size = GetGenitalSize(pawn, handAnimationData.targetBodyPart) * 0.2f;
|
|
|
|
|
float m = (data.actorFacing == Rot4.North ? -1f : 1f) * (handAnimationData.mirror ? -1f : 1f) * (pawn.TryGetComp<CompBodyAnimator>().Mirror ? -1f : 1f);
|
|
|
|
|
|
|
|
|
|
handPosition.x = 0.025f * m;
|
|
|
|
|
handPosition.z = size * p;
|
|
|
|
|
|
|
|
|
|
handPosition = handPosition.RotatedBy(baseAngle);
|
|
|
|
|
|
|
|
|
|
return handPosition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Vector3 Motion_StrokeGenitalsUpAndDown_FacingEW(Pawn pawn, HandAnimationData handAnimationData, float baseAngle)
|
|
|
|
|
{
|
|
|
|
|
Vector3 handPosition = new Vector3();
|
|
|
|
|
ActorAnimationData data = pawn.GetAnimationData();
|
|
|
|
|
|
|
|
|
|
float p = Mathf.PingPong(data.stageTicks, handAnimationData.cycleTime) / handAnimationData.cycleTime;
|
|
|
|
|
float size = GetGenitalSize(pawn, handAnimationData.targetBodyPart) * 0.2f;
|
|
|
|
|
float m = (data.actorFacing == Rot4.West ? -1f : 1f) * (handAnimationData.mirror ? -1f : 1f);
|
|
|
|
|
|
|
|
|
|
handPosition.x = Mathf.Sin(m * (baseAngle + 45f) / 180f * Mathf.PI) * size * p;
|
|
|
|
|
handPosition.z = Mathf.Cos(m * (baseAngle + 45f) / 180f * Mathf.PI) * size * p;
|
|
|
|
|
|
|
|
|
|
return handPosition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Vector3 Motion_RubGenitals_FacingNS(Pawn pawn, HandAnimationData handAnimationData, float baseAngle)
|
|
|
|
|
{
|
|
|
|
|
Vector3 handPosition = new Vector3();
|
|
|
|
|
ActorAnimationData data = pawn.GetAnimationData();
|
|
|
|
|
|
|
|
|
|
float a = ((float)data.stageTicks % (float)handAnimationData.cycleTime) / (float)handAnimationData.cycleTime * 360f;
|
|
|
|
|
float m = (data.actorFacing == Rot4.North ? 1f : -1f) * (handAnimationData.mirror ? -1f : 1f) * (pawn.TryGetComp<CompBodyAnimator>().Mirror ? -1f : 1f);
|
|
|
|
|
|
|
|
|
|
handPosition.x = (Mathf.Sin(a / 180f * Mathf.PI) * 0.05f - 0.025f) * m;
|
|
|
|
|
handPosition.z = Mathf.Cos(a / 180f * Mathf.PI) * 0.015f + 0.03f;
|
|
|
|
|
|
|
|
|
|
handPosition = handPosition.RotatedBy(baseAngle);
|
|
|
|
|
|
|
|
|
|
return handPosition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Vector3 Motion_RubGenitals_FacingEW(Pawn pawn, HandAnimationData handAnimationData, float baseAngle)
|
|
|
|
|
{
|
|
|
|
|
Vector3 handPosition = new Vector3();
|
|
|
|
|
ActorAnimationData data = pawn.GetAnimationData();
|
|
|
|
|
|
|
|
|
|
float a = ((float)data.stageTicks % (float)handAnimationData.cycleTime) / (float)handAnimationData.cycleTime * 360f;
|
|
|
|
|
float m = (data.actorFacing == Rot4.West ? 1f : -1f) * (handAnimationData.mirror ? -1f : 1f);
|
|
|
|
|
|
|
|
|
|
handPosition.x = (Mathf.Sin(a / 180f * Mathf.PI) * 0.005f - 0.05f) * m;
|
|
|
|
|
handPosition.z = Mathf.Cos(a / 180f * Mathf.PI) * 0.015f;
|
|
|
|
|
//handPosition.y = -0.1f;
|
|
|
|
|
|
|
|
|
|
handPosition = handPosition.RotatedBy(baseAngle);
|
|
|
|
|
|
|
|
|
|
return handPosition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Vector3 Motion_RubBreasts_FacingNS(Pawn pawn, HandAnimationData handAnimationData, float baseAngle)
|
|
|
|
|
{
|
|
|
|
|
Vector3 handPosition = new Vector3();
|
|
|
|
|
ActorAnimationData data = pawn.GetAnimationData();
|
|
|
|
|
|
|
|
|
|
float a = ((float)data.stageTicks % (float)handAnimationData.cycleTime) / (float)handAnimationData.cycleTime * 360f;
|
|
|
|
|
float m = (data.actorFacing == Rot4.North ? -1f : 1f) * (handAnimationData.mirror ? -1f : 1f) * (pawn.TryGetComp<CompBodyAnimator>().Mirror ? -1f : 1f);
|
|
|
|
|
float size = GetGenitalSize(pawn, "breasts");
|
|
|
|
|
|
|
|
|
|
handPosition.x = (Mathf.Sin(a / 180f * Mathf.PI) * 0.05f * size - size * 0.25f) * m;
|
|
|
|
|
handPosition.z = Mathf.Cos(a / 180f * Mathf.PI) * 0.015f - size * 0.125f;
|
|
|
|
|
|
|
|
|
|
handPosition = handPosition.RotatedBy(baseAngle);
|
|
|
|
|
|
|
|
|
|
return handPosition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Vector3 Motion_RubBreasts_FacingEW(Pawn pawn, HandAnimationData handAnimationData, float baseAngle)
|
|
|
|
|
{
|
|
|
|
|
Vector3 handPosition = new Vector3();
|
|
|
|
|
ActorAnimationData data = pawn.GetAnimationData();
|
|
|
|
|
|
|
|
|
|
float a = ((float)data.stageTicks % (float)handAnimationData.cycleTime) / (float)handAnimationData.cycleTime * 360f;
|
|
|
|
|
float m = (data.actorFacing == Rot4.West ? 1f : -1f) * (handAnimationData.mirror ? -1f : 1f);
|
|
|
|
|
float size = GetGenitalSize(pawn, "breasts");
|
|
|
|
|
|
|
|
|
|
handPosition.x = (Mathf.Sin(a / 180f * Mathf.PI) * 0.005f - size * 0.25f) * m;
|
|
|
|
|
handPosition.z = Mathf.Cos(a / 180f * Mathf.PI) * 0.015f - size * 0.125f;
|
|
|
|
|
|
|
|
|
|
handPosition = handPosition.RotatedBy(baseAngle);
|
|
|
|
|
|
|
|
|
|
return handPosition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Graphic GetHandGraphic(Pawn touchingPawn, string touchedBodyAddonName, HandAnimationData handAnimationData)
|
|
|
|
|
{
|
|
|
|
|
string handGraphicPath = "Hands/HandClean";
|
|
|
|
|
Color skinColour = touchingPawn.story.SkinColor;
|
|
|
|
|
float handSize = 0.6667f * touchingPawn.RaceProps.baseBodySize;
|
|
|
|
|
|
|
|
|
|
return GraphicDatabase.Get<Graphic_Single>(handGraphicPath, ShaderDatabase.Cutout, new Vector2(handSize, handSize), skinColour);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static bool TryToDrawHand(Pawn pawn, string bodyAddonName, Vector3 bodyAddonPosition, float bodyAddonAngle, Rot4 bodyAddonRotation, PawnRenderFlags renderFlags)
|
|
|
|
|
{
|
2022-09-11 06:05:16 +00:00
|
|
|
|
if (BodyPartIsBeingTouched(pawn, bodyAddonName, out List<HandAnimationData> handAnimationData))
|
2022-09-10 01:22:08 +00:00
|
|
|
|
{
|
|
|
|
|
foreach (HandAnimationData datum in handAnimationData)
|
|
|
|
|
{
|
|
|
|
|
Pawn touchingPawn = datum.touchingActorID >= 0 && pawn.GetAllSexParticipants().Count > datum.touchingActorID ? pawn.GetAllSexParticipants()[datum.touchingActorID] : pawn;
|
|
|
|
|
|
|
|
|
|
Graphic handgraphic = GetHandGraphic(touchingPawn, bodyAddonName, datum);
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|