diff --git a/1.4/Assemblies/RimJobWorldWhoring.dll b/1.4/Assemblies/RimJobWorldWhoring.dll index af89fa2..3028e50 100644 Binary files a/1.4/Assemblies/RimJobWorldWhoring.dll and b/1.4/Assemblies/RimJobWorldWhoring.dll differ diff --git a/1.4/Defs/JobDefs/Jobs_Whoring.xml b/1.4/Defs/JobDefs/Jobs_Whoring.xml index d3e6bed..60eedda 100644 --- a/1.4/Defs/JobDefs/Jobs_Whoring.xml +++ b/1.4/Defs/JobDefs/Jobs_Whoring.xml @@ -4,14 +4,14 @@ WhoreIsServingVisitors rjwwhoring.JobDriver_WhoreIsServingVisitors - serving visitors + servicing TargetA. false WhoreInvitingVisitors rjwwhoring.JobDriver_WhoreInvitingVisitors - attempting hookup + soliciting TargetA. false \ No newline at end of file diff --git a/1.4/Defs/WhoringTab/PawnColumnDefs/PawnColumns.xml b/1.4/Defs/WhoringTab/PawnColumnDefs/PawnColumns.xml index 63985a5..d6fe0fb 100644 --- a/1.4/Defs/WhoringTab/PawnColumnDefs/PawnColumns.xml +++ b/1.4/Defs/WhoringTab/PawnColumnDefs/PawnColumns.xml @@ -49,4 +49,11 @@ rjwwhoring.MainTab.PawnColumnWorker_Mood 100 + + RJW_WhoringPolicy + Trade sex for benefits + + rjwwhoring.MainTab.PawnColumnWorker_WhoringPolicy + 100 + diff --git a/1.4/Defs/WhoringTab/PawnTableDefs.xml b/1.4/Defs/WhoringTab/PawnTableDefs.xml index f321b97..af172f9 100644 --- a/1.4/Defs/WhoringTab/PawnTableDefs.xml +++ b/1.4/Defs/WhoringTab/PawnTableDefs.xml @@ -21,6 +21,7 @@
  • RJW_EarnedMoneyByWhore
  • RJW_AverageMoneyByWhore
  • RJW_PriceRangeOfWhore
  • +
  • RJW_WhoringPolicy
  • RemainingSpace
  • diff --git a/1.4/Languages/English/Keyed/Whoring.xml b/1.4/Languages/English/Keyed/Whoring.xml index 401855b..e86e4f0 100644 --- a/1.4/Languages/English/Keyed/Whoring.xml +++ b/1.4/Languages/English/Keyed/Whoring.xml @@ -24,7 +24,7 @@ Assign to whorin' diff --git a/1.4/Source/Mod/Data/DataStore.cs b/1.4/Source/Mod/Data/DataStore.cs index 1f3566b..8241197 100644 --- a/1.4/Source/Mod/Data/DataStore.cs +++ b/1.4/Source/Mod/Data/DataStore.cs @@ -11,6 +11,7 @@ namespace rjwwhoring public class DataStore : WorldComponent { public Dictionary bedData = new Dictionary(); + public Dictionary whoringData = new Dictionary(); public DataStore(World world) : base(world) { @@ -21,13 +22,16 @@ namespace rjwwhoring if (Scribe.mode == LoadSaveMode.Saving) { bedData.RemoveAll(item => item.Value == null || !item.Value.IsValid); + whoringData.RemoveAll(item => item.Value == null || !item.Value.IsValid); } base.ExposeData(); Scribe_Collections.Look(ref bedData, "BedData", LookMode.Value, LookMode.Deep); + Scribe_Collections.Look(ref whoringData, "WhoringData", LookMode.Value, LookMode.Deep); if (Scribe.mode == LoadSaveMode.LoadingVars) { if (bedData == null) bedData = new Dictionary(); + if (whoringData == null) whoringData = new Dictionary(); } } @@ -46,5 +50,21 @@ namespace rjwwhoring } return res; } + + public WhoringData GetWhoringData(Pawn pawn) + { + WhoringData res; + var filled = whoringData.TryGetValue(pawn.thingIDNumber, out res); + if ((res == null) || (!res.IsValid)) + { + if (filled) + { + whoringData.Remove(pawn.thingIDNumber); + } + res = new WhoringData(pawn); + whoringData.Add(pawn.thingIDNumber, res); + } + return res; + } } } \ No newline at end of file diff --git a/1.4/Source/Mod/Data/PawnExtensions.cs b/1.4/Source/Mod/Data/PawnExtensions.cs new file mode 100644 index 0000000..479ca2e --- /dev/null +++ b/1.4/Source/Mod/Data/PawnExtensions.cs @@ -0,0 +1,17 @@ +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Verse; + +namespace rjwwhoring +{ + public static class PawnExtensions + { + public static WhoringData WhoringData(this Pawn pawn) + { + return WhoringBase.DataStore.GetWhoringData(pawn); + } + } +} diff --git a/1.4/Source/Mod/Data/WhoringData.cs b/1.4/Source/Mod/Data/WhoringData.cs new file mode 100644 index 0000000..b113bb6 --- /dev/null +++ b/1.4/Source/Mod/Data/WhoringData.cs @@ -0,0 +1,36 @@ +using System; +using Verse; +using System.Linq; +using RimWorld; +using static rjw.xxx; +using System.Collections.ObjectModel; + +namespace rjwwhoring +{ + public class WhoringData : IExposable + { + public Pawn pawn; + public bool allowedForWhoringOwner = true; + public bool allowedForWhoringAll = false; + public int reservedForPawnID = 0; + + public WhoringType WhoringPolicy = WhoringType.Silver; + public enum WhoringType { Silver, Goodwill }; + + public WhoringData() { } + public WhoringData(Pawn pawn) + { + this.pawn = pawn; + } + + public void ExposeData() + { + Scribe_References.Look(ref pawn, "pawn"); + Scribe_Values.Look(ref WhoringPolicy, "WhoringPolicy", WhoringType.Silver, true); + Scribe_Values.Look(ref allowedForWhoringOwner, "allowedForWhoringOwner", true, true); + Scribe_Values.Look(ref allowedForWhoringAll, "allowedForWhoringAll", false, true); + } + + public bool IsValid { get { return pawn != null; } } + } +} diff --git a/1.4/Source/Mod/JobDrivers/JobDriver_WhoreIsServingVisitors.cs b/1.4/Source/Mod/JobDrivers/JobDriver_WhoreIsServingVisitors.cs index ecd45d2..5b5683d 100644 --- a/1.4/Source/Mod/JobDrivers/JobDriver_WhoreIsServingVisitors.cs +++ b/1.4/Source/Mod/JobDrivers/JobDriver_WhoreIsServingVisitors.cs @@ -143,26 +143,34 @@ namespace rjwwhoring if (!(Partner.IsColonist && (pawn.IsPrisonerOfColony || pawn.IsColonist))) { - int netPrice = (int) (basePrice * bedMult); - if (netPrice == 0) - netPrice += 1; - - int bedTip = netPrice - basePrice; - int defect = WhoringHelper.PayPriceToWhore(Partner, netPrice, pawn); - - if (WhoringBase.DebugWhoring) + if (pawn.WhoringData().WhoringPolicy == WhoringData.WhoringType.Silver) { - ModLog.Message($"{GetType()}:afterSex toil - {Partner} tried to pay {basePrice}(whore price) + {bedTip}(room modifier) silver to {pawn}"); + int netPrice = (int) (basePrice * bedMult); + if (netPrice == 0) + netPrice += 1; + + int bedTip = netPrice - basePrice; + int defect = WhoringHelper.PayPriceToWhore(Partner, netPrice, pawn); + + if (WhoringBase.DebugWhoring) + { + ModLog.Message($"{GetType()}:afterSex toil - {Partner} tried to pay {basePrice}(whore price) + {bedTip}(room modifier) silver to {pawn}"); - if (defect <= 0) - ModLog.Message(" Paid full price"); - else if (defect <= bedTip) - ModLog.Message(" Could not pay full tip"); - else - ModLog.Message(" Failed to pay base price"); + if (defect <= 0) + ModLog.Message(" Paid full price"); + else if (defect <= bedTip) + ModLog.Message(" Could not pay full tip"); + else + ModLog.Message(" Failed to pay base price"); + } + WhoringHelper.UpdateRecords(pawn, netPrice - defect); + } + else + { + int bedTip = 1; + ModLog.Message($"{GetType()}:afterSex toil - {Partner} tried to pay {bedTip} goodwill to {pawn}"); + WhoringHelper.PayRespectToWhore(Partner, bedTip, pawn); } - - WhoringHelper.UpdateRecords(pawn, netPrice - defect); } if (SexUtility.ConsiderCleaning(pawn)) diff --git a/1.4/Source/Mod/JobGivers/JobGiver_WhoreInvitingVisitors.cs b/1.4/Source/Mod/JobGivers/JobGiver_WhoreInvitingVisitors.cs index c438e29..f6c9a3b 100644 --- a/1.4/Source/Mod/JobGivers/JobGiver_WhoreInvitingVisitors.cs +++ b/1.4/Source/Mod/JobGivers/JobGiver_WhoreInvitingVisitors.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using HugsLib.Utils; using RimWorld; using rjw; using Verse; @@ -18,6 +19,23 @@ namespace rjwwhoring return val == null ? false : true; } + public static Thought_Memory GetMemory(Pawn pawn, Pawn target, ThoughtDef thought) + { + Thought_Memory val = pawn.needs.mood.thoughts.memories.Memories.Find( + (Thought_Memory x) => + { + if (x.def != thought) + return false; + + if (x.otherPawn == null || x.otherPawn != target) + return false; + + return true; + } + ); + return val; + } + //[SyncMethod] private static bool Roll_to_skip(Pawn client, Pawn whore) { @@ -132,7 +150,8 @@ namespace rjwwhoring && !x.IsPrisoner && !xxx.is_slave(x) && !x.IsColonist - && x.Position.DistanceTo(pos) < 100 + //&& (!x.IsColonist || x.guest?.GuestStatus == GuestStatus.Guest) + && x.Position.DistanceTo(pos) < 100 && xxx.is_healthy_enough(x)); @@ -146,6 +165,7 @@ namespace rjwwhoring if (!potentialClients.Any()) return null; if (WhoringBase.DebugWhoring) ModLog.Message($" FindAttractivePawn number of all potential clients {potentialClients.Count()}"); + //if (WhoringBase.DebugWhoring) ModLog.Message($" FindAttractivePawn number of all potential clients {potentialClients.ListElements()}"); List valid_targets = new List(); @@ -165,11 +185,12 @@ namespace rjwwhoring } if (WhoringBase.DebugWhoring) ModLog.Message($" number of reachable clients {valid_targets.Count()}"); + //if (WhoringBase.DebugWhoring) ModLog.Message($" number of reachable clients {valid_targets.ListElements()}"); //IEnumerable guestsSpawned = valid_targets.Where(x => x.Faction != whore.Faction // && WhoringHelper.CanAfford(x, whore, priceOfWhore)); - + //if (RJWSettings.DebugWhoring) ModLog.Message($" number of clients can afford {guestsSpawned.Count()}"); //guestsSpawned = valid_targets.Where(x => x.Faction != whore.Faction @@ -181,10 +202,29 @@ namespace rjwwhoring //if (RJWSettings.DebugWhoring) ModLog.Message($" number of clients can memory OK {guestsSpawned.Count()}"); - IEnumerable guestsSpawned = valid_targets.Where(x => x.Faction != whore.Faction - && !MemoryChecker(x, ThoughtDef.Named("RJWFailedSolicitation")) - && WhoringHelper.CanAfford(x, whore, priceOfWhore) - && x != LovePartnerRelationUtility.ExistingLovePartner(whore)); + List guestsSpawned = new List(); + + foreach(Pawn x in valid_targets) + { + bool canAfford = WhoringHelper.CanAfford(x, whore, priceOfWhore); + Thought_Memory refusedMmeory = GetMemory(x, whore, ThoughtDef.Named("RJWFailedSolicitation")); + bool refused = refusedMmeory != null; + DirectPawnRelation relationship = LovePartnerRelationUtility.ExistingLoveRealtionshipBetween(whore, x); + bool relation = relationship != null; + bool differentFaction = x.Faction != whore.Faction; + + bool finalResult = canAfford && !refused && !relation && differentFaction; + + if (WhoringBase.DebugWhoring) + { + ModLog.Message($"Pawn {x.Name} is an {(finalResult ? "acceptable" : "unacceptable")} client for {whore.Name}. Explanation: canAfford {canAfford.ToString()} refused: {refused.ToString()} relation: {relation.ToString()} differentFaction: {differentFaction.ToString()}"); + } + + if (canAfford && !refused && !relation && differentFaction) + guestsSpawned.Add(x); + + } + if (guestsSpawned.Any()) { diff --git a/1.4/Source/Mod/Whoring.csproj b/1.4/Source/Mod/Whoring.csproj index b213640..f115507 100644 --- a/1.4/Source/Mod/Whoring.csproj +++ b/1.4/Source/Mod/Whoring.csproj @@ -78,6 +78,7 @@ + @@ -86,6 +87,8 @@ + + @@ -95,6 +98,7 @@ + diff --git a/1.4/Source/Mod/WhoringTab/PawnColumnWorker_PriceRangeOfWhore.cs b/1.4/Source/Mod/WhoringTab/PawnColumnWorker_PriceRangeOfWhore.cs index 220713b..892a249 100644 --- a/1.4/Source/Mod/WhoringTab/PawnColumnWorker_PriceRangeOfWhore.cs +++ b/1.4/Source/Mod/WhoringTab/PawnColumnWorker_PriceRangeOfWhore.cs @@ -16,8 +16,16 @@ namespace rjwwhoring.MainTab protected override string GetTextFor(Pawn pawn) { - min = WhoringHelper.WhoreMinPrice(pawn); - max = WhoringHelper.WhoreMaxPrice(pawn); + if (pawn.WhoringData().WhoringPolicy == WhoringData.WhoringType.Silver) + { + min = WhoringHelper.WhoreMinPrice(pawn); + max = WhoringHelper.WhoreMaxPrice(pawn); + } + else + { + min = 1; + max = 1; + } return string.Format("{0} - {1}", min, max); } @@ -28,23 +36,30 @@ namespace rjwwhoring.MainTab protected override string GetTip(Pawn pawn) { - string minPriceTip = string.Format( - " Base: {0}\n Traits: {1}", - WhoringHelper.baseMinPrice, - (WhoringHelper.WhoreTraitAdjustmentMin(pawn) -1f).ToStringPercent() - ); - string maxPriceTip = string.Format( - " Base: {0}\n Traits: {1}", - WhoringHelper.baseMaxPrice, - (WhoringHelper.WhoreTraitAdjustmentMax(pawn) -1f).ToStringPercent() - ); - string bothTip = string.Format( - " Gender: {0}\n Age: {1}\n Injuries: {2}", - (WhoringHelper.WhoreGenderAdjustment(pawn) - 1f).ToStringPercent(), - (WhoringHelper.WhoreAgeAdjustment(pawn) - 1f).ToStringPercent(), - (WhoringHelper.WhoreInjuryAdjustment(pawn) - 1f).ToStringPercent() - ); - return string.Format("Min:\n{0}\nMax:\n{1}\nBoth:\n{2}", minPriceTip, maxPriceTip, bothTip); + if (pawn.WhoringData().WhoringPolicy == WhoringData.WhoringType.Silver) + { + string minPriceTip = string.Format( + " Base: {0}\n Traits: {1}", + WhoringHelper.baseMinPrice, + (WhoringHelper.WhoreTraitAdjustmentMin(pawn) - 1f).ToStringPercent() + ); + string maxPriceTip = string.Format( + " Base: {0}\n Traits: {1}", + WhoringHelper.baseMaxPrice, + (WhoringHelper.WhoreTraitAdjustmentMax(pawn) - 1f).ToStringPercent() + ); + string bothTip = string.Format( + " Gender: {0}\n Age: {1}\n Injuries: {2}", + (WhoringHelper.WhoreGenderAdjustment(pawn) - 1f).ToStringPercent(), + (WhoringHelper.WhoreAgeAdjustment(pawn) - 1f).ToStringPercent(), + (WhoringHelper.WhoreInjuryAdjustment(pawn) - 1f).ToStringPercent() + ); + return string.Format("Min:\n{0}\nMax:\n{1}\nBoth:\n{2}", minPriceTip, maxPriceTip, bothTip); + } + else + { + return string.Format("Raise Goodwill by 1"); + } } private int GetValueToCompare(Pawn pawn) diff --git a/1.4/Source/Mod/WhoringTab/PawnColumnWorker_WhoringPolicy.cs b/1.4/Source/Mod/WhoringTab/PawnColumnWorker_WhoringPolicy.cs new file mode 100644 index 0000000..392bea7 --- /dev/null +++ b/1.4/Source/Mod/WhoringTab/PawnColumnWorker_WhoringPolicy.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; +using RimWorld; +using RimWorld.Planet; +using UnityEngine; +using Verse; +using Verse.Sound; + +namespace rjwwhoring.MainTab +{ + [StaticConstructorOnStartup] + public class PawnColumnWorker_WhoringPolicy : PawnColumnWorker + { + public override void DoCell(Rect rect, Pawn pawn, PawnTable table) + { + if (pawn.drugs != null) + { + WhoringPolicyUIUtility.DoAssignWhoringPolicyButtons(rect, pawn); + } + } + } +} diff --git a/1.4/Source/Mod/WhoringTab/WhoringPolicyUIUtility.cs b/1.4/Source/Mod/WhoringTab/WhoringPolicyUIUtility.cs new file mode 100644 index 0000000..a5af8cc --- /dev/null +++ b/1.4/Source/Mod/WhoringTab/WhoringPolicyUIUtility.cs @@ -0,0 +1,45 @@ +using RimWorld; +using System; +using System.Collections.Generic; +using UnityEngine; +using Verse; + +namespace rjwwhoring +{ + public static class WhoringPolicyUIUtility + { + //public const string AssigningDrugsTutorHighlightTag = "ButtonAssignDrugs"; + + public static void DoAssignWhoringPolicyButtons(Rect rect, Pawn pawn) + { + int num = Mathf.FloorToInt(rect.width); + float x = rect.x; + Rect rect2 = new Rect(x, rect.y + 2f, num, rect.height - 4f); + string text = pawn.WhoringData().WhoringPolicy.ToStringSafe(); + + Widgets.Dropdown(rect2, pawn, (Pawn p) => p.WhoringData().WhoringPolicy, Button_GenerateMenu, text.Truncate(rect2.width), paintable: true); + //Widgets.Dropdown(rect2, pawn, (Pawn p) => p.drugs.CurrentPolicy, Button_GenerateMenu, text.Truncate(((Rect)(ref rect2)).get_width()), null, pawn.drugs.CurrentPolicy.label, null, delegate + //{ + // PlayerKnowledgeDatabase.KnowledgeDemonstrated(ConceptDefOf.DrugPolicies, KnowledgeAmount.Total); + //}, paintable: true); + x += num; + x += 4f; + //UIHighlighter.HighlightOpportunity(rect2, "ButtonAssignDrugs"); + } + + private static IEnumerable> Button_GenerateMenu(Pawn pawn) + { + foreach (WhoringData.WhoringType option in Enum.GetValues(typeof(WhoringData.WhoringType))) + { + yield return new Widgets.DropdownMenuElement + { + option = new FloatMenuOption(option.ToString(), delegate + { + pawn.WhoringData().WhoringPolicy = option; + }), + payload = option + }; + } + } + } +} diff --git a/1.4/Source/Mod/Whoring_Helper.cs b/1.4/Source/Mod/Whoring_Helper.cs index d313a98..72739eb 100644 --- a/1.4/Source/Mod/Whoring_Helper.cs +++ b/1.4/Source/Mod/Whoring_Helper.cs @@ -188,6 +188,8 @@ namespace rjwwhoring public static bool CanAfford(Pawn targetPawn, Pawn whore, int priceOfWhore = -1) { //if (targetPawn.Faction == whore.Faction) return true; + if (whore.WhoringData().WhoringPolicy == WhoringData.WhoringType.Goodwill) return true; + if (WhoringBase.MoneyPrinting) return true; //if (RJWSettings.DebugWhoring) ModLog.Message($"CanAfford for client {xxx.get_pawnname(targetPawn)}"); @@ -310,6 +312,19 @@ namespace rjwwhoring return AmountLeft; } + public static int PayRespectToWhore(Pawn targetPawn, int priceOfWhore, Pawn whore) + { + if ((targetPawn.Faction != whore.Faction && targetPawn.GuestStatus != GuestStatus.Guest)) + { + if (WhoringBase.DebugWhoring) ModLog.Message($" No need to pay respect"); + return 0; + } + targetPawn.Faction.TryAffectGoodwillWith(Faction.OfPlayer, priceOfWhore); + if (WhoringBase.DebugWhoring) ModLog.Message($" price: {priceOfWhore}, paid: {priceOfWhore}"); + + return priceOfWhore; + } + //[SyncMethod] public static bool IsHookupAppealing(Pawn target, Pawn whore) { diff --git a/1.4/Source/Mod/harmony_Building_BedPatches.cs b/1.4/Source/Mod/harmony_Building_BedPatches.cs index 852b633..78a1794 100644 --- a/1.4/Source/Mod/harmony_Building_BedPatches.cs +++ b/1.4/Source/Mod/harmony_Building_BedPatches.cs @@ -10,7 +10,7 @@ using rjw; /// /// patches Building_Bed to add stuff for WhoreBeds /// -/// Also contains smaller patches for RoomRoleWorker_Barracks (don't count whore beds) (disabled) and Toils_LayDown.ApplyBedThoughts (slept in brothel thought) +/// Also contains smaller patches for RoomRoleWorker_Barracks (don't count whore beds) (disabled), Toils_LayDown.ApplyBedThoughts (slept in brothel thought) and RestUtility (don't automatically claim brothel beds) /// namespace rjwwhoring @@ -288,5 +288,29 @@ namespace rjwwhoring } } } - } + + /// + ///Prevents automatic claiming of brothel beds (beds that allow anyone to use for whoring) + ///Note, that intent is not verified here, and this works because bed usage for actual whoring does not rely on IsValidBedFor call. + ///Should above change in future, this patch needs to be removed or adjusted + ///If the bed is already claimed (for example - assigned manually to pawn), it will still be used. + ///Modifies __result to false, if bed is set to allow anyone for whroing AND is not already claimed. + /// + [HarmonyPatch(typeof(RestUtility), nameof(RestUtility.IsValidBedFor))] + public class RestUtility_IsValidBedFor_Patch + { + [HarmonyPostfix] + public static void Postfix(Pawn sleeper, Thing bedThing, ref bool __result) + { + if (!__result) return; + Building_Bed building_Bed = bedThing as Building_Bed; + bool isOwner = sleeper.ownership != null && sleeper.ownership.OwnedBed == bedThing; + if (building_Bed.IsAllowedForWhoringAll() && !isOwner ) __result = false; + + } + + + } + + } } \ No newline at end of file diff --git a/About/Manifest.xml b/About/Manifest.xml index 98de210..3070f97 100644 --- a/About/Manifest.xml +++ b/About/Manifest.xml @@ -1,7 +1,7 @@ RimJobWorld Whoring - 1.0.2 + 1.0.6
  • RimJobWorld