From b943cb55c60a2b945649f8d868f6e23aa83ddf21 Mon Sep 17 00:00:00 2001 From: Ed86 Date: Wed, 26 Oct 2022 12:25:26 +0300 Subject: [PATCH] support for 1.4 --- 1.3/Source/Mod/RimJobWorldCum.csproj | 2 +- 1.4/Assemblies/RimJobWorldCum.dll | Bin 0 -> 40960 bytes 1.4/Defs/HediffsDef/Hediff_CumController.xml | 49 ++ 1.4/Defs/HediffsDef/Hediffs_Cum.xml | 72 ++ 1.4/Defs/JobDefs/Jobs_CleanSelf.xml | 10 + .../WorkGiverDefs/WorkGivers_CleanSelf.xml | 16 + 1.4/Languages/English/Keyed/Cum.xml | 15 + 1.4/Patches/FacialAnimation_compatibility.xml | 20 + 1.4/Source/Mod/CumBase.cs | 53 ++ 1.4/Source/Mod/CumHelper.cs | 620 ++++++++++++++++++ 1.4/Source/Mod/DefOf/HediffDefOf.cs | 17 + 1.4/Source/Mod/DefOf/JobDefOf.cs | 11 + 1.4/Source/Mod/Hediffs/Hediff_Cum.cs | 155 +++++ .../Mod/Hediffs/Hediff_CumController.cs | 272 ++++++++ .../Mod/JobDrivers/JobDriver_CleanSelf.cs | 53 ++ 1.4/Source/Mod/Patch_AddCumOnOrgasm.cs | 66 ++ 1.4/Source/Mod/Patch_AddGizmo.cs | 68 ++ .../Mod/Patch_JobDriver_DubsBadHygiene.cs | 85 +++ 1.4/Source/Mod/Patch_RenderOverBody.cs | 54 ++ 1.4/Source/Mod/RimJobWorldCum.csproj | 79 +++ 1.4/Source/Mod/Textures.cs | 58 ++ .../Mod/WorkGivers/WorkGiver_CleanSelf.cs | 76 +++ 1.4/Source/Mod/packages.config | 4 + 1.4/Source/Properties/AssemblyInfo.cs | 32 + 1.4/Source/mod.sln | 25 + 1.4/Textures/CumIcon_drenched.png | Bin 0 -> 419 bytes 1.4/Textures/CumIcon_dripping.png | Bin 0 -> 385 bytes 1.4/Textures/CumIcon_little.png | Bin 0 -> 226 bytes 1.4/Textures/CumIcon_some.png | Bin 0 -> 265 bytes 1.4/Textures/splatch_1.png | Bin 0 -> 3417 bytes 1.4/Textures/splatch_2.png | Bin 0 -> 3027 bytes 1.4/Textures/splatch_3.png | Bin 0 -> 2976 bytes 1.4/Textures/splatch_4.png | Bin 0 -> 2965 bytes 1.4/Textures/splatch_5.png | Bin 0 -> 2990 bytes 1.4/Textures/splatch_6.png | Bin 0 -> 3463 bytes 1.4/Textures/splatch_7.png | Bin 0 -> 2226 bytes 1.4/Textures/splatch_8.png | Bin 0 -> 2480 bytes 1.4/Textures/splatch_9.png | Bin 0 -> 3066 bytes About/About.xml | 1 + 39 files changed, 1912 insertions(+), 1 deletion(-) create mode 100644 1.4/Assemblies/RimJobWorldCum.dll create mode 100644 1.4/Defs/HediffsDef/Hediff_CumController.xml create mode 100644 1.4/Defs/HediffsDef/Hediffs_Cum.xml create mode 100644 1.4/Defs/JobDefs/Jobs_CleanSelf.xml create mode 100644 1.4/Defs/WorkGiverDefs/WorkGivers_CleanSelf.xml create mode 100644 1.4/Languages/English/Keyed/Cum.xml create mode 100644 1.4/Patches/FacialAnimation_compatibility.xml create mode 100644 1.4/Source/Mod/CumBase.cs create mode 100644 1.4/Source/Mod/CumHelper.cs create mode 100644 1.4/Source/Mod/DefOf/HediffDefOf.cs create mode 100644 1.4/Source/Mod/DefOf/JobDefOf.cs create mode 100644 1.4/Source/Mod/Hediffs/Hediff_Cum.cs create mode 100644 1.4/Source/Mod/Hediffs/Hediff_CumController.cs create mode 100644 1.4/Source/Mod/JobDrivers/JobDriver_CleanSelf.cs create mode 100644 1.4/Source/Mod/Patch_AddCumOnOrgasm.cs create mode 100644 1.4/Source/Mod/Patch_AddGizmo.cs create mode 100644 1.4/Source/Mod/Patch_JobDriver_DubsBadHygiene.cs create mode 100644 1.4/Source/Mod/Patch_RenderOverBody.cs create mode 100644 1.4/Source/Mod/RimJobWorldCum.csproj create mode 100644 1.4/Source/Mod/Textures.cs create mode 100644 1.4/Source/Mod/WorkGivers/WorkGiver_CleanSelf.cs create mode 100644 1.4/Source/Mod/packages.config create mode 100644 1.4/Source/Properties/AssemblyInfo.cs create mode 100644 1.4/Source/mod.sln create mode 100644 1.4/Textures/CumIcon_drenched.png create mode 100644 1.4/Textures/CumIcon_dripping.png create mode 100644 1.4/Textures/CumIcon_little.png create mode 100644 1.4/Textures/CumIcon_some.png create mode 100644 1.4/Textures/splatch_1.png create mode 100644 1.4/Textures/splatch_2.png create mode 100644 1.4/Textures/splatch_3.png create mode 100644 1.4/Textures/splatch_4.png create mode 100644 1.4/Textures/splatch_5.png create mode 100644 1.4/Textures/splatch_6.png create mode 100644 1.4/Textures/splatch_7.png create mode 100644 1.4/Textures/splatch_8.png create mode 100644 1.4/Textures/splatch_9.png diff --git a/1.3/Source/Mod/RimJobWorldCum.csproj b/1.3/Source/Mod/RimJobWorldCum.csproj index 1e94d1f..148b9d0 100644 --- a/1.3/Source/Mod/RimJobWorldCum.csproj +++ b/1.3/Source/Mod/RimJobWorldCum.csproj @@ -40,7 +40,7 @@ False - ..\..\..\..\..\..\..\workshop\content\294100\818773962\v1.2\Assemblies\HugsLib.dll + ..\..\..\..\..\..\..\workshop\content\294100\818773962\v1.3\Assemblies\HugsLib.dll False diff --git a/1.4/Assemblies/RimJobWorldCum.dll b/1.4/Assemblies/RimJobWorldCum.dll new file mode 100644 index 0000000000000000000000000000000000000000..dbec018b6ac70a88c5906f85c9a32e28f92bb145 GIT binary patch literal 40960 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 literal 0 HcmV?d00001 diff --git a/1.4/Defs/HediffsDef/Hediff_CumController.xml b/1.4/Defs/HediffsDef/Hediff_CumController.xml new file mode 100644 index 0000000..854f8e0 --- /dev/null +++ b/1.4/Defs/HediffsDef/Hediff_CumController.xml @@ -0,0 +1,49 @@ + + + + + Hediff_CumController + rjwcum.Hediff_CumController + + Covered in cum. + false + 0.01 + 1 + + + + + false + false + +
  • + + false +
  • +
  • + 0.3 + + + 0.2 + -0.1 + +
  • +
  • + 0.6 + + + 0.3 + -0.3 + +
  • +
  • + 0.8 + + + -0.1 + -0.5 + +
  • +
    +
    +
    \ No newline at end of file diff --git a/1.4/Defs/HediffsDef/Hediffs_Cum.xml b/1.4/Defs/HediffsDef/Hediffs_Cum.xml new file mode 100644 index 0000000..3a77e61 --- /dev/null +++ b/1.4/Defs/HediffsDef/Hediffs_Cum.xml @@ -0,0 +1,72 @@ + + + + rjwcum.Hediff_Cum + Hediff_Cum + + cum + cum. + cum on {1} + (0.95,0.95,0.95) + false + false + false + false + 1 + 0.001 + + true + + +
  • + +
  • +
  • + 0.25 + +
  • +
  • + 0.5 + +
  • +
  • + 0.8 + +
  • +
    + +
  • + + 1800 + 0.01 +
  • +
    +
    + + + Hediff_Cum + + cum + cum + cum on {1} + (0.95,0.95,0.95) + + + + Hediff_InsectSpunk + Insect spunk. + + insect spunk + insect spunk on {1} + (0.6,0.83,0.35) + + + + Hediff_MechaFluids + Mechanoid fluids. + + mechanoid fluids + mecha fluids on {1} + (0.37,0.71,0.82) + +
    \ No newline at end of file diff --git a/1.4/Defs/JobDefs/Jobs_CleanSelf.xml b/1.4/Defs/JobDefs/Jobs_CleanSelf.xml new file mode 100644 index 0000000..12ae606 --- /dev/null +++ b/1.4/Defs/JobDefs/Jobs_CleanSelf.xml @@ -0,0 +1,10 @@ + + + + + CleanSelf + rjwcum.JobDriver_CleanSelf + cleaning self + true + + \ No newline at end of file diff --git a/1.4/Defs/WorkGiverDefs/WorkGivers_CleanSelf.xml b/1.4/Defs/WorkGiverDefs/WorkGivers_CleanSelf.xml new file mode 100644 index 0000000..62b7637 --- /dev/null +++ b/1.4/Defs/WorkGiverDefs/WorkGivers_CleanSelf.xml @@ -0,0 +1,16 @@ + + + + CleanSelf + + rjwcum.WorkGiver_CleanSelf + Cleaning + clean self + cleaning self + false + 11 + +
  • Manipulation
  • +
    +
    +
    \ No newline at end of file diff --git a/1.4/Languages/English/Keyed/Cum.xml b/1.4/Languages/English/Keyed/Cum.xml new file mode 100644 index 0000000..54ce568 --- /dev/null +++ b/1.4/Languages/English/Keyed/Cum.xml @@ -0,0 +1,15 @@ + + + Debug + + Enable cum on body (Hediffs) + Enables cum hediffs in health tab. + Adjust cum amount on body + All cum applied to pawn bodies will be multiplied by this amount. + Enable cum overlays (Visuals) + Enables cum overlay for pawn drawer(may have conflicts with mods that change pawn appearance and other issues).\nRequires Cum on body option enabled. + Hero manual CleanSelf + Hero pawn will only clean cum from body if manually told so. + DubsBadHygiene block CleanSelf + If DubsBadHygiene installed, pawns will only clean cum from body in buckets, showers, baths, hottubs etc. + \ No newline at end of file diff --git a/1.4/Patches/FacialAnimation_compatibility.xml b/1.4/Patches/FacialAnimation_compatibility.xml new file mode 100644 index 0000000..7a6b70e --- /dev/null +++ b/1.4/Patches/FacialAnimation_compatibility.xml @@ -0,0 +1,20 @@ + + + + +
  • [NL] Facial Animation - WIP
  • +
    + + Always + +
  • + /Defs/FacialAnimation.FaceAnimationDef[defName="Wear" or defName="Wear2" or defName="Wear3"]/targetJobs + Always + +
  • CleanSelf
  • + + +
    +
    +
    +
    \ No newline at end of file diff --git a/1.4/Source/Mod/CumBase.cs b/1.4/Source/Mod/CumBase.cs new file mode 100644 index 0000000..294e079 --- /dev/null +++ b/1.4/Source/Mod/CumBase.cs @@ -0,0 +1,53 @@ +using System; +using HugsLib; +using HugsLib.Settings; +using Verse; + +namespace rjwcum +{ + public class CumBase : ModBase + { + public override string ModIdentifier + { + get + { + return "RJW_Cum"; + } + } + + public static SettingHandle debug; + public static SettingHandle cum_on_body; + public static SettingHandle cum_overlays; + public static SettingHandle cum_on_body_amount; + public static SettingHandle manual_hero_CleanSelf; + public static SettingHandle dubsDBH_block_CleanSelf; + + public override void DefsLoaded() + { + debug = Settings.GetHandle("debug", + Translator.Translate("debug"), + Translator.Translate("debug_desc"), + false); + cum_on_body = Settings.GetHandle("cum_on_body", + Translator.Translate("cum_on_body"), + Translator.Translate("cum_on_body_desc"), + true); + cum_overlays = Settings.GetHandle("cum_overlays", + Translator.Translate("cum_overlays"), + Translator.Translate("cum_overlays_desc"), + true); + cum_on_body_amount = Settings.GetHandle("cum_on_body_amount", + Translator.Translate("cum_on_body_amount"), + Translator.Translate("cum_on_body_amount_desc"), + 1.0f); + manual_hero_CleanSelf = Settings.GetHandle("manual_hero_CleanSelf", + Translator.Translate("manual_hero_CleanSelf"), + Translator.Translate("manual_hero_CleanSelf_desc"), + true); + dubsDBH_block_CleanSelf = Settings.GetHandle("dubsDBH_block_CleanSelf", + Translator.Translate("dubsDBH_block_CleanSelf"), + Translator.Translate("dubsDBH_block_CleanSelf_desc"), + true); + } + } +} diff --git a/1.4/Source/Mod/CumHelper.cs b/1.4/Source/Mod/CumHelper.cs new file mode 100644 index 0000000..9de0f69 --- /dev/null +++ b/1.4/Source/Mod/CumHelper.cs @@ -0,0 +1,620 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using RimWorld; +using Verse; +using HarmonyLib; +using UnityEngine; +//using Multiplayer.API; +using rjw; + +namespace rjwcum +{ + [StaticConstructorOnStartup] + public static class CumHelper + { + /* + contains many important functions of use to the other classes + */ + + //amount of cum per sex act: + + public static readonly Dictionary splatchAdjust;//saves x (horizontal) and z (vertical) adjustments of texture positiion for each unique combination of bodyType and bodyPart + public static readonly Dictionary layerAdjust;//saves y adjustments (drawing plane) for left/right appendages + bodyPart combinations to hide spunk if pawn looks in the wrong direction + + //structs are used to pack related variables together - used as keys for the dictionaries + public struct key//allows to save all unique combinations of bodyType and bodyPart + { + public readonly BodyTypeDef bodyType; + public readonly BodyPartDef bodyPart; + public key(BodyTypeDef bodyType, BodyPartDef bodyPart) + { + this.bodyType = bodyType; + this.bodyPart = bodyPart; + } + } + + //for the 4 directions, use arrays to store the different adjust for north, east, south, west (in that order) + public struct values + { + public readonly float[] x; + public readonly float[] z; + //public readonly bool over_clothing;//on gentials: hide when clothes are worn - in case of the other body parts it can't be said (for now) if it was added on the clothing or not + public values(float[] xAdjust, float[] zAdjust) + { + x = xAdjust; + z = zAdjust; + //this.over_clothing = over_clothing; + } + } + + + public struct key_layer//used to save left/right appendage + bodyPart combinations + { + public readonly bool left_side; + public readonly BodyPartDef bodyPart; + + public key_layer(bool left_side, BodyPartDef bodyPart) + { + this.left_side = left_side; + this.bodyPart = bodyPart; + } + } + + public struct values_layer//saves the y-adjustments for different body parts and sides -> e.g. allows hiding spunk on the right arm if pawn is looking to the left (aka west) + { + public readonly float[] y; + + public values_layer(float[] yAdjust) + { + y = yAdjust; + } + } + + //get defs of the rjw parts + public static BodyPartDef genitalsDef = BodyDefOf.Human.AllParts.Find(bpr => string.Equals(bpr.def.defName, "Genitals")).def; + public static BodyPartDef anusDef = BodyDefOf.Human.AllParts.Find(bpr => string.Equals(bpr.def.defName, "Anus")).def; + public static BodyPartDef chestDef = BodyDefOf.Human.AllParts.Find(bpr => string.Equals(bpr.def.defName, "Chest")).def; + + + static CumHelper() + { + splatchAdjust = new Dictionary(); + //maybe there is a more elegant way to save and load this data, but I don't know about it + + //structure explained: + //1) key: struct consisting of bodyType + bodyPart (= unique key for every combination of bodyType + part) + //2) values: struct containing positioning information (xAdjust: horizontal positioning, yAdjust: vertical positioning, zAdjust: whether to draw above or below pawn + //note: arms, hands, and legs (which are only visible from one direction) values need not be inverted between west and east + + //BodyType Thin + splatchAdjust.Add(new key(BodyTypeDefOf.Thin, BodyPartDefOf.Arm), new values(new float[] { -0.13f, 0.05f, 0.13f, 0.05f }, new float[] { 0f, 0f, 0f, 0f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Thin, BodyPartDefOf.Hand), new values(new float[] { -0.12f, 0.15f, 0.12f, 0.15f }, new float[] { -0.25f, -0.25f, -0.25f, -0.25f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Thin, BodyPartDefOf.Head), new values(new float[] { 0f, -0.23f, 0f, 0.23f }, new float[] { 0.37f, 0.35f, 0.33f, 0.35f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Thin, BodyPartDefOf.Jaw), new values(new float[] { 0f, -0.19f, 0f, 0.19f }, new float[] { 0.15f, 0.15f, 0.15f, 0.15f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Thin, BodyPartDefOf.Leg), new values(new float[] { -0.1f, 0.1f, 0.1f, 0.1f }, new float[] { -0.4f, -0.4f, -0.4f, -0.4f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Thin, BodyPartDefOf.Neck), new values(new float[] { 0f, -0.07f, 0f, 0.07f }, new float[] { 0.06f, 0.06f, 0.06f, 0.06f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Thin, BodyPartDefOf.Torso), new values(new float[] { 0f, 0f, 0f, 0f }, new float[] { -0.18f, -0.20f, -0.25f, -0.25f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Thin, genitalsDef), new values(new float[] { 0f, 0.01f, 0f, -0.01f }, new float[] { 0, -0.35f, -0.35f, -0.35f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Thin, anusDef), new values(new float[] { 0, 0.18f, 0, -0.18f }, new float[] { -0.42f, -0.35f, 0, -0.35f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Thin, chestDef), new values(new float[] { 0f, -0.1f, 0f, 0.1f }, new float[] { -0.06f, -0.05f, -0.06f, -0.05f })); + + //BodyType Female + splatchAdjust.Add(new key(BodyTypeDefOf.Female, BodyPartDefOf.Arm), new values(new float[] { -0.17f, 0f, 0.17f, 0f }, new float[] { 0f, 0f, 0f, 0f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Female, BodyPartDefOf.Hand), new values(new float[] { -0.17f, 0.1f, 0.17f, 0.1f }, new float[] { -0.25f, -0.25f, -0.25f, -0.25f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Female, BodyPartDefOf.Head), new values(new float[] { 0f, -0.23f, 0f, 0.23f }, new float[] { 0.37f, 0.35f, 0.33f, 0.35f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Female, BodyPartDefOf.Jaw), new values(new float[] { 0f, -0.19f, 0f, 0.19f }, new float[] { 0.15f, 0.15f, 0.15f, 0.15f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Female, BodyPartDefOf.Leg), new values(new float[] { -0.2f, 0.1f, 0.2f, 0.1f }, new float[] { -0.4f, -0.4f, -0.4f, -0.4f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Female, BodyPartDefOf.Neck), new values(new float[] { 0f, -0.07f, 0f, 0.07f }, new float[] { 0.06f, 0.06f, 0.06f, 0.06f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Female, BodyPartDefOf.Torso), new values(new float[] { 0f, -0.05f, 0f, 0.05f }, new float[] { -0.20f, -0.25f, -0.25f, -0.25f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Female, genitalsDef), new values(new float[] { 0f, -0.10f, 0f, 0.10f }, new float[] { 0, -0.42f, -0.45f, -0.42f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Female, anusDef), new values(new float[] { 0, 0.26f, 0, -0.26f }, new float[] { -0.42f, -0.35f, 0, -0.35f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Female, chestDef), new values(new float[] { 0f, -0.12f, 0f, 0.12f }, new float[] { -0.06f, -0.05f, -0.06f, -0.05f })); + + //BodyType Male + splatchAdjust.Add(new key(BodyTypeDefOf.Male, BodyPartDefOf.Arm), new values(new float[] { -0.21f, 0.05f, 0.21f, 0.05f }, new float[] { 0f, -0.02f, 0f, -0.02f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Male, BodyPartDefOf.Hand), new values(new float[] { -0.17f, 0.07f, 0.17f, 0.07f }, new float[] { -0.25f, -0.25f, -0.25f, -0.25f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Male, BodyPartDefOf.Head), new values(new float[] { 0f, -0.23f, 0f, 0.23f }, new float[] { 0.37f, 0.35f, 0.33f, 0.35f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Male, BodyPartDefOf.Jaw), new values(new float[] { 0f, -0.19f, 0f, 0.19f }, new float[] { 0.15f, 0.15f, 0.15f, 0.15f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Male, BodyPartDefOf.Leg), new values(new float[] { -0.17f, 0.07f, 0.17f, 0.07f }, new float[] { -0.4f, -0.4f, -0.4f, -0.4f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Male, BodyPartDefOf.Neck), new values(new float[] { 0f, -0.07f, 0f, 0.07f }, new float[] { 0.06f, 0.06f, 0.06f, 0.06f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Male, BodyPartDefOf.Torso), new values(new float[] { 0f, -0.05f, 0f, 0.05f }, new float[] { -0.20f, -0.25f, -0.25f, -0.25f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Male, genitalsDef), new values(new float[] { 0f, -0.07f, 0f, 0.07f }, new float[] { 0, -0.35f, -0.42f, -0.35f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Male, anusDef), new values(new float[] { 0, 0.17f, 0, -0.17f }, new float[] { -0.42f, -0.35f, 0, -0.35f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Male, chestDef), new values(new float[] { 0f, -0.16f, 0f, 0.16f }, new float[] { -0.06f, -0.05f, -0.06f, -0.05f })); + + //BodyType Hulk + splatchAdjust.Add(new key(BodyTypeDefOf.Hulk, BodyPartDefOf.Arm), new values(new float[] { -0.3f, 0.05f, 0.3f, 0.05f }, new float[] { 0f, -0.02f, 0f, -0.02f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Hulk, BodyPartDefOf.Hand), new values(new float[] { -0.22f, 0.07f, 0.22f, 0.07f }, new float[] { -0.28f, -0.28f, -0.28f, -0.28f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Hulk, BodyPartDefOf.Head), new values(new float[] { 0f, -0.23f, 0f, 0.23f }, new float[] { 0.37f, 0.35f, 0.33f, 0.35f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Hulk, BodyPartDefOf.Jaw), new values(new float[] { 0f, -0.19f, 0f, 0.19f }, new float[] { 0.15f, 0.15f, 0.15f, 0.15f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Hulk, BodyPartDefOf.Leg), new values(new float[] { -0.17f, 0.07f, 0.17f, 0.07f }, new float[] { -0.5f, -0.5f, -0.5f, -0.5f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Hulk, BodyPartDefOf.Neck), new values(new float[] { 0f, -0.07f, 0f, 0.07f }, new float[] { 0.06f, 0.06f, 0.06f, 0.06f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Hulk, BodyPartDefOf.Torso), new values(new float[] { 0f, -0.05f, 0f, 0.05f }, new float[] { -0.20f, -0.3f, -0.3f, -0.3f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Hulk, genitalsDef), new values(new float[] { 0f, -0.02f, 0f, 0.02f }, new float[] { 0, -0.55f, -0.55f, -0.55f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Hulk, anusDef), new values(new float[] { 0, 0.35f, 0, -0.35f }, new float[] { -0.5f, -0.5f, 0, -0.5f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Hulk, chestDef), new values(new float[] { 0f, -0.22f, 0f, 0.22f }, new float[] { -0.06f, -0.05f, -0.06f, -0.05f })); + + //BodyType Fat + splatchAdjust.Add(new key(BodyTypeDefOf.Fat, BodyPartDefOf.Arm), new values(new float[] { -0.3f, 0.05f, 0.3f, 0.05f }, new float[] { 0f, -0.02f, 0f, -0.02f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Fat, BodyPartDefOf.Hand), new values(new float[] { -0.32f, 0.07f, 0.32f, 0.07f }, new float[] { -0.28f, -0.28f, -0.28f, -0.28f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Fat, BodyPartDefOf.Head), new values(new float[] { 0f, -0.23f, 0f, 0.23f }, new float[] { 0.37f, 0.35f, 0.33f, 0.35f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Fat, BodyPartDefOf.Jaw), new values(new float[] { 0f, -0.19f, 0f, 0.19f }, new float[] { 0.15f, 0.15f, 0.15f, 0.15f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Fat, BodyPartDefOf.Leg), new values(new float[] { -0.17f, 0.07f, 0.17f, 0.07f }, new float[] { -0.45f, -0.45f, -0.45f, -0.45f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Fat, BodyPartDefOf.Neck), new values(new float[] { 0f, -0.07f, 0f, 0.07f }, new float[] { 0.06f, 0.06f, 0.06f, 0.06f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Fat, BodyPartDefOf.Torso), new values(new float[] { 0f, -0.15f, 0f, 0.15f }, new float[] { -0.20f, -0.3f, -0.3f, -0.3f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Fat, genitalsDef), new values(new float[] { 0f, -0.25f, 0f, 0.25f }, new float[] { 0, -0.45f, -0.50f, -0.45f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Fat, anusDef), new values(new float[] { 0, 0.35f, 0, -0.35f }, new float[] { -0.5f, -0.4f, 0, -0.4f })); + splatchAdjust.Add(new key(BodyTypeDefOf.Fat, chestDef), new values(new float[] { 0f, -0.27f, 0f, 0.27f }, new float[] { -0.07f, -0.05f, -0.07f, -0.05f })); + + + //now for the layer/plane adjustments: + layerAdjust = new Dictionary(); + + //left body parts: + //in theory, all body parts not coming in pairs should have the bool as false -> be listed as right, so I wouldn't need to add them here, but it doesn't hurt to be safe + layerAdjust.Add(new key_layer(true, BodyPartDefOf.Arm), new values_layer(new float[] { 0f, -99f, 0f, 0f }));//0.00 = drawn over body (=visible) if the pawn looks in any direction except west, in which case it's hidden (-99) + layerAdjust.Add(new key_layer(true, BodyPartDefOf.Hand), new values_layer(new float[] { 0f, -99f, 0f, 0f })); + layerAdjust.Add(new key_layer(true, BodyPartDefOf.Leg), new values_layer(new float[] { 0f, -99f, 0f, 0f })); + + layerAdjust.Add(new key_layer(true, BodyPartDefOf.Head), new values_layer(new float[] { 0.02f, 0.02f, 0.02f, 0.02f }));//drawn from all directions, 0.02 = over hair + layerAdjust.Add(new key_layer(true, BodyPartDefOf.Jaw), new values_layer(new float[] { -9f, 0.01f, 0.01f, 0.01f }));//0.01 = drawn over head but under hair, only hidden if facing north + layerAdjust.Add(new key_layer(true, BodyPartDefOf.Neck), new values_layer(new float[] { 0f, 0f, 0f, 0f })); + layerAdjust.Add(new key_layer(true, BodyPartDefOf.Torso), new values_layer(new float[] { 0f, 0f, 0f, 0f })); + layerAdjust.Add(new key_layer(true, genitalsDef), new values_layer(new float[] { -99f, 0f, 0f, 0f }));//only hidden if facing north + layerAdjust.Add(new key_layer(true, anusDef), new values_layer(new float[] { 0f, 0f, -99f, 0f })); + layerAdjust.Add(new key_layer(true, chestDef), new values_layer(new float[] { -99f, 0f, 0f, 0f })); + + //right body parts: + layerAdjust.Add(new key_layer(false, BodyPartDefOf.Arm), new values_layer(new float[] { 0f, 0f, 0f, -99f })); + layerAdjust.Add(new key_layer(false, BodyPartDefOf.Hand), new values_layer(new float[] { 0f, 0f, 0f, -99f })); + layerAdjust.Add(new key_layer(false, BodyPartDefOf.Leg), new values_layer(new float[] { 0f, 0f, 0f, -99f })); + + layerAdjust.Add(new key_layer(false, BodyPartDefOf.Head), new values_layer(new float[] { 0.02f, 0.02f, 0.02f, 0.02f })); + layerAdjust.Add(new key_layer(false, BodyPartDefOf.Jaw), new values_layer(new float[] { -99f, 0.01f, 0.01f, 0.01f })); + layerAdjust.Add(new key_layer(false, BodyPartDefOf.Neck), new values_layer(new float[] { 0f, 0f, 0f, 0f })); + layerAdjust.Add(new key_layer(false, BodyPartDefOf.Torso), new values_layer(new float[] { 0f, 0f, 0f, 0f })); + layerAdjust.Add(new key_layer(false, genitalsDef), new values_layer(new float[] { -99f, 0f, 0f, 0f })); + layerAdjust.Add(new key_layer(false, anusDef), new values_layer(new float[] { 0f, 0f, -99f, 0f })); + layerAdjust.Add(new key_layer(false, chestDef), new values_layer(new float[] { -99f, 0f, 0f, 0f })); + + } + + //all body parts that cum can theoretically be applied to: + public static List getAllowedBodyParts() + { + List allowedParts = new List(); + + allowedParts.Add(BodyPartDefOf.Arm); + allowedParts.Add(BodyPartDefOf.Hand); + allowedParts.Add(BodyPartDefOf.Leg); + allowedParts.Add(BodyPartDefOf.Head); + allowedParts.Add(BodyPartDefOf.Jaw); + allowedParts.Add(BodyPartDefOf.Neck); + allowedParts.Add(BodyPartDefOf.Torso); + allowedParts.Add(genitalsDef); + allowedParts.Add(anusDef); + allowedParts.Add(chestDef); + + return allowedParts; + } + + //get valid body parts for a specific pawn + public static IEnumerable getAvailableBodyParts(Pawn pawn) + { + //get all non-missing body parts: + IEnumerable bodyParts = pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Outside, null, null); + BodyPartRecord anus = pawn.def.race.body.AllParts.Find(bpr => string.Equals(bpr.def.defName, "Anus"));//not found by above function since depth is "inside" + + if (anus != null) + { + bodyParts = bodyParts.AddItem(anus); + } + + //filter for allowed body parts (e.g. no single fingers/toes): + List filterParts = CumHelper.getAllowedBodyParts(); + + IEnumerable filteredParts = bodyParts.Where(item1 => filterParts.Any(item2 => item2.Equals(item1.def))); + return filteredParts; + } + + + public const int CUM_NORMAL = 0; + public const int CUM_INSECT = 1; + public const int CUM_MECHA = 2; + + public static readonly Color color_normal = new Color(0.95f, 0.95f, 0.95f); + public static readonly Color color_insect = new Color(0.6f, 0.83f, 0.35f);//green-yellowish + public static readonly Color color_mecha = new Color(0.37f, 0.71f, 0.82f);//cyan-ish + + //name should be self-explanatory: + public static void cumOn(Pawn receiver, BodyPartRecord bodyPart, float amount = 0.2f, Pawn giver = null, int cumType = CUM_NORMAL) + { + Hediff_Cum hediff; + if (cumType == CUM_NORMAL) + { + hediff = (Hediff_Cum)HediffMaker.MakeHediff(HediffDefOf.Hediff_Cum, receiver, null); + } + else if (cumType == CUM_INSECT) + { + hediff = (Hediff_Cum)HediffMaker.MakeHediff(HediffDefOf.Hediff_InsectSpunk, receiver, null); + } + else + { + hediff = (Hediff_Cum)HediffMaker.MakeHediff(HediffDefOf.Hediff_MechaFluids, receiver, null); + } + + hediff.Severity = amount;//if this body part is already maximally full -> spill over to other parts + + //idea: here, a log entry that can act as source could be linked to the hediff - maybe reuse the playlog entry of rjw: + hediff.cumType = cumType; + + try + { + //error when adding to missing part + receiver.health.AddHediff(hediff, bodyPart, null, null); + } + catch + { + + } + + //Log.Message(xxx.get_pawnname(receiver) + " cum amount" + amount); + //causes significant memory leak, fixx someday + //if (amount > 1f)//spillover in case of very large amounts: just apply hediff a second time + //{ + // Hediff_cum hediff2 = (Hediff_cum)HediffMaker.MakeHediff(hediff.def, receiver, null); + // hediff2.cumType = cumType; + // hediff2.Severity = amount - 1f; + // receiver.health.AddHediff(hediff2, bodyPart, null, null); + //} + + //always also add cumcontroller hediff as manager + receiver.health.AddHediff(HediffDefOf.Hediff_CumController); + } + + //if spunk on one body part reaches a certain level, it can spill over to others, this function returns from where to where + //[SyncMethod] + public static BodyPartDef spillover(BodyPartDef sourcePart) + { + //caution: danger of infinite loop if circular spillover between 2 full parts -> don't define possible circles + BodyPartDef newPart = null; + int sel; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); + if (sourcePart == BodyPartDefOf.Torso) + { + sel = Rand.Range(0, 4); + if (sel == 0) + { + newPart = BodyPartDefOf.Arm; + } + else if (sel == 1) + { + newPart = BodyPartDefOf.Leg; + } + else if (sel == 2) + { + newPart = BodyPartDefOf.Neck; + } + else if (sel == 3) + { + newPart = chestDef; + } + } + else if (sourcePart == BodyPartDefOf.Jaw) + { + sel = Rand.Range(0, 4); + if (sel == 0) + { + newPart = BodyPartDefOf.Head; + } + else if (sel == 1) + { + newPart = BodyPartDefOf.Torso; + } + else if (sel == 2) + { + newPart = BodyPartDefOf.Neck; + } + else if (sel == 3) + { + newPart = chestDef; + } + } + else if (sourcePart == genitalsDef) + { + sel = Rand.Range(0, 2); + if (sel == 0) + { + newPart = BodyPartDefOf.Leg; + } + else if (sel == 1) + { + newPart = BodyPartDefOf.Torso; + } + } + else if (sourcePart == anusDef) + { + sel = Rand.Range(0, 2); + if (sel == 0) + { + newPart = BodyPartDefOf.Leg; + } + else if (sel == 1) + { + newPart = BodyPartDefOf.Torso; + } + } + else if (sourcePart == chestDef) + { + sel = Rand.Range(0, 3); + if (sel == 0) + { + newPart = BodyPartDefOf.Arm; + } + else if (sel == 1) + { + newPart = BodyPartDefOf.Torso; + } + else if (sel == 2) + { + newPart = BodyPartDefOf.Neck; + } + } + return newPart; + } + + //determines who is the active male (or equivalent) in the exchange and the amount of cum dispensed and where to + //[SyncMethod] + public static void calculateAndApplyCum(SexProps props) + { + if (!CumBase.cum_on_body) return; + Pawn pawn = props.pawn; + Pawn partner = props.partner; + + Pawn giver, receiver; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); + + List giverparts; + List pawnparts = pawn.GetGenitalsList(); + List partnerparts = partner != pawn ? partner.GetGenitalsList(): null; // masturbation + + //dispenser of the seed + if (xxx.is_mechanoid(pawn) || Genital_Helper.has_penis_fertile(pawn, pawnparts) || Genital_Helper.has_ovipositorF(pawn, pawnparts)) + { + giver = pawn; + giverparts = pawnparts; + receiver = partner; + } + else if (partner != null && props.isCoreLovin && (xxx.is_mechanoid(partner) || Genital_Helper.has_penis_fertile(partner, partnerparts) || Genital_Helper.has_ovipositorF(partner, partnerparts))) + { + giver = partner; + giverparts = partnerparts; + receiver = pawn; + } + else//female on female or genderless - no cum dispensed; maybe add futa support? + { + return; + } + + //slimes do not waste fluids? + //if (xxx.is_slime(giver)) return; + + //determine entity: + int entityType = CumHelper.CUM_NORMAL; + if (xxx.is_mechanoid(giver)) + { + entityType = CumHelper.CUM_MECHA; + } + else if (xxx.is_insect(giver)) + { + entityType = CumHelper.CUM_INSECT; + } + + //ModLog.Message("giver " + xxx.get_pawnname(giver)); + //ModLog.Message("receiver " + xxx.get_pawnname(receiver)); + //ModLog.Message("Cumtype " + entityType); + + //get pawn genitalia: + BodyPartRecord genitals; + if (xxx.is_mechanoid(giver)) + { + genitals = giver.RaceProps.body.AllParts.Find(x => string.Equals(x.def.defName, "MechGenitals")); + } + else//insects, animals, humans + { + genitals = giver.RaceProps.body.AllParts.Find(x => x.def == CumHelper.genitalsDef); + + } + //no cum without genitals + if (genitals == null) + { + return; + } + + float cumAmount = giver.BodySize; //fallback for mechanoinds and w/e without hediffs + float horniness = 1f; + float ageScale = Math.Min(80 / SexUtility.ScaleToHumanAge(giver), 1.0f);//calculation lifted from rjw + + if (xxx.is_mechanoid(giver) && giverparts.NullOrEmpty()) + { + //use default above + } + else if (giverparts.NullOrEmpty()) + return; + else + { + var penisHediff = giverparts.FindAll((Hediff hed) => hed.def.defName.ToLower().Contains("penis")).InRandomOrder().FirstOrDefault(); + + if (penisHediff == null) + penisHediff = giverparts.FindAll((Hediff hed) => hed.def.defName.ToLower().Contains("ovipositorf")).InRandomOrder().FirstOrDefault(); + if (penisHediff == null) + penisHediff = giverparts.FindAll((Hediff hed) => hed.def.defName.ToLower().Contains("ovipositorm")).InRandomOrder().FirstOrDefault(); + if (penisHediff == null) + penisHediff = giverparts.FindAll((Hediff hed) => hed.def.defName.ToLower().Contains("tentacle")).InRandomOrder().FirstOrDefault(); + + if (penisHediff != null) + { + cumAmount = penisHediff.Severity * giver.BodySize; + + CompHediffBodyPart chdf = penisHediff.TryGetComp(); + if (chdf != null) + { + if (chdf.FluidAmmount != 0) + cumAmount = chdf.FluidAmmount * chdf.FluidModifier; + } + //ModLog.Message("cumAmount base " + cumAmount); + + Need sexNeed = giver?.needs?.AllNeeds.Find(x => string.Equals(x.def.defName, "Sex")); + if (sexNeed != null)//non-humans don't have it - therefore just use the default value + { + horniness = 1f - sexNeed.CurLevel; + } + } + else + { + //something is wrong... vagina? + return; + } + } + + cumAmount *= CumBase.cum_on_body_amount; + //ModLog.Message("cumAmount after cum_on_body_amount_adjust after " + cumAmount); + cumAmount *= horniness; + //ModLog.Message("cumAmount after horniness mod " + cumAmount); + cumAmount *= ageScale; + //ModLog.Message("cumAmount after ageScale mod " + cumAmount); + cumAmount /= 10; + //ModLog.Message("cumAmount final " + cumAmount); + + //TODO: cumHelper Autofellatio + //if no partner -> masturbation, apply some cum on self: + //if (partner == null && sextype == xxx.rjwSextype.Autofellatio) + //{ + // if (!xxx.is_slime(giver)) + // cumHelper.cumOn(giver, BodyPartDefOf.Jaw, cumAmount, giver); + // return; + //} + if (props.sexType == xxx.rjwSextype.Masturbation) + { + if (!xxx.is_slime(giver)) + CumHelper.cumOn(giver, genitals, cumAmount * 0.3f, giver);//pawns are usually not super-messy -> only apply 30% + return; + } + else if (receiver != null) + { + List targetParts = new List();//which to apply cum on + IEnumerable availableParts = CumHelper.getAvailableBodyParts(receiver); + BodyPartRecord randomPart;//not always needed + + switch (props.sexType) + { + case rjw.xxx.rjwSextype.Anal: + targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == CumHelper.anusDef)); + break; + case rjw.xxx.rjwSextype.Boobjob: + targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == CumHelper.chestDef)); + break; + case rjw.xxx.rjwSextype.DoublePenetration: + targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == CumHelper.anusDef)); + targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == CumHelper.genitalsDef)); + break; + case rjw.xxx.rjwSextype.Fingering: + cumAmount = 0; + break; + case rjw.xxx.rjwSextype.Fisting: + cumAmount = 0; + break; + case rjw.xxx.rjwSextype.Footjob: + //random part: + availableParts.TryRandomElement(out randomPart); + targetParts.Add(randomPart); + break; + case rjw.xxx.rjwSextype.Handjob: + //random part: + availableParts.TryRandomElement(out randomPart); + targetParts.Add(randomPart); + break; + case rjw.xxx.rjwSextype.Masturbation: + cumAmount *= 2f; + break; + case rjw.xxx.rjwSextype.MechImplant: + //one of the openings: + int random = Rand.Range(0, 3); + if (random == 0) + { + targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == CumHelper.genitalsDef)); + } + else if (random == 1) + { + targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == CumHelper.anusDef)); + } + else if (random == 2) + { + targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == BodyPartDefOf.Jaw)); + } + break; + case rjw.xxx.rjwSextype.MutualMasturbation: + //random + availableParts.TryRandomElement(out randomPart); + targetParts.Add(randomPart); + break; + case rjw.xxx.rjwSextype.None: + cumAmount = 0; + break; + case rjw.xxx.rjwSextype.Oral: + targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == BodyPartDefOf.Jaw)); + break; + case rjw.xxx.rjwSextype.Scissoring: + //I guess if it came to here, a male must be involved? + targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == CumHelper.genitalsDef)); + break; + case rjw.xxx.rjwSextype.Vaginal: + targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == CumHelper.genitalsDef)); + break; + } + + if (cumAmount > 0) + { + if (receiver != null && xxx.is_slime(receiver)) + { + //slime absorb cum + //this needs balancing, since cumamount ranges 0-10(?) which is fine for cum/hentai but not very realistic for feeding + //using TransferNutrition for now + //Log.Message("cumAmount " + cumAmount); + //float nutrition_amount = cumAmount/10; + + Need_Food need = need = giver.needs.TryGetNeed(); + if (need == null) + { + //Log.Message("xxx::TransferNutrition() " + xxx.get_pawnname(pawn) + " doesn't track nutrition in itself, probably shouldn't feed the others"); + return; + } + + if (receiver?.needs?.TryGetNeed() != null) + { + //Log.Message("xxx::TransferNutrition() " + xxx.get_pawnname(partner) + " can receive"); + float nutrition_amount = Math.Min(need.MaxLevel / 15f, need.CurLevel); //body size is taken into account implicitly by need.MaxLevel + receiver.needs.food.CurLevel += nutrition_amount; + } + } + else + { + CumHelper.cumOn(giver, genitals, cumAmount * 0.3f, giver, entityType);//cum on self - smaller amount + if (receiver != null) + foreach (BodyPartRecord bpr in targetParts) + { + if (bpr != null) + { + CumHelper.cumOn(receiver, bpr, cumAmount, giver, entityType);//cum on partner + } + } + } + } + } + } + + } +} diff --git a/1.4/Source/Mod/DefOf/HediffDefOf.cs b/1.4/Source/Mod/DefOf/HediffDefOf.cs new file mode 100644 index 0000000..46e8255 --- /dev/null +++ b/1.4/Source/Mod/DefOf/HediffDefOf.cs @@ -0,0 +1,17 @@ +using RimWorld; +using Verse; + +namespace rjwcum +{ + [DefOf] + public static class HediffDefOf + { + public static HediffDef Hediff_Cum;//for humans & animals + public static HediffDef Hediff_InsectSpunk; + public static HediffDef Hediff_MechaFluids; + + public static HediffDef Hediff_CumController;//cum hediff manager + + } + +} diff --git a/1.4/Source/Mod/DefOf/JobDefOf.cs b/1.4/Source/Mod/DefOf/JobDefOf.cs new file mode 100644 index 0000000..f8569e6 --- /dev/null +++ b/1.4/Source/Mod/DefOf/JobDefOf.cs @@ -0,0 +1,11 @@ +using RimWorld; +using Verse; + +namespace rjwcum +{ + [DefOf] + public static class JobDefOf + { + public static JobDef CleanSelf; + } +} diff --git a/1.4/Source/Mod/Hediffs/Hediff_Cum.cs b/1.4/Source/Mod/Hediffs/Hediff_Cum.cs new file mode 100644 index 0000000..7652b64 --- /dev/null +++ b/1.4/Source/Mod/Hediffs/Hediff_Cum.cs @@ -0,0 +1,155 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Verse; +using UnityEngine; +//using Multiplayer.API; + +namespace rjwcum +{ + public class Hediff_Cum : HediffWithComps + { + public int cumType = CumHelper.CUM_NORMAL;//-> different colors + + public string giverName = null;//not utilized right now, maybe in the future save origin of the cum + + public override string LabelInBrackets + { + get + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append(base.LabelInBrackets); + if (this.sourceHediffDef != null) + { + if (stringBuilder.Length != 0) + { + stringBuilder.Append(", "); + } + stringBuilder.Append(this.sourceHediffDef.label); + } + else if (this.source != null) + { + if (stringBuilder.Length != 0) + { + stringBuilder.Append(", "); + } + stringBuilder.Append(this.source.label); + if (this.sourceBodyPartGroup != null) + { + stringBuilder.Append(" "); + stringBuilder.Append(this.sourceBodyPartGroup.LabelShort); + } + } + return stringBuilder.ToString(); + } + } + + + public override string SeverityLabel + { + get + { + if (this.Severity == 0f) + { + return null; + } + return this.Severity.ToString("F1"); + } + } + + //[SyncMethod] + public override bool TryMergeWith(Hediff other) + { + //if a new cum hediff is added to the same body part, they are combined. if severity reaches more than 1, spillover to other body parts occurs + + Hediff_Cum hediff_cum = other as Hediff_Cum; + if (hediff_cum != null && hediff_cum.def == this.def && hediff_cum.Part == base.Part && this.def.injuryProps.canMerge) + { + cumType = hediff_cum.cumType;//take over new creature color + + float totalAmount = hediff_cum.Severity + this.Severity; + if (totalAmount > 1.0f) + { + BodyPartDef spillOverTo = CumHelper.spillover(this.Part.def);//cumHelper saves valid other body parts for spillover + if (spillOverTo != null) + { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); + IEnumerable availableParts = CumHelper.getAvailableBodyParts(pawn);//gets all non missing, valid body parts + IEnumerable filteredParts = availableParts.Where(x => x.def == spillOverTo);//filters again for valid spill target + if (!filteredParts.EnumerableNullOrEmpty()) + { + BodyPartRecord spillPart = null; + spillPart = filteredParts.RandomElement();//then pick one + if (spillPart != null) + { + CumHelper.cumOn(pawn, spillPart, totalAmount - this.Severity, null, cumType); + } + } + } + } + + return (base.TryMergeWith(other)); + + } + return (false); + } + + public override void ExposeData() + { + base.ExposeData(); + Scribe_Values.Look(ref cumType, "cumType", CumHelper.CUM_NORMAL); + + if (Scribe.mode == LoadSaveMode.PostLoadInit && base.Part == null) + { + //Log.Error("Hediff_cum has null part after loading.", false); + this.pawn.health.hediffSet.hediffs.Remove(this); + return; + } + } + + //handles the icon in the health tab and its color + public override TextureAndColor StateIcon + { + get + { + TextureAndColor tex = TextureAndColor.None; + Color color = Color.white; + switch (cumType) + { + case CumHelper.CUM_NORMAL: + color = CumHelper.color_normal; + break; + case CumHelper.CUM_INSECT: + color = CumHelper.color_insect; + break; + case CumHelper.CUM_MECHA: + color = CumHelper.color_mecha; + break; + } + + Texture2D tex2d = CumTextures.CumIcon_little; + switch (this.CurStageIndex) + { + case 0: + tex2d = CumTextures.CumIcon_little; + break; + case 1: + tex2d = CumTextures.CumIcon_some; + break; + case 2: + tex2d = CumTextures.CumIcon_dripping; + break; + case 3: + tex2d = CumTextures.CumIcon_drenched; + break; + } + + tex = new TextureAndColor(tex2d, color); + + return tex; + } + } + + } +} diff --git a/1.4/Source/Mod/Hediffs/Hediff_CumController.cs b/1.4/Source/Mod/Hediffs/Hediff_CumController.cs new file mode 100644 index 0000000..a3a3224 --- /dev/null +++ b/1.4/Source/Mod/Hediffs/Hediff_CumController.cs @@ -0,0 +1,272 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Verse; +using RimWorld; +using UnityEngine; +//using Multiplayer.API; + +namespace rjwcum +{ + class Hediff_CumController : HediffWithComps + { + /* + Whenever cum is applied, this hediff is also added to the pawn. + Since there is always only a single hediff of this type on the pawn, it serves as master controller, adding up the individual cum hediffs, applying debuffs and drawing overlays + */ + + private static readonly float cumWeight = 0.2f;//how much individual cum_hediffs contribute to the overall bukkake severity + List hediffs_cum; + Dictionary splatches; + + public override void ExposeData() + { + base.ExposeData(); + //Scribe_Values.Look>(ref splatches, "splatches", new Dictionary()); - causes errors when loading. for now, just make a new dictionary + splatches = new Dictionary();//instead of loading, just recreate anew + hediffs_cum = new List(); + } + + public override void PostMake() + { + base.PostMake(); + splatches = new Dictionary(); + } + + public override void PostTick() + { + if (pawn.RaceProps.Humanlike)//for now, only humans are supported + { + hediffs_cum = this.pawn.health.hediffSet.hediffs.FindAll(x => (x.def == HediffDefOf.Hediff_Cum || x.def == HediffDefOf.Hediff_InsectSpunk || x.def == HediffDefOf.Hediff_MechaFluids)); + float Level = CalculateLevel();//sum of severity of all the cum hediffs x cumWeight + this.Severity = Level; + bool updatePortrait = false; + + //loop through all cum hediffs, add missing ones to dictionary + for (int i = 0; i < hediffs_cum.Count(); i++) + { + Hediff_Cum h = (Hediff_Cum)hediffs_cum[i]; + string ID = h.GetUniqueLoadID();//unique ID for each hediff + if (!splatches.ContainsKey(ID))//if it isn't here yet, make new object + { + updatePortrait = true; + bool leftSide = h.Part.Label.Contains("left") ? true : false;//depending on whether the body part is left or right, drawing-offset on x-aixs may be inverted + + splatches[ID] = new CumSplatch(h, pawn.story.bodyType, h.Part.def, leftSide, h.cumType); + } + } + + + + //remove splatch objects once their respective cum hediff is gone + List removeKeys = new List(); + foreach (string key in splatches.Keys) + { + CumSplatch s = splatches[key]; + + if (!hediffs_cum.Contains(s.hediff_cum)) + { + removeKeys.Add(key); + updatePortrait = true; + } + } + //loop over and remove elements that should be destroyed: + foreach (string key in removeKeys) + { + CumSplatch s = splatches[key]; + splatches.Remove(key); + } + + if (updatePortrait)//right now, portraits are only updated when a completely new cum hediff is added or an old one removed - maybe that should be done more frequently + { + PortraitsCache.SetDirty(pawn); + } + } + } + + //called from the PawnWoundDrawer (see HarmonyPatches) + public void DrawCum(Vector3 drawLoc, Quaternion quat, bool forPortrait, float angle, bool inBed = false) + { + Rot4 bodyFacing = pawn.Rotation; + int facingDir = bodyFacing.AsInt;//0: north, 1:east, 2:south, 3:west + foreach (string key in splatches.Keys) + { + CumSplatch s = splatches[key]; + s.Draw(drawLoc, quat, forPortrait, facingDir, angle, inBed); + } + } + + //new Hediff_CumController added to pawn -> just combine the two + public override bool TryMergeWith(Hediff other) + { + if (other == null || other.def != this.def) + { + return false; + } + return true; + } + + private float CalculateLevel() + { + float num = 0f; + for (int i = 0; i < hediffs_cum.Count; i++) + { + num += hediffs_cum[i].Severity * cumWeight; + } + return num; + } + + //class for handling drawing of the individual splatches + private class CumSplatch + { + public readonly Hediff_Cum hediff_cum; + public readonly Material cumMaterial; + public readonly BodyPartDef bodyPart; + private bool mirrorMesh; + + private const float maxSize = 0.20f;//1.0 = 1 tile + private const float minSize = 0.05f; + + //data taken from CumHelper.cs: + private readonly float[] xAdjust; + private readonly float[] zAdjust; + private readonly float[] yAdjust; + + public CumSplatch(Hediff_Cum hediff, BodyTypeDef bodyType, BodyPartDef bodyPart, bool leftSide = false, int cumType = CumHelper.CUM_NORMAL) + { + hediff_cum = hediff; + cumMaterial = new Material(CumTextures.pickRandomSplatch());//needs to create new material in order to allow for different colors + cumMaterial.SetTextureScale("_MainTex", new Vector2(-1, 1)); + this.bodyPart = bodyPart; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); + + //set color: + switch (cumType) + { + case CumHelper.CUM_NORMAL: + cumMaterial.color = CumHelper.color_normal; + break; + case CumHelper.CUM_INSECT: + cumMaterial.color = CumHelper.color_insect; + break; + case CumHelper.CUM_MECHA: + cumMaterial.color = CumHelper.color_mecha; + break; + } + + //if (!MP.enabled) + mirrorMesh = (Rand.Value > 0.5f);//in 50% of the cases, flip mesh horizontally for more variance + + //x,y,z adjustments to draw splatches over the approximately correct locations; values stored in Cum helper - accessed by unique combinations of bodyTypes and bodyParts + CumHelper.key k = new CumHelper.key(bodyType, bodyPart); + if (CumHelper.splatchAdjust.Keys.Contains(k)) + { + CumHelper.values helperValues = CumHelper.splatchAdjust[k]; + + //invert, x-adjust (horizontal) depending on left/right body side: + if (!leftSide) + { + float[] xAdjTemp = new float[4]; + for (int i = 0; i < xAdjTemp.Length; i++) + { + xAdjTemp[i] = helperValues.x[i] * -1f; + } + xAdjust = xAdjTemp; + } + else + { + xAdjust = helperValues.x; + } + + zAdjust = helperValues.z;//vertical adjustment + + } + else//fallback in the the key can't be found + { + //if (RJWSettings.DevMode) + //{ + // ModLog.Message("created cum splatch for undefined body type or part. BodyType: " + bodyType + " , BodyPart: " + bodyPart); + //} + xAdjust = new float[] { 0f, 0f, 0f, 0f }; + zAdjust = new float[] { 0f, 0f, 0f, 0f }; + } + + + //y adjustments: plane/layer of drawing, > 0 -> above certain objects, < 0 -> below + CumHelper.key_layer k2 = new CumHelper.key_layer(leftSide, bodyPart); + + if (CumHelper.layerAdjust.Keys.Contains(k2)) + { + CumHelper.values_layer helperValues_layer = CumHelper.layerAdjust[k2]; + yAdjust = helperValues_layer.y; + } + else + { + yAdjust = new float[] { 0.02f, 0.02f, 0.02f, 0.02f };//over body in every direction + } + + } + + public void Draw(Vector3 drawPos, Quaternion quat, bool forPortrait, int facingDir = 0, float angle = 0,bool inBed=false) + { + if (inBed) + { + if (this.bodyPart != BodyPartDefOf.Jaw && this.bodyPart != BodyPartDefOf.Head)//when pawn is in bed (=bed with sheets), only draw cum on head + { + return; + } + } + + //these two create new mesh instance and never destroying it, filling ram and crashing + //float size = minSize+((maxSize-minSize)*hediff_cum.Severity); + //mesh = MeshMakerPlanes.NewPlaneMesh(size); + + //use core MeshPool.plane025 instead + + //if (mirrorMesh)//horizontal flip + //{ + //mesh = flipMesh(mesh); + //} + + //rotation: + if (angle == 0)//normal situation (pawn standing upright) + { + drawPos.x += xAdjust[facingDir]; + drawPos.z += zAdjust[facingDir]; + } + else//if downed etc, more complex calculation becomes necessary + { + float radian = angle / 180 * (float)Math.PI; + radian = -radian; + drawPos.x += Mathf.Cos(radian) * xAdjust[hediff_cum.pawn.Rotation.AsInt] - Mathf.Sin(radian) * zAdjust[facingDir];//facingDir doesn't appear to be chosen correctly in all cases + drawPos.z += Mathf.Cos(radian) * zAdjust[hediff_cum.pawn.Rotation.AsInt] + Mathf.Sin(radian) * xAdjust[facingDir]; + } + + //drawPos.y += yAdjust[facingDir];// 0.00: over body; 0.01: over body but under face, 0.02: over face, but under hair, -99 = "never" visible + drawPos.y += yAdjust[facingDir]; + + GenDraw.DrawMeshNowOrLater(MeshPool.plane025, drawPos, quat, cumMaterial, forPortrait); + } + + //flips mesh UV horizontally, thereby mirroring the texture + private Mesh flipMesh(Mesh meshToFlip) + { + var uvs = meshToFlip.uv; + if (uvs.Length != 4) + { + return (meshToFlip); + } + for (var i = 0; i < uvs.Length; i++) + { + if (Mathf.Approximately(uvs[i].x, 1.0f)) + uvs[i].x = 0.0f; + else + uvs[i].x = 1.0f; + } + meshToFlip.uv = uvs; + return (meshToFlip); + } + } + } +} diff --git a/1.4/Source/Mod/JobDrivers/JobDriver_CleanSelf.cs b/1.4/Source/Mod/JobDrivers/JobDriver_CleanSelf.cs new file mode 100644 index 0000000..d1d4ce3 --- /dev/null +++ b/1.4/Source/Mod/JobDrivers/JobDriver_CleanSelf.cs @@ -0,0 +1,53 @@ +using RimWorld; +using System.Collections.Generic; +using Verse; +using Verse.AI; + +namespace rjwcum +{ + class JobDriver_CleanSelf : JobDriver + { + float cleanAmount = 1f;//severity of a single cumHediff removed per cleaning-round; 1f = remove entirely + int cleaningTime = 120;//ticks - 120 = 2 real seconds, 3 in-game minutes + + public override bool TryMakePreToilReservations(bool errorOnFailed) + { + return pawn.Reserve(pawn, job, 1, -1, null, errorOnFailed); + } + + protected override IEnumerable MakeNewToils() + { + this.FailOn(delegate + { + List hediffs = pawn.health.hediffSet.hediffs; + return !hediffs.Exists(x => x.def == HediffDefOf.Hediff_CumController);//fail if cum disappears - means that also all the cum is gone + }); + Toil cleaning = Toils_General.Wait(cleaningTime, TargetIndex.None);//duration of + cleaning.WithProgressBarToilDelay(TargetIndex.A); + + yield return cleaning; + yield return new Toil() + { + initAction = delegate () + { + //get one of the cum hediffs, reduce its severity + Hediff hediff = pawn.health.hediffSet.hediffs.Find(x => (x.def == HediffDefOf.Hediff_Cum || x.def == HediffDefOf.Hediff_InsectSpunk || x.def == HediffDefOf.Hediff_MechaFluids)); + if (hediff != null) + { + if (hediff.Severity >= 0.5) + { + if (hediff.def == HediffDefOf.Hediff_InsectSpunk) + { + Thing jelly = ThingMaker.MakeThing(ThingDefOf.InsectJelly); + jelly.SetForbidden(true, false); + GenPlace.TryPlaceThing(jelly, pawn.PositionHeld, pawn.MapHeld, ThingPlaceMode.Near); + } + } + hediff.Severity -= cleanAmount; + } + } + }; + yield break; + } + } +} diff --git a/1.4/Source/Mod/Patch_AddCumOnOrgasm.cs b/1.4/Source/Mod/Patch_AddCumOnOrgasm.cs new file mode 100644 index 0000000..a348076 --- /dev/null +++ b/1.4/Source/Mod/Patch_AddCumOnOrgasm.cs @@ -0,0 +1,66 @@ +using Verse; +using HarmonyLib; +using rjw; +using System; +//using Multiplayer.API; + +namespace rjwcum +{ + /// + ///apply cum to pawn after vanilla sex + /// + [HarmonyPatch(typeof(SexUtility), "Aftersex")] + [StaticConstructorOnStartup] + static class Aftersex_Cum_Apply + { + [HarmonyPostfix] + private static void Aftersex_Cum_Patch(SexProps props) + { + try + { + if (props.isCoreLovin) + if (!props.usedCondom) + { + CumHelper.calculateAndApplyCum(props); + //SexUtility.CumFilthGenerator(props.pawn); + //SexUtility.CumFilthGenerator(props.partner); + } + } + catch (Exception e) + { + Log.Error(e.ToString()); + } + } + } + + /// + ///apply cum to pawn after rjw orgasm + /// + [HarmonyPatch(typeof(JobDriver_Sex), "Orgasm")] + [StaticConstructorOnStartup] + static class Orgasm_Cum_Apply + { + [HarmonyPrefix] + private static bool Orgasm_Cum_Patch(JobDriver_Sex __instance) + { + try + { + if (__instance.sex_ticks > __instance.orgasmstick) //~3s at speed 1 + { + return true; + } + var props = __instance.Sexprops; + if (!props.usedCondom) + { + CumHelper.calculateAndApplyCum(props); + //SexUtility.CumFilthGenerator(props.pawn); + } + } + catch (Exception e) + { + Log.Error(e.ToString()); + } + return true; + } + } +} diff --git a/1.4/Source/Mod/Patch_AddGizmo.cs b/1.4/Source/Mod/Patch_AddGizmo.cs new file mode 100644 index 0000000..e995f01 --- /dev/null +++ b/1.4/Source/Mod/Patch_AddGizmo.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using Verse; +using HarmonyLib; +using rjw; +//using Multiplayer.API; + +namespace rjwcum +{ + //adds new gizmo for adding cum for testing + [HarmonyPatch(typeof(Pawn), "GetGizmos")] + class Patch_AddGizmo + { + [HarmonyPriority(99),HarmonyPostfix] + static IEnumerable AddCum_test(IEnumerable __result, Pawn __instance) + { + + foreach (Gizmo entry in __result) + { + yield return entry; + } + + if (Prefs.DevMode )//&& RJWSettings.DevMode && !MP.IsInMultiplayer) + { + Command_Action addCum = new Command_Action(); + addCum.defaultDesc = "AddCumHediff"; + addCum.defaultLabel = "AddCum"; + addCum.action = delegate () + { + AddCum(__instance); + }; + + yield return addCum; + } + } + + //[SyncMethod] + static void AddCum(Pawn pawn) + { + //Log.Message("add cum button is pressed for " + pawn); + + if (!pawn.Dead && pawn.records != null) + { + //get all acceptable body parts: + IEnumerable filteredParts = CumHelper.getAvailableBodyParts(pawn); + + //select random part: + BodyPartRecord randomPart; + //filteredParts.TryRandomElement(out randomPart); + //for testing - choose either genitals or anus: + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); + if (Rand.Value > 0.5f) + { + randomPart = pawn.RaceProps.body.AllParts.Find(x => x.def == xxx.anusDef); + } + else + { + randomPart = pawn.RaceProps.body.AllParts.Find(x => x.def == xxx.genitalsDef); + } + + if (randomPart != null) + { + CumHelper.cumOn(pawn, randomPart, 0.2f, null, CumHelper.CUM_NORMAL); + } + }; + } + } +} diff --git a/1.4/Source/Mod/Patch_JobDriver_DubsBadHygiene.cs b/1.4/Source/Mod/Patch_JobDriver_DubsBadHygiene.cs new file mode 100644 index 0000000..3ed4168 --- /dev/null +++ b/1.4/Source/Mod/Patch_JobDriver_DubsBadHygiene.cs @@ -0,0 +1,85 @@ +using System; +using HarmonyLib; +using Verse; +using Verse.AI; +using rjw; + +namespace rjwcum +{ + [HarmonyPatch(typeof(JobDriver), "Cleanup")] + internal static class Patch_JobDriver_DubsBadHygiene + { + //not very good solution, some other mod can have same named jobdriver but w/e + + //Dubs Bad Hygiene washing + private readonly static Type JobDriver_useWashBucket = AccessTools.TypeByName("JobDriver_useWashBucket"); + //private readonly static Type JobDriver_washAtCell = AccessTools.TypeByName("JobDriver_washAtCell"); + + private readonly static Type JobDriver_UseHotTub = AccessTools.TypeByName("JobDriver_UseHotTub"); + private readonly static Type JobDriver_takeShower = AccessTools.TypeByName("JobDriver_takeShower"); + private readonly static Type JobDriver_takeBath = AccessTools.TypeByName("JobDriver_takeBath"); + + [HarmonyPostfix] + private static void Cleanup_cum(JobDriver __instance, JobCondition condition) + { + try + { + if (__instance == null) + return; + + if (condition == JobCondition.Succeeded) + { + Do_cleanup_cum(__instance); + } + } + catch (Exception e) + { + Log.Error(e.ToString()); + } + } + + public static void Do_cleanup_cum(JobDriver __instance) + { + Pawn pawn = __instance.pawn; + + //ModLog.Message("patches_DubsBadHygiene::on_cleanup_driver" + xxx.get_pawnname(pawn)); + + if (xxx.DubsBadHygieneIsActive) + //clear one instance of cum + if ( + __instance.GetType() == JobDriver_useWashBucket// || + //__instance.GetType() == JobDriver_washAtCell + ) + { + Hediff hediff = pawn.health.hediffSet.hediffs.Find(x => (x.def == HediffDefOf.Hediff_Cum + || x.def == HediffDefOf.Hediff_InsectSpunk + || x.def == HediffDefOf.Hediff_MechaFluids + )); + if (hediff != null) + { + //ModLog.Message("patches_DubsBadHygiene::" + __instance.GetType() + " clear => " + hediff.Label); + hediff.Severity -= 1f; + } + } + //clear all instance of cum + else if ( + __instance.GetType() == JobDriver_UseHotTub || + __instance.GetType() == JobDriver_takeShower || + __instance.GetType() == JobDriver_takeBath + ) + { + foreach (Hediff hediff in pawn.health.hediffSet.hediffs) + { + if (hediff.def == HediffDefOf.Hediff_Cum || + hediff.def == HediffDefOf.Hediff_InsectSpunk || + hediff.def == HediffDefOf.Hediff_MechaFluids + ) + { + //ModLog.Message("patches_DubsBadHygiene::" + __instance.GetType() + " clear => " + hediff.Label); + hediff.Severity -= 1f; + } + } + } + } + } +} \ No newline at end of file diff --git a/1.4/Source/Mod/Patch_RenderOverBody.cs b/1.4/Source/Mod/Patch_RenderOverBody.cs new file mode 100644 index 0000000..1437182 --- /dev/null +++ b/1.4/Source/Mod/Patch_RenderOverBody.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +using Verse; +using HarmonyLib; +using UnityEngine; +using System; +using RimWorld; +//using Multiplayer.API; + +namespace rjwcum +{ + + [HarmonyPatch(typeof(RimWorld.PawnOverlayDrawer))] + [HarmonyPatch("RenderPawnOverlay")] + [HarmonyPatch(new Type[] { typeof(Vector3), typeof(Mesh), typeof(Quaternion), typeof(bool), typeof(PawnOverlayDrawer.OverlayLayer), typeof(Rot4), typeof(bool) })] + class Patch_RenderPawnOverlay + { + [HarmonyPostfix] + static void DrawCum(RimWorld.PawnOverlayDrawer __instance, Vector3 drawLoc, Mesh bodyMesh, Quaternion quat, bool drawNow, PawnOverlayDrawer.OverlayLayer layer, Rot4 pawnRot, bool? overApparel = null) + { + if (!CumBase.cum_overlays) return; + + Pawn pawn = Traverse.Create(__instance).Field("pawn").GetValue();//get local variable + + //TODO add support for animals? unlikely as they has weird meshes + //for now, only draw humans + if (pawn.RaceProps.Humanlike) //&& CumOverlayBase.cum_overlays) + { + //find cum hediff. if it exists, use its draw function + List hediffs = pawn.health.hediffSet.hediffs; + if (hediffs.Exists(x => x.def == HediffDefOf.Hediff_CumController)) + { + Hediff_CumController h = hediffs.Find(x => x.def == HediffDefOf.Hediff_CumController) as Hediff_CumController; + + quat.ToAngleAxis(out float angle, out Vector3 axis);//angle changes when pawn is e.g. downed + + //adjustments if the pawn is sleeping in a bed: + bool inBed = false; + Building_Bed building_Bed = pawn.CurrentBed(); + if (building_Bed != null) + { + inBed = !building_Bed.def.building.bed_showSleeperBody; + AltitudeLayer altLayer = (AltitudeLayer)Mathf.Max((int)building_Bed.def.altitudeLayer, 15); + Vector3 vector2 = pawn.Position.ToVector3ShiftedWithAltitude(altLayer); + vector2.y += 0.02734375f+0.01f;//just copied from rimworld code+0.01f + drawLoc.y = vector2.y; + } + + h.DrawCum(drawLoc, quat, layer == PawnOverlayDrawer.OverlayLayer.Head, angle); + } + } + + } + } +} diff --git a/1.4/Source/Mod/RimJobWorldCum.csproj b/1.4/Source/Mod/RimJobWorldCum.csproj new file mode 100644 index 0000000..6cff0eb --- /dev/null +++ b/1.4/Source/Mod/RimJobWorldCum.csproj @@ -0,0 +1,79 @@ + + + + + Debug + AnyCPU + {3FC2D442-19B8-4CF9-9D35-CD13B6AC7B28} + Library + rjwcum + RimJobWorldCum + v4.7.2 + 512 + + + AnyCPU + true + full + false + ..\..\Assemblies\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + ..\..\Assemblies\ + TRACE + prompt + 4 + + + + ..\packages\Lib.Harmony.2.2.2\lib\net472\0Harmony.dll + + + ..\..\..\..\..\RimWorldWin64_Data\Managed\Assembly-CSharp.dll + False + + + ..\..\..\..\..\..\..\workshop\content\294100\818773962\v1.4\Assemblies\HugsLib.dll + False + + + ..\..\..\..\rjw\1.4\Assemblies\RJW.dll + False + + + + + ..\..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.CoreModule.dll + False + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/1.4/Source/Mod/Textures.cs b/1.4/Source/Mod/Textures.cs new file mode 100644 index 0000000..6ec85f6 --- /dev/null +++ b/1.4/Source/Mod/Textures.cs @@ -0,0 +1,58 @@ +using Verse; +using UnityEngine; +//using Multiplayer.API; + +namespace rjwcum +{ + [StaticConstructorOnStartup] + public static class CumTextures + { + //UI: + public static readonly Texture2D CumIcon_little = ContentFinder.Get("CumIcon_little", true); + public static readonly Texture2D CumIcon_some = ContentFinder.Get("CumIcon_some", true); + public static readonly Texture2D CumIcon_dripping = ContentFinder.Get("CumIcon_dripping", true); + public static readonly Texture2D CumIcon_drenched = ContentFinder.Get("CumIcon_drenched", true); + + //on pawn: + public static readonly Material cumSplatch1 = MaterialPool.MatFrom("splatch_1", ShaderDatabase.Cutout); + public static readonly Material cumSplatch2 = MaterialPool.MatFrom("splatch_2", ShaderDatabase.Cutout); + public static readonly Material cumSplatch3 = MaterialPool.MatFrom("splatch_3", ShaderDatabase.Cutout); + public static readonly Material cumSplatch4 = MaterialPool.MatFrom("splatch_4", ShaderDatabase.Cutout); + public static readonly Material cumSplatch5 = MaterialPool.MatFrom("splatch_5", ShaderDatabase.Cutout); + public static readonly Material cumSplatch6 = MaterialPool.MatFrom("splatch_6", ShaderDatabase.Cutout); + public static readonly Material cumSplatch7 = MaterialPool.MatFrom("splatch_7", ShaderDatabase.Cutout); + public static readonly Material cumSplatch8 = MaterialPool.MatFrom("splatch_8", ShaderDatabase.Cutout); + public static readonly Material cumSplatch9 = MaterialPool.MatFrom("splatch_9", ShaderDatabase.Cutout); + + + //[SyncMethod] + public static Material pickRandomSplatch() + { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); + int rand = Rand.Range(0, 8); + switch (rand) + { + case 0: + return cumSplatch1; + case 1: + return cumSplatch2; + case 2: + return cumSplatch3; + case 3: + return cumSplatch4; + case 4: + return cumSplatch5; + case 5: + return cumSplatch6; + case 6: + return cumSplatch7; + case 7: + return cumSplatch8; + case 8: + return cumSplatch9; + } + return null; + } + } +} diff --git a/1.4/Source/Mod/WorkGivers/WorkGiver_CleanSelf.cs b/1.4/Source/Mod/WorkGivers/WorkGiver_CleanSelf.cs new file mode 100644 index 0000000..533b827 --- /dev/null +++ b/1.4/Source/Mod/WorkGivers/WorkGiver_CleanSelf.cs @@ -0,0 +1,76 @@ +using RimWorld; +using Verse; +using Verse.AI; +using rjw; + +namespace rjwcum +{ + public class WorkGiver_CleanSelf : WorkGiver_Scanner + { + public override PathEndMode PathEndMode + { + get + { + return PathEndMode.InteractionCell; + } + } + + public override Danger MaxPathDanger(Pawn pawn) + { + return Danger.Deadly; + } + + public override ThingRequest PotentialWorkThingRequest + { + get + { + return ThingRequest.ForGroup(ThingRequestGroup.Pawn); + } + } + + //conditions for self-cleaning job to be available + public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false) + { + if (xxx.DubsBadHygieneIsActive && CumBase.dubsDBH_block_CleanSelf) // selfclean only in shower/bath etc + return false; + + if (pawn != t) + return false; + + if (!pawn.CanReserve(t, 1, -1, null, forced)) + return false; + + if (pawn.IsDesignatedHero()) + { + if (!forced && CumBase.manual_hero_CleanSelf) + { + //ModLog.Message("WorkGiver_CleanSelf::not player interaction for hero, exit"); + return false; + } + if (!pawn.IsHeroOwner()) + { + //ModLog.Message("WorkGiver_CleanSelf::player interaction for not owned hero, exit"); + return false; + } + } + + Hediff hediff = pawn.health.hediffSet.hediffs.Find(x => (x.def == HediffDefOf.Hediff_CumController)); + if (hediff == null) + return false; + + int minAge = 3 * 2500;//3 hours in-game must have passed + if (!forced) + if (!(hediff.ageTicks > minAge)) + { + //ModLog.Message("WorkGiver_CleanSelf:: 3 hours in-game must pass to self-clean, exit"); + return false; + } + return true; + } + + public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false) + { + return JobMaker.MakeJob(JobDefOf.CleanSelf); + } + } +} diff --git a/1.4/Source/Mod/packages.config b/1.4/Source/Mod/packages.config new file mode 100644 index 0000000..c5bef78 --- /dev/null +++ b/1.4/Source/Mod/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/1.4/Source/Properties/AssemblyInfo.cs b/1.4/Source/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..78fe39f --- /dev/null +++ b/1.4/Source/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("RimJobWorld Cum")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("RimJobWorld Cum")] +[assembly: AssemblyCopyright("Copyright © 2022")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c2825019-7f0b-456d-85a3-479c1a2a8805")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] diff --git a/1.4/Source/mod.sln b/1.4/Source/mod.sln new file mode 100644 index 0000000..ee41d20 --- /dev/null +++ b/1.4/Source/mod.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30907.101 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RimJobWorldCum", "Mod\RimJobWorldCum.csproj", "{3FC2D442-19B8-4CF9-9D35-CD13B6AC7B28}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3FC2D442-19B8-4CF9-9D35-CD13B6AC7B28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3FC2D442-19B8-4CF9-9D35-CD13B6AC7B28}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3FC2D442-19B8-4CF9-9D35-CD13B6AC7B28}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3FC2D442-19B8-4CF9-9D35-CD13B6AC7B28}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5A0C2732-36A9-4ACA-807E-019E02C37E10} + EndGlobalSection +EndGlobal diff --git a/1.4/Textures/CumIcon_drenched.png b/1.4/Textures/CumIcon_drenched.png new file mode 100644 index 0000000000000000000000000000000000000000..842f804f80c8028e69c0e6dd1f2256a88968fc5d GIT binary patch literal 419 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjY)RhkE4tGzVzuXQ_u8RmNf@|ihf|rVKz=kN>iWtb-Tm)Gi|+`DzQxS8*Ah(nC2|$ z&Nv%#$>WmCqz2yyI}IHRiuidN4zDO>o^l{rpxm*hPu*DhNX%-}C(9Ss#Vmfy!2jj2 z_+vf0SywjB@s`r=ja)VF(Vv+K>=q{~3QV_#C)~;EY7*XlK%|Z#IN|P@vdx@_j_zVT zeuq(iXJ(HyzvZ%3tAf_aEknLAZNLoE{)UrrW3T)qCsevPjDi#t2xIhPzMdg8t1khqK4ik$NTcMpNW+SAp~ JWt~$(6951nsa600 literal 0 HcmV?d00001 diff --git a/1.4/Textures/CumIcon_dripping.png b/1.4/Textures/CumIcon_dripping.png new file mode 100644 index 0000000000000000000000000000000000000000..daea57002a55d7a939c8028d7b21146cb18aa829 GIT binary patch literal 385 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjY)RhkE(e4)v42*o9E{-7{$KOsd^kX&@aJ}EcvCBh) z^=zIMmjElP`U4)BM&^RuG7M4yT^Jos^mL*Z%YW zo>b{?8~GWGt8Z>8n=r%NXmfjuo0xCTjEoPwGNm2++dd>Zg$Fw{%x5TP7dfE$K~d@X zSs71*6;{?PX$O=)u!w|4g0KR4I6DhY4tw2yR4@xKrzBGTn!@WR>Vwd(Afwe#=$ zWHfaa>&=ikyqRZC@#Gm5fg*n;R=@iHHXt-OboB?T@Q*j&FNh48w)Dsjwf&`6)Nl3v ZV0JpNm7#0xl3k#X^mO%eS?83{1OUpCkBI;P literal 0 HcmV?d00001 diff --git a/1.4/Textures/CumIcon_little.png b/1.4/Textures/CumIcon_little.png new file mode 100644 index 0000000000000000000000000000000000000000..f7abde3f82359a56fcc4e12bb10011c6e3f68e63 GIT binary patch literal 226 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 literal 0 HcmV?d00001 diff --git a/1.4/Textures/splatch_2.png b/1.4/Textures/splatch_2.png new file mode 100644 index 0000000000000000000000000000000000000000..514a2f1d2233b7e0467a1e3dcc6df34c222d2317 GIT binary patch literal 3027 zcmV;^3oP`BP){+vD~%!*q4EXLSVaXBNR+RLl}`vE@gYM@sGHiUQY4^I ziFK-wD5GdqQl+3~EK1TWNoyx<-b!O9@$EyOGf$2?$4>0d-AN}$@pE_2@ArTEJ^$wn zRPW#b@COeb6#D!78&01-9eU!4CoBLA00{m5|MuW0NYnA-$2ZBcd{CCmy0WVJki1HjMC z&6xn$05}2oL!nT@&8gk*ngm3(XshTdjhF;E^s&;77E@1 zzzRTcyWM7;96&z!;DZ%Ol1u=i(P*?e91j0_aB#4ldP2pMXSE4{)9F-zn*j&_#BeyQ z7XqZOuaD60+yGoYpHFnV-Fq%xyx3ZeaHu)~k|fzFa3cT{08cWRwCe!j^7%Y}`SRre z^%^?>hu`lPB}v+G?AS4XrAerI2#BKSq6C;I31T9VaO+*Lu&^M@vTURwqny@oI2>zh zYwKW2Xw7>72LKL-!$aNQKu>!t7W3#_BLk2P27`f;rkoZ4R*S{5HI+))m|Vcsya(89 zHpOif0)$8;6446*yWLKBo>xM~$b^m%i^Z&oM8e60K~0uH1sJz|`*y)>Hv3f1;k{mO zOa-8DO(YUA#^do73R+Dq2!iEqSql)K&(}yN zPSmH}Zf{H`lLGTU03gw5bPE+uyov-KfI$!hQ!NuvaObYBE{ntAh%*^`6#>Cu(D&@K z&xRNeAn|zI=<#?qYY|58W8`_>SnEoV13;d8?zvbX5Re!EoGJ`_9UUDlOc;`%)YCQxv z0KCKDXjFB6enNuHX8U+ZAAo%0)xUtsO0tKMkwrw+6t=2k?vZwrQSIJ`~!I|m* z4aGty6biZa@89pPRDZD2Re&5gaKIY~1RNT`Ia=DRMV>1#p#vQa5q<2j$67T??Ejnq z0)Vu)w{OPnjS#JgnW&|Uk!aQc#{O+a{_ z`iJ4+;YT(S4y2Oq|I$k@-6Kg-K(B&RZE8*HU|LB#FN5?%v?!)CMX9T*t64`ptlkqUW$ z;pwNJzR%gAi@Fz~3XbuDdKP&PK z#eKOo$mB|VrqU)SOv97|;0Xi*;+-Nuv6>-~NbI5sPU~<|>vLtyrxcgB zE!8HVAbuWw^wCaH6gTONvCu??b-Hvh>#tD3!>K&R8jr_q)g+*hfF6GMVVfw5+l#ok zP-Z-9y#OU^eCF}v3s#((gxjwcRJSF@0pO1uIkHWXq z74Ssknwt|76ANp2(uN2ql)n1<`d{M5jSuyt^9)#-xlZeTGS&G@I=w@dth|O&RPG^9 zPEO9AJ$rVVAx5qw0R`*6{`%`4yWRc^orYwdsm-O_GfxRv)=-DCjylwOlXNMQ$y_*h z?%d6C7DI;hB)?QD)g+3dPiM@nH6*Rx%8wN^Wv}a}rl$V$*=L`f!Ri+^8XQ1K8bxc|4WN z@4x@%t+(F#$5&r{b%O%WGKsV*LWonkzRk_e4^oZKTAgiZ*yv<#Q442jIM|ptU!(P; zj~?~X3tC=})z^~)_(UQR z^85Yjw>0&(uL|!2>JYZpif}odPXGO>r=I$ThEk5n?)ef{juj_>n9XK~YI$1UDnd6B84cKK=C5_uqT( zy-AhjWmMspW2H)A`QpWknep*)Eo+q8(vpj~t_&bIGBR@h#EBE{KL7ml1FF(i74W6F zF~_X!t^NJ|&$P6(bkR<)QB?(?5({T}7#kZqbNKM#zkKn<7gN;rb0w0! zp@T1xAPxW#Me%w(9*>Kn=!NzshZ-Qa2GLgs2L~^lIdkSu-QC?EkB*Mctyj`ki-1)? zzWnmbTbnm;zUK9M10IjZtx|VH1GrYw%BIul>EYqwb02;5(O(~b{PB~$y}cuhoV{b< z%Mn6~7%~B{?A^Q9_sT1;JQ9sY@2jh;b5l`cRE2}0=M`0WZE$e##>mJ>e{XN^KYMz5 zCh+5~?}im!H3?uzD7?21K-jl$pRc>SJ06S0Ho4vIfYoZX^E_|N=kszlo4s}O=FPcG zCNn)WG&FJk{P~Gfr%p|0v)M%k@KU7|U9|~Ndjk7&7Ip>46=`HFYe?CODZ2F@{{>BV VKEyIU7|j3x002ovPDHLkV1k@By&V7m literal 0 HcmV?d00001 diff --git a/1.4/Textures/splatch_3.png b/1.4/Textures/splatch_3.png new file mode 100644 index 0000000000000000000000000000000000000000..452bc0c16452014362388ee8458352a75dcbf2e4 GIT binary patch literal 2976 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 Wzi+W0D03$O0000*P4=Q+>&yw7>h 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 kGVw(i2?O(K8gw($ErKp#OC0i=AQoB-VRH-Ci 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 literal 0 HcmV?d00001 diff --git a/1.4/Textures/splatch_7.png b/1.4/Textures/splatch_7.png new file mode 100644 index 0000000000000000000000000000000000000000..c28106684561b7eda63f395d689071042f6af4bc GIT binary patch literal 2226 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://gitgud.io/Ed86/rjw-cum
  • 1.3
  • +
  • 1.4
  • rjw.cum