diff --git a/1.6/Source/Animations/GroupAnimations/GroupAnimationContexts/GroupAnimationContext.cs b/1.6/Source/Animations/GroupAnimations/GroupAnimationContexts/GroupAnimationContext.cs index 0cb13b6..74d91da 100644 --- a/1.6/Source/Animations/GroupAnimations/GroupAnimationContexts/GroupAnimationContext.cs +++ b/1.6/Source/Animations/GroupAnimations/GroupAnimationContexts/GroupAnimationContext.cs @@ -91,7 +91,7 @@ namespace Rimworld_Animations public List FindAnyWorkingSet(List actors) { - if (whitelist.NullOrEmpty() || actors.Count != whitelist.Count) return null; + if (actors.Count != whitelist.Count) return null; int numActors = actors.Count; @@ -170,7 +170,7 @@ namespace Rimworld_Animations return false; } - if (!blacklist.NullOrEmpty() && index < blacklist.Count && blacklist[index] != null && blacklist[index].PawnTest(actor)) + if (!blacklist.NullOrEmpty() && blacklist[index].PawnTest(actor)) { return false; } diff --git a/1.6/Source/Animations/GroupAnimations/GroupAnimationDef.cs b/1.6/Source/Animations/GroupAnimations/GroupAnimationDef.cs index c314bef..30c9f61 100644 --- a/1.6/Source/Animations/GroupAnimations/GroupAnimationDef.cs +++ b/1.6/Source/Animations/GroupAnimations/GroupAnimationDef.cs @@ -167,9 +167,7 @@ namespace Rimworld_Animations string bodyTypeDef = (pawn.story?.bodyType != null) ? pawn.story.bodyType.ToString() : ""; - //defs without offsetDefs (or fewer than numActors) just get no offset - if (!offsetDefs.NullOrEmpty() && actor < offsetDefs.Count && offsetDefs[actor] != null - && offsetDefs[actor].FindOffset(pawn, out BaseAnimationOffset animationOffset)) + if (offsetDefs[actor].FindOffset(pawn, out BaseAnimationOffset animationOffset)) { position = animationOffset.getOffset(pawn); rotation = animationOffset.getRotation(pawn); diff --git a/1.6/Source/Comps/CompExtendedAnimator.cs b/1.6/Source/Comps/CompExtendedAnimator.cs index fe71c2a..17ce3a3 100644 --- a/1.6/Source/Comps/CompExtendedAnimator.cs +++ b/1.6/Source/Comps/CompExtendedAnimator.cs @@ -26,12 +26,6 @@ namespace Rimworld_Animations { private VoiceDef voice; private VoiceTagDef lastVoiceTag; - //dead actors (corpses) in this pawn's animation; corpses only TickRare, so this comp ticks their animators for them - private List drivenPawns; - - //the renderer's current animation isn't saved by vanilla; reapply it on the first tick after loading - private bool restoreAnimationAfterLoad; - private bool isAnimating = false; @@ -47,7 +41,7 @@ namespace Rimworld_Animations { { get { - return anchor != null && anchor.IsValid; + return anchor != null; } } @@ -141,42 +135,6 @@ namespace Rimworld_Animations { public override void CompTick() { - AnimatorTick(); - - if (!drivenPawns.NullOrEmpty()) - { - foreach (Pawn drivenPawn in drivenPawns.ToList()) - { - CompExtendedAnimator drivenAnimator = drivenPawn?.TryGetComp(); - - //stop driving if the corpse finished, was destroyed or got resurrected (it ticks itself again) - if (drivenAnimator == null || !drivenAnimator.IsAnimating || !drivenPawn.Dead) - { - drivenPawns.Remove(drivenPawn); - continue; - } - - drivenAnimator.AnimatorTick(); - } - } - - base.CompTick(); - } - - public void AddDrivenPawn(Pawn deadPawn) - { - if (drivenPawns == null) drivenPawns = new List(); - drivenPawns.AddDistinct(deadPawn); - } - - public void AnimatorTick() - { - if (restoreAnimationAfterLoad) - { - restoreAnimationAfterLoad = false; - RestoreAnimationAfterLoad(); - } - if (isAnimating) { animationTicks++; @@ -199,6 +157,10 @@ namespace Rimworld_Animations { CheckAndPlaySounds(); } + + + + base.CompTick(); } //returns false if still more animations @@ -224,33 +186,8 @@ namespace Rimworld_Animations { } } - private void RestoreAnimationAfterLoad() - { - if (!isAnimating || animationQueue.NullOrEmpty()) return; - - PawnRenderer renderer = pawn.Drawer?.renderer; - if (renderer?.renderTree == null) return; - - renderer.SetAnimation(animationQueue[0]); - - //resume partway through the current animation instead of from its first frame - renderer.renderTree.animationStartTick = GenTicks.TicksGame - animationTicks; - renderer.SetAllGraphicsDirty(); - } - public void StopAnimating() { - //stop any corpses this pawn was animating, since they can't stop themselves - if (!drivenPawns.NullOrEmpty()) - { - List pawnsToStop = drivenPawns; - drivenPawns = null; - foreach (Pawn drivenPawn in pawnsToStop) - { - drivenPawn?.TryGetComp()?.StopAnimating(); - } - } - isAnimating = false; animationQueue = null; anchor = null; @@ -266,7 +203,6 @@ namespace Rimworld_Animations { this.actorIndex = actorIndex; this.currentGroupAnimation = groupAnimationDef; - drivenPawns = null; ticksSinceLastVoicePlayed = GenTicks.TicksGame; ticksUntilNextVoice = 0; @@ -300,23 +236,9 @@ namespace Rimworld_Animations { Scribe_Collections.Look(ref animationQueue, "animations_queue"); Scribe_Defs.Look(ref currentGroupAnimation, "animations_groupAnimationDef"); Scribe_Deep.Look(ref this.anchor, "animations_anchor"); - //dead pawns count as destroyed, so their references must be saved with saveDestroyedThings or they load as null - Scribe_Collections.Look(ref this.drivenPawns, "animations_drivenPawns", true, LookMode.Reference); Scribe_Values.Look(ref this.offset, "animations_offset", Vector3.zero); Scribe_Values.Look(ref this.rotation, "animations_rotationOffset", 0); Scribe_Defs.Look(ref this.voice, "animations_voice"); - - if (Scribe.mode == LoadSaveMode.PostLoadInit) - { - drivenPawns?.RemoveAll(x => x == null); - - if (isAnimating) - { - //animation defs can go missing between saves (e.g. an anim pack was removed) - if (animationQueue.NullOrEmpty()) isAnimating = false; - else restoreAnimationAfterLoad = true; - } - } } @@ -389,79 +311,123 @@ namespace Rimworld_Animations { public void CheckAndPlaySounds() { - //use held position/map so it also works for pawns inside corpses - Map map = pawn.MapHeld; - if (map == null) return; PawnRenderNode rootNode = pawn.Drawer?.renderer?.renderTree?.rootNode; - //check the rootnode for sounds - if (rootNode != null) + //check if the rootnode has sounds; if so play it + if (rootNode?.AnimationWorker is AnimationWorker_KeyframesExtended animWorker) { - PlaySoundsForNode(rootNode, map); - } - - //do the same for all the child nodes - if (rootNode?.children != null) - { - foreach (PawnRenderNode node in rootNode.children) - { - if (node != null) PlaySoundsForNode(node, map); - } - } - } - - private void PlaySoundsForNode(PawnRenderNode node, Map map) - { - if (!(node.AnimationWorker is AnimationWorker_KeyframesExtended animWorker)) return; - - if (RJWAnimationSettings.playSounds) - { - SoundDef sound = animWorker.soundAtTick(node.tree.AnimationTick, node.tree.currentAnimation, node); + SoundDef sound = animWorker.soundAtTick(rootNode.tree.AnimationTick, rootNode.tree.currentAnimation, rootNode); if (sound != null) { - SoundInfo soundInfo = new TargetInfo(pawn.PositionHeld, map); + SoundInfo soundInfo = new TargetInfo(pawn.Position, pawn.Map); //temp; does not consider non-rjw animations //todo: replace with value stored in comp or somewhere else? soundInfo.volumeFactor = RJWAnimationSettings.soundVolume; + sound.PlayOneShot(soundInfo); } - } - //corpses don't talk - if (!RJWAnimationSettings.playVoices || pawn.Dead) return; - - //play voice sounds - VoiceTagDef voiceTag = animWorker.voiceAtTick(node.tree.AnimationTick, node.tree.currentAnimation, node); - if (voiceTag == null - || (lastVoiceTag == voiceTag && ticksSinceLastVoicePlayed + ticksUntilNextVoice >= GenTicks.TicksGame)) //play a new voice tag, or wait until time elapsed - { - return; - } - - lastVoiceTag = voiceTag; - ticksSinceLastVoicePlayed = GenTicks.TicksGame; - - SoundInfo voiceInfo = new TargetInfo(pawn.PositionHeld, map); - voiceInfo.volumeFactor = RJWAnimationSettings.voicesVolume; - - if (voice != null && voice.sounds.ContainsKey(voiceTag)) - { - ticksUntilNextVoice = voice.ticksBetweenPlays.RandomInRange; - voice.sounds[voiceTag].PlayOneShot(voiceInfo); - } - else if (pawn.RaceProps.Humanlike && RJWAnimationSettings.playHumanlikeVoicesAsDefault) - { - //play default voice - VoiceDef pawnDefaultVoice = (pawn.gender == Gender.Male ? VoiceDefOf.Voice_HumanMale : VoiceDefOf.Voice_HumanFemale); - if (pawnDefaultVoice.sounds.ContainsKey(voiceTag)) + if (RJWAnimationSettings.playVoices) { - ticksUntilNextVoice = pawnDefaultVoice.ticksBetweenPlays.RandomInRange; - pawnDefaultVoice.sounds[voiceTag].PlayOneShot(voiceInfo); + SoundInfo voiceInfo = new TargetInfo(pawn.Position, pawn.Map); + voiceInfo.volumeFactor = RJWAnimationSettings.voicesVolume; + + //play voice sounds + VoiceTagDef voiceTag = animWorker.voiceAtTick(rootNode.tree.AnimationTick, rootNode.tree.currentAnimation, rootNode); + if (voiceTag != null + && (lastVoiceTag != voiceTag || ticksSinceLastVoicePlayed + ticksUntilNextVoice < GenTicks.TicksGame)) //play a new voice tag, or wait until time elapsed + { + lastVoiceTag = voiceTag; + ticksSinceLastVoicePlayed = GenTicks.TicksGame; + + if (voice != null && voice.sounds.ContainsKey(voiceTag)) + { + ticksUntilNextVoice = voice.ticksBetweenPlays.RandomInRange; + voice.sounds[voiceTag].PlayOneShot(voiceInfo); + } + + else if (pawn.RaceProps.Humanlike && RJWAnimationSettings.playHumanlikeVoicesAsDefault) + { + //play default voice + VoiceDef pawnDefaultVoice = (pawn.gender == Gender.Male ? VoiceDefOf.Voice_HumanMale : VoiceDefOf.Voice_HumanFemale); + + ticksUntilNextVoice = pawnDefaultVoice.ticksBetweenPlays.RandomInRange; + + if (pawnDefaultVoice.sounds.ContainsKey(voiceTag)) + { + ticksUntilNextVoice = pawnDefaultVoice.ticksBetweenPlays.RandomInRange; + pawnDefaultVoice.sounds[voiceTag].PlayOneShot(voiceInfo); + } + + + } + + } + } + + + } + + //check rootnodes and children + if (rootNode?.children != null) + { + foreach (PawnRenderNode node in rootNode?.children) + { + if (node?.AnimationWorker is AnimationWorker_KeyframesExtended childrenAnimWorker) + { + + + if (RJWAnimationSettings.playSounds) + { + SoundDef sound = childrenAnimWorker.soundAtTick(node.tree.AnimationTick, node.tree.currentAnimation, node); + + if (sound != null) + { + SoundInfo soundInfo = new TargetInfo(pawn.Position, pawn.Map); + soundInfo.volumeFactor = RJWAnimationSettings.soundVolume; + sound.PlayOneShot(soundInfo); + } + } + + if (RJWAnimationSettings.playVoices) + { + + SoundInfo voiceInfo = new TargetInfo(pawn.Position, pawn.Map); + voiceInfo.volumeFactor = RJWAnimationSettings.voicesVolume; + + //play voice sounds + VoiceTagDef voiceTag = childrenAnimWorker.voiceAtTick(rootNode.tree.AnimationTick, rootNode.tree.currentAnimation, rootNode); + if (voiceTag != null + && (lastVoiceTag != voiceTag || ticksSinceLastVoicePlayed + ticksUntilNextVoice < GenTicks.TicksGame)) //play a new voice tag, or wait until time elapsed + { + lastVoiceTag = voiceTag; + ticksSinceLastVoicePlayed = GenTicks.TicksGame; + + if (voice != null && voice.sounds.ContainsKey(voiceTag)) + { + ticksUntilNextVoice = voice.ticksBetweenPlays.RandomInRange; + voice.sounds[voiceTag].PlayOneShot(voiceInfo); + } + else if (pawn.RaceProps.Humanlike && RJWAnimationSettings.playHumanlikeVoicesAsDefault) + { + + VoiceDef pawnDefaultVoice = (pawn.gender == Gender.Male ? VoiceDefOf.Voice_HumanMale : VoiceDefOf.Voice_HumanFemale); + if (pawnDefaultVoice.sounds.ContainsKey(voiceTag)) + { + ticksUntilNextVoice = pawnDefaultVoice.ticksBetweenPlays.RandomInRange; + pawnDefaultVoice.sounds[voiceTag].PlayOneShot(voiceInfo); + } + } + } + } + } } } + //do the same for all the child nodes + } diff --git a/1.6/Source/Comps/ExtendedAnimatorAnchor/BaseExtendedAnimatorAnchor.cs b/1.6/Source/Comps/ExtendedAnimatorAnchor/BaseExtendedAnimatorAnchor.cs index 8cf28af..6116a8c 100644 --- a/1.6/Source/Comps/ExtendedAnimatorAnchor/BaseExtendedAnimatorAnchor.cs +++ b/1.6/Source/Comps/ExtendedAnimatorAnchor/BaseExtendedAnimatorAnchor.cs @@ -15,9 +15,6 @@ namespace Rimworld_Animations public virtual void ExposeData() { } public abstract Vector3 getDrawPos(); - //false if the anchor can't be drawn at anymore (e.g. the thing was destroyed) - public virtual bool IsValid => true; - public string GetUniqueLoadID() { throw new NotImplementedException(); diff --git a/1.6/Source/Comps/ExtendedAnimatorAnchor/ExtendedAnimatorAnchor_Thing.cs b/1.6/Source/Comps/ExtendedAnimatorAnchor/ExtendedAnimatorAnchor_Thing.cs index bd1fa4b..6f86334 100644 --- a/1.6/Source/Comps/ExtendedAnimatorAnchor/ExtendedAnimatorAnchor_Thing.cs +++ b/1.6/Source/Comps/ExtendedAnimatorAnchor/ExtendedAnimatorAnchor_Thing.cs @@ -26,9 +26,6 @@ namespace Rimworld_Animations this.thing = thing; } - //spawned check also covers destroyed things, and things that didn't come back after loading - public override bool IsValid => thing != null && thing.Spawned; - public override Vector3 getDrawPos() { //x and z position, regular altitude for pawns diff --git a/1.6/Source/MainTabWindows/MainTabWindow_OffsetConfigure.cs b/1.6/Source/MainTabWindows/MainTabWindow_OffsetConfigure.cs index 4b2878a..318e9c2 100644 --- a/1.6/Source/MainTabWindows/MainTabWindow_OffsetConfigure.cs +++ b/1.6/Source/MainTabWindows/MainTabWindow_OffsetConfigure.cs @@ -58,20 +58,13 @@ namespace Rimworld_Animations { if (listingStandard.ButtonText("RimAnims_Reset".Translate())) { - //remove the saved override entirely; an entry left behind would keep overriding the def's offset with zeros - RJWAnimationSettings.offsets?.Remove(AnimationUtility.OffsetLookupKey(curPawn)); - - //go back to the offset from the animation's offsetDefs - extendedAnimator.CurrentGroupAnimation.GetOffset(extendedAnimator.ActorIndex, curPawn, out Vector3? defOffset, out int? defRotation); - extendedAnimator.Offset = defOffset; - extendedAnimator.Rotation = defRotation; - - Vector3 resetOffset = defOffset ?? Vector3.zero; - posX = resetOffset.x; - posY = resetOffset.y; - posZ = resetOffset.z; - rot = defRotation ?? 0; - + if (!RJWAnimationSettings.offsets.NullOrEmpty() + && RJWAnimationSettings.offsets.ContainsKey(AnimationUtility.OffsetLookupKey(curPawn))) + { + RJWAnimationSettings.offsets[AnimationUtility.OffsetLookupKey(curPawn)].Reset(); + } + posX = posY = posZ = rot = 0; + } listingStandard.GapLine(); diff --git a/1.6/Source/Patches/RJWPatches/JobDrivers/HarmonyPatch_JobDriver_Masturbate.cs b/1.6/Source/Patches/RJWPatches/JobDrivers/HarmonyPatch_JobDriver_Masturbate.cs new file mode 100644 index 0000000..d7c9e98 --- /dev/null +++ b/1.6/Source/Patches/RJWPatches/JobDrivers/HarmonyPatch_JobDriver_Masturbate.cs @@ -0,0 +1,55 @@ +using HarmonyLib; +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 +{ + [HarmonyPatch(typeof(JobDriver_Masturbate), "SetupDurationTicks")] + public class HarmonyPatch_JobDriver_Masturbate + { + public static void Postfix(JobDriver_Masturbate __instance) + { + //prevent early stoppage of masturbate jobdriver during animation + + /* not needed anymore? Ticks are assigned during animation + + __instance.duration = 10000000; + __instance.ticks_left = __instance.duration; + + */ + + } + } + + [HarmonyPatch(typeof(JobDriver_Masturbate), "MakeNewToils")] + public class HarmonyPatch_JobDriver_Masturbate2 + { + public static void Postfix(JobDriver_Masturbate __instance, ref IEnumerable __result) + { + + var toils = __result.ToList(); + + //sex toil + toils[1].initAction += delegate () + { + CompExtendedAnimator pawnAnimator = __instance.pawn.TryGetComp(); + + // if pawn was given an animation to play, + if (pawnAnimator.IsAnimating) + { + //set duration of masturbate toil to anim length + toils[1].defaultDuration = pawnAnimator.AnimationLength; + } + + }; + + __result = toils.AsEnumerable(); + } + } +} diff --git a/1.6/Source/Patches/RJWPatches/JobDrivers/HarmonyPatch_JobDriver_Sex.cs b/1.6/Source/Patches/RJWPatches/JobDrivers/HarmonyPatch_JobDriver_Sex.cs index d8d3ae2..622b7c1 100644 --- a/1.6/Source/Patches/RJWPatches/JobDrivers/HarmonyPatch_JobDriver_Sex.cs +++ b/1.6/Source/Patches/RJWPatches/JobDrivers/HarmonyPatch_JobDriver_Sex.cs @@ -30,57 +30,36 @@ namespace Rimworld_Animations public static void Postfix(JobDriver_Sex __instance, Pawn pawn, Thing target) { //if neverending sex and pawn doesn't have an animation, - //only retry about once a second; searching every animation def every tick is expensive when none fit - if (!__instance.neverendingsex - || !pawn.IsHashIntervalTick(60) - || !(pawn.TryGetComp() is CompExtendedAnimator animator) - || animator.IsAnimating) + if (__instance.neverendingsex + && !pawn.TryGetComp().IsAnimating) { - return; - } - //start a new animation for all the pawns paired with receiver job driver - List participants; - Thing anchor = __instance.Bed; - if (target is Pawn receiverPawn) - { - participants = (receiverPawn.jobs?.curDriver as JobDriver_SexBaseReciever)?.parteners?.ToList(); - if (participants.NullOrEmpty()) return; - - if (!participants.Contains(receiverPawn)) + //start a new animation for all the pawns paired with receiver job driver + List participants; + if (target is Pawn receiverPawn) { - participants.Add(receiverPawn); + participants = (receiverPawn?.jobs?.curDriver as JobDriver_SexBaseReciever)?.parteners; + if (!participants.NullOrEmpty() && !participants.Contains(receiverPawn)) + { + participants = participants.Append(receiverPawn).ToList(); + } } - anchor = anchor ?? receiverPawn; - } - else if (target is Corpse corpse && corpse.InnerPawn != null) - { - participants = new List { pawn, corpse.InnerPawn }; - anchor = anchor ?? corpse; - } - else - { - participants = new List { pawn }; - anchor = anchor ?? pawn; - } - - GroupAnimationDef animation = AnimationUtility.FindGroupAnimation(participants, out List participantsOrdered); - if (animation == null) return; - - AnimationUtility.StartGroupAnimation(participantsOrdered, animation, anchor); - - //keep rjw's timers in step with the new animation, same as when sex starts - int animTicks = AnimationUtility.GetAnimationLength(pawn); - foreach (Pawn participant in participants) - { - if (participant?.jobs?.curDriver is JobDriver_Sex participantJobDriver) + else { - participantJobDriver.ticks_left = animTicks; - participantJobDriver.sex_ticks = animTicks; - participantJobDriver.orgasmStartTick = animTicks; - participantJobDriver.duration = animTicks; + participants = new List { pawn }; } + + + GroupAnimationDef animation = AnimationUtility.FindGroupAnimation(participants, out List participantsOrdered); + if (animation != null) + { + Thing anchor = (Thing)__instance.Bed ?? pawn; + AnimationUtility.StartGroupAnimation(participantsOrdered, animation, anchor); + } + + } + } } diff --git a/1.6/Source/Patches/RJWPatches/JobDrivers/HarmonyPatch_JobDriver_SexBaseInitiator.cs b/1.6/Source/Patches/RJWPatches/JobDrivers/HarmonyPatch_JobDriver_SexBaseInitiator.cs index d2680ce..36a1316 100644 --- a/1.6/Source/Patches/RJWPatches/JobDrivers/HarmonyPatch_JobDriver_SexBaseInitiator.cs +++ b/1.6/Source/Patches/RJWPatches/JobDrivers/HarmonyPatch_JobDriver_SexBaseInitiator.cs @@ -24,10 +24,6 @@ namespace Rimworld_Animations { participants = new List() { pawn }; } - else if (partner == null) - { - return; - } else if (__instance is JobDriver_ViolateCorpse) { participants = new List() { pawn, partner }; @@ -56,23 +52,18 @@ namespace Rimworld_Animations if (groupAnimation != null) { - //anchor to the corpse itself, not its InnerPawn; a pawn inside a corpse keeps the position it died at - Thing anchor = (Thing)__instance.Bed ?? (Thing)(__instance.Target as Corpse) ?? partner; + Thing anchor = (Thing)__instance.Bed ?? partner; AnimationUtility.StartGroupAnimation(participantsOrdered, groupAnimation, anchor); int animTicks = AnimationUtility.GetAnimationLength(pawn); - if (RJWAnimationSettings.debugMode) - { - Log.Message("InteractionDef: " + __instance.Sexprops?.dictionaryKey); - } - + Log.Message("InteractionDef: " + __instance.Sexprops.dictionaryKey); foreach (Pawn participant in participants) { if (RJWAnimationSettings.debugMode) { - Log.Message("Participant: " + participant?.Name); - Log.Message("JobDriver: " + participant?.CurJobDef?.defName); + Log.Message("Participant: " + participant.Name); + Log.Message("JobDriver: " + participant.CurJobDef.defName); } //null ref check for pawns that might have lost their jobs or become null for some reason diff --git a/1.6/Source/Patches/RJWPatches/JobDrivers/SexBaseReceivers/HarmonyPatch_JobDriver_SexBaseReceiverRaped.cs b/1.6/Source/Patches/RJWPatches/JobDrivers/SexBaseReceivers/HarmonyPatch_JobDriver_SexBaseReceiverRaped.cs new file mode 100644 index 0000000..703bdcc --- /dev/null +++ b/1.6/Source/Patches/RJWPatches/JobDrivers/SexBaseReceivers/HarmonyPatch_JobDriver_SexBaseReceiverRaped.cs @@ -0,0 +1,29 @@ +using HarmonyLib; +using rjw; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse.AI; + +namespace Rimworld_Animations +{ + [HarmonyPatch(typeof(JobDriver_SexBaseRecieverRaped), "MakeNewToils")] + public class HarmonyPatch_JobDriver_SexBaseReceiverRaped + { + /* + * Doesn't work; ienumerables are read-only, can't modify toil + * would need to harmonypatch; stopped partner animating in sexbaseinitiator instead + * + public static void Postfix(JobDriver_SexBaseRecieverRaped __instance, ref IEnumerable __result) + { + //added for sudden end of jobdriver + __result.Last().AddFinishAction(delegate { + AnimationUtility.StopGroupAnimation(__instance.pawn); + }); + } + + */ + } +} diff --git a/1.6/Source/Patches/RimworldPatches/HarmonyPatch_PawnRenderTree.cs b/1.6/Source/Patches/RimworldPatches/HarmonyPatch_PawnRenderTree.cs index 3070ff7..c62bcc4 100644 --- a/1.6/Source/Patches/RimworldPatches/HarmonyPatch_PawnRenderTree.cs +++ b/1.6/Source/Patches/RimworldPatches/HarmonyPatch_PawnRenderTree.cs @@ -57,7 +57,7 @@ namespace Rimworld_Animations if (pivot != Vector3.zero) matrix *= Matrix4x4.Translate(pivot); if (quaternion != Quaternion.identity) matrix *= Matrix4x4.Rotate(quaternion); if (scale != Vector3.one) matrix *= Matrix4x4.Scale(scale); - if (pivot != Vector3.zero) matrix *= Matrix4x4.Translate(pivot).inverse; + if (pivot != Vector3.zero) matrix *= Matrix4x4.Translate(scale).inverse; float num = node.Worker.AltitudeFor(node, parms); if (num != 0f) @@ -96,7 +96,7 @@ namespace Rimworld_Animations if (pivot != Vector3.zero) matrix *= Matrix4x4.Translate(pivot); if (canRotate && rotation != Quaternion.identity) matrix *= Matrix4x4.Rotate(rotation); if (canScale && scale != Vector3.one) matrix *= Matrix4x4.Scale(scale); - if (pivot != Vector3.zero) matrix *= Matrix4x4.Translate(pivot).inverse; + if (pivot != Vector3.zero) matrix *= Matrix4x4.Translate(scale).inverse; } float num = node.Worker.AltitudeFor(node, parms); diff --git a/1.6/Source/Patches/RimworldPatches/HarmonyPatch_Thing.cs b/1.6/Source/Patches/RimworldPatches/HarmonyPatch_Thing.cs new file mode 100644 index 0000000..ec738f7 --- /dev/null +++ b/1.6/Source/Patches/RimworldPatches/HarmonyPatch_Thing.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using HarmonyLib; +using RimWorld; +using Verse; + +namespace Rimworld_Animations +{ + [HarmonyPatch(typeof(Thing), "DrawAt")] + public static class HarmonyPatch_Thing + { + /* + public static bool Prefix(Thing __instance) + { + CompThingAnimator thingAnimator = __instance.TryGetComp(); + if (thingAnimator != null && thingAnimator.isAnimating) + { + thingAnimator.AnimateThing(__instance); + return false; + + } + + return true; + + } + + + */ + } +} diff --git a/1.6/Source/Settings/PawnScaledOffsets.cs b/1.6/Source/Settings/PawnScaledOffsets.cs index 38577e4..8f280a1 100644 --- a/1.6/Source/Settings/PawnScaledOffsets.cs +++ b/1.6/Source/Settings/PawnScaledOffsets.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -46,7 +46,7 @@ public class PawnScaledOffsets : IExposable { smallestSizeOffset = largestSizeOffset = Vector3.zero; smallestSizeRotation = largestSizeRotation = 0; - smallestSize = largestSize = -1; //back to uninitialized + smallestSize = largestSize = 1; } public void GetOffsets(Pawn pawn, out Vector3 offset, out int rotation) diff --git a/1.6/Source/Settings/RJWAnimationSettings.cs b/1.6/Source/Settings/RJWAnimationSettings.cs index 184bb7f..2c594bc 100644 --- a/1.6/Source/Settings/RJWAnimationSettings.cs +++ b/1.6/Source/Settings/RJWAnimationSettings.cs @@ -27,25 +27,21 @@ namespace Rimworld_Animations { { base.ExposeData(); - - //some load defaults below differ from the field defaults. keys equal to their load default were never written, - //so a missing key in an existing file usually means the player chose that value; keep those load defaults - //and force-save these keys so the file is always explicit from now on Scribe_Values.Look(ref playVoices, "RJWAnimations_PlayVoices", true); Scribe_Values.Look(ref playSounds, "RJWAnimations_PlaySounds", true); Scribe_Values.Look(ref playHumanlikeVoicesAsDefault, "RJWAnimations-playHumanlikeVoicesAsDefault", true); - Scribe_Values.Look(ref maleSounds, "RJWAnimations-maleSounds", true, true); - Scribe_Values.Look(ref femaleSounds, "RJWAnimations-femaleSounds", true, true); + Scribe_Values.Look(ref maleSounds, "RJWAnimations-maleSounds", true); + Scribe_Values.Look(ref femaleSounds, "RJWAnimations-femaleSounds", true); Scribe_Values.Look(ref debugMode, "RJWAnimations-AnimsDebugMode", false); - Scribe_Values.Look(ref offsetTab, "RJWAnimations-EnableOffsetTab", false, true); - Scribe_Values.Look(ref hearts, "RJWAnimation-heartsOnLovin", false, true); + Scribe_Values.Look(ref offsetTab, "RJWAnimations-EnableOffsetTab", false); + Scribe_Values.Look(ref hearts, "RJWAnimation-heartsOnLovin"); Scribe_Values.Look(ref soundOverride, "RJWAnimations-rjwAnimSoundOverride", true); Scribe_Values.Look(ref maleAnalCanBeFucked, "RJWAnimations-maleAnalCanBeFucked", true); Scribe_Values.Look(ref floatRangeInRenderTreeMenu, "RJWAnimations-FloatRangeRenderMenu", 1f); Scribe_Values.Look(ref soundVolume, "RJWAnimations-soundVolume", 1f); Scribe_Values.Look(ref voicesVolume, "RJWAnimations-voicesVolume", 1f); - Scribe_Values.Look(ref voicesFrequencyTicks, "RJWAnimations-voicesFrequencyTicks", 1f, true); + Scribe_Values.Look(ref voicesFrequencyTicks, "RJWAnimations-voicesFrequencyTicks", 1f); Scribe_Collections.Look(ref offsets, "RJWAnimations-animationScaledOffsets", LookMode.Value, LookMode.Deep); diff --git a/1.6/Source/Utilities/AnimationUtility.cs b/1.6/Source/Utilities/AnimationUtility.cs index 5f3aa2d..dfaddc9 100644 --- a/1.6/Source/Utilities/AnimationUtility.cs +++ b/1.6/Source/Utilities/AnimationUtility.cs @@ -27,9 +27,7 @@ namespace Rimworld_Animations { for (int i = 0; i < participants.Count; i++) { - //don't anchor a pawn to itself, or a dead pawn to its own corpse - if ((anchor is Pawn pawn && pawn == participants[i]) - || (anchor is Corpse corpse && corpse.InnerPawn == participants[i])) + if (anchor is Pawn pawn && pawn == participants[i]) { participants[i].TryGetComp().PlayGroupAnimation(groupAnimationDef, null, i, seed, participants); @@ -40,27 +38,6 @@ namespace Rimworld_Animations { participants[i].TryGetComp().PlayGroupAnimation(groupAnimationDef, animatorAnchor, i, seed, participants); } } - - DriveDeadParticipants(participants); - } - - //corpses only TickRare, so their animators never advance on their own; - //hand them to a living participant's animator to tick - private static void DriveDeadParticipants(List participants) - { - Pawn driver = participants.FirstOrDefault(x => !x.Dead); - if (driver == null) return; - - CompExtendedAnimator driverAnimator = driver.TryGetComp(); - if (driverAnimator == null) return; - - foreach (Pawn participant in participants) - { - if (participant.Dead) - { - driverAnimator.AddDrivenPawn(participant); - } - } } //startgroupanimation without anchor; just play where standing @@ -72,8 +49,6 @@ namespace Rimworld_Animations { { participants[i].TryGetComp().PlayGroupAnimation(groupAnimationDef, i, seed, participants); } - - DriveDeadParticipants(participants); } @@ -92,9 +67,8 @@ namespace Rimworld_Animations { public static GroupAnimationDef FindGroupAnimation(List participants, out List pawnOrder) { - pawnOrder = null; - if (participants.NullOrEmpty() || participants.Contains(null)) return null; + /* This method is fooken expensive List<(GroupAnimationDef, List, int Priority)> potentialAnimations = new List<(GroupAnimationDef, List, int)>(); @@ -134,17 +108,13 @@ namespace Rimworld_Animations { } + //Randomize the list, + potentialAnimations.OrderBy(_ => Rand.Int); (GroupAnimationDef, List, int) selectedAnimation; - //pick randomly, weighted by priority - //negative priorities count as 0 so they don't log "Negative weight" errors - if (!potentialAnimations.TryRandomElementByWeight(((GroupAnimationDef, List, int) x) => Math.Max(x.Item3, 0), out selectedAnimation) - && potentialAnimations.Count > 0) - { - //every candidate has priority <= 0 (weak/fallback contexts); pick evenly between the best of them - int bestPriority = potentialAnimations.Max(x => x.Item3); - potentialAnimations.Where(x => x.Item3 == bestPriority).TryRandomElement(out selectedAnimation); - } + potentialAnimations.TryRandomElementByWeight(((GroupAnimationDef, List, int) x) => x.Item3, out selectedAnimation); + //Find a highest priority animation, out as selectedAnimation + // .TryMaxBy(((GroupAnimationDef, List, int) x) => x.Item3, out (GroupAnimationDef, List, int) selectedAnimation); //set pawnOrder as selected animation permutation pawnOrder = selectedAnimation.Item2; diff --git a/About/About.xml b/About/About.xml index 9c21172..a37de85 100644 --- a/About/About.xml +++ b/About/About.xml @@ -8,7 +8,7 @@
  • 1.6
  • c0ffee.rimworld.animations - 2.2.1 + 2.2.0 UI/MainTab
  • diff --git a/Languages/ChineseSimplified/DefInjected/MainButtonDef/MainButtonDef.xml b/Languages/ChineseSimplified/DefInjected/MainButtonDef/MainButtonDef.xml deleted file mode 100644 index da8bf6c..0000000 --- a/Languages/ChineseSimplified/DefInjected/MainButtonDef/MainButtonDef.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - 动画管理器 - 编辑角色动画的偏移量。 - \ No newline at end of file diff --git a/Languages/ChineseSimplified/DefInjected/Rimworld_Animations.AnimationPropDef/AnimationPropDef_Cowgirl_Xray.xml b/Languages/ChineseSimplified/DefInjected/Rimworld_Animations.AnimationPropDef/AnimationPropDef_Cowgirl_Xray.xml deleted file mode 100644 index e1991a7..0000000 --- a/Languages/ChineseSimplified/DefInjected/Rimworld_Animations.AnimationPropDef/AnimationPropDef_Cowgirl_Xray.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - 女牛仔式-透视 - \ No newline at end of file diff --git a/Languages/ChineseSimplified/DefInjected/Rimworld_Animations.AnimationPropDef/AnimationPropDef_Xray_Inside.xml b/Languages/ChineseSimplified/DefInjected/Rimworld_Animations.AnimationPropDef/AnimationPropDef_Xray_Inside.xml deleted file mode 100644 index 5904ef1..0000000 --- a/Languages/ChineseSimplified/DefInjected/Rimworld_Animations.AnimationPropDef/AnimationPropDef_Xray_Inside.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - 体内透视 - \ No newline at end of file diff --git a/Languages/ChineseSimplified/DefInjected/Rimworld_Animations.AnimationPropDef/AnimationPropDef_Xray_Penis.xml b/Languages/ChineseSimplified/DefInjected/Rimworld_Animations.AnimationPropDef/AnimationPropDef_Xray_Penis.xml deleted file mode 100644 index dfd781e..0000000 --- a/Languages/ChineseSimplified/DefInjected/Rimworld_Animations.AnimationPropDef/AnimationPropDef_Xray_Penis.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - 阴茎透视 - \ No newline at end of file diff --git a/Languages/ChineseSimplified/DefInjected/Rimworld_Animations.AnimationPropDef/AnimationPropDef_Xray_Race.xml b/Languages/ChineseSimplified/DefInjected/Rimworld_Animations.AnimationPropDef/AnimationPropDef_Xray_Race.xml deleted file mode 100644 index f6253ee..0000000 --- a/Languages/ChineseSimplified/DefInjected/Rimworld_Animations.AnimationPropDef/AnimationPropDef_Xray_Race.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - 阴道透视 - 阴道透视 - \ No newline at end of file diff --git a/Languages/ChineseSimplified/Keyed/RJWAnimations-LanguageData.xml b/Languages/ChineseSimplified/Keyed/RJWAnimations-LanguageData.xml index 3addfa5..1d72019 100644 --- a/Languages/ChineseSimplified/Keyed/RJWAnimations-LanguageData.xml +++ b/Languages/ChineseSimplified/Keyed/RJWAnimations-LanguageData.xml @@ -1,25 +1,28 @@ - + - RJW 动画设置 - 启用声音覆盖 - 控制生殖器旋转 - 启用高潮颤抖 - 启用强奸颤动 - 性爱时启用心形 - 播放非性行为的动画 (牵手、亲热) - 启用动画管理器选项卡 - 颤抖/颤动强度 (默认为 2): - 在动画期间播放语音 - 如果没有找到外星种族的声音,则默认播放人类的声音 - 调试模式 - 调整渲染树偏移表单的浮动范围: - 为男性角色播放肛交动画 - 在动画期间播放声音 - 语音音量: - 声音音量: - 动画管理器 - 警告--一般情况下,你不想更改人类偏移值,只想更改外星种族偏移值或动物偏移值 - 将偏移值复制到剪贴板 - 将偏移值粘贴到 OffsetDef 中,或在 Discord 中共享 - 重置 + + + RJW Animation Settings + 启用声音覆盖 + 控制生殖器旋转 + 启用高潮颤抖 + 启用强奸颤动 + 性爱时启用心形 + 播放非性行为的动画 (牵手、亲热) + 启用动画管理器选项卡 + 颤抖/颤动强度 (默认为 2): + 在动画期间播放语音 + 如果没有找到外星种族的声音,则默认播放人类的声音 + 调试模式 + 调整渲染树偏移表单的浮动范围: + + + + Animation Manager + 警告--一般情况下,你不想更改人类偏移值,只想更改外星种族偏移值或动物偏移值 + 将偏移值复制到剪贴板 + 将偏移值粘贴到 OffsetDef 中,或在 Discord 中共享 + + + \ No newline at end of file diff --git a/LoadFolders.xml b/LoadFolders.xml index e41f229..b369dab 100644 --- a/LoadFolders.xml +++ b/LoadFolders.xml @@ -35,6 +35,8 @@
  • /
  • 1.6
  • +
  • Patch_HumanoidAlienRaces/1.5
  • +
  • Patch_SexToysMasturbation/1.5
  • Patch_NoRimNudeWorld/1.5
  • Patch_NoRimNudeWorldZoo/1.5