diff --git a/Assemblies/RJW.dll b/Assemblies/RJW.dll index 4723803b72bd4c4cc1db380250d39911473895cf..77d366e50e950ecb091bfa35c8eec3659d63f04e 100644 Binary files a/Assemblies/RJW.dll and b/Assemblies/RJW.dll differ diff --git a/Multiplayer.txt b/Multiplayer.txt index 9627f4810abe768896334e83cbc44e5f2f9531aa..4e8b6e7607480e36a168bb4346d7d33fe836515f 100644 --- a/Multiplayer.txt +++ b/Multiplayer.txt @@ -1,23 +1,10 @@ Multiplayer: -Zetrith's Multiplayer https://ludeon.com/forums/index.php?topic=47445.0 -UnofficialMultiplayerAPI https://github.com/Pecius/UnofficialMultiplayerAPI +https://github.com/Parexy/Multiplayer ===================================================== -working: -sex -rape -records -operations -bondage -gender change effects not working: -nymph incidents -after sex log and social stuff is not added -(rape) mood effects -pregnancy? +-? desync: -spawn things with dev mode -changing designators after host started hosing -added traits (not sure if they get added after sex) +-? ===================================================== \ No newline at end of file diff --git a/RimJobWorld.Main.csproj b/RimJobWorld.Main.csproj index 40517a6809f19e673eeb4ce6db114c6115601fca..5f54510e7f57f963a826fdba8a4a875d705b39f0 100644 --- a/RimJobWorld.Main.csproj +++ b/RimJobWorld.Main.csproj @@ -44,6 +44,7 @@ </PropertyGroup> <ItemGroup> <Compile Include="Source\Harmony\patch_races.cs" /> + <Compile Include="Source\JobDrivers\JobDriver_Sex.cs" /> <Compile Include="Source\Modules\Bondage\bondage_gear.cs" /> <Compile Include="Source\Common\Breeder_Helper.cs" /> <Compile Include="Source\Modules\Multiplayer\Multiplayer.cs" /> @@ -219,6 +220,7 @@ <Content Include="About\Preview.png" /> <Content Include="Assemblies\%24HugsLibChecker.dll" /> <Content Include="Assemblies\0Harmony.dll" /> + <Content Include="Assemblies\0MultiplayerAPI.dll" /> <Content Include="Assemblies\RJW.dll" /> <Compile Include="Source\Settings\Settings.cs" /> <Content Include="Defs\BodyPartDefs\BodyParts_Humanlike.xml"> diff --git a/Source/Common/Breeder_Helper.cs b/Source/Common/Breeder_Helper.cs index a1930561c57bd6bfeed5e24616c9fe44eca981b9..216973ceb4d6a96157b0463c922004015f66454d 100644 --- a/Source/Common/Breeder_Helper.cs +++ b/Source/Common/Breeder_Helper.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using RimWorld; using System.Diagnostics; +using Multiplayer.API; namespace rjw { @@ -23,6 +24,7 @@ namespace rjw } //animal try to find best designated pawn to breed + [SyncMethod] public static Pawn find_designated_breeder(Pawn pawn, Map m) { DebugText("BreederHelper::find_designated_breeder( " + xxx.get_pawnname(pawn) + " ) called"); @@ -57,6 +59,7 @@ namespace rjw //animal or human try to find animals to breed //public static Pawn find_breeder_animal(Pawn pawn, Map m, bool SameRace = true) + [SyncMethod] public static Pawn find_breeder_animal(Pawn pawn, Map m) { DebugText("BreederHelper::find_breeder_animal( " + xxx.get_pawnname(pawn) + " ) called"); @@ -136,6 +139,8 @@ namespace rjw } DebugText(valid_targets.Count() + " valid targets found on map."); + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); return valid_targets.Any() ? valid_targets.RandomElement() : null; } } diff --git a/Source/Common/CORE_EXPOSED/PawnGenerator.cs b/Source/Common/CORE_EXPOSED/PawnGenerator.cs index bd43aab20ba034b2e58dbb874e0481ffde83bdfb..3041ba834b30b15325960fb608b8a257e9bafe8c 100644 --- a/Source/Common/CORE_EXPOSED/PawnGenerator.cs +++ b/Source/Common/CORE_EXPOSED/PawnGenerator.cs @@ -16,6 +16,7 @@ using System.Linq; using System.Runtime.InteropServices; using UnityEngine; using Verse; +using Multiplayer.API; namespace rjw { @@ -158,9 +159,12 @@ namespace rjw } } + [SyncMethod] private static Pawn GenerateOrRedressPawnInternal(PawnGenerationRequest request) { Pawn result = null; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); if (!request.Newborn && !request.ForceGenerateNewPawn) { if (request.ForceRedressWorldPawnIfFormerColonist) @@ -364,11 +368,14 @@ namespace rjw return pawn; } + [SyncMethod] private static Pawn TryGenerateNewPawnInternal(ref PawnGenerationRequest request, out string error, bool ignoreScenarioRequirements, bool ignoreValidator) { error = null; Pawn pawn = (Pawn)ThingMaker.MakeThing(request.KindDef.race); pawnsBeingGenerated.Add(new PawnGenerationStatus(pawn, null)); + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); try { pawn.kindDef = request.KindDef; @@ -551,6 +558,7 @@ namespace rjw PawnInventoryGenerator.GenerateInventoryFor(pawn, request); } + [SyncMethod] private static void GenerateInitialHediffs(Pawn pawn, PawnGenerationRequest request) { int num = 0; @@ -591,8 +599,11 @@ namespace rjw } } + [SyncMethod] private static void GenerateRandomAge(Pawn pawn, PawnGenerationRequest request) { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); if (request.FixedBiologicalAge.HasValue && request.FixedChronologicalAge.HasValue) { float? fixedBiologicalAge = request.FixedBiologicalAge; @@ -671,15 +682,19 @@ namespace rjw } } + [SyncMethod] public static int RandomTraitDegree(TraitDef traitDef) { if (traitDef.degreeDatas.Count == 1) { return traitDef.degreeDatas[0].degree; } + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); return traitDef.degreeDatas.RandomElementByWeight((TraitDegreeData dd) => dd.commonality).degree; } + [SyncMethod] private static void GenerateTraits(Pawn pawn, PawnGenerationRequest request) { if (pawn.story != null) @@ -716,6 +731,8 @@ namespace rjw } } } + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); int num = Rand.RangeInclusive(2, 3); if (request.AllowGay && (LovePartnerRelationUtility.HasAnyLovePartnerOfTheSameGender(pawn) || LovePartnerRelationUtility.HasAnyExLovePartnerOfTheSameGender(pawn))) { @@ -748,8 +765,11 @@ namespace rjw } } + [SyncMethod] private static void GenerateBodyType(Pawn pawn) { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); if (pawn.story.adulthood != null) { pawn.story.bodyType = pawn.story.adulthood.BodyTypeFor(pawn.gender); @@ -764,6 +784,7 @@ namespace rjw } } + [SyncMethod] private static void GenerateSkills(Pawn pawn) { List<SkillDef> allDefsListForReading = DefDatabase<SkillDef>.AllDefsListForReading; @@ -775,6 +796,8 @@ namespace rjw skill.Level = num; if (!skill.TotallyDisabled) { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); float num2 = (float)num * 0.11f; float value = Rand.Value; if (value < num2) @@ -793,8 +816,11 @@ namespace rjw } } + [SyncMethod] private static int FinalLevelOfSkill(Pawn pawn, SkillDef sk) { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); float num = (!sk.usuallyDefinedInBackstories) ? Rand.ByCurve(LevelRandomCurve) : ((float)Rand.RangeInclusive(0, 4)); foreach (Backstory item in from bs in pawn.story.AllBackstories where bs != null @@ -836,10 +862,13 @@ namespace rjw } } + [SyncMethod] private static void GeneratePawnRelations(Pawn pawn, ref PawnGenerationRequest request) { if (pawn.RaceProps.Humanlike) { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); Pawn[] array = (from x in PawnsFinder.AllMapsWorldAndTemporary_AliveOrDead where x.def == pawn.def select x).ToArray(); @@ -875,9 +904,12 @@ namespace rjw } } + [SyncMethod] private static Pair<Pawn, PawnRelationDef>[] GenerateSamples(Pawn[] pawns, PawnRelationDef[] relations, int count) { Pair<Pawn, PawnRelationDef>[] array = new Pair<Pawn, PawnRelationDef>[count]; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); for (int i = 0; i < count; i++) { array[i] = new Pair<Pawn, PawnRelationDef>(pawns[Rand.Range(0, pawns.Length)], relations[Rand.Range(0, relations.Length)]); diff --git a/Source/Common/Genital_Helper.cs b/Source/Common/Genital_Helper.cs index 9f79959076976c076892528e6ecd073fac03a5d6..3ad743bca85c37d150576efd59049f055a0fcba6 100644 --- a/Source/Common/Genital_Helper.cs +++ b/Source/Common/Genital_Helper.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Verse; using System; +using Multiplayer.API; namespace rjw { @@ -340,6 +341,7 @@ namespace rjw return (has_penis(pawn) && has_vagina(pawn)); } + [SyncMethod] public static double GenderTechLevelCheck(Pawn pawn) { if (pawn == null) @@ -348,6 +350,8 @@ namespace rjw bool lowtechlevel = true; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); double value = Rand.Value; if (pawn.Faction != null) @@ -368,6 +372,7 @@ namespace rjw return (pawn.gender == Gender.Male) ? (gender != Gender.Female) : (gender == Gender.Male); } + [SyncMethod] public static void add_genitals(Pawn pawn, Pawn parent = null, Gender gender = Gender.None) { //--Log.Message("Genital_Helper::add_genitals( " + xxx.get_pawnname(pawn) + " ) called"); @@ -713,6 +718,8 @@ namespace rjw else if (racename.Contains("impmother") || racename.Contains("demon")) { pawn.health.AddHediff((privates_gender(pawn, gender)) ? demon_penis : demon_vagina, Part); + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); if (Rand.Value < 0.25f) pawn.health.AddHediff((privates_gender(pawn, gender)) ? demon_penis : demonT_penis, Part); return; @@ -720,6 +727,8 @@ namespace rjw //animal demons - MoreMonstergirls else if (racename.Contains("baphomet")) { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); if (Rand.Value < 0.50f) pawn.health.AddHediff((privates_gender(pawn, gender)) ? demon_penis : demon_vagina, Part); else @@ -1201,12 +1210,15 @@ namespace rjw pawn.health.AddHediff(asshole, Part); } + [SyncMethod] public static void sexualize_pawn(Pawn pawn) { //Log.Message("[RJW] sexualize_pawn( " + xxx.get_pawnname(pawn) + " ) called"); if (pawn == null) return; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); if (!pawn.RaceProps.hasGenders) { if (Current.ProgramState == ProgramState.Playing) // DO NOT run at world generation, throws error diff --git a/Source/Common/PawnData.cs b/Source/Common/PawnData.cs index 22a72cc9d1fd46d398c9808d74d0c240e861bb85..55a1c2a34489dde418b76f8593610276b614a04f 100644 --- a/Source/Common/PawnData.cs +++ b/Source/Common/PawnData.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using Verse; using RimWorld; +using Multiplayer.API; namespace rjw { @@ -37,6 +38,7 @@ namespace rjw public bool Breeding = false; public bool Milking = false; public bool Hero = false; + public string HeroOwner = ""; public bool BreedingAnimal = false; public Pawn Pawn = null; @@ -56,69 +58,132 @@ namespace rjw Scribe_Values.Look<bool>(ref Breeding, "Breeding", false, true); Scribe_Values.Look<bool>(ref Milking, "Milking", false, true); Scribe_Values.Look<bool>(ref Hero, "Hero", false, true); + Scribe_Values.Look<String>(ref HeroOwner, "HeroOwner", "", true); Scribe_Values.Look<bool>(ref BreedingAnimal, "BreedingAnimal", false, true); Scribe_References.Look<Pawn>(ref this.Pawn, "Pawn"); } public bool IsValid { get { return Pawn != null; } } } - //Shitcode ahead public static class PawnDesignations { - public static bool IsDesignatedComfort(this Pawn pawn) + public static bool CanChangeDesignationColonist(this Pawn pawn) { - //return comfort_prisoners.is_designated(pawn); - if (!CanDesignateComfort(pawn)) - UnDesignateComfort(pawn); + //check if pawn is a hero of other player + //limit widget access in mp - return SaveStorage.DataStore.GetPawnData(pawn).Comfort; - } - public static bool IsDesignatedService(this Pawn pawn) - { - if (!CanDesignateService(pawn)) - UnDesignateService(pawn); + //Log.Warning("CanChangeDesignationColonist:: IsHeroOwner" + pawn.Name + " IsDesignatedHero" + pawn.IsDesignatedHero() + " IsHeroOwner" + pawn.IsHeroOwner()); + if ((pawn.IsDesignatedHero() && !pawn.IsHeroOwner())) + return false; - return SaveStorage.DataStore.GetPawnData(pawn).Service; + return true; } - public static bool IsDesignatedBreeding(this Pawn pawn) + public static bool CanChangeDesignationPrisoner(this Pawn pawn) { - if (!CanDesignateBreed(pawn)) - UnDesignateBreeding(pawn); + //check if player hero slave/prisoner + //limit widget access in mp - return SaveStorage.DataStore.GetPawnData(pawn).Breeding; + foreach (Pawn item in Find.AnyPlayerHomeMap.mapPawns.AllPawnsSpawned.ToList().Where(x => x.IsDesignatedHero())) + //foreach (Pawn item in AllDesignationsOn(pawn.Map).Where(data => (data.Hero)).Select(data => data.Pawn)) + { + //Log.Warning(item.IsHeroOwner() + " IsHeroOwner" + item.Name ); + if (item.IsHeroOwner()) + { + if (item.IsPrisonerOfColony || xxx.is_slave(item)) + { + //Log.Warning("Hero of "+MP.PlayerName+" is prisoner"); + return false; + } + } + } + + return true; } - public static bool IsDesignatedMilking(this Pawn pawn) + public static bool CanDesignateComfort(this Pawn pawn) { - if (!CanDesignateMilk(pawn)) - UnDesignateMilking(pawn); + //no permission to change designation for NON prisoner hero/ other player + if (!pawn.CanChangeDesignationPrisoner() && !pawn.CanChangeDesignationColonist()) + return false; - return SaveStorage.DataStore.GetPawnData(pawn).Milking; + //no permission to change designation for prisoner hero/ self + if (!pawn.CanChangeDesignationPrisoner()) + return false; + + //cant sex + if (!(xxx.can_fuck(pawn) || xxx.can_be_fucked(pawn))) + return false; + + if (!pawn.IsDesignatedHero()) + { + if (xxx.is_masochist(pawn) && pawn.IsColonist) + return true; + } + else if (pawn.IsHeroOwner()) + return true; + + if (pawn.IsPrisonerOfColony || xxx.is_slave(pawn)) + return true; + + return false; } - public static bool IsDesignatedHero(this Pawn pawn) + public static bool CanDesignateService(this Pawn pawn) { - return SaveStorage.DataStore.GetPawnData(pawn).Hero; + //no permission to change designation for NON prisoner hero/ other player + if (!pawn.CanChangeDesignationPrisoner() && !pawn.CanChangeDesignationColonist()) + return false; + + //no permission to change designation for prisoner hero/ self + if (!pawn.CanChangeDesignationPrisoner()) + return false; + + //cant sex + if (!(xxx.can_fuck(pawn) || xxx.can_be_fucked(pawn))) + return false; + + if (!pawn.IsDesignatedHero()) + { + if (pawn.IsColonist) + return true; + } + else if (pawn.IsHeroOwner()) + return true; + + if (pawn.IsPrisonerOfColony || xxx.is_slave(pawn)) + return true; + + return false; } - public static bool IsDesignatedBreedingAnimal(this Pawn pawn) + public static bool CanDesignateBreeding(this Pawn pawn) { - if (!CanDesignateBreedAnimal(pawn)) - UnDesignateBreedingAnimal(pawn); + //no permission to change designation for NON prisoner hero/ other player + if (!pawn.CanChangeDesignationPrisoner() && !pawn.CanChangeDesignationColonist()) + return false; - return SaveStorage.DataStore.GetPawnData(pawn).BreedingAnimal; - } + //no permission to change designation for prisoner hero/ self + if (!pawn.CanChangeDesignationPrisoner()) + return false; - public static bool CanDesignateComfort(this Pawn pawn) { return (RJWSettings.WildMode || (pawn.IsPrisonerOfColony || xxx.is_slave(pawn) || (xxx.is_masochist(pawn) && pawn.IsColonist) || pawn.IsDesignatedHero()) && (xxx.can_fuck(pawn) || xxx.can_be_fucked(pawn))); } - public static bool CanDesignateService(this Pawn pawn) { return (RJWSettings.WildMode || (pawn.IsColonist || pawn.IsPrisonerOfColony || pawn.IsDesignatedHero()) && (xxx.can_fuck(pawn) || xxx.can_be_fucked(pawn))); } - public static bool CanDesignateBreed(this Pawn pawn) - { - if (RJWSettings.bestiality_enabled - && xxx.is_human(pawn) - && xxx.can_be_fucked(pawn) - && (RJWSettings.WildMode || (pawn.IsPrisonerOfColony || xxx.is_slave(pawn) || (xxx.is_zoophile(pawn) && pawn.IsColonist)) || pawn.IsDesignatedHero())) - return true; + //cant sex + if (!xxx.can_be_fucked(pawn)) + return false; + + + if (RJWSettings.bestiality_enabled && xxx.is_human(pawn)) + { + if (!pawn.IsDesignatedHero()) + { + if (xxx.is_zoophile(pawn) && pawn.IsColonist) + return true; + } + else if (pawn.IsHeroOwner()) + return true; + + if (pawn.IsPrisonerOfColony || xxx.is_slave(pawn)) + return true; + } if (RJWSettings.animal_on_animal_enabled && xxx.is_animal(pawn) - && xxx.can_be_fucked(pawn) && pawn.Faction == Faction.OfPlayer) return true; @@ -126,6 +191,14 @@ namespace rjw } public static bool CanDesignateBreedAnimal(this Pawn pawn) { + //no permission to change designation for NON prisoner hero/ other player + if (!pawn.CanChangeDesignationPrisoner() && !pawn.CanChangeDesignationColonist()) + return false; + + //no permission to change designation for prisoner hero/ self + if (!pawn.CanChangeDesignationPrisoner()) + return false; + //Log.Message("CanDesignateAnimal for " + xxx.get_pawnname(pawn) + " " + SaveStorage.bestiality_enabled); //Log.Message("checking animal props " + (pawn.Faction?.IsPlayer.ToString()?? "tynanfag") + xxx.is_animal(pawn) + xxx.can_rape(pawn)); if ((RJWSettings.bestiality_enabled || RJWSettings.animal_on_animal_enabled) @@ -137,7 +210,7 @@ namespace rjw return false; } - public static bool CanDesignateMilk(this Pawn pawn) { return false; }//todo + public static bool CanDesignateMilking(this Pawn pawn) { return false; }//todo public static bool CanDesignateHero(this Pawn pawn) { if ((RJWSettings.RPG_hero_control) @@ -145,12 +218,18 @@ namespace rjw && pawn.IsColonist && pawn.Map.IsPlayerHome) { - foreach (Pawn item in Find.ColonistBar.GetColonistsInOrder()) - //foreach (Pawn item in Find.AnyPlayerHomeMap.mapPawns.AllPawnsSpawned.ToList()) + //foreach (Pawn item in (Find.ColonistBar.GetColonistsInOrder())) + foreach (Pawn item in Find.AnyPlayerHomeMap.mapPawns.AllPawnsSpawned.ToList()) { if (item.IsDesignatedHero()) { - return false; + if (item.IsHeroOwner()) + { + //Log.Warning("CanDesignateHero:: " + MP.PlayerName + " already has hero - " + item.Name); + return false; + } + else + continue; } } return true; @@ -158,59 +237,208 @@ namespace rjw return false; } - public static void DesignateComfort(this Pawn pawn) + + + + public static void ToggleComfort(this Pawn pawn) { if (pawn.CanDesignateComfort()) { - SaveStorage.DataStore.GetPawnData(pawn).Comfort = true; + if (!pawn.IsDesignatedComfort()) + DesignateComfort(pawn); + else + UnDesignateComfort(pawn); } } - public static void DesignateService(this Pawn pawn) + public static bool IsDesignatedComfort(this Pawn pawn) + { + //return comfort_prisoners.is_designated(pawn); + + //fix for prisoners becoming colonists, breaks mp permissions, fuck it + + //if (!pawn.IsDesignatedHero() && pawn.CanChangeDesignationColonist() && pawn.CanChangeDesignationPrisoner()) + // if (!CanDesignateComfort(pawn)) + // UnDesignateComfort(pawn); + + return SaveStorage.DataStore.GetPawnData(pawn).Comfort; + } + [SyncMethod] + public static void DesignateComfort(this Pawn pawn) + { + SaveStorage.DataStore.GetPawnData(pawn).Comfort = true; + } + [SyncMethod] + public static void UnDesignateComfort(this Pawn pawn) + { + SaveStorage.DataStore.GetPawnData(pawn).Comfort = false; + } + + public static void ToggleService(this Pawn pawn) { if (pawn.CanDesignateService()) { - SaveStorage.DataStore.GetPawnData(pawn).Service = true; + if (!pawn.IsDesignatedService()) + DesignateService(pawn); + else + UnDesignateService(pawn); } } + public static bool IsDesignatedService(this Pawn pawn) + { + /* + if (pawn.CanChangeDesignationColonist() && pawn.CanChangeDesignationPrisoner()) + if (!CanDesignateService(pawn)) + UnDesignateService(pawn); + */ + + return SaveStorage.DataStore.GetPawnData(pawn).Service; + } + [SyncMethod] + public static void DesignateService(this Pawn pawn) + { + SaveStorage.DataStore.GetPawnData(pawn).Service = true; + } + [SyncMethod] + public static void UnDesignateService(this Pawn pawn) + { + SaveStorage.DataStore.GetPawnData(pawn).Service = false; + } + + public static void ToggleBreeding(this Pawn pawn) + { + if (pawn.CanDesignateBreeding()) + { + if (!pawn.IsDesignatedBreeding()) + DesignateBreeding(pawn); + else + UnDesignateBreeding(pawn); + } + } + public static bool IsDesignatedBreeding(this Pawn pawn) + { + /* + if (pawn.CanChangeDesignationColonist() && pawn.CanChangeDesignationPrisoner()) + if (!CanDesignateBreed(pawn)) + UnDesignateBreeding(pawn); + */ + + return SaveStorage.DataStore.GetPawnData(pawn).Breeding; + } + [SyncMethod] public static void DesignateBreeding(this Pawn pawn) { - if (pawn.CanDesignateBreed()) + SaveStorage.DataStore.GetPawnData(pawn).Breeding = true; + } + [SyncMethod] + public static void UnDesignateBreeding(this Pawn pawn) + { + SaveStorage.DataStore.GetPawnData(pawn).Breeding = false; + } + + public static void ToggleBreedingAnimal(this Pawn pawn) + { + if (pawn.CanDesignateBreeding()) { - SaveStorage.DataStore.GetPawnData(pawn).Breeding = true; + if (!pawn.IsDesignatedBreedingAnimal()) + DesignateBreedingAnimal(pawn); + else + UnDesignateBreedingAnimal(pawn); } } + public static bool IsDesignatedBreedingAnimal(this Pawn pawn) + { + /* + if (pawn.CanChangeDesignationColonist() && pawn.CanChangeDesignationPrisoner()) + if (!CanDesignateBreedAnimal(pawn)) + UnDesignateBreedingAnimal(pawn); + */ + return SaveStorage.DataStore.GetPawnData(pawn).BreedingAnimal; + } + [SyncMethod] public static void DesignateBreedingAnimal(this Pawn pawn) { - if (pawn.CanDesignateBreedAnimal()) + SaveStorage.DataStore.GetPawnData(pawn).BreedingAnimal = true; + } + [SyncMethod] + public static void UnDesignateBreedingAnimal(this Pawn pawn) + { + SaveStorage.DataStore.GetPawnData(pawn).BreedingAnimal = false; + } + + public static void ToggleMilking(this Pawn pawn) + { + if (pawn.CanDesignateMilking()) { - SaveStorage.DataStore.GetPawnData(pawn).BreedingAnimal = true; + if (!pawn.IsDesignatedMilking()) + DesignateMilking(pawn); + else + UnDesignateMilking(pawn); } } + public static bool IsDesignatedMilking(this Pawn pawn) + { + /* + if (pawn.CanChangeDesignationColonist() && pawn.CanChangeDesignationPrisoner()) + if (!CanDesignateMilk(pawn)) + UnDesignateMilking(pawn); + */ + return SaveStorage.DataStore.GetPawnData(pawn).Milking; + } + [SyncMethod] public static void DesignateMilking(this Pawn pawn) { - if (pawn.CanDesignateMilk()) - { - SaveStorage.DataStore.GetPawnData(pawn).Milking = true; - } + SaveStorage.DataStore.GetPawnData(pawn).Milking = true; + } + [SyncMethod] + public static void UnDesignateMilking(this Pawn pawn) + { + SaveStorage.DataStore.GetPawnData(pawn).Milking = false; } - public static void DesignateHero(this Pawn pawn) + public static void ToggleHero(this Pawn pawn) { if (pawn.CanDesignateHero()) { - SaveStorage.DataStore.GetPawnData(pawn).Hero = true; - Log.Message(pawn.Name + " is set to hero:" + SaveStorage.DataStore.GetPawnData(pawn).Hero); + if (!pawn.IsDesignatedHero()) + DesignateHero(pawn); + else + UnDesignateHero(pawn); } } + public static void DesignateHero(this Pawn pawn) + { + MyMethod(pawn, MP.PlayerName); + } + public static bool IsDesignatedHero(this Pawn pawn) + { + return SaveStorage.DataStore.GetPawnData(pawn).Hero; + } + public static bool IsHeroOwner(this Pawn pawn) + { + if (!MP.enabled) + return SaveStorage.DataStore.GetPawnData(pawn).HeroOwner == ""; + else + return SaveStorage.DataStore.GetPawnData(pawn).HeroOwner == MP.PlayerName; + } + [SyncMethod] + static void MyMethod(Pawn pawn, string theName) + { + SaveStorage.DataStore.GetPawnData(pawn).Hero = true; + SaveStorage.DataStore.GetPawnData(pawn).HeroOwner = theName; + string text = pawn.Name + " is now hero of " + theName; + Messages.Message(text, pawn, MessageTypeDefOf.NeutralEvent); + //Log.Message(MP.PlayerName + " set " + pawn.Name + " to hero:" + SaveStorage.DataStore.GetPawnData(pawn).Hero); + } + [SyncMethod] + public static void UnDesignateHero(this Pawn pawn) + { + } + + + - public static void UnDesignateComfort(this Pawn pawn) { SaveStorage.DataStore.GetPawnData(pawn).Comfort = false; } - public static void UnDesignateService(this Pawn pawn) { SaveStorage.DataStore.GetPawnData(pawn).Service = false; } - public static void UnDesignateBreeding(this Pawn pawn) { SaveStorage.DataStore.GetPawnData(pawn).Breeding = false; } - public static void UnDesignateBreedingAnimal(this Pawn pawn) { SaveStorage.DataStore.GetPawnData(pawn).BreedingAnimal = false; } - public static void UnDesignateMilking(this Pawn pawn) { SaveStorage.DataStore.GetPawnData(pawn).Milking = false; } - public static void UnDesignateHero(this Pawn pawn) {} private static IEnumerable<PawnData> AllDesignationsOn(Map map) { diff --git a/Source/Common/SexUtility.cs b/Source/Common/SexUtility.cs index e8327f18ea852c8177e09aca285c93763f96782a..2b0b779112c04fb7504421308d70d0f270c86f51 100644 --- a/Source/Common/SexUtility.cs +++ b/Source/Common/SexUtility.cs @@ -8,6 +8,7 @@ using Verse.AI; using Verse.Sound; using JobDriver_Lovin = rjw_CORE_EXPOSED.JobDriver_Lovin; using Harmony; +using Multiplayer.API; namespace rjw @@ -229,6 +230,7 @@ namespace rjw } // The pawn may or may not clean up the mess after fapping. + [SyncMethod] public static bool ConsiderCleaning(Pawn fapper) { if (!RJWSettings.cum_filth) return false; @@ -276,10 +278,13 @@ namespace rjw if (xxx.is_ascetic(fapper)) do_cleaning += 0.2f; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); return Rand.Chance(do_cleaning); } // <summary>Handles after-sex trait and thought gain, and fluid creation. Initiator of the act (whore, rapist, female zoophile, etc) should be first.</summary> + [SyncMethod] private static void Aftersex(Pawn pawn, Pawn partner, bool rape = false, bool isCoreLovin = false, xxx.rjwSextype sextype = xxx.rjwSextype.Vaginal) { bool bothInMap = false; @@ -292,6 +297,8 @@ namespace rjw pawn.rotationTracker.Face(partner.DrawPos); pawn.rotationTracker.FaceCell(partner.Position); + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); if (bothInMap) { if (!partner.Dead) @@ -576,6 +583,7 @@ namespace rjw } + [SyncMethod] private static void CheckTraitGain(Pawn pawn) { if (!xxx.has_traits(pawn) || pawn.records.GetValue(xxx.CountOfSex) <= 10) return; @@ -595,6 +603,8 @@ namespace rjw if (xxx.is_bloodlust(pawn)) chance += 0.2f; if (xxx.is_psychopath(pawn)) chance += 0.25f; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); if (Rand.Chance(chance)) { pawn.story.traits.GainTrait(new Trait(xxx.rapist)); @@ -628,9 +638,12 @@ namespace rjw pawn.mindState.canLovinTick = currentTime + GenerateMinTicksToNextLovin(pawn); } + [SyncMethod] public static int GenerateMinTicksToNextLovin(Pawn pawn) { if (DebugSettings.alwaysDoLovin) return 100; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); float interval = JobDriver_Lovin.LovinIntervalHoursFromAgeCurve.Evaluate(ScaleToHumanAge(pawn)); float rinterval = Math.Max(0.5f, Rand.Gaussian(interval, 0.3f)); @@ -691,6 +704,7 @@ namespace rjw pawn.Drawer.Notify_MeleeAttackOn(partner); } + [SyncMethod] private static xxx.rjwSextype DetermineSextype(Pawn pawn, Pawn partner, bool rape, bool whoring, ref Pawn receiving) { //--Log.Message("[RJW]SexUtility::processSex is called for pawn" + xxx.get_pawnname(pawn) + " and partner " + xxx.get_pawnname(partner)); @@ -710,6 +724,9 @@ namespace rjw bool pawnHasHands = pawn.health.hediffSet.GetNotMissingParts().Any(part => part.IsInGroup(BodyPartGroupDefOf.RightHand) || part.IsInGroup(BodyPartGroupDefOf.LeftHand)); bool partnerHasHands = partner.health.hediffSet.GetNotMissingParts().Any(part => part.IsInGroup(BodyPartGroupDefOf.RightHand) || part.IsInGroup(BodyPartGroupDefOf.LeftHand)); + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); + /*Things to keep in mind: - Both the initiator and the partner can be female, male, or futa. - Can be rape or consensual. diff --git a/Source/Common/xxx.cs b/Source/Common/xxx.cs index 52eb425f169cf679c44f88fa2209676b6665124a..68dc0f6c7de42f03c2c6144896af1e5ea83968ce 100644 --- a/Source/Common/xxx.cs +++ b/Source/Common/xxx.cs @@ -10,6 +10,7 @@ using Verse; using Verse.AI; using Verse.AI.Group; using Verse.Sound; +using Multiplayer.API; //using static RimWorld.Planet.CaravanInventoryUtility; //using RimWorldChildren; @@ -243,8 +244,11 @@ namespace rjw return pawn != null && is_human(pawn) && CompRJW.Comp(pawn).quirks.ToString().Contains(quirk); } + [SyncMethod] public static string random_pick_a_trait(this Pawn pawn) { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); return has_traits(pawn) ? pawn.story.traits.allTraits.RandomElement().def.defName : null; } @@ -771,6 +775,7 @@ namespace rjw /// Returns boolean, no more messing around with floats. /// Just a simple 'Would rape? True/false'. /// </summary> + [SyncMethod] public static bool would_rape(Pawn rapist, Pawn rapee) { float rape_factor = 0.3f; // start at 30% @@ -834,6 +839,8 @@ namespace rjw if (rapist.needs.joy != null && rapist.needs.joy.CurLevel < 0.1f) // The rapist is really bored... rape_factor *= 1.2f; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); if (rapist.relations == null || is_animal(rapist)) return Rand.Chance(rape_factor); int opinion = rapist.relations.OpinionOf(rapee); diff --git a/Source/Comps/CompRJW.cs b/Source/Comps/CompRJW.cs index 6be8ab1790e0c0b808e5beddac9bad854b24af65..c8a3b444e9cfef665e2dc92346427e31407f8a8b 100644 --- a/Source/Comps/CompRJW.cs +++ b/Source/Comps/CompRJW.cs @@ -3,6 +3,7 @@ using SyrTraits; using System.Text; using Verse; using RimWorld; +using Multiplayer.API; namespace rjw { @@ -144,12 +145,15 @@ namespace rjw } } + [SyncMethod] public void GenerateQuirks(Pawn pawn) { // No quirks for droids, at least not for now. if (pawn.kindDef.race.defName.ToLower().Contains("droid") || xxx.is_mechanoid(pawn)) - return; + return; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); if (Rand.Chance(0.025f)) quirks.AppendWithComma("Messy"); // Increased cum generation. @@ -311,6 +315,7 @@ namespace rjw } } + [SyncMethod] public static bool CheckPreference(Pawn pawn, Pawn partner) { if (xxx.RomanceDiversifiedIsActive || (xxx.has_traits(pawn) && pawn.story.traits.HasTrait(TraitDefOf.Gay))) @@ -342,6 +347,8 @@ namespace rjw bool isHomo = (Genital_Helper.has_vagina(pawn) && Genital_Helper.has_vagina(partner)) || ((Genital_Helper.has_penis(partner) || Genital_Helper.has_penis_infertile(partner)) && (Genital_Helper.has_penis(pawn) || Genital_Helper.has_penis_infertile(pawn))); + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); switch (ori) { case Orientation.Heterosexual: @@ -363,9 +370,12 @@ namespace rjw } // Just an example for now. Not used anywhere yet. + [SyncMethod] public Orientation RollOrientation() { - float random = UnityEngine.Random.Range(0f, 1f); + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); + float random = Rand.Range(0f, 1f); float checkpoint = RJWPreferenceSettings.asexual_ratio / RJWPreferenceSettings.GetTotal(); float checkpoint_pan = checkpoint + (RJWPreferenceSettings.pansexual_ratio / RJWPreferenceSettings.GetTotal()); @@ -395,9 +405,12 @@ namespace rjw // Simpler system for animals, with most of them being heterosexual. // Don't want to disturb player breeding projects by adding too many gay animals. + [SyncMethod] public Orientation RollAnimalOrientation() { - var random = UnityEngine.Random.Range(0f, 1f); + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); + float random = Rand.Range(0f, 1f); if (random < 0.03f) return Orientation.Asexual; diff --git a/Source/Designators/RJWdesignations.cs b/Source/Designators/RJWdesignations.cs index 315934ccae57f9226d6879efa6f5e765c6526ec2..b8bde8abc62bc7f4bdfc00d2b8eb424b883b9ce8 100644 --- a/Source/Designators/RJWdesignations.cs +++ b/Source/Designators/RJWdesignations.cs @@ -108,18 +108,20 @@ namespace rjw static readonly Texture2D iconAccept = ContentFinder<Texture2D>.Get("UI/Commands/ComfortPrisoner_off"); static readonly Texture2D iconRefuse = ContentFinder<Texture2D>.Get("UI/Commands/ComfortPrisoner_Refuse"); static readonly Texture2D iconCancel = ContentFinder<Texture2D>.Get("UI/Commands/ComfortPrisoner_on"); - public override Texture2D texture(Pawn pawn) => pawn.CanDesignateComfort() && xxx.is_human(pawn) ? iconAccept : iconRefuse; + public override Texture2D texture(Pawn pawn) => (pawn.CanDesignateComfort() || pawn.IsDesignatedComfort()) && xxx.is_human(pawn) ? iconAccept : iconRefuse; public override Texture2D cancel { get; } = iconCancel; static readonly Vector2 posComf = new Vector2(IconGap + IconSize, 0); public override Vector2 offset => posComf; - public override string desc(Pawn pawn) => pawn.CanDesignateComfort() ? "ForComfortDesc" : "ForComfortRefuseDesc"; + public override string desc(Pawn pawn) => pawn.CanDesignateComfort() ? "ForComfortDesc" : + !pawn.CanChangeDesignationPrisoner() ? "ForHeroRefuse2Desc" : + !pawn.CanChangeDesignationColonist() ? "ForHeroRefuse1Desc" : "ForComfortRefuseDesc"; public override bool applicable(Pawn pawn) => xxx.is_human(pawn); public override bool applied(Pawn pawn) => pawn.IsDesignatedComfort(); - public override void apply(Pawn pawn) => pawn.DesignateComfort(); - public override void unapply(Pawn pawn) => pawn.UnDesignateComfort(); + public override void apply(Pawn pawn) => pawn.ToggleComfort(); + public override void unapply(Pawn pawn) => pawn.ToggleComfort(); } [StaticConstructorOnStartup] public class Service : SubIcon @@ -128,17 +130,19 @@ namespace rjw static readonly Texture2D iconAccept = ContentFinder<Texture2D>.Get("UI/Commands/Service_off"); static readonly Texture2D iconRefuse = ContentFinder<Texture2D>.Get("UI/Commands/Service_Refuse"); static readonly Texture2D iconCancel = ContentFinder<Texture2D>.Get("UI/Commands/Service_on"); - public override Texture2D texture(Pawn pawn) => pawn.CanDesignateService() && xxx.is_human(pawn) ? iconAccept : iconRefuse; + public override Texture2D texture(Pawn pawn) => (pawn.CanDesignateService() || pawn.IsDesignatedService()) && xxx.is_human(pawn) ? iconAccept : iconRefuse; public override Texture2D cancel { get; } = iconCancel; public override Vector2 offset { get; } = new Vector2(0, 0); - public override string desc(Pawn pawn) => pawn.CanDesignateService() ? "ForServiceDesc" : "ForServiceRefuseDesc"; + public override string desc(Pawn pawn) => pawn.CanDesignateService() ? "ForServiceDesc" : + !pawn.CanChangeDesignationPrisoner() ? "ForHeroRefuse2Desc" : + !pawn.CanChangeDesignationColonist() ? "ForHeroRefuse1Desc" : "ForServiceRefuseDesc"; public override bool applicable(Pawn pawn) => xxx.is_human(pawn); public override bool applied(Pawn pawn) => pawn.IsDesignatedService() && xxx.is_human(pawn); - public override void apply(Pawn pawn) => pawn.DesignateService(); - public override void unapply(Pawn pawn) => pawn.UnDesignateService(); + public override void apply(Pawn pawn) => pawn.ToggleService(); + public override void unapply(Pawn pawn) => pawn.ToggleService(); } [StaticConstructorOnStartup] public class BreedingHuman : SubIcon @@ -147,17 +151,19 @@ namespace rjw static readonly Texture2D iconAccept = ContentFinder<Texture2D>.Get("UI/Commands/Breeding_Pawn_off"); static readonly Texture2D iconRefuse = ContentFinder<Texture2D>.Get("UI/Commands/Breeding_Pawn_Refuse"); static readonly Texture2D iconCancel = ContentFinder<Texture2D>.Get("UI/Commands/Breeding_Pawn_on"); - public override Texture2D texture(Pawn pawn) => (pawn.CanDesignateBreed() || pawn.IsDesignatedBreeding()) && xxx.is_human(pawn) ? iconAccept : iconRefuse; + public override Texture2D texture(Pawn pawn) => (pawn.CanDesignateBreeding() || pawn.IsDesignatedBreeding()) && xxx.is_human(pawn) ? iconAccept : iconRefuse; public override Texture2D cancel { get; } = iconCancel; public override Vector2 offset { get; } = new Vector2(0, IconSize + IconGap); - public override string desc(Pawn pawn) => (pawn.CanDesignateBreed() || pawn.IsDesignatedBreeding()) && xxx.is_human(pawn) ? "ForBreedingDesc" : "ForBreedingRefuseDesc"; + public override string desc(Pawn pawn) => pawn.CanDesignateBreeding() && xxx.is_human(pawn) ? "ForBreedingDesc" : + !pawn.CanChangeDesignationPrisoner() ? "ForHeroRefuse2Desc" : + !pawn.CanChangeDesignationColonist() ? "ForHeroRefuse1Desc" : "ForBreedingRefuseDesc"; public override bool applicable(Pawn pawn) => xxx.is_human(pawn); public override bool applied(Pawn pawn) => pawn.IsDesignatedBreeding() && xxx.is_human(pawn); - public override void apply(Pawn pawn) => pawn.DesignateBreeding(); - public override void unapply(Pawn pawn) => pawn.UnDesignateBreeding(); + public override void apply(Pawn pawn) => pawn.ToggleBreeding(); + public override void unapply(Pawn pawn) => pawn.ToggleBreeding(); } [StaticConstructorOnStartup] @@ -171,12 +177,12 @@ namespace rjw public override Vector2 offset { get; } = new Vector2(0, IconSize + IconGap); - public override string desc(Pawn pawn) => "ForBreedingDesc"; + public override string desc(Pawn pawn) => !pawn.CanChangeDesignationPrisoner() ? "ForHeroRefuse2Desc" : "ForBreedingDesc"; - public override bool applicable(Pawn pawn) => (pawn.CanDesignateBreed() || pawn.IsDesignatedBreeding()) && xxx.is_animal(pawn); + public override bool applicable(Pawn pawn) => (pawn.CanDesignateBreeding() || pawn.IsDesignatedBreeding()) && xxx.is_animal(pawn); public override bool applied(Pawn pawn) => pawn.IsDesignatedBreeding() && xxx.is_animal(pawn); - public override void apply(Pawn pawn) => pawn.DesignateBreeding(); - public override void unapply(Pawn pawn) => pawn.UnDesignateBreeding(); + public override void apply(Pawn pawn) => pawn.ToggleBreeding(); + public override void unapply(Pawn pawn) => pawn.ToggleBreeding(); } [StaticConstructorOnStartup] public class Breeder : SubIcon @@ -189,12 +195,12 @@ namespace rjw public override Vector2 offset { get; } = new Vector2(0, 0); - public override string desc(Pawn pawn) => "ForBreedingAnimalDesc"; + public override string desc(Pawn pawn) => !pawn.CanChangeDesignationPrisoner() ? "ForHeroRefuse2Desc" : "ForBreedingAnimalDesc"; public override bool applicable(Pawn pawn) => pawn.CanDesignateBreedAnimal() || pawn.IsDesignatedBreedingAnimal(); public override bool applied(Pawn pawn) => pawn.IsDesignatedBreedingAnimal(); - public override void apply(Pawn pawn) => pawn.DesignateBreedingAnimal(); - public override void unapply(Pawn pawn) => pawn.UnDesignateBreedingAnimal(); + public override void apply(Pawn pawn) => pawn.ToggleBreedingAnimal(); + public override void unapply(Pawn pawn) => pawn.ToggleBreedingAnimal(); } [StaticConstructorOnStartup] public class Milking : SubIcon @@ -206,12 +212,12 @@ namespace rjw public override Vector2 offset { get; } = new Vector2(IconGap + IconSize, IconSize + IconGap); - public override string desc(Pawn pawn) => "ForMilkingDesc"; + public override string desc(Pawn pawn) => !pawn.CanChangeDesignationPrisoner() ? "ForHeroRefuse2Desc" : "ForMilkingDesc"; - public override bool applicable(Pawn pawn) => pawn.CanDesignateMilk() || pawn.IsDesignatedMilking(); + public override bool applicable(Pawn pawn) => pawn.CanDesignateMilking() || pawn.IsDesignatedMilking(); public override bool applied(Pawn pawn) => pawn.IsDesignatedMilking(); - public override void apply(Pawn pawn) => pawn.DesignateMilking(); - public override void unapply(Pawn pawn) => pawn.UnDesignateMilking(); + public override void apply(Pawn pawn) => pawn.ToggleMilking(); + public override void unapply(Pawn pawn) => pawn.ToggleMilking(); } [StaticConstructorOnStartup] public class Hero : SubIcon @@ -223,12 +229,14 @@ namespace rjw public override Vector2 offset { get; } = new Vector2(IconGap + IconSize, IconSize + IconGap); - public override string desc(Pawn pawn) => "ForHeroDesc"; + //public override string desc(Pawn pawn) => pawn.CanDesignateHero() || (pawn.IsDesignatedHero() && pawn.IsHeroOwner()) ? "ForHeroDesc" : "Hero of " + SaveStorage.DataStore.GetPawnData(pawn).HeroOwner; + public override string desc(Pawn pawn) => pawn.CanDesignateHero() ? "ForHeroDesc" : + pawn.IsDesignatedHero() ? "Hero of " + SaveStorage.DataStore.GetPawnData(pawn).HeroOwner : "ForHeroDesc"; public override bool applicable(Pawn pawn) => pawn.CanDesignateHero() || pawn.IsDesignatedHero(); public override bool applied(Pawn pawn) => pawn.IsDesignatedHero(); - public override void apply(Pawn pawn) => pawn.DesignateHero(); - public override void unapply(Pawn pawn) => pawn.UnDesignateHero(); + public override void apply(Pawn pawn) => pawn.ToggleHero(); + public override void unapply(Pawn pawn) => pawn.ToggleHero(); } } } diff --git a/Source/Harmony/patch_pregnancy.cs b/Source/Harmony/patch_pregnancy.cs index e896417f125d72308b9ae8681723553edde9db6d..4b8e1b6ba501427608a0c434ac89ca2e88675da4 100644 --- a/Source/Harmony/patch_pregnancy.cs +++ b/Source/Harmony/patch_pregnancy.cs @@ -4,6 +4,7 @@ using RimWorld; using RimWorld.Planet; using UnityEngine; using Verse; +using Multiplayer.API; namespace rjw { @@ -21,6 +22,7 @@ namespace rjw /// <param name="father"></param> /// <returns></returns> [HarmonyPrefix] + [SyncMethod] private static bool on_begin_DoBirthSpawn(ref Pawn mother, ref Pawn father) { //--Log.Message("patches_pregnancy::PATCH_Hediff_Pregnant::DoBirthSpawn() called"); @@ -69,6 +71,8 @@ namespace rjw Log.Error("Hediff_Pregnant::DoBirthSpawn() - mother is male -> exit"); return false; } + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); // get a reference to the hediff we are applying //do birth for vanilla pregnancy, if using rjw - add RJW pregnancy and birth it instead diff --git a/Source/Harmony/patch_semenOverlay.cs b/Source/Harmony/patch_semenOverlay.cs index f750227309dc4ed9059a5273d6c5399f72fa7067..441629e65b26ffea95a8cf0906e09b77988e4858 100644 --- a/Source/Harmony/patch_semenOverlay.cs +++ b/Source/Harmony/patch_semenOverlay.cs @@ -4,6 +4,7 @@ using Harmony; using UnityEngine; using System; using RimWorld; +using Multiplayer.API; namespace rjw { @@ -70,32 +71,7 @@ namespace rjw addSemen.defaultLabel = "AddSemen"; addSemen.action = delegate () { - Pawn pawn = __instance; - - if (!pawn.Dead && pawn.records != null) - { - //get all acceptable body parts: - IEnumerable<BodyPartRecord> filteredParts = SemenHelper.getAvailableBodyParts(pawn); - - //select random part: - BodyPartRecord randomPart; - //filteredParts.TryRandomElement<BodyPartRecord>(out randomPart); - //for testing - choose either genitals or anus: - if (Rand.Value > 0.5f) - { - randomPart = pawn.RaceProps.body.AllParts.Find(x => x.def == xxx.anus.def); - } - else - { - randomPart = pawn.RaceProps.body.AllParts.Find(x => x.def == xxx.genitals.def); - } - - if (randomPart != null) - { - SemenHelper.cumOn(pawn, randomPart, 0.2f, null, SemenHelper.CUM_NORMAL); - } - - }; + Addsemen(__instance); }; NewList.Add(addSemen); @@ -107,5 +83,37 @@ namespace rjw __result = output; } + + [SyncMethod] + static void Addsemen(Pawn pawn) + { + //Log.Message("add semen button is pressed for " + pawn); + + if (!pawn.Dead && pawn.records != null) + { + //get all acceptable body parts: + IEnumerable<BodyPartRecord> filteredParts = SemenHelper.getAvailableBodyParts(pawn); + + //select random part: + BodyPartRecord randomPart; + //filteredParts.TryRandomElement<BodyPartRecord>(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.anus.def); + } + else + { + randomPart = pawn.RaceProps.body.AllParts.Find(x => x.def == xxx.genitals.def); + } + + if (randomPart != null) + { + SemenHelper.cumOn(pawn, randomPart, 0.2f, null, SemenHelper.CUM_NORMAL); + } + }; + } } } diff --git a/Source/Harmony/submit_button.cs b/Source/Harmony/submit_button.cs index 827480191806bf2f097ac573d80d08f957c74963..f939769c5cfb054765f8c7a922ed31d8fab18ba9 100644 --- a/Source/Harmony/submit_button.cs +++ b/Source/Harmony/submit_button.cs @@ -4,7 +4,7 @@ using Harmony; using RimWorld; using Verse; using UnityEngine; - +using Multiplayer.API; namespace rjw { @@ -21,30 +21,32 @@ namespace rjw var gizmos = __result.ToList(); var enabled = RJWSettings.submit_button_enabled; - if (enabled && pawn.IsColonistPlayerControlled && pawn.Drafted) - { - gizmos.Add(new Command_Action + if (pawn.CanChangeDesignationColonist()) + if (enabled && pawn.IsColonistPlayerControlled && pawn.Drafted) { - defaultLabel = "CommandSubmit".Translate(), - icon = submit_icon, - defaultDesc = "CommandSubmitDesc".Translate(), - action = delegate + gizmos.Add(new Command_Action { - pawn.health.AddHediff(submit_hediff); - }, - hotKey = KeyBindingDefOf.Misc3 - }); - } + defaultLabel = "CommandSubmit".Translate(), + icon = submit_icon, + defaultDesc = "CommandSubmitDesc".Translate(), + action = delegate + { + LayDownAndAccept(pawn); + }, + hotKey = KeyBindingDefOf.Misc3 + }); + } __result = gizmos.AsEnumerable(); } static Texture2D submit_icon = ContentFinder<Texture2D>.Get("UI/Commands/Submit", true); static HediffDef submit_hediff= HediffDef.Named("Hediff_Submitting"); - //static void LayDownAndAccept(Pawn pawn) - //{ - // //Log.Message("Submit button is pressed for " + pawn); - // pawn.health.AddHediff(submit_hediff); - //} + [SyncMethod] + static void LayDownAndAccept(Pawn pawn) + { + //Log.Message("Submit button is pressed for " + pawn); + pawn.health.AddHediff(submit_hediff); + } } } diff --git a/Source/JobDrivers/JobDriver_BestialityForFemale.cs b/Source/JobDrivers/JobDriver_BestialityForFemale.cs index 4b3f5e400be63e974d98baf2a9315e4d6414fdd8..74ee30e5e76a8afc6df2dca2c7f0ccb23e864dbb 100644 --- a/Source/JobDrivers/JobDriver_BestialityForFemale.cs +++ b/Source/JobDrivers/JobDriver_BestialityForFemale.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using RimWorld; using Verse; using Verse.AI; +using Multiplayer.API; namespace rjw { @@ -40,6 +41,7 @@ namespace rjw return pawn.Reserve(Partner, job, 1, 0, null, errorOnFailed); } + [SyncMethod] protected override IEnumerable<Toil> MakeNewToils() { this.FailOnDespawnedOrNull(PartnerInd); @@ -75,6 +77,8 @@ namespace rjw { initAction = delegate { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); ticksLeftThisToil = 5000; ticks_left = (int)(2000.0f * Rand.Range(0.30f, 1.30f)); }, diff --git a/Source/JobDrivers/JobDriver_BestialityForMale.cs b/Source/JobDrivers/JobDriver_BestialityForMale.cs index 168d9fd2fb0ac7010a9c1796a55b5de5dea96bb2..e7cd8f13061a5bc0bee19c6bf4d89bba1a617935 100644 --- a/Source/JobDrivers/JobDriver_BestialityForMale.cs +++ b/Source/JobDrivers/JobDriver_BestialityForMale.cs @@ -1,9 +1,9 @@ -using System; using System.Collections.Generic; using System.Linq; using RimWorld; using Verse; using Verse.AI; +using Multiplayer.API; namespace rjw { @@ -22,9 +22,12 @@ namespace rjw return pawn.Reserve(animal, job, 1, 0, null, errorOnFailed); } + [SyncMethod] protected override IEnumerable<Toil> MakeNewToils() { //--Log.Message("[RJW] JobDriver_BestialityForMale::MakeNewToils() called"); + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); duration = (int)(2500.0f * Rand.Range(0.50f, 0.90f)); ticks_between_hearts = Rand.RangeInclusive(70, 130); ticks_between_hits = Rand.Range(xxx.config.min_ticks_between_hits, xxx.config.max_ticks_between_hits); @@ -158,6 +161,7 @@ namespace rjw }; } + [SyncMethod] private Toil TalkToAnimal(Pawn pawn, Pawn animal) { Toil toil = new Toil(); @@ -165,6 +169,8 @@ namespace rjw { pawn.interactions.TryInteractWith(animal, SexUtility.AnimalSexChat); }; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); toil.defaultCompleteMode = ToilCompleteMode.Delay; toil.defaultDuration = Rand.Range(120, 220); return toil; diff --git a/Source/JobDrivers/JobDriver_Breeding.cs b/Source/JobDrivers/JobDriver_Breeding.cs index 94ef0fc0120a3c5d439d4465b80408b18c49b317..3a901c732c76daa42fbd87fc027144d06c479677 100644 --- a/Source/JobDrivers/JobDriver_Breeding.cs +++ b/Source/JobDrivers/JobDriver_Breeding.cs @@ -1,8 +1,8 @@ -using System; using System.Collections.Generic; using RimWorld; using Verse; using Verse.AI; +using Multiplayer.API; namespace rjw { @@ -20,11 +20,14 @@ namespace rjw return pawn.Reserve(Target, job, BreederHelper.max_animals_at_once, 0); } + [SyncMethod] public virtual void roll_to_hit(Pawn pawn, Pawn partner) { if (!RJWSettings.rape_beating || !xxx.is_human(pawn)) return; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); float rand_value = Rand.Value; float victim_pain = partner.health.hediffSet.PainTotal; float chance_to_hit = xxx.config.base_chance_to_hit_prisoner/5; @@ -37,8 +40,11 @@ namespace rjw } } + [SyncMethod] protected override IEnumerable<Toil> MakeNewToils() { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); int duration = (int)(2000.0f * Rand.Range(0.50f, 0.90f)); int ticks_between_hearts = Rand.RangeInclusive(70, 130); int ticks_between_hits = Rand.Range(xxx.config.min_ticks_between_hits, xxx.config.max_ticks_between_hits); diff --git a/Source/JobDrivers/JobDriver_Fappin.cs b/Source/JobDrivers/JobDriver_Fappin.cs index b55db38f02a84925c9f7a16480911c142f6ad241..b6181618e7865ea3254d7a290607cc324c01be85 100644 --- a/Source/JobDrivers/JobDriver_Fappin.cs +++ b/Source/JobDrivers/JobDriver_Fappin.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using RimWorld; using Verse; using Verse.AI; +using Multiplayer.API; namespace rjw { @@ -19,9 +20,12 @@ namespace rjw return pawn.Reserve(Bed, job, Bed.SleepingSlotsCount, 0, null, errorOnFailed); } + [SyncMethod] protected override IEnumerable<Toil> MakeNewToils() { // Faster fapping when frustrated. + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); ticks_left = (int)(xxx.need_some_sex(pawn) > 2f ? 2500.0f * Rand.Range(0.2f, 0.7f) : 2500.0f * Rand.Range(0.2f, 0.4f)); this.FailOnDespawnedOrNull(ibed); diff --git a/Source/JobDrivers/JobDriver_GettinRaped.cs b/Source/JobDrivers/JobDriver_GettinRaped.cs index ca10580108cbf6a770bea7bcb14b2ca3836bd47b..e3263d343e1557eb7c3d684a4d902b65c65dab96 100644 --- a/Source/JobDrivers/JobDriver_GettinRaped.cs +++ b/Source/JobDrivers/JobDriver_GettinRaped.cs @@ -53,6 +53,8 @@ namespace rjw protected override IEnumerable<Toil> MakeNewToils() { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); ticks_between_hearts = Rand.RangeInclusive(70, 130); //was_laying_down = pawn.GetPosture() != PawnPosture.Standing; //Log.Message(xxx.get_pawnname(Initiator) + ": was_laying_down:" + was_laying_down + " LayingInBed:" + Initiator.GetPosture()); diff --git a/Source/JobDrivers/JobDriver_JoinInBed.cs b/Source/JobDrivers/JobDriver_JoinInBed.cs index 624b26993d9b4154a76a49b7c749c951e366fb0a..2bde244490d12705caa130f85aac2ea04158da04 100644 --- a/Source/JobDrivers/JobDriver_JoinInBed.cs +++ b/Source/JobDrivers/JobDriver_JoinInBed.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using RimWorld; using Verse; using Verse.AI; +using Multiplayer.API; namespace rjw { @@ -24,6 +25,7 @@ namespace rjw return Top.Reserve(Partner, job, xxx.max_rapists_per_prisoner, 0, null, errorOnFailed); } + [SyncMethod] protected override IEnumerable<Toil> MakeNewToils() { //--Log.Message("JobDriver_JoinInBed::MakeNewToils() called"); @@ -39,6 +41,8 @@ namespace rjw initAction = delegate { //--Log.Message("JobDriver_JoinInBed::MakeNewToils() - setting initAction"); + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); ticks_left = (int)(2500.0f * Rand.Range(0.30f, 1.30f)); Job gettin_loved = new Job(xxx.gettin_loved, Top, Bed); Partner.jobs.StartJob(gettin_loved, JobCondition.InterruptForced); diff --git a/Source/JobDrivers/JobDriver_PrisonerComfortRapin.cs b/Source/JobDrivers/JobDriver_PrisonerComfortRapin.cs index 87df4f76740d89f9ce2d9c63b1de3daa889a743c..16921eb099a9ea7358f2959062ca257199d08752 100644 --- a/Source/JobDrivers/JobDriver_PrisonerComfortRapin.cs +++ b/Source/JobDrivers/JobDriver_PrisonerComfortRapin.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using RimWorld; using Verse; using Verse.AI; +using Multiplayer.API; namespace rjw { @@ -24,6 +25,7 @@ namespace rjw return pawn.Reserve(Target, job, xxx.max_rapists_per_prisoner, 0, null, errorOnFailed); } + [SyncMethod] public virtual void roll_to_hit(Pawn rapist, Pawn p) { if (!RJWSettings.rape_beating) @@ -31,6 +33,8 @@ namespace rjw return; } + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); float rand_value = Rand.Value; float victim_pain = p.health.hediffSet.PainTotal; // bloodlust makes the aggressor more likely to hit the prisoner @@ -62,8 +66,11 @@ namespace rjw */ } + [SyncMethod] protected override IEnumerable<Toil> MakeNewToils() { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); duration = (int)(2000.0f * Rand.Range(0.50f, 0.90f)); ticks_between_hearts = Rand.RangeInclusive(70, 130); ticks_between_hits = Rand.Range(xxx.config.min_ticks_between_hits, xxx.config.max_ticks_between_hits); diff --git a/Source/JobDrivers/JobDriver_QuickFap.cs b/Source/JobDrivers/JobDriver_QuickFap.cs index 10647b7657117fd7619a3ccafc5d0d570e94a1e0..dc56f0c333ad688aeb9ad111b5dc7c3f16ffa5bc 100644 --- a/Source/JobDrivers/JobDriver_QuickFap.cs +++ b/Source/JobDrivers/JobDriver_QuickFap.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using RimWorld; using Verse; using Verse.AI; +using Multiplayer.API; namespace rjw { @@ -17,6 +18,7 @@ namespace rjw return true; // No reservations needed. } + [SyncMethod] protected override IEnumerable<Toil> MakeNewToils() { //this.FailOn(() => PawnUtility.PlayerForcedJobNowOrSoon(pawn)); @@ -25,6 +27,8 @@ namespace rjw this.FailOn(() => pawn.IsFighting()); this.FailOn(() => pawn.Drafted); + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); // Faster fapping when frustrated. ticks_left = (int)(xxx.need_some_sex(pawn) > 2f ? 2500.0f * Rand.Range(0.2f, 0.7f) : 2500.0f * Rand.Range(0.2f, 0.4f)); diff --git a/Source/JobDrivers/JobDriver_Rape.cs b/Source/JobDrivers/JobDriver_Rape.cs index 0a67181091234133d39e1c1f32103cca7e736543..3fac0d21ee0c208556a104ea63e0a875c58a1881 100644 --- a/Source/JobDrivers/JobDriver_Rape.cs +++ b/Source/JobDrivers/JobDriver_Rape.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using RimWorld; using Verse; using Verse.AI; +using Multiplayer.API; namespace rjw { @@ -22,11 +23,14 @@ namespace rjw return pawn.Reserve(Target, job, xxx.max_rapists_per_prisoner, 0, null, errorOnFailed); } + [SyncMethod] public static void roll_to_hit(Pawn rapist, Pawn p) { if (!RJWSettings.rape_beating) return; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); float rand_value = Rand.Value; float victim_pain = p.health.hediffSet.PainTotal; // bloodlust makes the aggressor more likely to hit the prisoner @@ -56,8 +60,11 @@ namespace rjw */ } + [SyncMethod] protected override IEnumerable<Toil> MakeNewToils() { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); //Log.Message("[RJW]" + this.GetType().ToString() + "::MakeNewToils() called"); duration = (int)(2000.0f * Rand.Range(0.50f, 0.90f)); ticks_between_hearts = Rand.RangeInclusive(70, 130); diff --git a/Source/JobDrivers/JobDriver_Sex.cs b/Source/JobDrivers/JobDriver_Sex.cs new file mode 100644 index 0000000000000000000000000000000000000000..3ca939c0e0004aba3873f3791abf36f129ebb59c --- /dev/null +++ b/Source/JobDrivers/JobDriver_Sex.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using RimWorld; +using Verse; +using Verse.AI; + +namespace rjw +{ + public abstract class JobDriver_Sex : JobDriver + { + protected float satisfaction = 1.0f; + + public bool shouldreserve = true; + + public int maxPawns = 1; + public int stackCount = 0; + + public int ticks_between_hearts; + public int ticks_between_hits = 50; + public int ticks_between_thrusts; + + public Thing Target = null; + + //private Building_Bed Bed; + + public override bool TryMakePreToilReservations(bool errorOnFailed) + { + Log.Message("shouldreserve " + shouldreserve); + if (shouldreserve) + return pawn.Reserve(Target, job, maxPawns, stackCount, null, errorOnFailed); + else + return true; // No reservations needed. + + //return this.pawn.Reserve(this.Partner, this.job, 1, 0, null) && this.pawn.Reserve(this.Bed, this.job, 1, 0, null); + } + + public void CalculateSatisfactionPerTick() + { + satisfaction = 1.0f; + } + + protected override IEnumerable<Toil> MakeNewToils() + { + return null; + } + } +} \ No newline at end of file diff --git a/Source/JobDrivers/JobDriver_ViolateCorpse.cs b/Source/JobDrivers/JobDriver_ViolateCorpse.cs index 2239cd57949948a46723a284886346ced328b0c6..52d11437602728ae87a2bb4e8279eb3ff28a6d72 100644 --- a/Source/JobDrivers/JobDriver_ViolateCorpse.cs +++ b/Source/JobDrivers/JobDriver_ViolateCorpse.cs @@ -3,6 +3,7 @@ using RimWorld; using Verse; using Verse.AI; using Verse.Sound; +using Multiplayer.API; namespace rjw { @@ -14,9 +15,9 @@ namespace rjw private int ticks_between_thrusts; protected TargetIndex icorpse = TargetIndex.A; - protected Corpse corpse => (Corpse)(job.GetTarget(icorpse)); + protected Corpse Target => (Corpse)(job.GetTarget(icorpse)); - public static void sexTick(Pawn pawn, Thing corpse) + public static void sexTick(Pawn pawn, Thing Target) { if (!xxx.has_quirk(pawn, "Endytophile")) { @@ -26,18 +27,21 @@ namespace rjw if (RJWSettings.sounds_enabled) SoundDef.Named("Sex").PlayOneShot(new TargetInfo(pawn.Position, pawn.Map)); - pawn.Drawer.Notify_MeleeAttackOn(corpse); - pawn.rotationTracker.FaceCell(corpse.Position); + pawn.Drawer.Notify_MeleeAttackOn(Target); + pawn.rotationTracker.FaceCell(Target.Position); } public override bool TryMakePreToilReservations(bool errorOnFailed) { - return pawn.Reserve(corpse, job, 1, -1, null, errorOnFailed); + return pawn.Reserve(Target, job, 1, -1, null, errorOnFailed); } + [SyncMethod] protected override IEnumerable<Toil> MakeNewToils() { //--Log.Message("[RJW] JobDriver_ViolateCorpse::MakeNewToils() called"); + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); duration = (int)(2000.0f * Rand.Range(0.50f, 0.90f)); ticks_between_hearts = Rand.RangeInclusive(70, 130); ticks_between_hits = Rand.Range(xxx.config.min_ticks_between_hits, xxx.config.max_ticks_between_hits); @@ -49,33 +53,33 @@ namespace rjw ticks_between_hits = (int)(ticks_between_hits * 0.90); this.FailOnDespawnedNullOrForbidden(icorpse); - this.FailOn(() => !pawn.CanReserve(corpse, 1, 0)); // Fail if someone else reserves the prisoner before the pawn arrives + this.FailOn(() => !pawn.CanReserve(Target, 1, 0)); // Fail if someone else reserves the prisoner before the pawn arrives this.FailOn(() => pawn.IsFighting()); this.FailOn(() => pawn.Drafted); - this.FailOn(corpse.IsBurning); + this.FailOn(Target.IsBurning); - //--Log.Message("[RJW] JobDriver_ViolateCorpse::MakeNewToils() - moving towards corpse"); + //--Log.Message("[RJW] JobDriver_ViolateCorpse::MakeNewToils() - moving towards Target"); yield return Toils_Goto.GotoThing(icorpse, PathEndMode.OnCell); var alert = RJWPreferenceSettings.rape_alert_sound == RJWPreferenceSettings.RapeAlert.Disabled ? MessageTypeDefOf.SilentInput : MessageTypeDefOf.NeutralEvent; - Messages.Message(pawn.Name + " is trying to rape a corpse.", pawn, alert); + Messages.Message(pawn.Name + " is trying to rape a Target.", pawn, alert); var rape = new Toil(); rape.initAction = delegate { - //--Log.Message("[RJW] JobDriver_ViolateCorpse::MakeNewToils() - reserving corpse"); - //pawn.Reserve(corpse, 1, 0); // corpse rapin seems like a solitary activity + //--Log.Message("[RJW] JobDriver_ViolateCorpse::MakeNewToils() - reserving Target"); + //pawn.Reserve(Target, 1, 0); // Target rapin seems like a solitary activity - //--Log.Message("[RJW] JobDriver_ViolateCorpse::MakeNewToils() - stripping corpse"); - corpse.Strip(); + //--Log.Message("[RJW] JobDriver_ViolateCorpse::MakeNewToils() - stripping Target"); + Target.Strip(); }; rape.tickAction = delegate { if (pawn.IsHashIntervalTick(ticks_between_hearts)) MoteMaker.ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Heart); if (pawn.IsHashIntervalTick(ticks_between_thrusts)) - sexTick(pawn, corpse); + sexTick(pawn, Target); /* if (pawn.IsHashIntervalTick (ticks_between_hits)) roll_to_hit (pawn, Corpse); @@ -96,10 +100,10 @@ namespace rjw initAction = delegate { //--Log.Message("[RJW] JobDriver_ViolateCorpse::MakeNewToils() - creating aftersex toil"); - //Addded by nizhuan-jjr: Try to apply an aftersex process for the pawn and the corpse - if (corpse.InnerPawn != null) + //Addded by nizhuan-jjr: Try to apply an aftersex process for the pawn and the Target + if (Target.InnerPawn != null) { - SexUtility.ProcessSex(pawn, corpse.InnerPawn, true); + SexUtility.ProcessSex(pawn, Target.InnerPawn, true); } }, defaultCompleteMode = ToilCompleteMode.Instant diff --git a/Source/JobGivers/JobGiver_AIRapePrisoner.cs b/Source/JobGivers/JobGiver_AIRapePrisoner.cs index 749e0107d0ff42cf529f0dbe6fded8352862ed08..5d95e4a1cf8fbaa5407fca249dfc271d61cc399d 100644 --- a/Source/JobGivers/JobGiver_AIRapePrisoner.cs +++ b/Source/JobGivers/JobGiver_AIRapePrisoner.cs @@ -3,6 +3,7 @@ using RimWorld; using Verse; using Verse.AI; using System.Collections.Generic; +using Multiplayer.API; namespace rjw { @@ -11,6 +12,7 @@ namespace rjw { private const float min_fuckability = 0.10f; // Don't rape prisoners with <10% fuckability + [SyncMethod] public static Pawn find_victim(Pawn rapist, Map m) { IEnumerable<Pawn> possible_targets = m.mapPawns.AllPawns.Where(x @@ -33,6 +35,8 @@ namespace rjw } } + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); return valid_targets.Any() ? valid_targets.RandomElement() : null; } diff --git a/Source/JobGivers/JobGiver_Breed.cs b/Source/JobGivers/JobGiver_Breed.cs index a274af5ccdc810bac158a69565d42a10eb8575e6..9789ca50f33a8d5864f40f4f6d9d85a1863d577a 100644 --- a/Source/JobGivers/JobGiver_Breed.cs +++ b/Source/JobGivers/JobGiver_Breed.cs @@ -1,6 +1,7 @@ using Verse; using Verse.AI; using System.Collections.Generic; +using Multiplayer.API; namespace rjw { @@ -9,6 +10,7 @@ namespace rjw /// </summary> public class JobGiver_Breed : ThinkNode_JobGiver { + [SyncMethod] protected override Job TryGiveJob(Pawn animal) { //Log.Message("[RJW] JobGiver_Breed::TryGiveJob( " + xxx.get_pawnname(animal) + " ) called0" + (SexUtility.ReadyForLovin(animal))); @@ -64,6 +66,8 @@ namespace rjw if (valid_targets != null && valid_targets.Any()) { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); var target = valid_targets.RandomElement(); //Log.Message("Target: " + xxx.get_pawnname(target)); return new Job(DefDatabase<JobDef>.GetNamed("Breed"), target, animal); diff --git a/Source/JobGivers/JobGiver_DoFappin.cs b/Source/JobGivers/JobGiver_DoFappin.cs index 047fa17d0e09d478ec7bfe50d2dd85601acefca9..995bde9755da73cf7c91842e894d987d11ad39f8 100644 --- a/Source/JobGivers/JobGiver_DoFappin.cs +++ b/Source/JobGivers/JobGiver_DoFappin.cs @@ -3,11 +3,13 @@ using Verse; using Verse.AI; using System.Collections.Generic; using System.Linq; +using Multiplayer.API; namespace rjw { public class JobGiver_DoFappin : ThinkNode_JobGiver { + [SyncMethod] public virtual IntVec3 FindFapLocation(Pawn p) { IntVec3 position = p.Position; @@ -26,6 +28,8 @@ namespace rjw //Log.Message("[RJW] Pawn is " + xxx.get_pawnname(p) + ", current cell is " + cell); + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); List<IntVec3> random_cells = new List<IntVec3>(); for (int loop = 0; loop < 50; ++loop) { diff --git a/Source/JobGivers/JobGiver_JoinInBed.cs b/Source/JobGivers/JobGiver_JoinInBed.cs index 64db0361605e282de7334780e7953738bc6e649b..b5a022069908ed6cdd76f3f40a057d2cbb6ee205 100644 --- a/Source/JobGivers/JobGiver_JoinInBed.cs +++ b/Source/JobGivers/JobGiver_JoinInBed.cs @@ -3,6 +3,7 @@ using System.Linq; using RimWorld; using Verse; using Verse.AI; +using Multiplayer.API; namespace rjw { @@ -13,19 +14,25 @@ namespace rjw return xxx.is_healthy(target) && (xxx.can_fuck(target) || xxx.can_be_fucked(target)); } + [SyncMethod] private static bool roll_to_skip(Pawn pawn, Pawn target) { float fuckability = xxx.would_fuck(pawn, target); // 0.0 to 1.0 if (fuckability < 0.1f) return false; float chance_to_skip = 0.9f - 0.7f * fuckability; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); return Rand.Value < chance_to_skip; } + [SyncMethod] public static Pawn find_pawn_to_fuck(Pawn pawn, Map map) { Pawn best_fuckee = null; float best_distance = 1.0e6f; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); List<Pawn> targets = map.mapPawns.FreeColonists.Where(x => x.InBed() diff --git a/Source/Modules/Bondage/Comps/CompHoloCryptoStamped.cs b/Source/Modules/Bondage/Comps/CompHoloCryptoStamped.cs index 78fdbcc6eb9d7241d3afb5f111dcc4baa3eb12d7..8a35a48f606e8b092165d2be927ba94a192c02ea 100644 --- a/Source/Modules/Bondage/Comps/CompHoloCryptoStamped.cs +++ b/Source/Modules/Bondage/Comps/CompHoloCryptoStamped.cs @@ -1,6 +1,7 @@ using System; using RimWorld; using Verse; +using Multiplayer.API; namespace rjw { @@ -9,8 +10,11 @@ namespace rjw public string name; public string key; + [SyncMethod] public string random_hex_byte() { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); var rv = Rand.RangeInclusive(0x00, 0xFF); var padding = (rv < 0x10) ? "0" : ""; return padding + rv.ToString("X"); diff --git a/Source/Modules/Bondage/Recipes/Recipe_ForceOffGear.cs b/Source/Modules/Bondage/Recipes/Recipe_ForceOffGear.cs index f897d96725627a0445b035d6521b0ca78f63d28d..10f02816890dc2ccc1584bf83c1ef5b905f2bf88 100644 --- a/Source/Modules/Bondage/Recipes/Recipe_ForceOffGear.cs +++ b/Source/Modules/Bondage/Recipes/Recipe_ForceOffGear.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using RimWorld; using Verse; +using Multiplayer.API; namespace rjw { @@ -29,6 +30,7 @@ namespace rjw yield return null; } + [SyncMethod] public static void apply_burns(Pawn p, List<BodyPartDef> parts, float min_severity, float max_severity) { foreach (var part in parts) @@ -36,6 +38,8 @@ namespace rjw var rec = find_part_record(part, p); if (rec != null) { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); var to_deal = Rand.Range(min_severity, max_severity) * part.GetMaxHealth(p); var dealt = 0.0f; var counter = 0; @@ -50,6 +54,7 @@ namespace rjw } } + [SyncMethod] public override void ApplyOnPawn(Pawn p, BodyPartRecord null_part, Pawn surgeon, List<Thing> ingredients,Bill bill) { var r = (force_off_gear_def)recipe; @@ -66,6 +71,8 @@ namespace rjw } // Destroy parts + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); var def_to_destroy = r.destroys_one_of.RandomElement<BodyPartDef>(); if (def_to_destroy != null) { diff --git a/Source/Modules/Multiplayer/Multiplayer.cs b/Source/Modules/Multiplayer/Multiplayer.cs index 8e16f001f55f14635981dd56706917dc8d768b93..429fd2f1882a823359b27d99aaa2b3dceb3e2369 100644 --- a/Source/Modules/Multiplayer/Multiplayer.cs +++ b/Source/Modules/Multiplayer/Multiplayer.cs @@ -1,6 +1,6 @@ -using Multiplayer.API; using Verse; -using Harmony; +using RimWorld; +using Multiplayer.API; namespace rjw { @@ -15,18 +15,23 @@ namespace rjw // auto register, similar to Harmony's PatchAll. MP.RegisterAll(); - var type = AccessTools.TypeByName("rjw.RJWdesignations"); + /* + Log.Message("RJW MP compat testing"); + var type = AccessTools.TypeByName("rjw.RJWdesignations"); + //Log.Message("rjw MP compat " + type.Name); + Log.Message("is host " + MP.IsHosting); + Log.Message("PlayerName " + MP.PlayerName); + Log.Message("IsInMultiplayer " + MP.IsInMultiplayer); - Log.Message("rjw MP compat " + type.Name); - //MP.RegisterSyncMethod(type, "Comfort"); - /* - MP.RegisterSyncMethod(type, "<GetGizmos>Service"); - MP.RegisterSyncMethod(type, "<GetGizmos>BreedingHuman"); - MP.RegisterSyncMethod(type, "<GetGizmos>BreedingAnimal"); - MP.RegisterSyncMethod(type, "<GetGizmos>Breeder"); - MP.RegisterSyncMethod(type, "<GetGizmos>Milking"); - MP.RegisterSyncMethod(type, "<GetGizmos>Hero"); - */ + //MP.RegisterSyncMethod(type, "Comfort"); + /* + MP.RegisterSyncMethod(type, "<GetGizmos>Service"); + MP.RegisterSyncMethod(type, "<GetGizmos>BreedingHuman"); + MP.RegisterSyncMethod(type, "<GetGizmos>BreedingAnimal"); + MP.RegisterSyncMethod(type, "<GetGizmos>Breeder"); + MP.RegisterSyncMethod(type, "<GetGizmos>Milking"); + MP.RegisterSyncMethod(type, "<GetGizmos>Hero"); + */ // You can choose to not auto register and do it manually @@ -35,5 +40,26 @@ namespace rjw // Use MP.IsInMultiplayer to act upon it in other places // user can have it enabled and not be in session } + + //generate PredictableSeed for Verse.Rand + public static int PredictableSeed() + { + int seed = 0; + try + { + Map map = Find.CurrentMap; + //int seedHourOfDay = GenLocalDate.HourOfDay(map); + //int seedDayOfYear = GenLocalDate.DayOfYear(map); + //int seedYear = GenLocalDate.Year(map); + seed = (GenLocalDate.HourOfDay(map) + GenLocalDate.DayOfYear(map)) * GenLocalDate.Year(map); + //int seed = (seedHourOfDay + seedDayOfYear) * seedYear; + //Log.Warning("seedHourOfDay: " + seedHourOfDay + "\nseedDayOfYear: " + seedDayOfYear + "\nseedYear: " + seedYear + "\n" + seed); + } + catch + { + seed = Rand.Int; + } + return seed; + } } } \ No newline at end of file diff --git a/Source/Modules/Nymphs/Incidents/IncidentWorker_NymphJoins.cs b/Source/Modules/Nymphs/Incidents/IncidentWorker_NymphJoins.cs index fd18818550a5588e692d7142a5462fab3a7e5cce..ffb776fa24cede71d2e7573a0997ce28023d7b50 100644 --- a/Source/Modules/Nymphs/Incidents/IncidentWorker_NymphJoins.cs +++ b/Source/Modules/Nymphs/Incidents/IncidentWorker_NymphJoins.cs @@ -1,6 +1,7 @@ using System.Linq; using RimWorld; using Verse; +using Multiplayer.API; namespace rjw { @@ -17,6 +18,7 @@ namespace rjw return colonist_count >= 1 && (nymph_fraction < xxx.config.max_nymph_fraction); } + [SyncMethod] protected override bool TryExecuteWorker(IncidentParms parms) { //--Log.Message("IncidentWorker_NymphJoins::TryExecute() called"); @@ -34,6 +36,8 @@ namespace rjw //--Log.Message("IncidentWorker_NymphJoins::TryExecute() - map is ok"); } + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); if (!RCellFinder.TryFindRandomPawnEntryCell(out IntVec3 loc, map, CellFinder.EdgeRoadChance_Friendly + 0.2f)) { //--Log.Message("IncidentWorker_NymphJoins::TryExecute() - no entry, abort!"); diff --git a/Source/Modules/Nymphs/Incidents/IncidentWorker_NymphVisitorGroup.cs b/Source/Modules/Nymphs/Incidents/IncidentWorker_NymphVisitorGroup.cs index b9a6c2573172609cdcec01ab1a16697825316025..37944c316c9dd8d23739fc88b107f581201f89aa 100644 --- a/Source/Modules/Nymphs/Incidents/IncidentWorker_NymphVisitorGroup.cs +++ b/Source/Modules/Nymphs/Incidents/IncidentWorker_NymphVisitorGroup.cs @@ -1,5 +1,6 @@ using RimWorld; using Verse; +using Multiplayer.API; namespace rjw { @@ -24,6 +25,7 @@ namespace rjw } } + [SyncMethod] protected override bool TryExecuteWorker(IncidentParms parms) { //--Log.Message("IncidentWorker_NymphVisitorGroup::TryExecute() called"); @@ -45,6 +47,8 @@ namespace rjw //--Log.Message("IncidentWorker_NymphJoins::TryExecute() - map is ok"); } + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); if (!RCellFinder.TryFindRandomPawnEntryCell(out IntVec3 loc, map, CellFinder.EdgeRoadChance_Friendly + 0.2f)) { //--Log.Message("IncidentWorker_NymphJoins::TryExecute() - no entry, abort!"); diff --git a/Source/Modules/Nymphs/Pawns/Nymph_Backstories.cs b/Source/Modules/Nymphs/Pawns/Nymph_Backstories.cs index 44fed8777c5283095186fe1b15b1c3945e54c75d..e05aad119d7cf871ad8dac5a8e730e942e5adcb6 100644 --- a/Source/Modules/Nymphs/Pawns/Nymph_Backstories.cs +++ b/Source/Modules/Nymphs/Pawns/Nymph_Backstories.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using RimWorld; using Verse; +using Multiplayer.API; namespace rjw { @@ -325,6 +326,7 @@ namespace rjw } // Randomly chooses backstories and traits for a nymph + [SyncMethod] public static nymph_story generate() { var tr = new nymph_story(); @@ -334,6 +336,8 @@ namespace rjw tr.traits = new List<Trait>(); tr.traits.Add(new Trait(xxx.nymphomaniac, 0, true)); + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); var beauty = 0; var rv = Rand.Value; var rv2 = Rand.Value; diff --git a/Source/Modules/Nymphs/Pawns/Nymph_Generator.cs b/Source/Modules/Nymphs/Pawns/Nymph_Generator.cs index 240613815039ce609a66aa80963fa3b914b6333f..23d669d59a4f269e76591ab65d5b30916dd89245 100644 --- a/Source/Modules/Nymphs/Pawns/Nymph_Generator.cs +++ b/Source/Modules/Nymphs/Pawns/Nymph_Generator.cs @@ -3,6 +3,7 @@ using RimWorld; using UnityEngine; using Verse; using System; +using Multiplayer.API; namespace rjw { @@ -16,10 +17,13 @@ namespace rjw return false; } + [SyncMethod] public static Gender setnymphgender() { //with males 100% its still 99%, coz im to lazy to fix it //float rnd = Rand.Value; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); float chance = RJWSettings.male_nymph_chance; Gender Pawngender = Rand.Chance(chance) ? Gender.Male: Gender.Female; @@ -29,6 +33,7 @@ namespace rjw } // Replaces a pawn's backstory and traits to turn it into a nymph + [SyncMethod] public static void set_story(Pawn pawn) { var gen_sto = nymph_backstories.generate(); @@ -41,6 +46,8 @@ namespace rjw { BodyPartRecord torso = pawn.RaceProps.body.AllParts.Find((bpr) => String.Equals(bpr.def.defName, "Torso")); pawn.health.AddHediff(xxx.feelingBroken, torso); + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); (pawn.health.hediffSet.GetFirstHediffOfDef(xxx.feelingBroken)).Severity = Rand.Range(0.4f, 1.0f); } @@ -73,6 +80,7 @@ namespace rjw } } + [SyncMethod] private static int sum_previous_gains(SkillDef def, Pawn_StoryTracker sto, Pawn_AgeTracker age) { int total_gain = 0; @@ -90,6 +98,8 @@ namespace rjw total_gain += gain; // Gains from age + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); var rgain = Rand.Value * (float)total_gain * 0.35f; var age_factor = Mathf.Clamp01((age.AgeBiologicalYearsFloat - 17.0f) / 10.0f); // Assume nymphs are 17~27 total_gain += (int)(age_factor * rgain); @@ -98,6 +108,7 @@ namespace rjw } // Set a nymph's initial skills & passions from backstory, traits, and age + [SyncMethod] public static void set_skills(Pawn pawn) { foreach (var skill_def in DefDatabase<SkillDef>.AllDefsListForReading) @@ -105,6 +116,8 @@ namespace rjw var rec = pawn.skills.GetSkill(skill_def); if (!rec.TotallyDisabled) { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); rec.Level = sum_previous_gains(skill_def, pawn.story, pawn.ageTracker); rec.xpSinceLastLevel = rec.XpRequiredForLevelUp * Rand.Range(0.10f, 0.90f); @@ -126,6 +139,7 @@ namespace rjw set_skills(pawn); } + [SyncMethod] public static Pawn spawn_nymph(IntVec3 around_loc, ref Map map, Faction faction = null) { PawnKindDef pkd; @@ -162,6 +176,8 @@ namespace rjw null); // Fixed last name + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); IntVec3 spawn_loc = CellFinder.RandomClosewalkCellNear(around_loc, map, 6);//RandomSpawnCellForPawnNear could be an alternative //Log.Message("[RJW] spawn_nymph1: " + request.FixedGender); diff --git a/Source/Modules/Pregnancy/Hediffs/HeDiff_MicroComputer.cs b/Source/Modules/Pregnancy/Hediffs/HeDiff_MicroComputer.cs index 885721dd35813d85e4bfbe23904e6a49591b11a8..a5781fd090ae38dc19ff53024f58a79504ddf0c9 100644 --- a/Source/Modules/Pregnancy/Hediffs/HeDiff_MicroComputer.cs +++ b/Source/Modules/Pregnancy/Hediffs/HeDiff_MicroComputer.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using Verse; +using Multiplayer.API; namespace rjw { @@ -14,9 +15,12 @@ namespace rjw Scribe_Values.Look<int>(ref this.nextEventTick, "nextEventTick", 60000, false); } + [SyncMethod] public override void PostMake() { base.PostMake(); + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); nextEventTick = Rand.Range(mcDef.minEventInterval, mcDef.maxEventInterval); } @@ -43,17 +47,28 @@ namespace rjw protected HediffDef_MechImplants mcDef { - get { return ((HediffDef_MechImplants)def); } + get + { + return ((HediffDef_MechImplants)def); + } } protected List<string> randomEffects { - get { return mcDef.randomHediffDefs; } + get + { + return mcDef.randomHediffDefs; + } } protected string randomEffect { - get { return randomEffects.RandomElement<string>(); } + get + { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); + return randomEffects.RandomElement<string>(); + } } } } \ No newline at end of file diff --git a/Source/Modules/Pregnancy/Hediffs/Hediff_BasePregnancy.cs b/Source/Modules/Pregnancy/Hediffs/Hediff_BasePregnancy.cs index b09f3b3ae497d088c62d3118a5ab010775ef76be..3be16448256090eb3c3e2d56506a05ce58bc1b8a 100644 --- a/Source/Modules/Pregnancy/Hediffs/Hediff_BasePregnancy.cs +++ b/Source/Modules/Pregnancy/Hediffs/Hediff_BasePregnancy.cs @@ -4,6 +4,7 @@ using RimWorld; using Verse; using UnityEngine; using System.Text; +using Multiplayer.API; namespace rjw { @@ -146,11 +147,14 @@ namespace rjw pawn.health?.RemoveHediff(this); } + [SyncMethod] public Pawn partstospawn(Pawn baby, Pawn mother, Pawn dad) { //decide what parts to inherit //default use own parts Pawn partstospawn = baby; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); //spawn with mother parts if (mother != null && Rand.Range(0, 100) <= 10) partstospawn = mother; @@ -162,6 +166,7 @@ namespace rjw return partstospawn; } + [SyncMethod] public bool spawnfutachild(Pawn baby, Pawn mother, Pawn dad) { int futachance = 0; @@ -171,9 +176,12 @@ namespace rjw futachance = futachance + 25; //Log.Message("[RJW] Pregnancy spawnfutachild " + futachance); + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); return (Rand.Range(0, 100) <= futachance); } + [SyncMethod] public override void Tick() { ageTicks++; @@ -276,6 +284,7 @@ namespace rjw } //This should generate pawns to be born in due time. Should take into account all settings and parent races + [SyncMethod] protected virtual void GenerateBabies() { Pawn mother = pawn; @@ -286,6 +295,8 @@ namespace rjw return; } + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); if (father == null) { Log.Warning("Hediff_BasePregnancy::GenerateBabies() - no father defined"); @@ -320,6 +331,8 @@ namespace rjw //Babies will have average number of traits of their parents, this way it will hopefully be compatible with various mods that change number of allowed traits int trait_count = 0; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); List<Trait> traitpool = new List<Trait>(); float skin_whiteness = Rand.Range(0, 1); @@ -613,6 +626,7 @@ namespace rjw contractions = 0; //Log.Message("[RJW]Base pregnancy generating babies before: " + this.babies.Count); GenerateBabies(); + //progress_per_tick = babies.NullOrEmpty() ? 1f : (1.0f) / (babies[0].RaceProps.gestationPeriodDays * TicksPerDay/50); progress_per_tick = babies.NullOrEmpty() ? 1f : (1.0f) / (babies[0].RaceProps.gestationPeriodDays * TicksPerDay); //Log.Message("[RJW]Base pregnancy generating babies after: " + this.babies.Count); } @@ -622,6 +636,7 @@ namespace rjw StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(base.DebugString()); stringBuilder.AppendLine("Gestation progress: " + GestationProgress.ToStringPercent()); + //stringBuilder.AppendLine("Time left: " + ((int)((1f - GestationProgress) * babies[0].RaceProps.gestationPeriodDays * TicksPerDay/50)).ToStringTicksToPeriod()); stringBuilder.AppendLine("Time left: " + ((int)((1f - GestationProgress) * babies[0].RaceProps.gestationPeriodDays * TicksPerDay)).ToStringTicksToPeriod()); stringBuilder.AppendLine(" Father: " + xxx.get_pawnname(father)); return stringBuilder.ToString(); diff --git a/Source/Modules/Pregnancy/Hediffs/Hediff_InsectEggPregnancy.cs b/Source/Modules/Pregnancy/Hediffs/Hediff_InsectEggPregnancy.cs index 98569e84a91e79c408aab81cee5c95e5a03cbad4..719c66953779e6af1df8f706cff7283445f09553 100644 --- a/Source/Modules/Pregnancy/Hediffs/Hediff_InsectEggPregnancy.cs +++ b/Source/Modules/Pregnancy/Hediffs/Hediff_InsectEggPregnancy.cs @@ -4,6 +4,7 @@ using RimWorld.Planet; using Verse; using System.Text; using Verse.AI.Group; +using Multiplayer.API; namespace rjw { @@ -126,10 +127,13 @@ namespace rjw } //should someday remake into birth eggs and then within few ticks hatch them + [SyncMethod] public void GiveBirth() { Pawn mother = pawn; Pawn baby = null; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); if (fertilized) { //Log.Message("[RJW]Hediff_InsectEgg::BirthBaby() - Egg of " + parentDef + " in " + mother.ToString() + " birth!"); diff --git a/Source/Modules/Pregnancy/Hediffs/Hediff_ParasitePregnancy.cs b/Source/Modules/Pregnancy/Hediffs/Hediff_ParasitePregnancy.cs index 1ab68a6a641abde7c575d756152756be16ebc3e0..cea435a64856122a35ea834884e115dc61c5760a 100644 --- a/Source/Modules/Pregnancy/Hediffs/Hediff_ParasitePregnancy.cs +++ b/Source/Modules/Pregnancy/Hediffs/Hediff_ParasitePregnancy.cs @@ -2,13 +2,17 @@ using RimWorld.Planet; using UnityEngine; using Verse; +using Multiplayer.API; namespace rjw { internal class Hediff_Parasite : Hediff_Pregnant { + [SyncMethod] new public static void DoBirthSpawn(Pawn mother, Pawn father) { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); int num = (mother.RaceProps.litterSizeCurve == null) ? 1 : Mathf.RoundToInt(Rand.ByCurve(mother.RaceProps.litterSizeCurve)); if (num < 1) { diff --git a/Source/Modules/Pregnancy/Hediffs/Hediff_SimpleBaby.cs b/Source/Modules/Pregnancy/Hediffs/Hediff_SimpleBaby.cs index 4532a15e0a75d7c9f38621adddff37f0f3f3cc07..4125363611519f0d224fce2140a5b942459ad1c6 100644 --- a/Source/Modules/Pregnancy/Hediffs/Hediff_SimpleBaby.cs +++ b/Source/Modules/Pregnancy/Hediffs/Hediff_SimpleBaby.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Text; using RimWorld; using Verse; +using Multiplayer.API; namespace rjw { @@ -59,8 +60,11 @@ namespace rjw GrowUpTo(stage, true); } + [SyncMethod] internal void GrowUpTo(int stage, bool generated) { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); grown_to = stage; // Update the Colonist Bar @@ -180,6 +184,8 @@ namespace rjw } // People(male or female) can turn gay during puberty + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); if (Rand.Value <= 0.03f && pawn.story.traits.allTraits.Count <= 3) { pawn.story.traits.GainTrait(new Trait(TraitDefOf.Gay, 0, true)); diff --git a/Source/Modules/Pregnancy/Pregnancy_Helper.cs b/Source/Modules/Pregnancy/Pregnancy_Helper.cs index 1224f361890fca849cd0448e527117d32bbf4bda..1e9e314060c6dcecaadcba13dd55181c7c16d89f 100644 --- a/Source/Modules/Pregnancy/Pregnancy_Helper.cs +++ b/Source/Modules/Pregnancy/Pregnancy_Helper.cs @@ -1,9 +1,9 @@ using RimWorld; using Verse; -using System.Reflection; using System; using System.Linq; using System.Collections.Generic; +using Multiplayer.API; ///RimWorldChildren pregnancy: //using RimWorldChildren; @@ -53,6 +53,8 @@ namespace rjw // Not an actual pregnancy. This implants mechanoid tech into the target. //may lead to pregnancy //old "chip pregnancies", maybe integrate them somehow? + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); HediffDef_MechImplants egg = (from x in DefDatabase<HediffDef_MechImplants>.AllDefs select x).RandomElement(); if (egg != null) { @@ -122,6 +124,7 @@ namespace rjw ///<summary>Can get preg with above conditions, do impregnation.</summary> + [SyncMethod] public static void DoEgg(Pawn pawn, Pawn partner) { if (RJWPregnancySettings.insect_pregnancy_enabled) @@ -144,6 +147,8 @@ namespace rjw float eggssize = ((xxx.is_human(pawn) || !xxx.is_insect(pawn)) && !EggRace_filter.Contains(pawn.kindDef.race.defName)) ? 0.04f : pawn.RaceProps.baseBodySize / 5; //TODO move "Megascarab" to InsectEgg and rework heddif, so it defaults to Megascarab if not insect //once there is some sort of genetic inheritance form parts/ovis + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); HediffDef_InsectEgg egg = (from x in DefDatabase<HediffDef_InsectEgg>.AllDefs where x.IsParent(defname) select x).RandomElement(); if (egg != null) { @@ -196,6 +201,7 @@ namespace rjw } } + [SyncMethod] public static void Doimpregnate(Pawn pawn, Pawn partner) { if (RJWSettings.DevMode) Log.Message("[RJW] Doimpregnate " + xxx.get_pawnname(pawn) + " is a father, " + xxx.get_pawnname(partner) + " is a mother"); @@ -213,6 +219,8 @@ namespace rjw fertility *= RJWPregnancySettings.interspecies_impregnation_modifier; } + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); float ReproductionFactor = Math.Min(pawn.health.capacities.GetLevel(xxx.reproduction), partner.health.capacities.GetLevel(xxx.reproduction)); float pregnancy_threshold = fertility * ReproductionFactor; float non_pregnancy_chance = Rand.Value; diff --git a/Source/Modules/STD/Thoughts/ThoughtWorker_ItchyCrotch.cs b/Source/Modules/STD/Thoughts/ThoughtWorker_ItchyCrotch.cs index 8202312c7f1262da88511454716663f51c730420..7a0c4703d64691232f20f62e45fdf0d6d8098cca 100644 --- a/Source/Modules/STD/Thoughts/ThoughtWorker_ItchyCrotch.cs +++ b/Source/Modules/STD/Thoughts/ThoughtWorker_ItchyCrotch.cs @@ -7,7 +7,7 @@ namespace rjw { protected override ThoughtState CurrentStateInternal(Pawn p) { - var sev = std.genital_rash_severity(p); + int sev = std.genital_rash_severity(p); if (sev <= 0) return ThoughtState.Inactive; else if (sev == 1) diff --git a/Source/Modules/STD/std.cs b/Source/Modules/STD/std.cs index 2d0c51e3164be617253bddf900ddc68cc988fb0b..52f805bb80b92b809b3ed173063d9cad078d20d9 100644 --- a/Source/Modules/STD/std.cs +++ b/Source/Modules/STD/std.cs @@ -3,6 +3,7 @@ using System.Text; using RimWorld; using UnityEngine; using Verse; +using Multiplayer.API; namespace rjw { @@ -123,6 +124,7 @@ namespace rjw return id != null && id.CurStageIndex > 0; } + [SyncMethod] public static void update_immunodeficiency(Pawn p) { float min_bf_for_id = 1.0f - immunodeficiency.minSeverity; @@ -162,6 +164,8 @@ namespace rjw // The new equation should be .1 = (1-x)^(24000/kj) // log(.1) = (24000/kj) log(1-x), so log(1-x)= (kj/24000) log(.1), 1-x = .1^(kj/24000), x= 1-.1^(kj/24000) // Since k=10,j=1, so kj=10, new x is 1-.1^(10/24000)=0.0009589504, let it be 959/1000000 + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); if (Rand.RangeInclusive(1, 1000000) <= 959 && Rand.Value < bf / min_bf_for_id) { BodyPartRecord part; @@ -194,9 +198,12 @@ namespace rjw } } + [SyncMethod] public static void roll_to_catch(Pawn catcher, Pawn pitcher) { if (!RJWSettings.stds_enabled) return; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); // Archotech genitalia automagically purge any known STDs. if (catcher.health.hediffSet.HasHediff(Genital_Helper.archotech_vagina) || pitcher.health.hediffSet.HasHediff(Genital_Helper.archotech_vagina) || @@ -280,6 +287,7 @@ namespace rjw } } + [SyncMethod] public static void generate_on(Pawn p) { if (p == null) return; @@ -289,6 +297,8 @@ namespace rjw if (!xxx.is_human(p)) return; float nymph_mul = !xxx.is_nympho(p) ? 1.0f : xxx.config.nymph_spawn_with_std_mul; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); foreach (std_def sd in all) if (Rand.Value < sd.spawn_chance * nymph_mul) { @@ -302,6 +312,7 @@ namespace rjw } } + [SyncMethod] public static void roll_for_syphilis_damage(Pawn p) { Hediff syp = p.health.hediffSet.GetFirstHediffOfDef(syphilis.hediff_def); @@ -315,6 +326,8 @@ namespace rjw // The new equation should be .7 = (1-x)^(400/kj) // 1-x = .7^(kj/400), x =1-.7^(kj/400) // Since k=10,j=1, so kj=10, new x is 1-.7^(10/400)=0.0088772362, let it be 888/100000 + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); if (Rand.RangeInclusive(1, 100000) <= 888) { BodyPartRecord part; diff --git a/Source/Modules/SemenOverlay/BukkakeContent.cs b/Source/Modules/SemenOverlay/BukkakeContent.cs index 5601e9be615ec105239b30d142cf25e1522ed2ca..dc3e488c7072aab87409cbee0c955d29fa9a52cd 100644 --- a/Source/Modules/SemenOverlay/BukkakeContent.cs +++ b/Source/Modules/SemenOverlay/BukkakeContent.cs @@ -1,6 +1,6 @@ using Verse; using UnityEngine; - +using Multiplayer.API; namespace rjw { @@ -25,8 +25,11 @@ namespace rjw public static readonly Material semenSplatch9 = MaterialPool.MatFrom("Bukkake/splatch_9", ShaderDatabase.Cutout); + [SyncMethod] public static Material pickRandomSplatch() { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); int rand = Rand.Range(0, 8); switch (rand) { diff --git a/Source/Modules/SemenOverlay/Hediffs/Hediff_Bukkake.cs b/Source/Modules/SemenOverlay/Hediffs/Hediff_Bukkake.cs index 4b6e53fb9074938c9ed42317a1b0eca6436cf0e8..b36d055e4b8aec23418c7744eea79c95ed37814a 100644 --- a/Source/Modules/SemenOverlay/Hediffs/Hediff_Bukkake.cs +++ b/Source/Modules/SemenOverlay/Hediffs/Hediff_Bukkake.cs @@ -138,6 +138,8 @@ namespace rjw semenMaterial = new Material(BukkakeContent.pickRandomSplatch());//needs to create new material in order to allow for different colors semenMaterial.SetTextureScale("_MainTex", new Vector2(-1, 1)); this.bodyPart = bodyPart; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); //set color: switch (semenType) diff --git a/Source/Modules/SemenOverlay/Hediffs/Hediff_Semen.cs b/Source/Modules/SemenOverlay/Hediffs/Hediff_Semen.cs index 509e9e1668881a03d7f40501084a57693da5afc6..2880c4616ff63f12d508fca6de70b260796a8b10 100644 --- a/Source/Modules/SemenOverlay/Hediffs/Hediff_Semen.cs +++ b/Source/Modules/SemenOverlay/Hediffs/Hediff_Semen.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text; using Verse; using UnityEngine; +using Multiplayer.API; namespace rjw { @@ -56,6 +57,7 @@ namespace rjw } } + [SyncMethod] public override bool TryMergeWith(Hediff other) { //if a new Semen hediff is added to the same body part, they are combined. if severity reaches more than 1, spillover to other body parts occurs @@ -71,6 +73,8 @@ namespace rjw BodyPartDef spillOverTo = SemenHelper.spillover(this.Part.def);//SemenHelper saves valid other body parts for spillover if (spillOverTo != null) { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); IEnumerable<BodyPartRecord> availableParts = SemenHelper.getAvailableBodyParts(pawn);//gets all non missing, valid body parts IEnumerable<BodyPartRecord> filteredParts = availableParts.Where(x => x.def == spillOverTo);//filters again for valid spill target BodyPartRecord spillPart = filteredParts.RandomElement<BodyPartRecord>();//then pick one diff --git a/Source/Modules/SemenOverlay/SemenHelper.cs b/Source/Modules/SemenOverlay/SemenHelper.cs index ec6f971d1e4d46c5d3f455c69d859a1c8add14a0..0c509741c49790f98a4fdbfac3a2a15eb26bba97 100644 --- a/Source/Modules/SemenOverlay/SemenHelper.cs +++ b/Source/Modules/SemenOverlay/SemenHelper.cs @@ -5,6 +5,7 @@ using RimWorld; using Verse; using Harmony; using UnityEngine; +using Multiplayer.API; namespace rjw { @@ -265,11 +266,14 @@ namespace rjw } //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); @@ -354,11 +358,14 @@ namespace rjw } //determines who is the active male (or equivalent) in the exchange and the amount of semen dispensed and where to + [SyncMethod] public static void calculateAndApplySemen(Pawn pawn, Pawn partner, xxx.rjwSextype sextype) { if (!RJWSettings.cum_on_body) return; Pawn giver, receiver; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); //dispenser of the seed if (Genital_Helper.has_penis(pawn) || xxx.is_mechanoid(pawn) || xxx.is_insect(pawn)) diff --git a/Source/Modules/SemenOverlay/WorkGivers/WorkGiver_CleanSelf.cs b/Source/Modules/SemenOverlay/WorkGivers/WorkGiver_CleanSelf.cs index 0f1d69fad7419969b92bc64f13a4d48133ad86a9..a6a87a7587bb2c512c4fa3d8d077bb3ba7ac28fc 100644 --- a/Source/Modules/SemenOverlay/WorkGivers/WorkGiver_CleanSelf.cs +++ b/Source/Modules/SemenOverlay/WorkGivers/WorkGiver_CleanSelf.cs @@ -30,13 +30,40 @@ namespace rjw //conditions for self-cleaning job to be available public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false) { + if (!pawn.CanReserve(t, 1, -1, null, forced)) + return false; + Hediff hediff = pawn.health.hediffSet.hediffs.Find(x => (x.def == RJW_SemenoOverlayHediffDefOf.Hediff_Bukkake)); - int minAge = 3 * 2500;//3 hours in-game must have passed - if (pawn == t && hediff != null && hediff.ageTicks > minAge && pawn.CanReserve(t, 1, -1, null, forced) && !xxx.DubsBadHygieneIsActive) + if (pawn != t || hediff == null ) + return false; + + if (xxx.DubsBadHygieneIsActive) + return false; + + if (pawn.IsDesignatedHero()) { - return true; + if (!forced) + { + //Log.Message("[RJW]WorkGiver_CleanSelf::not player interaction for hero, exit"); + return false; + } + if (!pawn.IsHeroOwner()) + { + //Log.Message("[RJW]WorkGiver_CleanSelf::player interaction for not owned hero, exit"); + return false; + } } - return false; + else + { + int minAge = 3 * 2500;//3 hours in-game must have passed + if (!(hediff.ageTicks > minAge)) + { + //Log.Message("[RJW]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) diff --git a/Source/Modules/Whoring/JobDrivers/JobDriver_WhoreIsServingVisitors.cs b/Source/Modules/Whoring/JobDrivers/JobDriver_WhoreIsServingVisitors.cs index a44e95fb8f108e986ea74b6b504916af1fb1afbd..d87684a57f5e5851563e815c4f743d7832133277 100644 --- a/Source/Modules/Whoring/JobDrivers/JobDriver_WhoreIsServingVisitors.cs +++ b/Source/Modules/Whoring/JobDrivers/JobDriver_WhoreIsServingVisitors.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using RimWorld; using Verse; using Verse.AI; +using Multiplayer.API; namespace rjw { @@ -43,6 +44,7 @@ namespace rjw return pawn.Reserve(Partner, job, 1, 0, null, errorOnFailed); } + [SyncMethod] protected override IEnumerable<Toil> MakeNewToils() { //Log.Message("[RJW]JobDriver_WhoreIsServingVisitors::MakeNewToils() - making toils"); @@ -82,6 +84,8 @@ namespace rjw { initAction = delegate { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); //Log.Message("JobDriver_WhoreIsServingVisitors::MakeNewToils() - waitInBed, initAction is called"); ticksLeftThisToil = 5000; ticks_left = (int)(2000.0f * Rand.Range(0.30f, 1.30f)); @@ -130,6 +134,8 @@ namespace rjw if (xxx.HasNonPolyPartner(Partner)) { Pawn lover = LovePartnerRelationUtility.ExistingLovePartner(Partner); + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); if ((Actor != lover && !lover.Dead) && (lover.Map == Partner.Map || Rand.Value < 0.25)) { lover.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.CheatedOnMe, Partner); diff --git a/Source/Modules/Whoring/JobGivers/JobGiver_WhoreInvitingVisitors.cs b/Source/Modules/Whoring/JobGivers/JobGiver_WhoreInvitingVisitors.cs index 7e14aaf7a1d8d4decf09a4b9a2142c2b7e48e55a..03e549a813201d6483b89759eac4fbc67d2723c2 100644 --- a/Source/Modules/Whoring/JobGivers/JobGiver_WhoreInvitingVisitors.cs +++ b/Source/Modules/Whoring/JobGivers/JobGiver_WhoreInvitingVisitors.cs @@ -3,6 +3,7 @@ using System.Linq; using RimWorld; using Verse; using Verse.AI; +using Multiplayer.API; namespace rjw { @@ -18,8 +19,11 @@ namespace rjw return val == null ? false : true; } + [SyncMethod] private static bool Roll_to_skip(Pawn client, Pawn whore) { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); float fuckability = xxx.would_fuck(client, whore); // 0.0 to 1. // More likely to skip other whores, because they're supposed to be working. @@ -81,6 +85,8 @@ namespace rjw //Use this check when client is in the same faction as the whore internal bool RelationCheckPass(Pawn client) { + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); if (xxx.isSingleOrPartnerNotHere(client) || xxx.is_lecher(client) || Rand.Value < 0.9f) { if (client != LovePartnerRelationUtility.ExistingLovePartner(whore)) @@ -92,6 +98,7 @@ namespace rjw } } + [SyncMethod] public static Pawn FindAttractivePawn(Pawn whore, out int price) { price = 0; @@ -99,6 +106,9 @@ namespace rjw { return null; } + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); + FindAttractivePawnHelper client = new FindAttractivePawnHelper { whore = whore @@ -163,6 +173,7 @@ namespace rjw // Most things are now checked in the ThinkNode_ConditionalWhore. if (pawn.Drafted) return null; + if (MP.IsInMultiplayer) return null; //fix error someday, maybe //Log.Message("[RJW] JobGiver_WhoreInvitingVisitors::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) called"); if (!SexUtility.ReadyForLovin(pawn)) diff --git a/Source/Modules/Whoring/Whoring_Helper.cs b/Source/Modules/Whoring/Whoring_Helper.cs index a86c4dd7bc725acdc4bdb7f2a332a7b14cc25950..1e294e567b7378a07f4b92bc0333fbffdc8708aa 100644 --- a/Source/Modules/Whoring/Whoring_Helper.cs +++ b/Source/Modules/Whoring/Whoring_Helper.cs @@ -9,6 +9,7 @@ using System.Diagnostics; using System; using UnityEngine; using Verse.AI.Group; +using Multiplayer.API; namespace rjw { @@ -152,10 +153,13 @@ namespace rjw return room_multiplier; } + [SyncMethod] public static int PriceOfWhore(Pawn whore) { float NeedSexFactor = xxx.need_some_sex(whore) > 1 ? 1 - xxx.need_some_sex(whore) / 8 : 1f; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); float price = Rand.Range(WhoreMinPrice(whore), WhoreMaxPrice(whore)); price *= NeedSexFactor; @@ -268,6 +272,7 @@ namespace rjw return xxx.is_healthy(pawn) && !pawn.Downed && !pawn.Suspended; } + [SyncMethod] public static bool IsHookupAppealing(Pawn target, Pawn whore) { if (PawnUtility.WillSoonHaveBasicNeed(target)) @@ -307,11 +312,14 @@ namespace rjw num *= 0.8f + ((float)whore.skills.GetSkill(SkillDefOf.Social).Level / 40); // 0.8 to 1.3 num *= Mathf.InverseLerp(-100f, 0f, target.relations.OpinionOf(whore)); //Log.Message("IsHookupAppealing - score: " + num); + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); return Rand.Range(0.05f, 1f) < num; } // Summary: // Check if the pawn is willing to hook up. Checked for both target and the whore. + [SyncMethod] public static bool WillPawnTryHookup(Pawn target) { if (xxx.RomanceDiversifiedIsActive && target.story.traits.HasTrait(xxx.asexual)) @@ -351,6 +359,8 @@ namespace rjw num2 *= 1.4f; } num2 /= 1.5f; + //Rand.PopState(); + //Rand.PushState(RJW_Multiplayer.PredictableSeed()); return Rand.Range(0f, 1f) < num2; } } diff --git a/Source/Settings/RJWSettingsController.cs b/Source/Settings/RJWSettingsController.cs index aa181bea78290639adbb25d8e5fd3342b6d991ac..e126076c93759a63f0db6379a9ed3069f3ca3c73 100644 --- a/Source/Settings/RJWSettingsController.cs +++ b/Source/Settings/RJWSettingsController.cs @@ -1,5 +1,6 @@ using UnityEngine; using Verse; +using Multiplayer.API; namespace rjw.Settings { @@ -17,6 +18,8 @@ namespace rjw.Settings public override void DoSettingsWindowContents(Rect inRect) { + if (MP.IsInMultiplayer) + return; RJWSettings.DoWindowContents(inRect); } } @@ -35,6 +38,8 @@ namespace rjw.Settings public override void DoSettingsWindowContents(Rect inRect) { + if (MP.IsInMultiplayer) + return; RJWDebugSettings.DoWindowContents(inRect); } } @@ -53,6 +58,8 @@ namespace rjw.Settings public override void DoSettingsWindowContents(Rect inRect) { + if (MP.IsInMultiplayer) + return; RJWPregnancySettings.DoWindowContents(inRect); } } @@ -71,6 +78,8 @@ namespace rjw.Settings public override void DoSettingsWindowContents(Rect inRect) { + if (MP.IsInMultiplayer) + return; RJWPreferenceSettings.DoWindowContents(inRect); } } diff --git a/Source/Settings/Settings.cs b/Source/Settings/Settings.cs index 762fc776362ba331e51e47281e809f89b680df0a..adbd39535d6b8cb230abb68611279e6a08fd59f5 100644 --- a/Source/Settings/Settings.cs +++ b/Source/Settings/Settings.cs @@ -1,5 +1,4 @@ -using System; -using HugsLib.Settings; +using HugsLib.Settings; using UnityEngine; using Verse; diff --git a/Source/WorkGivers/WorkGiver_Sexchecks.cs b/Source/WorkGivers/WorkGiver_Sexchecks.cs index 99264a5be5c03aaea0331e4759b86582190f1ece..a7a2e73707485ef3a9b5383b787282ee9dcb0c05 100644 --- a/Source/WorkGivers/WorkGiver_Sexchecks.cs +++ b/Source/WorkGivers/WorkGiver_Sexchecks.cs @@ -81,6 +81,7 @@ namespace rjw } //Log.Message("7"); if (!pawn.IsDesignatedHero()) + { if (!RJWSettings.WildMode) { if (pawn.IsDesignatedComfort() || pawn.IsDesignatedBreeding()) @@ -100,6 +101,16 @@ namespace rjw } } + } + else + { + if (!pawn.IsHeroOwner()) + { + //Log.Message("[RJW]WorkGiver_Sexchecks::player interaction for not owned hero, exit"); + return false; + } + } + if (!MoreChecks(pawn, t, forced)) return false; diff --git a/todo.txt b/todo.txt index a356edf6b11ab29a446bb1a2dc685d94bccfe47b..2ea6de43ea8c8ab82668cb84659331068e80be7d 100644 --- a/todo.txt +++ b/todo.txt @@ -1,4 +1,5 @@ CORE: + fix naked pawn drawing when job driver is interrupted for any reason and pawn doesnt get redressed/changes back to dressed art split processsex(again) in 2 functions: 1st - at beginning of jobgiver to determine sex type @@ -47,9 +48,7 @@ BDSM: -vibrators? Multiplayer: --synchronising for designators, so it doesnt disconnect, pawn interraction log, who knows what else --bind hero to player id --fixing all unknown bugs?(lol) +-figure out predictable seeds instead of syncmethod's maybe: add support for other pregnancy mods