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 { /// /// A collection/tracker of pawn's quirks /// public class QuirkSet : ThingComp { protected Pawn pawn; protected List quirks = new List(); 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); } } /// /// QuirkSet owner /// public Pawn Pawn => pawn; /// /// Read-only collection of pawn quirks /// public IReadOnlyCollection AllQuirks => quirks.AsReadOnly(); /// /// Try to add a quirk of to the pawn /// /// Def of quirk to add /// Ignore all restrictions and "just do it" /// Added quirk or null if addiction failed public Quirk AddQuirk(QuirkDef quirkDef, bool ignoreChecks = false) { Quirk quirk = new Quirk(quirkDef, pawn); if (AddQuirk(quirk, ignoreChecks).Accepted) { return quirk; } else { return null; } } /// /// Try to add the to the pawn /// /// Quirk to add /// Ignore all restrictions and "just do it" /// AcceptanceReport 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; } /// /// Try to remove the from the pawn /// /// Quirk to remove /// Ignore all restrictions and "just do it" /// AcceptanceReport 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; } /// /// Check if a quirk of can be added to the pawn /// 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 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; } /// /// Check if a quirk of can be removed from the pawn /// public AcceptanceReport CanBeRemoved(QuirkDef quirkDef) { if (!Contains(quirkDef)) { return AcceptanceReport.WasRejected; } if (quirkDef.rarity == QuirkRarity.ForcedOnly) { return new AcceptanceReport("CannotRemoveForced".Translate()); } return AcceptanceReport.WasAccepted; } /// /// Check if the pawn has a quirk of /// public bool Contains(QuirkDef quirkDef) { for (int i = 0; i < quirks.Count; i++) { if (quirks[i].def == quirkDef) { return true; } } return false; } /// /// Get a quirk of /// public Quirk GetQuirk(QuirkDef quirkDef) { for (int i = 0; i < quirks.Count; i++) { if (quirks[i].def == quirkDef) { return quirks[i]; } } return null; } /// /// Remove all quirks from the pawn /// /// even quirks that can't be removed normaly public void Clear(bool ignoreChecks = false) => new List(quirks).ForEach(quirk => RemoveQuirk(quirk, ignoreChecks)); /// /// Get a collection of quirks that are satified by a particular sex act /// public IEnumerable GetSatisfiedBySex(SexProps props) => quirks.Where(quirk => quirk.def.IsSatisfiedBySex(props)); /// /// Pass the RJW event to every quirk of the pawn /// 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()) .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()) .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(); } /// /// Fill the QuirkSet from a legacy save string /// 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.GetNamed(defName); if (def == null) continue; quirks.Add(new Quirk(def, pawn)); } } } }