mirror of
				https://gitgud.io/AbstractConcept/rimworld-animations-patch.git
				synced 2024-08-15 00:43:27 +00:00 
			
		
		
		
	v 2.0.0
This commit is contained in:
		
							parent
							
								
									fcf187c7dd
								
							
						
					
					
						commit
						38ec4f86c1
					
				
					 68 changed files with 846 additions and 1934 deletions
				
			
		| 
						 | 
				
			
			@ -29,7 +29,7 @@ namespace Rimworld_Animations_Patch
 | 
			
		|||
				}))();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			catch (TypeLoadException ex) { }
 | 
			
		||||
			catch (TypeLoadException) {  }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static bool Prefix_ShouldNotDrawAddonsForPawn(ref bool __result, Pawn pawn)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,9 +23,9 @@ namespace Rimworld_Animations_Patch
 | 
			
		|||
				LocalTargetInfo b = jobdriver.job.targetB.IsValid ? jobdriver.job.targetB : jobdriver.job.targetQueueB.FirstValid();
 | 
			
		||||
				LocalTargetInfo targetC = jobdriver.job.targetC;
 | 
			
		||||
 | 
			
		||||
				__result = JobUtility.GetResolvedJobReport(jobdriver.pawn.GetAnimationData().animationDef.label, a, b, targetC);
 | 
			
		||||
				//__result = JobUtility.GetResolvedJobReport(jobdriver.pawn.GetAnimationData().animationDef.label, a, b, targetC);
 | 
			
		||||
 | 
			
		||||
				return false;
 | 
			
		||||
				//return false;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return true;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,11 +17,6 @@ namespace Rimworld_Animations_Patch
 | 
			
		|||
        {
 | 
			
		||||
            Harmony harmony = new Harmony("Rimworld_Animations_Patch");
 | 
			
		||||
            harmony.PatchAll(Assembly.GetExecutingAssembly());
 | 
			
		||||
 | 
			
		||||
            Quirk voyeur = new Quirk("Voyeur", "VoyeurQuirk", null, null);
 | 
			
		||||
 | 
			
		||||
            if (Quirk.All.Contains(voyeur) == false)
 | 
			
		||||
            { Quirk.All.Add(voyeur); }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,67 +12,11 @@ using rjw;
 | 
			
		|||
 | 
			
		||||
namespace Rimworld_Animations_Patch
 | 
			
		||||
{
 | 
			
		||||
	/*[StaticConstructorOnStartup]
 | 
			
		||||
	[HarmonyPatch(typeof(PawnRenderer), "RenderPawnInternal", new Type[]
 | 
			
		||||
	{
 | 
			
		||||
				typeof(Vector3),
 | 
			
		||||
				typeof(float),
 | 
			
		||||
				typeof(bool),
 | 
			
		||||
				typeof(Rot4),
 | 
			
		||||
				typeof(RotDrawMode),
 | 
			
		||||
				typeof(PawnRenderFlags)
 | 
			
		||||
	}
 | 
			
		||||
	)]
 | 
			
		||||
	public static class HarmonyPatch_PawnRenderer_RenderPawnInternal
 | 
			
		||||
	{
 | 
			
		||||
		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
 | 
			
		||||
		{
 | 
			
		||||
			List<CodeInstruction> ins = instructions.ToList();
 | 
			
		||||
 | 
			
		||||
			for (int i = 0; i < instructions.Count(); i++)
 | 
			
		||||
			{
 | 
			
		||||
				bool runIns = true;
 | 
			
		||||
 | 
			
		||||
				// Replaces the rotation that gets passed to DrawHeadHair with one that is based the current 'true' head orientation
 | 
			
		||||
				if (i + 8 < instructions.Count() && ins[i + 8].opcode == OpCodes.Call && ins[i + 8].operand != null && ins[i + 8].OperandIs(AccessTools.DeclaredMethod(typeof(PawnRenderer), "DrawHeadHair")))
 | 
			
		||||
				{
 | 
			
		||||
					// Get the true head rotation
 | 
			
		||||
					yield return new CodeInstruction(OpCodes.Ldarg_0);
 | 
			
		||||
					yield return new CodeInstruction(OpCodes.Ldfld, AccessTools.DeclaredField(typeof(PawnRenderer), "pawn"));
 | 
			
		||||
					yield return new CodeInstruction(OpCodes.Ldloc, (object)7); // local body facing
 | 
			
		||||
					yield return new CodeInstruction(OpCodes.Ldarg_S, (object)6); // renderer flags
 | 
			
		||||
					yield return new CodeInstruction(OpCodes.Call, AccessTools.DeclaredMethod(typeof(AnimationPatchUtility), "PawnHeadRotInAnimation"));
 | 
			
		||||
					yield return new CodeInstruction(OpCodes.Stloc_S, (object)7); // set local body facing to true head facing
 | 
			
		||||
 | 
			
		||||
					// Pass this head rotation to a new DrawHeadHair call
 | 
			
		||||
					yield return new CodeInstruction(OpCodes.Ldarg_0);
 | 
			
		||||
					yield return new CodeInstruction(OpCodes.Ldarg_1);
 | 
			
		||||
					yield return new CodeInstruction(OpCodes.Ldloc_S, (object)6);
 | 
			
		||||
					yield return new CodeInstruction(OpCodes.Ldarg_2);
 | 
			
		||||
					yield return new CodeInstruction(OpCodes.Ldloc_S, (object)7); // local true head facing
 | 
			
		||||
					yield return new CodeInstruction(OpCodes.Ldloc_S, (object)7); // local true head facing
 | 
			
		||||
					yield return new CodeInstruction(OpCodes.Ldarg_S, (object)5); // bodyDrawType
 | 
			
		||||
					yield return new CodeInstruction(OpCodes.Ldarg_S, (object)6); // renderer flags
 | 
			
		||||
					yield return new CodeInstruction(OpCodes.Call, AccessTools.DeclaredMethod(typeof(PawnRenderer), "DrawHeadHair"));
 | 
			
		||||
 | 
			
		||||
					// Skip the original call to DrawHeadHair
 | 
			
		||||
					i = i + 8;
 | 
			
		||||
 | 
			
		||||
					runIns = false;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (runIns)
 | 
			
		||||
				{
 | 
			
		||||
					yield return ins[i];
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}*/
 | 
			
		||||
 | 
			
		||||
	[StaticConstructorOnStartup]
 | 
			
		||||
	[HarmonyPatch(typeof(PawnGraphicSet), "ResolveAllGraphics")]
 | 
			
		||||
	public static class HarmonyPatch_PawnGraphicSet_ResolveAllGraphics
 | 
			
		||||
	{
 | 
			
		||||
		// Update whether body parts are visible after resolving graphics
 | 
			
		||||
		public static void Postfix(PawnGraphicSet __instance)
 | 
			
		||||
		{
 | 
			
		||||
			if (__instance?.pawn?.apparel == null)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,6 @@ using Verse;
 | 
			
		|||
using Verse.AI;
 | 
			
		||||
using rjw;
 | 
			
		||||
using Rimworld_Animations;
 | 
			
		||||
using RJW_ToysAndMasturbation;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations_Patch
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -16,48 +15,8 @@ namespace Rimworld_Animations_Patch
 | 
			
		|||
	{
 | 
			
		||||
		public static void Postfix(ref JobDriver_Sex __instance)
 | 
			
		||||
		{
 | 
			
		||||
			Pawn pawn = __instance.pawn;
 | 
			
		||||
 | 
			
		||||
			// Sets ticks so that the orgasm meter starts empty, plus stop any running animations
 | 
			
		||||
			HarmonyPatch_JobDriver_Masturbate_setup_ticks.Postfix(ref __instance);
 | 
			
		||||
 | 
			
		||||
			// Invite another for a threesome?
 | 
			
		||||
			if (RJWHookupSettings.QuickHookupsEnabled &&
 | 
			
		||||
				__instance is JobDriver_SexBaseInitiator &&
 | 
			
		||||
				pawn.GetAllSexParticipants().Count == 2 &&
 | 
			
		||||
				(__instance is JobDriver_JoinInSex) == false &&
 | 
			
		||||
				Random.value < BasicSettings.chanceForOtherToJoinInSex)
 | 
			
		||||
			{
 | 
			
		||||
				DebugMode.Message("Find another to join in sex");
 | 
			
		||||
 | 
			
		||||
				List<Pawn> candidates = new List<Pawn>();
 | 
			
		||||
				float radius = 4f;
 | 
			
		||||
 | 
			
		||||
				foreach (Thing thing in GenRadial.RadialDistinctThingsAround(pawn.Position, pawn.Map, radius, true))
 | 
			
		||||
				{
 | 
			
		||||
					Pawn other = thing as Pawn;
 | 
			
		||||
					ThoughtDef thoughtDef = SexInteractionUtility.GetThoughtsAboutSexAct(other, __instance, out Precept precept);
 | 
			
		||||
 | 
			
		||||
					// Find candidates to invite
 | 
			
		||||
					if (other != null && thoughtDef?.hediff == null && SexInteractionUtility.InvitePasserbyForSex(other, pawn.GetAllSexParticipants()))
 | 
			
		||||
					{
 | 
			
		||||
						DebugMode.Message(other.NameShortColored + " is a potential candidate");
 | 
			
		||||
						candidates.Add(other);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Invite a random candidate (weighted by attraction)
 | 
			
		||||
				if (candidates.Count > 0)
 | 
			
		||||
				{
 | 
			
		||||
					Pawn invitedPawn = candidates.RandomElementByWeight(x => SexAppraiser.would_fuck(pawn, x, false, false, true) + SexAppraiser.would_fuck(pawn.GetSexPartner(), x, false, false, true));
 | 
			
		||||
					pawn.GetSexInitiator().IsInBed(out Building bed);
 | 
			
		||||
 | 
			
		||||
					DebugMode.Message(invitedPawn.NameShortColored + " was invited to join in sex");
 | 
			
		||||
 | 
			
		||||
					Job job = new Job(DefDatabase<JobDef>.GetNamed("JoinInSex", false), pawn.GetSexPartner(), bed);
 | 
			
		||||
					invitedPawn.jobs.TryTakeOrderedJob(job);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -117,10 +76,10 @@ namespace Rimworld_Animations_Patch
 | 
			
		|||
 | 
			
		||||
				SexProps sexProps = new SexProps();
 | 
			
		||||
				sexProps.pawn = __instance.pawn;
 | 
			
		||||
				sexProps.partner = __instance.pawn;
 | 
			
		||||
				sexProps.partner = null;
 | 
			
		||||
				sexProps.sexType = xxx.rjwSextype.Masturbation;
 | 
			
		||||
 | 
			
		||||
				List<InteractionDef> interactionDefs = DefDatabase<InteractionDef>.AllDefs.Where(x => x.HasModExtension<InteractionExtension>()).ToList();
 | 
			
		||||
				IEnumerable<InteractionDef> interactionDefs = DefDatabase<InteractionDef>.AllDefs.Where(x => x.HasModExtension<InteractionExtension>());
 | 
			
		||||
				Dictionary<rjw.Modules.Interactions.Objects.InteractionWithExtension, float> interactionsPlusWeights = new Dictionary<rjw.Modules.Interactions.Objects.InteractionWithExtension, float>();
 | 
			
		||||
 | 
			
		||||
				foreach (InteractionDef interactionDef in interactionDefs)
 | 
			
		||||
| 
						 | 
				
			
			@ -161,7 +120,6 @@ namespace Rimworld_Animations_Patch
 | 
			
		|||
			{ return; }
 | 
			
		||||
 | 
			
		||||
			// Get animation data
 | 
			
		||||
			AnimationDef anim = __instance.pawn.GetAnimationData()?.animationDef;
 | 
			
		||||
			List<Pawn> pawnsToAnimate = __instance.pawn.GetAllSexParticipants();
 | 
			
		||||
 | 
			
		||||
			// Sync animations across participants
 | 
			
		||||
| 
						 | 
				
			
			@ -276,8 +234,8 @@ namespace Rimworld_Animations_Patch
 | 
			
		|||
			if (sexProps.sexType != xxx.rjwSextype.Oral || pawnsToAnimate.Count != 2)
 | 
			
		||||
			{ return; }
 | 
			
		||||
 | 
			
		||||
			List<AnimationDef> kissingAnims = DefDatabase<AnimationDef>.AllDefs.Where(x => x.defName.Contains("Kiss")).ToList();
 | 
			
		||||
			AnimationDef anim = kissingAnims[Random.Range(0, kissingAnims.Count)];
 | 
			
		||||
			IEnumerable<AnimationDef> kissingAnims = DefDatabase<AnimationDef>.AllDefs.Where(x => x.defName.Contains("Kiss"));
 | 
			
		||||
			AnimationDef anim = kissingAnims.ElementAt(Random.Range(0, kissingAnims.Count()));
 | 
			
		||||
 | 
			
		||||
			if (anim == null)
 | 
			
		||||
			{ DebugMode.Message("No animation found"); return; }
 | 
			
		||||
| 
						 | 
				
			
			@ -299,41 +257,6 @@ namespace Rimworld_Animations_Patch
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	[HarmonyPatch(typeof(JobDriver_Sex), "SexTick")]
 | 
			
		||||
	public static class HarmonyPatch_JobDriver_Sex_SexTick
 | 
			
		||||
	{
 | 
			
		||||
		// If pawns don't have privacy, they'll stop having sex
 | 
			
		||||
		public static void Postfix(ref JobDriver_Sex __instance, Pawn pawn)
 | 
			
		||||
		{
 | 
			
		||||
			if (pawn.IsHashIntervalTick(90))
 | 
			
		||||
			{
 | 
			
		||||
				if (pawn.IsMasturbating() && pawn.HasPrivacy(8f) == false)
 | 
			
		||||
				{ pawn.jobs.EndCurrentJob(JobCondition.InterruptForced, false, false); }
 | 
			
		||||
 | 
			
		||||
				else if (pawn.IsHavingSex())
 | 
			
		||||
				{
 | 
			
		||||
					bool havePrivacy = true;
 | 
			
		||||
					List<Pawn> participants = pawn.GetAllSexParticipants();
 | 
			
		||||
 | 
			
		||||
					foreach (Pawn participant in participants)
 | 
			
		||||
					{
 | 
			
		||||
						if (participant.HasPrivacy(8f) == false)
 | 
			
		||||
						{ havePrivacy = false; }
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					if (__instance.Sexprops != null && (__instance.Sexprops.isRape || __instance.Sexprops.isWhoring))
 | 
			
		||||
					{ return; }
 | 
			
		||||
 | 
			
		||||
					if (havePrivacy == false)
 | 
			
		||||
					{
 | 
			
		||||
						foreach (Pawn participant in participants)
 | 
			
		||||
						{ participant.jobs.EndCurrentJob(JobCondition.InterruptForced, false, false); }
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	[HarmonyPatch(typeof(JobDriver_Sex), "Orgasm")]
 | 
			
		||||
	public static class HarmonyPatch_JobDriver_Sex_Orgasm
 | 
			
		||||
	{
 | 
			
		||||
| 
						 | 
				
			
			@ -346,7 +269,8 @@ namespace Rimworld_Animations_Patch
 | 
			
		|||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static bool ParticipantsDesireMoreSex(JobDriver_Sex jobdriver)
 | 
			
		||||
		// Causes too much trouble...
 | 
			
		||||
		/*public static bool ParticipantsDesireMoreSex(JobDriver_Sex jobdriver)
 | 
			
		||||
		{
 | 
			
		||||
			List<Pawn> participants = jobdriver.pawn.GetAllSexParticipants();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -387,7 +311,7 @@ namespace Rimworld_Animations_Patch
 | 
			
		|||
					participants[1].jobs.StartJob(job, JobCondition.Succeeded);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		}*/
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	[HarmonyPatch(typeof(JobDriver_SexBaseInitiator), "End")]
 | 
			
		||||
| 
						 | 
				
			
			@ -398,7 +322,7 @@ namespace Rimworld_Animations_Patch
 | 
			
		|||
		{
 | 
			
		||||
			if (__instance.Partner != null && __instance?.Partner?.jobs?.curDriver != null && __instance.Partner.Dead == false && __instance.Partner?.jobs.curDriver is JobDriver_SexBaseReciever)
 | 
			
		||||
			{
 | 
			
		||||
				foreach (Pawn participant in (__instance.Partner?.jobs.curDriver as JobDriver_SexBaseReciever).parteners.ToList())
 | 
			
		||||
				foreach (Pawn participant in (__instance.Partner?.jobs.curDriver as JobDriver_SexBaseReciever).parteners)
 | 
			
		||||
				{ participant.jobs.EndCurrentJob(JobCondition.Succeeded, false, true); }
 | 
			
		||||
 | 
			
		||||
				(__instance.Partner?.jobs.curDriver as JobDriver_SexBaseReciever).parteners.Clear();
 | 
			
		||||
| 
						 | 
				
			
			@ -426,7 +350,7 @@ namespace Rimworld_Animations_Patch
 | 
			
		|||
		// Fixes mouth check
 | 
			
		||||
		public static bool Prefix(ref bool __result, Pawn pawn)
 | 
			
		||||
		{
 | 
			
		||||
			__result = pawn.health.hediffSet.GetNotMissingParts().Any(x => x.def.defName.ToLower().ContainsAny("mouth", "teeth", "jaw", "beak"));
 | 
			
		||||
			__result = pawn.health.hediffSet.GetNotMissingParts().Any(x => x.def.defName.ContainsAny("mouth", "teeth", "jaw", "beak", "Mouth", "Teeth", "Jaw", "Beak"));
 | 
			
		||||
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,7 +26,7 @@ namespace Rimworld_Animations_Patch
 | 
			
		|||
				}))();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			catch (TypeLoadException ex) { }
 | 
			
		||||
			catch (TypeLoadException) { }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public static bool Postfix_ThinkNode_ConditionalNude_Satisfied(ref bool __result, Pawn pawn)
 | 
			
		||||
| 
						 | 
				
			
			@ -34,7 +34,7 @@ namespace Rimworld_Animations_Patch
 | 
			
		|||
			if (__result == false && pawn?.apparel?.WornApparel != null)
 | 
			
		||||
			{
 | 
			
		||||
				// If 'isBeingWorn' has a value, the apparel has already been checked if it should be discarded
 | 
			
		||||
				if (pawn.apparel.WornApparel.Any(x => x.TryGetComp<CompApparelVisibility>() != null && x.TryGetComp<CompApparelVisibility>().isBeingWorn.HasValue))
 | 
			
		||||
				if (pawn.apparel.WornApparel.NullOrEmpty() || pawn.apparel.WornApparel.Any(x => x.TryGetComp<CompApparelVisibility>() != null && x.TryGetComp<CompApparelVisibility>().isBeingWorn.HasValue))
 | 
			
		||||
				{ __result = true; }
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,7 @@ using RimNudeWorld;
 | 
			
		|||
 | 
			
		||||
namespace Rimworld_Animations_Patch
 | 
			
		||||
{
 | 
			
		||||
	[StaticConstructorOnStartup]
 | 
			
		||||
	/*[StaticConstructorOnStartup]
 | 
			
		||||
	public static class HarmonyPatch_RimNudeWorld
 | 
			
		||||
	{
 | 
			
		||||
		static HarmonyPatch_RimNudeWorld()
 | 
			
		||||
| 
						 | 
				
			
			@ -33,5 +33,5 @@ namespace Rimworld_Animations_Patch
 | 
			
		|||
		{
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	}*/
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,7 +38,7 @@ namespace Rimworld_Animations_Patch
 | 
			
		|||
				CompPawnSexData comp = participant.TryGetComp<CompPawnSexData>();
 | 
			
		||||
				if (comp == null) return;
 | 
			
		||||
 | 
			
		||||
				comp.UpdateHands();
 | 
			
		||||
				comp.UpdateBodyPartCountAndSize();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +48,7 @@ namespace Rimworld_Animations_Patch
 | 
			
		|||
			CompPawnSexData comp = __instance.pawn.TryGetComp<CompPawnSexData>();
 | 
			
		||||
			if (comp == null) return;
 | 
			
		||||
 | 
			
		||||
			comp.handAnimationDef = DefDatabase<HandAnimationDef>.AllDefs.FirstOrDefault(x => x.animationDefName == __instance.pawn?.GetAnimationData()?.animationDef?.defName);
 | 
			
		||||
			comp.handAnimationDef = DefDatabase<HandAnimationDef>.AllDefs.FirstOrDefault(x => x.animationDef == __instance.pawn?.GetAnimationData()?.animationDef);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Extend the animation selector's body part check to include hands and whether the pawn is in bed or not
 | 
			
		||||
| 
						 | 
				
			
			@ -108,32 +108,32 @@ namespace Rimworld_Animations_Patch
 | 
			
		|||
		public static bool Prefix_DrawAddons(PawnRenderFlags renderFlags, Vector3 vector, Vector3 headOffset, Pawn pawn, Quaternion quat, Rot4 rotation)
 | 
			
		||||
		{
 | 
			
		||||
			if (!(pawn.def is ThingDef_AlienRace alienProps) || renderFlags.FlagSet(PawnRenderFlags.Invisible)) return false;
 | 
			
		||||
			if (AnimationPatchUtility.ShouldNotDrawAddonsForPawn(pawn))
 | 
			
		||||
			{ return false; }	
 | 
			
		||||
 | 
			
		||||
			// Get actor components and body addons
 | 
			
		||||
			List<AlienPartGenerator.BodyAddon> bodyAddons = alienProps.alienRace.generalSettings.alienPartGenerator.bodyAddons;
 | 
			
		||||
			AlienPartGenerator.AlienComp alienComp = pawn.GetComp<AlienPartGenerator.AlienComp>();
 | 
			
		||||
			CompBodyAnimator animatorComp = pawn.TryGetComp<CompBodyAnimator>();
 | 
			
		||||
			CompPawnSexData sexDataComp = pawn.TryGetComp<CompPawnSexData>();
 | 
			
		||||
			ActorAnimationData pawnAnimationData = pawn?.GetAnimationData();
 | 
			
		||||
 | 
			
		||||
			// Try to draw apparel thrown on ground
 | 
			
		||||
			if (ApparelSettings.clothesThrownOnGround)
 | 
			
		||||
			{ ApparelAnimationUtility.TryToDrawApparelOnFloor(pawn); }
 | 
			
		||||
 | 
			
		||||
			// Get actor components and body addons
 | 
			
		||||
			List<AlienPartGenerator.BodyAddon> bodyAddons = alienProps.alienRace.generalSettings.alienPartGenerator.bodyAddons.ToList();
 | 
			
		||||
			AlienPartGenerator.AlienComp alienComp = pawn.GetComp<AlienPartGenerator.AlienComp>();
 | 
			
		||||
			CompBodyAnimator animatorComp = pawn.TryGetComp<CompBodyAnimator>();
 | 
			
		||||
			CompPawnSexData sexDataComp = pawn.TryGetComp<CompPawnSexData>();
 | 
			
		||||
			if (sexDataComp == null) return true;
 | 
			
		||||
			// Exit clauses
 | 
			
		||||
			if (BasicSettings.useLegacyAnimationSystem || AnimationPatchUtility.ShouldNotDrawAddonsForPawn(pawn) || sexDataComp == null)
 | 
			
		||||
			{ return true; }
 | 
			
		||||
 | 
			
		||||
			// Get available hands
 | 
			
		||||
			int handsAvailableCount = sexDataComp.GetNumberOfHands();
 | 
			
		||||
 | 
			
		||||
			// Sort addons by their layer offset, otherwise body parts will actualy be layered according to their position in the list
 | 
			
		||||
			// Note that sorting the addons directly seems to mess up relations between lists need by AlienRace
 | 
			
		||||
			var sortedBodyAddons = bodyAddons.Select((x, i) => new KeyValuePair<AlienPartGenerator.BodyAddon, int>(x, i)).OrderBy(x => x.Key.offsets.GetOffset(rotation).layerOffset).ToList();
 | 
			
		||||
			List<int> idxBodyAddons = sortedBodyAddons.Select(x => x.Value).ToList();
 | 
			
		||||
			var sortedBodyAddons = bodyAddons.Select((x, i) => new KeyValuePair<AlienPartGenerator.BodyAddon, int>(x, i)).OrderBy(x => x.Key.offsets.GetOffset(rotation).layerOffset);
 | 
			
		||||
			IEnumerable<int> idxBodyAddons = sortedBodyAddons.Select(x => x.Value);
 | 
			
		||||
 | 
			
		||||
			for (int idx = 0; idx < idxBodyAddons.Count; idx++)
 | 
			
		||||
			foreach(int i in idxBodyAddons)
 | 
			
		||||
			{
 | 
			
		||||
				int i = idxBodyAddons[idx];
 | 
			
		||||
 | 
			
		||||
				// Get body addon components
 | 
			
		||||
				AlienPartGenerator.BodyAddon bodyAddon = bodyAddons[i];
 | 
			
		||||
				Graphic addonGraphic = alienComp.addonGraphics[i];
 | 
			
		||||
| 
						 | 
				
			
			@ -141,33 +141,33 @@ namespace Rimworld_Animations_Patch
 | 
			
		|||
				if (bodyAddonDatum == null) continue;
 | 
			
		||||
 | 
			
		||||
				// Can draw?
 | 
			
		||||
				bool canDraw = addonGraphic.path.ToLower().Contains("featureless") == false && bodyAddonDatum.CanDraw();
 | 
			
		||||
				bool canDraw = addonGraphic.path.Contains("featureless") == false && addonGraphic.path.Contains("Featureless") == false && bodyAddonDatum.CanDraw();
 | 
			
		||||
				bool drawHand = BasicSettings.showHands && handsAvailableCount > 0 && renderFlags.FlagSet(PawnRenderFlags.Portrait) == false;
 | 
			
		||||
				
 | 
			
		||||
 | 
			
		||||
				if (canDraw == false && drawHand == false)
 | 
			
		||||
				{ continue; }
 | 
			
		||||
 | 
			
		||||
				// Get body angle
 | 
			
		||||
				float bodyAngle = animatorComp?.isAnimating == true && renderFlags.FlagSet(PawnRenderFlags.Portrait) == false ? animatorComp.bodyAngle : quat.eulerAngles.y;
 | 
			
		||||
				bodyAngle = bodyAngle < 0f ? 360f + (bodyAngle % 360f) : bodyAngle % 360f;
 | 
			
		||||
				bodyAngle = MathUtility.ClampAngle(bodyAngle);
 | 
			
		||||
 | 
			
		||||
				// Get the apparent rotation and body addon angle
 | 
			
		||||
				Rot4 apparentRotation = rotation;
 | 
			
		||||
				float bodyAddonAngle = bodyAddon.angle;
 | 
			
		||||
 | 
			
		||||
				float bodyAddonAngle = MathUtility.ClampAngle(bodyAddon.angle);
 | 
			
		||||
 | 
			
		||||
				if (renderFlags.FlagSet(PawnRenderFlags.Portrait) == false && animatorComp?.isAnimating == true)
 | 
			
		||||
				{
 | 
			
		||||
					apparentRotation = bodyAddonDatum.alignsWithHead ? animatorComp.headFacing : animatorComp.bodyFacing;
 | 
			
		||||
 | 
			
		||||
					if (animatorComp.controlGenitalAngle && addonGraphic.path.ToLower().Contains("penis"))
 | 
			
		||||
					{ bodyAddonAngle += AnimationSettings.controlGenitalRotation ? animatorComp.genitalAngle : 0f; }
 | 
			
		||||
 | 
			
		||||
					if (bodyAddonDatum.alignsWithHead)
 | 
			
		||||
					{ bodyAngle = animatorComp.headAngle; }
 | 
			
		||||
					{ bodyAngle = MathUtility.ClampAngle(animatorComp.headAngle); }
 | 
			
		||||
 | 
			
		||||
					if (animatorComp.controlGenitalAngle && (addonGraphic.path.Contains("penis") || addonGraphic.path.Contains("Penis")))
 | 
			
		||||
					{ bodyAddonAngle = MathUtility.ClampAngle(bodyAddonAngle + (AnimationSettings.controlGenitalRotation ? MathUtility.ClampAngle(animatorComp.genitalAngle) : 0f)); }
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				bodyAddonAngle = bodyAddonAngle < 0f ? 360f - (bodyAddonAngle % 360) : bodyAddonAngle % 360f;
 | 
			
		||||
				float combinedAngle = (bodyAngle + bodyAddonAngle) < 0f ? 360f + ((bodyAngle + bodyAddonAngle) % 360) : (bodyAngle + bodyAddonAngle) % 360f;
 | 
			
		||||
				float combinedAngle = MathUtility.ClampAngle(bodyAngle + bodyAddonAngle);
 | 
			
		||||
 | 
			
		||||
				Vector3 vector_ = vector;
 | 
			
		||||
				Vector3 headOffset_ = bodyAddonDatum.alignsWithHead ? headOffset : Vector3.zero;
 | 
			
		||||
| 
						 | 
				
			
			@ -190,21 +190,45 @@ namespace Rimworld_Animations_Patch
 | 
			
		|||
				{
 | 
			
		||||
					GenDraw.DrawMeshNowOrLater(mesh: addonGraphic.MeshAt(rot: apparentRotation),
 | 
			
		||||
						loc: bodyAddonPosition,
 | 
			
		||||
						quat: Mathf.Approximately(combinedAngle, 0f) ? quat : Quaternion.AngleAxis(angle: combinedAngle, axis: Vector3.up),
 | 
			
		||||
						quat: Quaternion.AngleAxis(angle: combinedAngle, axis: Vector3.up),
 | 
			
		||||
						mat: addonGraphic.MatAt(rot: apparentRotation),
 | 
			
		||||
						drawNow: renderFlags.FlagSet(PawnRenderFlags.DrawNow));
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
 | 
			
		||||
				// Draw hand over the body part if required
 | 
			
		||||
				if (drawHand)
 | 
			
		||||
				{
 | 
			
		||||
					float finalAngle = 0;
 | 
			
		||||
 | 
			
		||||
					if (HandAnimationUtility.TryToDrawHand(pawn, addonGraphic.path, bodyAddonPosition, finalAngle, rotation, renderFlags))
 | 
			
		||||
					if (HandAnimationUtility.TryToDrawHand(pawn, pawnAnimationData, addonGraphic.path, bodyAddonPosition, finalAngle, rotation, renderFlags))
 | 
			
		||||
					{ handsAvailableCount--; }
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Add-ons
 | 
			
		||||
			if (animatorComp?.isAnimating == true)
 | 
			
		||||
			{
 | 
			
		||||
				//ActorAnimationData actorData = pawn.GetAnimationData();
 | 
			
		||||
				//PawnAnimationClipExt clip = actorData.animationDef.animationStages[actorData.currentStage].animationClips[actorData.actorID] as PawnAnimationClipExt;
 | 
			
		||||
 | 
			
		||||
				/*foreach (ActorAddon addon in clip.Addons)
 | 
			
		||||
				{
 | 
			
		||||
					actorBodypart = actorBody.GetActorBodyPart(addon.AddonName);
 | 
			
		||||
					if (actorBodypart == null) continue;
 | 
			
		||||
 | 
			
		||||
					ActorBody anchoringActorBody = actorBodies.GetComponentsInChildren<ActorBody>()?.FirstOrDefault(x => x.actorID == addon.AnchoringActor);
 | 
			
		||||
					Vector3 anchor = PawnUtility.GetBodyPartAnchor(anchoringActorBody, addon.anchorName);
 | 
			
		||||
 | 
			
		||||
					actorBodypart.transform.position = anchor + new Vector3(addon.PosX.Evaluate(clipPercent), addon.PosZ.Evaluate(clipPercent), 0);
 | 
			
		||||
					actorBodypart.transform.eulerAngles = new Vector3(0, 0, -addon.Rotation.Evaluate(clipPercent));
 | 
			
		||||
 | 
			
		||||
					actorBodypart.bodyPartRenderer.sortingLayerName = addon.Layer;
 | 
			
		||||
					//actorBodypart.bodyPartRenderer.sprite
 | 
			
		||||
 | 
			
		||||
					actorBodypart.gameObject.SetActive(addon.Render);
 | 
			
		||||
				}*/
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Body addons are sometimes are not appropriately concealed by long hair in portraits, so re-draw the pawn's hair here
 | 
			
		||||
			if (pawn.Drawer.renderer.graphics.headGraphic != null && renderFlags.FlagSet(PawnRenderFlags.Portrait) && BasicSettings.redrawHair)
 | 
			
		||||
			{
 | 
			
		||||
| 
						 | 
				
			
			@ -214,10 +238,10 @@ namespace Rimworld_Animations_Patch
 | 
			
		|||
				float headAngle = animatorComp != null && animatorComp.isAnimating && !renderFlags.FlagSet(PawnRenderFlags.Portrait) ? animatorComp.headAngle : quat.eulerAngles.y;
 | 
			
		||||
				RotDrawMode rotDrawMode = (RotDrawMode)AccessTools.Property(typeof(PawnRenderer), "CurRotDrawMode").GetValue(pawn.Drawer.renderer);
 | 
			
		||||
 | 
			
		||||
				methodInfo.Invoke(pawn.Drawer.renderer, new object[] { vector + new Vector3(0f, YOffset_Head, 0f), headOffset, headAngle, headFacing, headFacing, rotDrawMode, renderFlags });
 | 
			
		||||
				methodInfo.Invoke(pawn.Drawer.renderer, new object[] { vector + new Vector3(0f, YOffset_Head, 0f), headOffset, headAngle, headFacing, headFacing, rotDrawMode, renderFlags, true });
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return false;
 | 
			
		||||
			return false;		
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// List of potentially useful layer offsets
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,107 +0,0 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using RimWorld;
 | 
			
		||||
using Verse;
 | 
			
		||||
using HarmonyLib;
 | 
			
		||||
 | 
			
		||||
namespace Rimworld_Animations_Patch
 | 
			
		||||
{
 | 
			
		||||
	[HarmonyPatch(typeof(ThoughtWorker_Precept_GroinChestHairOrFaceUncovered), "HasUncoveredGroinChestHairOrFace")]
 | 
			
		||||
	public static class HarmonyPatch_ThoughtWorker_Precept_GroinChestHairOrFaceUncovered
 | 
			
		||||
	{
 | 
			
		||||
		public static void Postfix(ref bool __result, Pawn p)
 | 
			
		||||
		{
 | 
			
		||||
			if (__result == false) return;
 | 
			
		||||
 | 
			
		||||
			Pawn pawn = p;
 | 
			
		||||
			if (ApparelSettings.underwearSufficentForIdeos == false) return;
 | 
			
		||||
 | 
			
		||||
			if (pawn?.apparel == null)
 | 
			
		||||
			{ __result = false; return; }
 | 
			
		||||
 | 
			
		||||
			if (pawn.apparel.WornApparel.NullOrEmpty())
 | 
			
		||||
			{ __result = true; return; }
 | 
			
		||||
 | 
			
		||||
			bool fullHeadCovered = pawn.apparel.WornApparel.Any(x => x.def.apparel.bodyPartGroups.Contains(BodyPartGroupDefOf.FullHead));
 | 
			
		||||
			bool groinCovered = pawn.apparel.WornApparel.Any(x => x.def.apparel.bodyPartGroups.Contains(BodyPartGroupDefOf.Legs) || x.def.apparel.bodyPartGroups.Contains(PatchBodyPartGroupDefOf.GenitalsBPG));
 | 
			
		||||
			bool chestCovered = pawn.apparel.WornApparel.Any(x => x.def.apparel.bodyPartGroups.Contains(BodyPartGroupDefOf.Torso) || x.def.apparel.bodyPartGroups.Contains(PatchBodyPartGroupDefOf.ChestBPG));
 | 
			
		||||
			bool faceCovered = fullHeadCovered || pawn.apparel.WornApparel.Any(x => x.def.apparel.bodyPartGroups.Contains(BodyPartGroupDefOf.Eyes));
 | 
			
		||||
			bool hairCovered = fullHeadCovered || pawn.apparel.WornApparel.Any(x => x.def.apparel.bodyPartGroups.Contains(BodyPartGroupDefOf.UpperHead));
 | 
			
		||||
 | 
			
		||||
			__result = !(groinCovered && chestCovered && faceCovered && hairCovered);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	[HarmonyPatch(typeof(ThoughtWorker_Precept_GroinChestOrHairUncovered), "HasUncoveredGroinChestOrHair")]
 | 
			
		||||
	public static class HarmonyPatch_ThoughtWorker_Precept_GroinChestOrHairUncovered
 | 
			
		||||
	{
 | 
			
		||||
		public static void Postfix(ref bool __result, Pawn p)
 | 
			
		||||
		{
 | 
			
		||||
			if (__result == false) return;
 | 
			
		||||
 | 
			
		||||
			Pawn pawn = p;
 | 
			
		||||
			if (ApparelSettings.underwearSufficentForIdeos == false) return;
 | 
			
		||||
 | 
			
		||||
			if (pawn?.apparel == null)
 | 
			
		||||
			{ __result = false; return; }
 | 
			
		||||
 | 
			
		||||
			if (pawn.apparel.WornApparel.NullOrEmpty())
 | 
			
		||||
			{ __result = true; return; }
 | 
			
		||||
 | 
			
		||||
			bool fullHeadCovered = pawn.apparel.WornApparel.Any(x => x.def.apparel.bodyPartGroups.Contains(BodyPartGroupDefOf.FullHead));
 | 
			
		||||
			bool groinCovered = pawn.apparel.WornApparel.Any(x => x.def.apparel.bodyPartGroups.Contains(BodyPartGroupDefOf.Legs) || x.def.apparel.bodyPartGroups.Contains(PatchBodyPartGroupDefOf.GenitalsBPG));
 | 
			
		||||
			bool chestCovered = pawn.apparel.WornApparel.Any(x => x.def.apparel.bodyPartGroups.Contains(BodyPartGroupDefOf.Torso) || x.def.apparel.bodyPartGroups.Contains(PatchBodyPartGroupDefOf.ChestBPG));
 | 
			
		||||
			bool hairCovered = fullHeadCovered || pawn.apparel.WornApparel.Any(x => x.def.apparel.bodyPartGroups.Contains(BodyPartGroupDefOf.UpperHead));
 | 
			
		||||
 | 
			
		||||
			__result = !(groinCovered && chestCovered && hairCovered);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	[HarmonyPatch(typeof(ThoughtWorker_Precept_GroinOrChestUncovered), "HasUncoveredGroinOrChest")]
 | 
			
		||||
	public static class HarmonyPatch_ThoughtWorker_Precept_HasUncoveredGroinOrChest
 | 
			
		||||
	{
 | 
			
		||||
		public static void Postfix(ref bool __result, Pawn p)
 | 
			
		||||
		{
 | 
			
		||||
			if (__result == false) return;
 | 
			
		||||
 | 
			
		||||
			Pawn pawn = p;
 | 
			
		||||
			if (ApparelSettings.underwearSufficentForIdeos == false) return;
 | 
			
		||||
 | 
			
		||||
			if (pawn?.apparel == null)
 | 
			
		||||
			{ __result = false; return; }
 | 
			
		||||
 | 
			
		||||
			if (pawn.apparel.WornApparel.NullOrEmpty())
 | 
			
		||||
			{ __result = true; return; }
 | 
			
		||||
 | 
			
		||||
			bool groinCovered = pawn.apparel.WornApparel.Any(x => x.def.apparel.bodyPartGroups.Contains(BodyPartGroupDefOf.Legs) || x.def.apparel.bodyPartGroups.Contains(PatchBodyPartGroupDefOf.GenitalsBPG));
 | 
			
		||||
			bool chestCovered = pawn.apparel.WornApparel.Any(x => x.def.apparel.bodyPartGroups.Contains(BodyPartGroupDefOf.Torso) || x.def.apparel.bodyPartGroups.Contains(PatchBodyPartGroupDefOf.ChestBPG));
 | 
			
		||||
 | 
			
		||||
			__result = !(groinCovered && chestCovered);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	[HarmonyPatch(typeof(ThoughtWorker_Precept_GroinUncovered), "HasUncoveredGroin")]
 | 
			
		||||
	public static class HarmonyPatch_ThoughtWorker_Precept_GroinUncovered
 | 
			
		||||
	{
 | 
			
		||||
		public static void Postfix(ref bool __result, Pawn p)
 | 
			
		||||
		{
 | 
			
		||||
			if (__result == false) return;
 | 
			
		||||
 | 
			
		||||
			Pawn pawn = p;
 | 
			
		||||
			if (ApparelSettings.underwearSufficentForIdeos == false) return;
 | 
			
		||||
 | 
			
		||||
			if (pawn?.apparel == null)
 | 
			
		||||
			{ __result = false; return; }
 | 
			
		||||
 | 
			
		||||
			if (pawn.apparel.WornApparel.NullOrEmpty())
 | 
			
		||||
			{ __result = true; return; }
 | 
			
		||||
 | 
			
		||||
			bool groinCovered = pawn.apparel.WornApparel.Any(x => x.def.apparel.bodyPartGroups.Contains(BodyPartGroupDefOf.Legs) || x.def.apparel.bodyPartGroups.Contains(PatchBodyPartGroupDefOf.GenitalsBPG));
 | 
			
		||||
 | 
			
		||||
			__result = !groinCovered;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue