2020-04-09 00:43:01 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using RimWorld;
|
|
|
|
|
using rjw;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
using Verse;
|
|
|
|
|
using Verse.Sound;
|
|
|
|
|
|
|
|
|
|
namespace Rimworld_Animations {
|
|
|
|
|
class CompBodyAnimator : ThingComp
|
|
|
|
|
{
|
|
|
|
|
public Pawn pawn => base.parent as Pawn;
|
|
|
|
|
public PawnGraphicSet Graphics;
|
|
|
|
|
|
|
|
|
|
public CompProperties_BodyAnimator Props => (CompProperties_BodyAnimator)(object)base.props;
|
|
|
|
|
|
|
|
|
|
public bool isAnimating {
|
|
|
|
|
get {
|
|
|
|
|
return Animating;
|
|
|
|
|
}
|
|
|
|
|
set {
|
|
|
|
|
Animating = value;
|
|
|
|
|
|
|
|
|
|
if(value == true) {
|
2020-04-26 15:03:57 +00:00
|
|
|
|
SexUtility.DrawNude(pawn);
|
2020-04-09 00:43:01 +00:00
|
|
|
|
} else {
|
|
|
|
|
pawn.Drawer.renderer.graphics.ResolveAllGraphics();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PortraitsCache.SetDirty(pawn);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
private bool Animating;
|
2020-04-21 04:59:09 +00:00
|
|
|
|
private bool mirror = false, quiver = false, shiver = false;
|
2020-04-09 00:43:01 +00:00
|
|
|
|
private int actor;
|
|
|
|
|
|
|
|
|
|
private int animTicks = 0, stageTicks = 0, clipTicks = 0;
|
|
|
|
|
private int curStage = 0;
|
|
|
|
|
private float clipPercent = 0;
|
|
|
|
|
|
|
|
|
|
public Vector3 anchor, deltaPos, headBob;
|
2020-04-29 03:42:53 +00:00
|
|
|
|
public float bodyAngle, headAngle, genitalAngle;
|
2020-04-09 00:43:01 +00:00
|
|
|
|
public Rot4 headFacing, bodyFacing;
|
|
|
|
|
|
2020-04-29 03:42:53 +00:00
|
|
|
|
public bool controlGenitalAngle = false;
|
|
|
|
|
|
2020-04-09 00:43:01 +00:00
|
|
|
|
private AnimationDef anim;
|
|
|
|
|
private AnimationStage stage => anim.animationStages[curStage];
|
|
|
|
|
private PawnAnimationClip clip => (PawnAnimationClip)stage.animationClips[actor];
|
|
|
|
|
|
|
|
|
|
public void setAnchor(IntVec3 pos)
|
|
|
|
|
{
|
2020-04-12 19:22:35 +00:00
|
|
|
|
anchor = pos.ToVector3Shifted();
|
2020-04-09 00:43:01 +00:00
|
|
|
|
}
|
|
|
|
|
public void setAnchor(Thing thing) {
|
2020-04-12 19:22:35 +00:00
|
|
|
|
|
2020-04-09 00:43:01 +00:00
|
|
|
|
//center on bed
|
|
|
|
|
if(thing is Building_Bed) {
|
2020-04-12 19:22:35 +00:00
|
|
|
|
anchor = thing.Position.ToVector3();
|
|
|
|
|
if (((Building_Bed)thing).SleepingSlotsCount == 2) {
|
2020-04-09 00:43:01 +00:00
|
|
|
|
if (thing.Rotation.AsInt == 0) {
|
|
|
|
|
anchor.x += 1;
|
|
|
|
|
anchor.z += 1;
|
|
|
|
|
}
|
|
|
|
|
else if (thing.Rotation.AsInt == 1) {
|
|
|
|
|
anchor.x += 1;
|
|
|
|
|
}
|
|
|
|
|
else if(thing.Rotation.AsInt == 3) {
|
|
|
|
|
anchor.z += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
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;
|
|
|
|
|
} else {
|
|
|
|
|
anchor.z += 0.5f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-12 19:22:35 +00:00
|
|
|
|
else {
|
|
|
|
|
anchor = thing.Position.ToVector3Shifted();
|
|
|
|
|
}
|
2020-04-09 00:43:01 +00:00
|
|
|
|
}
|
2020-04-21 04:59:09 +00:00
|
|
|
|
public void StartAnimation(AnimationDef anim, int actor, bool mirror = false, bool shiver = false) {
|
2020-04-09 00:43:01 +00:00
|
|
|
|
|
|
|
|
|
isAnimating = true;
|
|
|
|
|
|
2020-04-28 03:34:30 +00:00
|
|
|
|
AlienRaceOffset raceOffset = anim?.actors[actor]?.raceOffsets?.Find(x => x.defName == pawn.def.defName);
|
2020-04-18 16:49:03 +00:00
|
|
|
|
|
2020-04-28 03:34:30 +00:00
|
|
|
|
if (raceOffset != null) {
|
|
|
|
|
anchor.x += mirror ? raceOffset.offset.x * -1f : raceOffset.offset.x;
|
|
|
|
|
anchor.z += raceOffset.offset.y;
|
2020-04-18 16:49:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-09 00:43:01 +00:00
|
|
|
|
pawn.jobs.posture = PawnPosture.Standing;
|
|
|
|
|
|
|
|
|
|
this.actor = actor;
|
|
|
|
|
this.anim = anim;
|
|
|
|
|
this.mirror = mirror;
|
|
|
|
|
|
|
|
|
|
curStage = 0;
|
|
|
|
|
animTicks = 0;
|
|
|
|
|
stageTicks = 0;
|
|
|
|
|
clipTicks = 0;
|
|
|
|
|
|
2020-04-21 03:07:15 +00:00
|
|
|
|
quiver = false;
|
2020-04-21 04:59:09 +00:00
|
|
|
|
this.shiver = shiver && AnimationSettings.rapeShiver;
|
2020-04-21 03:07:15 +00:00
|
|
|
|
|
2020-04-29 03:42:53 +00:00
|
|
|
|
controlGenitalAngle = anim.actors[actor].controlGenitalAngle;
|
|
|
|
|
|
2020-04-09 00:43:01 +00:00
|
|
|
|
//tick once for initialization
|
|
|
|
|
tickAnim();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
public override void CompTick() {
|
2020-04-19 01:52:59 +00:00
|
|
|
|
|
2020-04-09 00:43:01 +00:00
|
|
|
|
base.CompTick();
|
|
|
|
|
|
2020-04-20 02:23:36 +00:00
|
|
|
|
if(isAnimating) {
|
2020-04-09 00:43:01 +00:00
|
|
|
|
if (pawn?.jobs?.curDriver == null || (pawn?.jobs?.curDriver != null && !(pawn?.jobs?.curDriver is rjw.JobDriver_Sex))) {
|
2020-04-10 00:03:56 +00:00
|
|
|
|
isAnimating = false;
|
2020-04-09 00:43:01 +00:00
|
|
|
|
}
|
2020-04-19 18:16:49 +00:00
|
|
|
|
else {
|
|
|
|
|
tickAnim();
|
|
|
|
|
}
|
2020-04-09 00:43:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public void animatePawn(ref Vector3 rootLoc, ref float angle, ref Rot4 bodyFacing, ref Rot4 headFacing) {
|
|
|
|
|
|
2020-04-20 02:23:36 +00:00
|
|
|
|
if(!isAnimating) {
|
2020-04-09 00:43:01 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
rootLoc = anchor + deltaPos;
|
|
|
|
|
angle = bodyAngle;
|
|
|
|
|
bodyFacing = this.bodyFacing;
|
|
|
|
|
headFacing = this.headFacing;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void tickGraphics(PawnGraphicSet graphics) {
|
|
|
|
|
this.Graphics = graphics;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void tickAnim() {
|
|
|
|
|
|
2020-04-20 02:23:36 +00:00
|
|
|
|
if (!isAnimating) return;
|
2020-04-09 00:43:01 +00:00
|
|
|
|
|
|
|
|
|
animTicks++;
|
|
|
|
|
if (animTicks < anim.animationTimeTicks) {
|
|
|
|
|
tickStage();
|
|
|
|
|
} else {
|
2020-04-25 18:08:00 +00:00
|
|
|
|
|
2020-04-20 02:23:36 +00:00
|
|
|
|
isAnimating = false;
|
2020-04-09 00:43:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void tickStage()
|
|
|
|
|
{
|
|
|
|
|
stageTicks++;
|
|
|
|
|
|
|
|
|
|
if(stageTicks >= stage.playTimeTicks) {
|
2020-04-20 02:23:36 +00:00
|
|
|
|
|
2020-04-09 00:43:01 +00:00
|
|
|
|
curStage++;
|
2020-04-20 02:23:36 +00:00
|
|
|
|
|
2020-04-09 00:43:01 +00:00
|
|
|
|
stageTicks = 0;
|
|
|
|
|
clipTicks = 0;
|
|
|
|
|
clipPercent = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-25 18:08:00 +00:00
|
|
|
|
if(curStage >= anim.animationStages.Count && animTicks < anim.animationTimeTicks && pawn.jobs.curDriver is JobDriver_SexBaseInitiator) {
|
|
|
|
|
pawn.jobs.curDriver.ReadyForNextToil();
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-09 00:43:01 +00:00
|
|
|
|
tickClip();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void tickClip() {
|
|
|
|
|
|
|
|
|
|
clipTicks++;
|
|
|
|
|
|
|
|
|
|
//play sound effect
|
2020-04-22 18:12:06 +00:00
|
|
|
|
if(rjw.RJWSettings.sounds_enabled && clip.SoundEffects.ContainsKey(clipTicks) && AnimationSettings.soundOverride) {
|
2020-04-09 00:43:01 +00:00
|
|
|
|
SoundDef.Named(clip.SoundEffects[clipTicks]).PlayOneShot(new TargetInfo(pawn.Position, pawn.Map));
|
|
|
|
|
}
|
2020-04-21 03:07:15 +00:00
|
|
|
|
if(AnimationSettings.orgasmQuiver && clip.quiver.ContainsKey(clipTicks)) {
|
|
|
|
|
quiver = clip.quiver[clipTicks];
|
|
|
|
|
}
|
2020-04-09 00:43:01 +00:00
|
|
|
|
|
|
|
|
|
//loop animation if possible
|
|
|
|
|
if (clipPercent >= 1 && stage.isLooping) {
|
|
|
|
|
clipTicks = 1;//warning: don't set to zero or else calculations go wrong
|
|
|
|
|
}
|
|
|
|
|
clipPercent = (float)clipTicks / (float)clip.duration;
|
|
|
|
|
|
|
|
|
|
calculateDrawValues();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void calculateDrawValues() {
|
|
|
|
|
|
|
|
|
|
deltaPos = new Vector3(clip.BodyOffsetX.Evaluate(clipPercent) * (mirror ? -1 : 1), clip.layer.AltitudeFor(), clip.BodyOffsetZ.Evaluate(clipPercent));
|
2020-04-21 04:59:09 +00:00
|
|
|
|
bodyAngle = (clip.BodyAngle.Evaluate(clipPercent) + (quiver || shiver ? ((Rand.Value * AnimationSettings.shiverIntensity) - (AnimationSettings.shiverIntensity / 2f)) : 0f)) * (mirror ? -1 : 1);
|
2020-04-22 18:12:06 +00:00
|
|
|
|
|
|
|
|
|
//don't go past 360 or less than 0
|
|
|
|
|
if (bodyAngle < 0) bodyAngle = 360 - ((-1f*bodyAngle) % 360);
|
|
|
|
|
if (bodyAngle > 360) bodyAngle %= 360;
|
|
|
|
|
|
2020-04-09 00:43:01 +00:00
|
|
|
|
headAngle = clip.HeadAngle.Evaluate(clipPercent) * (mirror ? -1 : 1);
|
2020-04-22 18:12:06 +00:00
|
|
|
|
if (headAngle < 0) headAngle = 360 - ((-1f * headAngle) % 360);
|
|
|
|
|
if (headAngle > 360) headAngle %= 360;
|
|
|
|
|
|
2020-04-29 03:42:53 +00:00
|
|
|
|
if (controlGenitalAngle) {
|
|
|
|
|
genitalAngle = clip.GenitalAngle.Evaluate(clipPercent) * (mirror ? -1 : 1);
|
|
|
|
|
if (genitalAngle < 0) genitalAngle = 360 - ((-1f * genitalAngle) % 360);
|
|
|
|
|
if (genitalAngle > 360) genitalAngle %= 360;
|
|
|
|
|
}
|
2020-04-22 18:12:06 +00:00
|
|
|
|
|
2020-04-09 00:43:01 +00:00
|
|
|
|
bodyFacing = mirror ? new Rot4((int)clip.BodyFacing.Evaluate(clipPercent)).Opposite : new Rot4((int)clip.BodyFacing.Evaluate(clipPercent));
|
|
|
|
|
|
|
|
|
|
bodyFacing = new Rot4((int)clip.BodyFacing.Evaluate(clipPercent));
|
|
|
|
|
if(bodyFacing.IsHorizontal && mirror) {
|
|
|
|
|
bodyFacing = bodyFacing.Opposite;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
headFacing = new Rot4((int)clip.HeadFacing.Evaluate(clipPercent));
|
|
|
|
|
if(headFacing.IsHorizontal && mirror) {
|
|
|
|
|
headFacing = headFacing.Opposite;
|
|
|
|
|
}
|
|
|
|
|
headBob = new Vector3(0, 0, clip.HeadBob.Evaluate(clipPercent));
|
2020-04-29 03:42:53 +00:00
|
|
|
|
|
2020-04-09 00:43:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Vector3 getPawnHeadPosition() {
|
|
|
|
|
|
|
|
|
|
return anchor + deltaPos + Quaternion.AngleAxis(bodyAngle, Vector3.up) * (pawn.Drawer.renderer.BaseHeadOffsetAt(headFacing) + headBob);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void PostExposeData() {
|
|
|
|
|
base.PostExposeData();
|
|
|
|
|
|
|
|
|
|
Scribe_Defs.Look(ref anim, "anim");
|
|
|
|
|
|
|
|
|
|
Scribe_Values.Look(ref animTicks, "animTicks", 1);
|
|
|
|
|
Scribe_Values.Look(ref stageTicks, "stageTicks", 1);
|
|
|
|
|
Scribe_Values.Look(ref clipTicks, "clipTicks", 1);
|
|
|
|
|
Scribe_Values.Look(ref clipPercent, "clipPercent", 1);
|
|
|
|
|
|
|
|
|
|
Scribe_Values.Look(ref mirror, "mirror");
|
|
|
|
|
|
|
|
|
|
Scribe_Values.Look(ref curStage, "curStage", 0);
|
|
|
|
|
Scribe_Values.Look(ref actor, "actor");
|
|
|
|
|
|
|
|
|
|
Scribe_Values.Look(ref Animating, "Animating");
|
|
|
|
|
Scribe_Values.Look(ref anchor, "anchor");
|
|
|
|
|
Scribe_Values.Look(ref deltaPos, "deltaPos");
|
|
|
|
|
Scribe_Values.Look(ref headBob, "headBob");
|
|
|
|
|
Scribe_Values.Look(ref bodyAngle, "bodyAngle");
|
|
|
|
|
Scribe_Values.Look(ref headAngle, "headAngle");
|
|
|
|
|
|
|
|
|
|
Scribe_Values.Look(ref headFacing, "headFacing");
|
|
|
|
|
Scribe_Values.Look(ref headFacing, "bodyFacing");
|
2020-04-21 03:07:15 +00:00
|
|
|
|
|
|
|
|
|
Scribe_Values.Look(ref quiver, "orgasmQuiver");
|
2020-04-09 00:43:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|