1.5 support
							
								
								
									
										
											BIN
										
									
								
								1.5/Assemblies/RimJobWorldWhoring.dll
									
										
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										17
									
								
								1.5/Defs/JobDefs/Jobs_Whoring.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,17 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="utf-8" ?>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<Defs>
 | 
				
			||||||
 | 
						<JobDef>
 | 
				
			||||||
 | 
							<defName>WhoreIsServingVisitors</defName>
 | 
				
			||||||
 | 
							<driverClass>rjwwhoring.JobDriver_WhoreIsServingVisitors</driverClass>
 | 
				
			||||||
 | 
							<reportString>servicing TargetA.</reportString>
 | 
				
			||||||
 | 
							<casualInterruptible>false</casualInterruptible>
 | 
				
			||||||
 | 
						</JobDef>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<JobDef>
 | 
				
			||||||
 | 
							<defName>WhoreInvitingVisitors</defName>
 | 
				
			||||||
 | 
							<driverClass>rjwwhoring.JobDriver_WhoreInvitingVisitors</driverClass>
 | 
				
			||||||
 | 
							<reportString>soliciting TargetA.</reportString>
 | 
				
			||||||
 | 
							<casualInterruptible>false</casualInterruptible>
 | 
				
			||||||
 | 
						</JobDef>
 | 
				
			||||||
 | 
					</Defs>
 | 
				
			||||||
							
								
								
									
										18
									
								
								1.5/Defs/RecordDefs/Records.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,18 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="utf-8" ?>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<Defs>
 | 
				
			||||||
 | 
						<!--Counts whoring stuff -->
 | 
				
			||||||
 | 
						<RecordDef>
 | 
				
			||||||
 | 
							<defName>CountOfWhore</defName>
 | 
				
			||||||
 | 
							<label>times whored</label>
 | 
				
			||||||
 | 
							<description>The number of times I whored myself.</description>
 | 
				
			||||||
 | 
							<type>Int</type>
 | 
				
			||||||
 | 
						</RecordDef>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<RecordDef>
 | 
				
			||||||
 | 
							<defName>EarnedMoneyByWhore</defName>
 | 
				
			||||||
 | 
							<label>silvers earned as a whore</label>
 | 
				
			||||||
 | 
							<description>The amount of silvers I have earned as a whore.</description>
 | 
				
			||||||
 | 
							<type>Int</type>
 | 
				
			||||||
 | 
						</RecordDef>
 | 
				
			||||||
 | 
					</Defs>
 | 
				
			||||||
							
								
								
									
										17
									
								
								1.5/Defs/Rooms/RoomRoles.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,17 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="utf-8" ?>
 | 
				
			||||||
 | 
					<Defs>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<RoomRoleDef>
 | 
				
			||||||
 | 
							<defName>Brothel</defName>
 | 
				
			||||||
 | 
							<label>brothel</label>
 | 
				
			||||||
 | 
							<workerClass>rjwwhoring.RoomRoleWorker_Brothel</workerClass>
 | 
				
			||||||
 | 
							<relatedStats>
 | 
				
			||||||
 | 
								<li>Beauty</li>
 | 
				
			||||||
 | 
								<li>Cleanliness</li>
 | 
				
			||||||
 | 
								<li>Wealth</li>
 | 
				
			||||||
 | 
								<li>Space</li>
 | 
				
			||||||
 | 
								<li>Impressiveness</li>
 | 
				
			||||||
 | 
							</relatedStats>
 | 
				
			||||||
 | 
						</RoomRoleDef>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</Defs>
 | 
				
			||||||
							
								
								
									
										22
									
								
								1.5/Defs/ThinkTreeDefs/ThinkTrees_Prisoner.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="utf-8" ?>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<Defs>
 | 
				
			||||||
 | 
						<ThinkTreeDef>
 | 
				
			||||||
 | 
							<defName>PrisonerWhoreSexualEmergencyTree</defName>
 | 
				
			||||||
 | 
							<insertTag>Humanlike_PostDuty</insertTag>
 | 
				
			||||||
 | 
							<insertPriority>100</insertPriority>
 | 
				
			||||||
 | 
							<thinkRoot Class="ThinkNode_Priority">
 | 
				
			||||||
 | 
								<subNodes>
 | 
				
			||||||
 | 
									<li Class="rjw.ThinkNode_ConditionalSexChecks">
 | 
				
			||||||
 | 
										<subNodes>
 | 
				
			||||||
 | 
											<li Class="rjwwhoring.ThinkNode_ConditionalWhore">
 | 
				
			||||||
 | 
												<subNodes>
 | 
				
			||||||
 | 
													<li Class="rjwwhoring.JobGiver_WhoreInvitingVisitors" />
 | 
				
			||||||
 | 
												</subNodes>
 | 
				
			||||||
 | 
											</li>
 | 
				
			||||||
 | 
										</subNodes>
 | 
				
			||||||
 | 
									</li>
 | 
				
			||||||
 | 
								</subNodes>
 | 
				
			||||||
 | 
							</thinkRoot>
 | 
				
			||||||
 | 
						</ThinkTreeDef>
 | 
				
			||||||
 | 
					</Defs>
 | 
				
			||||||
							
								
								
									
										43
									
								
								1.5/Defs/ThinkTreeDefs/ThinkTrees_Whore.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,43 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="utf-8" ?>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<Defs>
 | 
				
			||||||
 | 
						<!-- Whores will find visitors before looking for work to do -->
 | 
				
			||||||
 | 
						<ThinkTreeDef>
 | 
				
			||||||
 | 
							<defName>WhoreSexualEmergencyTree</defName>
 | 
				
			||||||
 | 
							<insertTag>Humanlike_PreMain</insertTag>
 | 
				
			||||||
 | 
							<insertPriority>15</insertPriority>
 | 
				
			||||||
 | 
							<thinkRoot Class="ThinkNode_Priority">
 | 
				
			||||||
 | 
								<subNodes>
 | 
				
			||||||
 | 
									<li Class="rjw.ThinkNode_ConditionalSexChecks">
 | 
				
			||||||
 | 
										<subNodes>
 | 
				
			||||||
 | 
											<li Class="rjwwhoring.ThinkNode_ConditionalWhore">
 | 
				
			||||||
 | 
												<subNodes>
 | 
				
			||||||
 | 
													<li Class="rjwwhoring.JobGiver_WhoreInvitingVisitors" />
 | 
				
			||||||
 | 
												</subNodes>
 | 
				
			||||||
 | 
											</li>
 | 
				
			||||||
 | 
										</subNodes>
 | 
				
			||||||
 | 
									</li>
 | 
				
			||||||
 | 
								</subNodes>
 | 
				
			||||||
 | 
							</thinkRoot>
 | 
				
			||||||
 | 
						</ThinkTreeDef>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<!-- Whores will always look for sex if they have nothing else to do -->
 | 
				
			||||||
 | 
						<ThinkTreeDef>
 | 
				
			||||||
 | 
							<defName>WhoreJobTree</defName>
 | 
				
			||||||
 | 
							<insertTag>Humanlike_PostMain</insertTag>
 | 
				
			||||||
 | 
							<insertPriority>15</insertPriority>
 | 
				
			||||||
 | 
							<thinkRoot Class="ThinkNode_Priority">
 | 
				
			||||||
 | 
								<subNodes>
 | 
				
			||||||
 | 
									<li Class="rjw.ThinkNode_ConditionalSexChecks">
 | 
				
			||||||
 | 
										<subNodes>
 | 
				
			||||||
 | 
											<li Class="rjwwhoring.ThinkNode_ConditionalWhore">
 | 
				
			||||||
 | 
												<subNodes>
 | 
				
			||||||
 | 
													<li Class="rjwwhoring.JobGiver_WhoreInvitingVisitors" />
 | 
				
			||||||
 | 
												</subNodes>
 | 
				
			||||||
 | 
											</li>
 | 
				
			||||||
 | 
										</subNodes>
 | 
				
			||||||
 | 
									</li>
 | 
				
			||||||
 | 
								</subNodes>
 | 
				
			||||||
 | 
							</thinkRoot>
 | 
				
			||||||
 | 
						</ThinkTreeDef>
 | 
				
			||||||
 | 
					</Defs>
 | 
				
			||||||
							
								
								
									
										125
									
								
								1.5/Defs/ThoughtDefs/Thoughts_Whore.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,125 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="utf-8" ?>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<Defs>
 | 
				
			||||||
 | 
						<rjwwhoring.ThoughtDef_Whore>
 | 
				
			||||||
 | 
							<defName>Whorish_Thoughts</defName>
 | 
				
			||||||
 | 
							<thoughtClass>rjwwhoring.ThoughtWorker_Whore</thoughtClass>
 | 
				
			||||||
 | 
							<durationDays>2.0</durationDays>
 | 
				
			||||||
 | 
							<stackLimit>10</stackLimit>
 | 
				
			||||||
 | 
							<stackedEffectMultiplier>0.4</stackedEffectMultiplier>
 | 
				
			||||||
 | 
							<!--Numbers of whoring times needed to pass to next stage, one less than the stages count-->
 | 
				
			||||||
 | 
							<!--I couldn't find a way to move them to thoughtStageDefs, fo a better code structure-->
 | 
				
			||||||
 | 
							<stageCounts>
 | 
				
			||||||
 | 
								<li>30</li>
 | 
				
			||||||
 | 
								<li>50</li>
 | 
				
			||||||
 | 
							</stageCounts>
 | 
				
			||||||
 | 
							<storyOffset>30</storyOffset><!--Special stories count as this much experience to grow accustomed-->
 | 
				
			||||||
 | 
							<stages>
 | 
				
			||||||
 | 
								<li>
 | 
				
			||||||
 | 
									<label>Resentful whore</label>
 | 
				
			||||||
 | 
									<description>We just need money! I'm not a ...</description>
 | 
				
			||||||
 | 
									<baseMoodEffect>-5</baseMoodEffect>
 | 
				
			||||||
 | 
								</li>
 | 
				
			||||||
 | 
								<li>
 | 
				
			||||||
 | 
									<label>Whore</label>
 | 
				
			||||||
 | 
									<description>Well, at least it pays well...</description>
 | 
				
			||||||
 | 
									<baseMoodEffect>-1</baseMoodEffect>
 | 
				
			||||||
 | 
								</li>
 | 
				
			||||||
 | 
								<li>
 | 
				
			||||||
 | 
									<label>WHORE</label>
 | 
				
			||||||
 | 
									<description>This job isn't so bad afterall!</description>
 | 
				
			||||||
 | 
									<baseMoodEffect>2</baseMoodEffect>
 | 
				
			||||||
 | 
								</li>
 | 
				
			||||||
 | 
							</stages>
 | 
				
			||||||
 | 
						</rjwwhoring.ThoughtDef_Whore>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<rjwwhoring.ThoughtDef_Whore>
 | 
				
			||||||
 | 
							<defName>Whorish_Thoughts_Captive</defName>
 | 
				
			||||||
 | 
							<thoughtClass>rjwwhoring.ThoughtWorker_Whore</thoughtClass>
 | 
				
			||||||
 | 
							<durationDays>4.0</durationDays>
 | 
				
			||||||
 | 
							<stackLimit>10</stackLimit>
 | 
				
			||||||
 | 
							<stackedEffectMultiplier>0.4</stackedEffectMultiplier>
 | 
				
			||||||
 | 
							<!--Numbers of whoring times needed to pass to next stage, one less than the stages count-->
 | 
				
			||||||
 | 
							<!--I couldn't find a way to move them to thoughtStageDefs, for a better code structure-->
 | 
				
			||||||
 | 
							<stageCounts>
 | 
				
			||||||
 | 
								<li>30</li>
 | 
				
			||||||
 | 
								<li>40</li>
 | 
				
			||||||
 | 
								<li>80</li>
 | 
				
			||||||
 | 
							</stageCounts>
 | 
				
			||||||
 | 
							<storyOffset>10</storyOffset>
 | 
				
			||||||
 | 
							<!--Special stories count as this much experience to grow accustomed-->
 | 
				
			||||||
 | 
							<stages>
 | 
				
			||||||
 | 
								<li>
 | 
				
			||||||
 | 
									<label>Forced whore</label>
 | 
				
			||||||
 | 
									<description>They forced me to serve as a sex toy!</description>
 | 
				
			||||||
 | 
									<baseMoodEffect>-20</baseMoodEffect>
 | 
				
			||||||
 | 
								</li>
 | 
				
			||||||
 | 
								<li>
 | 
				
			||||||
 | 
									<label>Unwilling whore</label>
 | 
				
			||||||
 | 
									<description>I'm not just a rental ride!</description>
 | 
				
			||||||
 | 
									<baseMoodEffect>-10</baseMoodEffect>
 | 
				
			||||||
 | 
								</li>
 | 
				
			||||||
 | 
								<li>
 | 
				
			||||||
 | 
									<label>Accustomed whore</label>
 | 
				
			||||||
 | 
									<description>Just no beatings, please.</description>
 | 
				
			||||||
 | 
									<baseMoodEffect>-1</baseMoodEffect>
 | 
				
			||||||
 | 
								</li>
 | 
				
			||||||
 | 
								<li>
 | 
				
			||||||
 | 
									<label>Complete whore</label>
 | 
				
			||||||
 | 
									<description>I could get more clients if not these restraints!</description>
 | 
				
			||||||
 | 
									<baseMoodEffect>2</baseMoodEffect>
 | 
				
			||||||
 | 
								</li>
 | 
				
			||||||
 | 
							</stages>
 | 
				
			||||||
 | 
						</rjwwhoring.ThoughtDef_Whore>
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						<!--Used to keep track of customers, so a whore doesn't repeatedly solicit the same guest-->
 | 
				
			||||||
 | 
						<ThoughtDef>
 | 
				
			||||||
 | 
							<defName>RJWFailedSolicitation</defName>
 | 
				
			||||||
 | 
							<thoughtClass>Thought_MemorySocial</thoughtClass>
 | 
				
			||||||
 | 
							<durationDays>0.4</durationDays>
 | 
				
			||||||
 | 
							<stackLimit>100</stackLimit>
 | 
				
			||||||
 | 
							<stackLimitForSameOtherPawn>1</stackLimitForSameOtherPawn>
 | 
				
			||||||
 | 
							<stackedEffectMultiplier>0.5</stackedEffectMultiplier>
 | 
				
			||||||
 | 
							<stages>
 | 
				
			||||||
 | 
								<li>
 | 
				
			||||||
 | 
									<label>tried to solicit me</label>
 | 
				
			||||||
 | 
									<baseOpinionOffset>-1</baseOpinionOffset>
 | 
				
			||||||
 | 
								</li>
 | 
				
			||||||
 | 
							</stages>
 | 
				
			||||||
 | 
						</ThoughtDef>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<!--Same as above, but for colonists-->
 | 
				
			||||||
 | 
						<ThoughtDef>
 | 
				
			||||||
 | 
							<defName>RJWTurnedDownWhore</defName>
 | 
				
			||||||
 | 
							<thoughtClass>Thought_MemorySocial</thoughtClass>
 | 
				
			||||||
 | 
							<durationDays>0.2</durationDays>
 | 
				
			||||||
 | 
							<stackLimit>1</stackLimit>
 | 
				
			||||||
 | 
							<stackLimitForSameOtherPawn>1</stackLimitForSameOtherPawn>
 | 
				
			||||||
 | 
							<stackedEffectMultiplier>0.5</stackedEffectMultiplier>
 | 
				
			||||||
 | 
							<stages>
 | 
				
			||||||
 | 
								<li>
 | 
				
			||||||
 | 
									<label>bothered me</label>
 | 
				
			||||||
 | 
									<baseOpinionOffset>-1</baseOpinionOffset>
 | 
				
			||||||
 | 
								</li>
 | 
				
			||||||
 | 
							</stages>
 | 
				
			||||||
 | 
						</ThoughtDef>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<ThoughtDef>
 | 
				
			||||||
 | 
							<defName>SleptInBrothel</defName>
 | 
				
			||||||
 | 
							<durationDays>1</durationDays>
 | 
				
			||||||
 | 
							<stackedEffectMultiplier>1</stackedEffectMultiplier>
 | 
				
			||||||
 | 
							<stackLimit>1</stackLimit>
 | 
				
			||||||
 | 
							<stages>
 | 
				
			||||||
 | 
								<li>
 | 
				
			||||||
 | 
									<label>slept in brothel</label>
 | 
				
			||||||
 | 
									<description>Eww, the sheets were all sticky.</description>
 | 
				
			||||||
 | 
									<baseMoodEffect>-10</baseMoodEffect>
 | 
				
			||||||
 | 
								</li>
 | 
				
			||||||
 | 
								<li>
 | 
				
			||||||
 | 
									<label>slept in brothel!</label>
 | 
				
			||||||
 | 
									<description>I just love this place, the smell, the sounds...</description>
 | 
				
			||||||
 | 
									<baseMoodEffect>2</baseMoodEffect>
 | 
				
			||||||
 | 
								</li>
 | 
				
			||||||
 | 
							</stages>
 | 
				
			||||||
 | 
						</ThoughtDef>
 | 
				
			||||||
 | 
					</Defs>
 | 
				
			||||||
							
								
								
									
										13
									
								
								1.5/Defs/TipSetDefs/Tips.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,13 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="utf-8" ?>
 | 
				
			||||||
 | 
					<Defs>
 | 
				
			||||||
 | 
						<TipSetDef>
 | 
				
			||||||
 | 
							<defName>RjwWhoringTips</defName>
 | 
				
			||||||
 | 
							<tips>
 | 
				
			||||||
 | 
								<!-- UI -->
 | 
				
			||||||
 | 
								<li>Whoring price is visible in the "show sexuality" menu on the bio tab (the icon looks like a heart).</li>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								<!-- Mechanics -->
 | 
				
			||||||
 | 
								<li>Condoms can be automatically used if placed in a stockpile next to a bed - it might be a good idea to have some around if you intend on whoring your colonists out.</li>
 | 
				
			||||||
 | 
							</tips>
 | 
				
			||||||
 | 
						</TipSetDef>
 | 
				
			||||||
 | 
					</Defs>
 | 
				
			||||||
							
								
								
									
										30
									
								
								1.5/Defs/WhoreBackstories.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,30 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="utf-8" ?>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<Defs>
 | 
				
			||||||
 | 
						<!--Provide bonus exp/less penalties for whores-->
 | 
				
			||||||
 | 
						<rjwwhoring.StringListDef>
 | 
				
			||||||
 | 
							<defName>WhoreBackstories</defName>
 | 
				
			||||||
 | 
							<strings>
 | 
				
			||||||
 | 
								<!--Story Short names-->
 | 
				
			||||||
 | 
								<!--Only adult stories are checked-->
 | 
				
			||||||
 | 
								<!--Due to some genius(that is not compliment) encrypting backstories in the game executable, there is no reliable way to determine them-->
 | 
				
			||||||
 | 
								<!--Will have to do string match along the names, this can have unexpected results-->
 | 
				
			||||||
 | 
								<li>Sex slave</li>
 | 
				
			||||||
 | 
								<li>Courtesean</li>
 | 
				
			||||||
 | 
								<li>Housemate</li><!--filthy MILF whores-->
 | 
				
			||||||
 | 
								<li>Model</li><!--in fashion business they are either whores or gays... or both-->
 | 
				
			||||||
 | 
								<li>idol</li><!--same as above-->
 | 
				
			||||||
 | 
								<!--rjw own-->
 | 
				
			||||||
 | 
								<li>Nymph</li>
 | 
				
			||||||
 | 
								<!--ChJees Androids-->
 | 
				
			||||||
 | 
								<li>Pleasure</li>
 | 
				
			||||||
 | 
								<li>Courtesan</li>
 | 
				
			||||||
 | 
								<!--Orassan-->
 | 
				
			||||||
 | 
								<li>Dancer</li>
 | 
				
			||||||
 | 
								<li>Holo-star</li>
 | 
				
			||||||
 | 
								<!--Nihal-->
 | 
				
			||||||
 | 
								<li>Prostitute</li>
 | 
				
			||||||
 | 
								<li>Breeder</li>
 | 
				
			||||||
 | 
							</strings>
 | 
				
			||||||
 | 
						</rjwwhoring.StringListDef>
 | 
				
			||||||
 | 
					</Defs>
 | 
				
			||||||
							
								
								
									
										59
									
								
								1.5/Defs/WhoringTab/PawnColumnDefs/PawnColumns.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,59 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
 | 
					<Defs>
 | 
				
			||||||
 | 
						<PawnColumnDef>
 | 
				
			||||||
 | 
							<defName>RJW_IsWhore</defName>
 | 
				
			||||||
 | 
							<headerTip>Whores</headerTip>
 | 
				
			||||||
 | 
							<workerClass>rjwwhoring.MainTab.PawnColumnWorker_IsWhore</workerClass>
 | 
				
			||||||
 | 
							<sortable>true</sortable>
 | 
				
			||||||
 | 
							<width>80</width>
 | 
				
			||||||
 | 
						</PawnColumnDef>
 | 
				
			||||||
 | 
						<PawnColumnDef>
 | 
				
			||||||
 | 
							<defName>RJW_WhoreExperience</defName>
 | 
				
			||||||
 | 
							<headerTip>Whoring experience</headerTip>
 | 
				
			||||||
 | 
							<label>Experience</label>
 | 
				
			||||||
 | 
							<workerClass>rjwwhoring.MainTab.PawnColumnWorker_WhoreExperience</workerClass>
 | 
				
			||||||
 | 
							<width>100</width>
 | 
				
			||||||
 | 
						</PawnColumnDef>
 | 
				
			||||||
 | 
						<PawnColumnDef>
 | 
				
			||||||
 | 
							<defName>RJW_PriceRangeOfWhore</defName>
 | 
				
			||||||
 | 
							<headerTip>Price range for whore</headerTip>
 | 
				
			||||||
 | 
							<label>Price</label>
 | 
				
			||||||
 | 
							<workerClass>rjwwhoring.MainTab.PawnColumnWorker_PriceRangeOfWhore</workerClass>
 | 
				
			||||||
 | 
							<width>100</width>
 | 
				
			||||||
 | 
						</PawnColumnDef>
 | 
				
			||||||
 | 
						<PawnColumnDef>
 | 
				
			||||||
 | 
							<defName>RJW_EarnedMoneyByWhore</defName>
 | 
				
			||||||
 | 
							<headerTip>Money earned(total)</headerTip>
 | 
				
			||||||
 | 
							<label>Earned</label>
 | 
				
			||||||
 | 
							<workerClass>rjwwhoring.MainTab.PawnColumnWorker_EarnedMoneyByWhore</workerClass>
 | 
				
			||||||
 | 
							<width>100</width>
 | 
				
			||||||
 | 
						</PawnColumnDef>
 | 
				
			||||||
 | 
						<PawnColumnDef>
 | 
				
			||||||
 | 
							<defName>RJW_CountOfWhore</defName>
 | 
				
			||||||
 | 
							<headerTip>Clients served</headerTip>
 | 
				
			||||||
 | 
							<label>Clients</label>
 | 
				
			||||||
 | 
							<workerClass>rjwwhoring.MainTab.PawnColumnWorker_CountOfWhore</workerClass>
 | 
				
			||||||
 | 
							<width>100</width>
 | 
				
			||||||
 | 
						</PawnColumnDef>
 | 
				
			||||||
 | 
						<PawnColumnDef>
 | 
				
			||||||
 | 
							<defName>RJW_AverageMoneyByWhore</defName>
 | 
				
			||||||
 | 
							<headerTip>Money earned(average)</headerTip>
 | 
				
			||||||
 | 
							<label>Average</label>
 | 
				
			||||||
 | 
							<workerClass>rjwwhoring.MainTab.PawnColumnWorker_AverageMoneyByWhore</workerClass>
 | 
				
			||||||
 | 
							<width>100</width>
 | 
				
			||||||
 | 
						</PawnColumnDef>
 | 
				
			||||||
 | 
						<PawnColumnDef>
 | 
				
			||||||
 | 
							<defName>RJW_WhoreMood</defName>
 | 
				
			||||||
 | 
							<headerTip>Mood of pawn</headerTip>
 | 
				
			||||||
 | 
							<label>Mood</label>
 | 
				
			||||||
 | 
							<workerClass>rjwwhoring.MainTab.PawnColumnWorker_Mood</workerClass>
 | 
				
			||||||
 | 
							<width>100</width>
 | 
				
			||||||
 | 
						</PawnColumnDef>
 | 
				
			||||||
 | 
						<PawnColumnDef>
 | 
				
			||||||
 | 
							<defName>RJW_WhoringPolicy</defName>
 | 
				
			||||||
 | 
							<headerTip>Trade sex for benefits</headerTip>
 | 
				
			||||||
 | 
							<label>Payment type</label>
 | 
				
			||||||
 | 
							<workerClass>rjwwhoring.MainTab.PawnColumnWorker_WhoringPolicy</workerClass>
 | 
				
			||||||
 | 
							<width>100</width>
 | 
				
			||||||
 | 
						</PawnColumnDef>
 | 
				
			||||||
 | 
					</Defs>
 | 
				
			||||||
							
								
								
									
										34
									
								
								1.5/Defs/WhoringTab/PawnTableDefs.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,34 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
 | 
					<Defs>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<PawnTableDef>
 | 
				
			||||||
 | 
							<defName>RJW_Brothel</defName>
 | 
				
			||||||
 | 
							<workerClass>rjwwhoring.MainTab.PawnTable_Whores</workerClass>
 | 
				
			||||||
 | 
							<columns>
 | 
				
			||||||
 | 
								<li>Label</li>
 | 
				
			||||||
 | 
								<li>GapTiny</li>
 | 
				
			||||||
 | 
								<li>RJW_Gender</li>
 | 
				
			||||||
 | 
								<li>GapTiny</li>
 | 
				
			||||||
 | 
								<li>LifeStage</li>
 | 
				
			||||||
 | 
								<li>GapTiny</li>
 | 
				
			||||||
 | 
								<li>RJW_IsPrisoner</li>
 | 
				
			||||||
 | 
								<li>RJW_IsSlave</li>
 | 
				
			||||||
 | 
								<li>GapTiny</li>
 | 
				
			||||||
 | 
								<li>RJW_IsWhore</li>
 | 
				
			||||||
 | 
								<li>RJW_WhoreMood</li>
 | 
				
			||||||
 | 
								<li>RJW_CountOfWhore</li>
 | 
				
			||||||
 | 
								<li>RJW_WhoreExperience</li>
 | 
				
			||||||
 | 
								<li>RJW_EarnedMoneyByWhore</li>
 | 
				
			||||||
 | 
								<li>RJW_AverageMoneyByWhore</li>
 | 
				
			||||||
 | 
								<li>RJW_PriceRangeOfWhore</li>
 | 
				
			||||||
 | 
								<li>RJW_WhoringPolicy</li>
 | 
				
			||||||
 | 
								<li>RemainingSpace</li>
 | 
				
			||||||
 | 
							</columns>
 | 
				
			||||||
 | 
							<modExtensions>
 | 
				
			||||||
 | 
								<li Class="rjw.MainTab.DefModExtensions.RJW_PawnTable">
 | 
				
			||||||
 | 
									<label>Brothel</label>
 | 
				
			||||||
 | 
								</li>
 | 
				
			||||||
 | 
							</modExtensions>
 | 
				
			||||||
 | 
						</PawnTableDef>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</Defs>
 | 
				
			||||||
							
								
								
									
										43
									
								
								1.5/Languages/English/Keyed/Whoring.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,43 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
 | 
					<LanguageData>
 | 
				
			||||||
 | 
						<whoringtab_enabled>Enable whoring tab</whoringtab_enabled>
 | 
				
			||||||
 | 
						<whoringtab_enabled_desc>Shows/hide whoring tab</whoringtab_enabled_desc>
 | 
				
			||||||
 | 
						<show_whore_price_factor_on_bed>Show whore price factor on beds</show_whore_price_factor_on_bed>
 | 
				
			||||||
 | 
						<show_whore_price_factor_on_bed_desc>Show whore price factor as a label on beds that are enabled for whoring.</show_whore_price_factor_on_bed_desc>
 | 
				
			||||||
 | 
						<show_whore_widgets_on_bed>Show bed widgets</show_whore_widgets_on_bed>
 | 
				
			||||||
 | 
						<show_whore_widgets_on_bed_desc>Show bed widgets to mark beds for public/private for whoring.</show_whore_widgets_on_bed_desc>
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						<MoneyPrinting>Money Printing</MoneyPrinting>
 | 
				
			||||||
 | 
						<MoneyPrinting_desc>Clients will spawn silver instead of using their own/caravan</MoneyPrinting_desc>
 | 
				
			||||||
 | 
						<ClientAlwaysAccept>Client RNG disable</ClientAlwaysAccept>
 | 
				
			||||||
 | 
						<ClientAlwaysAccept_desc>Instead of doing rng roll, Clients always accept solicitation.</ClientAlwaysAccept_desc>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<DebugWhoring>Debug log whoring info</DebugWhoring>
 | 
				
			||||||
 | 
						<DebugWhoring_desc>Enables some very spamming debug logs to help find bugs in Whoring solicitation operations.</DebugWhoring_desc>
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						<!--Whore Activities-->
 | 
				
			||||||
 | 
						<RJW_VisitorAcceptWhore>{0} accepted the deal {1} offered.</RJW_VisitorAcceptWhore>
 | 
				
			||||||
 | 
						<RJW_VisitorSolicitWhore>{0} wants to be serviced by {1}.</RJW_VisitorSolicitWhore>
 | 
				
			||||||
 | 
						<RJW_VisitorRejectWhore>{0} rejected the deal {1} offered.</RJW_VisitorRejectWhore>
 | 
				
			||||||
 | 
						<RJW_VisitorSickWhore>{0} rejected the offer because {1} does not look healthy</RJW_VisitorSickWhore>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<!--Whore designators-->
 | 
				
			||||||
 | 
						<ForService>Assign to whorin'</ForService> <!-- This field is not visible -->
 | 
				
			||||||
 | 
						<ForServiceDesc><![CDATA[Mark for whoring
 | 
				
			||||||
 | 
					- Will try to solicit visitors.
 | 
				
			||||||
 | 
					- Entertains other colonists if not busy.
 | 
				
			||||||
 | 
					- Tries to refrain from masturbation while on the job, may cause frustration.
 | 
				
			||||||
 | 
					]]></ForServiceDesc>
 | 
				
			||||||
 | 
						<ForServiceRefuseDesc>Won't agree to be a whore</ForServiceRefuseDesc>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						<!--Bed designators-->
 | 
				
			||||||
 | 
						<CommandBedSetAsWhoreBedLabel>Allow everyone to whore</CommandBedSetAsWhoreBedLabel>
 | 
				
			||||||
 | 
						<CommandBedSetAsWhoreBedDesc>Allow all whores to use this bed to entertain customers.</CommandBedSetAsWhoreBedDesc>
 | 
				
			||||||
 | 
						<CommandBedAllowWhoringLabel>Allow owner to whore</CommandBedAllowWhoringLabel>
 | 
				
			||||||
 | 
						<CommandBedAllowWhoringDesc>Whether owner(s) are allowed to use this bed for whoring.</CommandBedAllowWhoringDesc>
 | 
				
			||||||
 | 
						<WhorePriceCalcDesc>Whoring price factor (based on comfort, room impressiveness and number of beds in room: {0}</WhorePriceCalcDesc>
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						<WhorePrice>Whoring price range: </WhorePrice>
 | 
				
			||||||
 | 
						<BrothelTabIsPrisoner>Prisoner</BrothelTabIsPrisoner>
 | 
				
			||||||
 | 
						<BrothelTabIsSlave>Slave</BrothelTabIsSlave>
 | 
				
			||||||
 | 
					</LanguageData>
 | 
				
			||||||
							
								
								
									
										27
									
								
								1.5/Patches/FacialAnimation_compatibility.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,27 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
 | 
					<Patch>
 | 
				
			||||||
 | 
					  <Operation Class="PatchOperationFindMod">
 | 
				
			||||||
 | 
					    <mods>
 | 
				
			||||||
 | 
					      <li>[NL] Facial Animation - WIP</li>
 | 
				
			||||||
 | 
					    </mods>
 | 
				
			||||||
 | 
					    <match Class="PatchOperationSequence">
 | 
				
			||||||
 | 
					      <success>Always</success>
 | 
				
			||||||
 | 
					      <operations>
 | 
				
			||||||
 | 
					        <li Class="PatchOperationAdd">
 | 
				
			||||||
 | 
					          <xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="Lovin" or defName="Lovin2"]/targetJobs</xpath>
 | 
				
			||||||
 | 
					          <success>Always</success>
 | 
				
			||||||
 | 
					          <value>
 | 
				
			||||||
 | 
					            <li>WhoreIsServingVisitors</li>
 | 
				
			||||||
 | 
					          </value>
 | 
				
			||||||
 | 
					        </li>
 | 
				
			||||||
 | 
					        <li Class="PatchOperationAdd">
 | 
				
			||||||
 | 
					          <xpath>/Defs/FacialAnimation.FaceAnimationDef[defName="StandAndBeSociallyActive"]/targetJobs</xpath>
 | 
				
			||||||
 | 
					          <success>Always</success>
 | 
				
			||||||
 | 
					          <value>
 | 
				
			||||||
 | 
					            <li>WhoreInvitingVisitors</li>
 | 
				
			||||||
 | 
					          </value>
 | 
				
			||||||
 | 
					        </li>
 | 
				
			||||||
 | 
					      </operations>
 | 
				
			||||||
 | 
					    </match>
 | 
				
			||||||
 | 
					  </Operation>
 | 
				
			||||||
 | 
					</Patch>
 | 
				
			||||||
							
								
								
									
										39
									
								
								1.5/Source/Mod/Data/BedData.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,39 @@
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public class BedData : IExposable
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							public Building_Bed bed = null;
 | 
				
			||||||
 | 
							public bool allowedForWhoringOwner = true;
 | 
				
			||||||
 | 
							public bool allowedForWhoringAll = false;
 | 
				
			||||||
 | 
							public int reservedUntilGameTick = 0;
 | 
				
			||||||
 | 
							public int reservedForPawnID = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public int lastScoreUpdateTick = -70; // GenTicks.TicksGame
 | 
				
			||||||
 | 
							public float bedScore = -1f;
 | 
				
			||||||
 | 
							public int scoreUpdateTickDelay = 60;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public float roomScore = -1f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public BedData() { }
 | 
				
			||||||
 | 
							public BedData(Building_Bed bed)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								this.bed = bed;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void ExposeData()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Scribe_References.Look(ref bed, "Bed");
 | 
				
			||||||
 | 
								Scribe_Values.Look(ref allowedForWhoringOwner, "allowedForWhoringOwner", true, true);
 | 
				
			||||||
 | 
								Scribe_Values.Look(ref allowedForWhoringAll, "allowedForWhoringAll", false, true);
 | 
				
			||||||
 | 
								Scribe_Values.Look(ref reservedUntilGameTick, "lastUsed", 0, true);
 | 
				
			||||||
 | 
								Scribe_Values.Look(ref reservedForPawnID, "lastUsedBy", 0, true);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public bool IsValid { get { return bed != null; } }
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										70
									
								
								1.5/Source/Mod/Data/DataStore.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,70 @@
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					using RimWorld.Planet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Rimworld object for storing the world/save info
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public class DataStore : WorldComponent
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							public Dictionary<int, BedData> bedData = new Dictionary<int, BedData>();
 | 
				
			||||||
 | 
							public Dictionary<int, WhoringData> whoringData = new Dictionary<int, WhoringData>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public DataStore(World world) : base(world)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public override void ExposeData()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								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<int, BedData>();
 | 
				
			||||||
 | 
									if (whoringData == null) whoringData = new Dictionary<int, WhoringData>();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public BedData GetBedData(Building_Bed bed)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								BedData res;
 | 
				
			||||||
 | 
								var filled = bedData.TryGetValue(bed.thingIDNumber, out res);
 | 
				
			||||||
 | 
								if ((res == null) || (!res.IsValid))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (filled)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										bedData.Remove(bed.thingIDNumber);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									res = new BedData(bed);
 | 
				
			||||||
 | 
									bedData.Add(bed.thingIDNumber, res);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								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;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										17
									
								
								1.5/Source/Mod/Data/PawnExtensions.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -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);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										14
									
								
								1.5/Source/Mod/Data/StringListDef.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Whore backstories from xml GET!
 | 
				
			||||||
 | 
						/// Just a simplest form of passing data from xml to the code
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public class StringListDef : Def
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							public List<string> strings = new List<string>(); 
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										36
									
								
								1.5/Source/Mod/Data/WhoringData.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -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; } }
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								1.5/Source/Mod/DefOf/RecordDefDefOf.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						[DefOf]
 | 
				
			||||||
 | 
						public static class RecordDefOf
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							public static RecordDef EarnedMoneyByWhore;
 | 
				
			||||||
 | 
							public static RecordDef CountOfWhore;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										19
									
								
								1.5/Source/Mod/DefOf/ThoughtDefOf.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    [DefOf]
 | 
				
			||||||
 | 
					    public static class ThoughtDefOf
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        public static ThoughtDef_Whore Whorish_Thoughts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static ThoughtDef_Whore Whorish_Thoughts_Captive;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static ThoughtDef SleptInBrothel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static ThoughtDef RJWFailedSolicitation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public static ThoughtDef RJWTurnedDownWhore;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										172
									
								
								1.5/Source/Mod/JobDrivers/JobDriver_WhoreInvitingVisitors.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,172 @@
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					using rjw;
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					using Verse.AI;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public class JobDriver_WhoreInvitingVisitors : JobDriver
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// List of jobs that can be interrupted by whores. 
 | 
				
			||||||
 | 
							public static readonly List<JobDef> allowedJobs = new List<JobDef> { null, JobDefOf.Wait_Wander, JobDefOf.GotoWander, JobDefOf.Clean, JobDefOf.ClearSnow,
 | 
				
			||||||
 | 
								JobDefOf.CutPlant, JobDefOf.HaulToCell, JobDefOf.Deconstruct, JobDefOf.Harvest, JobDefOf.LayDown, JobDefOf.Research, JobDefOf.SmoothFloor, JobDefOf.SmoothWall,
 | 
				
			||||||
 | 
								JobDefOf.StandAndBeSociallyActive, JobDefOf.RemoveApparel, JobDefOf.Strip, JobDefOf.Tame, JobDefOf.Wait, JobDefOf.Wear, JobDefOf.FixBrokenDownBuilding,
 | 
				
			||||||
 | 
								JobDefOf.FillFermentingBarrel, JobDefOf.DoBill, JobDefOf.Sow, JobDefOf.Shear, JobDefOf.BuildRoof, JobDefOf.DeliverFood,	JobDefOf.HaulToContainer, JobDefOf.Hunt, JobDefOf.Mine,
 | 
				
			||||||
 | 
								JobDefOf.OperateDeepDrill, JobDefOf.OperateScanner, JobDefOf.RearmTurret, JobDefOf.Refuel, JobDefOf.RefuelAtomic, JobDefOf.RemoveFloor, JobDefOf.RemoveRoof, JobDefOf.Repair,
 | 
				
			||||||
 | 
								JobDefOf.TakeBeerOutOfFermentingBarrel, JobDefOf.Train, JobDefOf.Uninstall, xxx.Masturbate};
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							public bool successfulPass = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private Pawn Whore => GetActor();
 | 
				
			||||||
 | 
							private Pawn TargetPawn => TargetThingA as Pawn;
 | 
				
			||||||
 | 
							private Building_Bed TargetBed => TargetThingB as Building_Bed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private readonly TargetIndex TargetPawnIndex = TargetIndex.A;
 | 
				
			||||||
 | 
							private readonly TargetIndex TargetBedIndex = TargetIndex.B;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private bool DoesTargetPawnAcceptAdvance()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (WhoringBase.DebugWhoring) ModLog.Message($"JobDriver_InvitingVisitors::DoesTargetPawnAcceptAdvance() - {xxx.get_pawnname(TargetPawn)}");
 | 
				
			||||||
 | 
								//if (RJWSettings.WildMode) return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (PawnUtility.EnemiesAreNearby(TargetPawn))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (WhoringBase.DebugWhoring) ModLog.Message($" fail - enemy near");
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (!allowedJobs.Contains(TargetPawn.jobs.curJob.def))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (WhoringBase.DebugWhoring) ModLog.Message($" fail - not allowed job");
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (WhoringBase.DebugWhoring)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									ModLog.Message("Will try hookup " + WhoringHelper.WillPawnTryHookup(TargetPawn));
 | 
				
			||||||
 | 
									ModLog.Message("Is whore appealing  " + WhoringHelper.IsHookupAppealing(TargetPawn, Whore));
 | 
				
			||||||
 | 
									ModLog.Message("Can afford whore " + WhoringHelper.CanAfford(TargetPawn, Whore));
 | 
				
			||||||
 | 
									ModLog.Message("Need sex " + (xxx.need_some_sex(TargetPawn) >= 1));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (WhoringHelper.WillPawnTryHookup(TargetPawn) && WhoringHelper.IsHookupAppealing(TargetPawn, Whore) && WhoringHelper.CanAfford(TargetPawn, Whore) && xxx.need_some_sex(TargetPawn) >= 1f)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (!Whore.IsPrisoner)
 | 
				
			||||||
 | 
										Whore.skills.Learn(SkillDefOf.Social, 1.2f);
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public override bool TryMakePreToilReservations(bool errorOnFailed) => true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected override IEnumerable<Toil> MakeNewToils()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								this.FailOnDespawnedOrNull(TargetPawnIndex);
 | 
				
			||||||
 | 
								this.FailOnDespawnedNullOrForbidden(TargetBedIndex);
 | 
				
			||||||
 | 
								this.FailOn(() => Whore is null || !WhoreBed_Utility.CanUseForWhoring(Whore, TargetBed));//|| !Whore.CanReserve(TargetPawn)
 | 
				
			||||||
 | 
								this.FailOn(() => pawn.Drafted);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!Whore.IsPrisoner)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									yield return Toils_Goto.GotoThing(TargetPawnIndex, PathEndMode.Touch);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									Toil TryItOn = new Toil();
 | 
				
			||||||
 | 
									TryItOn.AddFailCondition(() => !xxx.IsTargetPawnOkay(TargetPawn));
 | 
				
			||||||
 | 
									TryItOn.defaultCompleteMode = ToilCompleteMode.Delay;
 | 
				
			||||||
 | 
									TryItOn.initAction = delegate
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										//ModLog.Message("JobDriver_InvitingVisitors::MakeNewToils - TryItOn - initAction is called");
 | 
				
			||||||
 | 
										Whore.jobs.curDriver.ticksLeftThisToil = 50;
 | 
				
			||||||
 | 
										FleckMaker.ThrowMetaIcon(Whore.Position, Whore.Map, FleckDefOf.Heart);
 | 
				
			||||||
 | 
									};
 | 
				
			||||||
 | 
									yield return TryItOn;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Toil AwaitResponse = new Toil();
 | 
				
			||||||
 | 
								AwaitResponse.defaultCompleteMode = ToilCompleteMode.Delay;
 | 
				
			||||||
 | 
								AwaitResponse.defaultDuration = 10;
 | 
				
			||||||
 | 
								AwaitResponse.initAction = delegate
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									List<RulePackDef> extraSentencePacks = new List<RulePackDef>();
 | 
				
			||||||
 | 
									successfulPass = DoesTargetPawnAcceptAdvance();
 | 
				
			||||||
 | 
									//ModLog.Message("JobDriver_InvitingVisitors::MakeNewToils - AwaitResponse - initAction is called");
 | 
				
			||||||
 | 
									if (successfulPass)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										FleckMaker.ThrowMetaIcon(TargetPawn.Position, TargetPawn.Map, FleckDefOf.Heart);
 | 
				
			||||||
 | 
										TargetPawn.jobs.EndCurrentJob(JobCondition.Incompletable);
 | 
				
			||||||
 | 
										if (xxx.RomanceDiversifiedIsActive)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											extraSentencePacks.Add(RulePackDef.Named("HookupSucceeded"));
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										if (Whore.health.HasHediffsNeedingTend())
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											successfulPass = false;
 | 
				
			||||||
 | 
											string key = "RJW_VisitorSickWhore";
 | 
				
			||||||
 | 
											string text = key.Translate(TargetPawn.LabelIndefinite(), Whore.LabelIndefinite()).CapitalizeFirst();
 | 
				
			||||||
 | 
											Messages.Message(text, Whore, MessageTypeDefOf.TaskCompletion);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										else
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											string key = "RJW_VisitorAcceptWhore";
 | 
				
			||||||
 | 
											if (Whore.IsPrisoner)
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												key = "RJW_VisitorSolicitWhore";
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											string text = key.Translate(TargetPawn.LabelIndefinite(), Whore.LabelIndefinite()).CapitalizeFirst();
 | 
				
			||||||
 | 
											Messages.Message(text, TargetPawn, MessageTypeDefOf.TaskCompletion);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (!successfulPass)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										// remove bed reservation
 | 
				
			||||||
 | 
										TargetBed.UnreserveForWhoring();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										FleckMaker.ThrowMetaIcon(TargetPawn.Position, TargetPawn.Map, FleckDefOf.IncapIcon);
 | 
				
			||||||
 | 
										TargetPawn.needs.mood.thoughts.memories.TryGainMemory(
 | 
				
			||||||
 | 
											TargetPawn.Faction == Whore.Faction
 | 
				
			||||||
 | 
												? ThoughtDef.Named("RJWTurnedDownWhore")
 | 
				
			||||||
 | 
												: ThoughtDef.Named("RJWFailedSolicitation"), Whore);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (xxx.RomanceDiversifiedIsActive)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Whore.needs.mood.thoughts.memories.TryGainMemory(ThoughtDef.Named("RebuffedMyHookupAttempt"), TargetPawn);
 | 
				
			||||||
 | 
											TargetPawn.needs.mood.thoughts.memories.TryGainMemory(ThoughtDef.Named("FailedHookupAttemptOnMe"), Whore);
 | 
				
			||||||
 | 
											extraSentencePacks.Add(RulePackDef.Named("HookupFailed"));
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										//Disabled rejection notifications
 | 
				
			||||||
 | 
										//Messages.Message("RJW_VisitorRejectWhore".Translate(new object[] { xxx.get_pawnname(TargetPawn), xxx.get_pawnname(Whore) }), TargetPawn, MessageTypeDefOf.SilentInput);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (xxx.RomanceDiversifiedIsActive)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Find.PlayLog.Add(new PlayLogEntry_Interaction(DefDatabase<InteractionDef>.GetNamed("TriedHookupWith"), pawn, TargetPawn, extraSentencePacks));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									//Log.Message("[RJW] AwaitResponse initAction - successfulPass: " + successfulPass.ToString());
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
								yield return AwaitResponse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Toil BothGoToBed = new Toil();
 | 
				
			||||||
 | 
								BothGoToBed.AddFailCondition(() => !successfulPass || !WhoreBed_Utility.CanUseForWhoring(Whore, TargetBed));
 | 
				
			||||||
 | 
								BothGoToBed.defaultCompleteMode = ToilCompleteMode.Instant;
 | 
				
			||||||
 | 
								BothGoToBed.initAction = delegate
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									//ModLog.Message("JobDriver_InvitingVisitors::MakeNewToils - BothGoToBed - initAction is called0");
 | 
				
			||||||
 | 
									if (!successfulPass) return;
 | 
				
			||||||
 | 
									if (!WhoreBed_Utility.CanUseForWhoring(Whore, TargetBed) && Whore.CanReserve(TargetPawn, 1, 0))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										//ModLog.Message("JobDriver_InvitingVisitors::MakeNewToils - BothGoToBed - cannot use the whore bed");
 | 
				
			||||||
 | 
										return;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									//ModLog.Message("JobDriver_InvitingVisitors::MakeNewToils - BothGoToBed - initAction is called1");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									TargetBed.ReserveForWhoring(Whore, 1800);//is 1800 ticks long enough to go to the bed (until next reservation is made?)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									Whore.jobs.jobQueue.EnqueueFirst(JobMaker.MakeJob(xxx.whore_is_serving_visitors, TargetPawn, TargetBed));
 | 
				
			||||||
 | 
									//TargetPawn.jobs.jobQueue.EnqueueFirst(JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("WhoreIsServingVisitors"), Whore, TargetBed, (TargetBed.MaxAssignedPawnsCount>1)?TargetBed.GetSleepingSlotPos(1): TargetBed.)), null);
 | 
				
			||||||
 | 
									Whore.jobs.curDriver.EndJobWith(JobCondition.InterruptOptional);
 | 
				
			||||||
 | 
									//TargetPawn.jobs.curDriver.EndJobWith(JobCondition.InterruptOptional);
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
								yield return BothGoToBed;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										191
									
								
								1.5/Source/Mod/JobDrivers/JobDriver_WhoreIsServingVisitors.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,191 @@
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					using Verse.AI;
 | 
				
			||||||
 | 
					//using Multiplayer.API;
 | 
				
			||||||
 | 
					using rjw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public class JobDriver_WhoreIsServingVisitors : JobDriver_SexBaseInitiator
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							public IntVec3 SleepSpot => Bed.SleepPosOfAssignedPawn(pawn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public override bool TryMakePreToilReservations(bool errorOnFailed)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return pawn.Reserve(Target, job, 1, 0, null, errorOnFailed);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							//[SyncMethod]
 | 
				
			||||||
 | 
							protected override IEnumerable<Toil> MakeNewToils()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (WhoringBase.DebugWhoring) ModLog.Message("" + this.GetType().ToString() + ":MakeNewToils() - making toils");
 | 
				
			||||||
 | 
								setup_ticks();
 | 
				
			||||||
 | 
								var PartnerJob = xxx.gettin_loved;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								this.FailOnDespawnedOrNull(iTarget);
 | 
				
			||||||
 | 
								this.FailOnDespawnedNullOrForbidden(iBed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (WhoringBase.DebugWhoring) ModLog.Message("" + this.GetType().ToString() + ":fail conditions check " + !WhoreBed_Utility.CanUseForWhoring(pawn, Bed) + " " + !pawn.CanReserve(Partner));
 | 
				
			||||||
 | 
								this.FailOn(() => !WhoreBed_Utility.CanUseForWhoring(pawn, Bed) || !pawn.CanReserve(Partner));
 | 
				
			||||||
 | 
								this.FailOn(() => pawn.Drafted);
 | 
				
			||||||
 | 
								this.FailOn(() => Partner.IsFighting());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								yield return Toils_Reserve.Reserve(iTarget, 1, 0);
 | 
				
			||||||
 | 
								int basePrice = WhoringHelper.PriceOfWhore(pawn);
 | 
				
			||||||
 | 
								float bedMult = WhoreBed_Utility.CalculatePriceFactor(Bed);
 | 
				
			||||||
 | 
								//yield return Toils_Reserve.Reserve(BedInd, Bed.SleepingSlotsCount, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (WhoringBase.DebugWhoring) ModLog.Message("" + this.GetType().ToString() + ":generate job toils");
 | 
				
			||||||
 | 
								Toil gotoBed = new Toil();
 | 
				
			||||||
 | 
								gotoBed.defaultCompleteMode = ToilCompleteMode.PatherArrival;
 | 
				
			||||||
 | 
								gotoBed.FailOnBedNoLongerUsable(iBed, Bed);
 | 
				
			||||||
 | 
								gotoBed.AddFailCondition(() => Partner.Downed);
 | 
				
			||||||
 | 
								gotoBed.FailOn(() => !Partner.CanReach(Bed, PathEndMode.Touch, Danger.Deadly));
 | 
				
			||||||
 | 
								gotoBed.initAction = delegate
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (WhoringBase.DebugWhoring) ModLog.Message("" + this.GetType().ToString() + ":gotoWhoreBed");
 | 
				
			||||||
 | 
									pawn.pather.StartPath(SleepSpot, PathEndMode.OnCell);
 | 
				
			||||||
 | 
									Partner.jobs.StopAll();
 | 
				
			||||||
 | 
									Job job = JobMaker.MakeJob(JobDefOf.GotoMindControlled, SleepSpot);
 | 
				
			||||||
 | 
									Partner.jobs.StartJob(job, JobCondition.InterruptForced);
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
								yield return gotoBed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								ticks_left = (int)(2000.0f * Rand.Range(0.30f, 1.30f));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Toil waitInBed = new Toil();
 | 
				
			||||||
 | 
								waitInBed.initAction = delegate
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									ticksLeftThisToil = 5000;
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
								waitInBed.tickAction = delegate
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									pawn.GainComfortFromCellIfPossible();
 | 
				
			||||||
 | 
									if (IsInOrByBed(Bed, Partner) && pawn.PositionHeld == Partner.PositionHeld)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										ReadyForNextToil();
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
								waitInBed.defaultCompleteMode = ToilCompleteMode.Delay;
 | 
				
			||||||
 | 
								yield return waitInBed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Toil StartPartnerJob = new Toil();
 | 
				
			||||||
 | 
								StartPartnerJob.defaultCompleteMode = ToilCompleteMode.Instant;
 | 
				
			||||||
 | 
								StartPartnerJob.socialMode = RandomSocialMode.Off;
 | 
				
			||||||
 | 
								StartPartnerJob.initAction = delegate
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (WhoringBase.DebugWhoring) ModLog.Message("" + this.GetType().ToString() + ":StartPartnerJob");
 | 
				
			||||||
 | 
									var gettin_loved = JobMaker.MakeJob(PartnerJob, pawn, Bed);
 | 
				
			||||||
 | 
									Partner.jobs.StartJob(gettin_loved, JobCondition.InterruptForced);
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
								yield return StartPartnerJob;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Toil SexToil = new Toil();
 | 
				
			||||||
 | 
								SexToil.defaultCompleteMode = ToilCompleteMode.Never;
 | 
				
			||||||
 | 
								SexToil.socialMode = RandomSocialMode.Off;
 | 
				
			||||||
 | 
								SexToil.handlingFacing = true;
 | 
				
			||||||
 | 
								SexToil.FailOn(() => Partner.Dead);
 | 
				
			||||||
 | 
								SexToil.FailOn(() => Partner.CurJob.def != PartnerJob);
 | 
				
			||||||
 | 
								SexToil.initAction = delegate
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (WhoringBase.DebugWhoring) ModLog.Message("" + this.GetType().ToString() + ":SexToil start");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// refresh bed reservation
 | 
				
			||||||
 | 
									Bed.ReserveForWhoring(pawn, ticks_left+100);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									Start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// TODO: replace this quick n dirty way
 | 
				
			||||||
 | 
									CondomUtility.GetCondomFromRoom(pawn);
 | 
				
			||||||
 | 
									// Try to use whore's condom first, then client's
 | 
				
			||||||
 | 
									Sexprops.usedCondom = CondomUtility.TryUseCondom(pawn) || CondomUtility.TryUseCondom(Partner);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (!RJWSettings.HippieMode && xxx.HasNonPolyPartner(Partner, true))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Pawn lover = LovePartnerRelationUtility.ExistingLovePartner(Partner);
 | 
				
			||||||
 | 
										// We have to do a few other checks because the pawn might have multiple lovers and ExistingLovePartner() might return the wrong one
 | 
				
			||||||
 | 
										if (lover != null && pawn != lover && !lover.Dead && (lover.Map == Partner.Map || Rand.Value < 0.25) && GenSight.LineOfSight(lover.Position, Partner.Position, lover.Map))
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											lover.needs.mood.thoughts.memories.TryGainMemory(RimWorld.ThoughtDefOf.CheatedOnMe, Partner);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
								SexToil.AddPreTickAction(delegate
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (pawn.IsHashIntervalTick(ticks_between_hearts))
 | 
				
			||||||
 | 
										if (xxx.is_nympho(pawn))
 | 
				
			||||||
 | 
											FleckMaker.ThrowMetaIcon(pawn.Position, pawn.Map, FleckDefOf.Heart);
 | 
				
			||||||
 | 
										else
 | 
				
			||||||
 | 
											FleckMaker.ThrowMetaIcon(pawn.Position, pawn.Map, xxx.mote_noheart);
 | 
				
			||||||
 | 
									SexTick(pawn, Partner);
 | 
				
			||||||
 | 
									SexUtility.reduce_rest(Partner, 1);
 | 
				
			||||||
 | 
									SexUtility.reduce_rest(pawn, 2);
 | 
				
			||||||
 | 
									if (ticks_left % 100 == 0)
 | 
				
			||||||
 | 
										Bed.ReserveForWhoring(pawn, ticks_left + 100); // without this, reservation sometimes expires before sex is finished
 | 
				
			||||||
 | 
									if (ticks_left <= 0)
 | 
				
			||||||
 | 
										ReadyForNextToil();
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
								SexToil.AddFinishAction(delegate
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									End();
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
								yield return SexToil;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Toil afterSex = new Toil
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									initAction = delegate
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										// Adding interactions, social logs, etc
 | 
				
			||||||
 | 
										SexUtility.ProcessSex(Sexprops);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										Bed.UnreserveForWhoring();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (!(Partner.IsColonist && (pawn.IsPrisonerOfColony || pawn.IsColonist)))
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											if (pawn.WhoringData().WhoringPolicy == WhoringData.WhoringType.Silver)
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												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");
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
												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);
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (SexUtility.ConsiderCleaning(pawn))
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											LocalTargetInfo cum = pawn.PositionHeld.GetFirstThing<Filth>(pawn.Map);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											Job clean = JobMaker.MakeJob(JobDefOf.Clean);
 | 
				
			||||||
 | 
											clean.AddQueuedTarget(TargetIndex.A, cum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											pawn.jobs.jobQueue.EnqueueFirst(clean);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									defaultCompleteMode = ToilCompleteMode.Instant
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
								yield return afterSex;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										300
									
								
								1.5/Source/Mod/JobGivers/JobGiver_WhoreInvitingVisitors.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,300 @@
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using HugsLib.Utils;
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					using rjw;
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					using Verse.AI;
 | 
				
			||||||
 | 
					//using Multiplayer.API;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public class JobGiver_WhoreInvitingVisitors : ThinkNode_JobGiver
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// Checks if pawn has a memory. 
 | 
				
			||||||
 | 
							// Maybe not the best place for function, might be useful elsewhere too.
 | 
				
			||||||
 | 
							public static bool MemoryChecker(Pawn pawn, ThoughtDef thought)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Thought_Memory val = pawn.needs.mood.thoughts.memories.Memories.Find((Thought_Memory x) => (object)x.def == thought);
 | 
				
			||||||
 | 
								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)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								//Rand.PopState();
 | 
				
			||||||
 | 
								//Rand.PushState(RJW_Multiplayer.PredictableSeed());
 | 
				
			||||||
 | 
								float fuckability = SexAppraiser.would_fuck(client, whore); // 0.0 to 1.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// More likely to skip other whores, because they're supposed to be working.
 | 
				
			||||||
 | 
								if (client.IsDesignatedService())
 | 
				
			||||||
 | 
									fuckability *= 0.6f;
 | 
				
			||||||
 | 
								if (WhoringBase.ClientAlwaysAccept)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return fuckability >= 0.1f && xxx.need_some_sex(client) >= 1f;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									return fuckability >= 0.1f && xxx.need_some_sex(client) >= 1f && Rand.Chance(0.5f);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							public static Pawn Find_pawn_to_fuck(Pawn whore, Map map)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Pawn best_fuckee = null;
 | 
				
			||||||
 | 
								float best_distance = 1.0e6f;
 | 
				
			||||||
 | 
								foreach (Pawn q in map.mapPawns.FreeColonists)
 | 
				
			||||||
 | 
									if ((q != whore) &&
 | 
				
			||||||
 | 
										xxx.need_some_sex(q)>0 &&
 | 
				
			||||||
 | 
										whore.CanReserve(q, 1, 0) &&
 | 
				
			||||||
 | 
										q.CanReserve(whore, 1, 0) &&
 | 
				
			||||||
 | 
										Roll_to_skip(whore, q) &&
 | 
				
			||||||
 | 
										(!q.Position.IsForbidden(whore)) &&
 | 
				
			||||||
 | 
										xxx.is_healthy(q))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										var dis = whore.Position.DistanceToSquared(q.Position);
 | 
				
			||||||
 | 
										if (dis < best_distance)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											best_fuckee = q;
 | 
				
			||||||
 | 
											best_distance = dis;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								return best_fuckee;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private sealed class FindAttractivePawnHelper
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								internal Pawn whore;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								internal bool TraitCheckFail(Pawn client)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (!xxx.is_human(client))
 | 
				
			||||||
 | 
										return true;
 | 
				
			||||||
 | 
									if (!xxx.has_traits(client))
 | 
				
			||||||
 | 
										return true;
 | 
				
			||||||
 | 
									if (!(xxx.can_fuck(client) || xxx.can_be_fucked(client)) || !xxx.IsTargetPawnOkay(client))
 | 
				
			||||||
 | 
										return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									//Log.Message("client:" + client + " whore:" + whore);
 | 
				
			||||||
 | 
									if (CompRJW.CheckPreference(client, whore) == false)
 | 
				
			||||||
 | 
										return true;
 | 
				
			||||||
 | 
									return false; // Everything ok.
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								//Use this check when client is not in the same faction as the whore
 | 
				
			||||||
 | 
								internal bool FactionCheckPass(Pawn client)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return ((client.Map == whore.Map) && (client.Faction != null && client.Faction != whore.Faction) && !client.IsPrisoner && !xxx.is_slave(client) && !client.HostileTo(whore));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								//Use this check when client is in the same faction as the whore
 | 
				
			||||||
 | 
								//[SyncMethod]
 | 
				
			||||||
 | 
								internal bool RelationCheckPass(Pawn client)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									//Rand.PopState();
 | 
				
			||||||
 | 
									//Rand.PushState(RJW_Multiplayer.PredictableSeed());
 | 
				
			||||||
 | 
									if (xxx.IsSingleOrPartnersNotHere(client) || xxx.is_lecher(client) || Rand.Value < 0.9f)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										if (client != LovePartnerRelationUtility.ExistingLovePartner(whore))
 | 
				
			||||||
 | 
										{ //Exception for prisoners to account for PrisonerWhoreSexualEmergencyTree, which allows prisoners to try to hook up with anyone who's around (mostly other prisoners or warden)
 | 
				
			||||||
 | 
											return (client != whore) & (client.Map == whore.Map) && (client.Faction == whore.Faction || whore.IsPrisoner) && (client.IsColonist || whore.IsPrisoner) && WhoringHelper.IsHookupAppealing(whore, client);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							//[SyncMethod]
 | 
				
			||||||
 | 
							public static Pawn FindAttractivePawn(Pawn whore, out int price)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								price = 0;
 | 
				
			||||||
 | 
								if (whore == null || xxx.is_asexual(whore))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (WhoringBase.DebugWhoring) ModLog.Message($" {xxx.get_pawnname(whore)} is asexual, abort");
 | 
				
			||||||
 | 
									return null;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								//Rand.PopState();
 | 
				
			||||||
 | 
								//Rand.PushState(RJW_Multiplayer.PredictableSeed());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								FindAttractivePawnHelper client = new FindAttractivePawnHelper
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									whore = whore
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
								price = WhoringHelper.PriceOfWhore(whore);
 | 
				
			||||||
 | 
								int priceOfWhore = price;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								IntVec3 pos = whore.Position;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								IEnumerable<Pawn> potentialClients = whore.Map.mapPawns.AllPawnsSpawned;
 | 
				
			||||||
 | 
								potentialClients = potentialClients.Where(x
 | 
				
			||||||
 | 
									=> x != whore
 | 
				
			||||||
 | 
									&& !x.IsForbidden(whore)
 | 
				
			||||||
 | 
									&& !x.HostileTo(whore)
 | 
				
			||||||
 | 
									&& !x.IsPrisoner
 | 
				
			||||||
 | 
									&& !xxx.is_slave(x)
 | 
				
			||||||
 | 
									&& !x.IsColonist
 | 
				
			||||||
 | 
									//&& (!x.IsColonist || x.guest?.GuestStatus == GuestStatus.Guest)
 | 
				
			||||||
 | 
									&& x.Position.DistanceTo(pos) < 100
 | 
				
			||||||
 | 
									&& xxx.is_healthy_enough(x));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
								potentialClients = potentialClients.Except(potentialClients.Where(client.TraitCheckFail));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!whore.IsPrisoner)
 | 
				
			||||||
 | 
									potentialClients = potentialClients.Except(potentialClients.Where(x => !whore.CanReserveAndReach(x, PathEndMode.ClosestTouch, Danger.Some, 1)));
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									potentialClients = potentialClients.Except(potentialClients.Where(x => !x.CanReserveAndReach(whore, PathEndMode.ClosestTouch, Danger.Some, 1)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								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<Pawn> valid_targets = new List<Pawn>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!whore.IsPrisoner)
 | 
				
			||||||
 | 
									foreach (Pawn target in potentialClients)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										if(Pather_Utility.cells_to_target_casual(whore, target.Position))
 | 
				
			||||||
 | 
											if (Pather_Utility.can_path_to_target(whore, target.Position))
 | 
				
			||||||
 | 
												valid_targets.Add(target);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									foreach (Pawn target in potentialClients)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										if (Pather_Utility.cells_to_target_casual(target, whore.Position))
 | 
				
			||||||
 | 
											if (Pather_Utility.can_path_to_target(target, whore.Position))
 | 
				
			||||||
 | 
												valid_targets.Add(target);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								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<Pawn> 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
 | 
				
			||||||
 | 
								//	&& x != LovePartnerRelationUtility.ExistingLovePartner(whore));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								//if (RJWSettings.DebugWhoring) ModLog.Message($" number of relations OK {guestsSpawned.Count()}");
 | 
				
			||||||
 | 
								//guestsSpawned = valid_targets.Where(x => x.Faction != whore.Faction
 | 
				
			||||||
 | 
								//	&& !MemoryChecker(x, ThoughtDef.Named("RJWFailedSolicitation")));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								//if (RJWSettings.DebugWhoring) ModLog.Message($" number of clients can memory OK {guestsSpawned.Count()}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								List<Pawn> guestsSpawned = new List<Pawn>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								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())
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (WhoringBase.DebugWhoring) ModLog.Message($" number of all acceptable Guests {guestsSpawned.Count()}");
 | 
				
			||||||
 | 
									return guestsSpawned.RandomElement();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								//use casual sex for colonist hooking
 | 
				
			||||||
 | 
								if (WhoringBase.DebugWhoring) ModLog.Message($" found no guests, trying colonists");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!WhoringHelper.WillPawnTryHookup(whore))// will hookup colonists?
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return null;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								IEnumerable<Pawn> freeColonists = valid_targets.Where(x => x.Faction == whore.Faction
 | 
				
			||||||
 | 
									&& Roll_to_skip(x, whore));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (WhoringBase.DebugWhoring) ModLog.Message($" number of free colonists {freeColonists.Count()}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								freeColonists = freeColonists.Where(x => client.RelationCheckPass(x) && !MemoryChecker(x, ThoughtDef.Named("RJWTurnedDownWhore")));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (freeColonists.Any())
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (WhoringBase.DebugWhoring) ModLog.Message($" number of all acceptable Colonists {freeColonists.Count()}");
 | 
				
			||||||
 | 
									return freeColonists.RandomElement();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected override Job TryGiveJob(Pawn pawn)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Most things are now checked in the ThinkNode_ConditionalWhore.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (pawn.Drafted) return null;
 | 
				
			||||||
 | 
								//if (MP.IsInMultiplayer) return null; //fix error someday, maybe
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (pawn.jobs.curDriver is JobDriver_Sex || pawn.jobs.curDriver is JobDriver_WhoreInvitingVisitors) return null; // already having sex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!SexUtility.ReadyForLovin(pawn))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									//Whores need rest too, but this'll reduxe the wait a bit every it triggers.
 | 
				
			||||||
 | 
									pawn.mindState.canLovinTick -= 40;
 | 
				
			||||||
 | 
									return null;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (WhoringBase.DebugWhoring) ModLog.Message($"JobGiver_WhoreInvitingVisitors.TryGiveJob:({xxx.get_pawnname(pawn)})");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								int price;
 | 
				
			||||||
 | 
								Pawn client = FindAttractivePawn(pawn, out price);
 | 
				
			||||||
 | 
								if (client == null)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (WhoringBase.DebugWhoring) ModLog.Message($" no clients found");
 | 
				
			||||||
 | 
									return null;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (WhoringBase.DebugWhoring) ModLog.Message($" {xxx.get_pawnname(client)} is client");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Building_Bed whorebed = WhoreBed_Utility.FindBed(pawn, client);
 | 
				
			||||||
 | 
								if (whorebed == null)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (WhoringBase.DebugWhoring) ModLog.Message($" {xxx.get_pawnname(pawn)} + {xxx.get_pawnname(client)} - no usable bed found");
 | 
				
			||||||
 | 
									return null;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								whorebed.ReserveForWhoring(pawn, 600); // reserve for a short while until whore can actually ask customer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return JobMaker.MakeJob(xxx.whore_inviting_visitors, client, whorebed);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										28
									
								
								1.5/Source/Mod/Location/Brothel_Room.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,28 @@
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public class RoomRoleWorker_Brothel : RoomRoleWorker
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							public override float GetScore(Room room)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								int num = 0;
 | 
				
			||||||
 | 
								var allContainedThings = room.ContainedAndAdjacentThings;
 | 
				
			||||||
 | 
								foreach (var thing in allContainedThings)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									var building_Bed = thing as Building_Bed;
 | 
				
			||||||
 | 
									if (building_Bed?.def.building.bed_humanlike == true)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										if (building_Bed.ForPrisoners) return 0;
 | 
				
			||||||
 | 
										if (building_Bed.IsAllowedForWhoringAll()) num++;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (num < 1) return 0;
 | 
				
			||||||
 | 
								return num * 110001; // higher than guest beds or "regular" beds when counting barracks
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,59 @@
 | 
				
			||||||
 | 
					namespace rjwwhoring
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						//This class is not used now.
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						public class ThinkNode_ChancePerHour_Whore : ThinkNode_ChancePerHour
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							protected override float MtbHours(Pawn pawn)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// Use the fappin mtb hours as the base number b/c it already accounts for things like age
 | 
				
			||||||
 | 
								var base_mtb = xxx.config.whore_mtbh_mul * ThinkNode_ChancePerHour_Fappin.get_fappin_mtb_hours(pawn);
 | 
				
			||||||
 | 
								if (base_mtb < 0.0f)
 | 
				
			||||||
 | 
									return -1.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								float desire_factor;
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									var need_sex = pawn.needs.TryGetNeed<Need_Sex>();
 | 
				
			||||||
 | 
									if (need_sex != null)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										if (need_sex.CurLevel <= need_sex.thresh_frustrated())
 | 
				
			||||||
 | 
											desire_factor = 0.15f;
 | 
				
			||||||
 | 
										else if (need_sex.CurLevel <= need_sex.thresh_horny())
 | 
				
			||||||
 | 
											desire_factor = 0.60f;
 | 
				
			||||||
 | 
										else
 | 
				
			||||||
 | 
											desire_factor = 1.00f;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else
 | 
				
			||||||
 | 
										desire_factor = 1.00f;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								float personality_factor;
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									personality_factor = 1.0f;
 | 
				
			||||||
 | 
									if (pawn.story != null)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										foreach (var trait in pawn.story.traits.allTraits)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											if (trait.def == xxx.nymphomaniac) personality_factor *= 0.25f;
 | 
				
			||||||
 | 
											else if (trait.def == TraitDefOf.Greedy) personality_factor *= 0.50f;
 | 
				
			||||||
 | 
											else if (xxx.RomanceDiversifiedIsActive&&(trait.def==xxx.philanderer || trait.def == xxx.polyamorous)) personality_factor *= 0.75f;
 | 
				
			||||||
 | 
											else if (xxx.RomanceDiversifiedIsActive && (trait.def == xxx.faithful)&& LovePartnerRelationUtility.HasAnyLovePartner(pawn)) personality_factor *= 30f;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								float fun_factor;
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if ((pawn.needs.joy != null) && (xxx.is_nympho(pawn)))
 | 
				
			||||||
 | 
										fun_factor = Mathf.Clamp01(0.50f + pawn.needs.joy.CurLevel);
 | 
				
			||||||
 | 
									else
 | 
				
			||||||
 | 
										fun_factor = 1.00f;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var gender_factor = (pawn.gender == Gender.Male) ? 1.0f : 3.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return base_mtb * desire_factor * personality_factor * fun_factor * gender_factor;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										25
									
								
								1.5/Source/Mod/ThinkTreeNodes/ThinkNode_ConditionalWhore.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,25 @@
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					using Verse.AI;
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					using rjw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Whore/prisoner look for customers
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public class ThinkNode_ConditionalWhore : ThinkNode_Conditional
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							protected override bool Satisfied(Pawn p)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// No animal whorin' for now.
 | 
				
			||||||
 | 
								if (xxx.is_animal(p))
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!InteractionUtility.CanInitiateInteraction(p))
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return xxx.is_whore(p);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										43
									
								
								1.5/Source/Mod/Thoughts/ThoughtWorker_Whore.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,43 @@
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Extends the standard thought to add a counter for the whore stages
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public class ThoughtDef_Whore : ThoughtDef
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							public List<int> stageCounts = new List<int>();
 | 
				
			||||||
 | 
							public int storyOffset = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public class ThoughtWorker_Whore : Thought_Memory
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							public static readonly HashSet<string> backstories = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("WhoreBackstories").strings);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected List<int> Stages => ((ThoughtDef_Whore) def).stageCounts;
 | 
				
			||||||
 | 
							protected int StoryOffset => ((ThoughtDef_Whore) def).storyOffset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public override int CurStageIndex
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								get
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									int timesWhored = pawn.records.GetAsInt(RecordDefOf.CountOfWhore);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (backstories.Contains(pawn.story?.Adulthood?.titleShort))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										timesWhored += StoryOffset;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (timesWhored > Stages[Stages.Count - 1])
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										return Stages.Count - 1;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return Stages.FindLastIndex(v => timesWhored > v) + 1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										116
									
								
								1.5/Source/Mod/Whoring.csproj
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,116 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
 | 
					<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 | 
				
			||||||
 | 
					  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
 | 
				
			||||||
 | 
					  <PropertyGroup>
 | 
				
			||||||
 | 
					    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
 | 
				
			||||||
 | 
					    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
 | 
				
			||||||
 | 
					    <ProjectGuid>{3FC2D442-19B8-4CF9-9D35-CD13B6AC7B28}</ProjectGuid>
 | 
				
			||||||
 | 
					    <OutputType>Library</OutputType>
 | 
				
			||||||
 | 
					    <RootNamespace>rjwwhoring</RootNamespace>
 | 
				
			||||||
 | 
					    <AssemblyName>RimJobWorldWhoring</AssemblyName>
 | 
				
			||||||
 | 
					    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
 | 
				
			||||||
 | 
					    <FileAlignment>512</FileAlignment>
 | 
				
			||||||
 | 
					  </PropertyGroup>
 | 
				
			||||||
 | 
					  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
 | 
				
			||||||
 | 
					    <PlatformTarget>AnyCPU</PlatformTarget>
 | 
				
			||||||
 | 
					    <DebugSymbols>true</DebugSymbols>
 | 
				
			||||||
 | 
					    <DebugType>full</DebugType>
 | 
				
			||||||
 | 
					    <Optimize>false</Optimize>
 | 
				
			||||||
 | 
					    <OutputPath>..\..\Assemblies\</OutputPath>
 | 
				
			||||||
 | 
					    <DefineConstants>DEBUG;TRACE</DefineConstants>
 | 
				
			||||||
 | 
					    <ErrorReport>prompt</ErrorReport>
 | 
				
			||||||
 | 
					    <WarningLevel>4</WarningLevel>
 | 
				
			||||||
 | 
					  </PropertyGroup>
 | 
				
			||||||
 | 
					  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
 | 
				
			||||||
 | 
					    <PlatformTarget>AnyCPU</PlatformTarget>
 | 
				
			||||||
 | 
					    <DebugType>pdbonly</DebugType>
 | 
				
			||||||
 | 
					    <Optimize>true</Optimize>
 | 
				
			||||||
 | 
					    <OutputPath>..\..\Assemblies\</OutputPath>
 | 
				
			||||||
 | 
					    <DefineConstants>TRACE</DefineConstants>
 | 
				
			||||||
 | 
					    <ErrorReport>prompt</ErrorReport>
 | 
				
			||||||
 | 
					    <WarningLevel>4</WarningLevel>
 | 
				
			||||||
 | 
					  </PropertyGroup>
 | 
				
			||||||
 | 
					  <ItemGroup>
 | 
				
			||||||
 | 
					    <Reference Include="0Harmony, Version=2.3.3.0, Culture=neutral, processorArchitecture=MSIL">
 | 
				
			||||||
 | 
					      <HintPath>..\packages\Lib.Harmony.2.3.3\lib\net472\0Harmony.dll</HintPath>
 | 
				
			||||||
 | 
					      <Private>False</Private>
 | 
				
			||||||
 | 
					    </Reference>
 | 
				
			||||||
 | 
					    <Reference Include="Assembly-CSharp">
 | 
				
			||||||
 | 
					      <HintPath>..\..\..\..\..\RimWorldWin64_Data\Managed\Assembly-CSharp.dll</HintPath>
 | 
				
			||||||
 | 
					      <Private>False</Private>
 | 
				
			||||||
 | 
					    </Reference>
 | 
				
			||||||
 | 
					    <Reference Include="HugsLib">
 | 
				
			||||||
 | 
					      <HintPath>..\..\..\..\..\..\..\workshop\content\294100\818773962\v1.5\Assemblies\HugsLib.dll</HintPath>
 | 
				
			||||||
 | 
					      <Private>False</Private>
 | 
				
			||||||
 | 
					    </Reference>
 | 
				
			||||||
 | 
					    <Reference Include="RJW">
 | 
				
			||||||
 | 
					      <HintPath>..\..\..\..\rjw\1.5\Assemblies\RJW.dll</HintPath>
 | 
				
			||||||
 | 
					      <Private>False</Private>
 | 
				
			||||||
 | 
					    </Reference>
 | 
				
			||||||
 | 
					    <Reference Include="System" />
 | 
				
			||||||
 | 
					    <Reference Include="System.Runtime.InteropServices.RuntimeInformation" />
 | 
				
			||||||
 | 
					    <Reference Include="UnityEngine.CoreModule">
 | 
				
			||||||
 | 
					      <HintPath>..\..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
 | 
				
			||||||
 | 
					      <Private>False</Private>
 | 
				
			||||||
 | 
					    </Reference>
 | 
				
			||||||
 | 
					    <Reference Include="UnityEngine.IMGUIModule">
 | 
				
			||||||
 | 
					      <HintPath>..\..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.IMGUIModule.dll</HintPath>
 | 
				
			||||||
 | 
					      <Private>False</Private>
 | 
				
			||||||
 | 
					    </Reference>
 | 
				
			||||||
 | 
					    <Reference Include="UnityEngine.InputLegacyModule">
 | 
				
			||||||
 | 
					      <HintPath>..\..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.InputLegacyModule.dll</HintPath>
 | 
				
			||||||
 | 
					      <Private>False</Private>
 | 
				
			||||||
 | 
					    </Reference>
 | 
				
			||||||
 | 
					    <Reference Include="UnityEngine.InputModule">
 | 
				
			||||||
 | 
					      <HintPath>..\..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.InputModule.dll</HintPath>
 | 
				
			||||||
 | 
					      <Private>False</Private>
 | 
				
			||||||
 | 
					    </Reference>
 | 
				
			||||||
 | 
					    <Reference Include="UnityEngine.TextRenderingModule">
 | 
				
			||||||
 | 
					      <HintPath>..\..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.TextRenderingModule.dll</HintPath>
 | 
				
			||||||
 | 
					      <Private>False</Private>
 | 
				
			||||||
 | 
					    </Reference>
 | 
				
			||||||
 | 
					  </ItemGroup>
 | 
				
			||||||
 | 
					  <ItemGroup>
 | 
				
			||||||
 | 
					    <AppDesigner Include="Properties\" />
 | 
				
			||||||
 | 
					  </ItemGroup>
 | 
				
			||||||
 | 
					  <ItemGroup>
 | 
				
			||||||
 | 
					    <Compile Include="..\Properties\AssemblyInfo.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="Data\BedData.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="Data\DataStore.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="Data\StringListDef.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="Data\WhoringData.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="DefOf\RecordDefDefOf.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="harmony_Building_BedPatches.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="harmony_AftersexPatch.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="harmony_RJWTab_patch.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="JobDrivers\JobDriver_WhoreInvitingVisitors.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="JobDrivers\JobDriver_WhoreIsServingVisitors.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="JobGivers\JobGiver_WhoreInvitingVisitors.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="Location\Brothel_Room.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="Data\PawnExtensions.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="WhoringTab\WhoringPolicyUIUtility.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="WhoringTab\PawnColumnCheckbox_Whore.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="WhoringTab\PawnColumnWorker_AverageMoneyByWhore.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="WhoringTab\PawnColumnWorker_CountOfWhore.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="WhoringTab\PawnColumnWorker_EarnedMoneyByWhore.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="WhoringTab\PawnColumnWorker_IsWhore.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="WhoringTab\PawnColumnWorker_Mood.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="WhoringTab\PawnColumnWorker_PriceRangeOfWhore.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="WhoringTab\PawnColumnWorker_TextCenter.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="WhoringTab\PawnColumnWorker_WhoreExperience.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="WhoringTab\PawnColumnWorker_WhoringPolicy.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="WhoringTab\PawnTable_Whores.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="WhoringTab\WhoreCheckbox.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="ThinkTreeNodes\ThinkNode_ChancePerHour_Whore.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="ThinkTreeNodes\ThinkNode_ConditionalWhore.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="Thoughts\ThoughtWorker_Whore.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="DefOf\ThoughtDefOf.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="WhoringBase.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="Whoring_Bed_Utilities.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="Whoring_Helper.cs" />
 | 
				
			||||||
 | 
					  </ItemGroup>
 | 
				
			||||||
 | 
					  <ItemGroup>
 | 
				
			||||||
 | 
					    <None Include="packages.config" />
 | 
				
			||||||
 | 
					  </ItemGroup>
 | 
				
			||||||
 | 
					  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
 | 
				
			||||||
 | 
					</Project>
 | 
				
			||||||
							
								
								
									
										71
									
								
								1.5/Source/Mod/WhoringBase.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,71 @@
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using HugsLib;
 | 
				
			||||||
 | 
					using HugsLib.Settings;
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public class WhoringBase : ModBase
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							public override string ModIdentifier
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								get
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return "RJW_Whoring";
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static DataStore DataStore;//reference to savegame data, hopefully
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public override void SettingsChanged()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								//ToggleTabIfNeeded();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							public override void WorldLoaded()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								DataStore = Find.World.GetComponent<DataStore>();
 | 
				
			||||||
 | 
								//ToggleTabIfNeeded();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private void ToggleTabIfNeeded()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								//DefDatabase<MainButtonDef>.GetNamed("RJW_Brothel").buttonVisible = whoringtab_enabled;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							//public static SettingHandle<bool> whoringtab_enabled;
 | 
				
			||||||
 | 
							public static SettingHandle<bool> show_whore_price_factor_on_bed;
 | 
				
			||||||
 | 
							public static SettingHandle<bool> show_whore_widgets_on_bed;
 | 
				
			||||||
 | 
							public static SettingHandle<bool> DebugWhoring;
 | 
				
			||||||
 | 
							public static SettingHandle<bool> MoneyPrinting;
 | 
				
			||||||
 | 
							public static SettingHandle<bool> ClientAlwaysAccept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public override void DefsLoaded()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								//whoringtab_enabled = Settings.GetHandle("whoringtab_enabled",
 | 
				
			||||||
 | 
								//						"whoringtab_enabled".Translate(),
 | 
				
			||||||
 | 
								//						"whoringtab_enabled_desc".Translate(),
 | 
				
			||||||
 | 
								//						true);
 | 
				
			||||||
 | 
								show_whore_price_factor_on_bed = Settings.GetHandle("show_whore_price_factor_on_bed",
 | 
				
			||||||
 | 
														"show_whore_price_factor_on_bed".Translate(),
 | 
				
			||||||
 | 
														"show_whore_price_factor_on_bed_desc".Translate(),
 | 
				
			||||||
 | 
														false);
 | 
				
			||||||
 | 
								show_whore_widgets_on_bed = Settings.GetHandle("show_whore_widgets_on_bed",
 | 
				
			||||||
 | 
														"show_whore_widgets_on_bed".Translate(),
 | 
				
			||||||
 | 
														"show_whore_widgets_on_bed_desc".Translate(),
 | 
				
			||||||
 | 
														false);
 | 
				
			||||||
 | 
								MoneyPrinting = Settings.GetHandle("MoneyPrinting",
 | 
				
			||||||
 | 
														"MoneyPrinting".Translate(),
 | 
				
			||||||
 | 
														"MoneyPrinting_desc".Translate(),
 | 
				
			||||||
 | 
														false);
 | 
				
			||||||
 | 
								ClientAlwaysAccept = Settings.GetHandle("ClientAlwaysAccept",
 | 
				
			||||||
 | 
														"ClientAlwaysAccept".Translate(),
 | 
				
			||||||
 | 
														"ClientAlwaysAccept_desc".Translate(),
 | 
				
			||||||
 | 
														false);
 | 
				
			||||||
 | 
								DebugWhoring = Settings.GetHandle("DebugWhoring",
 | 
				
			||||||
 | 
														"DebugWhoring".Translate(),
 | 
				
			||||||
 | 
														"DebugWhoring_desc".Translate(),
 | 
				
			||||||
 | 
														false);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										151
									
								
								1.5/Source/Mod/WhoringTab/PawnColumnCheckbox_Whore.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,151 @@
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					using UnityEngine;
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					using Verse.Sound;
 | 
				
			||||||
 | 
					using rjw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring.MainTab
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public abstract class PawnColumnCheckbox_Whore : PawnColumnWorker
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							public const int HorizontalPadding = 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public override void DoCell(Rect rect, Pawn pawn, PawnTable table)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (!this.HasCheckbox(pawn))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								int num = (int)((rect.width - 24f) / 2f);
 | 
				
			||||||
 | 
								int num2 = Mathf.Max(3, 0);
 | 
				
			||||||
 | 
								Vector2 vector = new Vector2(rect.x + (float)num, rect.y + (float)num2);
 | 
				
			||||||
 | 
								Rect rect2 = new Rect(vector.x, vector.y, 24f, 24f);
 | 
				
			||||||
 | 
								if (Find.TickManager.TicksGame % 60 == 0)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									pawn.UpdatePermissions();
 | 
				
			||||||
 | 
									//Log.Message("GetDisabled UpdateCanDesignateService for " + xxx.get_pawnname(pawn));
 | 
				
			||||||
 | 
									//Log.Message("UpdateCanDesignateService " + pawn.UpdateCanDesignateService());
 | 
				
			||||||
 | 
									//Log.Message("CanDesignateService " + pawn.CanDesignateService());
 | 
				
			||||||
 | 
									//Log.Message("GetDisabled " + GetDisabled(pawn));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								bool disabled = this.GetDisabled(pawn);
 | 
				
			||||||
 | 
								bool value;
 | 
				
			||||||
 | 
								if (disabled) 
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									value = false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else 
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									value = this.GetValue(pawn);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								bool flag = value;
 | 
				
			||||||
 | 
								Vector2 topLeft = vector;
 | 
				
			||||||
 | 
								WhoreCheckbox.Checkbox(topLeft, ref value, 24f, disabled, WhoreCheckbox.WhoreCheckboxOnTex, WhoreCheckbox.WhoreCheckboxOffTex, WhoreCheckbox.WhoreCheckboxDisabledTex);
 | 
				
			||||||
 | 
								if (Mouse.IsOver(rect2))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									string tip = this.GetTip(pawn);
 | 
				
			||||||
 | 
									if (!tip.NullOrEmpty())
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										TooltipHandler.TipRegion(rect2, tip);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (value != flag)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									this.SetValue(pawn, value);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public override int GetMinWidth(PawnTable table)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return Mathf.Max(base.GetMinWidth(table), 28);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public override int GetMaxWidth(PawnTable table)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return Mathf.Min(base.GetMaxWidth(table), this.GetMinWidth(table));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public override int GetMinCellHeight(Pawn pawn)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return Mathf.Max(base.GetMinCellHeight(pawn), 24);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public override int Compare(Pawn a, Pawn b)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return this.GetValueToCompare(a).CompareTo(this.GetValueToCompare(b));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private int GetValueToCompare(Pawn pawn)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (!this.HasCheckbox(pawn))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (!this.GetValue(pawn))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return 1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return 2;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected virtual string GetTip(Pawn pawn)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected virtual bool HasCheckbox(Pawn pawn)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected abstract bool GetValue(Pawn pawn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected abstract void SetValue(Pawn pawn, bool value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected abstract bool GetDisabled(Pawn pawn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected override void HeaderClicked(Rect headerRect, PawnTable table)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								base.HeaderClicked(headerRect, table);
 | 
				
			||||||
 | 
								if (Event.current.shift)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									List<Pawn> pawnsListForReading = table.PawnsListForReading;
 | 
				
			||||||
 | 
									for (int i = 0; i < pawnsListForReading.Count; i++)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										if (this.HasCheckbox(pawnsListForReading[i]))
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											if (Event.current.button == 0)
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												if (!this.GetValue(pawnsListForReading[i]))
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													this.SetValue(pawnsListForReading[i], true);
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											else if (Event.current.button == 1 && this.GetValue(pawnsListForReading[i]))
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												this.SetValue(pawnsListForReading[i], false);
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (Event.current.button == 0)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										SoundDefOf.Checkbox_TurnedOn.PlayOneShotOnCamera(null);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else if (Event.current.button == 1)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										SoundDefOf.Checkbox_TurnedOff.PlayOneShotOnCamera(null);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected override string GetHeaderTip(PawnTable table)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return base.GetHeaderTip(table) + "\n" + "CheckboxShiftClickTip".Translate();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,29 @@
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring.MainTab
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						[StaticConstructorOnStartup]
 | 
				
			||||||
 | 
						public class PawnColumnWorker_AverageMoneyByWhore : PawnColumnWorker_TextCenter
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							protected override string GetTextFor(Pawn pawn)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return ((int)GetValueToCompare(pawn)).ToString();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public override int Compare(Pawn a, Pawn b)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return GetValueToCompare(a).CompareTo(GetValueToCompare(b));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private float GetValueToCompare(Pawn pawn)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								float total = pawn.records.GetValue(RecordDefOf.EarnedMoneyByWhore);
 | 
				
			||||||
 | 
								float count = pawn.records.GetValue(RecordDefOf.CountOfWhore);
 | 
				
			||||||
 | 
								if ((int)count == 0)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return (total / count);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										23
									
								
								1.5/Source/Mod/WhoringTab/PawnColumnWorker_CountOfWhore.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,23 @@
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring.MainTab
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						[StaticConstructorOnStartup]
 | 
				
			||||||
 | 
						public class PawnColumnWorker_CountOfWhore : PawnColumnWorker_TextCenter
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							protected override string GetTextFor(Pawn pawn)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return GetValueToCompare(pawn).ToString();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public override int Compare(Pawn a, Pawn b)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return GetValueToCompare(a).CompareTo(GetValueToCompare(b));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private int GetValueToCompare(Pawn pawn)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return pawn.records.GetAsInt(RecordDefOf.CountOfWhore);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,23 @@
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring.MainTab
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						[StaticConstructorOnStartup]
 | 
				
			||||||
 | 
						public class PawnColumnWorker_EarnedMoneyByWhore : PawnColumnWorker_TextCenter
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							protected override string GetTextFor(Pawn pawn)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return GetValueToCompare(pawn).ToString();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public override int Compare(Pawn a, Pawn b)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return GetValueToCompare(a).CompareTo(GetValueToCompare(b));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private int GetValueToCompare(Pawn pawn)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return pawn.records.GetAsInt(RecordDefOf.EarnedMoneyByWhore);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										40
									
								
								1.5/Source/Mod/WhoringTab/PawnColumnWorker_IsWhore.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,40 @@
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					using RimWorld.Planet;
 | 
				
			||||||
 | 
					using rjw;
 | 
				
			||||||
 | 
					using UnityEngine;
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring.MainTab
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						[StaticConstructorOnStartup]
 | 
				
			||||||
 | 
						public class PawnColumnWorker_IsWhore : PawnColumnCheckbox_Whore
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							protected override bool GetDisabled(Pawn pawn)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return !pawn.CanDesignateService();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected override bool GetValue(Pawn pawn)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return pawn.IsDesignatedService() && xxx.is_human(pawn);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected override void SetValue(Pawn pawn, bool value)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (value == this.GetValue(pawn)) return;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								pawn.ToggleService();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							private static readonly Texture2D serviceOn = ContentFinder<Texture2D>.Get("UI/Tab/Service_on");
 | 
				
			||||||
 | 
							private static readonly Texture2D serviceOff = ContentFinder<Texture2D>.Get("UI/Tab/Service_off");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected override Texture2D GetIconFor(Pawn pawn)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return pawn.IsDesignatedService() ? serviceOn : null;
 | 
				
			||||||
 | 
							}*/
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										29
									
								
								1.5/Source/Mod/WhoringTab/PawnColumnWorker_Mood.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,29 @@
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					using RimWorld.Planet;
 | 
				
			||||||
 | 
					using UnityEngine;
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring.MainTab
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						[StaticConstructorOnStartup]
 | 
				
			||||||
 | 
						public class PawnColumnWorker_Mood : PawnColumnWorker_TextCenter
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							protected override string GetTextFor(Pawn pawn)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return GetValueToCompare(pawn).ToStringPercent();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public override int Compare(Pawn a, Pawn b)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return GetValueToCompare(a).CompareTo(GetValueToCompare(b));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private float GetValueToCompare(Pawn pawn)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return pawn.needs.mood.CurLevelPercentage;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,70 @@
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					using RimWorld.Planet;
 | 
				
			||||||
 | 
					using UnityEngine;
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring.MainTab
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						[StaticConstructorOnStartup]
 | 
				
			||||||
 | 
						public class PawnColumnWorker_PriceRangeOfWhore : PawnColumnWorker_TextCenter
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							protected internal int min;
 | 
				
			||||||
 | 
							protected internal int max;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected override string GetTextFor(Pawn 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);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public override int Compare(Pawn a, Pawn b)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return GetValueToCompare(a).CompareTo(GetValueToCompare(b));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected override string GetTip(Pawn pawn)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								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)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return min;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										33
									
								
								1.5/Source/Mod/WhoringTab/PawnColumnWorker_TextCenter.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,33 @@
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					using RimWorld.Planet;
 | 
				
			||||||
 | 
					using UnityEngine;
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring.MainTab
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public abstract class PawnColumnWorker_TextCenter : PawnColumnWorker_Text
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							public override void DoCell(Rect rect, Pawn pawn, PawnTable table)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Rect rect2 = new Rect(rect.x, rect.y, rect.width, Mathf.Min(rect.height, 30f));
 | 
				
			||||||
 | 
								string textFor = GetTextFor(pawn);
 | 
				
			||||||
 | 
								if (textFor != null)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Text.Font = GameFont.Small;
 | 
				
			||||||
 | 
									Text.Anchor = TextAnchor.MiddleCenter;
 | 
				
			||||||
 | 
									Text.WordWrap = false;
 | 
				
			||||||
 | 
									Widgets.Label(rect2, textFor);
 | 
				
			||||||
 | 
									Text.WordWrap = true;
 | 
				
			||||||
 | 
									Text.Anchor = TextAnchor.UpperLeft;
 | 
				
			||||||
 | 
									string tip = GetTip(pawn);
 | 
				
			||||||
 | 
									if (!tip.NullOrEmpty())
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										TooltipHandler.TipRegion(rect2, tip);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring.MainTab
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						[StaticConstructorOnStartup]
 | 
				
			||||||
 | 
						public class PawnColumnWorker_WhoreExperience : PawnColumnWorker_TextCenter
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							public static readonly HashSet<string> backstories = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("WhoreBackstories").strings);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected override string GetTextFor(Pawn pawn)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								int b = backstories.Contains(pawn.story?.Adulthood?.titleShort) ? 30 : 0;
 | 
				
			||||||
 | 
								int score = pawn.records.GetAsInt(RecordDefOf.CountOfWhore);
 | 
				
			||||||
 | 
								return (score + b).ToString();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										23
									
								
								1.5/Source/Mod/WhoringTab/PawnColumnWorker_WhoringPolicy.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -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);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										33
									
								
								1.5/Source/Mod/WhoringTab/PawnTable_Whores.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,33 @@
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					using rjw;
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring.MainTab
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public class PawnTable_Whores : PawnTable_PlayerPawns
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							public PawnTable_Whores(PawnTableDef def, Func<IEnumerable<Pawn>> pawnsGetter, int uiWidth, int uiHeight) : base(def, pawnsGetter, uiWidth, uiHeight) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							//default sorting
 | 
				
			||||||
 | 
							protected override IEnumerable<Pawn> LabelSortFunction(IEnumerable<Pawn> input)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								//return input.OrderBy(p => p.Name);
 | 
				
			||||||
 | 
								foreach (Pawn p in input)
 | 
				
			||||||
 | 
									p.UpdatePermissions();
 | 
				
			||||||
 | 
								return input.OrderByDescending(p => (p.IsPrisonerOfColony || p.IsSlaveOfColony) != false).ThenBy(p => xxx.get_pawnname(p));
 | 
				
			||||||
 | 
								//return input.OrderByDescending(p => (p.IsPrisonerOfColony || p.IsSlaveOfColony) != false).ThenBy(p => (p.Name.ToStringShort.Colorize(Color.yellow)));
 | 
				
			||||||
 | 
								//return input.OrderBy(p => xxx.get_pawnname(p));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected override IEnumerable<Pawn> PrimarySortFunction(IEnumerable<Pawn> input)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								foreach (Pawn p in input)
 | 
				
			||||||
 | 
									p.UpdatePermissions();
 | 
				
			||||||
 | 
								return input;
 | 
				
			||||||
 | 
								//return base.PrimarySortFunction(input);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										86
									
								
								1.5/Source/Mod/WhoringTab/WhoreCheckbox.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,86 @@
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					using UnityEngine;
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					using Verse.Sound;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring.MainTab
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						[StaticConstructorOnStartup]
 | 
				
			||||||
 | 
						public static class WhoreCheckbox
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							public static readonly Texture2D WhoreCheckboxOnTex = ContentFinder<Texture2D>.Get("UI/Commands/Service_on");
 | 
				
			||||||
 | 
							public static readonly Texture2D WhoreCheckboxOffTex = ContentFinder<Texture2D>.Get("UI/Commands/Service_off");
 | 
				
			||||||
 | 
							public static readonly Texture2D WhoreCheckboxDisabledTex = ContentFinder<Texture2D>.Get("UI/Commands/Service_Refuse");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private static bool checkboxPainting;
 | 
				
			||||||
 | 
							private static bool checkboxPaintingState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static void Checkbox(Vector2 topLeft, ref bool checkOn, float size = 24f, bool disabled = false, Texture2D texChecked = null, Texture2D texUnchecked = null, Texture2D texDisabled = null)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								WhoreCheckbox.Checkbox(topLeft.x, topLeft.y, ref checkOn, size, disabled, texChecked, texUnchecked);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static void Checkbox(float x, float y, ref bool checkOn, float size = 24f, bool disabled = false, Texture2D texChecked = null, Texture2D texUnchecked = null, Texture2D texDisabled = null)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Rect rect = new Rect(x, y, size, size);
 | 
				
			||||||
 | 
								WhoreCheckbox.CheckboxDraw(x, y, checkOn, disabled, size, texChecked, texUnchecked,texDisabled);
 | 
				
			||||||
 | 
								if (!disabled)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									MouseoverSounds.DoRegion(rect);
 | 
				
			||||||
 | 
									bool flag = false;
 | 
				
			||||||
 | 
									Widgets.DraggableResult draggableResult = Widgets.ButtonInvisibleDraggable(rect, false);
 | 
				
			||||||
 | 
									if (draggableResult == Widgets.DraggableResult.Pressed)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										checkOn = !checkOn;
 | 
				
			||||||
 | 
										flag = true;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else if (draggableResult == Widgets.DraggableResult.Dragged)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										checkOn = !checkOn;
 | 
				
			||||||
 | 
										flag = true;
 | 
				
			||||||
 | 
										WhoreCheckbox.checkboxPainting = true;
 | 
				
			||||||
 | 
										WhoreCheckbox.checkboxPaintingState = checkOn;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (Mouse.IsOver(rect) && WhoreCheckbox.checkboxPainting && Input.GetMouseButton(0) && checkOn != WhoreCheckbox.checkboxPaintingState)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										checkOn = WhoreCheckbox.checkboxPaintingState;
 | 
				
			||||||
 | 
										flag = true;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (flag)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										if (checkOn)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											SoundDefOf.Checkbox_TurnedOn.PlayOneShotOnCamera(null);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										else
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											SoundDefOf.Checkbox_TurnedOff.PlayOneShotOnCamera(null);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private static void CheckboxDraw(float x, float y, bool active, bool disabled, float size = 24f, Texture2D texChecked = null, Texture2D texUnchecked = null, Texture2D texDisabled = null)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Texture2D image;
 | 
				
			||||||
 | 
								if (disabled)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									image = ((!(texDisabled != null)) ? WhoreCheckbox.WhoreCheckboxDisabledTex : texDisabled);
 | 
				
			||||||
 | 
								} 
 | 
				
			||||||
 | 
								else if (active)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									image = ((!(texChecked != null)) ? WhoreCheckbox.WhoreCheckboxOnTex : texChecked);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									image = ((!(texUnchecked != null)) ? WhoreCheckbox.WhoreCheckboxOffTex : texUnchecked);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								Rect position = new Rect(x, y, size, size);
 | 
				
			||||||
 | 
								GUI.DrawTexture(position, image);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										45
									
								
								1.5/Source/Mod/WhoringTab/WhoringPolicyUIUtility.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -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<Widgets.DropdownMenuElement<Enum>> Button_GenerateMenu(Pawn pawn)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								foreach (WhoringData.WhoringType option in Enum.GetValues(typeof(WhoringData.WhoringType)))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									yield return new Widgets.DropdownMenuElement<Enum>
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										option = new FloatMenuOption(option.ToString(), delegate
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											pawn.WhoringData().WhoringPolicy = option;
 | 
				
			||||||
 | 
										}),
 | 
				
			||||||
 | 
										payload = option
 | 
				
			||||||
 | 
									};
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										381
									
								
								1.5/Source/Mod/Whoring_Bed_Utilities.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,381 @@
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					using Verse.AI;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using UnityEngine;
 | 
				
			||||||
 | 
					using rjw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public static class WhoreBed_Utility
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							public static readonly RoomRoleDef roleDefBrothel = DefDatabase<RoomRoleDef>.GetNamed("Brothel");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// find the best bed for a customer; whore is needed as parameter to only select beds that are reachable
 | 
				
			||||||
 | 
							public static Building_Bed FindBed(Pawn whore, Pawn customer)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								List<Building_Bed> b = FindReachableAndAvailableWhoreBeds(whore, customer);
 | 
				
			||||||
 | 
								return GetBestBedForCustomer(customer, b);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							public static bool CanUseForWhoring(Pawn pawn, Building_Bed bed)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								bool flag = bed.IsAvailableForWhoring(pawn) && pawn.CanReserveAndReach(bed, PathEndMode.InteractionCell, Danger.Unspecified) && !bed.IsForbidden(pawn);
 | 
				
			||||||
 | 
								return flag;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static Building_Bed GetBestBedForCustomer(Pawn customer, List<Building_Bed> beds)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (beds != null && beds.Any())
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return beds.MaxBy(bed => CalculateBedScore(customer, bed));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return null;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							public static float GetCheapestBedFactor(Pawn whore, Pawn customer)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								List<Building_Bed> beds = FindReachableAndAvailableWhoreBeds(whore, customer);
 | 
				
			||||||
 | 
								return GetCheapestBedFactor(beds);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							public static float GetCheapestBedFactor(List<Building_Bed> beds)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (beds != null && beds.Any())
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return CalculatePriceFactor(beds.MinBy(bed => CalculatePriceFactor(bed)));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return 0f;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// unused
 | 
				
			||||||
 | 
							/*public static float GetMostExpensiveBedFactor(List<Building_Bed> beds)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (beds != null && beds.Any())
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return CalculatePriceFactor(beds.MaxBy(bed => CalculatePriceFactor(bed)));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return 0f;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}//*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static float CalculateRoomFactor(Room room, int num_humanlike_beds)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (room == null || room.Role == RoomRoleDefOf.None || room.OutdoorsForWork)
 | 
				
			||||||
 | 
									return 0.1f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								float room_multiplier = 1f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (room.Role == roleDefBrothel)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									room_multiplier *= (float)Math.Pow(0.8, num_humanlike_beds - 1);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else // if(room.Role == RoomRoleDefOf.Barracks)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									room_multiplier /= 2 * (num_humanlike_beds - 1) + 1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								int scoreStageIndex = RoomStatDefOf.Impressiveness.GetScoreStageIndex(room.GetStat(RoomStatDefOf.Impressiveness));
 | 
				
			||||||
 | 
								//Room impressiveness factor
 | 
				
			||||||
 | 
								//0 < scoreStageIndex < 10 (Last time checked)
 | 
				
			||||||
 | 
								//3 is mediocore
 | 
				
			||||||
 | 
								room_multiplier *= (float)(scoreStageIndex <= 3 ? .4f + scoreStageIndex * .2f : 1f + .3f * (scoreStageIndex - 3));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return Mathf.Max(room_multiplier, 0);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static float CalculateBedFactorsForRoom(Room room, Building_Bed except_this_bed = null)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								float room_factor = 0.1f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (room == null)
 | 
				
			||||||
 | 
									return room_factor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// get eligible beds
 | 
				
			||||||
 | 
								IEnumerable<Building_Bed> humanlike_beds = room.ContainedBeds.Where(b => b.def.building.bed_humanlike);
 | 
				
			||||||
 | 
								int num_humanlike_beds = humanlike_beds.Count();
 | 
				
			||||||
 | 
								if (num_humanlike_beds <= 0)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return room_factor;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								IEnumerable<Building_Bed> whoring_beds = humanlike_beds.Where(b => b.IsAllowedForWhoringOwner());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (whoring_beds.Any())
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									// if beds exist, calculate room score
 | 
				
			||||||
 | 
									room_factor = CalculateRoomFactor(room, num_humanlike_beds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// and update all beds
 | 
				
			||||||
 | 
									foreach (Building_Bed b in whoring_beds)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										// except the bed given as parameter (will be calculated in that bed's function)
 | 
				
			||||||
 | 
										if (except_this_bed == null || b.thingIDNumber != except_this_bed.thingIDNumber)
 | 
				
			||||||
 | 
											CalculatePriceFactor(b, room_factor);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return room_factor;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static void ResetTicksUntilUpdate(Room room)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								IEnumerable<Building_Bed> whoring_beds = room.ContainedBeds.Where(b => b.IsAllowedForWhoringOwner());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								foreach (Building_Bed bed in whoring_beds)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									// set all to 0
 | 
				
			||||||
 | 
									//	if one is needed, it updates all the other beds
 | 
				
			||||||
 | 
									//	if none is needed, it doesn't matter
 | 
				
			||||||
 | 
									// only setting one bed to update has the risk that a different bed's value is required that doesn't trigger an update
 | 
				
			||||||
 | 
									WhoringBase.DataStore.GetBedData(bed).scoreUpdateTickDelay = 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static float CalculatePriceFactor(Building_Bed bed, float room_multiplier = -1f)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								BedData saved_bed_data = WhoringBase.DataStore.GetBedData(bed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// cache result (no need for saving): if no result available, calculate; otherwise save tick at which it has been calculated.
 | 
				
			||||||
 | 
								// additional parameter "room_multiplier" to skip room analysis
 | 
				
			||||||
 | 
								if ((room_multiplier == -1 || room_multiplier >= 0 && room_multiplier == saved_bed_data.roomScore)
 | 
				
			||||||
 | 
									&& saved_bed_data.bedScore >= 0f
 | 
				
			||||||
 | 
									&& saved_bed_data.lastScoreUpdateTick >
 | 
				
			||||||
 | 
										GenTicks.TicksGame - saved_bed_data.scoreUpdateTickDelay)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (room_multiplier >= 0 && saved_bed_data.scoreUpdateTickDelay < 720)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										// if saved value is used due to unchanged room multiplier, increase recalc delay
 | 
				
			||||||
 | 
										saved_bed_data.scoreUpdateTickDelay += 60 + Rand.Int % 10;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									//Log.Message("[RJW] lastScoreUpdateTick: " + BukkakeBase.DataStore.GetBedData(bed).lastScoreUpdateTick.ToString() + " / TicksGame: "+ GenTicks.TicksGame.ToString());
 | 
				
			||||||
 | 
									return saved_bed_data.bedScore;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (room_multiplier < 0)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Room room = bed.Map != null && bed.Map.regionAndRoomUpdater.Enabled ? bed.GetRoom() : null;
 | 
				
			||||||
 | 
									room_multiplier = CalculateBedFactorsForRoom(room, bed);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// uncomfortable beds reduce price, comfortable beds make customers pay a tip
 | 
				
			||||||
 | 
								float comfort = bed.GetStatValue(StatDefOf.Comfort);
 | 
				
			||||||
 | 
								float price_factor = room_multiplier * comfort;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// delay recalculation if result is the same as before
 | 
				
			||||||
 | 
								// Rand.Int % 10 flattens the spike over time if many beds are toggled at once
 | 
				
			||||||
 | 
								if (price_factor == saved_bed_data.bedScore)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (saved_bed_data.scoreUpdateTickDelay < 720)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										// slowly increase recalculation delay to two seconds on speed 3
 | 
				
			||||||
 | 
										saved_bed_data.scoreUpdateTickDelay += 60 + Rand.Int % 10;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									// reset recalculation delay
 | 
				
			||||||
 | 
									saved_bed_data.scoreUpdateTickDelay = 60 + Rand.Int % 10;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// update bed data
 | 
				
			||||||
 | 
								saved_bed_data.lastScoreUpdateTick = GenTicks.TicksGame;
 | 
				
			||||||
 | 
								saved_bed_data.bedScore = price_factor;
 | 
				
			||||||
 | 
								saved_bed_data.roomScore = room_multiplier;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// this is quite spammy
 | 
				
			||||||
 | 
								//if (RJWSettings.DebugWhoring)
 | 
				
			||||||
 | 
								//	Log.Message("[RJW]CalculatePriceFactor for bed " + bed.thingIDNumber.ToString() + ": "
 | 
				
			||||||
 | 
								//		+ "room_multiplier (num beds, impressiveness) ("+room_multiplier.ToString() +") * "
 | 
				
			||||||
 | 
								//		+ "comfort (" + comfort.ToString() + ") = " + price_factor.ToString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return price_factor;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// customers would want the best bed
 | 
				
			||||||
 | 
							// TODO: price as factor, rebalance
 | 
				
			||||||
 | 
							public static float CalculateBedScore(Pawn customer, Building_Bed bed)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								float basePriceFactor = CalculatePriceFactor(bed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// ascetic pawns want the least impressive room
 | 
				
			||||||
 | 
								if (customer.story.traits.HasTrait(TraitDefOf.Ascetic))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									float comfort = bed.GetStatValue(StatDefOf.Comfort);
 | 
				
			||||||
 | 
									basePriceFactor = comfort * comfort / basePriceFactor; // inverse room effects - may be cheap, but should still be comfortable. ascetic isn't masochistic!
 | 
				
			||||||
 | 
									if (WhoringBase.DebugWhoring)
 | 
				
			||||||
 | 
										Log.Message("[RJW]CalculateBedScore - Customer is ascetic");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								basePriceFactor *= 200; // make a larger number for better distance scaling (and random effect)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// horny pawns are in a hurry and want a closer bed
 | 
				
			||||||
 | 
								int distance = 0;
 | 
				
			||||||
 | 
								if (xxx.is_hornyorfrustrated(customer))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									distance = (int)bed.Position.DistanceTo(customer.Position);
 | 
				
			||||||
 | 
									//if (RJWSettings.DebugWhoring)
 | 
				
			||||||
 | 
									//	Log.Message("[RJW]CalculateBedScore - Pawn is horny - distance = "+distance.ToString());
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								int random_factor = Rand.Int % 100;
 | 
				
			||||||
 | 
								float score = basePriceFactor - distance + random_factor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (WhoringBase.DebugWhoring)
 | 
				
			||||||
 | 
									Log.Message("[RJW]CalculateBedScore for bed " + bed.thingIDNumber.ToString() + ": "
 | 
				
			||||||
 | 
										+ "score from price (" + basePriceFactor.ToString() + ") "
 | 
				
			||||||
 | 
										+ "- distance (" + distance.ToString() + ") "
 | 
				
			||||||
 | 
										+ "+ randomness (" + random_factor.ToString() + ") "
 | 
				
			||||||
 | 
										+ "= " + score.ToString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return score;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static List<Building_Bed> FindReachableAndAvailableWhoreBeds(Pawn whore, Pawn customer)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								List<Building_Bed> wb = new List<Building_Bed>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								wb = whore.MapHeld.GetWhoreBeds().Where(bed =>
 | 
				
			||||||
 | 
									!bed.IsForbidden(whore) &&
 | 
				
			||||||
 | 
									!bed.IsForbidden(customer) &&
 | 
				
			||||||
 | 
									!bed.IsBurning() &&
 | 
				
			||||||
 | 
									bed.WhoringIsAllowedForPawn(whore) &&
 | 
				
			||||||
 | 
									bed.IsAvailableForWhoring(whore) &&
 | 
				
			||||||
 | 
									whore.CanReserveAndReach(bed, PathEndMode.OnCell, Danger.Unspecified) &&
 | 
				
			||||||
 | 
									customer.CanReach(bed, PathEndMode.OnCell, Danger.Some)
 | 
				
			||||||
 | 
									// TODO: price/affordable?
 | 
				
			||||||
 | 
									).ToList();
 | 
				
			||||||
 | 
								if (WhoringBase.DebugWhoring)
 | 
				
			||||||
 | 
									Log.Message("[RJW]FindReachableAndAvailableWhoreBeds - found " + wb.Count().ToString() + " beds");
 | 
				
			||||||
 | 
								return wb;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static IEnumerable<Building_Bed> GetWhoreBeds(this Map map, Area area = null)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (map == null) return new Building_Bed[0];
 | 
				
			||||||
 | 
								if (area == null) return map.listerBuildings.AllBuildingsColonistOfClass<Building_Bed>();
 | 
				
			||||||
 | 
								return map.listerBuildings.AllBuildingsColonistOfClass<Building_Bed>().Where(b => area[b.Position]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static bool WhoringIsAllowedForPawn(this Building_Bed bed, Pawn pawn)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (bed.IsAllowedForWhoringAll())
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								if (bed == pawn.ownership.OwnedBed && bed.IsAllowedForWhoringOwner())
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static void SetAllowedForWhoringOwner(this Building_Bed bed, bool isAllowed)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (!isAllowed)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									// if whoring is disallowed for owner, also disallow for all
 | 
				
			||||||
 | 
									bed.SetAllowedForWhoringAll(false);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								WhoringBase.DataStore.GetBedData(bed).allowedForWhoringOwner = isAllowed;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							public static void ToggleAllowedForWhoringOwner(this Building_Bed bed)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								bed.SetAllowedForWhoringOwner(!WhoringBase.DataStore.GetBedData(bed).allowedForWhoringOwner);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							public static bool IsAllowedForWhoringOwner(this Building_Bed bed)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (!bed.def.building.bed_humanlike ||
 | 
				
			||||||
 | 
									bed.Faction != Faction.OfPlayerSilentFail ||
 | 
				
			||||||
 | 
									bed.Medical ||
 | 
				
			||||||
 | 
									bed.def.defName.Contains("Guest") ||
 | 
				
			||||||
 | 
									bed.def.defName.Contains("Android") )
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (bed.ForPrisoners)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									// no toggle on prisoner beds, they may always use their own bed (if they are supposed to whore, anyway)
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return WhoringBase.DataStore.GetBedData(bed).allowedForWhoringOwner;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static void SetAllowedForWhoringAll(this Building_Bed bed, bool isAllowed)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (isAllowed)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									// if whoring is allowed for all, also visibly allow for owner
 | 
				
			||||||
 | 
									bed.SetAllowedForWhoringOwner(true);
 | 
				
			||||||
 | 
									// if bed is designated for whoring, disable prisoner/medical use
 | 
				
			||||||
 | 
									bed.ForPrisoners = false;
 | 
				
			||||||
 | 
									bed.Medical = false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								WhoringBase.DataStore.GetBedData(bed).allowedForWhoringAll = isAllowed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								bed.GetRoom()?.Notify_BedTypeChanged();
 | 
				
			||||||
 | 
								bed.Notify_ColorChanged();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							public static void ToggleAllowedForWhoringAll(this Building_Bed bed)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								bed.SetAllowedForWhoringAll(!WhoringBase.DataStore.GetBedData(bed).allowedForWhoringAll);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							public static bool IsAllowedForWhoringAll(this Building_Bed bed)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (WhoringBase.DataStore.GetBedData(bed).allowedForWhoringAll)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (!bed.def.building.bed_humanlike ||
 | 
				
			||||||
 | 
										bed.Faction != Faction.OfPlayerSilentFail ||
 | 
				
			||||||
 | 
										bed.Medical ||
 | 
				
			||||||
 | 
										bed.ForPrisoners ||
 | 
				
			||||||
 | 
										bed.def.defName.Contains("Guest") ||
 | 
				
			||||||
 | 
										bed.def.defName.Contains("Android")  ||
 | 
				
			||||||
 | 
										bed.GetRoom()?.IsPrisonCell == true)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										return false;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static void ReserveForWhoring(this Building_Bed bed, Pawn p, int num_ticks)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								WhoringBase.DataStore.GetBedData(bed).reservedUntilGameTick = GenTicks.TicksGame + num_ticks;
 | 
				
			||||||
 | 
								WhoringBase.DataStore.GetBedData(bed).reservedForPawnID = p.thingIDNumber;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							public static void UnreserveForWhoring(this Building_Bed bed)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								WhoringBase.DataStore.GetBedData(bed).reservedUntilGameTick = 0;
 | 
				
			||||||
 | 
								WhoringBase.DataStore.GetBedData(bed).reservedForPawnID = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							public static bool IsAvailableForWhoring(this Building_Bed bed, Pawn p)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// check for active reservation
 | 
				
			||||||
 | 
								if (WhoringBase.DataStore.GetBedData(bed).reservedUntilGameTick > GenTicks.TicksGame)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (WhoringBase.DataStore.GetBedData(bed).reservedForPawnID != p.thingIDNumber)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										// a different pawn has reserved this bed
 | 
				
			||||||
 | 
										return false;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (bed.OwnersForReading.Any())
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									for (int i = 0; i < bed.OwnersForReading.Count; i++)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										if (bed.OwnersForReading[i].InBed() && bed.OwnersForReading[i].CurrentBed() == bed)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											// someone sleeping in this bed
 | 
				
			||||||
 | 
											return false;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										440
									
								
								1.5/Source/Mod/Whoring_Helper.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,440 @@
 | 
				
			||||||
 | 
					// #define TESTMODE // Uncomment to enable logging.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using UnityEngine;
 | 
				
			||||||
 | 
					using Verse.AI.Group;
 | 
				
			||||||
 | 
					//using Multiplayer.API;
 | 
				
			||||||
 | 
					using rjw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/// <summary>
 | 
				
			||||||
 | 
						/// Helper for whoring related stuff
 | 
				
			||||||
 | 
						/// </summary>
 | 
				
			||||||
 | 
						public class WhoringHelper
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							public const float baseMinPrice = 10f;
 | 
				
			||||||
 | 
							public const float baseMaxPrice = 20f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static readonly HashSet<string> backstories = new HashSet<string>(DefDatabase<StringListDef>.GetNamed("WhoreBackstories").strings);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static int WhoreMinPrice(Pawn whore)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								float min_price = baseMinPrice;
 | 
				
			||||||
 | 
								min_price *= WhoreAgeAdjustment(whore);
 | 
				
			||||||
 | 
								min_price *= WhoreGenderAdjustment(whore);
 | 
				
			||||||
 | 
								min_price *= WhoreInjuryAdjustment(whore);
 | 
				
			||||||
 | 
								min_price *= WhoreAbilityAdjustmentMin(whore);
 | 
				
			||||||
 | 
								//min_price *= WhoreRoomAdjustment(whore);
 | 
				
			||||||
 | 
								if (xxx.has_traits(whore))
 | 
				
			||||||
 | 
									min_price *= WhoreTraitAdjustmentMin(whore);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return (int)min_price;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static int WhoreMaxPrice(Pawn whore)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								float max_price = baseMaxPrice;
 | 
				
			||||||
 | 
								max_price *= WhoreAgeAdjustment(whore);
 | 
				
			||||||
 | 
								max_price *= WhoreGenderAdjustment(whore);
 | 
				
			||||||
 | 
								max_price *= WhoreInjuryAdjustment(whore);
 | 
				
			||||||
 | 
								max_price *= WhoreAbilityAdjustmentMax(whore);
 | 
				
			||||||
 | 
								//max_price *= WhoreRoomAdjustment(whore);
 | 
				
			||||||
 | 
								if (xxx.has_traits(whore))
 | 
				
			||||||
 | 
									max_price *= WhoreTraitAdjustmentMax(whore);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return (int)max_price;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static float WhoreGenderAdjustment(Pawn whore)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (GenderHelper.GetSex(whore) == GenderHelper.Sex.futa)
 | 
				
			||||||
 | 
									return 1.2f;
 | 
				
			||||||
 | 
								return 1f;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static float WhoreAgeAdjustment(Pawn whore)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return AgeConfigDef.Instance.whoringPriceByAge.Evaluate(SexUtility.ScaleToHumanAge(whore));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static float WhoreInjuryAdjustment(Pawn whore)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								float modifier = 1.0f;
 | 
				
			||||||
 | 
								int injuries = whore.health.hediffSet.hediffs.Count(x => x.Visible && x.def.everCurableByItem && x.IsPermanent());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (injuries == 0) return modifier;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								while (injuries > 0)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									modifier *= 0.85f;
 | 
				
			||||||
 | 
									injuries--;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return modifier;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static float WhoreAbilityAdjustmentMin(Pawn whore)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								int b = backstories.Contains(whore.story?.Adulthood?.titleShort) ? 30 : 0;
 | 
				
			||||||
 | 
								int score = whore.records.GetAsInt(RecordDefOf.EarnedMoneyByWhore);
 | 
				
			||||||
 | 
								float multiplier = (score + b) / 100;
 | 
				
			||||||
 | 
								multiplier = Math.Min(multiplier, 2);
 | 
				
			||||||
 | 
								multiplier = (multiplier - 0.5f) * 0.5f + 1;
 | 
				
			||||||
 | 
								return multiplier;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static float WhoreAbilityAdjustmentMax(Pawn whore)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								int b = backstories.Contains(whore.story?.Adulthood?.titleShort) ? 30 : 0;
 | 
				
			||||||
 | 
								int score = whore.records.GetAsInt(RecordDefOf.CountOfWhore);
 | 
				
			||||||
 | 
								float multiplier = (score + b) / 100;
 | 
				
			||||||
 | 
								multiplier = Math.Min(multiplier, 2);
 | 
				
			||||||
 | 
								multiplier = (multiplier - 0.5f) * 0.5f + 1;
 | 
				
			||||||
 | 
								return multiplier;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static float WhoreTraitAdjustmentMin(Pawn whore)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								float multiplier = WhoreTraitAdjustment(whore);
 | 
				
			||||||
 | 
								if (xxx.is_masochist(whore)) // Won't haggle, may settle for low price
 | 
				
			||||||
 | 
									multiplier *= 0.7f;
 | 
				
			||||||
 | 
								if (xxx.is_nympho(whore)) // Same as above
 | 
				
			||||||
 | 
									multiplier *= 0.4f;
 | 
				
			||||||
 | 
								if (whore.story.traits.HasTrait(TraitDefOf.Wimp)) // Same as above
 | 
				
			||||||
 | 
									multiplier *= 0.4f;
 | 
				
			||||||
 | 
								return multiplier;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static float WhoreTraitAdjustmentMax(Pawn whore)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								float multiplier = WhoreTraitAdjustment(whore);
 | 
				
			||||||
 | 
								if (xxx.IndividualityIsActive && whore.story.traits.HasTrait(xxx.SYR_Haggler))
 | 
				
			||||||
 | 
									multiplier *= 1.5f;
 | 
				
			||||||
 | 
								if (whore.story.traits.HasTrait(TraitDefOf.Greedy))
 | 
				
			||||||
 | 
									multiplier *= 2f;
 | 
				
			||||||
 | 
								return multiplier;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static float WhoreTraitAdjustment(Pawn whore)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								float multiplier = 1f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (xxx.has_traits(whore))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (whore.story.traits.DegreeOfTrait(TraitDefOf.Industriousness) == 2) // Industrious
 | 
				
			||||||
 | 
										multiplier *= 1.2f;
 | 
				
			||||||
 | 
									if (whore.story.traits.DegreeOfTrait(TraitDefOf.Industriousness) == 1) // Hard Worker
 | 
				
			||||||
 | 
										multiplier *= 1.1f;
 | 
				
			||||||
 | 
									if (whore.story.traits.HasTrait(TraitDefOf.CreepyBreathing))
 | 
				
			||||||
 | 
										multiplier *= 0.75f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (whore.GetStatValue(StatDefOf.PawnBeauty) >= 2)
 | 
				
			||||||
 | 
										multiplier *= 3.5f;
 | 
				
			||||||
 | 
									else if (whore.GetStatValue(StatDefOf.PawnBeauty) >= 1)
 | 
				
			||||||
 | 
										multiplier *= 2f;
 | 
				
			||||||
 | 
									else if (whore.GetStatValue(StatDefOf.PawnBeauty) < 0)
 | 
				
			||||||
 | 
										if (whore.GetStatValue(StatDefOf.PawnBeauty) >= -1)
 | 
				
			||||||
 | 
											multiplier *= 0.8f;
 | 
				
			||||||
 | 
										else
 | 
				
			||||||
 | 
											multiplier *= 0.6f;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return multiplier;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*public static float WhoreRoomAdjustment(Pawn whore)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								float room_multiplier = 1f;
 | 
				
			||||||
 | 
								Room ownedRoom = whore.ownership.OwnedRoom;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (ownedRoom == null) return 0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								//Room sharing is not liked by patrons
 | 
				
			||||||
 | 
								room_multiplier = room_multiplier / (2 * (ownedRoom.Owners.Count() - 1) + 1);
 | 
				
			||||||
 | 
								int scoreStageIndex = RoomStatDefOf.Impressiveness.GetScoreStageIndex(ownedRoom.GetStat(RoomStatDefOf.Impressiveness));
 | 
				
			||||||
 | 
								//Room impressiveness factor
 | 
				
			||||||
 | 
								//0 < scoreStageIndex < 10 (Last time checked)
 | 
				
			||||||
 | 
								//3 is mediocore
 | 
				
			||||||
 | 
								if (scoreStageIndex == 0)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									room_multiplier *= 0.3f;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else if (scoreStageIndex > 3)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									room_multiplier *= 1 + ((float)scoreStageIndex - 3) / 3.5f;
 | 
				
			||||||
 | 
								} //top room triples the price
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return room_multiplier;
 | 
				
			||||||
 | 
							}//*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							//[SyncMethod]
 | 
				
			||||||
 | 
							public static int PriceOfWhore(Pawn whore)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								float NeedSexFactor = xxx.is_hornyorfrustrated(whore) ? 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;
 | 
				
			||||||
 | 
								//--ModLog.Message(" xxx::PriceOfWhore - price is " + price);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return (int)Math.Round(price);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							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)}");
 | 
				
			||||||
 | 
								int price = priceOfWhore < 0 ? PriceOfWhore(whore) : priceOfWhore;
 | 
				
			||||||
 | 
								if (price == 0)
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// can customer afford the cheapest bed? - skip check, should rarely make a difference
 | 
				
			||||||
 | 
								//float bed_factor = WhoreBed_Utility.GetCheapestBedFactor(whore, targetPawn);
 | 
				
			||||||
 | 
								//price = (int)(price * bed_factor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								//if (RJWSettings.DebugWhoring) ModLog.Message($" whore price {price}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Lord lord = targetPawn.GetLord();
 | 
				
			||||||
 | 
								Faction faction = targetPawn.Faction;
 | 
				
			||||||
 | 
								int clientAmountOfSilvers = targetPawn.inventory.innerContainer.TotalStackCountOfDef(ThingDefOf.Silver);
 | 
				
			||||||
 | 
								int totalAmountOfSilvers = clientAmountOfSilvers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (faction != null)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									List<Pawn> caravanMembers = targetPawn.Map.mapPawns.PawnsInFaction(targetPawn.Faction).Where(x => x.GetLord() == lord && x.inventory?.innerContainer?.TotalStackCountOfDef(ThingDefOf.Silver) > 0).ToList();
 | 
				
			||||||
 | 
									if (!caravanMembers.Any())
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										//if (RJWSettings.DebugWhoring) ModLog.Message($" client not in caravan");
 | 
				
			||||||
 | 
										//if (RJWSettings.DebugWhoring) ModLog.Message("CanAfford::(" + xxx.get_pawnname(targetPawn) + "," + xxx.get_pawnname(whore) + ") - totalAmountOfSilvers is " + totalAmountOfSilvers);
 | 
				
			||||||
 | 
										return totalAmountOfSilvers >= price;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									totalAmountOfSilvers += caravanMembers.Sum(member => member.inventory.innerContainer.TotalStackCountOfDef(ThingDefOf.Silver));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								//if (RJWSettings.DebugWhoring) ModLog.Message($" client silver = {clientAmountOfSilvers} caravan silver = {totalAmountOfSilvers - clientAmountOfSilvers}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								//if (RJWSettings.DebugWhoring) ModLog.Message("CanAfford:: can afford the whore: " + (totalAmountOfSilvers >= price));
 | 
				
			||||||
 | 
								return totalAmountOfSilvers >= price;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							//priceOfWhore is assumed >=0, and targetPawn is assumed to be able to pay the price(either by caravan, or by himself)
 | 
				
			||||||
 | 
							//This means that targetPawn has total stackcount of silvers >= priceOfWhore.
 | 
				
			||||||
 | 
							public static int PayPriceToWhore(Pawn targetPawn, int priceOfWhore, Pawn whore)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (WhoringBase.DebugWhoring) ModLog.Message($"PayPriceToWhore for client {xxx.get_pawnname(targetPawn)}");
 | 
				
			||||||
 | 
								if (WhoringBase.MoneyPrinting)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									DebugThingPlaceHelper.DebugSpawn(ThingDefOf.Silver, whore.PositionHeld, priceOfWhore, false, null);
 | 
				
			||||||
 | 
									if (WhoringBase.DebugWhoring) ModLog.Message($" MoneyPrinting " + priceOfWhore + " silver to pay price");
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								int AmountLeft = priceOfWhore;
 | 
				
			||||||
 | 
								if ((targetPawn.Faction == whore.Faction && targetPawn.GuestStatus != GuestStatus.Guest) || priceOfWhore == 0)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (WhoringBase.DebugWhoring) ModLog.Message($" No need to pay price");
 | 
				
			||||||
 | 
									return AmountLeft;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								Lord lord = targetPawn.GetLord();
 | 
				
			||||||
 | 
								//Caravan guestCaravan = Find.WorldObjects.Caravans.Where(x => x.Spawned && x.ContainsPawn(targetPawn) && x.Faction == targetPawn.Faction && !x.IsPlayerControlled).FirstOrDefault();
 | 
				
			||||||
 | 
								List<Pawn> caravan = targetPawn.Map.mapPawns.PawnsInFaction(targetPawn.Faction).Where(x => x.GetLord() == lord && x.inventory?.innerContainer != null && x.inventory.innerContainer.TotalStackCountOfDef(ThingDefOf.Silver) > 0).ToList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								IEnumerable<Thing> TraderSilvers;
 | 
				
			||||||
 | 
								if (!caravan.Any())
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (WhoringBase.DebugWhoring) ModLog.Message($" (not a caravan member), try to pay with own silver");
 | 
				
			||||||
 | 
									TraderSilvers = targetPawn.inventory.innerContainer.Where(x => x.def == ThingDefOf.Silver);
 | 
				
			||||||
 | 
									foreach (Thing silver in TraderSilvers)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										if (AmountLeft <= 0)
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										int dropAmount = silver.stackCount >= AmountLeft ? AmountLeft : silver.stackCount;
 | 
				
			||||||
 | 
										if (targetPawn.inventory.innerContainer.TryDrop(silver, whore.Position, whore.Map, ThingPlaceMode.Near, dropAmount, out Thing resultingSilvers))
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											if (resultingSilvers is null)
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												if (WhoringBase.DebugWhoring) ModLog.Message($" have no silver");
 | 
				
			||||||
 | 
												continue;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											AmountLeft -= resultingSilvers.stackCount;
 | 
				
			||||||
 | 
											if (AmountLeft <= 0)
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												if (WhoringBase.DebugWhoring) ModLog.Message($" {xxx.get_pawnname(targetPawn)} paid {resultingSilvers.stackCount} silver");
 | 
				
			||||||
 | 
												break;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										else
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											if (WhoringBase.DebugWhoring) ModLog.Message($" TryDrop failed");
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (WhoringBase.DebugWhoring) ModLog.Message($" price: {priceOfWhore}, paid: {priceOfWhore - AmountLeft}");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (WhoringBase.DebugWhoring) ModLog.Message($" (caravan member), try to pay {AmountLeft} silver with caravan silver");
 | 
				
			||||||
 | 
									foreach (Pawn caravanMember in caravan)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										TraderSilvers = caravanMember.inventory.innerContainer.Where(x => x.def == ThingDefOf.Silver);
 | 
				
			||||||
 | 
										if (WhoringBase.DebugWhoring) ModLog.Message($" try to pay with {xxx.get_pawnname(caravanMember)} silver");
 | 
				
			||||||
 | 
										foreach (Thing silver in TraderSilvers)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											if (AmountLeft <= 0)
 | 
				
			||||||
 | 
												break;
 | 
				
			||||||
 | 
											int dropAmount = silver.stackCount >= AmountLeft ? AmountLeft : silver.stackCount;
 | 
				
			||||||
 | 
											if (caravanMember.inventory.innerContainer.TryDrop(silver, whore.Position, whore.Map, ThingPlaceMode.Near, dropAmount, out Thing resultingSilvers))
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												if (resultingSilvers is null)
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													if (WhoringBase.DebugWhoring) ModLog.Message($" have no silver");
 | 
				
			||||||
 | 
													continue;
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
												AmountLeft -= resultingSilvers.stackCount;
 | 
				
			||||||
 | 
												if (AmountLeft <= 0)
 | 
				
			||||||
 | 
												{
 | 
				
			||||||
 | 
													if (WhoringBase.DebugWhoring) ModLog.Message($" {xxx.get_pawnname(caravanMember)} paid {resultingSilvers.stackCount} silver");
 | 
				
			||||||
 | 
													break;
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (WhoringBase.DebugWhoring) ModLog.Message($" price: {priceOfWhore}, paid: {priceOfWhore - AmountLeft}");
 | 
				
			||||||
 | 
								return AmountLeft;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static int PayRespectToWhore(Pawn targetPawn, int priceOfWhore, Pawn whore)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (targetPawn.Faction == whore.Faction)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									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)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (PawnUtility.WillSoonHaveBasicNeed(target))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									//Log.Message("IsHookupAppealing - fail: " + xxx.get_pawnname(target) + " has need to do");
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (WhoringBase.ClientAlwaysAccept)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								float num = target.relations.SecondaryRomanceChanceFactor(whore) / 1.5f;
 | 
				
			||||||
 | 
								if (xxx.is_frustrated(target))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									num *= 3.0f;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else if (xxx.is_hornyorfrustrated(target))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									num *= 2.0f;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (xxx.is_zoophile(target) && !xxx.is_animal(whore))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									num *= 0.5f;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (xxx.AlienFrameworkIsActive)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (xxx.is_xenophile(target))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										if (target.def.defName == whore.def.defName)
 | 
				
			||||||
 | 
											num *= 0.5f; // Same species, xenophile less interested.
 | 
				
			||||||
 | 
										else
 | 
				
			||||||
 | 
											num *= 1.5f; // Different species, xenophile more interested.
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else if (xxx.is_xenophobe(target))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										if (target.def.defName != whore.def.defName)
 | 
				
			||||||
 | 
											num *= 0.25f; // Different species, xenophobe less interested.
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								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)); // 1 to 0 reduce score by negative opinion/relations to 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(when hooking colonists).
 | 
				
			||||||
 | 
							/// </summary>  
 | 
				
			||||||
 | 
							//[SyncMethod]
 | 
				
			||||||
 | 
							public static bool WillPawnTryHookup(Pawn target)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (WhoringBase.ClientAlwaysAccept)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (target.story.traits.HasTrait(TraitDefOf.Asexual))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								Pawn lover = LovePartnerRelationUtility.ExistingMostLikedLovePartner(target, false);
 | 
				
			||||||
 | 
								if (lover == null)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								float num = target.relations.OpinionOf(lover);
 | 
				
			||||||
 | 
								float num2 = Mathf.InverseLerp(30f, -80f, num);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (xxx.is_prude(target))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									num2 = 0f;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else if (xxx.is_lecher(target))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									//Lechers are always up for it.
 | 
				
			||||||
 | 
									num2 = Mathf.InverseLerp(100f, 50f, num);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else if (target.Map == lover.Map)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									//Less likely to cheat if the lover is on the same map.
 | 
				
			||||||
 | 
									num2 = Mathf.InverseLerp(70f, 15f, num);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								//else default values
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (xxx.is_frustrated(target))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									num2 *= 1.8f;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else if (xxx.is_hornyorfrustrated(target))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									num2 *= 1.4f;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								num2 /= 1.5f;
 | 
				
			||||||
 | 
								//Rand.PopState();
 | 
				
			||||||
 | 
								//Rand.PushState(RJW_Multiplayer.PredictableSeed());
 | 
				
			||||||
 | 
								return Rand.Range(0f, 1f) < num2;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/// <summary>
 | 
				
			||||||
 | 
							/// Updates records for whoring.
 | 
				
			||||||
 | 
							/// </summary>
 | 
				
			||||||
 | 
							public static void UpdateRecords(Pawn pawn, int price)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								pawn.records.AddTo(RecordDefOf.EarnedMoneyByWhore, price);
 | 
				
			||||||
 | 
								pawn.records.Increment(RecordDefOf.CountOfWhore);
 | 
				
			||||||
 | 
								//this is added by normal outcome
 | 
				
			||||||
 | 
								//pawn.records.Increment(CountOfSex);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										64
									
								
								1.5/Source/Mod/harmony_AftersexPatch.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,64 @@
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					using HarmonyLib;
 | 
				
			||||||
 | 
					using rjw;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						[HarmonyPatch(typeof(AfterSexUtility), "think_about_sex", new Type[] {typeof(Pawn), typeof(Pawn), typeof(bool), typeof(SexProps), typeof(bool)})]
 | 
				
			||||||
 | 
						[StaticConstructorOnStartup]
 | 
				
			||||||
 | 
						static class Aftersex_WhoringhoughtApply
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							[HarmonyPostfix]
 | 
				
			||||||
 | 
							private static void ThinkAboutWhoringPatch(Pawn pawn, Pawn partner, bool isReceiving, SexProps props, bool whoring = false)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								try
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									AfterSexUtilityPatch.ThinkAboutWhoring(pawn, partner, isReceiving, props, whoring);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								catch (Exception e)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Log.Error(e.ToString());
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} 
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static class AfterSexUtilityPatch
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							///<summary>
 | 
				
			||||||
 | 
							///add aftersex thoughts for whoring
 | 
				
			||||||
 | 
							///</summary>
 | 
				
			||||||
 | 
							public static void ThinkAboutWhoring(Pawn pawn, Pawn partner, bool isReceiving, SexProps props, bool whoring = false)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								//no whoring in vanilla sex
 | 
				
			||||||
 | 
								if (props.isCoreLovin)
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								//masturbation?
 | 
				
			||||||
 | 
								if (pawn == null || partner == null)
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								//necro
 | 
				
			||||||
 | 
								if (pawn.Dead || partner.Dead)
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								//bestiality
 | 
				
			||||||
 | 
								if (!(xxx.is_human(pawn) && xxx.is_human(partner)))
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								//whoring, initiator is whore
 | 
				
			||||||
 | 
								if (whoring && !props.isReceiver)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									ThoughtDef memory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (pawn.IsPrisoner || xxx.is_slave(pawn))
 | 
				
			||||||
 | 
										memory = ThoughtDefOf.Whorish_Thoughts_Captive;
 | 
				
			||||||
 | 
									else
 | 
				
			||||||
 | 
										memory = ThoughtDefOf.Whorish_Thoughts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									pawn.needs.mood.thoughts.memories.TryGainMemory(memory);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										322
									
								
								1.5/Source/Mod/harmony_Building_BedPatches.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,322 @@
 | 
				
			||||||
 | 
					using HarmonyLib;
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using UnityEngine;
 | 
				
			||||||
 | 
					using rjw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// patches Building_Bed to add stuff for WhoreBeds
 | 
				
			||||||
 | 
					/// 
 | 
				
			||||||
 | 
					/// 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) 
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public static class harmony_Building_BedPatches
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							private static readonly Color sheetColorForWhores = new Color(181 / 255f, 55 / 255f, 109 / 255f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Set color for whore beds
 | 
				
			||||||
 | 
							[HarmonyPatch(typeof(Building_Bed))]
 | 
				
			||||||
 | 
							[HarmonyPatch(nameof(Building_Bed.DrawColorTwo), MethodType.Getter)]
 | 
				
			||||||
 | 
							public static class Building_Bed_DrawColor_Patch
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								[HarmonyPostfix]
 | 
				
			||||||
 | 
								public static void Postfix(Building_Bed __instance, ref Color __result)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (__instance.IsAllowedForWhoringAll())
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										__result = sheetColorForWhores;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// add whoring toggles to beds
 | 
				
			||||||
 | 
							[HarmonyPatch(typeof(Building_Bed), nameof(Building_Bed.GetGizmos))]
 | 
				
			||||||
 | 
							public static class Building_Bed_GetGizmos_Patch
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								[HarmonyPostfix]
 | 
				
			||||||
 | 
								public static void Postfix(Building_Bed __instance, ref IEnumerable<Gizmo> __result)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (!WhoringBase.show_whore_widgets_on_bed)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										return;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									__result = Process(__instance, __result);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								private static IEnumerable<Gizmo> Process(Building_Bed __instance, IEnumerable<Gizmo> __result)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									var isPrisonCell = __instance.GetRoom()?.IsPrisonCell == true;
 | 
				
			||||||
 | 
									if (!__instance.ForPrisoners && 
 | 
				
			||||||
 | 
										!__instance.Medical && 
 | 
				
			||||||
 | 
										__instance.def.building.bed_humanlike && 
 | 
				
			||||||
 | 
										__instance.Faction == Faction.OfPlayerSilentFail && 
 | 
				
			||||||
 | 
										!__instance.def.defName.Contains("Guest") && 
 | 
				
			||||||
 | 
										!__instance.def.defName.Contains("Android") && 
 | 
				
			||||||
 | 
										!isPrisonCell)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										yield return
 | 
				
			||||||
 | 
											new Command_Toggle
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												defaultLabel = "CommandBedAllowWhoringLabel".Translate(),
 | 
				
			||||||
 | 
												defaultDesc = "CommandBedAllowWhoringDesc".Translate(),
 | 
				
			||||||
 | 
												icon = ContentFinder<Texture2D>.Get("UI/Commands/AsWhore"),
 | 
				
			||||||
 | 
												isActive = __instance.IsAllowedForWhoringOwner,
 | 
				
			||||||
 | 
												toggleAction = __instance.ToggleAllowedForWhoringOwner,
 | 
				
			||||||
 | 
												hotKey = KeyBindingDefOf.Misc5, // Guest Beds uses Misc4
 | 
				
			||||||
 | 
												Disabled = !__instance.def.HasAssignableCompFrom(typeof(CompAssignableToPawn_Bed)),
 | 
				
			||||||
 | 
												disabledReason = "This bed type is not assignable to pawns."
 | 
				
			||||||
 | 
											};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										yield return
 | 
				
			||||||
 | 
											new Command_Toggle
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												defaultLabel = "CommandBedSetAsWhoreBedLabel".Translate(),
 | 
				
			||||||
 | 
												defaultDesc = "CommandBedSetAsWhoreBedDesc".Translate(),
 | 
				
			||||||
 | 
												icon = ContentFinder<Texture2D>.Get("UI/Commands/AsWhoreMany"),
 | 
				
			||||||
 | 
												isActive = __instance.IsAllowedForWhoringAll,
 | 
				
			||||||
 | 
												toggleAction = __instance.ToggleAllowedForWhoringAll,
 | 
				
			||||||
 | 
												hotKey = KeyBindingDefOf.Misc6, // Guest Beds uses Misc4
 | 
				
			||||||
 | 
												Disabled = !__instance.def.HasAssignableCompFrom(typeof(CompAssignableToPawn_Bed)),
 | 
				
			||||||
 | 
												disabledReason = "This bed type is not assignable to pawns."
 | 
				
			||||||
 | 
											};
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									foreach (var gizmo in __result)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										if (__instance.IsAllowedForWhoringAll())
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											if (gizmo is Command_Toggle && ((Command_Toggle)gizmo).defaultLabel == "CommandBedSetAsGuestLabel".Translate())
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												// hide set as guest bed
 | 
				
			||||||
 | 
												continue;
 | 
				
			||||||
 | 
											};
 | 
				
			||||||
 | 
											// old: instead of hiding, just disable
 | 
				
			||||||
 | 
											/*switch (gizmo)
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												case Command_Toggle toggle:
 | 
				
			||||||
 | 
													{
 | 
				
			||||||
 | 
														// Disable prisoner and medical, and guest buttons
 | 
				
			||||||
 | 
														if (//toggle.defaultLabel == "CommandBedSetForPrisonersLabel".Translate() ||
 | 
				
			||||||
 | 
															//toggle.defaultLabel == "CommandBedSetAsMedicalLabel".Translate() ||
 | 
				
			||||||
 | 
															toggle.defaultLabel == "CommandBedSetAsGuestLabel".Translate()) gizmo.Disable();
 | 
				
			||||||
 | 
														break;
 | 
				
			||||||
 | 
													}
 | 
				
			||||||
 | 
											}//*/
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										yield return gizmo;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// add description of whore price factor to inspect string (bottom left corner if item selected)
 | 
				
			||||||
 | 
							[HarmonyPatch(typeof(Building_Bed), nameof(Building_Bed.GetInspectString))]
 | 
				
			||||||
 | 
							public static class Building_Bed_GetInspectString_Patch
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								[HarmonyPostfix]
 | 
				
			||||||
 | 
								public static void Postfix(Building_Bed __instance, ref string __result)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (__instance.def.building.bed_humanlike && __instance.Faction == Faction.OfPlayerSilentFail && (__instance.IsAllowedForWhoringAll() || __instance.IsAllowedForWhoringOwner()))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										__result = __result + "\n" + "WhorePriceCalcDesc".Translate(WhoreBed_Utility.CalculatePriceFactor(__instance).ToString("F2"));
 | 
				
			||||||
 | 
										if (WhoringBase.DebugWhoring)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											__result = __result + "\nbed.thingIDNumber: " + __instance.thingIDNumber.ToString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											__result = __result + "\nscoreUpdateTickDelay: " + WhoringBase.DataStore.GetBedData(__instance).scoreUpdateTickDelay.ToString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											if (WhoringBase.DataStore.GetBedData(__instance).reservedUntilGameTick > GenTicks.TicksGame)
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												__result = __result + "\nreserved by pawn id: " + WhoringBase.DataStore.GetBedData(__instance).reservedForPawnID.ToString();
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// add whore price factor as overlay
 | 
				
			||||||
 | 
							[HarmonyPatch(typeof(Building_Bed), nameof(Building_Bed.DrawGUIOverlay))]
 | 
				
			||||||
 | 
							public static class Building_Bed_DrawGUIOverlay_Patch
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								[HarmonyPrefix]
 | 
				
			||||||
 | 
								public static bool Prefix(Building_Bed __instance)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (WhoringBase.show_whore_price_factor_on_bed && __instance.def.building.bed_humanlike && __instance.Faction == Faction.OfPlayerSilentFail) {
 | 
				
			||||||
 | 
										// if whore bed, print price factor on it
 | 
				
			||||||
 | 
										if (Find.CameraDriver.CurrentZoom == CameraZoomRange.Closest
 | 
				
			||||||
 | 
											&& ((__instance.IsAllowedForWhoringOwner() && __instance.OwnersForReading.Any<Pawn>())
 | 
				
			||||||
 | 
												|| __instance.IsAllowedForWhoringAll()))
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Color defaultThingLabelColor = GenMapUI.DefaultThingLabelColor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											// make string
 | 
				
			||||||
 | 
											float whore_price_factor = WhoreBed_Utility.CalculatePriceFactor(__instance);
 | 
				
			||||||
 | 
											string wpf;
 | 
				
			||||||
 | 
											if (Math.Abs(whore_price_factor) >= 100)
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												wpf = ((int)whore_price_factor).ToString("D");
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											else if (Math.Abs(whore_price_factor) >= 10)
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												wpf = whore_price_factor.ToString("F1");
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											else
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												wpf = whore_price_factor.ToString("F2");
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											// get dimensions of text and make it appear above names
 | 
				
			||||||
 | 
											Vector2 textsize = Text.CalcSize(wpf);
 | 
				
			||||||
 | 
											Vector2 baseLabelPos = GenMapUI.LabelDrawPosFor(__instance, -0.4f); // -0.4f is copied from vanilla code
 | 
				
			||||||
 | 
											baseLabelPos.y -= textsize.y * 0.75f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											GenMapUI.DrawThingLabel(baseLabelPos, wpf, defaultThingLabelColor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											if (__instance.IsAllowedForWhoringAll() && !__instance.OwnersForReading.Any<Pawn>())
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												// hide "Unowned" if whore bed with no owner
 | 
				
			||||||
 | 
												return false;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									// after drawing whore price factor, draw the actual names
 | 
				
			||||||
 | 
									// could have been done as a postfix, but I started with a prefix, hoping I could get by with only one draw call
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// barracks don't count whore beds, so room type switches to brothel sooner
 | 
				
			||||||
 | 
							// disabled - barracks have their own slept in ~ debuff; doesn't really matter; put some effort in your brothels!
 | 
				
			||||||
 | 
							/*[HarmonyPatch(typeof(RoomRoleWorker_Barracks), nameof(RoomRoleWorker_Barracks.GetScore))]
 | 
				
			||||||
 | 
							public static class RoomRoleWorker_Barracks_GetScore_Patch
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								public static bool Prefix(Room room, ref float __result)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									int num = 0;
 | 
				
			||||||
 | 
									int num2 = 0;
 | 
				
			||||||
 | 
									List<Thing> containedAndAdjacentThings = room.ContainedAndAdjacentThings;
 | 
				
			||||||
 | 
									for (int i = 0; i < containedAndAdjacentThings.Count; i++)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Building_Bed building_Bed = containedAndAdjacentThings[i] as Building_Bed;
 | 
				
			||||||
 | 
										if (building_Bed != null && building_Bed.def.building.bed_humanlike)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											if (building_Bed.ForPrisoners)
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												__result = 0f;
 | 
				
			||||||
 | 
												return false;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											num++;
 | 
				
			||||||
 | 
											if (!building_Bed.Medical && !building_Bed.IsAllowedForWhoringAll())
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												num2++;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (num <= 1)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										__result = 0f;
 | 
				
			||||||
 | 
										return false;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									__result = (float)num2 * 100100f;
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// if pawns sleep in a brothel or a whoring bed, they get a thought
 | 
				
			||||||
 | 
							[HarmonyPatch(typeof(Toils_LayDown), "ApplyBedThoughts")]
 | 
				
			||||||
 | 
							public class Toils_LayDown_ApplyBedThoughts_Patch
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								[HarmonyPostfix]
 | 
				
			||||||
 | 
								public static void Postfix(Pawn actor)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (actor?.needs?.mood == null) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									Building_Bed building_Bed = actor.CurrentBed();
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
									actor?.needs?.mood?.thoughts?.memories?.RemoveMemoriesOfDef(ThoughtDefOf.SleptInBrothel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (building_Bed == null) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (building_Bed?.GetRoom()?.Role == WhoreBed_Utility.roleDefBrothel || building_Bed.IsAllowedForWhoringAll())
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										var memoryHandler = actor.needs.mood.thoughts.memories;
 | 
				
			||||||
 | 
										int thoughtStage = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										foreach (var thoughtDef in DefDatabase<ThoughtDef_Whore>.AllDefsListForReading)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											var memory = memoryHandler.GetFirstMemoryOfDef(thoughtDef);
 | 
				
			||||||
 | 
											if (memory?.CurStageIndex >= thoughtDef.stages.Count - 1)
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												thoughtStage = 1;
 | 
				
			||||||
 | 
												break;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										memoryHandler.TryGainMemory(ThoughtMaker.MakeThought(ThoughtDefOf.SleptInBrothel, thoughtStage));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// if room stats are updated, update beds within
 | 
				
			||||||
 | 
							//	"necessary" if beds are toggled during pause
 | 
				
			||||||
 | 
							[HarmonyPatch(typeof(Room), "UpdateRoomStatsAndRole")]
 | 
				
			||||||
 | 
							public class Room_UpdateRoomStatsAndRole_Patch
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								[HarmonyPostfix]
 | 
				
			||||||
 | 
								public static void Postfix(Room __instance)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									// note: with room stat display enabled, this get's called quite often for whatever room the mouse hovers over
 | 
				
			||||||
 | 
									//	even large outdoor areas
 | 
				
			||||||
 | 
									//	where iterating over all things to find all beds (even if there are none) is expensive
 | 
				
			||||||
 | 
									//	for now, skip doing anything if even the game decides it's not worth it
 | 
				
			||||||
 | 
									//	(game sets role to None if region count >36 or something)
 | 
				
			||||||
 | 
									//	- the beds will update eventually
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (/*Find.PlaySettings.showRoomStats && */__instance.Role == RoomRoleDefOf.None)
 | 
				
			||||||
 | 
										return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (Find.TickManager.Paused)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										// if paused, update immediately
 | 
				
			||||||
 | 
										WhoreBed_Utility.CalculateBedFactorsForRoom(__instance);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										// else, just make beds update as soon as needed
 | 
				
			||||||
 | 
										WhoreBed_Utility.ResetTicksUntilUpdate(__instance);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /// <summary>
 | 
				
			||||||
 | 
					        ///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. 
 | 
				
			||||||
 | 
							///<returns>Modifies __result to false, if bed is set to allow anyone for whroing AND is not already claimed.</returns>
 | 
				
			||||||
 | 
					        /// </summary>
 | 
				
			||||||
 | 
					        [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;  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										53
									
								
								1.5/Source/Mod/harmony_RJWTab_patch.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,53 @@
 | 
				
			||||||
 | 
					using Verse;
 | 
				
			||||||
 | 
					using HarmonyLib;
 | 
				
			||||||
 | 
					using rjw;
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using RimWorld;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using UnityEngine;
 | 
				
			||||||
 | 
					using rjw.MainTab.DefModExtensions;
 | 
				
			||||||
 | 
					using System.Linq;
 | 
				
			||||||
 | 
					using System.Reflection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace rjwwhoring
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						[HarmonyPatch(typeof(rjw.MainTab.MainTabWindow))]
 | 
				
			||||||
 | 
						[HarmonyPatch(nameof(rjw.MainTab.MainTabWindow.MakeOptions))]
 | 
				
			||||||
 | 
						static class RJWTab_Brothel
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							[HarmonyPostfix]
 | 
				
			||||||
 | 
							private static void MakeOptionsPatch(rjw.MainTab.MainTabWindow __instance, ref List<FloatMenuOption> __result)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								try
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									RJWTab_Brothel_Patch.MakeOptionsPatch(__instance, ref __result);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								catch (Exception e)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									Log.Error(e.ToString());
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static class RJWTab_Brothel_Patch
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							public static List<FloatMenuOption> MakeOptionsPatch(rjw.MainTab.MainTabWindow __instance, ref List<FloatMenuOption> __result)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								PawnTableDef RJW_Brothel = DefDatabase<PawnTableDef>.GetNamed("RJW_Brothel");
 | 
				
			||||||
 | 
								ModLog.Message("0");
 | 
				
			||||||
 | 
								__result.Add(new FloatMenuOption(RJW_Brothel.GetModExtension<RJW_PawnTable>().label, () =>
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									ModLog.Message("1");
 | 
				
			||||||
 | 
									__instance.pawnTableDef = RJW_Brothel;
 | 
				
			||||||
 | 
									ModLog.Message("2");
 | 
				
			||||||
 | 
									__instance.pawns = Find.CurrentMap.mapPawns.AllPawns.Where(p => xxx.is_human(p) && (p.IsColonist || p.IsPrisonerOfColony));
 | 
				
			||||||
 | 
									ModLog.Message("3");
 | 
				
			||||||
 | 
									__instance.Notify_ResolutionChanged();
 | 
				
			||||||
 | 
									ModLog.Message("4");
 | 
				
			||||||
 | 
									rjw.MainTab.MainTabWindow.Reloadtab();
 | 
				
			||||||
 | 
									ModLog.Message("5");
 | 
				
			||||||
 | 
								}, MenuOptionPriority.Default));
 | 
				
			||||||
 | 
								return __result;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										4
									
								
								1.5/Source/Mod/packages.config
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
 | 
					<packages>
 | 
				
			||||||
 | 
					  <package id="Lib.Harmony" version="2.3.3" targetFramework="net472" />
 | 
				
			||||||
 | 
					</packages>
 | 
				
			||||||
							
								
								
									
										32
									
								
								1.5/Source/Properties/AssemblyInfo.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,32 @@
 | 
				
			||||||
 | 
					using System.Reflection;
 | 
				
			||||||
 | 
					using System.Runtime.CompilerServices;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// General Information about an assembly is controlled through the following 
 | 
				
			||||||
 | 
					// set of attributes. Change these attribute values to modify the information
 | 
				
			||||||
 | 
					// associated with an assembly.
 | 
				
			||||||
 | 
					[assembly: AssemblyTitle("RimJobWorld Whoring")]
 | 
				
			||||||
 | 
					[assembly: AssemblyDescription("")]
 | 
				
			||||||
 | 
					[assembly: AssemblyConfiguration("")]
 | 
				
			||||||
 | 
					[assembly: AssemblyCompany("")]
 | 
				
			||||||
 | 
					[assembly: AssemblyProduct("RimJobWorld Whoring")]
 | 
				
			||||||
 | 
					[assembly: AssemblyCopyright("Copyright © 2022")]
 | 
				
			||||||
 | 
					[assembly: AssemblyTrademark("")]
 | 
				
			||||||
 | 
					[assembly: AssemblyCulture("")]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Setting ComVisible to false makes the types in this assembly not visible 
 | 
				
			||||||
 | 
					// to COM components. If you need to access a type in this assembly from 
 | 
				
			||||||
 | 
					// COM, set the ComVisible attribute to true on that type.
 | 
				
			||||||
 | 
					[assembly: ComVisible(false)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The following GUID is for the ID of the typelib if this project is exposed to COM
 | 
				
			||||||
 | 
					[assembly: Guid("c2825019-7f0b-456d-85a3-479c1a2a8805")]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Version information for an assembly consists of the following four values:
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//      Major Version
 | 
				
			||||||
 | 
					//      Minor Version 
 | 
				
			||||||
 | 
					//      Build Number
 | 
				
			||||||
 | 
					//      Revision
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					[assembly: AssemblyVersion("1.0.0.0")]
 | 
				
			||||||
							
								
								
									
										25
									
								
								1.5/Source/mod.sln
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
						 | 
					@ -0,0 +1,25 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Microsoft Visual Studio Solution File, Format Version 12.00
 | 
				
			||||||
 | 
					# Visual Studio Version 16
 | 
				
			||||||
 | 
					VisualStudioVersion = 16.0.30907.101
 | 
				
			||||||
 | 
					MinimumVisualStudioVersion = 10.0.40219.1
 | 
				
			||||||
 | 
					Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Whoring", "Mod\Whoring.csproj", "{3FC2D442-19B8-4CF9-9D35-CD13B6AC7B28}"
 | 
				
			||||||
 | 
					EndProject
 | 
				
			||||||
 | 
					Global
 | 
				
			||||||
 | 
						GlobalSection(SolutionConfigurationPlatforms) = preSolution
 | 
				
			||||||
 | 
							Debug|Any CPU = Debug|Any CPU
 | 
				
			||||||
 | 
							Release|Any CPU = Release|Any CPU
 | 
				
			||||||
 | 
						EndGlobalSection
 | 
				
			||||||
 | 
						GlobalSection(ProjectConfigurationPlatforms) = postSolution
 | 
				
			||||||
 | 
							{3FC2D442-19B8-4CF9-9D35-CD13B6AC7B28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
				
			||||||
 | 
							{3FC2D442-19B8-4CF9-9D35-CD13B6AC7B28}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
				
			||||||
 | 
							{3FC2D442-19B8-4CF9-9D35-CD13B6AC7B28}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
				
			||||||
 | 
							{3FC2D442-19B8-4CF9-9D35-CD13B6AC7B28}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
				
			||||||
 | 
						EndGlobalSection
 | 
				
			||||||
 | 
						GlobalSection(SolutionProperties) = preSolution
 | 
				
			||||||
 | 
							HideSolutionNode = FALSE
 | 
				
			||||||
 | 
						EndGlobalSection
 | 
				
			||||||
 | 
						GlobalSection(ExtensibilityGlobals) = postSolution
 | 
				
			||||||
 | 
							SolutionGuid = {5A0C2732-36A9-4ACA-807E-019E02C37E10}
 | 
				
			||||||
 | 
						EndGlobalSection
 | 
				
			||||||
 | 
					EndGlobal
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								1.5/Textures/UI/Commands/AsWhore.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.7 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								1.5/Textures/UI/Commands/AsWhoreMany.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 6.8 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								1.5/Textures/UI/Commands/Service_Refuse.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 26 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								1.5/Textures/UI/Commands/Service_off.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 22 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								1.5/Textures/UI/Commands/Service_on.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 37 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								1.5/Textures/UI/Tab/ComfortPrisoner_off.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.2 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								1.5/Textures/UI/Tab/ComfortPrisoner_off_nobg.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 7.4 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								1.5/Textures/UI/Tab/ComfortPrisoner_on.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.3 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								1.5/Textures/UI/Tab/Service_off.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.8 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								1.5/Textures/UI/Tab/Service_on.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.9 KiB  | 
| 
						 | 
					@ -7,6 +7,7 @@
 | 
				
			||||||
	<supportedVersions>
 | 
						<supportedVersions>
 | 
				
			||||||
		<li>1.3</li>
 | 
							<li>1.3</li>
 | 
				
			||||||
		<li>1.4</li>
 | 
							<li>1.4</li>
 | 
				
			||||||
 | 
							<li>1.5</li>
 | 
				
			||||||
	</supportedVersions>
 | 
						</supportedVersions>
 | 
				
			||||||
	<packageId>rjw.whoring</packageId>
 | 
						<packageId>rjw.whoring</packageId>
 | 
				
			||||||
	<modDependencies>
 | 
						<modDependencies>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||