mirror of
https://gitgud.io/AbstractConcept/rimworld-animations-patch.git
synced 2024-08-15 00:43:27 +00:00
170 lines
5.1 KiB
C#
170 lines
5.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using RimWorld;
|
|
using UnityEngine;
|
|
using HarmonyLib;
|
|
using Verse;
|
|
using Rimworld_Animations;
|
|
using rjw;
|
|
|
|
namespace Rimworld_Animations_Patch
|
|
{
|
|
public static class AnimationPatchUtility
|
|
{
|
|
public static int FindTrueAnimationLength(Pawn pawn, out int orgasmTick)
|
|
{
|
|
orgasmTick = int.MaxValue;
|
|
|
|
ActorAnimationData actorAnimationData = pawn.GetAnimationData();
|
|
CompBodyAnimator compBodyAnimator = pawn.TryGetComp<CompBodyAnimator>();
|
|
|
|
// No data
|
|
if (actorAnimationData == null || compBodyAnimator == null)
|
|
{
|
|
DebugMode.Message("There is no actor animation data for " + pawn.NameShortColored);
|
|
orgasmTick = 1500 + (int)(Rand.Value * 1000f);
|
|
|
|
return orgasmTick;
|
|
}
|
|
|
|
AnimationDef anim = actorAnimationData.animationDef;
|
|
int actorId = actorAnimationData.actorID;
|
|
bool isQuickie = compBodyAnimator.fastAnimForQuickie;
|
|
|
|
int ticks = 0;
|
|
|
|
foreach (AnimationStage animStage in anim.animationStages)
|
|
{
|
|
// Legacy: skip the first stage of quickies if there's no playTimeTicksQuick values declared
|
|
if (anim.animationStages.IndexOf(animStage) == 0 && isQuickie && anim.animationStages.Any(x => x.playTimeTicksQuick >= 0) == false)
|
|
{ continue; }
|
|
|
|
int curr_tick = 0;
|
|
|
|
foreach (PawnKeyframe keyframe in (animStage.animationClips[actorId] as PawnAnimationClip).keyframes)
|
|
{
|
|
curr_tick += keyframe.tickDuration;
|
|
|
|
if (keyframe.soundEffect != null && keyframe.soundEffect == "Cum" && orgasmTick > (ticks + curr_tick))
|
|
{ orgasmTick = ticks + curr_tick; }
|
|
|
|
if (isQuickie && animStage.playTimeTicksQuick > 0 && curr_tick >= animStage.playTimeTicksQuick)
|
|
{ break; }
|
|
}
|
|
|
|
ticks += isQuickie && animStage.playTimeTicksQuick > 0 && animStage.playTimeTicksQuick < animStage.playTimeTicks ? animStage.playTimeTicksQuick : animStage.playTimeTicks;
|
|
}
|
|
|
|
// Orgasm tick not found
|
|
if (orgasmTick > ticks)
|
|
{
|
|
// Safeguard for penial, vaginal and anal sex
|
|
if (anim.actors[actorId].isFucked || anim.actors[actorId].isFucking || anim.actors[actorId].requiredGenitals.Any(x => x.ToLower().ContainsAny("penis", "vagina", "anus")))
|
|
{ orgasmTick = Mathf.Clamp(ticks - 5, 0, int.MaxValue); }
|
|
|
|
// Actor does not orgasm
|
|
else
|
|
{ orgasmTick = (int)(ticks * (2f + Rand.Value)); }
|
|
}
|
|
|
|
return ticks;
|
|
|
|
}
|
|
|
|
// Extended version of PawnHeadRotInAnimation (prevents pawn hair from getting messed up when draw in portraits)
|
|
public static Rot4 PawnHeadRotInAnimation(Pawn pawn, Rot4 regularPos, PawnRenderFlags renderFlags)
|
|
{
|
|
if (!renderFlags.FlagSet(PawnRenderFlags.Portrait) && pawn?.TryGetComp<CompBodyAnimator>() != null && pawn.TryGetComp<CompBodyAnimator>().isAnimating)
|
|
{
|
|
return pawn.TryGetComp<CompBodyAnimator>().headFacing;
|
|
}
|
|
|
|
return regularPos;
|
|
}
|
|
|
|
public static BodyPartRecord GetBodyPartRecord(Pawn pawn, string bodyPart)
|
|
{
|
|
if (bodyPart.NullOrEmpty())
|
|
{ return null; }
|
|
|
|
return pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined, null, null).FirstOrDefault(x => x.untranslatedCustomLabel == bodyPart || x.def.defName == bodyPart);
|
|
}
|
|
|
|
public static Vector3 GetAnchorPosition(Pawn pawn, Thing thing = null)
|
|
{
|
|
Vector3 anchor;
|
|
|
|
if (thing == null)
|
|
{ return pawn.Position.ToVector3Shifted(); }
|
|
|
|
int numOfSleepingSlots = 0;
|
|
|
|
if (thing is Building_Bed)
|
|
{ numOfSleepingSlots = BedUtility.GetSleepingSlotsCount(thing.def.size); }
|
|
|
|
// Anchor to the pawn's sleeping slot when masturbating in own bed
|
|
if (thing is Building_Bed && (pawn.ownership.OwnedBed == thing || pawn.CurrentBed() == thing) && pawn.IsMasturbating())
|
|
{
|
|
anchor = RestUtility.GetBedSleepingSlotPosFor(pawn, thing as Building_Bed).ToVector3();
|
|
|
|
if (thing.Rotation.AsInt == 0)
|
|
{
|
|
anchor.x += 0.5f;
|
|
anchor.z += 1f;
|
|
}
|
|
else if (thing.Rotation.AsInt == 1)
|
|
{
|
|
anchor.x += 1f;
|
|
anchor.z += 0.5f;
|
|
}
|
|
else if (thing.Rotation.AsInt == 2)
|
|
{
|
|
anchor.x += 0.5f;
|
|
anchor.z += 0.5f;
|
|
}
|
|
else if (thing.Rotation.AsInt == 3)
|
|
{
|
|
anchor.x += 0f;
|
|
anchor.z += 0.5f;
|
|
}
|
|
}
|
|
|
|
// Anchor to the center of the bed (should work for beds of any size?)
|
|
else if (thing is Building_Bed && numOfSleepingSlots > 0)
|
|
{
|
|
anchor = thing.Position.ToVector3();
|
|
float halfSlots = numOfSleepingSlots / 2f;
|
|
|
|
if (thing.Rotation.AsInt == 0)
|
|
{
|
|
anchor.x += halfSlots;
|
|
anchor.z += 1f;
|
|
}
|
|
else if (thing.Rotation.AsInt == 1)
|
|
{
|
|
anchor.x += 1f;
|
|
anchor.z += (1.0f - halfSlots);
|
|
}
|
|
else if (thing.Rotation.AsInt == 2)
|
|
{
|
|
anchor.x += (1f - halfSlots);
|
|
anchor.z += 0f;
|
|
}
|
|
else if (thing.Rotation.AsInt == 3)
|
|
{
|
|
anchor.x += 0f;
|
|
anchor.z += halfSlots;
|
|
}
|
|
}
|
|
|
|
// Anchor to the centre of the thing
|
|
else
|
|
{
|
|
anchor = thing.Position.ToVector3Shifted();
|
|
}
|
|
|
|
return anchor;
|
|
}
|
|
}
|
|
}
|