/// <summary> /// Update <see cref="CompAwesomeInventoryLoadout.InventoryMargins"/> whenever a new loadout is assigned to pawn. /// </summary> /// <param name="newLoadout"> The new loadout assigned to pawn. </param> public void UpdateForNewLoadout(AwesomeInventoryLoadout newLoadout) { if (newLoadout == null || this.Loadout == newLoadout) { return; } if (this.InventoryMargins == null) { this.InventoryMargins = new Dictionary <ThingGroupSelector, int>(); } else { this.InventoryMargins.Clear(); } this.Loadout?.RemoveAddNewThingGroupSelectorCallback(this.AddNewThingGroupSelectorCallback); this.Loadout?.RemoveRemoveThingGroupSelectorCallback(this.RemoveThingGroupSelectorCallback); this.Loadout?.RemoveStackCountChangedCallback(this.StackCountChangedCallback); this.UpdateInventoryMargin(newLoadout); newLoadout.AddAddNewThingGroupSelectorCallback(this.AddNewThingGroupSelectorCallback); newLoadout.AddRemoveThingGroupSelectorCallback(this.RemoveThingGroupSelectorCallback); newLoadout.AddStackCountChangedCallback(this.StackCountChangedCallback); Loadout = newLoadout; _initialized = true; }
/// <summary> /// Add loadout to manager and the game's outfit database. /// </summary> /// <param name="loadout"> Loadout to add. </param> public static void AddLoadout(AwesomeInventoryLoadout loadout) { ValidateArg.NotNull(loadout, nameof(loadout)); _loadouts.Add(loadout); Current.Game.outfitDatabase.AllOutfits.Add(loadout); }
/// <summary> /// Initializes a new instance of the <see cref="AwesomeInventoryLoadout"/> class. /// </summary> /// <param name="pawn"> Initialize <see cref="AwesomeInventoryLoadout"/> with items on this <paramref name="pawn"/>. </param> public AwesomeInventoryLoadout(Pawn pawn) { ValidateArg.NotNull(pawn, nameof(pawn)); this.AddItems(pawn.equipment?.AllEquipmentListForReading); this.AddItems(pawn.apparel?.WornApparel); this.AddItems(pawn.inventory?.innerContainer); if (pawn.outfits?.CurrentOutfit?.filter is ThingFilter filter) { this.filter.CopyAllowancesFrom(filter); } else { this.filter.SetAllow(ThingCategoryDefOf.Apparel, true); } this.uniqueId = Current.Game.outfitDatabase.AllOutfits.Max(o => o.uniqueId) + 1; CompAwesomeInventoryLoadout compLoadout = pawn.TryGetComp <CompAwesomeInventoryLoadout>(); this.label = compLoadout?.Loadout == null ? AwesomeInventoryLoadout.GetDefaultLoadoutName(pawn) : LoadoutManager.GetIncrementalLabel(compLoadout.Loadout.label); pawn.SetLoadout(this); }
/// <summary> /// Set Pawn's loadout. Called by a harmony patch, Pawn_OutfitTracker_CurrentOutfit. /// </summary> /// <param name="pawn"> Set loadout on this <paramref name="pawn"/>. </param> /// <param name="loadout"> Loadout to assign to <paramref name="pawn"/>. </param> /// <param name="delay"> If true, put jobs for changing apparel in job queue, otherwise, execute jobs immediately. </param> /// <param name="forced"> If true, update pawn's comp for <paramref name="loadout"/> even though it is the same as current loadout. </param> public static void SetLoadout(this Pawn pawn, AwesomeInventoryLoadout loadout, bool delay = false, bool forced = false) { if (pawn.TryGetComp <CompAwesomeInventoryLoadout>() is CompAwesomeInventoryLoadout comp) { if (comp.Loadout == loadout && !forced) { return; } ApparelOptionUtility.StopDressingJobs(pawn); comp.UpdateForNewLoadout(loadout, delay, forced: forced); if (loadout == pawn.outfits.CurrentOutfit) { return; } pawn.outfits.CurrentOutfit = loadout; if (!comp.HotSwapCostume?.InSameLoadoutTree(loadout) ?? true) { comp.HotSwapCostume = null; comp.LoadoutBeforeHotSwap = null; comp.HotswapState = CompAwesomeInventoryLoadout.HotSwapState.Inactive; } } }
/// <summary> /// Remove outfit from <see cref="LoadoutManager"/>. /// </summary> /// <param name="loadout"> Loadout to remove. </param> /// <param name="fromOutfit"> If ture, this method is called from <see cref="OutfitDatabase.TryDelete(Outfit)"/>. </param> /// <returns> Returns true if loadout is rmeoved successfully. </returns> public static bool TryRemoveLoadout(AwesomeInventoryLoadout loadout, bool fromOutfit = false) { ValidateArg.NotNull(loadout, nameof(loadout)); List <Pawn> pawns = PawnsFinder.AllMapsCaravansAndTravelingTransportPods_Alive_Colonists; List <AwesomeInventoryLoadout> loadouts = loadout.Costumes.Concat(loadout).ToList(); foreach (AwesomeInventoryLoadout l in loadouts) { foreach (Pawn pawn in pawns) { if (pawn.outfits?.CurrentOutfit == l) { Messages.Message("OutfitInUse".Translate(pawn), MessageTypeDefOf.RejectInput, false); return(false); } } } foreach (AwesomeInventoryLoadout l in loadouts) { _loadouts.Remove(l); Current.Game.outfitDatabase.AllOutfits.Remove(l); if (l is AwesomeInventoryCostume costume) { RemoveHotSwapCostume(costume); } } return(true); }
/// <summary> /// Check if <paramref name="loadout"/> is in the same family tree of this costume. /// </summary> /// <param name="loadout"> loadout to check. </param> /// <returns> Returns true if <paramref name="loadout"/> is the parent or sibling of this costume. </returns> public virtual bool InSameLoadoutTree(AwesomeInventoryLoadout loadout) { return(this.CostumeOf(loadout) || (loadout is AwesomeInventoryCostume costume && this.SibilingOf(costume))); }
/// <summary> /// Initializes a new instance of the <see cref="AwesomeInventoryCostume"/> class. /// </summary> /// <param name="loadout"> The loadout this costume creates from. </param> public AwesomeInventoryCostume(AwesomeInventoryLoadout loadout) : base(loadout, true) { ValidateArg.NotNull(loadout, nameof(loadout)); this.label = string.Concat(loadout.label, UIText.Costume.TranslateSimple()); this.Base = loadout; }
/// <summary> /// Handle callback from <see cref="OutfitDatabase.TryDelete(Outfit)"/>. /// </summary> /// <param name="loadout"> Loadout to delete. </param> public static void TryRemoveLoadoutCallback(AwesomeInventoryLoadout loadout) { _loadouts.Remove(loadout); if (loadout?.GetType() == typeof(AwesomeInventoryLoadout)) { foreach (AwesomeInventoryCostume costume in loadout.Costumes) { _loadouts.Remove(costume); Current.Game.outfitDatabase.AllOutfits.Remove(costume); } } }
/// <summary> /// Initializes a new instance of the <see cref="AwesomeInventoryLoadout"/> class. /// </summary> /// <param name="other"> Copy <paramref name="other"/> to this loadout. </param> public AwesomeInventoryLoadout(AwesomeInventoryLoadout other) { ValidateArg.NotNull(other, nameof(other)); foreach (ThingGroupSelector selector in other._thingGroupSelectors) { ThingGroupSelector newSelector = new ThingGroupSelector(selector); this.Add(newSelector); } this.uniqueId = Current.Game.outfitDatabase.AllOutfits.Max(o => o.uniqueId) + 1; this.label = LoadoutManager.GetIncrementalLabel(other.label); }
/// <summary> /// Save states of this costume to xml. /// </summary> public override void ExposeData() { AwesomeInventoryLoadout b = this.Base; Scribe_Collections.Look(ref _costumeItems, nameof(_costumeItems), LookMode.Reference); Scribe_References.Look(ref b, nameof(this.Base)); this.Base = b; if (Scribe.mode == LoadSaveMode.PostLoadInit) { _thingGroupSelectors = this.Base.ThingGroupSelectors; _thingGroupSelectors.ForEach(g => this.Add(g, true)); } }
/// <summary> /// Initializes a new instance of the <see cref="AwesomeInventoryLoadout"/> class. /// </summary> /// <param name="pawn"> Initialize <see cref="AwesomeInventoryLoadout"/> with items on this <paramref name="pawn"/>. </param> public AwesomeInventoryLoadout(Pawn pawn) { ValidateArg.NotNull(pawn, nameof(pawn)); this.AddItems(pawn.equipment?.AllEquipmentListForReading); this.AddItems(pawn.apparel?.WornApparel); this.AddItems(pawn.inventory?.innerContainer); this.uniqueId = Current.Game.outfitDatabase.AllOutfits.Max(o => o.uniqueId) + 1; CompAwesomeInventoryLoadout compLoadout = pawn.TryGetComp <CompAwesomeInventoryLoadout>(); this.label = compLoadout?.Loadout == null ? AwesomeInventoryLoadout.GetDefaultLoadoutName(pawn) : LoadoutManager.GetIncrementalLabel(compLoadout.Loadout.label); pawn.SetLoadout(this); }
/// <summary> /// Set Pawn's loadout. Called by a harmony patch, Pawn_OutfitTracker_CurrentOutfit. /// </summary> /// <param name="pawn"> Set loadout on this <paramref name="pawn"/>. </param> /// <param name="loadout"> Loadout to assign to <paramref name="pawn"/>. </param> public static void SetLoadout(this Pawn pawn, AwesomeInventoryLoadout loadout) { if (pawn.TryGetComp <CompAwesomeInventoryLoadout>() is CompAwesomeInventoryLoadout comp) { if (comp.Loadout == loadout) { return; } comp.UpdateForNewLoadout(loadout); if (loadout == pawn.outfits.CurrentOutfit) { return; } pawn.outfits.CurrentOutfit = loadout; } }
/// <summary> /// Remove outfit from <see cref="LoadoutManager"/>. /// </summary> /// <param name="loadout"> Loadout to remove. </param> /// <param name="fromOutfit"> If ture, this method is called from <see cref="OutfitDatabase.TryDelete(Outfit)"/>. </param> /// <returns> Returns true if loadout is rmeoved successfully. </returns> public static bool TryRemoveLoadout(AwesomeInventoryLoadout loadout, bool fromOutfit = false) { if (fromOutfit) { _loadouts.Remove(loadout); return(true); } else { AcceptanceReport report = Current.Game.outfitDatabase.TryDelete(loadout); if (report.Accepted) { return(true); } Messages.Message(report.Reason, MessageTypeDefOf.RejectInput, historical: false); return(false); } }
/// <summary> /// Initializes a new instance of the <see cref="AwesomeInventoryLoadout"/> class. /// </summary> /// <param name="other"> Copy <paramref name="other"/> to this loadout. </param> /// <param name="shallow"> Make a shallow copy for costume. </param> public AwesomeInventoryLoadout(AwesomeInventoryLoadout other, bool shallow = false) { ValidateArg.NotNull(other, nameof(other)); this.uniqueId = Current.Game.outfitDatabase.AllOutfits.Max(o => o.uniqueId) + 1; this.label = LoadoutManager.GetIncrementalLabel(other.label); if (shallow) { _thingGroupSelectors = other._thingGroupSelectors; _blacklistSelectors = other._blacklistSelectors; this.filter = other.filter; _isDirty = true; foreach (ThingGroupSelector selector in _thingGroupSelectors) { this.AddAddNewThingSelectorCallbackTo(selector); this.AddRemoveThingSelectorCallbackTo(selector); this.AddStackCountChangedCallbackTo(selector); } } else { foreach (ThingGroupSelector selector in other._thingGroupSelectors) { ThingGroupSelector newSelector = new ThingGroupSelector(selector); this.Add(newSelector); } foreach (ThingGroupSelector selector in other._blacklistSelectors) { ThingGroupSelector newSelector = new ThingGroupSelector(selector); this.AddToBlacklist(newSelector); } this.filter.CopyAllowancesFrom(other.filter); this.CopyCostumeFrom(other); } }
/// <summary> /// Change getup when switch loadout. /// </summary> /// <param name="newLoadout"> New loadout pawn switch to. </param> protected void ChangeCostume(AwesomeInventoryLoadout newLoadout) { ValidateArg.NotNull(newLoadout, nameof(newLoadout)); if (newLoadout is AwesomeInventoryCostume costume) { ConcurrentBag <Apparel> wornApparels = new ConcurrentBag <Apparel>(); Parallel.ForEach( Partitioner.Create(_pawn.apparel.WornApparel) , (Apparel apparel) => { if (!costume.CostumeItems.Any(c => c.Allows(apparel, out _))) { wornApparels.Add(apparel); } }); if (wornApparels.Any()) { _pawn.jobs.StopAll(true); foreach (Apparel apparel in wornApparels) { Job job = JobMaker.MakeJob(AwesomeInventory_JobDefOf.AwesomeInventory_Undress, apparel); if (_pawn.CurJob == null) { _pawn.jobs.StartJob(job); } else { _pawn.jobs.jobQueue.EnqueueLast(job); } } } if (costume.CostumeItems.Any()) { ConcurrentBag <Thing> things = new ConcurrentBag <Thing>(); Parallel.ForEach( Partitioner.Create(costume.CostumeItems) , (ThingGroupSelector selector) => { Thing thing = _pawn.inventory.innerContainer.FirstOrDefault(t => selector.Allows(t, out _)); if (thing != null) { things.Add(thing); } }); if (things.Any()) { if (_pawn.jobs.curJob.def != AwesomeInventory_JobDefOf.AwesomeInventory_Undress) { _pawn.jobs.StopAll(true); } foreach (Thing thing in things.Distinct()) { if (thing.def.IsApparel) { Job job = new DressJob(AwesomeInventory_JobDefOf.AwesomeInventory_Dress, thing, false); if (_pawn.CurJob == null) { _pawn.jobs.StartJob(job); } else { _pawn.jobs.jobQueue.EnqueueLast(job); } } else if (thing.def.IsWeapon) { Job job = JobMaker.MakeJob(AwesomeInventory_JobDefOf.AwesomeInventory_MapEquip, thing); if (_pawn.CurJob == null) { _pawn.jobs.StartJob(job); } else { _pawn.jobs.jobQueue.EnqueueLast(job); } } } } } } }
/// <summary> /// Check if this costume is derived from <paramref name="loadout"/>. /// </summary> /// <param name="loadout"> Loadout used for query. </param> /// <returns> Returns true if this costume is derived from <paramref name="loadout"/>. </returns> public virtual bool CostumeOf(AwesomeInventoryLoadout loadout) { ValidateArg.NotNull(loadout, nameof(loadout)); return(loadout.Costumes.Contains(this)); }