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
Binary file not shown.
|
@ -19,7 +19,7 @@
|
|||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\1.3\Assemblies\</OutputPath>
|
||||
<OutputPath>..\1.4\Assemblies\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
|
@ -42,7 +42,7 @@
|
|||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="AlienRace">
|
||||
<HintPath>..\..\..\..\..\workshop\content\294100\839005762\1.3\Assemblies\AlienRace.dll</HintPath>
|
||||
<HintPath>..\..\..\..\..\workshop\content\294100\839005762\1.4\Assemblies\AlienRace.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
|
@ -66,34 +66,25 @@
|
|||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="RimNudeWorld">
|
||||
<HintPath>..\..\rimnude-unofficial-master\1.3 Assembly\Assemblies\RimNudeWorld.dll</HintPath>
|
||||
<HintPath>..\..\rimnude-unofficial-master\Assembly Folders\1.4 Assembly\Assemblies\RimNudeWorld.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Rimworld-Animations, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\rimworld-animations-master\1.3\Assemblies\Rimworld-Animations.dll</HintPath>
|
||||
<Reference Include="Rimworld-Animations">
|
||||
<HintPath>..\..\rimworld-animations-master\1.4\Assemblies\Rimworld-Animations.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="RJW, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\rjw-master\1.3\Assemblies\RJW.dll</HintPath>
|
||||
<Reference Include="RJW">
|
||||
<HintPath>..\..\RJW\1.4\Assemblies\RJW.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="RJW-Events">
|
||||
<HintPath>..\..\rjw-events-master\1.3\Assemblies\RJW-Events.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="RJW-ToysAndMasturbation">
|
||||
<HintPath>..\..\rjw-toys-and-masturbation-master\Assemblies\RJW-ToysAndMasturbation.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="RJWSexperience.Ideology">
|
||||
<HintPath>..\..\rjw-sexperience-ideology-master\1.3\Assemblies\RJWSexperience.Ideology.dll</HintPath>
|
||||
<HintPath>..\..\rjw-events-master\1.4\Assemblies\RJW-Events.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="UnityEngine">
|
||||
<HintPath>..\..\..\RimWorldWin64_Data\Managed\UnityEngine.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
|
@ -117,20 +108,32 @@
|
|||
<Compile Include="Scripts\Comps\CompProperties_ApparelVisibility.cs" />
|
||||
<Compile Include="Scripts\Comps\CompApparelVisibility.cs" />
|
||||
<Compile Include="Scripts\Comps\CompPawnSexData.cs" />
|
||||
<Compile Include="Scripts\Defs\ActorAddon.cs" />
|
||||
<Compile Include="Scripts\Defs\ActorAddonDef.cs" />
|
||||
<Compile Include="Scripts\Defs\ActorAnimationData.cs" />
|
||||
<Compile Include="Scripts\Defs\AddonKeyframe.cs" />
|
||||
<Compile Include="Scripts\Defs\BodyAddonData.cs" />
|
||||
<Compile Include="Scripts\Defs\HandAnimationDef.cs" />
|
||||
<Compile Include="Scripts\Extensions\StringExtension.cs" />
|
||||
<Compile Include="Scripts\HandMotions\HandMotion.cs" />
|
||||
<Compile Include="Scripts\HandMotions\RubBreasts_FacingEW.cs" />
|
||||
<Compile Include="Scripts\HandMotions\RubGenitals_FacingEW.cs" />
|
||||
<Compile Include="Scripts\HandMotions\StrokeGenitalsUpAndDown_FacingEW.cs" />
|
||||
<Compile Include="Scripts\HandMotions\RubGenitals_FacingNS.cs" />
|
||||
<Compile Include="Scripts\HandMotions\RubBreasts_FacingNS.cs" />
|
||||
<Compile Include="Scripts\HandMotions\StrokeGenitalsUpAndDown_FacingNS.cs" />
|
||||
<Compile Include="Scripts\HandMotions\StrokeGenitalsUpAndDownShort_FacingNS.cs" />
|
||||
<Compile Include="Scripts\Extensions\PawnAnimationClipExt.cs" />
|
||||
<Compile Include="Scripts\Defs\RimNudeData.cs" />
|
||||
<Compile Include="Scripts\Enums.cs" />
|
||||
<Compile Include="Scripts\Extensions\PawnKeyframeExt.cs" />
|
||||
<Compile Include="Scripts\Patches\HarmonyPatch_ApparelGraphicRecordGetter.cs" />
|
||||
<Compile Include="Scripts\Patches\HarmonyPatch_BabiesAndChildren.cs" />
|
||||
<Compile Include="Scripts\Patches\HarmonyPatch_Pawn_ApparelTracker.cs" />
|
||||
<Compile Include="Scripts\Patches\HarmonyPatch_DrawGUIOverlay.cs" />
|
||||
<Compile Include="Scripts\Patches\HarmonyPatch_JobDriver.cs" />
|
||||
<Compile Include="Scripts\Patches\HarmonyPatch_RJWEvents.cs" />
|
||||
<Compile Include="Scripts\Patches\HarmonyPatch_ThoughtWorkers.cs" />
|
||||
<Compile Include="Scripts\Settings\ApparelSettings.cs" />
|
||||
<Compile Include="Scripts\ThoughtWorkers\ThoughtWorker_ExposedUnderwear.cs" />
|
||||
<Compile Include="Scripts\Utilities\ApparelAnimationUtility.cs" />
|
||||
<Compile Include="Scripts\Utilities\ApparelSettingsUtility.cs" />
|
||||
<Compile Include="Scripts\Utilities\DebugMode.cs" />
|
||||
|
@ -149,7 +152,6 @@
|
|||
<Compile Include="Scripts\Settings\BasicSettings.cs" />
|
||||
<Compile Include="Scripts\Utilities\GraphicMaskingUtility.cs" />
|
||||
<Compile Include="Scripts\Utilities\MathUtility.cs" />
|
||||
<Compile Include="Scripts\Utilities\SexInteractionUtility.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
|
@ -32,6 +32,7 @@ namespace Rimworld_Animations_Patch
|
|||
Scribe_Values.Look(ref cellPosition, "cellPosition", default);
|
||||
}
|
||||
|
||||
// Used to find a place to have clothes thrown onto the floor
|
||||
public void GenerateFloorPosition(IntVec3 apparelCell, Vector2 apparelOffset = default)
|
||||
{
|
||||
Pawn pawn = apparel.Wearer;
|
||||
|
|
|
@ -16,12 +16,13 @@ namespace Rimworld_Animations_Patch
|
|||
public Graphic handGraphic = null;
|
||||
|
||||
public List<BodyPartRecord> hands = new List<BodyPartRecord>();
|
||||
public float sizeOfPenis = 0f;
|
||||
public float sizeOfBreasts = 0f;
|
||||
|
||||
public Dictionary<AlienPartGenerator.BodyAddon, BodyAddonData> bodyAddonData = new Dictionary<AlienPartGenerator.BodyAddon, BodyAddonData>();
|
||||
public Dictionary<AlienPartGenerator.BodyAddon, BodyAddonData> bodyAddonDataPortraits = new Dictionary<AlienPartGenerator.BodyAddon, BodyAddonData>();
|
||||
|
||||
private Pawn pawn;
|
||||
private int lastExclaimationTick = -1;
|
||||
private int exclaimationCoolDown = 90;
|
||||
|
||||
public BodyAddonData GetBodyAddonData(AlienPartGenerator.BodyAddon bodyAddon, bool isPortrait)
|
||||
{
|
||||
|
@ -62,25 +63,22 @@ namespace Rimworld_Animations_Patch
|
|||
{ kvp.Value?.UpdateVisibility(); }
|
||||
}
|
||||
|
||||
public void UpdateHands()
|
||||
public void UpdateBodyPartCountAndSize()
|
||||
{
|
||||
hands = pawn?.health?.hediffSet?.GetNotMissingParts()?.Where(x => x.def.tags.Contains(BodyPartTagDefOf.ManipulationLimbCore))?.ToList();
|
||||
|
||||
Hediff hediffPenis = pawn?.health?.hediffSet?.hediffs?.FirstOrDefault(x => x.def.defName.Contains("penis") == true || x.def.defName.Contains("Penis"));
|
||||
sizeOfPenis = hediffPenis != null ? hediffPenis.Severity : 0f;
|
||||
|
||||
Hediff hediffBreasts = pawn?.health?.hediffSet?.hediffs?.FirstOrDefault(x => x.def.defName.Contains("breasts") == true || x.def.defName.Contains("Breasts") == true);
|
||||
sizeOfBreasts = hediffBreasts != null ? hediffBreasts.Severity : 0f;
|
||||
}
|
||||
|
||||
public int GetNumberOfHands()
|
||||
{
|
||||
if (hands.NullOrEmpty()) return 0;
|
||||
if (hands.Any() == false) return 0;
|
||||
|
||||
return hands.Count;
|
||||
}
|
||||
|
||||
public void TryToExclaim()
|
||||
{
|
||||
if (Find.TickManager.TicksGame > exclaimationCoolDown + lastExclaimationTick)
|
||||
{
|
||||
lastExclaimationTick = Find.TickManager.TicksGame;
|
||||
FleckMaker.ThrowMetaIcon(pawn.Position, pawn.Map, FleckDefOf.IncapIcon);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
70
Source/Scripts/Defs/ActorAddon.cs
Normal file
70
Source/Scripts/Defs/ActorAddon.cs
Normal file
|
@ -0,0 +1,70 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Verse;
|
||||
|
||||
namespace Rimworld_Animations_Patch
|
||||
{
|
||||
public class ActorAddon
|
||||
{
|
||||
// Data to/from animationDef
|
||||
public string addonName;
|
||||
public int? anchoringActor;
|
||||
public string anchorName;
|
||||
public string layer = "Pawn";
|
||||
public GraphicData graphicData;
|
||||
public bool? render;
|
||||
|
||||
// Data helper functions
|
||||
public string AddonName
|
||||
{
|
||||
get { return addonName; }
|
||||
set { addonName = value; }
|
||||
}
|
||||
|
||||
public int AnchoringActor
|
||||
{
|
||||
get { return anchoringActor.HasValue ? anchoringActor.Value : 0; }
|
||||
set { anchoringActor = value; }
|
||||
}
|
||||
|
||||
public string AnchorName
|
||||
{
|
||||
get { return anchorName; }
|
||||
set { anchorName = value; }
|
||||
}
|
||||
|
||||
public string Layer
|
||||
{
|
||||
get { return layer; }
|
||||
set { layer = value; }
|
||||
}
|
||||
|
||||
public GraphicData GraphicData
|
||||
{
|
||||
get { return graphicData; }
|
||||
set { graphicData = value; }
|
||||
}
|
||||
|
||||
public bool Render
|
||||
{
|
||||
get { return render == true; }
|
||||
set { render = value; }
|
||||
}
|
||||
|
||||
// Simple curves
|
||||
public SimpleCurve PosX = new SimpleCurve();
|
||||
public SimpleCurve PosZ = new SimpleCurve();
|
||||
public SimpleCurve Rotation = new SimpleCurve();
|
||||
|
||||
// Constructors
|
||||
public ActorAddon() { }
|
||||
|
||||
public ActorAddon(ActorAddonDef actorAddonDef)
|
||||
{
|
||||
this.GraphicData = actorAddonDef.graphicData;
|
||||
}
|
||||
}
|
||||
}
|
15
Source/Scripts/Defs/ActorAddonDef.cs
Normal file
15
Source/Scripts/Defs/ActorAddonDef.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Verse;
|
||||
|
||||
namespace Rimworld_Animations_Patch
|
||||
{
|
||||
public class ActorAddonDef : Def
|
||||
{
|
||||
public float scale = 1f;
|
||||
public GraphicData graphicData;
|
||||
}
|
||||
}
|
|
@ -16,14 +16,16 @@ namespace Rimworld_Animations_Patch
|
|||
public int currentStage = 0;
|
||||
public int stageTicks = 0;
|
||||
public Rot4 actorFacing = Rot4.South;
|
||||
public bool isMirrored;
|
||||
|
||||
public ActorAnimationData(AnimationDef animationDef, int actorID, int currentStage, int stageTicks, Rot4 actorFacing)
|
||||
public ActorAnimationData(AnimationDef animationDef, int actorID, int currentStage, int stageTicks, Rot4 actorFacing, bool isMirrored)
|
||||
{
|
||||
this.animationDef = animationDef;
|
||||
this.actorID = actorID;
|
||||
this.currentStage = currentStage;
|
||||
this.stageTicks = stageTicks;
|
||||
this.actorFacing = actorFacing;
|
||||
this.isMirrored = isMirrored;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
56
Source/Scripts/Defs/AddonKeyFrame.cs
Normal file
56
Source/Scripts/Defs/AddonKeyFrame.cs
Normal file
|
@ -0,0 +1,56 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Rimworld_Animations_Patch
|
||||
{
|
||||
public class AddonKeyframe
|
||||
{
|
||||
// Data to/from animationDef
|
||||
public string addonName;
|
||||
public float? posX;
|
||||
public float? posZ;
|
||||
public float? rotation;
|
||||
|
||||
// Data serialization control
|
||||
public bool ShouldSerializeposX() { return posX.HasValue; }
|
||||
public bool ShouldSerializeposZ() { return posZ.HasValue; }
|
||||
public bool ShouldSerializerotation() { return rotation.HasValue; }
|
||||
|
||||
|
||||
// Data helper functions
|
||||
public string AddonName
|
||||
{
|
||||
get { return addonName; }
|
||||
set { addonName = value; }
|
||||
}
|
||||
|
||||
public float PosX
|
||||
{
|
||||
get { return posX.HasValue ? posX.Value : 0f; }
|
||||
set { posX = value; }
|
||||
}
|
||||
|
||||
public float PosZ
|
||||
{
|
||||
get { return posZ.HasValue ? posZ.Value : 0f; }
|
||||
set { posZ = value; }
|
||||
}
|
||||
|
||||
public float Rotation
|
||||
{
|
||||
get { return rotation.HasValue ? rotation.Value : 0f; }
|
||||
set { rotation = value; }
|
||||
}
|
||||
|
||||
// Constructors
|
||||
public AddonKeyframe() { }
|
||||
|
||||
public AddonKeyframe(string addonName)
|
||||
{
|
||||
this.AddonName = addonName;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@ namespace Rimworld_Animations_Patch
|
|||
public BodyPartRecord bodyPartRecord;
|
||||
public List<Vector3> bodyAddonOffsets = new List<Vector3>();
|
||||
public bool alignsWithHead = false;
|
||||
|
||||
|
||||
private Pawn pawn;
|
||||
private string bodyType;
|
||||
private PawnRenderFlags renderFlags;
|
||||
|
@ -31,7 +31,7 @@ namespace Rimworld_Animations_Patch
|
|||
if (isPortrait)
|
||||
{ renderFlags |= PawnRenderFlags.Portrait; }
|
||||
|
||||
bodyPartRecord = pawn.def?.race?.body?.AllParts?.FirstOrDefault(x => x.def.defName == bodyAddon?.bodyPart || x.customLabel == bodyAddon?.bodyPart);
|
||||
bodyPartRecord = pawn.def?.race?.body?.AllParts?.FirstOrDefault(x => x.def == bodyAddon?.bodyPart);
|
||||
alignsWithHead = bodyAddon.alignWithHead || (bodyPartRecord != null && bodyPartRecord.IsInGroup(BodyPartGroupDefOf.FullHead));
|
||||
|
||||
GenerateOffsets();
|
||||
|
@ -43,7 +43,7 @@ namespace Rimworld_Animations_Patch
|
|||
bodyType = pawn.story.bodyType.defName;
|
||||
bodyAddonOffsets.Clear();
|
||||
|
||||
int bodyAddonIndex = (pawn.def as ThingDef_AlienRace).alienRace.generalSettings.alienPartGenerator.bodyAddons.ToList().IndexOf(bodyAddon);
|
||||
int bodyAddonIndex = (pawn.def as ThingDef_AlienRace).alienRace.generalSettings.alienPartGenerator.bodyAddons.IndexOf(bodyAddon);
|
||||
AlienPartGenerator.AlienComp alienComp = pawn.GetComp<AlienPartGenerator.AlienComp>();
|
||||
Graphic addonGraphic = alienComp.addonGraphics[bodyAddonIndex];
|
||||
|
||||
|
@ -53,20 +53,20 @@ namespace Rimworld_Animations_Patch
|
|||
|
||||
// Get basic offset for body addon
|
||||
AlienPartGenerator.RotationOffset defaultOffsets = bodyAddon.defaultOffsets.GetOffset(apparentRotation);
|
||||
Vector3 bodyTypeOffset = (defaultOffsets != null) ? defaultOffsets.GetOffset(renderFlags.FlagSet(PawnRenderFlags.Portrait), pawn.story.bodyType, alienComp.crownType) : Vector3.zero;
|
||||
Vector3 bodyTypeOffset = (defaultOffsets != null) ? defaultOffsets.GetOffset(renderFlags.FlagSet(PawnRenderFlags.Portrait), pawn.story.bodyType, pawn.story.headType) : Vector3.zero;
|
||||
|
||||
AlienPartGenerator.RotationOffset rotationOffsets = bodyAddon.offsets.GetOffset(apparentRotation);
|
||||
Vector3 bodyAddonOffset = bodyTypeOffset + ((rotationOffsets != null) ? rotationOffsets.GetOffset(renderFlags.FlagSet(PawnRenderFlags.Portrait), pawn.story.bodyType, alienComp.crownType) : Vector3.zero);
|
||||
Vector3 bodyAddonOffset = bodyTypeOffset + ((rotationOffsets != null) ? rotationOffsets.GetOffset(renderFlags.FlagSet(PawnRenderFlags.Portrait), pawn.story.bodyType, pawn.story.headType) : Vector3.zero);
|
||||
|
||||
// Offset private parts so that they render over tattoos but under apparel (rendering under tatoos looks weird)
|
||||
if (bodyAddon.bodyPart == "Genitals" || bodyAddon.bodyPart == "Chest" || bodyAddon.bodyPart == "Anus" || addonGraphic.path.ToLower().Contains("belly"))
|
||||
if (bodyAddon.bodyPart == PatchBodyPartDefOf.Genitals || bodyAddon.bodyPart == PatchBodyPartDefOf.Chest || bodyAddon.bodyPart == PatchBodyPartDefOf.Anus || addonGraphic.path.Contains("belly") || addonGraphic.path.Contains("Belly"))
|
||||
{
|
||||
bodyAddonOffset.y = (bodyAddonOffset.y + 0.40f) / 1000f + 0.012f;
|
||||
|
||||
// Erected penises should be drawn over apparel
|
||||
if (pawn.RaceProps.Humanlike &&
|
||||
addonGraphic.path.ToLower().Contains("penis") &&
|
||||
addonGraphic.path.ToLower().Contains("flaccid") == false &&
|
||||
(addonGraphic.path.Contains("penis") || addonGraphic.path.Contains("Penis")) &&
|
||||
(addonGraphic.path.Contains("flaccid") == false && addonGraphic.path.Contains("Flaccid") == false) &&
|
||||
apparentRotation == Rot4.South)
|
||||
{ bodyAddonOffset.y += 0.010f; }
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ namespace Rimworld_Animations_Patch
|
|||
if (renderFlags.FlagSet(PawnRenderFlags.Portrait) == false && (pawn.GetPosture() == PawnPosture.LayingOnGroundNormal || pawn.GetPosture() == PawnPosture.LayingOnGroundFaceUp) && bodyAddon.drawnOnGround == false)
|
||||
{ return false; }
|
||||
|
||||
if (bodyAddon.backstoryRequirement.NullOrEmpty() == false && pawn.story?.AllBackstories?.Any((Backstory x) => x.identifier == bodyAddon.backstoryRequirement) == false)
|
||||
if (bodyAddon.backstoryRequirement != null && pawn.story?.AllBackstories?.Any((BackstoryDef x) => x == bodyAddon.backstoryRequirement) == false)
|
||||
{ return false; }
|
||||
|
||||
if (bodyAddon.drawnDesiccated == false && pawn.Corpse?.GetRotStage() == RotStage.Dessicated)
|
||||
|
@ -130,7 +130,7 @@ namespace Rimworld_Animations_Patch
|
|||
if (pawn.gender == Gender.Female && bodyAddon.drawForFemale == false || pawn.gender == Gender.Male && bodyAddon.drawForMale == false)
|
||||
{ return false; }
|
||||
|
||||
if (bodyAddon.bodyTypeRequirement.NullOrEmpty() == false && pawn.story?.bodyType.ToString() != bodyAddon.bodyTypeRequirement)
|
||||
if (bodyAddon.bodyTypeRequirement != null && pawn.story?.bodyType != bodyAddon.bodyTypeRequirement)
|
||||
{ return false; }
|
||||
|
||||
return true;
|
||||
|
@ -139,7 +139,6 @@ namespace Rimworld_Animations_Patch
|
|||
public void UpdateVisibility()
|
||||
{
|
||||
if (pawn == null || bodyAddon == null || bodyPartRecord == null) return;
|
||||
|
||||
canDraw = true;
|
||||
|
||||
if (pawn.health?.hediffSet?.GetNotMissingParts()?.Contains(bodyPartRecord) == false)
|
||||
|
@ -156,15 +155,18 @@ namespace Rimworld_Animations_Patch
|
|||
|
||||
if (comp.isBeingWorn == false) continue;
|
||||
|
||||
if (bodyAddon.bodyPart == "Genitals" || bodyAddon.bodyPart == "Anus" || bodyAddon.bodyPart == "Chest" || bodyAddon.hediffGraphics?.Any(x => x.path.NullOrEmpty() == false && x.path.ToLower().Contains("belly")) == true)
|
||||
if (bodyAddon.bodyPart == PatchBodyPartDefOf.Genitals ||
|
||||
bodyAddon.bodyPart == PatchBodyPartDefOf.Anus ||
|
||||
bodyAddon.bodyPart == PatchBodyPartDefOf.Chest ||
|
||||
bodyAddon.hediffGraphics?.Any(x => x.path.NullOrEmpty() == false && (x.path.Contains("belly") || x.path.Contains("Belly"))) == true)
|
||||
{
|
||||
if ((bodyAddon.bodyPart == "Genitals" || bodyAddon.bodyPart == "Anus") && comp.coversGroin)
|
||||
if ((bodyAddon.bodyPart == PatchBodyPartDefOf.Genitals || bodyAddon.bodyPart == PatchBodyPartDefOf.Anus) && comp.coversGroin)
|
||||
{ canDraw = false; return; };
|
||||
|
||||
if (bodyAddon.bodyPart == "Chest" && comp.coversChest)
|
||||
if (bodyAddon.bodyPart == PatchBodyPartDefOf.Chest && comp.coversChest)
|
||||
{ canDraw = false; return; };
|
||||
|
||||
if (bodyAddon.hediffGraphics?.Any(x => x.path.NullOrEmpty() == false && x.path.ToLower().Contains("belly")) == true && comp.coversBelly)
|
||||
if (bodyAddon.hediffGraphics?.Any(x => x.path.NullOrEmpty() == false && (x.path.Contains("belly") || x.path.Contains("Belly"))) == true && comp.coversBelly)
|
||||
{ canDraw = false; return; }
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using Verse;
|
||||
using Rimworld_Animations;
|
||||
|
||||
|
@ -8,8 +12,7 @@ namespace Rimworld_Animations_Patch
|
|||
{
|
||||
public class HandAnimationDef : Def
|
||||
{
|
||||
public string animationDefName;
|
||||
|
||||
public AnimationDef animationDef;
|
||||
public List<HandAnimationData> handAnimationData = new List<HandAnimationData>();
|
||||
}
|
||||
|
||||
|
@ -24,5 +27,23 @@ namespace Rimworld_Animations_Patch
|
|||
public string motion;
|
||||
public int cycleTime = 0;
|
||||
public bool mirror = false;
|
||||
|
||||
private HandMotion _motion;
|
||||
|
||||
public HandMotion Motion
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_motion == null)
|
||||
{
|
||||
if (Type.GetType(motion) == null)
|
||||
{ DebugMode.Message("ERROR: Hand motion " + motion + " does not exist!"); return null; }
|
||||
|
||||
_motion = (HandMotion)Activator.CreateInstance(Type.GetType(motion));
|
||||
}
|
||||
|
||||
return _motion;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
54
Source/Scripts/Extensions/PawnAnimationClipExt.cs
Normal file
54
Source/Scripts/Extensions/PawnAnimationClipExt.cs
Normal file
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Rimworld_Animations;
|
||||
|
||||
namespace Rimworld_Animations_Patch
|
||||
{
|
||||
public class PawnAnimationClipExt : PawnAnimationClip
|
||||
{
|
||||
public List<ActorAddon> addons = new List<ActorAddon>();
|
||||
|
||||
public override void buildSimpleCurves()
|
||||
{
|
||||
base.buildSimpleCurves();
|
||||
int keyframePosition = 0;
|
||||
|
||||
for (int i = 0; i < keyframes.Count; i++)
|
||||
{
|
||||
PawnKeyframeExt keyframe = keyframes[i] as PawnKeyframeExt;
|
||||
|
||||
|
||||
if (keyframe.atTick.HasValue)
|
||||
{
|
||||
foreach (ActorAddon addon in addons)
|
||||
{
|
||||
if (keyframe.addonKeyframes.Any(x => x.AddonName == addon.AddonName) == false)
|
||||
{ keyframe.addonKeyframes.Add(new AddonKeyframe(addon.AddonName)); }
|
||||
|
||||
addon.PosX.Add((float)keyframe.atTick / (float)duration, keyframe.GetAddonKeyframe(addon.AddonName).PosX, true);
|
||||
addon.PosZ.Add((float)keyframe.atTick / (float)duration, keyframe.GetAddonKeyframe(addon.AddonName).PosZ, true);
|
||||
addon.Rotation.Add((float)keyframe.atTick / (float)duration, keyframe.GetAddonKeyframe(addon.AddonName).Rotation, true);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
foreach (ActorAddon addon in addons)
|
||||
{
|
||||
if (keyframe.addonKeyframes.Any(x => x.AddonName == addon.AddonName) == false)
|
||||
{ keyframe.addonKeyframes.Add(new AddonKeyframe(addon.AddonName)); }
|
||||
|
||||
addon.PosX.Add((float)keyframePosition / (float)duration, keyframe.GetAddonKeyframe(addon.AddonName).PosX, true);
|
||||
addon.PosZ.Add((float)keyframePosition / (float)duration, keyframe.GetAddonKeyframe(addon.AddonName).PosZ, true);
|
||||
addon.Rotation.Add((float)keyframePosition / (float)duration, keyframe.GetAddonKeyframe(addon.AddonName).Rotation, true);
|
||||
}
|
||||
|
||||
keyframePosition += keyframe.tickDuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -85,14 +85,14 @@ namespace Rimworld_Animations_Patch
|
|||
|
||||
if (pawn.GetSexReceiver() != null)
|
||||
{
|
||||
List<Pawn> partners = (pawn.GetSexReceiver().jobs.curDriver as JobDriver_SexBaseReciever).parteners.ToList();
|
||||
List<Pawn> partners = (pawn.GetSexReceiver().jobs.curDriver as JobDriver_SexBaseReciever).parteners;
|
||||
|
||||
if (partners != null)
|
||||
{
|
||||
foreach (Pawn partner in partners)
|
||||
{
|
||||
if (partner != null)
|
||||
{ participants = partners; }
|
||||
{ participants = partners; break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,77 +111,6 @@ namespace Rimworld_Animations_Patch
|
|||
return participants;
|
||||
}
|
||||
|
||||
public static bool IsLoverOfOther(this Pawn pawn, Pawn other)
|
||||
{
|
||||
if (pawn == null || other == null)
|
||||
{ return false; }
|
||||
|
||||
List<DirectPawnRelation> lovers = SpouseRelationUtility.GetLoveRelations(pawn, false);
|
||||
return lovers.Any(x => x.otherPawn == other);
|
||||
}
|
||||
|
||||
public static bool HasPrivacy(this Pawn pawn, float radius)
|
||||
{
|
||||
if (pawn.AnimalOrWildMan() || pawn.RaceProps.Humanlike == false)
|
||||
{ return true; }
|
||||
|
||||
if (pawn.IsHavingSex() == false && pawn.IsMasturbating() == false)
|
||||
{ return true; }
|
||||
|
||||
if (pawn.GetLord() != null && pawn.GetLord().LordJob is LordJob_Ritual)
|
||||
{ return true; }
|
||||
|
||||
if (pawn.GetLord() != null && pawn.GetLord().LordJob is LordJob_Joinable_Party)
|
||||
{ return true; }
|
||||
|
||||
bool hasPrivacy = true;
|
||||
bool isExhibitionist = xxx.has_quirk(pawn, "Exhibitionist");
|
||||
|
||||
pawn.IsInBed(out Building bed);
|
||||
|
||||
foreach (Thing thing in GenRadial.RadialDistinctThingsAround(pawn.Position, pawn.Map, radius, true))
|
||||
{
|
||||
Pawn witness = thing as Pawn;
|
||||
|
||||
// Caught having sex
|
||||
if (SexInteractionUtility.PawnCaughtLovinByWitness(pawn, witness))
|
||||
{
|
||||
SexInteractionUtility.ResolveThoughtsForWhenSexIsWitnessed(pawn, witness, out bool witnessJoiningSex);
|
||||
|
||||
// Try to invite intruder to join in
|
||||
if (witnessJoiningSex)
|
||||
{
|
||||
if (pawn.IsMasturbating())
|
||||
{
|
||||
if (bed == null)
|
||||
{
|
||||
Job job = new Job(xxx.quick_sex, pawn);
|
||||
witness.jobs.TryTakeOrderedJob(job);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Job job = new Job(xxx.casual_sex, pawn, bed);
|
||||
witness.jobs.TryTakeOrderedJob(job);
|
||||
}
|
||||
}
|
||||
|
||||
else if (pawn.GetSexReceiver() != null)
|
||||
{
|
||||
Job job = new Job(DefDatabase<JobDef>.GetNamed("JoinInSex", false), pawn.GetSexReceiver(), bed);
|
||||
witness.jobs.TryTakeOrderedJob(job);
|
||||
}
|
||||
}
|
||||
|
||||
// The invitation failed
|
||||
else
|
||||
{ hasPrivacy = false; }
|
||||
}
|
||||
}
|
||||
|
||||
return hasPrivacy || isExhibitionist || BasicSettings.needPrivacy == false;
|
||||
}
|
||||
|
||||
public static ActorAnimationData GetAnimationData(this Pawn pawn)
|
||||
{
|
||||
if (pawn.TryGetComp<CompBodyAnimator>() == null) return null;
|
||||
|
@ -192,82 +121,9 @@ namespace Rimworld_Animations_Patch
|
|||
int currentStage = (int)AccessTools.Field(typeof(CompBodyAnimator), "curStage").GetValue(pawn.TryGetComp<CompBodyAnimator>());
|
||||
int stageTicks = (int)AccessTools.Field(typeof(CompBodyAnimator), "stageTicks").GetValue(pawn.TryGetComp<CompBodyAnimator>());
|
||||
Rot4 actorFacing = (Rot4)AccessTools.Field(typeof(CompBodyAnimator), "bodyFacing").GetValue(pawn.TryGetComp<CompBodyAnimator>());
|
||||
bool isMirrored = pawn.TryGetComp<CompBodyAnimator>().Mirror;
|
||||
|
||||
return new ActorAnimationData(animationDef, actorID, currentStage, stageTicks, actorFacing);
|
||||
}
|
||||
|
||||
public static List<BodyPartRecord> GetHands(this Pawn pawn)
|
||||
{
|
||||
return pawn.health.hediffSet.GetNotMissingParts().Where(x => x.def == PatchBodyPartDefOf.Hand)?.ToList();
|
||||
}
|
||||
|
||||
public static bool HasPreceptForIssue(this Pawn pawn, string issueDefName, out Precept precept)
|
||||
{
|
||||
precept = null;
|
||||
|
||||
if (pawn?.Ideo == null)
|
||||
{ return false; }
|
||||
|
||||
foreach (Precept _precept in pawn.Ideo.PreceptsListForReading)
|
||||
{
|
||||
if (_precept.def.issue.defName == issueDefName)
|
||||
{
|
||||
precept = _precept;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool EnjoysViolence(this Pawn pawn)
|
||||
{
|
||||
if (pawn.IsAnimal() || pawn.RaceProps.IsMechanoid)
|
||||
{ return true; }
|
||||
|
||||
if (pawn?.story?.traits?.allTraits == null || pawn?.story?.traits?.allTraits.NullOrEmpty() == true)
|
||||
{ return false; }
|
||||
|
||||
List<string> traits = new List<string>() { "Brawler", "Psychopath", "Bloodlust" };
|
||||
|
||||
return pawn.story.traits.allTraits.Any(x => traits.Contains(x.def.defName));
|
||||
}
|
||||
|
||||
public static bool DislikesViolence(this Pawn pawn)
|
||||
{
|
||||
if (pawn.IsAnimal() || pawn.RaceProps.IsMechanoid)
|
||||
{ return false; }
|
||||
|
||||
if (pawn?.story?.traits?.allTraits == null || pawn?.story?.traits?.allTraits.NullOrEmpty() == true)
|
||||
{ return false; }
|
||||
|
||||
List<string> traits = new List<string>() { "Kind", "Wimp" };
|
||||
|
||||
return pawn.WorkTagIsDisabled(WorkTags.Violent) || pawn.story.traits.allTraits.Any(x => traits.Contains(x.def.defName));
|
||||
}
|
||||
|
||||
public static bool HasTrait(this Pawn pawn, string trait)
|
||||
{
|
||||
if (pawn?.story?.traits?.allTraits == null || pawn.story.traits.allTraits.NullOrEmpty())
|
||||
{ return false; }
|
||||
|
||||
TraitDef traitDef = DefDatabase<TraitDef>.GetNamedSilentFail(trait);
|
||||
|
||||
if (traitDef == null)
|
||||
{ traitDef = DefDatabase<TraitDef>.GetNamedSilentFail(trait.ToLower()); }
|
||||
|
||||
return HasTrait(pawn, traitDef);
|
||||
}
|
||||
|
||||
public static bool HasTrait(this Pawn pawn, TraitDef traitDef)
|
||||
{
|
||||
if (pawn?.story?.traits?.allTraits == null || pawn.story.traits.allTraits.NullOrEmpty())
|
||||
{ return false; }
|
||||
|
||||
if (traitDef == null)
|
||||
{ return false; }
|
||||
|
||||
return pawn.story.traits.HasTrait(traitDef);
|
||||
return new ActorAnimationData(animationDef, actorID, currentStage, stageTicks, actorFacing, isMirrored);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
19
Source/Scripts/Extensions/PawnKeyframeExt.cs
Normal file
19
Source/Scripts/Extensions/PawnKeyframeExt.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_Animations;
|
||||
|
||||
namespace Rimworld_Animations_Patch
|
||||
{
|
||||
public class PawnKeyframeExt : PawnKeyframe
|
||||
{
|
||||
public List<AddonKeyframe> addonKeyframes;
|
||||
|
||||
public AddonKeyframe GetAddonKeyframe(string addonName)
|
||||
{
|
||||
return addonKeyframes.FirstOrDefault(x => x.AddonName == addonName);
|
||||
}
|
||||
}
|
||||
}
|
16
Source/Scripts/Extensions/StringExtension.cs
Normal file
16
Source/Scripts/Extensions/StringExtension.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Rimworld_Animations_Patch
|
||||
{
|
||||
public static class StringExtension
|
||||
{
|
||||
public static bool Contains(this string fullString, string subString, StringComparison comparer)
|
||||
{
|
||||
return fullString?.IndexOf(subString, comparer) >= 0;
|
||||
}
|
||||
}
|
||||
}
|
15
Source/Scripts/HandMotions/HandMotion.cs
Normal file
15
Source/Scripts/HandMotions/HandMotion.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
namespace Rimworld_Animations_Patch
|
||||
{
|
||||
public abstract class HandMotion
|
||||
{
|
||||
public abstract Vector3 GetHandPosition(Pawn pawn, HandAnimationData handAnimationData, float baseAngle);
|
||||
}
|
||||
}
|
33
Source/Scripts/HandMotions/RubBreasts_FacingEW.cs
Normal file
33
Source/Scripts/HandMotions/RubBreasts_FacingEW.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
namespace Rimworld_Animations_Patch
|
||||
{
|
||||
public class RubBreasts_FacingEW : HandMotion
|
||||
{
|
||||
public override Vector3 GetHandPosition(Pawn pawn, HandAnimationData handAnimationData, float baseAngle)
|
||||
{
|
||||
Vector3 handPosition = new Vector3();
|
||||
ActorAnimationData data = pawn.GetAnimationData();
|
||||
|
||||
float a = ((float)data.stageTicks % (float)handAnimationData.cycleTime) / (float)handAnimationData.cycleTime * 360f;
|
||||
float m = (data.actorFacing == Rot4.West ? 1f : -1f) * (handAnimationData.mirror ? -1f : 1f);
|
||||
float size = HandAnimationUtility.GetGenitalSize(pawn, "breasts");
|
||||
|
||||
handPosition.x = (Mathf.Sin(a / 180f * Mathf.PI) * 0.005f - size * 0.25f) * m;
|
||||
handPosition.z = Mathf.Cos(a / 180f * Mathf.PI) * 0.015f - size * 0.125f;
|
||||
|
||||
handPosition = handPosition.RotatedBy(baseAngle);
|
||||
|
||||
return handPosition;
|
||||
}
|
||||
}
|
||||
}
|
34
Source/Scripts/HandMotions/RubBreasts_FacingNS.cs
Normal file
34
Source/Scripts/HandMotions/RubBreasts_FacingNS.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
using Rimworld_Animations;
|
||||
|
||||
namespace Rimworld_Animations_Patch
|
||||
{
|
||||
public class RubBreasts_FacingNS : HandMotion
|
||||
{
|
||||
public override Vector3 GetHandPosition(Pawn pawn, HandAnimationData handAnimationData, float baseAngle)
|
||||
{
|
||||
Vector3 handPosition = new Vector3();
|
||||
ActorAnimationData data = pawn.GetAnimationData();
|
||||
|
||||
float a = ((float)data.stageTicks % (float)handAnimationData.cycleTime) / (float)handAnimationData.cycleTime * 360f;
|
||||
float m = (data.actorFacing == Rot4.North ? -1f : 1f) * (handAnimationData.mirror ? -1f : 1f) * (data.isMirrored ? -1f : 1f);
|
||||
float size = HandAnimationUtility.GetGenitalSize(pawn, "breasts");
|
||||
|
||||
handPosition.x = (Mathf.Sin(a / 180f * Mathf.PI) * 0.05f * size - size * 0.25f) * m;
|
||||
handPosition.z = Mathf.Cos(a / 180f * Mathf.PI) * 0.015f - size * 0.125f;
|
||||
|
||||
handPosition = handPosition.RotatedBy(baseAngle);
|
||||
|
||||
return handPosition;
|
||||
}
|
||||
}
|
||||
}
|
34
Source/Scripts/HandMotions/RubGenitals_FacingEW.cs
Normal file
34
Source/Scripts/HandMotions/RubGenitals_FacingEW.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
using Rimworld_Animations;
|
||||
|
||||
namespace Rimworld_Animations_Patch
|
||||
{
|
||||
public class RubGenitals_FacingEW : HandMotion
|
||||
{
|
||||
public override Vector3 GetHandPosition(Pawn pawn, HandAnimationData handAnimationData, float baseAngle)
|
||||
{
|
||||
Vector3 handPosition = new Vector3();
|
||||
ActorAnimationData data = pawn.GetAnimationData();
|
||||
|
||||
float a = ((float)data.stageTicks % (float)handAnimationData.cycleTime) / (float)handAnimationData.cycleTime * 360f;
|
||||
float m = (data.actorFacing == Rot4.West ? 1f : -1f) * (handAnimationData.mirror ? -1f : 1f);
|
||||
|
||||
handPosition.x = (Mathf.Sin(a / 180f * Mathf.PI) * 0.005f - 0.05f) * m;
|
||||
handPosition.z = Mathf.Cos(a / 180f * Mathf.PI) * 0.015f;
|
||||
//handPosition.y = -0.1f;
|
||||
|
||||
handPosition = handPosition.RotatedBy(baseAngle);
|
||||
|
||||
return handPosition;
|
||||
}
|
||||
}
|
||||
}
|
33
Source/Scripts/HandMotions/RubGenitals_FacingNS.cs
Normal file
33
Source/Scripts/HandMotions/RubGenitals_FacingNS.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
using Rimworld_Animations;
|
||||
|
||||
namespace Rimworld_Animations_Patch
|
||||
{
|
||||
public class RubGenitals_FacingNS : HandMotion
|
||||
{
|
||||
public override Vector3 GetHandPosition(Pawn pawn, HandAnimationData handAnimationData, float baseAngle)
|
||||
{
|
||||
Vector3 handPosition = new Vector3();
|
||||
ActorAnimationData data = pawn.GetAnimationData();
|
||||
|
||||
float a = ((float)data.stageTicks % (float)handAnimationData.cycleTime) / (float)handAnimationData.cycleTime * 360f;
|
||||
float m = (data.actorFacing == Rot4.North ? 1f : -1f) * (handAnimationData.mirror ? -1f : 1f) * (data.isMirrored ? -1f : 1f);
|
||||
|
||||
handPosition.x = (Mathf.Sin(a / 180f * Mathf.PI) * 0.05f - 0.025f) * m;
|
||||
handPosition.z = Mathf.Cos(a / 180f * Mathf.PI) * 0.015f + 0.03f;
|
||||
|
||||
handPosition = handPosition.RotatedBy(baseAngle);
|
||||
|
||||
return handPosition;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
using RimWorld;
|
||||
|
||||
namespace Rimworld_Animations_Patch
|
||||
{
|
||||
public class StrokeGenitalsUpAndDownShort_FacingNS : HandMotion
|
||||
{
|
||||
public override Vector3 GetHandPosition(Pawn pawn, HandAnimationData handAnimationData, float baseAngle)
|
||||
{
|
||||
Vector3 handPosition = new Vector3();
|
||||
ActorAnimationData data = pawn.GetAnimationData();
|
||||
|
||||
float p = (Mathf.PingPong(data.stageTicks, handAnimationData.cycleTime) / handAnimationData.cycleTime);
|
||||
float length = 0.035f;
|
||||
|
||||
handPosition.x = 0;
|
||||
handPosition.z = length * p;
|
||||
|
||||
handPosition = handPosition.RotatedBy(baseAngle);
|
||||
|
||||
return handPosition;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
namespace Rimworld_Animations_Patch
|
||||
{
|
||||
public class StrokeGenitalsUpAndDown_FacingEW : HandMotion
|
||||
{
|
||||
public override Vector3 GetHandPosition(Pawn pawn, HandAnimationData handAnimationData, float baseAngle)
|
||||
{
|
||||
Vector3 handPosition = new Vector3();
|
||||
ActorAnimationData data = pawn.GetAnimationData();
|
||||
|
||||
float p = Mathf.PingPong(data.stageTicks, handAnimationData.cycleTime) / handAnimationData.cycleTime;
|
||||
float size = HandAnimationUtility.GetGenitalSize(pawn, handAnimationData.targetBodyPart) * 0.2f;
|
||||
float m = (data.actorFacing == Rot4.West ? -1f : 1f) * (handAnimationData.mirror ? -1f : 1f);
|
||||
|
||||
handPosition.x = Mathf.Sin(m * (baseAngle + 45f) / 180f * Mathf.PI) * size * p;
|
||||
handPosition.z = Mathf.Cos(m * (baseAngle + 45f) / 180f * Mathf.PI) * size * p;
|
||||
|
||||
return handPosition;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
namespace Rimworld_Animations_Patch
|
||||
{
|
||||
public class Motion_StrokeGenitalsUpAndDown_FacingNS : HandMotion
|
||||
{
|
||||
public override Vector3 GetHandPosition(Pawn pawn, HandAnimationData handAnimationData, float baseAngle)
|
||||
{
|
||||
Vector3 handPosition = new Vector3();
|
||||
ActorAnimationData data = pawn.GetAnimationData();
|
||||
|
||||
float p = (Mathf.PingPong(data.stageTicks, handAnimationData.cycleTime) / handAnimationData.cycleTime);
|
||||
float size = HandAnimationUtility.GetGenitalSize(pawn, handAnimationData.targetBodyPart) * 0.2f;
|
||||
float m = (data.actorFacing == Rot4.North ? -1f : 1f) * (handAnimationData.mirror ? -1f : 1f) * (data.isMirrored ? -1f : 1f);
|
||||
|
||||
handPosition.x = 0.025f * m;
|
||||
handPosition.z = size * p;
|
||||
|
||||
handPosition = handPosition.RotatedBy(baseAngle);
|
||||
|
||||
return handPosition;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,8 +15,6 @@ namespace Rimworld_Animations_Patch
|
|||
public static bool cropApparel = false;
|
||||
public static bool clothesThrownOnGround = true;
|
||||
public static RJWPreferenceSettings.Clothing apparelWornForQuickies = RJWPreferenceSettings.Clothing.Clothed;
|
||||
public static bool underwearSufficentForIdeos = true;
|
||||
public static bool exposedUnderwearMood = true;
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
|
@ -25,8 +23,6 @@ namespace Rimworld_Animations_Patch
|
|||
Scribe_Values.Look(ref cropApparel, "cropApparel", false);
|
||||
Scribe_Values.Look(ref clothesThrownOnGround, "clothesThrownOnGround", true);
|
||||
Scribe_Values.Look(ref apparelWornForQuickies, "apparelWornForQuickies", RJWPreferenceSettings.Clothing.Clothed);
|
||||
Scribe_Values.Look(ref underwearSufficentForIdeos, "underwearSufficentForIdeos", true);
|
||||
Scribe_Values.Look(ref underwearSufficentForIdeos, "exposedUnderwearMood", true);
|
||||
}
|
||||
|
||||
public static RimNudeData GetRimNudeData(Apparel apparel)
|
||||
|
@ -46,8 +42,8 @@ namespace Rimworld_Animations_Patch
|
|||
|
||||
public class ApparelSettingsDisplay : Mod
|
||||
{
|
||||
private const float windowY = 280f;
|
||||
private const float windowHeight = 330f;
|
||||
private const float windowY = 290f;
|
||||
private const float windowHeight = 320f;
|
||||
|
||||
private Vector2 scrollPosition;
|
||||
private const float scrollBarWidthMargin = 18f;
|
||||
|
@ -66,7 +62,11 @@ namespace Rimworld_Animations_Patch
|
|||
private const float singleColumnWidth = 100f;
|
||||
private const float doubleColumnWidth = 180f;
|
||||
|
||||
private static List<ThingDef> thingDefs = new List<ThingDef>();
|
||||
private IEnumerable<ThingDef> shortListedApparelDefs = new List<ThingDef>();
|
||||
private IEnumerable<ThingDef> allApparelDefs = new List<ThingDef>();
|
||||
|
||||
private IEnumerable<ModContentPack> relevantModContentPacks = new List<ModContentPack>();
|
||||
private ModContentPack currentModContentPack;
|
||||
|
||||
public ApparelSettingsDisplay(ModContentPack content) : base(content)
|
||||
{
|
||||
|
@ -146,8 +146,6 @@ namespace Rimworld_Animations_Patch
|
|||
|
||||
listingStandard.CheckboxLabeled("clothes_thrown_on_ground".Translate(), ref ApparelSettings.clothesThrownOnGround, "clothes_thrown_on_ground_desc".Translate());
|
||||
listingStandard.CheckboxLabeled("crop_apparel".Translate(), ref ApparelSettings.cropApparel, "crop_apparel_desc".Translate());
|
||||
listingStandard.CheckboxLabeled("underwear_sufficent_for_ideos".Translate(), ref ApparelSettings.underwearSufficentForIdeos, "underwear_sufficent_for_ideos_desc".Translate());
|
||||
listingStandard.CheckboxLabeled("exposed_underwear_mood".Translate(), ref ApparelSettings.exposedUnderwearMood, "exposed_underwear_mood_desc".Translate());
|
||||
|
||||
listingStandard.End();
|
||||
base.DoSettingsWindowContents(inRect);
|
||||
|
@ -162,9 +160,20 @@ namespace Rimworld_Animations_Patch
|
|||
|
||||
bool isEnabled = false;
|
||||
|
||||
// Get a list of apparel of interest
|
||||
if (thingDefs.NullOrEmpty())
|
||||
{ thingDefs = ApparelSettingsUtility.GetApparelOfInterest(); }
|
||||
// Get a list of apparel and mods of interest
|
||||
if (allApparelDefs.Any() == false)
|
||||
{
|
||||
allApparelDefs = ApparelSettingsUtility.GetApparelOfInterest();
|
||||
|
||||
foreach (ThingDef thingDef in allApparelDefs)
|
||||
{
|
||||
if (relevantModContentPacks.Contains(thingDef.modContentPack) == false)
|
||||
{ relevantModContentPacks.Append(thingDef.modContentPack); }
|
||||
}
|
||||
|
||||
currentModContentPack = relevantModContentPacks.First();
|
||||
shortListedApparelDefs = allApparelDefs.Where(x => x.modContentPack == currentModContentPack);
|
||||
}
|
||||
|
||||
// Ensure that all apparel has associated RimNudeData
|
||||
if (ApparelSettings.rimNudeData.NullOrEmpty())
|
||||
|
@ -173,6 +182,28 @@ namespace Rimworld_Animations_Patch
|
|||
// Add buttons to the top of the main window
|
||||
innerX = halfColumnWidth;
|
||||
|
||||
// Mod selection button
|
||||
if (Widgets.ButtonText(new Rect(innerX + SettingsUtility.Align(labelWidth, doubleColumnWidth), windowY - 2 * headerHeight - 5, 2 * doubleColumnWidth + 10, headerHeight), currentModContentPack.Name))
|
||||
{
|
||||
List<FloatMenuOption> options = new List<FloatMenuOption> { };
|
||||
|
||||
foreach (ModContentPack modContentPack in relevantModContentPacks)
|
||||
{
|
||||
FloatMenuOption option = new FloatMenuOption(modContentPack.Name, delegate ()
|
||||
{
|
||||
currentModContentPack = modContentPack;
|
||||
shortListedApparelDefs = allApparelDefs.Where(x => x.modContentPack == currentModContentPack);
|
||||
},
|
||||
MenuOptionPriority.Default, null, null, 0f, null, null, true, 0);
|
||||
|
||||
options.Add(option);
|
||||
}
|
||||
|
||||
Find.WindowStack.Add(new FloatMenu(options));
|
||||
}
|
||||
|
||||
if (shortListedApparelDefs.Any() == false) return;
|
||||
|
||||
// Apparel
|
||||
tempRect = new Rect(innerX + SettingsUtility.Align(labelWidth, doubleColumnWidth), windowY - headerHeight - 5, labelWidth, headerHeight);
|
||||
Widgets.DrawHighlightIfMouseover(tempRect);
|
||||
|
@ -183,10 +214,10 @@ namespace Rimworld_Animations_Patch
|
|||
List<FloatMenuOption> options = new List<FloatMenuOption>
|
||||
{
|
||||
new FloatMenuOption("Sort by name", delegate()
|
||||
{ thingDefs = thingDefs.OrderBy(x => x.label).ToList();
|
||||
{ shortListedApparelDefs = shortListedApparelDefs.OrderBy(x => x.label);
|
||||
}, MenuOptionPriority.Default, null, null, 0f, null, null, true, 0),
|
||||
new FloatMenuOption("Sort by mod", delegate()
|
||||
{ thingDefs = ApparelSettingsUtility.GetApparelOfInterest();
|
||||
{ shortListedApparelDefs = ApparelSettingsUtility.GetApparelOfInterest();
|
||||
}, MenuOptionPriority.Default, null, null, 0f, null, null, true, 0),
|
||||
}; Find.WindowStack.Add(new FloatMenu(options));
|
||||
}; innerX += doubleColumnWidth;
|
||||
|
@ -272,7 +303,7 @@ namespace Rimworld_Animations_Patch
|
|||
{ ApparelSettingsUtility.ResetRimNudeData(ApparelSettings.rimNudeData); }; innerX += singleColumnWidth + scrollBarWidthMargin;
|
||||
|
||||
// Determine the height of the scrollable area
|
||||
int apparelCount = thingDefs.Count;
|
||||
int apparelCount = shortListedApparelDefs.Count();
|
||||
float totalContentHeight = rowHeight * (float)apparelCount;
|
||||
|
||||
// Create a rect for the scroll window
|
||||
|
@ -288,7 +319,7 @@ namespace Rimworld_Animations_Patch
|
|||
Widgets.DrawHighlight(contentRect);
|
||||
Widgets.BeginScrollView(contentRect, ref scrollPosition, scrollViewTotal);
|
||||
|
||||
foreach (ThingDef thingDef in thingDefs)
|
||||
foreach (ThingDef thingDef in shortListedApparelDefs)
|
||||
{
|
||||
isEnabled = false;
|
||||
|
||||
|
|
|
@ -9,23 +9,12 @@ namespace Rimworld_Animations_Patch
|
|||
{
|
||||
public class BasicSettings : ModSettings
|
||||
{
|
||||
public static bool autoscaleDeltaPos = true;
|
||||
|
||||
public static bool linkChanges = false;
|
||||
public static bool needPrivacy = true;
|
||||
public static float chanceForOtherToJoinInSex = 0.25f;
|
||||
public static bool autoscaleDeltaPos = true;
|
||||
public static bool hideNamesForSex = false;
|
||||
public static bool debugMode = false;
|
||||
public static bool showHands = true;
|
||||
public static bool redrawHair = true;
|
||||
|
||||
public static bool worryAboutInfidelity = true;
|
||||
public static bool worryAboutBeastiality = true;
|
||||
public static bool worryAboutRape = true;
|
||||
public static bool worryAboutNecro = true;
|
||||
public static bool worryAboutXeno = true;
|
||||
public static bool ignoreSlaveRape = false;
|
||||
public static bool majorTabooCanStartFights = false;
|
||||
public static bool useLegacyAnimationSystem = false;
|
||||
|
||||
public static float genitalMasturbationChance = 1.0f;
|
||||
public static float analMasturbationChance = 0.25f;
|
||||
|
@ -40,21 +29,10 @@ namespace Rimworld_Animations_Patch
|
|||
base.ExposeData();
|
||||
|
||||
Scribe_Values.Look(ref autoscaleDeltaPos, "autoscaleDeltaPos", true);
|
||||
Scribe_Values.Look(ref linkChanges, "linkChanges", false);
|
||||
Scribe_Values.Look(ref needPrivacy, "needPrivacy", true);
|
||||
Scribe_Values.Look(ref chanceForOtherToJoinInSex, "chanceForSexExtra", 0.25f);
|
||||
Scribe_Values.Look(ref hideNamesForSex, "hideNamesForSex", false);
|
||||
Scribe_Values.Look(ref debugMode, "debugMode", false);
|
||||
Scribe_Values.Look(ref showHands, "showHands", true);
|
||||
Scribe_Values.Look(ref redrawHair, "redrawHair", true);
|
||||
Scribe_Values.Look(ref worryAboutInfidelity, "worryAboutInfidelity", true);
|
||||
Scribe_Values.Look(ref worryAboutBeastiality, "worryAboutBeastiality", true);
|
||||
Scribe_Values.Look(ref worryAboutRape, "worryAboutRape", true);
|
||||
Scribe_Values.Look(ref worryAboutNecro, "worryAboutNecro", true);
|
||||
Scribe_Values.Look(ref worryAboutXeno, "worryAboutXeno", true);
|
||||
Scribe_Values.Look(ref ignoreSlaveRape, "ignoreSlaveRape", false);
|
||||
Scribe_Values.Look(ref majorTabooCanStartFights, "majorTabooCanStartFights", false);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,23 +76,6 @@ namespace Rimworld_Animations_Patch
|
|||
listingStandard.Label("rimworld_animation_patch_general".Translate());
|
||||
listingStandard.Gap(5f);
|
||||
|
||||
listingStandard.CheckboxLabeled("need_privacy".Translate(), ref BasicSettings.needPrivacy, "need_privacy_desc".Translate());
|
||||
listingStandard.CheckboxLabeled("worry_about_infidelity".Translate(), ref BasicSettings.worryAboutInfidelity, "worry_about_infidelity_desc".Translate());
|
||||
listingStandard.CheckboxLabeled("worry_about_beastiality".Translate(), ref BasicSettings.worryAboutBeastiality, "worry_about_beastiality_desc".Translate());
|
||||
listingStandard.CheckboxLabeled("worry_about_rape".Translate(), ref BasicSettings.worryAboutRape, "worry_about_rape_desc".Translate());
|
||||
|
||||
if (BasicSettings.worryAboutRape)
|
||||
{
|
||||
listingStandard.CheckboxLabeled("ignore_slave_rape".Translate(), ref BasicSettings.ignoreSlaveRape);
|
||||
}
|
||||
|
||||
listingStandard.CheckboxLabeled("worry_about_necro".Translate(), ref BasicSettings.worryAboutNecro, "worry_about_necro_desc".Translate());
|
||||
listingStandard.CheckboxLabeled("worry_about_xeno".Translate(), ref BasicSettings.worryAboutXeno, "worry_about_xeno_desc".Translate());
|
||||
listingStandard.CheckboxLabeled("major_taboo_can_start_fights".Translate(), ref BasicSettings.majorTabooCanStartFights, "major_taboo_can_start_fights_desc".Translate());
|
||||
|
||||
listingStandard.Label("chance_for_other_to_join_in_sex".Translate() + ": " + BasicSettings.chanceForOtherToJoinInSex.ToString("F"), -1f, "chance_for_other_to_join_in_sex_desc".Translate());
|
||||
BasicSettings.chanceForOtherToJoinInSex = listingStandard.Slider(BasicSettings.chanceForOtherToJoinInSex, 0f, 1f);
|
||||
|
||||
//listingStandard.Label("test slide: " + BasicSettings.sliderValue.ToString("F"), -1f);
|
||||
//BasicSettings.sliderValue = listingStandard.Slider(BasicSettings.sliderValue, -2f, 2f);
|
||||
|
||||
|
@ -125,10 +86,11 @@ namespace Rimworld_Animations_Patch
|
|||
listingStandard.Label("rimworld_animation_patch_animation".Translate());
|
||||
listingStandard.Gap(5f);
|
||||
|
||||
listingStandard.CheckboxLabeled("autoscale_delta_pos".Translate(), ref BasicSettings.autoscaleDeltaPos, "autoscale_delta_pos_desc".Translate());
|
||||
listingStandard.CheckboxLabeled("show_hands".Translate(), ref BasicSettings.showHands, "show_hands_desc".Translate());
|
||||
listingStandard.CheckboxLabeled("autoscale_delta_pos".Translate(), ref BasicSettings.autoscaleDeltaPos, "autoscale_delta_pos_desc".Translate());
|
||||
listingStandard.CheckboxLabeled("redraw_hair".Translate(), ref BasicSettings.redrawHair, "redraw_hair_desc".Translate());
|
||||
|
||||
listingStandard.CheckboxLabeled("show_hands".Translate(), ref BasicSettings.showHands, "show_hands_desc".Translate());
|
||||
|
||||
listingStandard.End();
|
||||
base.DoSettingsWindowContents(inRect);
|
||||
}
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
using System;
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
using rjw;
|
||||
|
||||
namespace Rimworld_Animations_Patch
|
||||
{
|
||||
public class ThoughtWorker_ExposedUnderwear : ThoughtWorker
|
||||
{
|
||||
public static ThoughtState CurrentThoughtState(Pawn pawn)
|
||||
{
|
||||
if (xxx.has_quirk(pawn, "Exhibitionist"))
|
||||
{
|
||||
return ThoughtState.ActiveAtStage(1);
|
||||
}
|
||||
|
||||
return ThoughtState.ActiveAtStage(0);
|
||||
}
|
||||
|
||||
protected override ThoughtState CurrentStateInternal(Pawn pawn)
|
||||
{
|
||||
if (ApparelSettings.exposedUnderwearMood == false) return false;
|
||||
|
||||
if (pawn?.apparel?.WornApparel == null || pawn.apparel.WornApparel.NullOrEmpty()) return false;
|
||||
|
||||
if (pawn.apparel.WornApparel.Any(x => x.def.apparel.bodyPartGroups.Contains(PatchBodyPartGroupDefOf.GenitalsBPG)) &&
|
||||
pawn.apparel.WornApparel.Any(x => x.def.apparel.bodyPartGroups.Contains(BodyPartGroupDefOf.Legs)) == false)
|
||||
{ return CurrentThoughtState(pawn); }
|
||||
|
||||
if (pawn.apparel.WornApparel.Any(x => x.def.apparel.bodyPartGroups.Contains(PatchBodyPartGroupDefOf.ChestBPG)) &&
|
||||
pawn.apparel.WornApparel.Any(x => x.def.apparel.bodyPartGroups.Contains(BodyPartGroupDefOf.Torso)) == false)
|
||||
{ return CurrentThoughtState(pawn); }
|
||||
|
||||
return ThoughtState.Inactive;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -60,7 +60,7 @@ namespace Rimworld_Animations_Patch
|
|||
if (orgasmTick > ticks)
|
||||
{
|
||||
// Safeguard for penial, vaginal and anal sex
|
||||
if (anim.actors[actorId].isFucked || anim.actors[actorId].isFucking || (anim.actors[actorId].requiredGenitals.NullOrEmpty() == false && anim.actors[actorId].requiredGenitals.Any(x => x.ToLower().ContainsAny("penis", "vagina", "anus"))))
|
||||
if (anim.actors[actorId].isFucked || anim.actors[actorId].isFucking || (anim.actors[actorId].requiredGenitals.NullOrEmpty() == false && anim.actors[actorId].requiredGenitals.Any(x => x.ContainsAny("penis", "vagina", "anus", "Penis", "Vagina", "Anus"))))
|
||||
{ orgasmTick = Mathf.Clamp(ticks - 5, 0, int.MaxValue); }
|
||||
|
||||
// Actor does not orgasm
|
||||
|
@ -187,16 +187,17 @@ namespace Rimworld_Animations_Patch
|
|||
{
|
||||
{ "Alien_Orassan", new Vector3(1.4f, 1.4f, 1.4f) },
|
||||
{ "Alien_Cutebold", new Vector3(1.2f, 1f, 1f) },
|
||||
{ "Rabbie", new Vector3(-0.5f, 1f, 1f) },
|
||||
};
|
||||
|
||||
public static Vector2 GetRaceSpecificOffsetMultipliers(Pawn pawn, string bodypart)
|
||||
public static Vector2 GetRaceSpecificOffsetMultipliers(Pawn pawn, BodyPartDef bodypart)
|
||||
{
|
||||
Vector2 multiplierVector = new Vector2();
|
||||
|
||||
if (GetBodySize(pawn) == 1f || raceSpecifocChildMultipliers.TryGetValue(pawn.def.defName, out Vector3 raceVector) == false)
|
||||
{ raceVector = new Vector3(1f, 1f, 1f); }
|
||||
|
||||
if (bodypart?.ToLower() == "tail")
|
||||
if (bodypart?.defName == "tail" || bodypart?.defName == "Tail")
|
||||
{
|
||||
multiplierVector.x = raceVector.z;
|
||||
multiplierVector.y = raceVector.x;
|
||||
|
|
|
@ -153,7 +153,7 @@ namespace Rimworld_Animations_Patch
|
|||
{ bodyPartCovered = bodyPartCovered || PrivatePartCoveredByApparel(apparel, "Chest"); }
|
||||
|
||||
if (requiredGenitals.Contains("Mouth"))
|
||||
{ bodyPartCovered = bodyPartCovered || apparel.def.apparel.CoversBodyPart(bodyParts.FirstOrDefault(x => x.def.defName.ToLower().ContainsAny("mouth", "teeth", "jaw", "beak"))); }
|
||||
{ bodyPartCovered = bodyPartCovered || apparel.def.apparel.CoversBodyPart(bodyParts.FirstOrDefault(x => x.def.defName.ContainsAny("mouth", "teeth", "jaw", "beak", "Mouth", "Teeth", "Jaw", "Beak"))); }
|
||||
|
||||
return bodyPartCovered;
|
||||
}
|
||||
|
|
|
@ -13,27 +13,21 @@ namespace Rimworld_Animations_Patch
|
|||
{
|
||||
public static BodyPartDef handDef;
|
||||
|
||||
public static bool BodyPartIsBeingTouched(Pawn pawn, string bodypartFilePath, out List<HandAnimationData> handAnimationData)
|
||||
public static bool BodyPartIsBeingTouched(Pawn pawn, ActorAnimationData actorAnimationData, string bodypartFilePath, out List<HandAnimationData> handAnimationData)
|
||||
{
|
||||
handAnimationData = new List<HandAnimationData>();
|
||||
HandAnimationDef handAnimationDef = pawn?.TryGetComp<CompPawnSexData>()?.handAnimationDef;
|
||||
ActorAnimationData actorAnimationData = pawn?.GetAnimationData();
|
||||
|
||||
if (handAnimationDef == null || actorAnimationData == null || bodypartFilePath.NullOrEmpty())
|
||||
{ return false; }
|
||||
|
||||
foreach (HandAnimationData datum in handAnimationDef.handAnimationData)
|
||||
{
|
||||
if (datum.stageID != actorAnimationData.currentStage || datum.actorID != actorAnimationData.actorID)
|
||||
{ continue; }
|
||||
if (datum.stageID != actorAnimationData.currentStage || datum.actorID != actorAnimationData.actorID) continue;
|
||||
if (datum.bodySide.NullOrEmpty() == false && bodypartFilePath.Contains(datum.bodySide, StringComparison.OrdinalIgnoreCase) == false) continue;
|
||||
|
||||
if (datum.bodySide.NullOrEmpty() == false && bodypartFilePath.ToLower().Contains(datum.bodySide) == false)
|
||||
{ continue; }
|
||||
|
||||
if (datum.targetBodyPart.NullOrEmpty() == false && bodypartFilePath.ToLower().Contains(datum.targetBodyPart.ToLower()))
|
||||
{ handAnimationData.Add(datum); }
|
||||
|
||||
else if (datum.targetBodyParts.Any(x => bodypartFilePath.ToLower().Contains(x.ToLower())))
|
||||
if ((datum.targetBodyPart.NullOrEmpty() == false && bodypartFilePath.Contains(datum.targetBodyPart, StringComparison.OrdinalIgnoreCase)) ||
|
||||
datum.targetBodyParts.Any(x => bodypartFilePath.Contains(x, StringComparison.OrdinalIgnoreCase)))
|
||||
{ handAnimationData.Add(datum); }
|
||||
}
|
||||
|
||||
|
@ -42,147 +36,26 @@ namespace Rimworld_Animations_Patch
|
|||
|
||||
public static Vector3 GetHandPosition(Pawn pawn, HandAnimationData handAnimationData, Vector3 basePosition, float baseAngle)
|
||||
{
|
||||
var methodInfo = AccessTools.Method(typeof(HandAnimationUtility), handAnimationData.motion, null, null);
|
||||
|
||||
if (methodInfo == null)
|
||||
{
|
||||
Debug.LogWarning("Hand animation motion '" + handAnimationData.motion + "' was not found");
|
||||
return default;
|
||||
}
|
||||
|
||||
Vector3 handPosition = (Vector3)methodInfo.Invoke(null, new object[] { pawn, handAnimationData, baseAngle });
|
||||
|
||||
Vector3 handPosition = handAnimationData.Motion.GetHandPosition(pawn, handAnimationData, baseAngle);
|
||||
return handPosition * pawn.RaceProps.baseBodySize + basePosition + new Vector3(0f, 0.3f, 0f);
|
||||
}
|
||||
|
||||
public static float GetGenitalSize(Pawn pawn, string genitalName)
|
||||
{
|
||||
switch(genitalName.ToLower())
|
||||
CompPawnSexData data = pawn?.TryGetComp<CompPawnSexData>();
|
||||
if (data == null) return 0f;
|
||||
|
||||
switch (genitalName)
|
||||
{
|
||||
case "penis": return pawn.health.hediffSet.hediffs.First(x => x.def.defName.ToLower().Contains("penis")).Severity;
|
||||
case "breasts": return pawn.health.hediffSet.hediffs.First(x => x.def.defName.ToLower().Contains("breasts")).Severity;
|
||||
case "vagina": return 0.1f;
|
||||
case "anus": return 0.1f;
|
||||
case "penis": return data.sizeOfPenis;
|
||||
case "breasts": return data.sizeOfBreasts;
|
||||
case "Penis": return data.sizeOfPenis;
|
||||
case "Breasts": return data.sizeOfBreasts;
|
||||
}
|
||||
|
||||
return 0.1f;
|
||||
}
|
||||
|
||||
public static Vector3 Motion_StrokeGenitalsUpAndDownShort_FacingNS(Pawn pawn, HandAnimationData handAnimationData, float baseAngle)
|
||||
{
|
||||
Vector3 handPosition = new Vector3();
|
||||
ActorAnimationData data = pawn.GetAnimationData();
|
||||
|
||||
float p = (Mathf.PingPong(data.stageTicks, handAnimationData.cycleTime) / handAnimationData.cycleTime);
|
||||
float length = 0.035f;
|
||||
|
||||
handPosition.x = 0;
|
||||
handPosition.z = length * p;
|
||||
|
||||
handPosition = handPosition.RotatedBy(baseAngle);
|
||||
|
||||
return handPosition;
|
||||
}
|
||||
|
||||
public static Vector3 Motion_StrokeGenitalsUpAndDown_FacingNS(Pawn pawn, HandAnimationData handAnimationData, float baseAngle)
|
||||
{
|
||||
Vector3 handPosition = new Vector3();
|
||||
ActorAnimationData data = pawn.GetAnimationData();
|
||||
|
||||
float p = (Mathf.PingPong(data.stageTicks, handAnimationData.cycleTime) / handAnimationData.cycleTime);
|
||||
float size = GetGenitalSize(pawn, handAnimationData.targetBodyPart) * 0.2f;
|
||||
float m = (data.actorFacing == Rot4.North ? -1f : 1f) * (handAnimationData.mirror ? -1f : 1f) * (pawn.TryGetComp<CompBodyAnimator>().Mirror ? -1f : 1f);
|
||||
|
||||
handPosition.x = 0.025f * m;
|
||||
handPosition.z = size * p;
|
||||
|
||||
handPosition = handPosition.RotatedBy(baseAngle);
|
||||
|
||||
return handPosition;
|
||||
}
|
||||
|
||||
public static Vector3 Motion_StrokeGenitalsUpAndDown_FacingEW(Pawn pawn, HandAnimationData handAnimationData, float baseAngle)
|
||||
{
|
||||
Vector3 handPosition = new Vector3();
|
||||
ActorAnimationData data = pawn.GetAnimationData();
|
||||
|
||||
float p = Mathf.PingPong(data.stageTicks, handAnimationData.cycleTime) / handAnimationData.cycleTime;
|
||||
float size = GetGenitalSize(pawn, handAnimationData.targetBodyPart) * 0.2f;
|
||||
float m = (data.actorFacing == Rot4.West ? -1f : 1f) * (handAnimationData.mirror ? -1f : 1f);
|
||||
|
||||
handPosition.x = Mathf.Sin(m * (baseAngle + 45f) / 180f * Mathf.PI) * size * p;
|
||||
handPosition.z = Mathf.Cos(m * (baseAngle + 45f) / 180f * Mathf.PI) * size * p;
|
||||
|
||||
return handPosition;
|
||||
}
|
||||
|
||||
public static Vector3 Motion_RubGenitals_FacingNS(Pawn pawn, HandAnimationData handAnimationData, float baseAngle)
|
||||
{
|
||||
Vector3 handPosition = new Vector3();
|
||||
ActorAnimationData data = pawn.GetAnimationData();
|
||||
|
||||
float a = ((float)data.stageTicks % (float)handAnimationData.cycleTime) / (float)handAnimationData.cycleTime * 360f;
|
||||
float m = (data.actorFacing == Rot4.North ? 1f : -1f) * (handAnimationData.mirror ? -1f : 1f) * (pawn.TryGetComp<CompBodyAnimator>().Mirror ? -1f : 1f);
|
||||
|
||||
handPosition.x = (Mathf.Sin(a / 180f * Mathf.PI) * 0.05f - 0.025f) * m;
|
||||
handPosition.z = Mathf.Cos(a / 180f * Mathf.PI) * 0.015f + 0.03f;
|
||||
|
||||
handPosition = handPosition.RotatedBy(baseAngle);
|
||||
|
||||
return handPosition;
|
||||
}
|
||||
|
||||
public static Vector3 Motion_RubGenitals_FacingEW(Pawn pawn, HandAnimationData handAnimationData, float baseAngle)
|
||||
{
|
||||
Vector3 handPosition = new Vector3();
|
||||
ActorAnimationData data = pawn.GetAnimationData();
|
||||
|
||||
float a = ((float)data.stageTicks % (float)handAnimationData.cycleTime) / (float)handAnimationData.cycleTime * 360f;
|
||||
float m = (data.actorFacing == Rot4.West ? 1f : -1f) * (handAnimationData.mirror ? -1f : 1f);
|
||||
|
||||
handPosition.x = (Mathf.Sin(a / 180f * Mathf.PI) * 0.005f - 0.05f) * m;
|
||||
handPosition.z = Mathf.Cos(a / 180f * Mathf.PI) * 0.015f;
|
||||
//handPosition.y = -0.1f;
|
||||
|
||||
handPosition = handPosition.RotatedBy(baseAngle);
|
||||
|
||||
return handPosition;
|
||||
}
|
||||
|
||||
public static Vector3 Motion_RubBreasts_FacingNS(Pawn pawn, HandAnimationData handAnimationData, float baseAngle)
|
||||
{
|
||||
Vector3 handPosition = new Vector3();
|
||||
ActorAnimationData data = pawn.GetAnimationData();
|
||||
|
||||
float a = ((float)data.stageTicks % (float)handAnimationData.cycleTime) / (float)handAnimationData.cycleTime * 360f;
|
||||
float m = (data.actorFacing == Rot4.North ? -1f : 1f) * (handAnimationData.mirror ? -1f : 1f) * (pawn.TryGetComp<CompBodyAnimator>().Mirror ? -1f : 1f);
|
||||
float size = GetGenitalSize(pawn, "breasts");
|
||||
|
||||
handPosition.x = (Mathf.Sin(a / 180f * Mathf.PI) * 0.05f * size - size * 0.25f) * m;
|
||||
handPosition.z = Mathf.Cos(a / 180f * Mathf.PI) * 0.015f - size * 0.125f;
|
||||
|
||||
handPosition = handPosition.RotatedBy(baseAngle);
|
||||
|
||||
return handPosition;
|
||||
}
|
||||
|
||||
public static Vector3 Motion_RubBreasts_FacingEW(Pawn pawn, HandAnimationData handAnimationData, float baseAngle)
|
||||
{
|
||||
Vector3 handPosition = new Vector3();
|
||||
ActorAnimationData data = pawn.GetAnimationData();
|
||||
|
||||
float a = ((float)data.stageTicks % (float)handAnimationData.cycleTime) / (float)handAnimationData.cycleTime * 360f;
|
||||
float m = (data.actorFacing == Rot4.West ? 1f : -1f) * (handAnimationData.mirror ? -1f : 1f);
|
||||
float size = GetGenitalSize(pawn, "breasts");
|
||||
|
||||
handPosition.x = (Mathf.Sin(a / 180f * Mathf.PI) * 0.005f - size * 0.25f) * m;
|
||||
handPosition.z = Mathf.Cos(a / 180f * Mathf.PI) * 0.015f - size * 0.125f;
|
||||
|
||||
handPosition = handPosition.RotatedBy(baseAngle);
|
||||
|
||||
return handPosition;
|
||||
}
|
||||
|
||||
public static Graphic GetHandGraphic(Pawn touchingPawn)
|
||||
{
|
||||
CompPawnSexData comp = touchingPawn?.TryGetComp<CompPawnSexData>();
|
||||
|
@ -198,9 +71,9 @@ namespace Rimworld_Animations_Patch
|
|||
return comp.handGraphic;
|
||||
}
|
||||
|
||||
public static bool TryToDrawHand(Pawn pawn, string bodyAddonName, Vector3 bodyAddonPosition, float bodyAddonAngle, Rot4 bodyAddonRotation, PawnRenderFlags renderFlags)
|
||||
public static bool TryToDrawHand(Pawn pawn, ActorAnimationData pawnAnimationData, string bodyAddonName, Vector3 bodyAddonPosition, float bodyAddonAngle, Rot4 bodyAddonRotation, PawnRenderFlags renderFlags)
|
||||
{
|
||||
if (BodyPartIsBeingTouched(pawn, bodyAddonName, out List<HandAnimationData> handAnimationData))
|
||||
if (BodyPartIsBeingTouched(pawn, pawnAnimationData, bodyAddonName, out List<HandAnimationData> handAnimationData))
|
||||
{
|
||||
foreach (HandAnimationData datum in handAnimationData)
|
||||
{
|
||||
|
|
|
@ -33,14 +33,19 @@ namespace Rimworld_Animations_Patch
|
|||
{
|
||||
for (int radius = 1; radius < maxRadius; radius++)
|
||||
{
|
||||
List<IntVec3> cells = GenRadial.RadialCellsAround(pawn.Position, radius + 0.75f, false).Where(x => x.Standable(pawn.Map) && x.GetRoom(pawn.Map) == pawn.GetRoom())?.ToList();
|
||||
IEnumerable<IntVec3> cells = GenRadial.RadialCellsAround(pawn.Position, radius + 0.75f, false).Where(x => x.Standable(pawn.Map) && x.GetRoom(pawn.Map) == pawn.GetRoom());
|
||||
|
||||
if (cells.NullOrEmpty() == false && cells.Count > 0)
|
||||
if (cells.Any() == true && cells.Count() > 0)
|
||||
{ return cells.RandomElement(); }
|
||||
}
|
||||
}
|
||||
|
||||
return GenAdj.RandomAdjacentCellCardinal(pawn);
|
||||
}
|
||||
|
||||
public static float ClampAngle(float angle)
|
||||
{
|
||||
return angle < 0f ? 360f - (angle % 360) : angle % 360f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,5 +16,8 @@ namespace Rimworld_Animations_Patch
|
|||
public static class PatchBodyPartDefOf
|
||||
{
|
||||
public static BodyPartDef Hand;
|
||||
public static BodyPartDef Genitals;
|
||||
public static BodyPartDef Anus;
|
||||
public static BodyPartDef Chest;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,266 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
using Verse.AI.Group;
|
||||
using RimWorld;
|
||||
using rjw;
|
||||
using RJWSexperience.Ideology;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Rimworld_Animations_Patch
|
||||
{
|
||||
public static class SexInteractionUtility
|
||||
{
|
||||
public static bool PawnCaughtLovinByWitness(Pawn pawn, Pawn witness)
|
||||
{
|
||||
if (witness == null || pawn == witness || witness.AnimalOrWildMan() || witness.RaceProps.IsMechanoid || witness.Awake() == false || witness.CanSee(pawn) == false)
|
||||
{ return false; }
|
||||
|
||||
if (pawn.IsHavingSex() == false && pawn.IsMasturbating() == false)
|
||||
{ return false; }
|
||||
|
||||
List<Pawn> sexParticipants = pawn.GetAllSexParticipants();
|
||||
bool witnessIsCourtingSexParticipant = witness.jobs.curDriver is JobDriver_SexBaseInitiator && sexParticipants.Contains((witness.jobs.curDriver as JobDriver_SexBaseInitiator).Partner);
|
||||
|
||||
if (sexParticipants.Contains(witness) || witnessIsCourtingSexParticipant)
|
||||
{ return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool PawnIsCheatingOnPartner(Pawn pawn, Pawn partner)
|
||||
{
|
||||
if (BasicSettings.worryAboutInfidelity == false || pawn.IsMasturbating() || pawn.IsHavingSex() == false || pawn.GetAllSexParticipants().Contains(partner))
|
||||
{ return false; }
|
||||
|
||||
if (pawn.GetAllSexParticipants().Any(x => pawn.GetSpouseCount(false) > 0 && pawn.GetSpouses(false).Contains(x)))
|
||||
{ return false; }
|
||||
|
||||
if (pawn.GetSexPartner().Dead || pawn.GetSexPartner().IsAnimal())
|
||||
{ return false; }
|
||||
|
||||
return partner.IsLoverOfOther(pawn) && pawn.HasTrait("Polygamist") == false && partner.HasTrait("Polygamist") == false;
|
||||
}
|
||||
|
||||
public static bool InvitePasserbyForSex(Pawn passerby, List<Pawn> participants)
|
||||
{
|
||||
if (passerby == null || participants.NullOrEmpty() || participants.Contains(passerby) || passerby.AnimalOrWildMan() || passerby.RaceProps.IsMechanoid || passerby.Awake() == false || participants.All(x => x.CanSee(passerby) == false))
|
||||
{ return false; }
|
||||
|
||||
if (participants.Any(x => x.IsForbidden(passerby) || x.HostileTo(passerby) || PawnIsCheatingOnPartner(x, passerby)) || CasualSex_Helper.CanHaveSex(passerby) == false || xxx.IsTargetPawnOkay(passerby) == false || participants.Count > 2)
|
||||
{ return false; }
|
||||
|
||||
if (passerby.MentalState != null ||
|
||||
passerby.jobs.curDriver is JobDriver_Flee ||
|
||||
passerby.jobs.curDriver is JobDriver_AttackMelee ||
|
||||
passerby.jobs.curDriver is JobDriver_Vomit)
|
||||
{ return false; }
|
||||
|
||||
if (SexUtility.ReadyForHookup(passerby) &&
|
||||
(passerby?.jobs?.curJob == null || (passerby.jobs.curJob.playerForced == false && CasualSex_Helper.quickieAllowedJobs.Contains(passerby.jobs.curJob.def))) &&
|
||||
participants.Any(x => SexAppraiser.would_fuck(x, passerby) > 0.1f && SexAppraiser.would_fuck(passerby, x) > 0.1f) &&
|
||||
participants.All(x => SexAppraiser.would_fuck(x, passerby, false, false, true) > 0.1f && SexAppraiser.would_fuck(passerby, x, false, false, true) > 0.1f))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static ThoughtDef GetThoughtsAboutSexAct(Pawn pawn, JobDriver_Sex jobDriver, out Precept precept)
|
||||
{
|
||||
ThoughtDef thoughtDef = null;
|
||||
precept = null;
|
||||
|
||||
if (pawn == null || jobDriver == null)
|
||||
{ return null; }
|
||||
|
||||
bool sexIsNecro = jobDriver.Partner != null && jobDriver.Partner.Dead;
|
||||
bool sexIsBeastial = jobDriver.Partner != null && jobDriver.Partner.RaceProps.Animal;
|
||||
bool sexIsRape = sexIsBeastial == false && sexIsNecro == false &&
|
||||
(jobDriver is JobDriver_Rape || jobDriver is JobDriver_RapeEnemy || jobDriver is JobDriver_SexBaseRecieverRaped);
|
||||
bool sexIsSlaveRape = sexIsRape && (jobDriver.Partner.IsPrisoner || jobDriver.Partner.IsSlave);
|
||||
bool sexIsXeno = jobDriver.Partner != null && jobDriver.Partner.def.defName != jobDriver.pawn.def.defName;
|
||||
bool isXenophobe = pawn.HasTrait("Xenophobia") && pawn.story.traits.DegreeOfTrait(DefDatabase<TraitDef>.GetNamedSilentFail("Xenophobia")) > 0;
|
||||
bool isXenophile = pawn.HasTrait("Xenophobia") && pawn.story.traits.DegreeOfTrait(DefDatabase<TraitDef>.GetNamedSilentFail("Xenophobia")) < 0;
|
||||
|
||||
if (BasicSettings.worryAboutNecro && sexIsNecro && xxx.is_necrophiliac(pawn) == false)
|
||||
{
|
||||
thoughtDef = xxx.is_necrophiliac(pawn) ? DefDatabase<ThoughtDef>.GetNamedSilentFail("SawNecrophilia_Honorable") :
|
||||
pawn.HasPreceptForIssue("Necrophilia", out precept) ? DefDatabase<ThoughtDef>.GetNamedSilentFail("Saw" + precept.def.defName) :
|
||||
DefDatabase<ThoughtDef>.GetNamedSilentFail("SawNecrophilia_Abhorrent");
|
||||
}
|
||||
|
||||
else if (BasicSettings.worryAboutBeastiality && sexIsBeastial)
|
||||
{
|
||||
thoughtDef = xxx.is_zoophile(pawn) ? DefDatabase<ThoughtDef>.GetNamedSilentFail("SawBeastility_Honorable") :
|
||||
pawn.HasPreceptForIssue("Beastility", out precept) ? DefDatabase<ThoughtDef>.GetNamedSilentFail("Saw" + precept.def.defName) :
|
||||
DefDatabase<ThoughtDef>.GetNamedSilentFail("SawBeastility_Abhorrent");
|
||||
}
|
||||
|
||||
else if (BasicSettings.worryAboutRape && BasicSettings.ignoreSlaveRape == false && sexIsSlaveRape)
|
||||
{
|
||||
thoughtDef = xxx.is_rapist(pawn) ? DefDatabase<ThoughtDef>.GetNamedSilentFail("SawRape_Honorable") :
|
||||
pawn.HasPreceptForIssue("Rape", out precept) ? DefDatabase<ThoughtDef>.GetNamedSilentFail("Saw" + precept.def.defName) :
|
||||
DefDatabase<ThoughtDef>.GetNamedSilentFail("SawRape_Abhorrent");
|
||||
}
|
||||
|
||||
else if (BasicSettings.worryAboutRape && sexIsRape)
|
||||
{
|
||||
thoughtDef = xxx.is_rapist(pawn) ? DefDatabase<ThoughtDef>.GetNamedSilentFail("SawRape_Honorable") :
|
||||
pawn.HasPreceptForIssue("Rape", out precept) ? DefDatabase<ThoughtDef>.GetNamedSilentFail("Saw" + precept.def.defName) :
|
||||
DefDatabase<ThoughtDef>.GetNamedSilentFail("SawRape_Abhorrent");
|
||||
}
|
||||
|
||||
else if (BasicSettings.worryAboutXeno && sexIsXeno)
|
||||
{
|
||||
thoughtDef = isXenophobe ? DefDatabase<ThoughtDef>.GetNamedSilentFail("SawHAR_AlienDating_Prohibited") :
|
||||
isXenophile ? DefDatabase<ThoughtDef>.GetNamedSilentFail("SawHAR_AlienDating_Honorable") :
|
||||
pawn.HasPreceptForIssue("HAR_AlienDating", out precept) ? DefDatabase<ThoughtDef>.GetNamedSilentFail("Saw" + precept.def.defName) :
|
||||
DefDatabase<ThoughtDef>.GetNamedSilentFail("SawHAR_AlienDating_Acceptable");
|
||||
}
|
||||
|
||||
//DebugMode.Message("Sex job is: " + jobDriver + " Issue is: " + (precept?.def?.issue?.defName).ToStringSafe() + " Opinion is: " + (precept?.def?.defName).ToStringSafe() + " Thought is: " + (thoughtDef?.defName).ToStringSafe());
|
||||
|
||||
return thoughtDef;
|
||||
}
|
||||
|
||||
public static void TriggerReactionInWitness(Pawn witness, Pawn otherPawn, string reaction)
|
||||
{
|
||||
if (BasicSettings.majorTabooCanStartFights == false || reaction.NullOrEmpty())
|
||||
{ return; }
|
||||
|
||||
if (witness.MentalState != null ||
|
||||
witness.jobs.curDriver is JobDriver_Flee ||
|
||||
witness.jobs.curDriver is JobDriver_AttackMelee ||
|
||||
witness.jobs.curDriver is JobDriver_Vomit)
|
||||
{ return; }
|
||||
|
||||
// Panicked
|
||||
if (reaction == "Panicked" || (reaction == "Indignant" && Random.value <= 0.5f))
|
||||
{
|
||||
// Fight
|
||||
if (otherPawn.RaceProps.Humanlike && witness.RaceProps.Humanlike && witness.DislikesViolence() == false && (Random.value <= 0.2f || witness.EnjoysViolence()) && witness.HostileTo(otherPawn) == false && InteractionUtility.TryGetRandomVerbForSocialFight(witness, out Verb verbToUse))
|
||||
{ witness.interactions.StartSocialFight(otherPawn, "MessageSocialFight"); }
|
||||
|
||||
// Flight
|
||||
else
|
||||
{
|
||||
Job job = JobMaker.MakeJob(JobDefOf.FleeAndCower, CellFinderLoose.GetFleeDest(witness, new List<Thing>() { otherPawn }, 24f), otherPawn);
|
||||
witness.jobs.EndCurrentJob(JobCondition.InterruptForced, false, false);
|
||||
witness.jobs.StartJob(job);
|
||||
}
|
||||
}
|
||||
|
||||
// Vomit
|
||||
else if (reaction == "Nauseated")
|
||||
{
|
||||
Job jobVomit = JobMaker.MakeJob(JobDefOf.Vomit);
|
||||
Job jobFlee = JobMaker.MakeJob(JobDefOf.FleeAndCower, CellFinderLoose.GetFleeDest(witness, new List<Thing>() { otherPawn }, 24f), otherPawn);
|
||||
|
||||
witness.jobs.EndCurrentJob(JobCondition.InterruptForced, false, false);
|
||||
|
||||
if (Random.value <= 0.2f)
|
||||
{
|
||||
witness.jobs.StartJob(jobVomit);
|
||||
witness.jobs.jobQueue.EnqueueFirst(jobFlee);
|
||||
}
|
||||
|
||||
else
|
||||
{ witness.jobs.StartJob(jobFlee); }
|
||||
}
|
||||
|
||||
// Indignant
|
||||
else if (reaction == "Indignant")
|
||||
{
|
||||
witness.mindState.mentalStateHandler.TryStartMentalState(DefDatabase<MentalStateDef>.GetNamedSilentFail("TargetedInsultingSpree"), null, true, false, null, true, false, false);
|
||||
(witness.mindState.mentalStateHandler.CurState as MentalState_TargetedInsultingSpree).target = otherPawn;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ResolveThoughtsForWhenSexIsWitnessed(Pawn pawn, Pawn witness, out bool witnessJoiningSex)
|
||||
{
|
||||
witnessJoiningSex = Random.value < BasicSettings.chanceForOtherToJoinInSex && InvitePasserbyForSex(witness, pawn.GetAllSexParticipants());
|
||||
|
||||
// Exit clauses
|
||||
if (witness.AnimalOrWildMan() || witness.RaceProps.IsMechanoid || witness.Dead || witness.Faction == null || witness.Faction.HostileTo(Faction.OfPlayer))
|
||||
{ return false; }
|
||||
|
||||
// Get basic thoughts
|
||||
string pawnThoughtDefName = pawn.IsMasturbating() ? "SeenMasturbating" : "SeenHavingSex";
|
||||
string witnessThoughtDefName = pawn.IsMasturbating() ? "SawMasturbation" : "SawSex";
|
||||
|
||||
ThoughtDef pawnThoughtDef = BasicSettings.needPrivacy ? DefDatabase<ThoughtDef>.GetNamedSilentFail(pawnThoughtDefName) : null;
|
||||
ThoughtDef witnessThoughtDef = BasicSettings.needPrivacy ? DefDatabase<ThoughtDef>.GetNamedSilentFail(witnessThoughtDefName) : null;
|
||||
|
||||
// Exhibitionist pawn
|
||||
if (xxx.has_quirk(pawn, "Exhibitionist"))
|
||||
{ pawnThoughtDef = DefDatabase<ThoughtDef>.GetNamedSilentFail(pawnThoughtDefName + "Exhibitionist"); }
|
||||
|
||||
// Voyeuristic witness
|
||||
if (xxx.has_quirk(witness, "Voyeur"))
|
||||
{ witnessThoughtDef = DefDatabase<ThoughtDef>.GetNamedSilentFail(witnessThoughtDefName + "Voyeur"); }
|
||||
|
||||
// Mediating cirumstances
|
||||
bool sexIsRitual = pawn.GetLord() != null && pawn.GetLord().LordJob is LordJob_Ritual && witness?.Ideo == pawn?.Ideo;
|
||||
bool sexIsParty = pawn.GetLord() != null && pawn.GetLord().LordJob is LordJob_Joinable_Party;
|
||||
bool pawnIsVictim = pawn.CurJob.def == xxx.gettin_raped || pawn.Dead;
|
||||
bool pawnIsCheating = sexIsRitual == false && sexIsParty == false && pawnIsVictim == false && PawnIsCheatingOnPartner(pawn, witness);
|
||||
|
||||
// Wipe thoughts if pawn is a victim
|
||||
if (pawnIsVictim)
|
||||
{
|
||||
pawnThoughtDef = null;
|
||||
witnessThoughtDef = null;
|
||||
}
|
||||
|
||||
// Add thought if pawn is cheating
|
||||
if (pawnIsCheating)
|
||||
{
|
||||
if (pawn.needs.mood.thoughts.memories.GetFirstMemoryOfDef(DefDatabase<ThoughtDef>.GetNamedSilentFail("CaughtCheating")) == null)
|
||||
{ pawn.needs.mood.thoughts.memories.TryGainMemory(DefDatabase<ThoughtDef>.GetNamedSilentFail("CaughtCheating"), witness); }
|
||||
|
||||
if (witness.needs.mood.thoughts.memories.GetFirstMemoryOfDef(ThoughtDefOf.CheatedOnMe) == null)
|
||||
{ witness.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.CheatedOnMe, pawn); }
|
||||
|
||||
witnessJoiningSex = false;
|
||||
}
|
||||
|
||||
// Determine if there are any issues with the sex event and the witness' morals
|
||||
Precept precept = null;
|
||||
|
||||
if (sexIsRitual == false && sexIsParty == false && pawnIsVictim == false)
|
||||
{ witnessThoughtDef = GetThoughtsAboutSexAct(witness, pawn.jobs.curDriver as JobDriver_Sex, out precept); }
|
||||
|
||||
// Apply thoughts to witness
|
||||
if (witnessThoughtDef != null)
|
||||
{
|
||||
witness.needs.mood.thoughts.memories.TryGainMemory(witnessThoughtDef, pawn, precept);
|
||||
|
||||
if (witnessThoughtDef.stages[0].baseMoodEffect < 0)
|
||||
{ witness?.TryGetComp<CompPawnSexData>()?.TryToExclaim(); }
|
||||
|
||||
witnessJoiningSex = witnessThoughtDef.hediff != null ? false : witnessJoiningSex;
|
||||
}
|
||||
|
||||
// Extreme reaction
|
||||
if (witnessThoughtDef?.hediff != null)
|
||||
{ TriggerReactionInWitness(witness, pawn, witnessThoughtDef.hediff.defName); }
|
||||
|
||||
else if (pawnIsCheating)
|
||||
{ TriggerReactionInWitness(witness, pawn, "Indignant"); }
|
||||
|
||||
// Apply thoughts to pawn
|
||||
if (pawnThoughtDef != null)
|
||||
{
|
||||
pawn.needs.mood.thoughts.memories.TryGainMemory(pawnThoughtDef, witness, null);
|
||||
|
||||
if (pawnThoughtDef.stages[0].baseMoodEffect < 0)
|
||||
{ pawn?.TryGetComp<CompPawnSexData>()?.TryToExclaim(); }
|
||||
}
|
||||
|
||||
return witnessJoiningSex;
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -1 +1 @@
|
|||
80ac53cd1937a7f3bc413d1816a7df030fc583c6
|
||||
0035486d66161d603d82d58abd89b02b042a2e0c
|
||||
|
|
|
@ -4,3 +4,5 @@ C:\Program Files (x86)\Steam\SteamApps\common\RimWorld\Mods\rimworld-animations-
|
|||
C:\Program Files (x86)\Steam\SteamApps\common\RimWorld\Mods\rimworld-animations-patch-abscon\Source\obj\Debug\Rimworld-Animations-Patch.dll
|
||||
C:\Program Files (x86)\Steam\SteamApps\common\RimWorld\Mods\rimworld-animations-patch-abscon\Source\obj\Debug\Rimworld-Animations-Patch.pdb
|
||||
C:\Program Files (x86)\Steam\SteamApps\common\RimWorld\Mods\rimworld-animations-patch-abscon\Source\obj\Debug\Rimworld-Animations-Patch.csprojAssemblyReference.cache
|
||||
C:\Program Files (x86)\Steam\SteamApps\common\RimWorld\Mods\rimworld-animations-patch-abscon\1.4\Assemblies\Rimworld-Animations-Patch.dll
|
||||
C:\Program Files (x86)\Steam\SteamApps\common\RimWorld\Mods\rimworld-animations-patch-abscon\1.4\Assemblies\Rimworld-Animations-Patch.pdb
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue