mirror of
				https://gitgud.io/c0ffeeeeeeee/rimworld-animations.git
				synced 2024-08-15 00:43:45 +00:00 
			
		
		
		
	commit
This commit is contained in:
		
							parent
							
								
									74a34b6f8d
								
							
						
					
					
						commit
						55ae1c5d10
					
				
					 29 changed files with 1387 additions and 28 deletions
				
			
		| 
						 | 
				
			
			@ -62,33 +62,33 @@
 | 
			
		|||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Compile Include="Properties\AssemblyInfo.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Actors\Actor.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Animations\AnimationStage.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Animations\Clips\BaseAnimationClip.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Animations\Clips\PawnAnimationClip.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Animations\Clips\ThingAnimationClip.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Animations\Keyframes\Keyframe.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Animations\Keyframes\PawnKeyframe.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Animations\Keyframes\ThingKeyframe.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\AnimationUtility.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Comps\CompBodyAnimator.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Comps\CompProperties_BodyAnimator.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Comps\CompProperties_ThingAnimator.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Comps\CompThingAnimator.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Defs\AnimationDef.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\JobDrivers\JobDriver_SexBaseRecieverLovedForAnimation.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\JobDrivers\JobDriver_SexCasualForAnimation.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\MainTabWindows\MainTabWindow_SexAnimator.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Patches\HarmonyPatch_AlienRace.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Patches\HarmonyPatch_FacialAnimation.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Patches\HarmonyPatch_PawnRenderer.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Patches\HarmonyPatch_Pawn_DrawTracker.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Patches\HarmonyPatch_ShowHairWithHats.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Patches\Harmony_PatchAll.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Patches\rjwPatches\HarmonyPatch_JobDriver_SexBaseInitiator.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Patches\rjwPatches\HarmonyPatch_JoinInBedGiveJob.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Patches\rjwPatches\HarmonyPatch_SexTick.cs" />
 | 
			
		||||
    <Compile Include="Source\Rimworld-Animations\Patches\rjwPatches\HarmonyPatch_WorkGiverSex.cs" />
 | 
			
		||||
    <Compile Include="Source\Actors\Actor.cs" />
 | 
			
		||||
    <Compile Include="Source\Animations\AnimationStage.cs" />
 | 
			
		||||
    <Compile Include="Source\Animations\Clips\BaseAnimationClip.cs" />
 | 
			
		||||
    <Compile Include="Source\Animations\Clips\PawnAnimationClip.cs" />
 | 
			
		||||
    <Compile Include="Source\Animations\Clips\ThingAnimationClip.cs" />
 | 
			
		||||
    <Compile Include="Source\Animations\Keyframes\Keyframe.cs" />
 | 
			
		||||
    <Compile Include="Source\Animations\Keyframes\PawnKeyframe.cs" />
 | 
			
		||||
    <Compile Include="Source\Animations\Keyframes\ThingKeyframe.cs" />
 | 
			
		||||
    <Compile Include="Source\AnimationUtility.cs" />
 | 
			
		||||
    <Compile Include="Source\Comps\CompBodyAnimator.cs" />
 | 
			
		||||
    <Compile Include="Source\Comps\CompProperties_BodyAnimator.cs" />
 | 
			
		||||
    <Compile Include="Source\Comps\CompProperties_ThingAnimator.cs" />
 | 
			
		||||
    <Compile Include="Source\Comps\CompThingAnimator.cs" />
 | 
			
		||||
    <Compile Include="Source\Defs\AnimationDef.cs" />
 | 
			
		||||
    <Compile Include="Source\JobDrivers\JobDriver_SexBaseRecieverLovedForAnimation.cs" />
 | 
			
		||||
    <Compile Include="Source\JobDrivers\JobDriver_SexCasualForAnimation.cs" />
 | 
			
		||||
    <Compile Include="Source\MainTabWindows\MainTabWindow_SexAnimator.cs" />
 | 
			
		||||
    <Compile Include="Source\Patches\HarmonyPatch_AlienRace.cs" />
 | 
			
		||||
    <Compile Include="Source\Patches\HarmonyPatch_FacialAnimation.cs" />
 | 
			
		||||
    <Compile Include="Source\Patches\HarmonyPatch_PawnRenderer.cs" />
 | 
			
		||||
    <Compile Include="Source\Patches\HarmonyPatch_Pawn_DrawTracker.cs" />
 | 
			
		||||
    <Compile Include="Source\Patches\HarmonyPatch_ShowHairWithHats.cs" />
 | 
			
		||||
    <Compile Include="Source\Patches\Harmony_PatchAll.cs" />
 | 
			
		||||
    <Compile Include="Source\Patches\rjwPatches\HarmonyPatch_JobDriver_SexBaseInitiator.cs" />
 | 
			
		||||
    <Compile Include="Source\Patches\rjwPatches\HarmonyPatch_JoinInBedGiveJob.cs" />
 | 
			
		||||
    <Compile Include="Source\Patches\rjwPatches\HarmonyPatch_SexTick.cs" />
 | 
			
		||||
    <Compile Include="Source\Patches\rjwPatches\HarmonyPatch_WorkGiverSex.cs" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup />
 | 
			
		||||
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										18
									
								
								Source/Actors/Actor.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								Source/Actors/Actor.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
    public class Actor {
 | 
			
		||||
        public List<string> defNames;
 | 
			
		||||
        public List<string> requiredGenitals;
 | 
			
		||||
        public bool activeRole = false;
 | 
			
		||||
        public string gender;
 | 
			
		||||
        public bool isFucking = false;
 | 
			
		||||
        public bool isFucked = false;
 | 
			
		||||
        public Vector3 offset = new Vector3(0, 0, 0);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										114
									
								
								Source/AnimationUtility.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								Source/AnimationUtility.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,114 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
    public static class AnimationUtility {
 | 
			
		||||
        /*  
 | 
			
		||||
         Note: always make the list in this order:
 | 
			
		||||
             Female pawns, animal female pawns, male pawns, animal male pawns
 | 
			
		||||
        */
 | 
			
		||||
        public static AnimationDef tryFindAnimation(ref List<Pawn> participants) {
 | 
			
		||||
 | 
			
		||||
            //aggressors first
 | 
			
		||||
            participants = participants.OrderByDescending(p => p.jobs.curDriver is rjw.JobDriver_SexBaseInitiator).ToList();
 | 
			
		||||
 | 
			
		||||
            //fucked first, fucking second
 | 
			
		||||
            participants = participants.OrderBy(p => rjw.xxx.can_fuck(p)).ToList();
 | 
			
		||||
 | 
			
		||||
            List<Pawn> localParticipants = new List<Pawn>(participants);
 | 
			
		||||
 | 
			
		||||
            IEnumerable<AnimationDef> options = DefDatabase<AnimationDef>.AllDefs.Where((AnimationDef x) => {
 | 
			
		||||
 | 
			
		||||
                if (x.actors.Count != localParticipants.Count) {
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
                for (int i = 0; i < x.actors.Count; i++) {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                    if(x.actors[i].defNames.Contains("Human")) {
 | 
			
		||||
                        if (!rjw.xxx.is_human(localParticipants[i])) {
 | 
			
		||||
                            if(rjw.RJWSettings.DevMode) {
 | 
			
		||||
                                Log.Message(x.defName.ToStringSafe() + " not selected -- " + localParticipants[i].def.defName.ToStringSafe() + " " + localParticipants[i].Name.ToStringSafe() + " is not human");
 | 
			
		||||
                            }
 | 
			
		||||
                            
 | 
			
		||||
                            return false;
 | 
			
		||||
                        }
 | 
			
		||||
                        
 | 
			
		||||
                    } else {
 | 
			
		||||
 | 
			
		||||
                        if (!x.actors[i].defNames.Contains(localParticipants[i].def.defName)) {
 | 
			
		||||
 | 
			
		||||
                            if (rjw.RJWSettings.DevMode) {
 | 
			
		||||
                                Log.Message(x.defName.ToStringSafe() + " not selected -- " + localParticipants[i].def.defName.ToStringSafe() + " " + localParticipants[i].Name.ToStringSafe() + " is not ");
 | 
			
		||||
                                foreach(String defname in x.actors[i].defNames) {
 | 
			
		||||
                                    Log.Message(defname + ", ");
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            return false;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if(x.actors[i].requiredGenitals != null && x.actors[i].requiredGenitals.Contains("Vagina")) {
 | 
			
		||||
 | 
			
		||||
                        if (!rjw.Genital_Helper.has_vagina(localParticipants[i])) {
 | 
			
		||||
                            Log.Message(x.defName.ToStringSafe() + " not selected -- " + localParticipants[i].def.defName.ToStringSafe() + " " + localParticipants[i].Name.ToStringSafe() + " doesn't have vagina");
 | 
			
		||||
                            return false;
 | 
			
		||||
                        } 
 | 
			
		||||
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    //TESTING ANIMATIONS ONLY REMEMBER TO COMMENT OUT BEFORE PUSH
 | 
			
		||||
                    /*
 | 
			
		||||
                    if (x.defName != "Tribadism")
 | 
			
		||||
                        return false;
 | 
			
		||||
                    */
 | 
			
		||||
 | 
			
		||||
                    if (x.actors[i].isFucking && !rjw.xxx.can_fuck(localParticipants[i])) {
 | 
			
		||||
                        Log.Message(x.defName.ToStringSafe() + " not selected -- " + localParticipants[i].def.defName.ToStringSafe() + " " + localParticipants[i].Name.ToStringSafe() + " can't fuck");
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (x.actors[i].isFucked && !rjw.xxx.can_be_fucked(localParticipants[i])) {
 | 
			
		||||
                        Log.Message(x.defName.ToStringSafe() + " not selected -- " + localParticipants[i].def.defName.ToStringSafe() + " " + localParticipants[i].Name.ToStringSafe() + " can't be fucked");
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                return true;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (options != null && options.Any()) {
 | 
			
		||||
                Log.Message("Randomly selecting animation...");
 | 
			
		||||
                return options.RandomElement();
 | 
			
		||||
            }
 | 
			
		||||
                
 | 
			
		||||
            else
 | 
			
		||||
                return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void RenderPawnHeadMeshInAnimation(Mesh mesh, Vector3 loc, Quaternion quaternion, Material material, bool portrait, Pawn pawn) {
 | 
			
		||||
 | 
			
		||||
            if(pawn == null) {
 | 
			
		||||
                GenDraw.DrawMeshNowOrLater(mesh, loc, quaternion, material, portrait);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            CompBodyAnimator pawnAnimator = pawn.TryGetComp<CompBodyAnimator>();
 | 
			
		||||
 | 
			
		||||
            if (pawnAnimator == null || !pawnAnimator.isAnimating || portrait) {
 | 
			
		||||
                GenDraw.DrawMeshNowOrLater(mesh, loc, quaternion, material, portrait);
 | 
			
		||||
            } else {
 | 
			
		||||
                Vector3 pawnHeadPosition = pawnAnimator.getPawnHeadPosition();
 | 
			
		||||
                pawnHeadPosition.y = loc.y;
 | 
			
		||||
                GenDraw.DrawMeshNowOrLater(mesh, pawnHeadPosition, Quaternion.AngleAxis(pawnAnimator.headAngle, Vector3.up), material, portrait);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								Source/Animations/AnimationStage.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								Source/Animations/AnimationStage.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
    public class AnimationStage
 | 
			
		||||
    {
 | 
			
		||||
        public string stageName;
 | 
			
		||||
        public int stageIndex;
 | 
			
		||||
        public int playTimeTicks = 0;
 | 
			
		||||
        public bool isLooping;
 | 
			
		||||
        public List<BaseAnimationClip> animationClips;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public void initialize() {
 | 
			
		||||
            foreach (BaseAnimationClip clip in animationClips) {
 | 
			
		||||
                clip.buildSimpleCurves();
 | 
			
		||||
                //select playTimeTicks as longest playtime of all the animations
 | 
			
		||||
                if(clip.duration > playTimeTicks) {
 | 
			
		||||
                    playTimeTicks = clip.duration;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								Source/Animations/Clips/BaseAnimationClip.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								Source/Animations/Clips/BaseAnimationClip.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
    public abstract class BaseAnimationClip
 | 
			
		||||
    {
 | 
			
		||||
        public List<ThingDef> types; //types of participants
 | 
			
		||||
        public int duration;
 | 
			
		||||
        public abstract void buildSimpleCurves();
 | 
			
		||||
        public string soundDef = null; //for playing sounds
 | 
			
		||||
        public int actor;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										101
									
								
								Source/Animations/Clips/PawnAnimationClip.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								Source/Animations/Clips/PawnAnimationClip.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,101 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
    public class PawnAnimationClip : BaseAnimationClip {
 | 
			
		||||
 | 
			
		||||
        public List<PawnKeyframe> keyframes;
 | 
			
		||||
        public AltitudeLayer layer = AltitudeLayer.Pawn;
 | 
			
		||||
 | 
			
		||||
        public Dictionary<int, string> SoundEffects = new Dictionary<int, string>();
 | 
			
		||||
        public SimpleCurve BodyAngle = new SimpleCurve();
 | 
			
		||||
        public SimpleCurve HeadAngle = new SimpleCurve();
 | 
			
		||||
        public SimpleCurve HeadBob = new SimpleCurve();
 | 
			
		||||
        public SimpleCurve BodyOffsetX = new SimpleCurve();
 | 
			
		||||
        public SimpleCurve BodyOffsetZ = new SimpleCurve();
 | 
			
		||||
        public SimpleCurve HeadFacing = new SimpleCurve();
 | 
			
		||||
        public SimpleCurve BodyFacing = new SimpleCurve();
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        public override void buildSimpleCurves() {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            int duration = 0;
 | 
			
		||||
            //getting the length of the whole clip
 | 
			
		||||
            foreach(PawnKeyframe frame in keyframes) {
 | 
			
		||||
                duration += frame.tickDuration;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //guarantees loops don't get cut off mid-anim
 | 
			
		||||
            this.duration = duration;
 | 
			
		||||
 | 
			
		||||
            int keyframePosition = 0;
 | 
			
		||||
            foreach (PawnKeyframe frame in keyframes) {
 | 
			
		||||
 | 
			
		||||
                if (frame.atTick.HasValue) {
 | 
			
		||||
                    if (frame.bodyAngle.HasValue)
 | 
			
		||||
                        BodyAngle.Add((float)frame.atTick / (float)duration, frame.bodyAngle.Value, true);
 | 
			
		||||
 | 
			
		||||
                    if (frame.headAngle.HasValue)
 | 
			
		||||
                        HeadAngle.Add((float)frame.atTick / (float)duration, frame.headAngle.Value, true);
 | 
			
		||||
 | 
			
		||||
                    if (frame.bodyOffsetX.HasValue)
 | 
			
		||||
                        BodyOffsetX.Add((float)frame.atTick / (float)duration, frame.bodyOffsetX.Value, true);
 | 
			
		||||
 | 
			
		||||
                    if (frame.bodyOffsetZ.HasValue)
 | 
			
		||||
                        BodyOffsetZ.Add((float)frame.atTick / (float)duration, frame.bodyOffsetZ.Value, true);
 | 
			
		||||
 | 
			
		||||
                    if (frame.headFacing.HasValue)
 | 
			
		||||
                        HeadFacing.Add((float)frame.atTick / (float)duration, frame.headFacing.Value, true);
 | 
			
		||||
 | 
			
		||||
                    if (frame.bodyFacing.HasValue)
 | 
			
		||||
                        BodyFacing.Add((float)frame.atTick / (float)duration, frame.bodyFacing.Value, true);
 | 
			
		||||
 | 
			
		||||
                    if (frame.headBob.HasValue)
 | 
			
		||||
                        HeadBob.Add((float)frame.atTick / (float)duration, frame.headBob.Value, true);
 | 
			
		||||
 | 
			
		||||
                    if (frame.soundEffect != null) {
 | 
			
		||||
                        SoundEffects.Add((int)frame.atTick, frame.soundEffect);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    if (frame.bodyAngle.HasValue)
 | 
			
		||||
                        BodyAngle.Add((float)keyframePosition / (float)duration, frame.bodyAngle.Value, true);
 | 
			
		||||
 | 
			
		||||
                    if (frame.headAngle.HasValue)
 | 
			
		||||
                        HeadAngle.Add((float)keyframePosition / (float)duration, frame.headAngle.Value, true);
 | 
			
		||||
 | 
			
		||||
                    if (frame.bodyOffsetX.HasValue)
 | 
			
		||||
                        BodyOffsetX.Add((float)keyframePosition / (float)duration, frame.bodyOffsetX.Value, true);
 | 
			
		||||
 | 
			
		||||
                    if (frame.bodyOffsetZ.HasValue)
 | 
			
		||||
                        BodyOffsetZ.Add((float)keyframePosition / (float)duration, frame.bodyOffsetZ.Value, true);
 | 
			
		||||
 | 
			
		||||
                    if (frame.headFacing.HasValue)
 | 
			
		||||
                        HeadFacing.Add((float)keyframePosition / (float)duration, frame.headFacing.Value, true);
 | 
			
		||||
 | 
			
		||||
                    if (frame.bodyFacing.HasValue)
 | 
			
		||||
                        BodyFacing.Add((float)keyframePosition / (float)duration, frame.bodyFacing.Value, true);
 | 
			
		||||
 | 
			
		||||
                    if (frame.headBob.HasValue)
 | 
			
		||||
                        HeadBob.Add((float)keyframePosition / (float)duration, frame.headBob.Value, true);
 | 
			
		||||
 | 
			
		||||
                    if (frame.soundEffect != null) {
 | 
			
		||||
                        SoundEffects.Add(keyframePosition, frame.soundEffect);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    keyframePosition += frame.tickDuration;
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								Source/Animations/Clips/ThingAnimationClip.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								Source/Animations/Clips/ThingAnimationClip.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
    public class ThingAnimationClip : BaseAnimationClip
 | 
			
		||||
    {
 | 
			
		||||
        public List<ThingKeyframe> keyframes;
 | 
			
		||||
 | 
			
		||||
        public override void buildSimpleCurves() {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								Source/Animations/Keyframes/Keyframe.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								Source/Animations/Keyframes/Keyframe.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
    public abstract class Keyframe
 | 
			
		||||
    {
 | 
			
		||||
        public int tickDuration = 1;
 | 
			
		||||
        
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								Source/Animations/Keyframes/PawnKeyframe.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								Source/Animations/Keyframes/PawnKeyframe.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
    public class PawnKeyframe : Keyframe
 | 
			
		||||
    {
 | 
			
		||||
        public float? bodyAngle;
 | 
			
		||||
        public float? headAngle;
 | 
			
		||||
 | 
			
		||||
        public float? bodyOffsetZ;
 | 
			
		||||
        public float? bodyOffsetX;
 | 
			
		||||
 | 
			
		||||
        public float? headBob;
 | 
			
		||||
        //todo: add headOffsets l/r?
 | 
			
		||||
 | 
			
		||||
        public int? bodyFacing;
 | 
			
		||||
        public int? headFacing;
 | 
			
		||||
 | 
			
		||||
        public string soundEffect;
 | 
			
		||||
 | 
			
		||||
        public float? atTick;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								Source/Animations/Keyframes/ThingKeyframe.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Source/Animations/Keyframes/ThingKeyframe.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
    public class ThingKeyframe : Keyframe
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										238
									
								
								Source/Comps/CompBodyAnimator.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										238
									
								
								Source/Comps/CompBodyAnimator.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,238 @@
 | 
			
		|||
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) {
 | 
			
		||||
                    xxx.DrawNude(pawn);
 | 
			
		||||
                } else {
 | 
			
		||||
                    pawn.Drawer.renderer.graphics.ResolveAllGraphics();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                PortraitsCache.SetDirty(pawn);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        private bool Animating;
 | 
			
		||||
        private bool mirror = false;
 | 
			
		||||
        private int actor;
 | 
			
		||||
 | 
			
		||||
        private int animTicks = 0, stageTicks = 0, clipTicks = 0;
 | 
			
		||||
        private int curStage = 0;
 | 
			
		||||
        private float clipPercent = 0;
 | 
			
		||||
 | 
			
		||||
        public Vector3 anchor, deltaPos, headBob;
 | 
			
		||||
        public float bodyAngle, headAngle;
 | 
			
		||||
        public Rot4 headFacing, bodyFacing;
 | 
			
		||||
 | 
			
		||||
        private AnimationDef anim;
 | 
			
		||||
        private AnimationStage stage => anim.animationStages[curStage];
 | 
			
		||||
        private PawnAnimationClip clip => (PawnAnimationClip)stage.animationClips[actor];
 | 
			
		||||
 | 
			
		||||
        public void setAnchor(IntVec3 pos)
 | 
			
		||||
        {
 | 
			
		||||
            anchor = pos.ToVector3();
 | 
			
		||||
        }
 | 
			
		||||
        public void setAnchor(Thing thing) {
 | 
			
		||||
            anchor = thing.Position.ToVector3();
 | 
			
		||||
            //center on bed
 | 
			
		||||
            if(thing is Building_Bed) {
 | 
			
		||||
                if(((Building_Bed)thing).SleepingSlotsCount == 2) {
 | 
			
		||||
                    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;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        public void StartAnimation(AnimationDef anim, int actor, bool mirror = false) {
 | 
			
		||||
 | 
			
		||||
            isAnimating = true;
 | 
			
		||||
 | 
			
		||||
            pawn.jobs.posture = PawnPosture.Standing;
 | 
			
		||||
 | 
			
		||||
            this.actor = actor;
 | 
			
		||||
            this.anim = anim;
 | 
			
		||||
            this.mirror = mirror;
 | 
			
		||||
 | 
			
		||||
            curStage = 0;
 | 
			
		||||
            animTicks = 0;
 | 
			
		||||
            stageTicks = 0;
 | 
			
		||||
            clipTicks = 0;
 | 
			
		||||
 | 
			
		||||
            //tick once for initialization
 | 
			
		||||
            tickAnim();
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        public override void CompTick() {
 | 
			
		||||
            base.CompTick();
 | 
			
		||||
 | 
			
		||||
            //maybe this is causing anim to stop mid?
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            if(Animating) {
 | 
			
		||||
 | 
			
		||||
                tickAnim();
 | 
			
		||||
 | 
			
		||||
                if (pawn?.jobs?.curDriver == null || (pawn?.jobs?.curDriver != null && !(pawn?.jobs?.curDriver is rjw.JobDriver_Sex))) {
 | 
			
		||||
                    Animating = false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        public void animatePawn(ref Vector3 rootLoc, ref float angle, ref Rot4 bodyFacing, ref Rot4 headFacing) {
 | 
			
		||||
 | 
			
		||||
            if(!Animating) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            rootLoc = anchor + deltaPos;
 | 
			
		||||
            angle = bodyAngle;
 | 
			
		||||
            bodyFacing = this.bodyFacing;
 | 
			
		||||
            headFacing = this.headFacing;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void tickGraphics(PawnGraphicSet graphics) {
 | 
			
		||||
            this.Graphics = graphics;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void tickAnim() {
 | 
			
		||||
 | 
			
		||||
            if (!Animating) return;
 | 
			
		||||
 | 
			
		||||
            animTicks++;
 | 
			
		||||
            if (animTicks < anim.animationTimeTicks) {
 | 
			
		||||
                tickStage();
 | 
			
		||||
            } else {
 | 
			
		||||
                Animating = false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void tickStage()
 | 
			
		||||
        {
 | 
			
		||||
            stageTicks++;
 | 
			
		||||
 | 
			
		||||
            if(stageTicks >= stage.playTimeTicks) {
 | 
			
		||||
                curStage++;
 | 
			
		||||
                stageTicks = 0;
 | 
			
		||||
                clipTicks = 0;
 | 
			
		||||
                clipPercent = 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            tickClip();
 | 
			
		||||
            
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void tickClip() {
 | 
			
		||||
 | 
			
		||||
            clipTicks++;
 | 
			
		||||
 | 
			
		||||
            //play sound effect
 | 
			
		||||
            if(rjw.RJWSettings.sounds_enabled && clip.SoundEffects.ContainsKey(clipTicks)) {
 | 
			
		||||
                SoundDef.Named(clip.SoundEffects[clipTicks]).PlayOneShot(new TargetInfo(pawn.Position, pawn.Map));
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            //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));
 | 
			
		||||
            bodyAngle = clip.BodyAngle.Evaluate(clipPercent) * (mirror ? -1 : 1);
 | 
			
		||||
            headAngle = clip.HeadAngle.Evaluate(clipPercent) * (mirror ? -1 : 1);
 | 
			
		||||
            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));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										17
									
								
								Source/Comps/CompProperties_BodyAnimator.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								Source/Comps/CompProperties_BodyAnimator.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
    class CompProperties_BodyAnimator : CompProperties
 | 
			
		||||
    {
 | 
			
		||||
        public CompProperties_BodyAnimator() {
 | 
			
		||||
 | 
			
		||||
            base.compClass = typeof(CompBodyAnimator);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								Source/Comps/CompProperties_ThingAnimator.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Source/Comps/CompProperties_ThingAnimator.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
    class CompProperties_ThingAnimator
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								Source/Comps/CompThingAnimator.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Source/Comps/CompThingAnimator.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
    class CompThingAnimator
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								Source/Defs/AnimationDef.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Source/Defs/AnimationDef.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
    public class AnimationDef : Def
 | 
			
		||||
    {
 | 
			
		||||
        public List<AnimationStage> animationStages;
 | 
			
		||||
        public List<Actor> actors;
 | 
			
		||||
        public int animationTimeTicks = 0; //do not set manually
 | 
			
		||||
        public bool sounds = false;
 | 
			
		||||
 | 
			
		||||
        public override void PostLoad() {
 | 
			
		||||
            base.PostLoad();
 | 
			
		||||
            foreach(AnimationStage stage in animationStages) {
 | 
			
		||||
                stage.initialize();
 | 
			
		||||
                animationTimeTicks += stage.playTimeTicks;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,62 @@
 | 
			
		|||
using System.Collections.Generic;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
using System;
 | 
			
		||||
using rjw;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
	public class JobDriver_SexBaseRecieverLovedForAnimation : JobDriver_SexBaseReciever {
 | 
			
		||||
 | 
			
		||||
		public readonly TargetIndex ipartner = TargetIndex.A;
 | 
			
		||||
		public readonly TargetIndex ibed = TargetIndex.B;
 | 
			
		||||
 | 
			
		||||
		public Pawn Partner => (Pawn)(job.GetTarget(ipartner));
 | 
			
		||||
		public new Building_Bed Bed => (Building_Bed)(job.GetTarget(ibed));
 | 
			
		||||
 | 
			
		||||
		protected override IEnumerable<Toil> MakeNewToils() {
 | 
			
		||||
			setup_ticks();
 | 
			
		||||
			parteners.Add(Partner);// add job starter, so this wont fail, before Initiator starts his job
 | 
			
		||||
								   //--Log.Message("[RJW]JobDriver_GettinLoved::MakeNewToils is called");
 | 
			
		||||
 | 
			
		||||
			float partner_ability = xxx.get_sex_ability(Partner);
 | 
			
		||||
 | 
			
		||||
			// More/less hearts based on partner ability.
 | 
			
		||||
			if (partner_ability < 0.8f)
 | 
			
		||||
				ticks_between_thrusts += 100;
 | 
			
		||||
			else if (partner_ability > 2.0f)
 | 
			
		||||
				ticks_between_thrusts -= 25;
 | 
			
		||||
 | 
			
		||||
			// More/less hearts based on opinion.
 | 
			
		||||
			if (pawn.relations.OpinionOf(Partner) < 0)
 | 
			
		||||
				ticks_between_hearts += 50;
 | 
			
		||||
			else if (pawn.relations.OpinionOf(Partner) > 60)
 | 
			
		||||
				ticks_between_hearts -= 25;
 | 
			
		||||
 | 
			
		||||
			this.FailOnDespawnedOrNull(ipartner);
 | 
			
		||||
			this.FailOn(() => !Partner.health.capacities.CanBeAwake);
 | 
			
		||||
			this.FailOn(() => pawn.Drafted);
 | 
			
		||||
			this.KeepLyingDown(ibed);
 | 
			
		||||
			yield return Toils_Reserve.Reserve(ipartner, 1, 0);
 | 
			
		||||
			yield return Toils_Reserve.Reserve(ibed, Bed.SleepingSlotsCount, 0);
 | 
			
		||||
 | 
			
		||||
			Toil get_loved = Toils_LayDown.LayDown(ibed, true, false, false, false);
 | 
			
		||||
			get_loved.FailOn(() => Partner.CurJobDef != DefDatabase<JobDef>.GetNamed("JoinInBedAnimation", true));
 | 
			
		||||
			get_loved.defaultCompleteMode = ToilCompleteMode.Never;
 | 
			
		||||
			get_loved.socialMode = RandomSocialMode.Off;
 | 
			
		||||
			get_loved.AddPreTickAction(delegate {
 | 
			
		||||
				if (pawn.IsHashIntervalTick(ticks_between_hearts))
 | 
			
		||||
					MoteMaker.ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Heart);
 | 
			
		||||
				if (pawn.IsHashIntervalTick(ticks_between_thrusts))
 | 
			
		||||
					xxx.sexTick(pawn, Partner, false);
 | 
			
		||||
			});
 | 
			
		||||
			get_loved.AddFinishAction(delegate {
 | 
			
		||||
				if (xxx.is_human(pawn))
 | 
			
		||||
					pawn.Drawer.renderer.graphics.ResolveApparelGraphics();
 | 
			
		||||
			});
 | 
			
		||||
			yield return get_loved;
 | 
			
		||||
			
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										92
									
								
								Source/JobDrivers/JobDriver_SexCasualForAnimation.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								Source/JobDrivers/JobDriver_SexCasualForAnimation.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,92 @@
 | 
			
		|||
using RimWorld;
 | 
			
		||||
using rjw;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
    class JobDriver_SexCasualForAnimation : JobDriver_SexBaseInitiator {
 | 
			
		||||
 | 
			
		||||
        public readonly TargetIndex ipartner = TargetIndex.A;
 | 
			
		||||
        public readonly TargetIndex ibed = TargetIndex.B;
 | 
			
		||||
 | 
			
		||||
        public Pawn Partner => (Pawn)job.GetTarget(ipartner);
 | 
			
		||||
        public new Building_Bed Bed => (Building_Bed)job.GetTarget(ibed);
 | 
			
		||||
 | 
			
		||||
        public override bool TryMakePreToilReservations(bool errorOnFailed) {
 | 
			
		||||
            return ReservationUtility.Reserve(base.pawn, Partner, job, xxx.max_rapists_per_prisoner, 0, null, errorOnFailed);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override IEnumerable<Toil> MakeNewToils() {
 | 
			
		||||
            setup_ticks();
 | 
			
		||||
            this.FailOnDespawnedOrNull(ipartner);
 | 
			
		||||
            this.FailOnDespawnedOrNull(ibed);
 | 
			
		||||
            this.FailOn(() => !Partner.health.capacities.CanBeAwake);
 | 
			
		||||
 | 
			
		||||
            yield return Toils_Reserve.Reserve(ipartner, xxx.max_rapists_per_prisoner, 0, null);
 | 
			
		||||
 | 
			
		||||
            Toil goToPawnInBed = Toils_Goto.GotoThing(ipartner, PathEndMode.OnCell);
 | 
			
		||||
            goToPawnInBed.FailOn(() => !RestUtility.InBed(Partner) && !xxx.in_same_bed(Partner, pawn));
 | 
			
		||||
 | 
			
		||||
            yield return goToPawnInBed;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            Toil startPartnerSex = new Toil();
 | 
			
		||||
            startPartnerSex.initAction = delegate {
 | 
			
		||||
 | 
			
		||||
                Log.Message("Attempting to start job...");
 | 
			
		||||
                Job gettinLovedJob = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("GettinLovedAnimation"), pawn, Bed); // new gettin loved toil that wakes up the pawn goes here
 | 
			
		||||
                
 | 
			
		||||
                Partner.jobs.jobQueue.EnqueueFirst(gettinLovedJob);
 | 
			
		||||
                Partner.jobs.EndCurrentJob(JobCondition.InterruptForced);
 | 
			
		||||
            };
 | 
			
		||||
            yield return startPartnerSex;
 | 
			
		||||
 | 
			
		||||
            Toil sexToil = new Toil();
 | 
			
		||||
            sexToil.FailOn(() => (Partner.CurJobDef == null) || Partner.CurJobDef != DefDatabase<JobDef>.GetNamed("GettinLovedAnimation", true)); //partner jobdriver is not sexbaserecieverlovedforanim
 | 
			
		||||
            sexToil.socialMode = RandomSocialMode.Off;
 | 
			
		||||
            sexToil.defaultCompleteMode = ToilCompleteMode.Never;
 | 
			
		||||
            sexToil.initAction = delegate {
 | 
			
		||||
 | 
			
		||||
                usedCondom = (CondomUtility.TryUseCondom(base.pawn) || CondomUtility.TryUseCondom(Partner));
 | 
			
		||||
                Start();
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            sexToil.AddPreTickAction(delegate {
 | 
			
		||||
 | 
			
		||||
                ticks_left--;
 | 
			
		||||
                if(Gen.IsHashIntervalTick(pawn, ticks_between_hearts)) {
 | 
			
		||||
                    MoteMaker.ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Heart);
 | 
			
		||||
                }
 | 
			
		||||
                PawnUtility.GainComfortFromCellIfPossible(pawn, false);
 | 
			
		||||
                PawnUtility.GainComfortFromCellIfPossible(Partner, false);
 | 
			
		||||
                xxx.reduce_rest(Partner);
 | 
			
		||||
                xxx.reduce_rest(pawn, 2);
 | 
			
		||||
                if (ticks_left <= 0)
 | 
			
		||||
                    ReadyForNextToil();
 | 
			
		||||
 | 
			
		||||
            });
 | 
			
		||||
            sexToil.AddFinishAction(delegate {
 | 
			
		||||
 | 
			
		||||
                End();
 | 
			
		||||
                if(xxx.is_human(pawn)) {
 | 
			
		||||
                    pawn.Drawer.renderer.graphics.ResolveApparelGraphics();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            });
 | 
			
		||||
            yield return sexToil;
 | 
			
		||||
 | 
			
		||||
            Toil finish = new Toil();
 | 
			
		||||
            finish.initAction = delegate {
 | 
			
		||||
                SexUtility.ProcessSex(pawn, Partner, usedCondom);    
 | 
			
		||||
            };
 | 
			
		||||
            finish.defaultCompleteMode = ToilCompleteMode.Instant;
 | 
			
		||||
            yield return finish;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								Source/MainTabWindows/MainTabWindow_SexAnimator.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								Source/MainTabWindows/MainTabWindow_SexAnimator.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
    class MainTabWindow_SexAnimator : MainTabWindow
 | 
			
		||||
    {
 | 
			
		||||
        //todo: add animation maker window
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										35
									
								
								Source/Patches/HarmonyPatch_AlienRace.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								Source/Patches/HarmonyPatch_AlienRace.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,35 @@
 | 
			
		|||
using HarmonyLib;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
    [StaticConstructorOnStartup]
 | 
			
		||||
    public static class HarmonyPatch_AlienRace {
 | 
			
		||||
        static HarmonyPatch_AlienRace () {
 | 
			
		||||
			try {
 | 
			
		||||
				((Action)(() => {
 | 
			
		||||
					if (LoadedModManager.RunningModsListForReading.Any(x => x.Name == "Humanoid Alien Races 2.0")) {
 | 
			
		||||
						(new Harmony("rjw")).Patch(AccessTools.Method(typeof(PawnGraphicSet), "ResolveApparelGraphics"),
 | 
			
		||||
							prefix: new HarmonyMethod(AccessTools.Method(typeof(HarmonyPatch_AlienRace), "Prefix_StopResolveAllGraphicsWhileSex")));
 | 
			
		||||
					}
 | 
			
		||||
				}))();
 | 
			
		||||
			}
 | 
			
		||||
			catch (TypeLoadException ex) {
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static bool Prefix_StopResolveAllGraphicsWhileSex(ref Pawn ___pawn) {
 | 
			
		||||
 | 
			
		||||
			if(___pawn.TryGetComp<CompBodyAnimator>() != null && ___pawn.TryGetComp<CompBodyAnimator>().isAnimating) {
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										44
									
								
								Source/Patches/HarmonyPatch_FacialAnimation.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								Source/Patches/HarmonyPatch_FacialAnimation.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,44 @@
 | 
			
		|||
using HarmonyLib;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Reflection.Emit;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
	[StaticConstructorOnStartup]
 | 
			
		||||
	public static class Patch_FacialAnimation {
 | 
			
		||||
 | 
			
		||||
		static Patch_FacialAnimation() {
 | 
			
		||||
			try {
 | 
			
		||||
				((Action)(() => {
 | 
			
		||||
					if (LoadedModManager.RunningModsListForReading.Any(x => x.Name == "[NL] Facial Animation - WIP")) {
 | 
			
		||||
						(new Harmony("rjw")).Patch(AccessTools.Method(AccessTools.TypeByName("FacialAnimation.DrawFaceGraphicsComp"), "DrawGraphics"),
 | 
			
		||||
							prefix: new HarmonyMethod(AccessTools.Method(typeof(Patch_FacialAnimation), "Prefix")));
 | 
			
		||||
					}
 | 
			
		||||
				}))();
 | 
			
		||||
			}
 | 
			
		||||
			catch (TypeLoadException ex) {
 | 
			
		||||
				
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static bool Prefix(ref Pawn ___pawn, ref Rot4 headFacing, ref Vector3 headOrigin, ref Quaternion quaternion, ref bool portrait) {
 | 
			
		||||
 | 
			
		||||
			CompBodyAnimator bodyAnim = ___pawn.TryGetComp<CompBodyAnimator>();
 | 
			
		||||
 | 
			
		||||
			if (bodyAnim.isAnimating && !portrait) {
 | 
			
		||||
 | 
			
		||||
				headFacing = bodyAnim.headFacing;
 | 
			
		||||
				headOrigin = new Vector3(bodyAnim.getPawnHeadPosition().x, headOrigin.y, bodyAnim.getPawnHeadPosition().z);
 | 
			
		||||
				quaternion = Quaternion.AngleAxis(bodyAnim.headAngle, Vector3.up);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										86
									
								
								Source/Patches/HarmonyPatch_PawnRenderer.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								Source/Patches/HarmonyPatch_PawnRenderer.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,86 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using HarmonyLib;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Reflection.Emit;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
 | 
			
		||||
	[HarmonyPatch(typeof(PawnRenderer), "RenderPawnInternal", new Type[]
 | 
			
		||||
	{
 | 
			
		||||
		typeof(Vector3),
 | 
			
		||||
		typeof(float),
 | 
			
		||||
		typeof(bool),
 | 
			
		||||
		typeof(Rot4),
 | 
			
		||||
		typeof(Rot4),
 | 
			
		||||
		typeof(RotDrawMode),
 | 
			
		||||
		typeof(bool),
 | 
			
		||||
		typeof(bool),
 | 
			
		||||
		typeof(bool)
 | 
			
		||||
	})]
 | 
			
		||||
	
 | 
			
		||||
	public static class HarmonyPatch_PawnRenderer
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
		[HarmonyBefore(new string[] { "showhair.kv.rw", "erdelf.HumanoidAlienRaces", "Nals.FacialAnimation" })]
 | 
			
		||||
		public static void Prefix(PawnRenderer __instance, ref Vector3 rootLoc, ref float angle, bool renderBody, ref Rot4 bodyFacing, ref Rot4 headFacing, RotDrawMode bodyDrawType, bool portrait, bool headStump, bool invisible)
 | 
			
		||||
		{
 | 
			
		||||
			PawnGraphicSet graphics = __instance.graphics;
 | 
			
		||||
			Pawn pawn = graphics.pawn;
 | 
			
		||||
			CompBodyAnimator bodyAnim = pawn.TryGetComp<CompBodyAnimator>();
 | 
			
		||||
 | 
			
		||||
			if (!graphics.AllResolved) {
 | 
			
		||||
				graphics.ResolveAllGraphics();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			
 | 
			
		||||
			if (bodyAnim != null && bodyAnim.isAnimating && !portrait) {
 | 
			
		||||
				bodyAnim.tickGraphics(graphics);
 | 
			
		||||
				pawn.TryGetComp<CompBodyAnimator>().animatePawn(ref rootLoc, ref angle, ref bodyFacing, ref headFacing);
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[HarmonyAfter(new string[] { "showhair.kv.rw", "erdelf.HumanoidAlienRaces", "Nals.FacialAnimation" })]
 | 
			
		||||
		[HarmonyReversePatch(HarmonyReversePatchType.Snapshot)]
 | 
			
		||||
		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) {
 | 
			
		||||
 | 
			
		||||
			MethodInfo drawMeshNowOrLater = AccessTools.Method(typeof(GenDraw), "DrawMeshNowOrLater");//typeof(GenDraw).GetMethod("DrawMeshNowOrLater", BindingFlags.Static | BindingFlags.Public);
 | 
			
		||||
			FieldInfo headGraphic = AccessTools.Field(typeof(PawnGraphicSet), "headGraphic");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
			List<CodeInstruction> codes = instructions.ToList();
 | 
			
		||||
			bool forHead = true;
 | 
			
		||||
			for(int i = 0; i < codes.Count(); i++) {
 | 
			
		||||
 | 
			
		||||
				//Instead of calling drawmeshnoworlater, add pawn to the stack and call my special static method
 | 
			
		||||
				if (codes[i].OperandIs(drawMeshNowOrLater) && forHead) {
 | 
			
		||||
 | 
			
		||||
					yield return new CodeInstruction(OpCodes.Ldarg_0);
 | 
			
		||||
					yield return new CodeInstruction(OpCodes.Ldfld, AccessTools.DeclaredField(typeof(PawnRenderer), "pawn"));
 | 
			
		||||
					yield return new CodeInstruction(OpCodes.Call, AccessTools.DeclaredMethod(typeof(AnimationUtility), nameof(AnimationUtility.RenderPawnHeadMeshInAnimation)));
 | 
			
		||||
 | 
			
		||||
				}
 | 
			
		||||
				//checking for if(graphics.headGraphic != null)
 | 
			
		||||
				else if (codes[i].opcode == OpCodes.Ldfld && codes[i].OperandIs(headGraphic)) {
 | 
			
		||||
					forHead = true;
 | 
			
		||||
					yield return codes[i];
 | 
			
		||||
				} 
 | 
			
		||||
				//checking for if(renderbody)
 | 
			
		||||
				else if(codes[i].opcode == OpCodes.Ldarg_3) {
 | 
			
		||||
					forHead = false;
 | 
			
		||||
					yield return codes[i];
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					yield return codes[i];
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								Source/Patches/HarmonyPatch_Pawn_DrawTracker.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Source/Patches/HarmonyPatch_Pawn_DrawTracker.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
using HarmonyLib;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
 | 
			
		||||
    [HarmonyPatch(typeof(Pawn_DrawTracker), "DrawPos", MethodType.Getter)]
 | 
			
		||||
    public static class HarmonyPatch_Pawn_DrawTracker {
 | 
			
		||||
        public static bool Prefix(ref Pawn ___pawn, ref Vector3 __result) {
 | 
			
		||||
 | 
			
		||||
            if(___pawn.TryGetComp<CompBodyAnimator>() != null && ___pawn.TryGetComp<CompBodyAnimator>().isAnimating) {
 | 
			
		||||
                __result = ___pawn.TryGetComp<CompBodyAnimator>().anchor + ___pawn.TryGetComp<CompBodyAnimator>().deltaPos;
 | 
			
		||||
                ___pawn.Position = __result.ToIntVec3();
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										50
									
								
								Source/Patches/HarmonyPatch_ShowHairWithHats.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								Source/Patches/HarmonyPatch_ShowHairWithHats.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
using HarmonyLib;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Reflection.Emit;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
    [StaticConstructorOnStartup]
 | 
			
		||||
    public static class Patch_ShowHairWithHats {
 | 
			
		||||
 | 
			
		||||
		static Patch_ShowHairWithHats() {
 | 
			
		||||
			try {
 | 
			
		||||
				((Action)(() =>
 | 
			
		||||
				{
 | 
			
		||||
					if (LoadedModManager.RunningModsListForReading.Any(x => x.Name == "[KV] Show Hair With Hats or Hide All Hats - 1.1")) {
 | 
			
		||||
						(new Harmony("rjw")).Patch(AccessTools.Method(AccessTools.TypeByName("ShowHair.Patch_PawnRenderer_RenderPawnInternal"), "Postfix"), //typeof(ShowHair.Patch_PawnRenderer_RenderPawnInternal), nameof(ShowHair.Patch_PawnRenderer_RenderPawnInternal.Postfix)),
 | 
			
		||||
							transpiler: new HarmonyMethod(AccessTools.Method(typeof(Patch_ShowHairWithHats), "Transpiler")));
 | 
			
		||||
					}
 | 
			
		||||
				}))();
 | 
			
		||||
			}
 | 
			
		||||
			catch (TypeLoadException ex) { }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) {
 | 
			
		||||
 | 
			
		||||
			MethodInfo drawMeshNowOrLater = AccessTools.Method(typeof(GenDraw), "DrawMeshNowOrLater");
 | 
			
		||||
 | 
			
		||||
			List<CodeInstruction> codes = instructions.ToList();
 | 
			
		||||
			for (int i = 0; i < codes.Count(); i++) {
 | 
			
		||||
 | 
			
		||||
				//Instead of calling drawmeshnoworlater, add pawn to the stack and call my special static method
 | 
			
		||||
				if (codes[i].OperandIs(drawMeshNowOrLater)) {
 | 
			
		||||
 | 
			
		||||
					yield return new CodeInstruction(OpCodes.Ldarg_0);
 | 
			
		||||
					yield return new CodeInstruction(OpCodes.Ldfld, AccessTools.DeclaredField(typeof(PawnRenderer), "pawn"));
 | 
			
		||||
					yield return new CodeInstruction(OpCodes.Call, AccessTools.DeclaredMethod(typeof(AnimationUtility), nameof(AnimationUtility.RenderPawnHeadMeshInAnimation)));
 | 
			
		||||
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					yield return codes[i];
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								Source/Patches/Harmony_PatchAll.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								Source/Patches/Harmony_PatchAll.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Verse;
 | 
			
		||||
using HarmonyLib;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
 | 
			
		||||
    [StaticConstructorOnStartup]
 | 
			
		||||
    public static class Harmony_PatchAll {
 | 
			
		||||
 | 
			
		||||
        static Harmony_PatchAll() {
 | 
			
		||||
 | 
			
		||||
            Harmony val = new Harmony("rimworldanim");
 | 
			
		||||
            val.PatchAll(Assembly.GetExecutingAssembly());
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,140 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using HarmonyLib;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse;
 | 
			
		||||
using rjw;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
 | 
			
		||||
    [HarmonyPatch(typeof(JobDriver_SexBaseInitiator), "Start")]
 | 
			
		||||
    static class HarmonyPatch_JobDriver_SexBaseInitiator_Start {
 | 
			
		||||
        public static void Postfix(ref JobDriver_SexBaseInitiator __instance) {
 | 
			
		||||
 | 
			
		||||
			if(__instance is JobDriver_JoinInBed) {
 | 
			
		||||
				Log.Warning("Tried to start wrong JobDriver with Rimworld-Animations installed. If you see this warning soon after installing this mod, it's fine and animated sex will start soon. If you see this a long time after installing, that's a problem.");	
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			Pawn Target = __instance.Target;
 | 
			
		||||
			Pawn pawn = __instance.pawn;
 | 
			
		||||
 | 
			
		||||
			Building_Bed bed = __instance.Bed;
 | 
			
		||||
 | 
			
		||||
			if (__instance is JobDriver_BestialityForFemale)
 | 
			
		||||
				bed = (__instance as JobDriver_BestialityForFemale).Bed;
 | 
			
		||||
			else if (__instance is JobDriver_WhoreIsServingVisitors) {
 | 
			
		||||
				bed = (__instance as JobDriver_WhoreIsServingVisitors).Bed;
 | 
			
		||||
			}
 | 
			
		||||
			else if(__instance is JobDriver_SexCasualForAnimation) {
 | 
			
		||||
				bed = (__instance as JobDriver_SexCasualForAnimation).Bed;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (__instance.Target.jobs?.curDriver is JobDriver_SexBaseReciever) {
 | 
			
		||||
 | 
			
		||||
				if (!(Target.jobs.curDriver as JobDriver_SexBaseReciever).parteners.Contains(pawn)) {
 | 
			
		||||
					(Target.jobs.curDriver as JobDriver_SexBaseReciever).parteners.Add(pawn);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (bed != null) {
 | 
			
		||||
					RerollAnimations(Target, __instance.duration, bed as Thing);
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					RerollAnimations(Target, __instance.duration);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static void RerollAnimations(Pawn pawn, int duration, Thing bed = null) {
 | 
			
		||||
 | 
			
		||||
			if(pawn == null || !(pawn.jobs?.curDriver is JobDriver_SexBaseReciever)) {
 | 
			
		||||
				Log.Message("Error: Tried to reroll animations when pawn isn't sexing");
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			List<Pawn> pawnsToAnimate = (pawn.jobs.curDriver as JobDriver_SexBaseReciever).parteners.ToList();
 | 
			
		||||
 | 
			
		||||
			if (!pawnsToAnimate.Contains(pawn)) {
 | 
			
		||||
				pawnsToAnimate = pawnsToAnimate.Append(pawn).ToList();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			AnimationDef anim = AnimationUtility.tryFindAnimation(ref pawnsToAnimate);
 | 
			
		||||
 | 
			
		||||
			if (anim != null) {
 | 
			
		||||
 | 
			
		||||
				Log.Message("Now playing " + anim.defName);
 | 
			
		||||
 | 
			
		||||
				bool mirror = GenTicks.TicksGame % 2 == 0;
 | 
			
		||||
				for (int i = 0; i < pawnsToAnimate.Count; i++) {
 | 
			
		||||
 | 
			
		||||
					if (bed != null)
 | 
			
		||||
						pawnsToAnimate[i].TryGetComp<CompBodyAnimator>().setAnchor(bed);
 | 
			
		||||
					else
 | 
			
		||||
						pawnsToAnimate[i].TryGetComp<CompBodyAnimator>().setAnchor(pawn);
 | 
			
		||||
 | 
			
		||||
					pawnsToAnimate[i].TryGetComp<CompBodyAnimator>().StartAnimation(anim, i, mirror);
 | 
			
		||||
					(pawnsToAnimate[i].jobs.curDriver as JobDriver_Sex).ticks_left = anim.animationTimeTicks;
 | 
			
		||||
					(pawnsToAnimate[i].jobs.curDriver as JobDriver_Sex).ticksLeftThisToil = anim.animationTimeTicks;
 | 
			
		||||
					(pawnsToAnimate[i].jobs.curDriver as JobDriver_Sex).duration = anim.animationTimeTicks;
 | 
			
		||||
					(pawnsToAnimate[i].jobs.curDriver as JobDriver_Sex).ticks_remaining = anim.animationTimeTicks;
 | 
			
		||||
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				Log.Message("Anim not found");
 | 
			
		||||
				//if pawn isn't already animating,
 | 
			
		||||
				if (!pawn.TryGetComp<CompBodyAnimator>().isAnimating) {
 | 
			
		||||
					(pawn.jobs.curDriver as JobDriver_SexBaseReciever).increase_time(duration);
 | 
			
		||||
					//they'll just do the thrusting anim
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	[HarmonyPatch(typeof(JobDriver_SexBaseInitiator), "End")]
 | 
			
		||||
	static class HarmonyPatch_JobDriver_SexBaseInitiator_End {
 | 
			
		||||
 | 
			
		||||
		public static void Postfix(ref JobDriver_SexBaseInitiator __instance) {
 | 
			
		||||
 | 
			
		||||
			if (__instance.Target.jobs?.curDriver is JobDriver_SexBaseReciever) {
 | 
			
		||||
				if (__instance.pawn.TryGetComp<CompBodyAnimator>().isAnimating) {
 | 
			
		||||
 | 
			
		||||
					List<Pawn> parteners = (__instance.Target.jobs.curDriver as JobDriver_SexBaseReciever).parteners;
 | 
			
		||||
 | 
			
		||||
					for (int i = 0; i < parteners.Count; i++) {
 | 
			
		||||
 | 
			
		||||
						//prevents pawns who started a new anim from stopping their new anim
 | 
			
		||||
						if (!((parteners[i].jobs.curDriver as JobDriver_SexBaseInitiator) != null && (parteners[i].jobs.curDriver as JobDriver_SexBaseInitiator).Target != __instance.pawn))
 | 
			
		||||
							parteners[i].TryGetComp<CompBodyAnimator>().isAnimating = false;
 | 
			
		||||
 | 
			
		||||
						if (xxx.is_human(parteners[i])) {
 | 
			
		||||
							parteners[i].Drawer.renderer.graphics.ResolveApparelGraphics();
 | 
			
		||||
							PortraitsCache.SetDirty(parteners[i]);
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					__instance.Target.TryGetComp<CompBodyAnimator>().isAnimating = false;
 | 
			
		||||
 | 
			
		||||
					if (xxx.is_human(__instance.Target)) {
 | 
			
		||||
						__instance.Target.Drawer.renderer.graphics.ResolveApparelGraphics();
 | 
			
		||||
						PortraitsCache.SetDirty(__instance.Target);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				(__instance.Target.jobs.curDriver as JobDriver_SexBaseReciever).parteners.Remove(__instance.pawn);
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (xxx.is_human(__instance.pawn)) {
 | 
			
		||||
				__instance.pawn.Drawer.renderer.graphics.ResolveApparelGraphics();
 | 
			
		||||
				PortraitsCache.SetDirty(__instance.pawn);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										71
									
								
								Source/Patches/rjwPatches/HarmonyPatch_JoinInBedGiveJob.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								Source/Patches/rjwPatches/HarmonyPatch_JoinInBedGiveJob.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,71 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using rjw;
 | 
			
		||||
using Verse;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using HarmonyLib;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
    [HarmonyPatch(typeof(JobGiver_JoinInBed), "TryGiveJob")]
 | 
			
		||||
    public static class HarmonyPatch_JoinInBedGiveJob {
 | 
			
		||||
 | 
			
		||||
        public static bool Prefix(ref Job __result, ref Pawn pawn) {
 | 
			
		||||
 | 
			
		||||
			__result = null;
 | 
			
		||||
 | 
			
		||||
			if (!RJWHookupSettings.HookupsEnabled)
 | 
			
		||||
				return false;
 | 
			
		||||
 | 
			
		||||
			if (pawn.Drafted)
 | 
			
		||||
				return false;
 | 
			
		||||
 | 
			
		||||
			if (!SexUtility.ReadyForHookup(pawn))
 | 
			
		||||
				return false;
 | 
			
		||||
 | 
			
		||||
			// We increase the time right away to prevent the fairly expensive check from happening too frequently
 | 
			
		||||
			SexUtility.IncreaseTicksToNextHookup(pawn);
 | 
			
		||||
 | 
			
		||||
			// If the pawn is a whore, or recently had sex, skip the job unless they're really horny
 | 
			
		||||
			if (!xxx.is_frustrated(pawn) && (xxx.is_whore(pawn) || !SexUtility.ReadyForLovin(pawn)))
 | 
			
		||||
				return false;
 | 
			
		||||
 | 
			
		||||
			// This check attempts to keep groups leaving the map, like guests or traders, from turning around to hook up
 | 
			
		||||
			if (pawn.mindState?.duty?.def == DutyDefOf.TravelOrLeave) {
 | 
			
		||||
				// TODO: Some guest pawns keep the TravelOrLeave duty the whole time, I think the ones assigned to guard the pack animals.
 | 
			
		||||
				// That's probably ok, though it wasn't the intention.
 | 
			
		||||
				if (RJWSettings.DebugLogJoinInBed) Log.Message($"[RJW] JoinInBed.TryGiveJob:({xxx.get_pawnname(pawn)}): has TravelOrLeave, no time for lovin!");
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (pawn.CurJob == null || pawn.CurJob.def == JobDefOf.LayDown) {
 | 
			
		||||
				//--Log.Message("   checking pawn and abilities");
 | 
			
		||||
				if (xxx.can_fuck(pawn) || xxx.can_be_fucked(pawn)) {
 | 
			
		||||
					//--Log.Message("   finding partner");
 | 
			
		||||
					Pawn partner = JobGiver_JoinInBed.find_pawn_to_fuck(pawn, pawn.Map);
 | 
			
		||||
 | 
			
		||||
					//--Log.Message("   checking partner");
 | 
			
		||||
					if (partner == null)
 | 
			
		||||
						return false;
 | 
			
		||||
 | 
			
		||||
					// Can never be null, since find checks for bed.
 | 
			
		||||
					Building_Bed bed = partner.CurrentBed();
 | 
			
		||||
 | 
			
		||||
					// Interrupt current job.
 | 
			
		||||
					if (pawn.CurJob != null && pawn.jobs.curDriver != null)
 | 
			
		||||
						pawn.jobs.curDriver.EndJobWith(JobCondition.InterruptForced);
 | 
			
		||||
 | 
			
		||||
					__result = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("JoinInBedAnimation", true), partner, bed);
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								Source/Patches/rjwPatches/HarmonyPatch_SexTick.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								Source/Patches/rjwPatches/HarmonyPatch_SexTick.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,42 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using HarmonyLib;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse;
 | 
			
		||||
using rjw;
 | 
			
		||||
using Verse.Sound;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
 | 
			
		||||
    [HarmonyPatch(typeof(xxx), "sexTick")]
 | 
			
		||||
    public static class HarmonyPatch_SexTick {
 | 
			
		||||
 | 
			
		||||
        public static bool Prefix(ref Pawn pawn, ref Pawn partner, ref bool enablerotation, ref bool pawnnude, ref bool partnernude) {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
			if (enablerotation) {
 | 
			
		||||
				pawn.rotationTracker.Face(((Thing)partner).DrawPos);
 | 
			
		||||
				partner.rotationTracker.Face(((Thing)pawn).DrawPos);
 | 
			
		||||
			}
 | 
			
		||||
			if (RJWSettings.sounds_enabled && !pawn.TryGetComp<CompBodyAnimator>().isAnimating) {
 | 
			
		||||
				SoundDef.Named("Sex").PlayOneShot(new TargetInfo(pawn.Position, pawn.Map));
 | 
			
		||||
			}
 | 
			
		||||
			pawn.Drawer.Notify_MeleeAttackOn((Thing)(object)partner);
 | 
			
		||||
			if (enablerotation) {
 | 
			
		||||
				pawn.rotationTracker.FaceCell(partner.Position);
 | 
			
		||||
			}
 | 
			
		||||
			if (pawnnude && !xxx.has_quirk(pawn, "Endytophile")) {
 | 
			
		||||
				xxx.DrawNude(pawn);
 | 
			
		||||
			}
 | 
			
		||||
			if (partnernude && !xxx.has_quirk(pawn, "Endytophile")) {
 | 
			
		||||
				xxx.DrawNude(partner);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								Source/Patches/rjwPatches/HarmonyPatch_WorkGiverSex.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								Source/Patches/rjwPatches/HarmonyPatch_WorkGiverSex.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,29 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using rjw;
 | 
			
		||||
using HarmonyLib;
 | 
			
		||||
using Verse;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse.AI;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations {
 | 
			
		||||
 | 
			
		||||
    [HarmonyPatch(typeof(WorkGiver_Sex), "JobOnThing")]
 | 
			
		||||
    public static class HarmonyPatch_WorkGiverSex {
 | 
			
		||||
 | 
			
		||||
        public static bool Prefix(ref Job __result, ref Thing t) {
 | 
			
		||||
 | 
			
		||||
            Building_Bed bed = RestUtility.CurrentBed(t as Pawn);
 | 
			
		||||
            if (bed == null) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            __result = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("JoinInBedAnimation", true), t as Pawn, bed);
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
Subproject commit ab9a1d98883cb78d0d40a6bd93d85de7e34b132b
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue