340 lines
11 KiB
C#
340 lines
11 KiB
C#
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));
|
|
}
|
|
}
|
|
}
|
|
}
|