- Fixed an issue with the orgasm not filling in some circumstances
- Fixed a bug with sex overdrive not applying correctly
- Fixed an issue with 'on orgasm' events not triggering correctly
This commit is contained in:
AbstractConcept 2023-02-08 23:32:58 -06:00
parent cce0053fd6
commit 003b67fb97
14 changed files with 92 additions and 102 deletions

View file

@ -1,3 +1,8 @@
Change log v 2.0.5
- Fixed an issue with the orgasm not filling in some circumstances
- Fixed a bug with sex overdrive not applying correctly
- Fixed an issue with 'on orgasm' events not triggering correctly
Change log v 2.0.4 Change log v 2.0.4
- Fixed a bug that was causing body parts to render over clothes - Fixed a bug that was causing body parts to render over clothes

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Manifest> <Manifest>
<version>2.0.4</version> <version>2.0.5</version>
<downloadUri>https://gitgud.io/AbstractConcept/rimworld-animations-patch</downloadUri> <downloadUri>https://gitgud.io/AbstractConcept/rimworld-animations-patch</downloadUri>
</Manifest> </Manifest>

View file

@ -1270,7 +1270,7 @@
</li> </li>
<li> <li>
<tickDuration>7</tickDuration> <tickDuration>7</tickDuration>
<!--<soundEffect>Cum</soundEffect>--> <soundEffect>Cum</soundEffect>
<bodyAngle>0</bodyAngle> <bodyAngle>0</bodyAngle>
<bodyOffsetX>0</bodyOffsetX> <bodyOffsetX>0</bodyOffsetX>
<bodyOffsetZ>0.475</bodyOffsetZ> <bodyOffsetZ>0.475</bodyOffsetZ>

View file

@ -7,6 +7,7 @@ using RimWorld;
using Verse; using Verse;
using AlienRace; using AlienRace;
using UnityEngine; using UnityEngine;
using rjw;
namespace Rimworld_Animations_Patch namespace Rimworld_Animations_Patch
{ {
@ -25,11 +26,16 @@ namespace Rimworld_Animations_Patch
private Pawn pawn { get { return parent as Pawn; } } private Pawn pawn { get { return parent as Pawn; } }
private bool initialized; private bool initialized;
// Refresh graphics on load
public override void CompTick() public override void CompTick()
{ {
if (initialized == false) if (initialized == false)
{ {
pawn?.Drawer?.renderer?.graphics?.ResolveAllGraphics(); pawn?.Drawer?.renderer?.graphics?.ResolveAllGraphics();
//if (pawn?.jobs?.curDriver is JobDriver_SexBaseInitiator && pawn.pather.Moving == false)
//{ (pawn.jobs.curDriver as JobDriver_SexBaseInitiator).Start(); }
initialized = true; initialized = true;
} }
} }
@ -72,7 +78,7 @@ namespace Rimworld_Animations_Patch
public void UpdateBodyPartCountAndSize() public void UpdateBodyPartCountAndSize()
{ {
hands = pawn?.health?.hediffSet?.GetNotMissingParts()?.Where(x => x.def.tags.Contains(BodyPartTagDefOf.ManipulationLimbCore))?.ToList(); hands = pawn?.health?.hediffSet?.GetNotMissingParts()?.Where(x => x.def.tags.Contains(RimWorld.BodyPartTagDefOf.ManipulationLimbCore))?.ToList();
Hediff hediffPenis = pawn?.health?.hediffSet?.hediffs?.FirstOrDefault(x => x.def.defName.Contains("penis", StringComparison.OrdinalIgnoreCase) == true); Hediff hediffPenis = pawn?.health?.hediffSet?.hediffs?.FirstOrDefault(x => x.def.defName.Contains("penis", StringComparison.OrdinalIgnoreCase) == true);
sizeOfPenis = hediffPenis != null ? hediffPenis.Severity : 0f; sizeOfPenis = hediffPenis != null ? hediffPenis.Severity : 0f;

View file

@ -106,7 +106,35 @@ namespace Rimworld_Animations_Patch
} }
participants.AddDistinct(pawn); participants.AddDistinct(pawn);
participants.SortBy(x => x.GetAnimationData() != null ? x.GetAnimationData().actorID : participants.IndexOf(x));
// Sort participants according to actorID, if they have one
Dictionary<int, Pawn> _participants = new Dictionary<int, Pawn>();
int c = 99;
foreach (Pawn participant in participants)
{
ActorAnimationData data = pawn.GetAnimationData();
if (data != null)
{
int idx = data.actorID;
if (_participants.ContainsKey(data.actorID))
{ DebugMode.Message("ERROR: Somehow you ended up with two actors with the same actorID"); idx = ++c; }
_participants.Add(idx, participant);
}
else
{ _participants.Add(++c, participant); }
}
participants = _participants.Values.ToList();
//ActorAnimationData data = pawn.GetAnimationData();
//if (data != null)
//participants.SortBy(x => x.GetAnimationData() != null ? x.GetAnimationData().actorID : participants.IndexOf(x));
return participants; return participants;
} }

View file

@ -108,16 +108,13 @@ namespace Rimworld_Animations_Patch
public static void Postfix(ref JobDriver_SexBaseInitiator __instance) public static void Postfix(ref JobDriver_SexBaseInitiator __instance)
{ {
// Allow solo animations to be played // Allow solo animations to be played
if (__instance is JobDriver_Masturbate && __instance.pawn.GetAnimationData() == null) if (__instance is JobDriver_Masturbate && __instance.pawn.GetAnimationData() == null) PickMasturbationAnimation(__instance.pawn, __instance.Sexprops);
{ PickMasturbationAnimation(__instance.pawn, __instance.Sexprops); }
// Allow make out animations to be played // Allow make out animations to be played
if (__instance.pawn.GetAnimationData() == null) if (__instance.pawn.GetAnimationData() == null) PickMakeOutAnimation(__instance.pawn, __instance.Sexprops);
{ PickMakeOutAnimation(__instance.pawn, __instance.Sexprops); }
// If there is no animation to play, exit // If there is no animation to play, exit
if (__instance.pawn.GetAnimationData() == null) if (__instance.pawn.GetAnimationData() == null) return;
{ return; }
// Get animation data // Get animation data
List<Pawn> pawnsToAnimate = __instance.pawn.GetAllSexParticipants(); List<Pawn> pawnsToAnimate = __instance.pawn.GetAllSexParticipants();
@ -126,9 +123,7 @@ namespace Rimworld_Animations_Patch
foreach (Pawn participant in pawnsToAnimate) foreach (Pawn participant in pawnsToAnimate)
{ {
JobDriver_Sex jobdriver = participant.jobs.curDriver as JobDriver_Sex; JobDriver_Sex jobdriver = participant.jobs.curDriver as JobDriver_Sex;
if (jobdriver == null) continue;
if (jobdriver == null)
{ continue; }
// Animation timing reset // Animation timing reset
jobdriver.orgasms = 0; jobdriver.orgasms = 0;
@ -136,7 +131,7 @@ namespace Rimworld_Animations_Patch
jobdriver.ticksLeftThisToil = jobdriver.ticks_left; jobdriver.ticksLeftThisToil = jobdriver.ticks_left;
jobdriver.sex_ticks = orgasmTick; jobdriver.sex_ticks = orgasmTick;
jobdriver.duration = jobdriver.sex_ticks; jobdriver.duration = jobdriver.sex_ticks;
jobdriver.orgasmstick = 0; jobdriver.orgasmstick = 1;
// Reset anchor and animation for sex toys // Reset anchor and animation for sex toys
CompThingAnimator sexToyCompThingAnimator = ((Thing)jobdriver.job.GetTarget(TargetIndex.A)).TryGetComp<CompThingAnimator>(); CompThingAnimator sexToyCompThingAnimator = ((Thing)jobdriver.job.GetTarget(TargetIndex.A)).TryGetComp<CompThingAnimator>();
@ -169,7 +164,7 @@ namespace Rimworld_Animations_Patch
public static void PickMasturbationAnimation(Pawn pawn, SexProps sexProps = null) public static void PickMasturbationAnimation(Pawn pawn, SexProps sexProps = null)
{ {
if (pawn.TryGetComp<CompBodyAnimator>() == null) if (pawn.TryGetComp<CompBodyAnimator>() == null)
{ Log.Error("Error: " + pawn.Name + " of race " + pawn.def.defName + " does not have CompBodyAnimator attached!"); return; } { Log.Error("ERROR: " + pawn.Name + " of race " + pawn.def.defName + " does not have CompBodyAnimator attached!"); return; }
pawn.TryGetComp<CompBodyAnimator>().isAnimating = false; pawn.TryGetComp<CompBodyAnimator>().isAnimating = false;
@ -227,7 +222,7 @@ namespace Rimworld_Animations_Patch
public static void PickMakeOutAnimation(Pawn pawn, SexProps sexProps = null) public static void PickMakeOutAnimation(Pawn pawn, SexProps sexProps = null)
{ {
if (pawn.TryGetComp<CompBodyAnimator>() == null) if (pawn.TryGetComp<CompBodyAnimator>() == null)
{ Log.Error("Error: " + pawn.Name + " of race " + pawn.def.defName + " does not have CompBodyAnimator attached!"); return; } { Log.Error("ERROR: " + pawn.Name + " of race " + pawn.def.defName + " does not have CompBodyAnimator attached!"); return; }
List<Pawn> pawnsToAnimate = pawn.GetAllSexParticipants(); List<Pawn> pawnsToAnimate = pawn.GetAllSexParticipants();
@ -260,58 +255,41 @@ namespace Rimworld_Animations_Patch
[HarmonyPatch(typeof(JobDriver_Sex), "Orgasm")] [HarmonyPatch(typeof(JobDriver_Sex), "Orgasm")]
public static class HarmonyPatch_JobDriver_Sex_Orgasm public static class HarmonyPatch_JobDriver_Sex_Orgasm
{ {
// Stops orgasm triggering more than once per animation
public static bool Prefix(ref JobDriver_Sex __instance) public static void Prefix(ref JobDriver_Sex __instance, out bool __state)
{ {
if (__instance.orgasms > 0) __state = __instance.sex_ticks > __instance.orgasmstick;
{ return false; }
return true;
}
// Causes too much trouble...
/*public static bool ParticipantsDesireMoreSex(JobDriver_Sex jobdriver)
{
List<Pawn> participants = jobdriver.pawn.GetAllSexParticipants();
float satisfaction = 0f;
foreach (Pawn pawn in participants)
{
Need_Sex sexNeed = pawn?.needs?.TryGetNeed<Need_Sex>();
if (sexNeed == null)
{ satisfaction += 1; continue; }
satisfaction += sexNeed.CurLevelPercentage;
}
return Rand.Chance(1 - satisfaction / participants.Count);
} }
// Alows the starting of a new animation cycle at the end of the current one // Alows the starting of a new animation cycle at the end of the current one
public static void Postfix(ref JobDriver_Sex __instance) public static void Postfix(ref JobDriver_Sex __instance, bool __state)
{ {
if (__instance.orgasms > 0) if (__state || __instance.pawn.TryGetComp<CompBodyAnimator>()?.isAnimating != true) return;
{ __instance.sex_ticks = 0; }
if (__instance is JobDriver_SexBaseInitiator == false || __instance is JobDriver_JoinInSex) DebugMode.Message(__instance.pawn.NameShortColored + " reached orgasm");
{ return; }
if (__instance.Sexprops != null && (__instance.Sexprops.isRape || __instance.Sexprops.isWhoring)) int duration = AnimationPatchUtility.FindTrueAnimationLength(__instance.pawn, out int orgasmTick, true);
{ return; } __instance.sex_ticks = duration;
__instance.duration = duration;
if (__instance.ticksLeftThisToil <= 1 && (__instance.neverendingsex || ParticipantsDesireMoreSex(__instance))) if (__instance.neverendingsex)
{ {
__instance.ticks_left = duration + (duration - orgasmTick) + 1;
__instance.ticksLeftThisToil = __instance.ticks_left + 1;
List<Pawn> participants = __instance.pawn.GetAllSexParticipants(); List<Pawn> participants = __instance.pawn.GetAllSexParticipants();
foreach (Pawn participant in participants)
if (participants.Count == 2)
{ {
Job job = JobMaker.MakeJob(participants[0].CurJobDef, participants[0], participants[0].jobs.curJob.targetC); JobDriver_Sex jobDriver = participant.jobs.curDriver as JobDriver_Sex;
participants[1].jobs.StartJob(job, JobCondition.Succeeded);
if (participant != __instance.pawn && jobDriver != null)
{
jobDriver.ticks_left = duration + (duration - orgasmTick) + 1;
jobDriver.ticksLeftThisToil = jobDriver.ticks_left;
}
}
} }
} }
}*/
} }
[HarmonyPatch(typeof(JobDriver_SexBaseInitiator), "End")] [HarmonyPatch(typeof(JobDriver_SexBaseInitiator), "End")]
@ -322,9 +300,11 @@ namespace Rimworld_Animations_Patch
{ {
if (__instance.Partner != null &&__instance.Partner.Dead == false && __instance.Partner?.jobs?.curDriver != null && __instance.Partner?.jobs?.curDriver is JobDriver_SexBaseReciever) if (__instance.Partner != null &&__instance.Partner.Dead == false && __instance.Partner?.jobs?.curDriver != null && __instance.Partner?.jobs?.curDriver is JobDriver_SexBaseReciever)
{ {
foreach (Pawn participant in (__instance.Partner?.jobs.curDriver as JobDriver_SexBaseReciever).parteners) List<Pawn> participants = (__instance.Partner?.jobs.curDriver as JobDriver_SexBaseReciever).parteners.ToList();
foreach (Pawn participant in participants)
{ {
if (__instance.pawn != participant) if (__instance.pawn != participant && __instance.Partner?.jobs?.curDriver is JobDriver_Sex)
{ participant.jobs.EndCurrentJob(JobCondition.Succeeded, false, true); } { participant.jobs.EndCurrentJob(JobCondition.Succeeded, false, true); }
} }
} }

View file

@ -20,8 +20,6 @@ namespace Rimworld_Animations_Patch
postfix: new HarmonyMethod(AccessTools.Method(typeof(HarmonyPatch_Rimworld_Animations), "PostFix_AnimationUtility_GenitalCheckForPawn"))); postfix: new HarmonyMethod(AccessTools.Method(typeof(HarmonyPatch_Rimworld_Animations), "PostFix_AnimationUtility_GenitalCheckForPawn")));
(new Harmony("Rimworld_Animations_Patch")).Patch(AccessTools.Method(AccessTools.TypeByName("Rimworld_Animations.CompBodyAnimator"), "setAnchor", new Type[] { typeof(Thing) }), (new Harmony("Rimworld_Animations_Patch")).Patch(AccessTools.Method(AccessTools.TypeByName("Rimworld_Animations.CompBodyAnimator"), "setAnchor", new Type[] { typeof(Thing) }),
prefix: new HarmonyMethod(AccessTools.Method(typeof(HarmonyPatch_Rimworld_Animations), "Prefix_HarmonyPatch_CompBodyAnimator_setAnchor"))); prefix: new HarmonyMethod(AccessTools.Method(typeof(HarmonyPatch_Rimworld_Animations), "Prefix_HarmonyPatch_CompBodyAnimator_setAnchor")));
(new Harmony("Rimworld_Animations_Patch")).Patch(AccessTools.Method(AccessTools.TypeByName("Rimworld_Animations.HarmonyPatch_JobDriver_SexBaseInitiator_Start"), "RerollAnimations"),
postfix: new HarmonyMethod(AccessTools.Method(typeof(HarmonyPatch_Rimworld_Animations), "Postfix_RerollAnimations")));
(new Harmony("Rimworld_Animations_Patch")).Patch(AccessTools.Method(AccessTools.TypeByName("Rimworld_Animations.HarmonyPatch_AlienRace"), "Prefix_AnimateHeadAddons"), (new Harmony("Rimworld_Animations_Patch")).Patch(AccessTools.Method(AccessTools.TypeByName("Rimworld_Animations.HarmonyPatch_AlienRace"), "Prefix_AnimateHeadAddons"),
prefix: new HarmonyMethod(AccessTools.Method(typeof(HarmonyPatch_Rimworld_Animations), "Prefix_DrawAddons"))); prefix: new HarmonyMethod(AccessTools.Method(typeof(HarmonyPatch_Rimworld_Animations), "Prefix_DrawAddons")));
(new Harmony("Rimworld_Animations_Patch")).Patch(AccessTools.Method(AccessTools.TypeByName("Rimworld_Animations.CompBodyAnimator"), "StartAnimation"), (new Harmony("Rimworld_Animations_Patch")).Patch(AccessTools.Method(AccessTools.TypeByName("Rimworld_Animations.CompBodyAnimator"), "StartAnimation"),
@ -61,8 +59,7 @@ namespace Rimworld_Animations_Patch
bool pawnInBed = pawn.IsInBed(out Building bed); bool pawnInBed = pawn.IsInBed(out Building bed);
if (requiredGenitals.NullOrEmpty()) if (requiredGenitals.NullOrEmpty()) return;
{ return; }
if (requiredGenitals.Contains("OneHand") && handCount < 1) if (requiredGenitals.Contains("OneHand") && handCount < 1)
{ failReason = "missing hand"; __result = false; } { failReason = "missing hand"; __result = false; }
@ -85,25 +82,6 @@ namespace Rimworld_Animations_Patch
return false; return false;
} }
// Adds functionality to determine which apparel each actor should discard based on the animation they are running
public static void Postfix_RerollAnimations(Pawn pawn)
{
AnimationDef anim = pawn.GetAnimationData()?.animationDef;
if (anim != null)
{
DebugMode.Message("Running animation: " + anim.defName);
List<Pawn> pawnsToAnimate = pawn.GetAllSexParticipants();
foreach (Pawn participant in pawnsToAnimate)
{
int actorID = (int)AccessTools.Field(typeof(CompBodyAnimator), "actor").GetValue(participant.TryGetComp<CompBodyAnimator>());
DebugMode.Message("Participant " + actorID + ": " + participant.NameShortColored);
}
}
}
// Replacement patch for AlienRace to draw the body addons // Replacement patch for AlienRace to draw the body addons
public static bool Prefix_DrawAddons(PawnRenderFlags renderFlags, Vector3 vector, Vector3 headOffset, Pawn pawn, Quaternion quat, Rot4 rotation) public static bool Prefix_DrawAddons(PawnRenderFlags renderFlags, Vector3 vector, Vector3 headOffset, Pawn pawn, Quaternion quat, Rot4 rotation)
{ {
@ -251,4 +229,4 @@ namespace Rimworld_Animations_Patch
Hat (over hair) = rootLoc + YOffset_PostHead; (~ 0.031) Hat (over hair) = rootLoc + YOffset_PostHead; (~ 0.031)
*/ */
} }
} }

View file

@ -12,7 +12,7 @@ namespace Rimworld_Animations_Patch
{ {
public static class AnimationPatchUtility public static class AnimationPatchUtility
{ {
public static int FindTrueAnimationLength(Pawn pawn, out int orgasmTick) public static int FindTrueAnimationLength(Pawn pawn, out int orgasmTick, bool skipFirstStage = false)
{ {
orgasmTick = int.MaxValue; orgasmTick = int.MaxValue;
@ -37,8 +37,8 @@ namespace Rimworld_Animations_Patch
foreach (AnimationStage animStage in anim.animationStages) foreach (AnimationStage animStage in anim.animationStages)
{ {
// Legacy: skip the first stage of quickies if there's no playTimeTicksQuick values declared // Legacy: skip the first stage of quickies if there's no playTimeTicksQuick values declared
if (anim.animationStages.IndexOf(animStage) == 0 && isQuickie && anim.animationStages.Any(x => x.playTimeTicksQuick >= 0) == false) if (anim.animationStages.IndexOf(animStage) == 0 && isQuickie && anim.animationStages.Any(x => x.playTimeTicksQuick >= 0) == false) continue;
{ continue; } if (anim.animationStages.IndexOf(animStage) == 0 && skipFirstStage) continue;
int curr_tick = 0; int curr_tick = 0;
@ -68,8 +68,9 @@ namespace Rimworld_Animations_Patch
{ orgasmTick = (int)(ticks * (2f + Rand.Value)); } { orgasmTick = (int)(ticks * (2f + Rand.Value)); }
} }
return ticks; DebugMode.Message(pawn.NameShortColored + " will orgasm at tick " + orgasmTick);
return ticks;
} }
// Extended version of PawnHeadRotInAnimation (prevents pawn hair from getting messed up when draw in portraits) // Extended version of PawnHeadRotInAnimation (prevents pawn hair from getting messed up when draw in portraits)

View file

@ -72,15 +72,12 @@ namespace Rimworld_Animations_Patch
public static void DetermineApparelToKeepOn(Pawn pawn) public static void DetermineApparelToKeepOn(Pawn pawn)
{ {
if (pawn?.apparel?.WornApparel == null) if (pawn?.apparel?.WornApparel == null) return;
{ return; }
foreach (Apparel apparel in pawn.apparel.WornApparel) foreach (Apparel apparel in pawn.apparel.WornApparel)
{ {
CompApparelVisibility comp = apparel.TryGetComp<CompApparelVisibility>(); CompApparelVisibility comp = apparel.TryGetComp<CompApparelVisibility>();
if (comp != null) comp.isBeingWorn = true;
if (comp != null)
{ comp.isBeingWorn = true; }
} }
ActorAnimationData animData = pawn.GetAnimationData(); ActorAnimationData animData = pawn.GetAnimationData();
@ -98,14 +95,9 @@ namespace Rimworld_Animations_Patch
{ {
CompApparelVisibility comp = apparel.TryGetComp<CompApparelVisibility>(); CompApparelVisibility comp = apparel.TryGetComp<CompApparelVisibility>();
if (comp == null) if (comp == null) continue;
{ continue; } if (apparel.def is bondage_gear_def) continue;
if (ApparelSettings.GetRimNudeData(apparel) != null && ApparelSettings.GetRimNudeData(apparel).sexWear) continue;
if (apparel.def is bondage_gear_def)
{ continue; }
if (ApparelSettings.GetRimNudeData(apparel) != null && ApparelSettings.GetRimNudeData(apparel).sexWear)
{ continue; }
if (clothingPreference == RJWPreferenceSettings.Clothing.Nude || undressForRitual || undressForParty) if (clothingPreference == RJWPreferenceSettings.Clothing.Nude || undressForRitual || undressForParty)
{ {