public static void TransferWeaponsToCorrectInventory(List <Pawn> pawns) { if (!(pawns?.Count > 0)) { return; } var missingWeaponsForPawn = new Dictionary <Pawn, List <ThingDefStuffDefPair> >(); var availableThings = new List <ThingWithComps>(); var availableBiocodedThings = new Dictionary <Pawn, List <ThingWithComps> >(); foreach (var pawn in pawns) { var pawnThings = new List <ThingWithComps>(); // add equipped weapon to list if (pawn.equipment?.Primary != null) { pawnThings.Add(pawn.equipment.Primary); } // add all weapons in inventory to list var inventory = pawn.inventory?.innerContainer; if (inventory != null) { // filter out all weapons in inventory foreach (var thing in inventory) { if ((thing.def.IsMeleeWeapon || thing.def.IsRangedWeapon) && thing is ThingWithComps thingWithComps) { pawnThings.Add(thingWithComps); } } } // check if we are looking at a colonist with an inventory if (pawn?.IsColonist == true) { var pawnWeapons = new List <ThingDefStuffDefPair>(CompSidearmMemory.GetMemoryCompForPawn(pawn)?.RememberedWeapons); // first remove things biocoded to this pawn; no-one else can use them anyway for (int i = 0; i < pawnThings.Count;) { var thing = pawnThings[i]; // check if thing is biocoded to this pawn var biocode = thing.TryGetComp <CompBiocodable>(); if (biocode?.Biocoded == true) { if (biocode.CodedPawn == pawn) { // remove from remembered weapon list var weaponMemory = thing.toThingDefStuffDefPair(); if (weaponMemory != null) { pawnWeapons.Remove(weaponMemory); } } else { // add biocoded thing to their own list var codedPawn = biocode.CodedPawn; if (!availableBiocodedThings.ContainsKey(codedPawn)) { availableBiocodedThings.Add(codedPawn, new List <ThingWithComps>()); } availableBiocodedThings[codedPawn].Add(thing); } // remove from thing list pawnThings.Remove(thing); continue; } i++; } // then remove things that fit the remembered weapons found on the pawn if (pawnWeapons.Count > 0) { for (int i = 0; i < pawnThings.Count;) { var thing = pawnThings[i]; // check if thing is remembered var weaponMemory = thing.toThingDefStuffDefPair(); if (weaponMemory != null && pawnWeapons.Contains(weaponMemory)) { // remove remembered weapon and the thing that fits it pawnWeapons.Remove(weaponMemory); pawnThings.Remove(thing); continue; } i++; } } // finally all weapons still in the pawn's remembered weapons list are missing; we will look for them on other pawns if (pawnWeapons.Count > 0 && !missingWeaponsForPawn.ContainsKey(pawn)) { missingWeaponsForPawn.Add(pawn, new List <ThingDefStuffDefPair>()); } foreach (var weapon in pawnWeapons) { missingWeaponsForPawn[pawn].Add(weapon); } } // all things in the pawn's thing list are not remembered weapons for this pawn; they can be used by other pawns foreach (var thing in pawnThings) { availableThings.Add(thing); } } // sort by quality; this way we should give every pawn the best weapon, unless they got a biocoded one availableThings.SortByDescending((thing) => { QualityUtility.TryGetQuality(thing, out QualityCategory qc); return((int)qc); }); // transfer unassigned weapons to pawns missing sidearms foreach (var entry in missingWeaponsForPawn) { var pawn = entry.Key; var missingWeapons = entry.Value; List <ThingWithComps> biocodedToThisPawn = null; if (availableBiocodedThings.ContainsKey(pawn)) { biocodedToThisPawn = availableBiocodedThings[pawn]; } // iterate over every missing weapon for (int i = 0; i < missingWeapons.Count;) { var weaponMemory = missingWeapons[i]; // check available biocoded weapons first if (biocodedToThisPawn != null) { // iterate over biocoded items for (int j = 0; biocodedToThisPawn.Count > j;) { // get ThingDefStuffDefPair for thing var thing = biocodedToThisPawn[j]; var thingMemory = thing.toThingDefStuffDefPair(); // check if thing fits weapon memory if (weaponMemory.Equals(thingMemory)) { //Log.Message($"Transferring '{thing}' from '{ThingOwnerUtility.GetAnyParent<Pawn>(thing)}' ({thing.ParentHolder}) to '{pawn}' [biocoded]"); // transfer weapon if (thing.holdingOwner.TryTransferToContainer(thing, pawn.inventory.innerContainer, 1) == 1) { // remove weapon from missing weapons list and thing from unassigned things list missingWeapons.Remove(weaponMemory); biocodedToThisPawn.Remove(thing); goto CONTINUE; } // if it gets here, tranferring the weapon failed; this should obviously not happen Log.Error($"Failed to transfer '{thing}' from '{ThingOwnerUtility.GetAnyParent<Pawn>(thing)}' ({thing.ParentHolder}) to '{pawn}'! [biocoded]"); } j++; } } // for each missing weapon, we check all things to find it for (int j = 0; j < availableThings.Count;) { // get ThingDefStuffDefPair for thing var thing = availableThings[j]; var thingMemory = thing.toThingDefStuffDefPair(); // all things in this list should have a ThingDefStuffDefPair, remove it if it does not if (thingMemory == null) { Log.Warning($"'{thing}' had null ThingDefStuffDefPair; removing from unassigned things"); availableThings.Remove(thing); continue; } // check if thing fits weapon memory if (weaponMemory.Equals(thingMemory)) { //Log.Message($"Transferring '{thing}' from '{ThingOwnerUtility.GetAnyParent<Pawn>(thing)}' ({thing.ParentHolder}) to '{pawn}' [standard]"); // transfer weapon if (thing.holdingOwner.TryTransferToContainer(thing, pawn.inventory.innerContainer, 1) == 1) { // remove weapon from missing weapons list and thing from unassigned things list missingWeapons.Remove(weaponMemory); availableThings.Remove(thing); goto CONTINUE; } // if it gets here, tranferring the weapon failed; this should obviously not happen Log.Error($"Failed to transfer '{thing}' from '{ThingOwnerUtility.GetAnyParent<Pawn>(thing)}' ({thing.ParentHolder}) to '{pawn}'! [standard]"); } j++; } i++; // if missing weapon was found go here without increasing the index CONTINUE :; } } }