mirror of
https://gitgud.io/Ed86/rjw-whoring.git
synced 2024-08-15 00:03:25 +00:00
300 lines
No EOL
10 KiB
C#
300 lines
No EOL
10 KiB
C#
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);
|
|
}
|
|
}
|
|
} |