rjw-quirks/RJW-Quirks/Modules/Quirks/QuirkSet.cs

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));
}
}
}
}