mirror of
https://gitgud.io/LonelyRain/rjw-quirks.git
synced 2024-08-15 00:03:31 +00:00
Initial upload
This commit is contained in:
parent
feb28b10a4
commit
7585da099c
106 changed files with 4860 additions and 0 deletions
71
RJW-Quirks/Modules/Interactions/QuirksPartKindUsageRule.cs
Normal file
71
RJW-Quirks/Modules/Interactions/QuirksPartKindUsageRule.cs
Normal file
|
@ -0,0 +1,71 @@
|
|||
using rjw.Modules.Interactions.Contexts;
|
||||
using rjw.Modules.Interactions.Enums;
|
||||
using rjw.Modules.Interactions.Objects;
|
||||
using rjw.Modules.Interactions.Rules.PartKindUsageRules;
|
||||
using rjw.Modules.Shared;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Interactions
|
||||
{
|
||||
public class QuirksPartKindUsageRule : IPartPreferenceRule
|
||||
{
|
||||
public IEnumerable<Weighted<LewdablePartKind>> ModifiersForDominant(InteractionContext context)
|
||||
{
|
||||
return Enumerable.Concat(
|
||||
ModifierFromPawnQuirks(context.Internals.Dominant, context.Internals.Submissive),
|
||||
ModifierFromPartnerQuirks(context.Internals.Submissive, context.Internals.Dominant)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public IEnumerable<Weighted<LewdablePartKind>> ModifiersForSubmissive(InteractionContext context)
|
||||
{
|
||||
return Enumerable.Concat(
|
||||
ModifierFromPawnQuirks(context.Internals.Submissive, context.Internals.Dominant),
|
||||
ModifierFromPartnerQuirks(context.Internals.Dominant, context.Internals.Submissive)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// What pawn wants to use because of quirks
|
||||
/// </summary>
|
||||
private IEnumerable<Weighted<LewdablePartKind>> ModifierFromPawnQuirks(InteractionPawn quirkOwner, InteractionPawn partner)
|
||||
{
|
||||
foreach (var comp in GetQuirkComps(quirkOwner.Pawn))
|
||||
{
|
||||
foreach (var rule in comp.GetModifiersForPawn(quirkOwner, partner))
|
||||
{
|
||||
yield return rule;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// What pawn want from partner because of pawn's quirks
|
||||
/// </summary>
|
||||
private IEnumerable<Weighted<LewdablePartKind>> ModifierFromPartnerQuirks(InteractionPawn quirkOwner, InteractionPawn partner)
|
||||
{
|
||||
foreach (var comp in GetQuirkComps(quirkOwner.Pawn))
|
||||
{
|
||||
foreach (var rule in comp.GetModifiersForPartner(quirkOwner, partner))
|
||||
{
|
||||
yield return rule;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<Quirks.Comps.PartKindUsageRules> GetQuirkComps(Pawn pawn)
|
||||
{
|
||||
foreach (var comp in pawn.GetQuirks().AllQuirks.SelectMany(quirk => quirk.def.GetComps<Quirks.Comps.PartKindUsageRules>()))
|
||||
{
|
||||
yield return comp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
17
RJW-Quirks/Modules/Quirks/CompProperties_QuirkSet.cs
Normal file
17
RJW-Quirks/Modules/Quirks/CompProperties_QuirkSet.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks
|
||||
{
|
||||
public class CompProperties_QuirkSet : CompProperties
|
||||
{
|
||||
public CompProperties_QuirkSet()
|
||||
{
|
||||
compClass = typeof(QuirkSet);
|
||||
}
|
||||
}
|
||||
}
|
53
RJW-Quirks/Modules/Quirks/Comps/Adder.cs
Normal file
53
RJW-Quirks/Modules/Quirks/Comps/Adder.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.Comps
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for the comps that add quirks to the pawns
|
||||
/// </summary>
|
||||
public abstract class Adder : QuirkComp
|
||||
{
|
||||
/// <summary>
|
||||
/// For def load only. Use <see cref="GetMessageFor"/>
|
||||
/// </summary>
|
||||
public string message;
|
||||
public MessageTypeDef messageType;
|
||||
|
||||
protected string MessageTemplate => message ?? parent.description;
|
||||
|
||||
public MessageTypeDef MessageType => messageType ?? MessageTypeDefOf.NeutralEvent;
|
||||
|
||||
/// <summary>
|
||||
/// Get adjusted message text to be shown to the user when adding a quirk
|
||||
/// </summary>
|
||||
public string GetMessageFor(Pawn pawn) => MessageTemplate.Formatted(pawn.Named("pawn")).AdjustedFor(pawn).Resolve();
|
||||
|
||||
/// <summary>
|
||||
/// Add quirk of comp parent def to the pawn
|
||||
/// </summary>
|
||||
protected void AddQuirkTo(Pawn pawn)
|
||||
{
|
||||
Quirk addedQuirk = pawn.GetQuirks().AddQuirk(parent);
|
||||
|
||||
if (addedQuirk != null)
|
||||
{
|
||||
Messages.Message(GetMessageFor(pawn), pawn, MessageType);
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||
{
|
||||
foreach (string error in base.ConfigErrors(parent))
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (eventDef == null)
|
||||
{
|
||||
yield return "<eventDef> is empty";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
52
RJW-Quirks/Modules/Quirks/Comps/Adder_OnRecordExceeding.cs
Normal file
52
RJW-Quirks/Modules/Quirks/Comps/Adder_OnRecordExceeding.cs
Normal file
|
@ -0,0 +1,52 @@
|
|||
using RimWorld;
|
||||
using rjw;
|
||||
using rjwquirks;
|
||||
using rjwquirks.Modules.Shared.Events;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.Comps
|
||||
{
|
||||
/// <summary>
|
||||
/// Comp to add a quirk when <see cref="record"/> crosses <see cref="value"/>
|
||||
/// </summary>
|
||||
public class Adder_OnRecordExceeding : Adder
|
||||
{
|
||||
public RecordDef record;
|
||||
public float value;
|
||||
|
||||
protected override void HandleEvent(RjwEvent ev)
|
||||
{
|
||||
if (!ev.args.TryGetArg(RjwEventArgNames.Pawn, out Pawn pawn))
|
||||
{
|
||||
ModLog.Error($"{GetType()}.HandleEvent: No pawn in the event");
|
||||
return;
|
||||
}
|
||||
|
||||
float recordValue = pawn.records?.GetValue(record) ?? 0f;
|
||||
|
||||
if (recordValue >= value && !pawn.HasQuirk(parent))
|
||||
{
|
||||
AddQuirkTo(pawn);
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||
{
|
||||
foreach (string error in base.ConfigErrors(parent))
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (record == null)
|
||||
{
|
||||
yield return "<record> is empty";
|
||||
}
|
||||
|
||||
if (value == 0f)
|
||||
{
|
||||
yield return "<value> is empty";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
25
RJW-Quirks/Modules/Quirks/Comps/CompAdder.cs
Normal file
25
RJW-Quirks/Modules/Quirks/Comps/CompAdder.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using rjw;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.Comps
|
||||
{
|
||||
// Adds quirk comp to all races
|
||||
[StaticConstructorOnStartup]
|
||||
public static class CompAdder
|
||||
{
|
||||
static CompAdder()
|
||||
{
|
||||
foreach (ThingDef thingDef in DefDatabase<ThingDef>.AllDefs.Where(thingDef =>
|
||||
thingDef.race != null && !thingDef.race.Animal ))
|
||||
{
|
||||
thingDef.comps.Add(new CompProperties_QuirkSet());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
44
RJW-Quirks/Modules/Quirks/Comps/HediffAdder.cs
Normal file
44
RJW-Quirks/Modules/Quirks/Comps/HediffAdder.cs
Normal file
|
@ -0,0 +1,44 @@
|
|||
using rjw;
|
||||
using rjwquirks.Modules.Shared.Events;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.Comps
|
||||
{
|
||||
/// <summary>
|
||||
/// Comp to add an <see cref="hediff"/> to the pawn on RJW event
|
||||
/// </summary>
|
||||
public class HediffAdder : QuirkComp
|
||||
{
|
||||
public HediffDef hediff;
|
||||
|
||||
protected override void HandleEvent(RjwEvent ev)
|
||||
{
|
||||
if (!ev.args.TryGetArg(RjwEventArgNames.Pawn, out Pawn pawn))
|
||||
{
|
||||
ModLog.Error($"{GetType()}.HandleEvent: No pawn in the event");
|
||||
return;
|
||||
}
|
||||
|
||||
pawn.health?.AddHediff(hediff);
|
||||
}
|
||||
|
||||
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||
{
|
||||
foreach (string error in base.ConfigErrors(parent))
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (hediff == null)
|
||||
{
|
||||
yield return "<hediff> is empty";
|
||||
}
|
||||
|
||||
if (eventDef == null)
|
||||
{
|
||||
yield return "<eventDef> is empty";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
48
RJW-Quirks/Modules/Quirks/Comps/HediffRemover.cs
Normal file
48
RJW-Quirks/Modules/Quirks/Comps/HediffRemover.cs
Normal file
|
@ -0,0 +1,48 @@
|
|||
using rjw;
|
||||
using rjwquirks.Modules.Shared.Events;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.Comps
|
||||
{
|
||||
/// <summary>
|
||||
/// Comp to remove an <see cref="hediff"/> to the pawn on RJW event
|
||||
/// </summary>
|
||||
public class HediffRemover : QuirkComp
|
||||
{
|
||||
public HediffDef hediff;
|
||||
|
||||
protected override void HandleEvent(RjwEvent ev)
|
||||
{
|
||||
if (!ev.args.TryGetArg(RjwEventArgNames.Pawn, out Pawn pawn))
|
||||
{
|
||||
ModLog.Error($"{GetType()}.HandleEvent: No pawn in the event");
|
||||
return;
|
||||
}
|
||||
|
||||
Hediff existingHediff = pawn.health?.hediffSet?.GetFirstHediffOfDef(hediff);
|
||||
if (existingHediff != null)
|
||||
{
|
||||
pawn.health.RemoveHediff(existingHediff);
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||
{
|
||||
foreach (string error in base.ConfigErrors(parent))
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (hediff == null)
|
||||
{
|
||||
yield return "<hediff> is empty";
|
||||
}
|
||||
|
||||
if (eventDef == null)
|
||||
{
|
||||
yield return "<eventDef> is empty";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
27
RJW-Quirks/Modules/Quirks/Comps/PartKindUsageRules.cs
Normal file
27
RJW-Quirks/Modules/Quirks/Comps/PartKindUsageRules.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
using rjw.Modules.Interactions.Enums;
|
||||
using rjw.Modules.Interactions.Objects;
|
||||
using rjw.Modules.Shared;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.Comps
|
||||
{
|
||||
/// <summary>
|
||||
/// QuirkComp to affect body part selection when choosing sex interaction
|
||||
/// </summary>
|
||||
public abstract class PartKindUsageRules : QuirkComp
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns body parts that pawn prefers because of the quirk
|
||||
/// </summary>
|
||||
/// <param name="pawn">Quirk owner</param>
|
||||
/// <param name="partner">Quirk owner's sex partner</param>
|
||||
public abstract IEnumerable<Weighted<LewdablePartKind>> GetModifiersForPawn(InteractionPawn quirkOwner, InteractionPawn partner);
|
||||
|
||||
/// <summary>
|
||||
/// Returns body parts that pawn wants partner to use
|
||||
/// </summary>
|
||||
/// <param name="pawn">Quirk owner</param>
|
||||
/// <param name="partner">Quirk owner's sex partner</param>
|
||||
public abstract IEnumerable<Weighted<LewdablePartKind>> GetModifiersForPartner(InteractionPawn quirkOwner, InteractionPawn partner);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
using rjw.Modules.Interactions.Enums;
|
||||
using rjw.Modules.Interactions.Objects;
|
||||
using rjw.Modules.Shared;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.Comps
|
||||
{
|
||||
public class PartKindUsageRules_ImpregnationFetish : PartKindUsageRules
|
||||
{
|
||||
/// <summary>
|
||||
/// Add desire to use penis if partner has vagina and vise-verse.
|
||||
/// Check of partner's parts is to avoid boosting vagina on futa when partner is female.
|
||||
/// No check of pawn's parts because interaction framework will filter it anyway
|
||||
/// </summary>
|
||||
public override IEnumerable<Weighted<LewdablePartKind>> GetModifiersForPawn(InteractionPawn quirkOwner, InteractionPawn partner)
|
||||
{
|
||||
if (!partner.BlockedParts.Contains(LewdablePartKind.Vagina))
|
||||
{
|
||||
yield return new Weighted<LewdablePartKind>(Multipliers.Doubled, LewdablePartKind.Penis);
|
||||
}
|
||||
if (!partner.BlockedParts.Contains(LewdablePartKind.Penis))
|
||||
{
|
||||
yield return new Weighted<LewdablePartKind>(Multipliers.Doubled, LewdablePartKind.Vagina);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ask partner to use penis if quirk owner has vagina and provide vagina if owner has penis.
|
||||
/// </summary>
|
||||
public override IEnumerable<Weighted<LewdablePartKind>> GetModifiersForPartner(InteractionPawn quirkOwner, InteractionPawn partner)
|
||||
{
|
||||
if (!quirkOwner.BlockedParts.Contains(LewdablePartKind.Vagina))
|
||||
{
|
||||
yield return new Weighted<LewdablePartKind>(Multipliers.Doubled, LewdablePartKind.Penis);
|
||||
}
|
||||
if (!quirkOwner.BlockedParts.Contains(LewdablePartKind.Penis))
|
||||
{
|
||||
yield return new Weighted<LewdablePartKind>(Multipliers.Doubled, LewdablePartKind.Vagina);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
45
RJW-Quirks/Modules/Quirks/Comps/PartKindUsageRules_Static.cs
Normal file
45
RJW-Quirks/Modules/Quirks/Comps/PartKindUsageRules_Static.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
using rjw.Modules.Interactions.Enums;
|
||||
using rjw.Modules.Interactions.Objects;
|
||||
using rjw.Modules.Shared;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.Comps
|
||||
{
|
||||
public class PartKindUsageRules_Static : PartKindUsageRules
|
||||
{
|
||||
// rjw.Modules.Shared can't be loaded directly because it uses properties.
|
||||
// Probably should change that, but it'll cause more ripples then I'm willing to handle rn
|
||||
public class WeightedDef
|
||||
{
|
||||
public LewdablePartKind partKind;
|
||||
public float weightMultiplier;
|
||||
}
|
||||
|
||||
public List<WeightedDef> self = new List<WeightedDef>();
|
||||
public List<WeightedDef> partner = new List<WeightedDef>();
|
||||
|
||||
public override IEnumerable<Weighted<LewdablePartKind>> GetModifiersForPawn(InteractionPawn quirkOwner, InteractionPawn partner)
|
||||
{
|
||||
return self.ConvertAll(ruleDef => new Weighted<LewdablePartKind>(ruleDef.weightMultiplier, ruleDef.partKind));
|
||||
}
|
||||
|
||||
public override IEnumerable<Weighted<LewdablePartKind>> GetModifiersForPartner(InteractionPawn quirkOwner, InteractionPawn partner)
|
||||
{
|
||||
return this.partner.ConvertAll(ruleDef => new Weighted<LewdablePartKind>(ruleDef.weightMultiplier, ruleDef.partKind));
|
||||
}
|
||||
|
||||
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||
{
|
||||
foreach (string error in base.ConfigErrors(parent))
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (self.NullOrEmpty() && partner.NullOrEmpty())
|
||||
{
|
||||
yield return "Both <self> and <partner> can not be empty";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
32
RJW-Quirks/Modules/Quirks/Comps/QuirkComp.cs
Normal file
32
RJW-Quirks/Modules/Quirks/Comps/QuirkComp.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
using rjwquirks.Modules.Shared.Events;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.Comps
|
||||
{
|
||||
public abstract class QuirkComp
|
||||
{
|
||||
public QuirkDef parent;
|
||||
public RjwEventDef eventDef;
|
||||
|
||||
/// <summary>
|
||||
/// Notify quirk comp about the RJW event
|
||||
/// </summary>
|
||||
public void NotifyEvent(RjwEvent ev)
|
||||
{
|
||||
if (eventDef != null && ev.def == eventDef)
|
||||
{
|
||||
HandleEvent(ev);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle an RJW event. This method called only for events of <see cref="eventDef"/>
|
||||
/// </summary>
|
||||
protected virtual void HandleEvent(RjwEvent ev) { }
|
||||
|
||||
public virtual IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
41
RJW-Quirks/Modules/Quirks/Comps/SexAppraisalModifier.cs
Normal file
41
RJW-Quirks/Modules/Quirks/Comps/SexAppraisalModifier.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.Comps
|
||||
{
|
||||
public abstract class SexAppraisalModifier : QuirkComp
|
||||
{
|
||||
public string factorName;
|
||||
public QuirkModifierPriority priority = QuirkModifierPriority.Normal;
|
||||
|
||||
public void TryModifyValue(Pawn quirkOwner, Pawn partner, string factorName, ref float value)
|
||||
{
|
||||
if (this.factorName != factorName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (parent.partnerPreference?.PartnerSatisfies(quirkOwner, partner) != true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ModifyValue(quirkOwner, partner, ref value);
|
||||
}
|
||||
|
||||
public abstract void ModifyValue(Pawn quirkOwner, Pawn partner, ref float value);
|
||||
|
||||
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||
{
|
||||
foreach (string error in base.ConfigErrors(parent))
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (factorName.NullOrEmpty())
|
||||
{
|
||||
yield return "<factorName> is empty";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.Comps
|
||||
{
|
||||
public class SexAppraisalModifier_ApplyMultiplier : SexAppraisalModifier
|
||||
{
|
||||
public float multiplier = 1f;
|
||||
|
||||
public override void ModifyValue(Pawn quirkOwner, Pawn partner, ref float value)
|
||||
{
|
||||
value *= multiplier;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||
{
|
||||
foreach (string error in base.ConfigErrors(parent))
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (multiplier == 1f)
|
||||
{
|
||||
yield return "<multiplier> is empty or is 1";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.Comps
|
||||
{
|
||||
public class SexAppraisalModifier_SetValue : SexAppraisalModifier
|
||||
{
|
||||
public float value;
|
||||
|
||||
public override void ModifyValue(Pawn quirkOwner, Pawn partner, ref float value)
|
||||
{
|
||||
value = this.value;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||
{
|
||||
foreach (string error in base.ConfigErrors(parent))
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (value <= 0f)
|
||||
{
|
||||
yield return "<value> must be > 0";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
37
RJW-Quirks/Modules/Quirks/Comps/ThoughtAdder.cs
Normal file
37
RJW-Quirks/Modules/Quirks/Comps/ThoughtAdder.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.Comps
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for the comps that add thoughts to the pawn
|
||||
/// </summary>
|
||||
public abstract class ThoughtAdder : QuirkComp
|
||||
{
|
||||
public ThoughtDef thought;
|
||||
|
||||
/// <summary>
|
||||
/// Add <see cref="thought"/> to the <paramref name="pawn"/>
|
||||
/// </summary>
|
||||
public void ApplyThought(Pawn pawn, Pawn partner) => pawn.needs?.mood?.thoughts?.memories?.TryGainMemory(thought, partner);
|
||||
|
||||
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||
{
|
||||
foreach (string error in base.ConfigErrors(parent))
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (thought == null)
|
||||
{
|
||||
yield return "<thought> is empty";
|
||||
}
|
||||
|
||||
if (eventDef == null)
|
||||
{
|
||||
yield return "<eventDef> is empty";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
30
RJW-Quirks/Modules/Quirks/Comps/ThoughtAdder_OnSexEvent.cs
Normal file
30
RJW-Quirks/Modules/Quirks/Comps/ThoughtAdder_OnSexEvent.cs
Normal file
|
@ -0,0 +1,30 @@
|
|||
using rjw;
|
||||
using rjwquirks.Modules.Shared.Events;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.Comps
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for the comps that add thoughts on RJW event with SexProps argument
|
||||
/// </summary>
|
||||
public abstract class ThoughtAdder_OnSexEvent : ThoughtAdder
|
||||
{
|
||||
/// <summary>
|
||||
/// Check if thought should be applied
|
||||
/// </summary>
|
||||
public abstract bool ShouldApplyThought(SexProps props);
|
||||
|
||||
protected override void HandleEvent(RjwEvent ev)
|
||||
{
|
||||
if (!ev.args.TryGetArg(RjwEventArgNames.SexProps, out SexProps props))
|
||||
{
|
||||
ModLog.Error($"{GetType()}.HandleEvent: No SexProps in the event");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ShouldApplyThought(props))
|
||||
{
|
||||
ApplyThought(props.pawn, props.partner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using rjw;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.Comps
|
||||
{
|
||||
public class ThoughtAdder_OnSexEvent_NonPreferred : ThoughtAdder_OnSexEvent
|
||||
{
|
||||
public override bool ShouldApplyThought(SexProps props) => !parent.IsSatisfiedBySex(props);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using rjw;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.Comps
|
||||
{
|
||||
public class ThoughtAdder_OnSexEvent_Preferred : ThoughtAdder_OnSexEvent
|
||||
{
|
||||
public override bool ShouldApplyThought(SexProps props) => parent.IsSatisfiedBySex(props);
|
||||
}
|
||||
}
|
36
RJW-Quirks/Modules/Quirks/Comps/ValueModifier.cs
Normal file
36
RJW-Quirks/Modules/Quirks/Comps/ValueModifier.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.Comps
|
||||
{
|
||||
public abstract class ValueModifier : QuirkComp
|
||||
{
|
||||
public string valueName;
|
||||
public QuirkModifierPriority priority = QuirkModifierPriority.Normal;
|
||||
|
||||
public void TryModifyValue(string valueName, ref float value)
|
||||
{
|
||||
if (this.valueName != valueName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ModifyValue(ref value);
|
||||
}
|
||||
|
||||
public abstract void ModifyValue(ref float value);
|
||||
|
||||
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||
{
|
||||
foreach (string error in base.ConfigErrors(parent))
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (valueName.NullOrEmpty())
|
||||
{
|
||||
yield return "<valueName> is empty";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.Comps
|
||||
{
|
||||
public class ValueModifier_ApplyMultiplier : ValueModifier
|
||||
{
|
||||
public float multiplier = 1f;
|
||||
|
||||
public override void ModifyValue(ref float value)
|
||||
{
|
||||
value *= multiplier;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||
{
|
||||
foreach (string error in base.ConfigErrors(parent))
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (multiplier == 1f)
|
||||
{
|
||||
yield return "<multiplier> is empty or is 1";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
27
RJW-Quirks/Modules/Quirks/Comps/ValueModifier_ApplyOffset.cs
Normal file
27
RJW-Quirks/Modules/Quirks/Comps/ValueModifier_ApplyOffset.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.Comps
|
||||
{
|
||||
public class ValueModifier_ApplyOffset : ValueModifier
|
||||
{
|
||||
public float offset;
|
||||
|
||||
public override void ModifyValue(ref float value)
|
||||
{
|
||||
value += offset;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> ConfigErrors(QuirkDef parent)
|
||||
{
|
||||
foreach (string error in base.ConfigErrors(parent))
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (offset == 0f)
|
||||
{
|
||||
yield return "<offset> is empty or is 0";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
111
RJW-Quirks/Modules/Quirks/EventHandlers/QuirkGenerator.cs
Normal file
111
RJW-Quirks/Modules/Quirks/EventHandlers/QuirkGenerator.cs
Normal file
|
@ -0,0 +1,111 @@
|
|||
using rjw;
|
||||
using rjwquirks.Modules.Shared.Events;
|
||||
using System.Linq;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.EventHandlers
|
||||
{
|
||||
public class QuirkGenerator : RjwEventHandler
|
||||
{
|
||||
public override void HandleEvent(RjwEvent ev)
|
||||
{
|
||||
if (!ev.args.TryGetArg(RjwEventArgNames.Pawn, out Pawn pawn))
|
||||
{
|
||||
ModLog.Error($"QuirkGenerator recieved {ev.def}, but event has no '{RjwEventArgNames.Pawn}' argument");
|
||||
return;
|
||||
}
|
||||
|
||||
Generate(pawn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate quirks for the pawn.
|
||||
/// Caution: Does not clears existing quirks
|
||||
/// </summary>
|
||||
public static void Generate(Pawn pawn)
|
||||
{
|
||||
if (!pawn.RaceHasSexNeed() || (pawn.kindDef.race.defName.ToLower().Contains("droid") && !AndroidsCompatibility.IsAndroid(pawn)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QuirkSet quirks = pawn.GetQuirks();
|
||||
|
||||
if (pawn.IsAnimal())
|
||||
{
|
||||
GenerateForAnimal(quirks);
|
||||
}
|
||||
else
|
||||
{
|
||||
GenerateForHumanlike(quirks);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rolls an X number between 0 and max quirks setting.
|
||||
/// Tries to add random quirks to the QuirkSet until X are added or out of available quirks.
|
||||
/// </summary>
|
||||
static void GenerateForHumanlike(QuirkSet quirks)
|
||||
{
|
||||
var count = Rand.RangeInclusive(0, RJWPreferenceSettings.MaxQuirks);
|
||||
var availableQuirks = DefDatabase<QuirkDef>.AllDefsListForReading
|
||||
.Where(def => def.rarity != QuirkRarity.ForcedOnly) // Have to earn these
|
||||
.ToArray(); // ToArray to get a shuffleable copy
|
||||
availableQuirks.Shuffle();
|
||||
|
||||
// Some quirks may be hard for a given pawn to indulge in.
|
||||
// For example a female homosexual will have a hard time satisfying an impregnation fetish.
|
||||
// But rimworld is a weird place and you never know what the pawn will be capable of in the future.
|
||||
// We still don't want straight up contradictory results like fertile + infertile.
|
||||
foreach (var quirkDef in availableQuirks)
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!quirks.CanBeAdded(quirkDef))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
count--;
|
||||
quirks.AddQuirk(quirkDef);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Original method rolled 10% chance on 3 hardcoded animal quirks.
|
||||
/// This implementation takes MaxQuirks (3 by default) number of quirks from
|
||||
/// available for animals and rolls 10% chance for each
|
||||
/// </summary>
|
||||
static void GenerateForAnimal(QuirkSet quirks)
|
||||
{
|
||||
int count = RJWPreferenceSettings.MaxQuirks;
|
||||
var availableQuirks = DefDatabase<QuirkDef>.AllDefsListForReading
|
||||
.Where(def => def.rarity != QuirkRarity.ForcedOnly)
|
||||
.ToArray();
|
||||
availableQuirks.Shuffle();
|
||||
|
||||
foreach (var quirkDef in availableQuirks)
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!quirks.CanBeAdded(quirkDef))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
count--;
|
||||
|
||||
if (Rand.Chance(0.1f))
|
||||
{
|
||||
quirks.AddQuirk(quirkDef);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
using rjw;
|
||||
using rjwquirks.Modules.Shared.Events;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.EventHandlers
|
||||
{
|
||||
/// <summary>
|
||||
/// Handler that passes RJW events to a single quirk
|
||||
/// </summary>
|
||||
public class QuirkRjwEventHandler : RjwEventHandler
|
||||
{
|
||||
public override void HandleEvent(RjwEvent ev)
|
||||
{
|
||||
if (!ev.args.TryGetArg(RjwEventArgNames.Quirk, out Quirk quirk))
|
||||
{
|
||||
ModLog.Error($"QuirkRjwEventHandler recieved {ev.def}, but event has no '{RjwEventArgNames.Quirk}' argument");
|
||||
return;
|
||||
}
|
||||
|
||||
quirk.NotifyEvent(ev);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
using rjw;
|
||||
using rjwquirks.Modules.Shared.Events;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.EventHandlers
|
||||
{
|
||||
/// <summary>
|
||||
/// Handler that passes RJW events to all quirks of a pawn
|
||||
/// </summary>
|
||||
public class QuirkSetRjwEventHandler : RjwEventHandler
|
||||
{
|
||||
public override void HandleEvent(RjwEvent ev)
|
||||
{
|
||||
ev.args.TryGetArg(RjwEventArgNames.Pawn, out Pawn pawn);
|
||||
|
||||
if (pawn == null && ev.args.TryGetArg(RjwEventArgNames.SexProps, out SexProps props))
|
||||
{
|
||||
pawn = props.pawn;
|
||||
}
|
||||
|
||||
if (pawn == null)
|
||||
{
|
||||
ModLog.Error($"QuirkSetRjwEventHandler recieved {ev.def}, but event has neither '{RjwEventArgNames.Pawn}' or '{RjwEventArgNames.SexProps}' argument");
|
||||
return;
|
||||
}
|
||||
|
||||
pawn.GetQuirks().NotifyEvent(ev);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
using RimWorld;
|
||||
using rjw;
|
||||
using rjwquirks.Modules.Shared.Events;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.EventHandlers
|
||||
{
|
||||
/// <summary>
|
||||
/// Handler that passes RJW events a particular comps of an unassigned QuirkDef
|
||||
/// </summary>
|
||||
public class RecordChangedRjwEventHandler : RjwEventHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Records that have associated quirk adder def comps.
|
||||
/// Used to quickly filter out updates of irrelevant records.
|
||||
/// </summary>
|
||||
private static Dictionary<RecordDef, List<Comps.Adder_OnRecordExceeding>> _recordsWithAdder;
|
||||
|
||||
public override void HandleEvent(RjwEvent ev)
|
||||
{
|
||||
if (ev.def != RjwEventDefOf.RecordChanged)
|
||||
{
|
||||
ModLog.Warning($"RecordChangedRjwEventHandler recieved {ev.def}, but it only handles RecordChanged event");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_recordsWithAdder == null)
|
||||
{
|
||||
BuildAdderCache();
|
||||
}
|
||||
|
||||
if (!ev.args.TryGetArg(RjwEventArgNames.Record, out RecordDef recordDef))
|
||||
{
|
||||
ModLog.Error($"RecordChangedRjwEventHandler recieved {ev.def}, but event has no '{RjwEventArgNames.Record}' argument");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_recordsWithAdder.TryGetValue(recordDef, out var comps))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var comp in comps)
|
||||
{
|
||||
// Send message to the def comps directly because the quirk is not assigned to a pawn yet
|
||||
comp.NotifyEvent(ev);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds _recordsWithAdder dictionary
|
||||
/// </summary>
|
||||
private static void BuildAdderCache()
|
||||
{
|
||||
_recordsWithAdder = new Dictionary<RecordDef, List<Comps.Adder_OnRecordExceeding>>();
|
||||
|
||||
foreach (var comp in DefDatabase<QuirkDef>.AllDefs.SelectMany(def => def.GetComps<Comps.Adder_OnRecordExceeding>()))
|
||||
{
|
||||
if (_recordsWithAdder.TryGetValue(comp.record, out var comps))
|
||||
{
|
||||
comps.Add(comp);
|
||||
}
|
||||
else
|
||||
{
|
||||
_recordsWithAdder[comp.record] = new List<Comps.Adder_OnRecordExceeding>() { comp };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
58
RJW-Quirks/Modules/Quirks/OwnerRequirement.cs
Normal file
58
RJW-Quirks/Modules/Quirks/OwnerRequirement.cs
Normal file
|
@ -0,0 +1,58 @@
|
|||
using rjwquirks.Modules.Shared.PawnSelectors;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks
|
||||
{
|
||||
/// <summary>
|
||||
/// Class to check if quirk can be assigned to a pawn
|
||||
/// </summary>
|
||||
public class OwnerRequirement
|
||||
{
|
||||
/// <summary>
|
||||
/// Requirement conditions
|
||||
/// </summary>
|
||||
public IPawnSelector pawnSelector;
|
||||
|
||||
/// <summary>
|
||||
/// Translation key for a displayed reason why quirk can't be assigned to a pawn
|
||||
/// </summary>
|
||||
[NoTranslate]
|
||||
public string rejectionReason;
|
||||
|
||||
/// <summary>
|
||||
/// Check if pawn satisfies requirement conditions
|
||||
/// </summary>
|
||||
public AcceptanceReport CheckBeforeAdd(Pawn pawn)
|
||||
{
|
||||
if (pawnSelector?.PawnSatisfies(pawn) == true)
|
||||
{
|
||||
return AcceptanceReport.WasAccepted;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new AcceptanceReport(rejectionReason.Translate());
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
if (pawnSelector == null)
|
||||
{
|
||||
yield return "<pawnSelector> is empty";
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string error in pawnSelector.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
}
|
||||
|
||||
if (rejectionReason.NullOrEmpty())
|
||||
{
|
||||
yield return "<rejectionReason> is empty";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
71
RJW-Quirks/Modules/Quirks/Quirk.cs
Normal file
71
RJW-Quirks/Modules/Quirks/Quirk.cs
Normal file
|
@ -0,0 +1,71 @@
|
|||
using rjwquirks.Modules.Shared.Events;
|
||||
using System.Text;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks
|
||||
{
|
||||
public class Quirk : IExposable
|
||||
{
|
||||
public QuirkDef def;
|
||||
public Pawn pawn;
|
||||
|
||||
/// <summary>
|
||||
/// Adjusted for the owner and cached quirk description
|
||||
/// </summary>
|
||||
public string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
if (descriptionCache == null)
|
||||
{
|
||||
// Description bulding is a fairly pricy operation
|
||||
descriptionCache = def.GetDescriptionFor(pawn);
|
||||
}
|
||||
return descriptionCache;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gender specific quirk label
|
||||
/// </summary>
|
||||
public string Label => def.GetLabelFor(pawn);
|
||||
|
||||
protected string descriptionCache;
|
||||
|
||||
/// <summary>
|
||||
/// For save loading only
|
||||
/// </summary>
|
||||
public Quirk() { }
|
||||
|
||||
public Quirk(QuirkDef def, Pawn pawn)
|
||||
{
|
||||
this.def = def;
|
||||
this.pawn = pawn;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pass RJW event to all comps of this quirk's def
|
||||
/// </summary>
|
||||
public void NotifyEvent(RjwEvent ev) => def.comps.ForEach(comp => comp.NotifyEvent(ev));
|
||||
|
||||
public string TipString()
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.AppendLine(Label.Colorize(UnityEngine.Color.yellow));
|
||||
stringBuilder.Append(Description);
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
public void ExposeData()
|
||||
{
|
||||
Scribe_Defs.Look(ref def, "def");
|
||||
|
||||
if (Scribe.mode == LoadSaveMode.ResolvingCrossRefs && def == null)
|
||||
{
|
||||
def = DefDatabase<QuirkDef>.GetRandom();
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString() => $"Quirk({def})";
|
||||
}
|
||||
}
|
147
RJW-Quirks/Modules/Quirks/QuirkDef.cs
Normal file
147
RJW-Quirks/Modules/Quirks/QuirkDef.cs
Normal file
|
@ -0,0 +1,147 @@
|
|||
using RimWorld;
|
||||
using rjw;
|
||||
using rjwquirks.Modules.Quirks.Comps;
|
||||
using rjwquirks.Modules.Quirks.SexSelectors;
|
||||
using rjwquirks.Modules.Shared.PawnSelectors;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks
|
||||
{
|
||||
public class QuirkDef : Def
|
||||
{
|
||||
[MustTranslate]
|
||||
public string labelMale;
|
||||
[MustTranslate]
|
||||
public string labelFemale;
|
||||
public QuirkRarity rarity = QuirkRarity.Common;
|
||||
public bool hidden;
|
||||
public IPartnerSelector partnerPreference;
|
||||
public ISexSelector sexPreference;
|
||||
public List<OwnerRequirement> ownerRequirements = new List<OwnerRequirement>();
|
||||
public List<QuirkComp> comps = new List<QuirkComp>();
|
||||
public List<QuirkDef> conflictingQuirks = new List<QuirkDef>();
|
||||
public List<TraitDef> conflictingTraits = new List<TraitDef>();
|
||||
public List<string> exclusionTags = new List<string>();
|
||||
|
||||
public string GetLabelFor(Gender gender)
|
||||
{
|
||||
if (gender == Gender.Male && !labelMale.NullOrEmpty())
|
||||
{
|
||||
return labelMale;
|
||||
}
|
||||
|
||||
if (gender == Gender.Female && !labelFemale.NullOrEmpty())
|
||||
{
|
||||
return labelFemale;
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
public string GetLabelFor(Pawn pawn) => GetLabelFor(pawn?.gender ?? Gender.None);
|
||||
|
||||
public IEnumerable<T> GetComps<T>() where T : QuirkComp
|
||||
{
|
||||
for (int i = 0; i < comps.Count; i++)
|
||||
{
|
||||
if (comps[i] is T compT)
|
||||
yield return compT;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSatisfiedBySex(SexProps props) => sexPreference?.SexSatisfies(props) == true;
|
||||
|
||||
public bool ConflictsWith(QuirkDef other)
|
||||
{
|
||||
if (other.conflictingQuirks?.Contains(this) == true || conflictingQuirks?.Contains(other) == true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (exclusionTags != null && other.exclusionTags != null)
|
||||
{
|
||||
for (int i = 0; i < exclusionTags.Count; i++)
|
||||
{
|
||||
if (other.exclusionTags.Contains(exclusionTags[i]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool ConflictsWith(TraitDef traitDef)
|
||||
{
|
||||
if (/*traitDef.conflictingQuirks?.Contains(this) == true || */conflictingTraits?.Contains(traitDef) == true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (exclusionTags != null && traitDef.exclusionTags != null)
|
||||
{
|
||||
for (int i = 0; i < exclusionTags.Count; i++)
|
||||
{
|
||||
if (traitDef.exclusionTags.Contains(exclusionTags[i]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public string GetDescriptionFor(Pawn pawn) => description.Formatted(pawn.Named("pawn")).AdjustedFor(pawn).Resolve();
|
||||
|
||||
public override void PostLoad()
|
||||
{
|
||||
base.PostLoad();
|
||||
|
||||
foreach (QuirkComp comp in comps)
|
||||
{
|
||||
comp.parent = this;
|
||||
}
|
||||
|
||||
sexPreference?.SetParent(this);
|
||||
}
|
||||
|
||||
public override IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
foreach (string error in base.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (partnerPreference != null)
|
||||
{
|
||||
foreach (string error in partnerPreference.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
}
|
||||
|
||||
if (sexPreference != null)
|
||||
{
|
||||
foreach (string error in sexPreference.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (OwnerRequirement req in ownerRequirements)
|
||||
{
|
||||
foreach (string error in req.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (QuirkComp comp in comps)
|
||||
{
|
||||
foreach (string error in comp.ConfigErrors(this))
|
||||
{
|
||||
yield return $"{comp.GetType()}: {error}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
15
RJW-Quirks/Modules/Quirks/QuirkDefOf.cs
Normal file
15
RJW-Quirks/Modules/Quirks/QuirkDefOf.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using RimWorld;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks
|
||||
{
|
||||
[DefOf]
|
||||
public static class QuirkDefOf
|
||||
{
|
||||
public static readonly QuirkDef Breeder;
|
||||
public static readonly QuirkDef Endytophile;
|
||||
public static readonly QuirkDef Exhibitionist;
|
||||
public static readonly QuirkDef ImpregnationFetish;
|
||||
public static readonly QuirkDef Incubator;
|
||||
public static readonly QuirkDef Somnophile;
|
||||
}
|
||||
}
|
11
RJW-Quirks/Modules/Quirks/QuirkModifierPriority.cs
Normal file
11
RJW-Quirks/Modules/Quirks/QuirkModifierPriority.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace rjwquirks.Modules.Quirks
|
||||
{
|
||||
public enum QuirkModifierPriority
|
||||
{
|
||||
First,
|
||||
High,
|
||||
Normal,
|
||||
Low,
|
||||
Last
|
||||
}
|
||||
}
|
8
RJW-Quirks/Modules/Quirks/QuirkRarity.cs
Normal file
8
RJW-Quirks/Modules/Quirks/QuirkRarity.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace rjwquirks.Modules.Quirks
|
||||
{
|
||||
public enum QuirkRarity
|
||||
{
|
||||
ForcedOnly,
|
||||
Common
|
||||
}
|
||||
}
|
339
RJW-Quirks/Modules/Quirks/QuirkSet.cs
Normal file
339
RJW-Quirks/Modules/Quirks/QuirkSet.cs
Normal file
|
@ -0,0 +1,339 @@
|
|||
using RimWorld;
|
||||
using rjw;
|
||||
using rjwquirks.Modules.Shared.Events;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks
|
||||
{
|
||||
/// <summary>
|
||||
/// A collection/tracker of pawn's quirks
|
||||
/// </summary>
|
||||
public class QuirkSet : ThingComp
|
||||
{
|
||||
protected Pawn pawn;
|
||||
protected List<Quirk> quirks = new List<Quirk>();
|
||||
|
||||
public QuirkSet() { }
|
||||
|
||||
public override void PostSpawnSetup(bool respawningAfterLoad)
|
||||
{
|
||||
base.PostSpawnSetup(respawningAfterLoad);
|
||||
|
||||
pawn = parent as Pawn;
|
||||
|
||||
/*if (pawn.kindDef.race.defName.Contains("AIRobot") // No genitalia/sexuality for roombas.
|
||||
|| pawn.kindDef.race.defName.Contains("AIPawn") // ...nor MAI.
|
||||
|| pawn.kindDef.race.defName.Contains("RPP_Bot")
|
||||
|| pawn.kindDef.race.defName.Contains("PRFDrone") // Project RimFactory Revived drones
|
||||
) return;*/
|
||||
|
||||
if (Scribe.mode == LoadSaveMode.LoadingVars && quirks == null)
|
||||
{
|
||||
// Try to restore quirks from old save
|
||||
string quirksave = string.Empty;
|
||||
Scribe_Values.Look(ref quirksave, "RJW_Quirks");
|
||||
if (!quirksave.NullOrEmpty()) // May be pawn really has no quirks
|
||||
{
|
||||
ParseQuirkSave(quirksave);
|
||||
}
|
||||
}
|
||||
else if (quirks.NullOrEmpty())
|
||||
{
|
||||
//add random quirk gen and shit later/last
|
||||
AddQuirk(QuirkDefOf.Incubator);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// QuirkSet owner
|
||||
/// </summary>
|
||||
public Pawn Pawn => pawn;
|
||||
/// <summary>
|
||||
/// Read-only collection of pawn quirks
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<Quirk> AllQuirks => quirks.AsReadOnly();
|
||||
|
||||
/// <summary>
|
||||
/// Try to add a quirk of <paramref name="quirkDef"/> to the pawn
|
||||
/// </summary>
|
||||
/// <param name="quirkDef">Def of quirk to add</param>
|
||||
/// <param name="ignoreChecks">Ignore all restrictions and "just do it"</param>
|
||||
/// <returns>Added quirk or null if addiction failed</returns>
|
||||
public Quirk AddQuirk(QuirkDef quirkDef, bool ignoreChecks = false)
|
||||
{
|
||||
Quirk quirk = new Quirk(quirkDef, pawn);
|
||||
|
||||
if (AddQuirk(quirk, ignoreChecks).Accepted)
|
||||
{
|
||||
return quirk;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to add the <paramref name="quirk"/> to the pawn
|
||||
/// </summary>
|
||||
/// <param name="quirk">Quirk to add</param>
|
||||
/// <param name="ignoreChecks">Ignore all restrictions and "just do it"</param>
|
||||
/// <returns>AcceptanceReport</returns>
|
||||
protected AcceptanceReport AddQuirk(Quirk quirk, bool ignoreChecks = false)
|
||||
{
|
||||
if (!ignoreChecks)
|
||||
{
|
||||
AcceptanceReport report = CanBeAdded(quirk.def);
|
||||
if (!report.Accepted)
|
||||
{
|
||||
return report;
|
||||
}
|
||||
}
|
||||
|
||||
quirks.Add(quirk);
|
||||
RjwEventManager.NotifyEvent(new RjwEvent(RjwEventDefOf.QuirkAddedTo, pawn.Named(RjwEventArgNames.Pawn), quirk.Named(RjwEventArgNames.Quirk)));
|
||||
return AcceptanceReport.WasAccepted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to remove the <paramref name="quirk"/> from the pawn
|
||||
/// </summary>
|
||||
/// <param name="quirk">Quirk to remove</param>
|
||||
/// <param name="ignoreChecks">Ignore all restrictions and "just do it"</param>
|
||||
/// <returns>AcceptanceReport</returns>
|
||||
public AcceptanceReport RemoveQuirk(Quirk quirk, bool ignoreChecks = false)
|
||||
{
|
||||
if (!ignoreChecks)
|
||||
{
|
||||
AcceptanceReport report = CanBeRemoved(quirk.def);
|
||||
if (!report.Accepted)
|
||||
{
|
||||
return report;
|
||||
}
|
||||
}
|
||||
|
||||
bool result = quirks.Remove(quirk);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
if (quirks.Contains(quirk))
|
||||
{
|
||||
ModLog.Warning($"Tried to remove {quirk.Label} quirk from {pawn} but failed.");
|
||||
}
|
||||
else
|
||||
{
|
||||
ModLog.Warning($"Trying to remove {quirk.Label} quirk but {pawn} doesn't have it.");
|
||||
}
|
||||
return AcceptanceReport.WasRejected;
|
||||
}
|
||||
|
||||
RjwEventManager.NotifyEvent(new RjwEvent(RjwEventDefOf.QuirkRemovedFrom, pawn.Named(RjwEventArgNames.Pawn), quirk.Named(RjwEventArgNames.Quirk)));
|
||||
return AcceptanceReport.WasAccepted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if a quirk of <paramref name="quirkDef"/> can be added to the pawn
|
||||
/// </summary>
|
||||
public AcceptanceReport CanBeAdded(QuirkDef quirkDef)
|
||||
{
|
||||
if (Contains(quirkDef))
|
||||
{
|
||||
return AcceptanceReport.WasRejected;
|
||||
}
|
||||
|
||||
foreach (OwnerRequirement req in quirkDef.ownerRequirements)
|
||||
{
|
||||
AcceptanceReport report = req.CheckBeforeAdd(pawn);
|
||||
if (!report.Accepted)
|
||||
{
|
||||
return report;
|
||||
}
|
||||
}
|
||||
|
||||
if (quirks.Find(quirk => quirk.def.ConflictsWith(quirkDef)) is Quirk quirked)
|
||||
{
|
||||
return new AcceptanceReport("ConflictsWithQuirk".Translate(quirked.Label));
|
||||
}
|
||||
|
||||
if (Pawn?.story?.traits?.allTraits is List<Trait> traits)
|
||||
{
|
||||
foreach (Trait trait in traits)
|
||||
{
|
||||
if (quirks.Find(quirk => quirk.def.ConflictsWith(trait.def)) != null)
|
||||
{
|
||||
return new AcceptanceReport("ConflictsWithTrait".Translate(trait.LabelCap));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return AcceptanceReport.WasAccepted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if a quirk of <paramref name="quirkDef"/> can be removed from the pawn
|
||||
/// </summary>
|
||||
public AcceptanceReport CanBeRemoved(QuirkDef quirkDef)
|
||||
{
|
||||
if (!Contains(quirkDef))
|
||||
{
|
||||
return AcceptanceReport.WasRejected;
|
||||
}
|
||||
|
||||
if (quirkDef.rarity == QuirkRarity.ForcedOnly)
|
||||
{
|
||||
return new AcceptanceReport("CannotRemoveForced".Translate());
|
||||
}
|
||||
|
||||
return AcceptanceReport.WasAccepted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the pawn has a quirk of <paramref name="quirkDef"/>
|
||||
/// </summary>
|
||||
public bool Contains(QuirkDef quirkDef)
|
||||
{
|
||||
for (int i = 0; i < quirks.Count; i++)
|
||||
{
|
||||
if (quirks[i].def == quirkDef)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a quirk of <paramref name="quirkDef"/>
|
||||
/// </summary>
|
||||
public Quirk GetQuirk(QuirkDef quirkDef)
|
||||
{
|
||||
for (int i = 0; i < quirks.Count; i++)
|
||||
{
|
||||
if (quirks[i].def == quirkDef)
|
||||
{
|
||||
return quirks[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove all quirks from the pawn
|
||||
/// </summary>
|
||||
/// <param name="ignoreChecks">even quirks that can't be removed normaly</param>
|
||||
public void Clear(bool ignoreChecks = false) => new List<Quirk>(quirks).ForEach(quirk => RemoveQuirk(quirk, ignoreChecks));
|
||||
|
||||
/// <summary>
|
||||
/// Get a collection of quirks that are satified by a particular sex act
|
||||
/// </summary>
|
||||
public IEnumerable<Quirk> GetSatisfiedBySex(SexProps props) => quirks.Where(quirk => quirk.def.IsSatisfiedBySex(props));
|
||||
|
||||
/// <summary>
|
||||
/// Pass the RJW event to every quirk of the pawn
|
||||
/// </summary>
|
||||
public void NotifyEvent(RjwEvent ev) => quirks.ForEach(quirk => quirk.NotifyEvent(ev));
|
||||
|
||||
public void ApplySexAppraisalModifiers(Pawn partner, string factorName, ref float value)
|
||||
{
|
||||
foreach (var comp in quirks.SelectMany(quirk => quirk.def.GetComps<Comps.SexAppraisalModifier>())
|
||||
.Where(comp => comp.factorName == factorName)
|
||||
.OrderBy(comp => comp.priority))
|
||||
{
|
||||
comp.TryModifyValue(pawn, partner, factorName, ref value);
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyValueModifiers(string valueName, ref float value)
|
||||
{
|
||||
foreach (var comp in quirks.SelectMany(quirk => quirk.def.GetComps<Comps.ValueModifier>())
|
||||
.Where(comp => comp.valueName == valueName)
|
||||
.OrderBy(comp => comp.priority))
|
||||
{
|
||||
comp.TryModifyValue(valueName, ref value);
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyValueModifiers(string valueName, ref int value)
|
||||
{
|
||||
float valueF = value;
|
||||
ApplyValueModifiers(valueName, ref valueF);
|
||||
value = (int)valueF;
|
||||
}
|
||||
|
||||
public override void PostExposeData()
|
||||
{
|
||||
base.PostExposeData();
|
||||
|
||||
Scribe_Collections.Look(ref quirks, "allQuirks", LookMode.Deep);
|
||||
|
||||
if (Scribe.mode == LoadSaveMode.LoadingVars)
|
||||
{
|
||||
if (quirks.RemoveAll((x) => x == null) != 0)
|
||||
{
|
||||
Log.Error("Some quirks were null after loading.");
|
||||
}
|
||||
if (quirks.RemoveAll((x) => x.def == null) != 0)
|
||||
{
|
||||
Log.Error("Some quirks had null def after loading.");
|
||||
}
|
||||
for (int i = 0; i < quirks.Count; i++)
|
||||
{
|
||||
quirks[i].pawn = pawn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string TipString()
|
||||
{
|
||||
if (quirks.Count == 0)
|
||||
{
|
||||
return "NoQuirks".Translate();
|
||||
}
|
||||
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
foreach (var quirk in quirks.OrderBy(q => q.Label))
|
||||
{
|
||||
stringBuilder.AppendLine(quirk.TipString());
|
||||
stringBuilder.AppendLine("");
|
||||
}
|
||||
|
||||
return stringBuilder.ToString().TrimEndNewlines();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fill the QuirkSet from a legacy save string
|
||||
/// </summary>
|
||||
public void ParseQuirkSave(string quirksave)
|
||||
{
|
||||
if (quirksave == "None")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (string name in quirksave.Split(','))
|
||||
{
|
||||
if (name.NullOrEmpty())
|
||||
continue;
|
||||
|
||||
string defName = name.Trim();
|
||||
|
||||
// Old keys doubled as labels. But we can't rely on that becaule def.label can be localized
|
||||
if (defName.Contains(" "))
|
||||
{
|
||||
// To PascalCase
|
||||
defName = defName.Split(' ').Select(part => part.CapitalizeFirst()).Aggregate((x, y) => x + y);
|
||||
}
|
||||
|
||||
QuirkDef def = DefDatabase<QuirkDef>.GetNamed(defName);
|
||||
|
||||
if (def == null)
|
||||
continue;
|
||||
|
||||
quirks.Add(new Quirk(def, pawn));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
25
RJW-Quirks/Modules/Quirks/SexSelectors/BySextype.cs
Normal file
25
RJW-Quirks/Modules/Quirks/SexSelectors/BySextype.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using rjw;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||
{
|
||||
public class BySextype : SexSelector
|
||||
{
|
||||
public xxx.rjwSextype sextype = xxx.rjwSextype.None;
|
||||
|
||||
public override bool SexSatisfies(SexProps sexProps) => sexProps.hasPartner() && sexProps.sexType == sextype;
|
||||
|
||||
public override IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
foreach (string error in base.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (sextype == xxx.rjwSextype.None)
|
||||
{
|
||||
yield return "<sextype> is not filled or has value \"None\"";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using rjw;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||
{
|
||||
public class CanBeImpregnated : SexSelector
|
||||
{
|
||||
public override bool SexSatisfies(SexProps sexProps) => sexProps.hasPartner() && PregnancyHelper.CanImpregnate(sexProps.partner, sexProps.pawn, sexProps.sexType);
|
||||
}
|
||||
}
|
9
RJW-Quirks/Modules/Quirks/SexSelectors/CanImpregnate.cs
Normal file
9
RJW-Quirks/Modules/Quirks/SexSelectors/CanImpregnate.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
using rjw;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||
{
|
||||
public class CanImpregnate : SexSelector
|
||||
{
|
||||
public override bool SexSatisfies(SexProps sexProps) => sexProps.hasPartner() && PregnancyHelper.CanImpregnate(sexProps.pawn, sexProps.partner, sexProps.sexType);
|
||||
}
|
||||
}
|
9
RJW-Quirks/Modules/Quirks/SexSelectors/Clothed.cs
Normal file
9
RJW-Quirks/Modules/Quirks/SexSelectors/Clothed.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
using rjw;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||
{
|
||||
public class Clothed : SexSelector
|
||||
{
|
||||
public override bool SexSatisfies(SexProps sexProps) => !sexProps.pawn.apparel.PsychologicallyNude;
|
||||
}
|
||||
}
|
10
RJW-Quirks/Modules/Quirks/SexSelectors/ISexSelector.cs
Normal file
10
RJW-Quirks/Modules/Quirks/SexSelectors/ISexSelector.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using rjw;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||
{
|
||||
public interface ISexSelector : Shared.IDefPart
|
||||
{
|
||||
void SetParent(QuirkDef quirkDef);
|
||||
bool SexSatisfies(SexProps sexProps);
|
||||
}
|
||||
}
|
20
RJW-Quirks/Modules/Quirks/SexSelectors/LogicalAnd.cs
Normal file
20
RJW-Quirks/Modules/Quirks/SexSelectors/LogicalAnd.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using rjw;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||
{
|
||||
public class LogicalAnd : LogicalMultipart
|
||||
{
|
||||
public override bool SexSatisfies(SexProps sexProps)
|
||||
{
|
||||
for (int i = 0; i < parts.Count; i++)
|
||||
{
|
||||
if (!parts[i].SexSatisfies(sexProps))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
36
RJW-Quirks/Modules/Quirks/SexSelectors/LogicalMultipart.cs
Normal file
36
RJW-Quirks/Modules/Quirks/SexSelectors/LogicalMultipart.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||
{
|
||||
public abstract class LogicalMultipart : SexSelector
|
||||
{
|
||||
public List<ISexSelector> parts = new List<ISexSelector>();
|
||||
|
||||
public override void SetParent(QuirkDef quirkDef)
|
||||
{
|
||||
base.SetParent(quirkDef);
|
||||
parts.ForEach(selector => selector.SetParent(quirkDef));
|
||||
}
|
||||
|
||||
public override IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
foreach (string error in base.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (parts.Count < 2)
|
||||
{
|
||||
yield return "<parts> should have at least 2 elements";
|
||||
}
|
||||
|
||||
foreach (var part in parts)
|
||||
{
|
||||
foreach (string error in part.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
39
RJW-Quirks/Modules/Quirks/SexSelectors/LogicalNot.cs
Normal file
39
RJW-Quirks/Modules/Quirks/SexSelectors/LogicalNot.cs
Normal file
|
@ -0,0 +1,39 @@
|
|||
using rjw;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||
{
|
||||
public class LogicalNot : SexSelector
|
||||
{
|
||||
public ISexSelector negated;
|
||||
|
||||
public override bool SexSatisfies(SexProps sexProps) => !negated.SexSatisfies(sexProps);
|
||||
|
||||
public override void SetParent(QuirkDef quirkDef)
|
||||
{
|
||||
base.SetParent(quirkDef);
|
||||
negated.SetParent(quirkDef);
|
||||
}
|
||||
|
||||
public override IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
foreach (string error in base.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (negated == null)
|
||||
{
|
||||
yield return "<negated> is empty";
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string error in negated.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
20
RJW-Quirks/Modules/Quirks/SexSelectors/LogicalOr.cs
Normal file
20
RJW-Quirks/Modules/Quirks/SexSelectors/LogicalOr.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using rjw;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||
{
|
||||
public class LogicalOr : LogicalMultipart
|
||||
{
|
||||
public override bool SexSatisfies(SexProps sexProps)
|
||||
{
|
||||
for (int i = 0; i < parts.Count; i++)
|
||||
{
|
||||
if (parts[i].SexSatisfies(sexProps))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
23
RJW-Quirks/Modules/Quirks/SexSelectors/Seen.cs
Normal file
23
RJW-Quirks/Modules/Quirks/SexSelectors/Seen.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
using rjw;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||
{
|
||||
public class Seen : SexSelector
|
||||
{
|
||||
// Current implementation works only if somebody sees pawn exactly at the moment quirks are evaluated
|
||||
public override bool SexSatisfies(SexProps sexProps) => sexProps.hasPartner() && SexSeen(sexProps);
|
||||
|
||||
public static bool SexSeen(SexProps sexProps)
|
||||
{
|
||||
bool isZoophile = xxx.is_zoophile(sexProps.pawn);
|
||||
return sexProps.pawn.Map.mapPawns.AllPawnsSpawned.Any(x =>
|
||||
x != sexProps.pawn
|
||||
&& x != sexProps.partner
|
||||
&& !x.Dead
|
||||
&& (isZoophile || !xxx.is_animal(x))
|
||||
&& x.CanSee(sexProps.pawn));
|
||||
}
|
||||
}
|
||||
}
|
19
RJW-Quirks/Modules/Quirks/SexSelectors/SexSelector.cs
Normal file
19
RJW-Quirks/Modules/Quirks/SexSelectors/SexSelector.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using rjw;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||
{
|
||||
public abstract class SexSelector : ISexSelector
|
||||
{
|
||||
protected QuirkDef parentDef;
|
||||
|
||||
public abstract bool SexSatisfies(SexProps sexProps);
|
||||
|
||||
public virtual void SetParent(QuirkDef quirkDef) => parentDef = quirkDef;
|
||||
|
||||
public virtual IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using rjw;
|
||||
|
||||
namespace rjwquirks.Modules.Quirks.SexSelectors
|
||||
{
|
||||
public class WithPreferedPartner : SexSelector
|
||||
{
|
||||
public override bool SexSatisfies(SexProps sexProps) => sexProps.hasPartner() && parentDef.partnerPreference?.PartnerSatisfies(sexProps.pawn, sexProps.partner) == true;
|
||||
}
|
||||
}
|
21
RJW-Quirks/Modules/Shared/Events/RjwEvent.cs
Normal file
21
RJW-Quirks/Modules/Shared/Events/RjwEvent.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Copy of the HistoryEvent.
|
||||
/// Made it it's own thing because it use cases are different
|
||||
/// </summary>
|
||||
public struct RjwEvent
|
||||
{
|
||||
public RjwEventDef def;
|
||||
public SignalArgs args;
|
||||
|
||||
public RjwEvent(RjwEventDef def, params NamedArgument[] args)
|
||||
{
|
||||
this.def = def;
|
||||
this.args = new SignalArgs(args);
|
||||
}
|
||||
}
|
||||
}
|
11
RJW-Quirks/Modules/Shared/Events/RjwEventArgNames.cs
Normal file
11
RJW-Quirks/Modules/Shared/Events/RjwEventArgNames.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace rjwquirks.Modules.Shared.Events
|
||||
{
|
||||
public static class RjwEventArgNames
|
||||
{
|
||||
public static readonly string Pawn = "Pawn";
|
||||
public static readonly string SexProps = "SexProps";
|
||||
public static readonly string Quirk = "Quirk";
|
||||
public static readonly string Record = "Record";
|
||||
public static readonly string Satisfaction = "Satisfaction";
|
||||
}
|
||||
}
|
10
RJW-Quirks/Modules/Shared/Events/RjwEventDef.cs
Normal file
10
RJW-Quirks/Modules/Shared/Events/RjwEventDef.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.Events
|
||||
{
|
||||
public class RjwEventDef : Def
|
||||
{
|
||||
public List<string> obligatoryArgs;
|
||||
}
|
||||
}
|
14
RJW-Quirks/Modules/Shared/Events/RjwEventDefOf.cs
Normal file
14
RJW-Quirks/Modules/Shared/Events/RjwEventDefOf.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using RimWorld;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.Events
|
||||
{
|
||||
[DefOf]
|
||||
public static class RjwEventDefOf
|
||||
{
|
||||
public static readonly RjwEventDef QuirkAddedTo;
|
||||
public static readonly RjwEventDef QuirkRemovedFrom;
|
||||
public static readonly RjwEventDef Orgasm;
|
||||
public static readonly RjwEventDef RecordChanged;
|
||||
public static readonly RjwEventDef PawnSexualized;
|
||||
}
|
||||
}
|
8
RJW-Quirks/Modules/Shared/Events/RjwEventHandler.cs
Normal file
8
RJW-Quirks/Modules/Shared/Events/RjwEventHandler.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace rjwquirks.Modules.Shared.Events
|
||||
{
|
||||
public abstract class RjwEventHandler
|
||||
{
|
||||
public RjwEventHandlerDef def;
|
||||
public abstract void HandleEvent(RjwEvent ev);
|
||||
}
|
||||
}
|
45
RJW-Quirks/Modules/Shared/Events/RjwEventHandlerDef.cs
Normal file
45
RJW-Quirks/Modules/Shared/Events/RjwEventHandlerDef.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.Events
|
||||
{
|
||||
public class RjwEventHandlerDef : Def
|
||||
{
|
||||
public Type workerClass;
|
||||
public List<RjwEventDef> handlesEvents;
|
||||
|
||||
private RjwEventHandler _worker;
|
||||
|
||||
public RjwEventHandler Worker
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_worker == null)
|
||||
{
|
||||
_worker = (RjwEventHandler)Activator.CreateInstance(workerClass);
|
||||
_worker.def = this;
|
||||
}
|
||||
return _worker;
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
foreach (string error in base.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (workerClass == null)
|
||||
{
|
||||
yield return "<workerClass> is empty";
|
||||
}
|
||||
|
||||
if (handlesEvents == null || handlesEvents.Count == 0)
|
||||
{
|
||||
yield return "<handlesEvents> is empty";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
97
RJW-Quirks/Modules/Shared/Events/RjwEventManager.cs
Normal file
97
RJW-Quirks/Modules/Shared/Events/RjwEventManager.cs
Normal file
|
@ -0,0 +1,97 @@
|
|||
using RimWorld;
|
||||
using rjw.Modules.Shared.Logs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.Events
|
||||
{
|
||||
public static class RjwEventManager
|
||||
{
|
||||
private static readonly Dictionary<RjwEventDef, List<RjwEventHandler>> _handlers = BuildHandlerDictionary();
|
||||
private static readonly ILog _logger = LogManager.GetLogger("RjwEventManager");
|
||||
|
||||
/// <summary>
|
||||
/// Routes RJW events to the relevant event handlers based on the def subscriptions
|
||||
/// </summary>
|
||||
public static void NotifyEvent(RjwEvent ev)
|
||||
{
|
||||
//implement own settings later
|
||||
if (Prefs.DevMode)
|
||||
{
|
||||
_logger.Message($"RJW Event {ev.def}{SignalArgsToString(ev.args)}");
|
||||
}
|
||||
|
||||
if (!_handlers.TryGetValue(ev.def, out List<RjwEventHandler> eventHandlers))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Prefs.DevMode)
|
||||
{
|
||||
// Since event args are filled in C#, no reason to waste time checking them outside of the actual mod developement
|
||||
CheckObligatoryArgs(ev);
|
||||
}
|
||||
|
||||
foreach (RjwEventHandler handler in eventHandlers)
|
||||
{
|
||||
try
|
||||
{
|
||||
handler.HandleEvent(ev);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// suppress exceptions so one bad mod wouldn't break everything
|
||||
_logger.Error($"Handler exception when handling {ev.def}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<RjwEventDef, List<RjwEventHandler>> BuildHandlerDictionary()
|
||||
{
|
||||
Dictionary<RjwEventDef, List<RjwEventHandler>> handlers = new Dictionary<RjwEventDef, List<RjwEventHandler>>();
|
||||
|
||||
foreach (RjwEventHandlerDef handlerDef in DefDatabase<RjwEventHandlerDef>.AllDefsListForReading)
|
||||
{
|
||||
foreach (RjwEventDef eventDef in handlerDef.handlesEvents)
|
||||
{
|
||||
if (handlers.ContainsKey(eventDef))
|
||||
{
|
||||
handlers[eventDef].Add(handlerDef.Worker);
|
||||
}
|
||||
else
|
||||
{
|
||||
handlers[eventDef] = new List<RjwEventHandler> { handlerDef.Worker };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return handlers;
|
||||
}
|
||||
|
||||
private static void CheckObligatoryArgs(RjwEvent ev)
|
||||
{
|
||||
foreach (string argName in ev.def.obligatoryArgs)
|
||||
{
|
||||
if (!ev.args.TryGetArg(argName, out _))
|
||||
{
|
||||
_logger.Error($"Got a {ev.def} event without the obligatory argument '{argName}'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string SignalArgsToString(SignalArgs args)
|
||||
{
|
||||
StringBuilder message = new StringBuilder();
|
||||
|
||||
foreach (var arg in args.Args)
|
||||
{
|
||||
message.Append(", ");
|
||||
message.Append(arg);
|
||||
}
|
||||
|
||||
return message.ToString();
|
||||
}
|
||||
}
|
||||
}
|
16
RJW-Quirks/Modules/Shared/IDefPart.cs
Normal file
16
RJW-Quirks/Modules/Shared/IDefPart.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace rjwquirks.Modules.Shared
|
||||
{
|
||||
/// <summary>
|
||||
/// This interface designates that a class is ment to be included in a def and
|
||||
/// instantiated by the Rimworld when the def is loaded
|
||||
/// </summary>
|
||||
public interface IDefPart
|
||||
{
|
||||
/// <summary>
|
||||
/// Needed to be called explicidly in the def's ConfigErrors()
|
||||
/// </summary>
|
||||
IEnumerable<string> ConfigErrors();
|
||||
}
|
||||
}
|
16
RJW-Quirks/Modules/Shared/Selectors/IPartnerSelector.cs
Normal file
16
RJW-Quirks/Modules/Shared/Selectors/IPartnerSelector.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||
{
|
||||
/// <summary>
|
||||
/// Partner selectors are similar to the pawn selectors, but can define relations between two pawns.
|
||||
/// </summary>
|
||||
public interface IPartnerSelector : IDefPart
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns true if the partner satisfies all XML-defined conditions in relation to the pawn.
|
||||
/// Non-commutative
|
||||
/// </summary>
|
||||
bool PartnerSatisfies(Pawn pawn, Pawn partner);
|
||||
}
|
||||
}
|
15
RJW-Quirks/Modules/Shared/Selectors/IPawnSelector.cs
Normal file
15
RJW-Quirks/Modules/Shared/Selectors/IPawnSelector.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||
{
|
||||
/// <summary>
|
||||
/// Pawn selectors are designed to provide a flexible way to define pawn requirements in the defs
|
||||
/// </summary>
|
||||
public interface IPawnSelector : IDefPart
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns true if pawn satisfies all XML-defined conditions
|
||||
/// </summary>
|
||||
bool PawnSatisfies(Pawn pawn);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
using rjw;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PartnerSelectors
|
||||
{
|
||||
public class CanBeImpregnatedBy : PartnerSelector
|
||||
{
|
||||
public override bool PartnerSatisfies(Pawn pawn, Pawn partner) => PregnancyHelper.CanImpregnate(partner, pawn);
|
||||
}
|
||||
}
|
10
RJW-Quirks/Modules/Shared/Selectors/Partner/CanImpregnate.cs
Normal file
10
RJW-Quirks/Modules/Shared/Selectors/Partner/CanImpregnate.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using rjw;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PartnerSelectors
|
||||
{
|
||||
public class CanImpregnate : PartnerSelector
|
||||
{
|
||||
public override bool PartnerSatisfies(Pawn pawn, Pawn partner) => PregnancyHelper.CanImpregnate(pawn, partner);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PartnerSelectors
|
||||
{
|
||||
public class HasOneOfRelations : PartnerSelector
|
||||
{
|
||||
public List<PawnRelationDef> relations;
|
||||
|
||||
private HashSet<PawnRelationDef> relationsHashSet;
|
||||
|
||||
public override bool PartnerSatisfies(Pawn pawn, Pawn partner)
|
||||
{
|
||||
if (relationsHashSet == null)
|
||||
{
|
||||
relationsHashSet = new HashSet<PawnRelationDef>(relations);
|
||||
}
|
||||
|
||||
IEnumerable<PawnRelationDef> pawnRelations = pawn.GetRelations(partner);
|
||||
|
||||
if (pawnRelations.EnumerableNullOrEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!relationsHashSet.Overlaps(pawnRelations))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
foreach (string error in base.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (relations.NullOrEmpty())
|
||||
{
|
||||
yield return "<relations> is empty";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
23
RJW-Quirks/Modules/Shared/Selectors/Partner/LogicalAnd.cs
Normal file
23
RJW-Quirks/Modules/Shared/Selectors/Partner/LogicalAnd.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PartnerSelectors
|
||||
{
|
||||
public class LogicalAnd : LogicalMultipart
|
||||
{
|
||||
public override bool PartnerSatisfies(Pawn pawn, Pawn partner)
|
||||
{
|
||||
if (partner == null)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < parts.Count; i++)
|
||||
{
|
||||
if (!parts[i].PartnerSatisfies(pawn, partner))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
using rjwquirks.Modules.Shared.PawnSelectors;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PartnerSelectors
|
||||
{
|
||||
public abstract class LogicalMultipart : PartnerSelector
|
||||
{
|
||||
public List<IPartnerSelector> parts = new List<IPartnerSelector>();
|
||||
|
||||
public override IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
foreach (string error in base.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (parts.Count < 2)
|
||||
{
|
||||
yield return "<parts> should have at least 2 elements";
|
||||
}
|
||||
|
||||
foreach (var part in parts)
|
||||
{
|
||||
foreach (string error in part.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
34
RJW-Quirks/Modules/Shared/Selectors/Partner/LogicalNot.cs
Normal file
34
RJW-Quirks/Modules/Shared/Selectors/Partner/LogicalNot.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
using rjwquirks.Modules.Shared.PawnSelectors;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PartnerSelectors
|
||||
{
|
||||
public class LogicalNot : PartnerSelector
|
||||
{
|
||||
public IPartnerSelector negated;
|
||||
|
||||
public override bool PartnerSatisfies(Pawn pawn, Pawn partner) => !negated.PartnerSatisfies(pawn, partner);
|
||||
|
||||
public override IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
foreach (string error in base.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (negated == null)
|
||||
{
|
||||
yield return "<negated> is empty";
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string error in negated.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
23
RJW-Quirks/Modules/Shared/Selectors/Partner/LogicalOr.cs
Normal file
23
RJW-Quirks/Modules/Shared/Selectors/Partner/LogicalOr.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PartnerSelectors
|
||||
{
|
||||
public class LogicalOr : LogicalMultipart
|
||||
{
|
||||
public override bool PartnerSatisfies(Pawn pawn, Pawn partner)
|
||||
{
|
||||
if (partner == null)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < parts.Count; i++)
|
||||
{
|
||||
if (parts[i].PartnerSatisfies(pawn, partner))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
using rjwquirks.Modules.Shared.PawnSelectors;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PartnerSelectors
|
||||
{
|
||||
public abstract class PartnerSelector : IPartnerSelector
|
||||
{
|
||||
public abstract bool PartnerSatisfies(Pawn pawn, Pawn partner);
|
||||
|
||||
public virtual IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
26
RJW-Quirks/Modules/Shared/Selectors/Pawn/HasBodyType.cs
Normal file
26
RJW-Quirks/Modules/Shared/Selectors/Pawn/HasBodyType.cs
Normal file
|
@ -0,0 +1,26 @@
|
|||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||
{
|
||||
public class HasBodyType : PawnSelector
|
||||
{
|
||||
public BodyTypeDef bodyType;
|
||||
|
||||
public override bool PawnSatisfies(Pawn pawn) => pawn.story?.bodyType == bodyType;
|
||||
|
||||
public override IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
foreach (string error in base.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (bodyType == null)
|
||||
{
|
||||
yield return "<bodyType> is empty";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
31
RJW-Quirks/Modules/Shared/Selectors/Pawn/HasDegreeOfTrait.cs
Normal file
31
RJW-Quirks/Modules/Shared/Selectors/Pawn/HasDegreeOfTrait.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||
{
|
||||
public class HasDegreeOfTrait : PawnSelector
|
||||
{
|
||||
public TraitDef trait;
|
||||
public int degree = 0;
|
||||
|
||||
public override bool PawnSatisfies(Pawn pawn) => pawn.story?.traits?.HasTrait(trait, degree) == true;
|
||||
|
||||
public override IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
foreach (string error in base.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (trait == null)
|
||||
{
|
||||
yield return "<trait> is empty";
|
||||
}
|
||||
else if (trait.degreeDatas.Find(d => d.degree == degree) == null)
|
||||
{
|
||||
yield return $"{trait.defName} has no data for a degree {degree}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
10
RJW-Quirks/Modules/Shared/Selectors/Pawn/HasFertility.cs
Normal file
10
RJW-Quirks/Modules/Shared/Selectors/Pawn/HasFertility.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using rjw;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||
{
|
||||
public class HasFertility : PawnSelector
|
||||
{
|
||||
public override bool PawnSatisfies(Pawn pawn) => pawn.RaceHasFertility();
|
||||
}
|
||||
}
|
25
RJW-Quirks/Modules/Shared/Selectors/Pawn/HasGender.cs
Normal file
25
RJW-Quirks/Modules/Shared/Selectors/Pawn/HasGender.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||
{
|
||||
public class HasGender : PawnSelector
|
||||
{
|
||||
public Gender gender = Gender.None;
|
||||
|
||||
public override bool PawnSatisfies(Pawn pawn) => pawn.gender == gender;
|
||||
|
||||
public override IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
foreach (string error in base.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (gender == Gender.None)
|
||||
{
|
||||
yield return "<gender> is empty";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
31
RJW-Quirks/Modules/Shared/Selectors/Pawn/HasHumanScaleAge.cs
Normal file
31
RJW-Quirks/Modules/Shared/Selectors/Pawn/HasHumanScaleAge.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
using rjw;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||
{
|
||||
public class HasHumanScaleAge : PawnSelector
|
||||
{
|
||||
public int min = 0;
|
||||
public int max = 1000;
|
||||
|
||||
public override bool PawnSatisfies(Pawn pawn)
|
||||
{
|
||||
int humanScaleAge = SexUtility.ScaleToHumanAge(pawn);
|
||||
return min <= humanScaleAge && humanScaleAge <= max;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
foreach (string error in base.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (min == 0 && max == 1000)
|
||||
{
|
||||
yield return "<min> and/or <max> should be filled";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
44
RJW-Quirks/Modules/Shared/Selectors/Pawn/HasRaceTag.cs
Normal file
44
RJW-Quirks/Modules/Shared/Selectors/Pawn/HasRaceTag.cs
Normal file
|
@ -0,0 +1,44 @@
|
|||
using rjw;
|
||||
using rjwquirks.Data;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||
{
|
||||
public class HasRaceTag : PawnSelector
|
||||
{
|
||||
/// <summary>
|
||||
/// For def load only. Use RaceTag property
|
||||
/// </summary>
|
||||
public string raceTag;
|
||||
|
||||
public RaceTags RaceTag
|
||||
{
|
||||
get
|
||||
{
|
||||
if (RaceTags.TryParse(raceTag, out RaceTags tag))
|
||||
return tag;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool PawnSatisfies(Pawn pawn) => pawn.HasRaceTag(RaceTag);
|
||||
|
||||
public override IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
foreach (string error in base.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (raceTag.NullOrEmpty())
|
||||
{
|
||||
yield return "<raceTag> is empty";
|
||||
}
|
||||
else if (!RaceTags.TryParse(raceTag, out _))
|
||||
{
|
||||
yield return $"\"{raceTag}\" is not a valid RaceTag";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
36
RJW-Quirks/Modules/Shared/Selectors/Pawn/HasSkillLevel.cs
Normal file
36
RJW-Quirks/Modules/Shared/Selectors/Pawn/HasSkillLevel.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||
{
|
||||
public class HasSkillLevel : PawnSelector
|
||||
{
|
||||
public SkillDef skill;
|
||||
public int minLevel = 0;
|
||||
public int maxLevel = 200; // mods can unlock levels past 20
|
||||
|
||||
public override bool PawnSatisfies(Pawn pawn)
|
||||
{
|
||||
int skillLevel = pawn.skills?.GetSkill(skill)?.levelInt ?? -1;
|
||||
return minLevel <= skillLevel && skillLevel <= maxLevel;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
foreach (string error in base.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (skill == null)
|
||||
{
|
||||
yield return "<skill> is empty";
|
||||
}
|
||||
if (minLevel == 0 && maxLevel == 200)
|
||||
{
|
||||
yield return "<minLevel> and/or <maxLevel> should be filled";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
36
RJW-Quirks/Modules/Shared/Selectors/Pawn/HasStatValue.cs
Normal file
36
RJW-Quirks/Modules/Shared/Selectors/Pawn/HasStatValue.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||
{
|
||||
public class HasStatValue : PawnSelector
|
||||
{
|
||||
public StatDef stat;
|
||||
public float minValue = float.MinValue;
|
||||
public float maxValue = float.MaxValue;
|
||||
|
||||
public override bool PawnSatisfies(Pawn pawn)
|
||||
{
|
||||
float statValue = pawn.GetStatValue(stat);
|
||||
return minValue <= statValue && statValue <= maxValue;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
foreach (string error in base.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (stat == null)
|
||||
{
|
||||
yield return "<stat> is empty";
|
||||
}
|
||||
if (minValue == float.MinValue && maxValue == float.MaxValue)
|
||||
{
|
||||
yield return "<minValue> and/or <maxValue> should be filled";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
26
RJW-Quirks/Modules/Shared/Selectors/Pawn/HasTrait.cs
Normal file
26
RJW-Quirks/Modules/Shared/Selectors/Pawn/HasTrait.cs
Normal file
|
@ -0,0 +1,26 @@
|
|||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||
{
|
||||
public class HasTrait : PawnSelector
|
||||
{
|
||||
public TraitDef trait;
|
||||
|
||||
public override bool PawnSatisfies(Pawn pawn) => pawn.story?.traits?.HasTrait(trait) == true;
|
||||
|
||||
public override IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
foreach (string error in base.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (trait == null)
|
||||
{
|
||||
yield return "<trait> is empty";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
10
RJW-Quirks/Modules/Shared/Selectors/Pawn/IsDisfigured.cs
Normal file
10
RJW-Quirks/Modules/Shared/Selectors/Pawn/IsDisfigured.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||
{
|
||||
public class IsDisfigured : PawnSelector
|
||||
{
|
||||
public override bool PawnSatisfies(Pawn pawn) => RelationsUtility.IsDisfigured(pawn);
|
||||
}
|
||||
}
|
9
RJW-Quirks/Modules/Shared/Selectors/Pawn/IsHumanlike.cs
Normal file
9
RJW-Quirks/Modules/Shared/Selectors/Pawn/IsHumanlike.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||
{
|
||||
public class IsHumanlike : PawnSelector
|
||||
{
|
||||
public override bool PawnSatisfies(Pawn pawn) => pawn?.RaceProps?.Humanlike == true;
|
||||
}
|
||||
}
|
10
RJW-Quirks/Modules/Shared/Selectors/Pawn/IsSleeping.cs
Normal file
10
RJW-Quirks/Modules/Shared/Selectors/Pawn/IsSleeping.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||
{
|
||||
public class IsSleeping : PawnSelector
|
||||
{
|
||||
public override bool PawnSatisfies(Pawn pawn) => !pawn.Awake();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
using rjw;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||
{
|
||||
public class IsVisiblyPregnant : PawnSelector
|
||||
{
|
||||
public override bool PawnSatisfies(Pawn pawn) => pawn.IsVisiblyPregnant();
|
||||
}
|
||||
}
|
20
RJW-Quirks/Modules/Shared/Selectors/Pawn/LogicalAnd.cs
Normal file
20
RJW-Quirks/Modules/Shared/Selectors/Pawn/LogicalAnd.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||
{
|
||||
public class LogicalAnd : LogicalMultipart
|
||||
{
|
||||
public override bool PawnSatisfies(Pawn pawn)
|
||||
{
|
||||
for (int i = 0; i < parts.Count; i++)
|
||||
{
|
||||
if (!parts[i].PawnSatisfies(pawn))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
30
RJW-Quirks/Modules/Shared/Selectors/Pawn/LogicalMultipart.cs
Normal file
30
RJW-Quirks/Modules/Shared/Selectors/Pawn/LogicalMultipart.cs
Normal file
|
@ -0,0 +1,30 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||
{
|
||||
public abstract class LogicalMultipart : PawnSelector
|
||||
{
|
||||
public List<IPawnSelector> parts = new List<IPawnSelector>();
|
||||
|
||||
public override IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
foreach (string error in base.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (parts.Count < 2)
|
||||
{
|
||||
yield return "<parts> should have at least 2 elements";
|
||||
}
|
||||
|
||||
foreach (var part in parts)
|
||||
{
|
||||
foreach (string error in part.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
33
RJW-Quirks/Modules/Shared/Selectors/Pawn/LogicalNot.cs
Normal file
33
RJW-Quirks/Modules/Shared/Selectors/Pawn/LogicalNot.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||
{
|
||||
public class LogicalNot : PawnSelector
|
||||
{
|
||||
public IPawnSelector negated;
|
||||
|
||||
public override bool PawnSatisfies(Pawn pawn) => !negated.PawnSatisfies(pawn);
|
||||
|
||||
public override IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
foreach (string error in base.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
if (negated == null)
|
||||
{
|
||||
yield return "<negated> is empty";
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string error in negated.ConfigErrors())
|
||||
{
|
||||
yield return error;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
20
RJW-Quirks/Modules/Shared/Selectors/Pawn/LogicalOr.cs
Normal file
20
RJW-Quirks/Modules/Shared/Selectors/Pawn/LogicalOr.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||
{
|
||||
public class LogicalOr : LogicalMultipart
|
||||
{
|
||||
public override bool PawnSatisfies(Pawn pawn)
|
||||
{
|
||||
for (int i = 0; i < parts.Count; i++)
|
||||
{
|
||||
if (parts[i].PawnSatisfies(pawn))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
17
RJW-Quirks/Modules/Shared/Selectors/Pawn/PawnSelector.cs
Normal file
17
RJW-Quirks/Modules/Shared/Selectors/Pawn/PawnSelector.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace rjwquirks.Modules.Shared.PawnSelectors
|
||||
{
|
||||
public abstract class PawnSelector : IPawnSelector, IPartnerSelector
|
||||
{
|
||||
public abstract bool PawnSatisfies(Pawn pawn);
|
||||
|
||||
public bool PartnerSatisfies(Pawn pawn, Pawn partner) => PawnSatisfies(partner);
|
||||
|
||||
public virtual IEnumerable<string> ConfigErrors()
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue