예제 #1
0
        /// <summary>
        /// Called when trying to find something to drop (ie coming back from a caravan).  This is useful even on pawns without a loadout.
        /// </summary>
        /// <param name="dropThing">Thing to be dropped from inventory.</param>
        /// <param name="dropCount">Amount to drop from inventory.</param>
        /// <returns></returns>
        static public bool GetAnythingForDrop(this Pawn pawn, out Thing dropThing, out int dropCount)
        {
            dropThing = null;
            dropCount = 0;

            if (pawn.inventory == null || pawn.inventory.innerContainer == null)
            {
                return(false);
            }

            Loadout loadout = pawn.GetLoadout();

            if (loadout == null || loadout.Slots.NullOrEmpty())
            {
                List <HoldRecord> recs = LoadoutManager.GetHoldRecords(pawn);
                if (recs != null)
                {
                    // hand out any inventory item not covered by a HoldRecord.
                    foreach (Thing thing in pawn.inventory.innerContainer)
                    {
                        int        numContained = pawn.inventory.innerContainer.TotalStackCountOfDef(thing.def);
                        HoldRecord rec          = recs.FirstOrDefault(hr => hr.thingDef == thing.def);
                        if (rec == null)
                        {
                            // we don't have a HoldRecord for this thing, drop it.
                            dropThing = thing;
                            dropCount = numContained > dropThing.stackCount ? dropThing.stackCount : numContained;
                            return(true);
                        }

                        if (numContained > rec.count)
                        {
                            dropThing = thing;
                            dropCount = numContained - rec.count;
                            dropCount = dropCount > dropThing.stackCount ? dropThing.stackCount : dropCount;
                            return(true);
                        }
                    }
                }
                else
                {
                    // we have nither a HoldTracker nor a Loadout that we can ask, so just pick stuff at random from Inventory.
                    dropThing = pawn.inventory.innerContainer.RandomElement <Thing>();
                    dropCount = dropThing.stackCount;
                }
            }
            else
            {
                // hand out an item from GetExcessThing...
                return(GetExcessThing(pawn, out dropThing, out dropCount));
            }

            return(false);
        }
예제 #2
0
        public static void SetLoadoutById(this Pawn pawn, int loadoutId)
        {
            Loadout loadout = LoadoutManager.GetLoadoutById(loadoutId);

            if (loadout == null)
            {
                throw new ArgumentNullException("loadout");
            }

            SetLoadout(pawn, loadout);
        }
예제 #3
0
        public static void RemoveLoadout(Loadout loadout)
        {
            Instance._loadouts.Remove(loadout);

            // assign default loadout to pawns that used to use this loadout
            IEnumerable <Pawn> obsolete = AssignedLoadouts.Where(a => a.Value == loadout).Select(a => a.Key);

            foreach (Pawn id in obsolete)
            {
                AssignedLoadouts[id] = DefaultLoadout;
            }
        }
예제 #4
0
        private bool CheckForExcessItems(Pawn pawn)
        {
            //if (pawn.CurJob != null && pawn.CurJob.def == JobDefOf.Tame) return false;
            CompInventory inventory = pawn.TryGetComp <CompInventory>();
            Loadout       loadout   = pawn.GetLoadout();

            if (inventory == null || inventory.container == null || loadout == null || loadout.Slots.NullOrEmpty())
            {
                return(false);
            }
            if (inventory.container.Count > loadout.SlotCount + 1)
            {
                return(true);
            }
            // Check to see if there is at least one loadout slot specifying currently equipped weapon
            ThingWithComps equipment = ((pawn.equipment == null) ? null : pawn.equipment.Primary) ?? null;

            if (equipment != null && !loadout.Slots.Any(slot => slot.Def == equipment.def && slot.Count >= 1))
            {
                return(true);
            }

            // Go through each item in the inventory and see if its part of our loadout
            bool allowDropRaw = Find.TickManager.TicksGame > pawn.mindState?.lastInventoryRawFoodUseTick + ticksBeforeDropRaw;

            foreach (Thing thing in inventory.container)
            {
                if (allowDropRaw || !thing.def.IsNutritionGivingIngestible || thing.def.ingestible.preferability > FoodPreferability.RawTasty)
                {
                    LoadoutSlot slot = loadout.Slots.FirstOrDefault(x => x.Def == thing.def);
                    if (slot == null)
                    {
                        return(true);
                    }
                    int numContained = inventory.container.TotalStackCountOfDef(thing.def);

                    // Add currently equipped gun
                    if (pawn.equipment != null && pawn.equipment.Primary != null)
                    {
                        if (pawn.equipment.Primary.def == slot.Def)
                        {
                            numContained++;
                        }
                    }
                    if (slot.Count < numContained)
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
예제 #5
0
 public Dialog_ManageLoadouts(Loadout loadout)
 {
     CurrentLoadout = null;
     if (loadout != null && !loadout.defaultLoadout)
     {
         CurrentLoadout = loadout;
     }
     SetSource(SourceSelection.Ranged);
     doCloseX = true;
     //doCloseButton = true; //Close button is awkward
     closeOnClickedOutside = true;
     Utility_Loadouts.UpdateColonistCapacities();
 }
 public Dialog_ManageLoadouts(Loadout loadout)
 {
     CurrentLoadout = null;
     if (loadout != null && !loadout.defaultLoadout)
     {
         CurrentLoadout = loadout;
     }
     SetSource(SourceSelection.Ranged);
     doCloseX = true;
     closeOnClickedOutside = true;
     this.closeOnAccept    = false;
     this.closeOnCancel    = false;
     Utility_Loadouts.UpdateColonistCapacities();
 }
예제 #7
0
        public static void SetLoadout(this Pawn pawn, Loadout loadout)
        {
            if (pawn == null)
            {
                throw new ArgumentNullException("pawn");
            }

            if (LoadoutManager.AssignedLoadouts.ContainsKey(pawn))
            {
                LoadoutManager.AssignedLoadouts[pawn] = loadout;
            }
            else
            {
                LoadoutManager.AssignedLoadouts.Add(pawn, loadout);
            }
        }
예제 #8
0
        public static void RemoveLoadout(Loadout loadout)
        {
            if (_current == null)
            {
                return;
            }
            // assign default loadout to pawns that used to use this loadout
            List <Pawn> obsolete = AssignedLoadouts.Where(kvp => kvp.Value == loadout).Select(kvp => kvp.Key).ToList(); // ToList separates this from the dictionary, ienumerable in this case would break as we change the relationship.

            foreach (Pawn id in obsolete)
            {
                AssignedLoadouts[id] = DefaultLoadout;
            }

            _current._loadouts.Remove(loadout);
        }
 private IEnumerable <Widgets.DropdownMenuElement <Loadout> > Button_GenerateMenu(Pawn pawn)
 {
     using (List <Loadout> .Enumerator enu = LoadoutManager.Loadouts.GetEnumerator())
     {
         while (enu.MoveNext())
         {
             Loadout loadout = enu.Current;
             yield return(new Widgets.DropdownMenuElement <Loadout>
             {
                 option = new FloatMenuOption(loadout.LabelCap, delegate()
                 {
                     pawn.SetLoadout(loadout);
                 }),
                 payload = loadout
             });
         }
     }
 }
        /// <summary>
        /// Basically counts the amount of ThingDef that a loadout can have.  Assumes Pawn has a Loadout (caller checked this already).
        /// </summary>
        /// <param name="pawn">Pawn who's loadout and holdtracker is to be inspected.</param>
        /// <param name = "def">ThingDef to match</param>
        /// <param name = "amount">int amount of ThingDef desired to be covered by Loadout/HoldTracker</param>
        /// <returns>int amount of that def that can be had.</returns>
        private bool TrackingSatisfied(Pawn pawn, ThingDef def, int amount)
        {
            // first check loadouts...
            Loadout loadout = pawn.GetLoadout();

            foreach (LoadoutSlot slot in loadout.Slots)
            {
                if (slot.thingDef != null)
                {
                    if (slot.thingDef == def)
                    {
                        amount -= slot.count;
                    }
                }
                else if (slot.genericDef != null)
                {
                    if (slot.genericDef.lambda(def))
                    {
                        amount -= slot.count;
                    }
                }
                if (amount <= 0)
                {
                    return(true);
                }
            }

            // if we got here, also check holdRecords.
            List <HoldRecord> records = pawn.GetHoldRecords();

            if (!records.NullOrEmpty())
            {
                foreach (HoldRecord rec in records)
                {
                    if (rec.thingDef == def)
                    {
                        amount -= rec.count;
                    }
                }
            }

            return(false);
        }
예제 #11
0
        /// <summary>
        /// Similar to GetExcessThing though narrower in scope.  If there is NOT a loadout which covers the equipped item, it should be dropped.
        /// </summary>
        /// <param name="pawn"></param>
        /// <param name="dropEquipment">Thing which should be unequiped.</param>
        /// <returns>bool, true if there is equipment that should be unequipped.</returns>
        static public bool GetExcessEquipment(this Pawn pawn, out ThingWithComps dropEquipment)
        {
            Loadout loadout = pawn.GetLoadout();

            dropEquipment = null;
            if (loadout == null || (loadout != null && loadout.Slots.NullOrEmpty()) || pawn.equipment?.Primary == null)
            {
                return(false);
            }

            LoadoutSlot eqSlot = loadout.Slots.FirstOrDefault(s => s.count >= 1 && ((s.thingDef != null && s.thingDef == pawn.equipment.Primary.def) ||
                                                                                    (s.genericDef != null && s.genericDef.lambda(pawn.equipment.Primary.def))));

            if (eqSlot == null)
            {
                dropEquipment = pawn.equipment.Primary;
                return(true);
            }
            return(false);
        }
예제 #12
0
        // Returns a copy of this loadout slot with a new unique ID and a label based on the original name.
        // LoadoutSlots need to be copied.
        /// <summary>
        /// Handles copying one Loadout to a new Loadout object.
        /// </summary>
        /// <param name="source">Loadout from which to copy properties/fields from.</param>
        /// <returns>new Loadout with copied properties from 'source'</returns>
        /// <remarks>
        /// uniqueID will be different as required.
        /// label will be different as required, but related to original.
        /// Slots are copied (not the same object) but have the same properties as source.Slots.
        /// </remarks>
        static Loadout Copy(Loadout source)
        {
            string newName = source.label;
            Regex  reNum   = new Regex(@"^(.*?)\d+$");

            if (reNum.IsMatch(newName))
            {
                newName = reNum.Replace(newName, @"$1");
            }
            newName = LoadoutManager.GetUniqueLabel(newName);

            Loadout dest = new Loadout(newName);

            dest.defaultLoadout = source.defaultLoadout;
            dest.canBeDeleted   = source.canBeDeleted;
            dest._slots         = new List <LoadoutSlot>();
            foreach (LoadoutSlot slot in source.Slots)
            {
                dest.AddSlot(slot.Copy());
            }
            return(dest);
        }
예제 #13
0
        /// <summary>
        /// Similar to GetExcessThing though narrower in scope.  If there is NOT a loadout which covers the equipped item, it should be dropped.
        /// </summary>
        /// <param name="pawn"></param>
        /// <param name="dropEquipment">Thing which should be unequiped.</param>
        /// <returns>bool, true if there is equipment that should be unequipped.</returns>
        static public bool GetExcessEquipment(this Pawn pawn, out ThingWithComps dropEquipment)
        {
            Loadout loadout = pawn.GetLoadout();

            dropEquipment = null;
            if (loadout == null || (loadout != null && loadout.Slots.NullOrEmpty()) || pawn.equipment?.Primary == null)
            {
                return(false);
            }

            //Check if equipment is part of the loadout
            LoadoutSlot eqSlot = loadout.Slots.FirstOrDefault(s => s.count >= 1 && ((s.thingDef != null && s.thingDef == pawn.equipment.Primary.def) ||
                                                                                    (s.genericDef != null && s.genericDef.lambda(pawn.equipment.Primary.def))));

            //Check if equipment is in the forced pick-up items list
            HoldRecord eqRecord = pawn.GetHoldRecords()?.FirstOrDefault(s => s.count >= 1 && s.thingDef != null && s.thingDef == pawn.equipment.Primary.def);

            if (eqSlot == null && eqRecord == null)
            {
                dropEquipment = pawn.equipment.Primary;
                return(true);
            }
            return(false);
        }
예제 #14
0
 public static string GetWeightAndBulkTip(this Loadout loadout)
 {
     return(loadout.GetWeightTip() + "\n\n" + loadout.GetBulkTip());
 }
        /* Rough Algorithm
         * Need Things so the collection of ammo users that use magazines.  Also need a collection of ammo (ThingDef is OK here).
         * For each weapon (that fits above),
         * -If we have no ammo in inventory that the gun is loaded with, check loadouts/holdtracker for a clip's worth of ammo that the gun contains.
         * --Find ammo the gun uses that we have a clip's worth in inventory (should check it against loadout/holdtracker as well)
         * -If weapon is low on ammo and we have enough in inventory to fill it up.
         *
         * If either of the above are true, trigger a reload.
         */
        /// <summary>
        /// Check's the pawn's equipment and inventory for weapons that could use a reload.
        /// </summary>
        /// <param name="pawn">Pawn to check the equipment and inventory of.</param>
        /// <param name="reloadWeapon">Thing weapon which needs to be reloaded.</param>
        /// <param name="reloadAmmo">AmmoDef ammo to reload the gun with.</param>
        /// <returns>Bool value indicating if the job needs to be done.</returns>
        private bool DoReloadCheck(Pawn pawn, out ThingWithComps reloadWeapon, out AmmoDef reloadAmmo)
        {
            reloadWeapon = null;
            reloadAmmo   = null;

            // First need to create the collections that will be searched.
            List <ThingWithComps> guns      = new List <ThingWithComps>();
            CompInventory         inventory = pawn.TryGetComp <CompInventory>();
            CompAmmoUser          tmpComp;
            Loadout loadout        = pawn.GetLoadout();
            bool    pawnHasLoadout = loadout != null && !loadout.Slots.NullOrEmpty();

            if (inventory == null)
            {
                return(false);                // There isn't any work to do since the pawn doesn't have a CE Inventory.
            }
            if ((tmpComp = pawn.equipment?.Primary?.TryGetComp <CompAmmoUser>()) != null && tmpComp.HasMagazine)
            {
                guns.Add(pawn.equipment.Primary);
            }

            // CompInventory doesn't track equipment and it's desired to check the pawn's equipped weapon before inventory items so need to copy stuff from Inventory Cache.
            guns.AddRange(inventory.rangedWeaponList.Where(t => t.TryGetComp <CompAmmoUser>() != null && t.GetComp <CompAmmoUser>().HasMagazine));

            if (guns.NullOrEmpty())
            {
                return(false);                // There isn't any work to do since the pawn doesn't have any ammo using guns.
            }
            // look at each gun...
            foreach (ThingWithComps gun in guns)
            {
                // Get key stats of the weapon.
                tmpComp = gun.TryGetComp <CompAmmoUser>();
                AmmoDef ammoType     = tmpComp.CurrentAmmo;
                int     ammoAmount   = tmpComp.CurMagCount;
                int     magazineSize = tmpComp.Props.magazineSize;

                // Is the gun loaded with ammo not in a Loadout/HoldTracker?
                if (tmpComp.UseAmmo && pawnHasLoadout && !TrackingSatisfied(pawn, ammoType, magazineSize))
                {
                    // Do we have ammo in the inventory that the gun uses which satisfies requirements? (expensive)
                    AmmoDef matchAmmo = tmpComp.Props.ammoSet.ammoTypes
                                        .Where(al => al.ammo != ammoType)
                                        .Select(al => al.ammo)
                                        .FirstOrDefault(ad => TrackingSatisfied(pawn, ad, magazineSize) &&
                                                        inventory.AmmoCountOfDef(ad) >= magazineSize);

                    if (matchAmmo != null)
                    {
                        reloadWeapon = gun;
                        reloadAmmo   = matchAmmo;
                        return(true);
                    }
                }

                // Is the gun low on ammo?
                if (tmpComp.CurMagCount < magazineSize)
                {
                    // Do we have enough ammo in the inventory to top it off?
                    if (!tmpComp.UseAmmo || inventory.AmmoCountOfDef(ammoType) >= (magazineSize - tmpComp.CurMagCount))
                    {
                        reloadWeapon = gun;
                        reloadAmmo   = ammoType;
                        return(true);
                        //} else {  // (ProfoundDarkness) I think the idea of this branch was that the JobGiver might initiate fetching ammo but it actually runs AFTER the one that fetches ammo for loadout.
                        // There wasn't enough in the inventory to top it off.  At this point we know the loadout is satisfied for this ammo...
                        // We could do a more strict check to see if the pawn's loadout is satisfied to pick up ammo and if not swap to another ammo...?
                    }
                }
            }

            return(false);
        }
예제 #16
0
        public override void DoWindowContents(Rect canvas)
        {
            // fix weird zooming bug
            Text.Font = GameFont.Small;

            // SET UP RECTS
            // top buttons
            Rect selectRect = new Rect(0f, 0f, canvas.width * .2f, _topAreaHeight);
            Rect newRect    = new Rect(selectRect.xMax + _margin, 0f, canvas.width * .2f, _topAreaHeight);
            Rect copyRect   = new Rect(newRect.xMax + _margin, 0f, canvas.width * .2f, _topAreaHeight);
            Rect deleteRect = new Rect(copyRect.xMax + _margin, 0f, canvas.width * .2f, _topAreaHeight);

            // main areas
            Rect nameRect = new Rect(
                0f,
                _topAreaHeight + _margin * 2,
                (canvas.width - _margin) / 2f,
                24f);

            Rect slotListRect = new Rect(
                0f,
                nameRect.yMax + _margin,
                (canvas.width - _margin) / 2f,
                canvas.height - _topAreaHeight - nameRect.height - _barHeight * 2 - _margin * 5);

            Rect weightBarRect = new Rect(slotListRect.xMin, slotListRect.yMax + _margin, slotListRect.width, _barHeight);
            Rect bulkBarRect   = new Rect(weightBarRect.xMin, weightBarRect.yMax + _margin, weightBarRect.width, _barHeight);

            Rect sourceButtonRect = new Rect(
                slotListRect.xMax + _margin,
                _topAreaHeight + _margin * 2,
                (canvas.width - _margin) / 2f,
                24f);

            Rect selectionRect = new Rect(
                slotListRect.xMax + _margin,
                sourceButtonRect.yMax + _margin,
                (canvas.width - _margin) / 2f,
                canvas.height - 24f - _topAreaHeight - _margin * 3);

            LoadoutManager.SortLoadouts();
            List <Loadout> loadouts = LoadoutManager.Loadouts.Where(l => !l.defaultLoadout).ToList();

            // DRAW CONTENTS
            // buttons
            // select loadout
            if (Widgets.ButtonText(selectRect, "CE_SelectLoadout".Translate()))
            {
                List <FloatMenuOption> options = new List <FloatMenuOption>();

                if (loadouts.Count == 0)
                {
                    options.Add(new FloatMenuOption("CE_NoLoadouts".Translate(), null));
                }
                else
                {
                    for (int i = 0; i < loadouts.Count; i++)
                    {
                        int local_i = i;
                        options.Add(new FloatMenuOption(loadouts[i].LabelCap, delegate
                                                        { CurrentLoadout = loadouts[local_i]; }));
                    }
                }

                Find.WindowStack.Add(new FloatMenu(options));
            }
            // create loadout
            if (Widgets.ButtonText(newRect, "CE_NewLoadout".Translate()))
            {
                Loadout loadout = new Loadout();
                loadout.AddBasicSlots();
                LoadoutManager.AddLoadout(loadout);
                CurrentLoadout = loadout;
            }
            // copy loadout
            if (CurrentLoadout != null && Widgets.ButtonText(copyRect, "CE_CopyLoadout".Translate()))
            {
                CurrentLoadout = CurrentLoadout.Copy();
                LoadoutManager.AddLoadout(CurrentLoadout);
            }
            // delete loadout
            if (loadouts.Any(l => l.canBeDeleted) && Widgets.ButtonText(deleteRect, "CE_DeleteLoadout".Translate()))
            {
                List <FloatMenuOption> options = new List <FloatMenuOption>();

                for (int i = 0; i < loadouts.Count; i++)
                {
                    int local_i = i;

                    // don't allow deleting the default loadout
                    if (!loadouts[i].canBeDeleted)
                    {
                        continue;
                    }
                    options.Add(new FloatMenuOption(loadouts[i].LabelCap,
                                                    delegate
                    {
                        if (CurrentLoadout == loadouts[local_i])
                        {
                            CurrentLoadout = LoadoutManager.DefaultLoadout;
                        }
                        LoadoutManager.RemoveLoadout(loadouts[local_i]);
                    }));
                }

                Find.WindowStack.Add(new FloatMenu(options));
            }

            // draw notification if no loadout selected
            if (CurrentLoadout == null)
            {
                Text.Anchor = TextAnchor.MiddleCenter;
                GUI.color   = Color.grey;
                Widgets.Label(canvas, "CE_NoLoadoutSelected".Translate());
                GUI.color   = Color.white;
                Text.Anchor = TextAnchor.UpperLeft;

                // and stop further drawing
                return;
            }

            // name
            DrawNameField(nameRect);

            // source selection
            DrawSourceSelection(sourceButtonRect);

            // selection area
            DrawSlotSelection(selectionRect);

            // current slots
            DrawSlotList(slotListRect);

            // bars
            if (CurrentLoadout != null)
            {
                Utility_Loadouts.DrawBar(weightBarRect, CurrentLoadout.Weight, Utility_Loadouts.medianWeightCapacity, "CE_Weight".Translate(), CurrentLoadout.GetWeightTip());
                Utility_Loadouts.DrawBar(bulkBarRect, CurrentLoadout.Bulk, Utility_Loadouts.medianBulkCapacity, "CE_Bulk".Translate(), CurrentLoadout.GetBulkTip());
            }

            // done!
        }
예제 #17
0
        protected override void DrawPawnRow(Rect rect, Pawn p)
        {
            // available space for row
            Rect rowRect = new Rect(rect.x + 165f, rect.y, rect.width - 165f, rect.height);

            // response button rect
            Vector2 responsePos = new Vector2(rowRect.xMin, rowRect.yMin + (rowRect.height - 24f) / 2f);

            // offset rest of row for that button, so we don't have to mess with all the other rect calculations
            rowRect.xMin += 24f + _margin;

            // label + buttons for outfit
            Rect outfitRect = new Rect(rowRect.xMin,
                                       rowRect.yMin,
                                       rowRect.width * (1f / 4f) + (_margin + _buttonSize) / 2f,
                                       rowRect.height);

            Rect labelOutfitRect = new Rect(outfitRect.xMin,
                                            outfitRect.yMin,
                                            outfitRect.width - _margin * 3 - _buttonSize * 2,
                                            outfitRect.height)
                                   .ContractedBy(_margin / 2f);
            Rect editOutfitRect = new Rect(labelOutfitRect.xMax + _margin,
                                           outfitRect.yMin + ((outfitRect.height - _buttonSize) / 2),
                                           _buttonSize,
                                           _buttonSize);
            Rect forcedOutfitRect = new Rect(labelOutfitRect.xMax + _buttonSize + _margin * 2,
                                             outfitRect.yMin + ((outfitRect.height - _buttonSize) / 2),
                                             _buttonSize,
                                             _buttonSize);

            // drucg policy
            Rect drugRect = new Rect(outfitRect.xMax,
                                     rowRect.yMin,
                                     rowRect.width * (1f / 4f) - (_margin + _buttonSize) / 2f,
                                     rowRect.height);
            Rect labelDrugRect = new Rect(drugRect.xMin,
                                          drugRect.yMin,
                                          drugRect.width - _margin * 2 - _buttonSize,
                                          drugRect.height)
                                 .ContractedBy(_margin / 2f);
            Rect editDrugRect = new Rect(labelDrugRect.xMax + _margin,
                                         drugRect.yMin + ((drugRect.height - _buttonSize) / 2),
                                         _buttonSize,
                                         _buttonSize);

            // label + button for loadout
            Rect loadoutRect = new Rect(drugRect.xMax,
                                        rowRect.yMin,
                                        rowRect.width * (1f / 4f) - (_margin + _buttonSize) / 2f,
                                        rowRect.height);
            Rect labelLoadoutRect = new Rect(loadoutRect.xMin,
                                             loadoutRect.yMin,
                                             loadoutRect.width - _margin * 2 - _buttonSize,
                                             loadoutRect.height)
                                    .ContractedBy(_margin / 2f);
            Rect editLoadoutRect = new Rect(labelLoadoutRect.xMax + _margin,
                                            loadoutRect.yMin + ((loadoutRect.height - _buttonSize) / 2),
                                            _buttonSize,
                                            _buttonSize);

            // fight or flight button
            HostilityResponseModeUtility.DrawResponseButton(responsePos, p);

            // weight + bulk indicators
            Rect weightRect = new Rect(loadoutRect.xMax, rowRect.yMin, rowRect.width * (1f / 8f) - _margin, rowRect.height).ContractedBy(_margin / 2f);
            Rect bulkRect   = new Rect(weightRect.xMax + _margin, rowRect.yMin, rowRect.width * (1f / 8f) - _margin, rowRect.height).ContractedBy(_margin / 2f);

            // OUTFITS
            // main button
            if (Widgets.ButtonText(labelOutfitRect, p.outfits.CurrentOutfit.label, true, false))
            {
                List <FloatMenuOption> options = new List <FloatMenuOption>();
                foreach (Outfit current in Current.Game.outfitDatabase.AllOutfits)
                {
                    // need to create a local copy for delegate
                    Outfit localOut = current;
                    options.Add(new FloatMenuOption(localOut.label, delegate
                    {
                        p.outfits.CurrentOutfit = localOut;
                    }, MenuOptionPriority.Default, null, null));
                }
                Find.WindowStack.Add(new FloatMenu(options, optionalTitle, false));
            }

            // edit button
            TooltipHandler.TipRegion(editOutfitRect, "CE_EditX".Translate("CE_outfit".Translate() + " " + p.outfits.CurrentOutfit.label));
            if (Widgets.ButtonImage(editOutfitRect, _iconEdit))
            {
                Text.Font = GameFont.Small;
                Find.WindowStack.Add(new Dialog_ManageOutfits(p.outfits.CurrentOutfit));
            }

            // clear forced button
            if (p.outfits.forcedHandler.SomethingIsForced)
            {
                TooltipHandler.TipRegion(forcedOutfitRect, "ClearForcedApparel".Translate());
                if (Widgets.ButtonImage(forcedOutfitRect, _iconClearForced))
                {
                    p.outfits.forcedHandler.Reset();
                }
                TooltipHandler.TipRegion(forcedOutfitRect, new TipSignal(delegate
                {
                    string text = "ForcedApparel".Translate() + ":\n";
                    foreach (Apparel current2 in p.outfits.forcedHandler.ForcedApparel)
                    {
                        text = text + "\n   " + current2.LabelCap;
                    }
                    return(text);
                }, p.GetHashCode() * 612));
            }

            // DRUG POLICY
            // main button
            string textDrug = p.drugs.CurrentPolicy.label;

            if (p.story != null && p.story.traits != null)
            {
                Trait trait = p.story.traits.GetTrait(TraitDefOf.DrugDesire);
                if (trait != null)
                {
                    textDrug = textDrug + " (" + trait.Label + ")";
                }
            }
            if (Widgets.ButtonText(labelDrugRect, textDrug, true, false, true))
            {
                List <FloatMenuOption> list = new List <FloatMenuOption>();
                foreach (DrugPolicy current in Current.Game.drugPolicyDatabase.AllPolicies)
                {
                    DrugPolicy localAssignedDrugs = current;
                    list.Add(new FloatMenuOption(current.label, delegate
                    {
                        p.drugs.CurrentPolicy = localAssignedDrugs;
                    }, MenuOptionPriority.Default, null, null, 0f, null));
                }
                Find.WindowStack.Add(new FloatMenu(list));
                PlayerKnowledgeDatabase.KnowledgeDemonstrated(ConceptDefOf.DrugPolicies, KnowledgeAmount.Total);
            }


            // edit button
            TooltipHandler.TipRegion(editDrugRect, "CE_EditX".Translate("CE_drugs".Translate() + " " + p.drugs.CurrentPolicy.label));
            if (Widgets.ButtonImage(editDrugRect, _iconEdit))
            {
                Text.Font = GameFont.Small;
                Find.WindowStack.Add(new Dialog_ManageDrugPolicies(p.drugs.CurrentPolicy));
                PlayerKnowledgeDatabase.KnowledgeDemonstrated(ConceptDefOf.DrugPolicies, KnowledgeAmount.Total);
            }

            // LOADOUTS
            // main button
            if (Widgets.ButtonText(labelLoadoutRect, p.GetLoadout().LabelCap, true, false))
            {
                List <FloatMenuOption> options = new List <FloatMenuOption>();
                foreach (Loadout loadout in LoadoutManager.Loadouts)
                {
                    // need to create a local copy for delegate
                    Loadout localLoadout = loadout;
                    options.Add(new FloatMenuOption(localLoadout.LabelCap, delegate
                    {
                        p.SetLoadout(localLoadout);
                    }, MenuOptionPriority.Default, null, null));
                }
                Find.WindowStack.Add(new FloatMenu(options, optionalTitle, false));
            }

            // edit button
            TooltipHandler.TipRegion(editLoadoutRect, "CE_EditX".Translate("CE_loadout".Translate() + " " + p.GetLoadout().LabelCap));
            if (Widgets.ButtonImage(editLoadoutRect, _iconEdit))
            {
                Find.WindowStack.Add(new Dialog_ManageLoadouts(p.GetLoadout()));
            }

            // STATUS BARS
            // fetch the comp
            CompInventory comp = p.TryGetComp <CompInventory>();

            if (comp != null)
            {
                Utility_Loadouts.DrawBar(bulkRect, comp.currentBulk, comp.capacityBulk, "", p.GetBulkTip());
                Utility_Loadouts.DrawBar(weightRect, comp.currentWeight, comp.capacityWeight, "", p.GetWeightTip());
            }
        }
예제 #18
0
        /// <summary>
        /// Tries to give the pawn a job related to picking up or dropping an item from their inventory.
        /// </summary>
        /// <param name="pawn">Pawn to which the job is given.</param>
        /// <returns>Job that the pawn was instructed to do, be it hauling a dropped Thing or going and getting a Thing.</returns>
        protected override Job TryGiveJob(Pawn pawn)
        {
            // Get inventory
            CompInventory inventory = pawn.TryGetComp <CompInventory>();

            if (inventory == null)
            {
                return(null);
            }

            Loadout loadout = pawn.GetLoadout();

            if (loadout != null)
            {
                ThingWithComps dropEq;
                if (pawn.GetExcessEquipment(out dropEq))
                {
                    ThingWithComps droppedEq;
                    if (pawn.equipment.TryDropEquipment(pawn.equipment.Primary, out droppedEq, pawn.Position, false))
                    {
                        if (droppedEq != null)
                        {
                            return(HaulAIUtility.HaulToStorageJob(pawn, droppedEq));
                        }
                        Log.Error(string.Concat(pawn, " tried dropping ", dropEq, " from loadout but resulting thing is null"));
                    }
                }
                Thing dropThing;
                int   dropCount;
                if (pawn.GetExcessThing(out dropThing, out dropCount))
                {
                    Thing droppedThing;
                    if (inventory.container.TryDrop(dropThing, pawn.Position, pawn.Map, ThingPlaceMode.Near, dropCount, out droppedThing))
                    {
                        if (droppedThing != null)
                        {
                            return(HaulAIUtility.HaulToStorageJob(pawn, droppedThing));
                        }
                        Log.Error(string.Concat(pawn, " tried dropping ", dropThing, " from loadout but resulting thing is null"));
                    }
                }

                // Find missing items
                ItemPriority priority;
                Thing        closestThing;
                int          count;
                Pawn         carriedBy;
                bool         doEquip      = false;
                LoadoutSlot  prioritySlot = GetPrioritySlot(pawn, out priority, out closestThing, out count, out carriedBy);
                // moved logic to detect if should equip vs put in inventory here...
                if (closestThing != null)
                {
                    if (closestThing.TryGetComp <CompEquippable>() != null &&
                        !(pawn.story != null && pawn.WorkTagIsDisabled(WorkTags.Violent)) &&
                        (pawn.health != null && pawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation)) &&
                        (pawn.equipment == null || pawn.equipment.Primary == null || !loadout.Slots.Any(s => s.thingDef == pawn.equipment.Primary.def ||
                                                                                                        (s.genericDef != null && s.countType == LoadoutCountType.pickupDrop &&
                                                                                                         s.genericDef.lambda(pawn.equipment.Primary.def)))))
                    {
                        doEquip = true;
                    }
                    if (carriedBy == null)
                    {
                        // Equip gun if unarmed or current gun is not in loadout
                        if (doEquip)
                        {
                            return(new Job(JobDefOf.Equip, closestThing));
                        }
                        return(new Job(JobDefOf.TakeInventory, closestThing)
                        {
                            count = Mathf.Min(closestThing.stackCount, count)
                        });
                    }
                    else
                    {
                        return(new Job(CE_JobDefOf.TakeFromOther, closestThing, carriedBy, doEquip ? pawn : null)
                        {
                            count = doEquip ? 1 : Mathf.Min(closestThing.stackCount, count)
                        });
                    }
                }
            }
            return(null);
        }
예제 #19
0
        /// <summary>
        /// This starts the work of finding something lacking that the pawn should pickup.
        /// </summary>
        /// <param name="pawn">Pawn who's inventory and loadout should be considered.</param>
        /// <param name="priority">Priority value for how important doing this job is.</param>
        /// <param name="closestThing">The thing found to be picked up.</param>
        /// <param name="count">The amount of closestThing to pickup.  Already checked if inventory can hold it.</param>
        /// <param name="carriedBy">If unable to find something on the ground to pickup, the pawn (pack animal/prisoner) which has the item to take.</param>
        /// <returns>LoadoutSlot which has something that can be picked up.</returns>
        private LoadoutSlot GetPrioritySlot(Pawn pawn, out ItemPriority priority, out Thing closestThing, out int count, out Pawn carriedBy)
        {
            priority = ItemPriority.None;
            LoadoutSlot slot = null;

            closestThing = null;
            count        = 0;
            carriedBy    = null;

            CompInventory inventory = pawn.TryGetComp <CompInventory>();

            if (inventory != null && inventory.container != null)
            {
                Loadout loadout = pawn.GetLoadout();
                if (loadout != null && !loadout.Slots.NullOrEmpty())
                {
                    // Need to generate a dictionary and nibble like when dropping in order to allow for conflicting loadouts to work properly.
                    Dictionary <ThingDef, Integer> listing = pawn.GetStorageByThingDef();

                    // process each loadout slot... (While the LoadoutSlot.countType property only really makes sense in the context of genericDef != null, it should be the correct value (pickupDrop) on .thingDef != null.)
                    foreach (LoadoutSlot curSlot in loadout.Slots.Where(s => s.countType != LoadoutCountType.dropExcess))
                    {
                        Thing        curThing    = null;
                        ItemPriority curPriority = ItemPriority.None;
                        Pawn         curCarrier  = null;
                        int          wantCount   = curSlot.count;

                        if (curSlot.thingDef != null)
                        {
                            if (listing.ContainsKey(curSlot.thingDef))
                            {
                                int amount = listing[curSlot.thingDef].value >= wantCount ? wantCount : listing[curSlot.thingDef].value;
                                listing[curSlot.thingDef].value -= amount;
                                wantCount -= amount;
                                if (listing[curSlot.thingDef].value <= 0)
                                {
                                    listing.Remove(curSlot.thingDef);
                                }
                            }
                        }
                        if (curSlot.genericDef != null)
                        {
                            List <ThingDef> killKeys = new List <ThingDef>();
                            int             amount;
                            foreach (ThingDef def in listing.Keys.Where(td => curSlot.genericDef.lambda(td)))
                            {
                                amount              = listing[def].value >= wantCount ? wantCount : listing[def].value;
                                listing[def].value -= amount;
                                wantCount          -= amount;
                                if (listing[def].value <= 0)
                                {
                                    killKeys.Add(def);
                                }
                                if (wantCount <= 0)
                                {
                                    break;
                                }
                            }
                            foreach (ThingDef def in killKeys) // oddly enough removing a dictionary entry while enumerating hasn't caused a problem but this is the 'correct' way based on reading.
                            {
                                listing.Remove(def);
                            }
                        }
                        if (wantCount > 0)
                        {
                            FindPickup(pawn, curSlot, wantCount, out curPriority, out curThing, out curCarrier);

                            if (curPriority > priority && curThing != null && inventory.CanFitInInventory(curThing, out count))
                            {
                                priority     = curPriority;
                                slot         = curSlot;
                                count        = count >= wantCount ? wantCount : count;
                                closestThing = curThing;
                                if (curCarrier != null)
                                {
                                    carriedBy = curCarrier;
                                }
                            }
                            if (priority >= ItemPriority.LowStock)
                            {
                                break;
                            }
                        }
                    }
                }
            }

            return(slot);
        }
예제 #20
0
        protected override void FillTab()
        {
            // get the inventory comp
            CompInventory comp = SelPawn.TryGetComp <CompInventory>();

            // set up rects
            Rect listRect = new Rect(
                _margin,
                _topPadding,
                size.x - 2 * _margin,
                size.y - _topPadding - _margin);

            if (comp != null)
            {
                PlayerKnowledgeDatabase.KnowledgeDemonstrated(CE_ConceptDefOf.CE_InventoryWeightBulk, KnowledgeAmount.FrameDisplayed);

                // adjust rects if comp found
                listRect.height -= (_margin / 2 + _barHeight) * 2;
                Rect weightRect = new Rect(_margin, listRect.yMax + _margin / 2, listRect.width, _barHeight);
                Rect bulkRect   = new Rect(_margin, weightRect.yMax + _margin / 2, listRect.width, _barHeight);

                // draw bars
                Utility_Loadouts.DrawBar(bulkRect, comp.currentBulk, comp.capacityBulk, "CE_Bulk".Translate(), SelPawn.GetBulkTip());
                Utility_Loadouts.DrawBar(weightRect, comp.currentWeight, comp.capacityWeight, "CE_Weight".Translate(), SelPawn.GetWeightTip());

                // draw text overlays on bars
                Text.Font   = GameFont.Small;
                Text.Anchor = TextAnchor.MiddleCenter;

                string currentBulk  = CE_StatDefOf.CarryBulk.ValueToString(comp.currentBulk, CE_StatDefOf.CarryBulk.toStringNumberSense);
                string capacityBulk = CE_StatDefOf.CarryBulk.ValueToString(comp.capacityBulk, CE_StatDefOf.CarryBulk.toStringNumberSense);
                Widgets.Label(bulkRect, currentBulk + "/" + capacityBulk);

                string currentWeight  = comp.currentWeight.ToString("0.#");
                string capacityWeight = CE_StatDefOf.CarryWeight.ValueToString(comp.capacityWeight, CE_StatDefOf.CarryWeight.toStringNumberSense);
                Widgets.Label(weightRect, currentWeight + "/" + capacityWeight);

                Text.Anchor = TextAnchor.UpperLeft;
            }

            // start drawing list (rip from ITab_Pawn_Gear)

            GUI.BeginGroup(listRect);
            Text.Font = GameFont.Small;
            GUI.color = Color.white;
            Rect outRect  = new Rect(0f, 0f, listRect.width, listRect.height);
            Rect viewRect = new Rect(0f, 0f, listRect.width - 16f, _scrollViewHeight);

            Widgets.BeginScrollView(outRect, ref _scrollPosition, viewRect);
            float num = 0f;

            TryDrawComfyTemperatureRange(ref num, viewRect.width);
            if (ShouldShowOverallArmor(SelPawnForGear))
            {
                Widgets.ListSeparator(ref num, viewRect.width, "OverallArmor".Translate());
                TryDrawOverallArmor(ref num, viewRect.width, StatDefOf.ArmorRating_Blunt, "ArmorBlunt".Translate(), " " + "CE_MPa".Translate());
                TryDrawOverallArmor(ref num, viewRect.width, StatDefOf.ArmorRating_Sharp, "ArmorSharp".Translate(), "CE_mmRHA".Translate());
                TryDrawOverallArmor(ref num, viewRect.width, StatDefOf.ArmorRating_Heat, "ArmorHeat".Translate(), "%");
            }
            if (ShouldShowEquipment(SelPawnForGear))
            {
                Widgets.ListSeparator(ref num, viewRect.width, "Equipment".Translate());
                foreach (ThingWithComps current in SelPawnForGear.equipment.AllEquipmentListForReading)
                {
                    DrawThingRow(ref num, viewRect.width, current);
                }
            }
            if (ShouldShowApparel(SelPawnForGear))
            {
                Widgets.ListSeparator(ref num, viewRect.width, "Apparel".Translate());
                foreach (Apparel current2 in from ap in SelPawnForGear.apparel.WornApparel
                         orderby ap.def.apparel.bodyPartGroups[0].listOrder descending
                         select ap)
                {
                    DrawThingRow(ref num, viewRect.width, current2);
                }
            }
            if (ShouldShowInventory(SelPawnForGear))
            {
                // get the loadout so we can make a decision to show a button.
                bool    showMakeLoadout = false;
                Loadout curLoadout      = SelPawnForGear.GetLoadout();
                if (SelPawnForGear.IsColonist && (curLoadout == null || curLoadout.Slots.NullOrEmpty()) && (SelPawnForGear.inventory.innerContainer.Any() || SelPawnForGear.equipment?.Primary != null))
                {
                    showMakeLoadout = true;
                }

                if (showMakeLoadout)
                {
                    num += 3;        // Make a little room for the button.
                }
                float buttonY = num; // Could be accomplished with seperator being after the button...

                Widgets.ListSeparator(ref num, viewRect.width, "Inventory".Translate());

                // only offer this button if the pawn has no loadout or has the default loadout and there are things/equipment...
                if (showMakeLoadout)
                {
                    Rect loadoutButtonRect = new Rect(viewRect.width / 2, buttonY, viewRect.width / 2, 26f); // button is half the available width...
                    if (Widgets.ButtonText(loadoutButtonRect, "CE_MakeLoadout".Translate()))
                    {
                        Loadout loadout = SelPawnForGear.GenerateLoadoutFromPawn();
                        LoadoutManager.AddLoadout(loadout);
                        SelPawnForGear.SetLoadout(loadout);

                        // Opening this window is the same way as if from the assign tab so should be correct.
                        Find.WindowStack.Add(new Dialog_ManageLoadouts(SelPawnForGear.GetLoadout()));
                    }
                }

                workingInvList.Clear();
                workingInvList.AddRange(SelPawnForGear.inventory.innerContainer);
                for (int i = 0; i < workingInvList.Count; i++)
                {
                    DrawThingRow(ref num, viewRect.width, workingInvList[i].GetInnerIfMinified(), true);
                }
            }
            if (Event.current.type == EventType.Layout)
            {
                _scrollViewHeight = num + 30f;
            }
            Widgets.EndScrollView();
            GUI.EndGroup();
            GUI.color   = Color.white;
            Text.Anchor = TextAnchor.UpperLeft;
        }
예제 #21
0
        /* (ProfoundDarkness) I've intentionally left some code remarked in the following code because it's a useful guide on how to create
         * and maintain the transpilers that will do nearly identical changes to RimWorld's code for the other 2 PawnColumnWorkers.
         */
        public override void DoCell(Rect rect, Pawn pawn, PawnTable table)
        {
            if (pawn.outfits == null)
            {
                return;
            }
            //changed: int num = Mathf.FloorToInt((rect.width - 4f) * 0.714285731f);
            int num = Mathf.FloorToInt((rect.width - 4f) - IconSize);
            //changed: int num2 = Mathf.FloorToInt((rect.width - 4f) * 0.2857143f);
            int   num2 = Mathf.FloorToInt(IconSize);
            float num3 = rect.x;
            //added:
            float num4 = rect.y + ((rect.height - IconSize) / 2);

            // Reduce width if we're adding a clear forced button
            bool somethingIsForced = pawn.HoldTrackerAnythingHeld();
            Rect loadoutButtonRect = new Rect(num3, rect.y + 2f, (float)num, rect.height - 4f);

            if (somethingIsForced)
            {
                loadoutButtonRect.width -= 4f + (float)num2;
            }

            // Main loadout button
            string label = pawn.GetLoadout().label.Truncate(loadoutButtonRect.width, null);

            if (Widgets.ButtonText(loadoutButtonRect, label, true, false, true))
            {
                LoadoutManager.SortLoadouts();
                List <FloatMenuOption> options = new List <FloatMenuOption>();
                foreach (Loadout loadout in LoadoutManager.Loadouts)
                {
                    // need to create a local copy for delegate
                    Loadout localLoadout = loadout;
                    options.Add(new FloatMenuOption(localLoadout.LabelCap, delegate
                    {
                        pawn.SetLoadout(localLoadout);
                    }, MenuOptionPriority.Default, null, null));
                }
                Find.WindowStack.Add(new FloatMenu(options));
            }

            // Clear forced button
            num3 += loadoutButtonRect.width;
            num3 += 4f;
            //changed: Rect forcedHoldRect = new Rect(num3, rect.y + 2f, (float)num2, rect.height - 4f);
            Rect forcedHoldRect = new Rect(num3, num4, (float)num2, (float)num2);

            if (somethingIsForced)
            {
                //changed: if (Widgets.ButtonText(forcedHoldRect, "ClearForcedApparel".Translate(), true, false, true)) // "Clear forced" is sufficient and that's what this is at the moment.
                if (Widgets.ButtonImage(forcedHoldRect, ClearImage))
                {
                    pawn.HoldTrackerClear(); // yes this will also delete records that haven't been picked up and thus not shown to the player...
                }
                TooltipHandler.TipRegion(forcedHoldRect, new TipSignal(delegate
                {
                    string text = "CE_ForcedHold".Translate() + ":\n";
                    foreach (HoldRecord rec in LoadoutManager.GetHoldRecords(pawn))
                    {
                        if (!rec.pickedUp)
                        {
                            continue;
                        }
                        text = text + "\n   " + rec.thingDef.LabelCap + " x" + rec.count;
                    }
                    return(text);
                }, pawn.GetHashCode() * 613));
                num3 += (float)num2;
                num3 += 4f;
            }

            //changed: Rect assignTabRect = new Rect(num3, rect.y + 2f, (float)num2, rect.height - 4f);
            Rect assignTabRect = new Rect(num3, num4, (float)num2, (float)num2);

            //changed: if (Widgets.ButtonText(assignTabRect, "AssignTabEdit".Translate(), true, false, true))
            if (Widgets.ButtonImage(assignTabRect, EditImage))
            {
                Find.WindowStack.Add(new Dialog_ManageLoadouts(pawn.GetLoadout()));
            }
            // Added this next line.
            TooltipHandler.TipRegion(assignTabRect, new TipSignal(textGetter("CE_Loadouts"), pawn.GetHashCode() * 613));
            num3 += (float)num2;
        }
        private WorkPriority GetPriorityWork(Pawn pawn)
        {
            CompAmmoUser primaryammouser = pawn.equipment.Primary.TryGetComp <CompAmmoUser>();

            if (pawn.Faction.IsPlayer && pawn.equipment.Primary != null && pawn.equipment.Primary.TryGetComp <CompAmmoUser>() != null)
            {
                Loadout loadout = pawn.GetLoadout();
                // if (loadout != null && !loadout.Slots.NullOrEmpty())
                if (loadout != null && loadout.SlotCount > 0)
                {
                    return(WorkPriority.None);
                }
            }

            if (pawn.kindDef.trader)
            {
                return(WorkPriority.None);
            }
            if (pawn.CurJob != null && pawn.CurJob.def == JobDefOf.Tame)
            {
                return(WorkPriority.None);
            }

            if (pawn.equipment.Primary == null)
            {
                if (Unload(pawn))
                {
                    return(WorkPriority.Unloading);
                }
                else
                {
                    return(WorkPriority.Weapon);
                }
            }

            if (pawn.equipment.Primary != null && primaryammouser != null)
            {
                int ammocount = 0;
                foreach (AmmoLink link in primaryammouser.Props.ammoSet.ammoTypes)
                {
                    Thing ammoThing;
                    ammoThing = pawn.TryGetComp <CompInventory>().ammoList.Find(thing => thing.def == link.ammo);
                    if (ammoThing != null)
                    {
                        ammocount += ammoThing.stackCount;
                    }
                }
                float atw = primaryammouser.CurrentAmmo.GetStatValueAbstract(CE_StatDefOf.Bulk);
                if ((ammocount < (1.5f / atw)) && ((1.5f / atw) > 3))
                {
                    if (Unload(pawn))
                    {
                        return(WorkPriority.Unloading);
                    }
                    else
                    {
                        return(WorkPriority.LowAmmo);
                    }
                }
                if (!PawnUtility.EnemiesAreNearby(pawn, 30, true))
                {
                    if ((ammocount < (3.5f / atw)) && ((3.5f / atw) > 4))
                    {
                        if (Unload(pawn))
                        {
                            return(WorkPriority.Unloading);
                        }
                        else
                        {
                            return(WorkPriority.Ammo);
                        }
                    }
                }
            }

            /*
             * if (!pawn.Faction.IsPlayer && pawn.equipment.Primary != null
             *  && !PawnUtility.EnemiesAreNearby(pawn, 30, true)
             || (!pawn.apparel.BodyPartGroupIsCovered(BodyPartGroupDefOf.Torso)
             || !pawn.apparel.BodyPartGroupIsCovered(BodyPartGroupDefOf.Legs)))
             ||{
             || return WorkPriority.Apparel;
             ||}
             */

            return(WorkPriority.None);
        }
예제 #23
0
        protected override void FillTab()
        {
            // get the inventory comp
            CompInventory comp = SelPawn.TryGetComp <CompInventory>();

            // set up rects
            Rect listRect = new Rect(
                _margin,
                _topPadding,
                size.x - 2 * _margin,
                size.y - _topPadding - _margin);

            if (comp != null)
            {
                PlayerKnowledgeDatabase.KnowledgeDemonstrated(CE_ConceptDefOf.CE_InventoryWeightBulk, KnowledgeAmount.FrameDisplayed);

                // adjust rects if comp found
                listRect.height -= (_margin / 2 + _barHeight) * 2;
                Rect weightRect = new Rect(_margin, listRect.yMax + _margin / 2, listRect.width, _barHeight);
                Rect bulkRect   = new Rect(_margin, weightRect.yMax + _margin / 2, listRect.width, _barHeight);

                Utility_Loadouts.DrawBar(bulkRect, comp.currentBulk, comp.capacityBulk, "CE_Bulk".Translate(), SelPawn.GetBulkTip());
                Utility_Loadouts.DrawBar(weightRect, comp.currentWeight, comp.capacityWeight, "CE_Weight".Translate(), SelPawn.GetWeightTip());
            }

            // start drawing list (rip from ITab_Pawn_Gear)

            GUI.BeginGroup(listRect);
            Text.Font = GameFont.Small;
            GUI.color = Color.white;
            Rect outRect  = new Rect(0f, 0f, listRect.width, listRect.height);
            Rect viewRect = new Rect(0f, 0f, listRect.width - 16f, _scrollViewHeight);

            Widgets.BeginScrollView(outRect, ref _scrollPosition, viewRect);
            float num = 0f;

            TryDrawComfyTemperatureRange(ref num, viewRect.width);
            if (SelPawnForGear.apparel != null)
            {
                bool flag = false;
                TryDrawAverageArmor(ref num, viewRect.width, StatDefOf.ArmorRating_Blunt, "ArmorBlunt".Translate(), ref flag);
                TryDrawAverageArmor(ref num, viewRect.width, StatDefOf.ArmorRating_Sharp, "ArmorSharp".Translate(), ref flag);
                TryDrawAverageArmor(ref num, viewRect.width, StatDefOf.ArmorRating_Heat, "ArmorHeat".Translate(), ref flag);
                TryDrawAverageArmor(ref num, viewRect.width, StatDefOf.ArmorRating_Electric, "ArmorElectric".Translate(), ref flag);
            }
            if (SelPawnForGear.equipment != null)
            {
                Widgets.ListSeparator(ref num, viewRect.width, "Equipment".Translate());
                foreach (ThingWithComps current in SelPawnForGear.equipment.AllEquipmentListForReading)
                {
                    DrawThingRow(ref num, viewRect.width, current);
                }
            }
            if (SelPawnForGear.apparel != null)
            {
                Widgets.ListSeparator(ref num, viewRect.width, "Apparel".Translate());
                foreach (Apparel current2 in from ap in SelPawnForGear.apparel.WornApparel
                         orderby ap.def.apparel.bodyPartGroups[0].listOrder descending
                         select ap)
                {
                    DrawThingRow(ref num, viewRect.width, current2);
                }
            }
            if (SelPawnForGear.inventory != null)
            {
                // get the loadout so we can make a decision to show a button.
                bool    showMakeLoadout = false;
                Loadout curLoadout      = SelPawnForGear.GetLoadout();
                if (SelPawnForGear.IsColonist && (curLoadout == null || curLoadout.Slots.NullOrEmpty()) && (SelPawnForGear.inventory.innerContainer.Any() || SelPawnForGear.equipment?.Primary != null))
                {
                    showMakeLoadout = true;
                }

                if (showMakeLoadout)
                {
                    num += 3;        // Make a little room for the button.
                }
                float buttonY = num; // Could be accomplished with seperator being after the button...

                Widgets.ListSeparator(ref num, viewRect.width, "Inventory".Translate());

                // only offer this button if the pawn has no loadout or has the default loadout and there are things/equipment...
                if (showMakeLoadout)
                {
                    Rect loadoutButtonRect = new Rect(viewRect.width / 2, buttonY, viewRect.width / 2, 26f);     // button is half the available width...
                    if (Widgets.ButtonText(loadoutButtonRect, "Make Loadout"))
                    {
                        Loadout loadout = SelPawnForGear.GenerateLoadoutFromPawn();
                        LoadoutManager.AddLoadout(loadout);
                        SelPawnForGear.SetLoadout(loadout);

                        // UNDONE ideally we'd open the assign (MainTabWindow_OutfitsAndLoadouts) tab as if the user clicked on it here.
                        // (ProfoundDarkness) But I have no idea how to do that just yet.  The attempts I made seem to put the RimWorld UI into a bit of a bad state.
                        //                     ie opening the tab like the dialog below.
                        //                    Need to understand how RimWorld switches tabs and see if something similar can be done here
                        //                     (or just remove the unfinished marker).

                        // Opening this window is the same way as if from the assign tab so should be correct.
                        Find.WindowStack.Add(new Dialog_ManageLoadouts(SelPawnForGear.GetLoadout()));
                    }
                }

                workingInvList.Clear();
                workingInvList.AddRange(SelPawnForGear.inventory.innerContainer);
                for (int i = 0; i < workingInvList.Count; i++)
                {
                    DrawThingRow(ref num, viewRect.width, workingInvList[i].GetInnerIfMinified(), true);
                }
            }
            if (Event.current.type == EventType.Layout)
            {
                _scrollViewHeight = num + 30f;
            }
            Widgets.EndScrollView();
            GUI.EndGroup();
            GUI.color   = Color.white;
            Text.Anchor = TextAnchor.UpperLeft;
        }
예제 #24
0
        /// <summary>
        /// Generates a loadout from a pawn's current equipment and inventory.  Attempts to put items which fit in Generics that are default/DropExcess into said Generic.
        /// </summary>
        /// <param name="pawn">Pawn to check equipment/inventory on and generate a Loadout from.</param>
        /// <returns>Loadout which was generated based on Pawn's inventory.</returns>
        public static Loadout GenerateLoadoutFromPawn(this Pawn pawn)
        {
            // generate the name for this new pawn based loadout.
            string newName = string.Concat(pawn.Name.ToStringShort, " ", "CE_DefaultLoadoutName".Translate());
            Regex  reNum   = new Regex(@"^(.*?)\d+$");

            if (reNum.IsMatch(newName))
            {
                newName = reNum.Replace(newName, @"$1");
            }
            newName = LoadoutManager.GetUniqueLabel(newName);

            // set basic loadout properties.
            Loadout loadout = new Loadout(newName);

            loadout.defaultLoadout = false;
            loadout.canBeDeleted   = true;

            LoadoutSlot slot = null;

            // grab the pawn's current equipment as a loadoutslot.
            if (pawn.equipment?.Primary != null)
            {
                slot = new LoadoutSlot(pawn.equipment.Primary.def);
                loadout.AddSlot(slot);
            }

            // get a list of generics which are drop only.  Assumes that anything that doesn't fit here is a Specific slot later.
            IEnumerable <LoadoutGenericDef> generics = DefDatabase <LoadoutGenericDef> .AllDefs.Where(gd => gd.defaultCountType == LoadoutCountType.dropExcess);

            // enumerate each item in the pawn's inventory and add appropriate slots.
            foreach (Thing thing in pawn.inventory.innerContainer)
            {
                LoadoutGenericDef foundGeneric = null;
                // first check if it's a generic-able item...
                foreach (LoadoutGenericDef generic in generics)
                {
                    if (generic.lambda(thing.def))
                    {
                        foundGeneric = generic;
                        break;
                    }
                }

                // assign a loadout slot that fits the thing.
                if (foundGeneric != null)
                {
                    slot = new LoadoutSlot(foundGeneric, thing.stackCount);
                }
                else
                {
                    slot = new LoadoutSlot(thing.def, thing.stackCount);
                }

                // add the slot (this also takes care of adding to existing slots)
                loadout.AddSlot(slot);
            }

            // finally check the loadout and make sure that it has sufficient generics like what happens with a new loadout in the management UI.
            foreach (LoadoutGenericDef generic in generics.Where(gd => gd.isBasic))
            {
                slot = loadout.Slots.FirstOrDefault(s => s.genericDef == generic);
                if (slot != null)
                {
                    if (slot.count < slot.genericDef.defaultCount)
                    {
                        slot.count = slot.genericDef.defaultCount;
                    }
                }
                else
                {
                    slot = new LoadoutSlot(generic);
                    loadout.AddSlot(slot);
                }
            }

            return(loadout);
        }
예제 #25
0
        private WorkPriority GetPriorityWork(Pawn pawn)
        {
            CompAmmoUser  primaryammouser = pawn.equipment.Primary.TryGetComp <CompAmmoUser>();
            CompInventory compammo        = pawn.TryGetComp <CompInventory>();

            if (pawn.Faction.IsPlayer && pawn.equipment.Primary != null && pawn.equipment.Primary.TryGetComp <CompAmmoUser>() != null)
            {
                Loadout loadout = pawn.GetLoadout();
                // if (loadout != null && !loadout.Slots.NullOrEmpty())
                if (loadout != null && loadout.SlotCount > 0)
                {
                    return(WorkPriority.None);
                }
            }

            if (pawn.kindDef.trader)
            {
                return(WorkPriority.None);
            }
            if (pawn.CurJob != null && pawn.CurJob.def == JobDefOf.Tame)
            {
                return(WorkPriority.None);
            }

            if (pawn.equipment.Primary == null)
            {
                if (Unload(pawn))
                {
                    return(WorkPriority.Unloading);
                }
                else
                {
                    return(WorkPriority.Weapon);
                }
            }

            if (pawn.equipment.Primary != null && primaryammouser != null)
            {
                int ammocount = 0;
                foreach (AmmoLink link in primaryammouser.Props.ammoSet.ammoTypes)
                {
                    Thing ammoThing;
                    ammoThing = compammo.ammoList.Find(thing => thing.def == link.ammo);
                    if (ammoThing != null)
                    {
                        ammocount += ammoThing.stackCount;
                    }
                }

                // current ammo bulk
                float currentAmmoBulk = primaryammouser.CurrentAmmo.GetStatValueAbstract(CE_StatDefOf.Bulk);

                // weapon magazine size
                float stackSize = primaryammouser.Props.magazineSize;

                // weight projectile ratio to free bulk with x1.5 reserve
                float weightProjectileRatio = Mathf.RoundToInt(((compammo.capacityBulk - compammo.currentBulk) / 1.5f) / currentAmmoBulk);

                if (ammocount < stackSize * 1 && (ammocount < weightProjectileRatio))
                {
                    if (Unload(pawn))
                    {
                        return(WorkPriority.Unloading);
                    }
                    else
                    {
                        return(WorkPriority.LowAmmo);
                    }
                }

                if (!PawnUtility.EnemiesAreNearby(pawn, 30, true))
                {
                    if (ammocount < stackSize * 2 && (ammocount < weightProjectileRatio))
                    {
                        if (Unload(pawn))
                        {
                            return(WorkPriority.Unloading);
                        }
                        else
                        {
                            return(WorkPriority.Ammo);
                        }
                    }
                }
            }

            /*
             * if (!pawn.Faction.IsPlayer && pawn.equipment.Primary != null
             *  && !PawnUtility.EnemiesAreNearby(pawn, 30, true)
             || (!pawn.apparel.BodyPartGroupIsCovered(BodyPartGroupDefOf.Torso)
             || !pawn.apparel.BodyPartGroupIsCovered(BodyPartGroupDefOf.Legs)))
             ||{
             || return WorkPriority.Apparel;
             ||}
             */

            return(WorkPriority.None);
        }
예제 #26
0
        protected override Job TryGiveJob(Pawn pawn)
        {
            // Get inventory
            CompInventory inventory = pawn.TryGetComp <CompInventory>();

            if (inventory == null)
            {
                return(null);
            }

            Loadout loadout = pawn.GetLoadout();

            if (loadout != null)
            {
                // Find and drop excess items
                foreach (LoadoutSlot slot in loadout.Slots)
                {
                    int numContained = inventory.container.TotalStackCountOfDef(slot.Def);

                    // Add currently equipped gun
                    if (pawn.equipment != null && pawn.equipment.Primary != null)
                    {
                        if (pawn.equipment.Primary.def == slot.Def)
                        {
                            numContained++;
                        }
                    }
                    // Drop excess items
                    if (numContained > slot.Count)
                    {
                        Thing thing = inventory.container.FirstOrDefault(x => x.def == slot.Def);
                        if (thing != null)
                        {
                            Thing droppedThing;
                            if (inventory.container.TryDrop(thing, pawn.Position, pawn.Map, ThingPlaceMode.Near, numContained - slot.Count, out droppedThing))
                            {
                                if (droppedThing != null)
                                {
                                    return(HaulAIUtility.HaulToStorageJob(pawn, droppedThing));
                                }
                                Log.Error(pawn + " tried dropping " + thing + " from loadout but resulting thing is null");
                            }
                        }
                    }
                }

                // Try drop currently equipped weapon
                if (pawn.equipment != null && pawn.equipment.Primary != null && !loadout.Slots.Any(slot => slot.Def == pawn.equipment.Primary.def && slot.Count >= 1))
                {
                    ThingWithComps droppedEq;
                    if (pawn.equipment.TryDropEquipment(pawn.equipment.Primary, out droppedEq, pawn.Position, false))
                    {
                        return(HaulAIUtility.HaulToStorageJob(pawn, droppedEq));
                    }
                }

                // Find excess items in inventory that are not part of our loadout
                bool  allowDropRaw  = Find.TickManager.TicksGame > pawn.mindState?.lastInventoryRawFoodUseTick + ticksBeforeDropRaw;
                Thing thingToRemove = inventory.container.FirstOrDefault(t =>
                                                                         (allowDropRaw || !t.def.IsNutritionGivingIngestible || t.def.ingestible.preferability > FoodPreferability.RawTasty) &&
                                                                         !loadout.Slots.Any(s => s.Def == t.def));
                if (thingToRemove != null)
                {
                    Thing droppedThing;
                    if (inventory.container.TryDrop(thingToRemove, pawn.Position, pawn.Map, ThingPlaceMode.Near, thingToRemove.stackCount, out droppedThing))
                    {
                        return(HaulAIUtility.HaulToStorageJob(pawn, droppedThing));
                    }
                    Log.Error(pawn + " tried dropping " + thingToRemove + " from inventory but resulting thing is null");
                }

                // Find missing items
                ItemPriority priority;
                Thing        closestThing;
                int          count;
                LoadoutSlot  prioritySlot = GetPrioritySlot(pawn, out priority, out closestThing, out count);
                if (closestThing != null)
                {
                    // Equip gun if unarmed or current gun is not in loadout
                    if (closestThing.TryGetComp <CompEquippable>() != null &&
                        (pawn.health != null && pawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation)) &&
                        (pawn.equipment == null || pawn.equipment.Primary == null || !loadout.Slots.Any(s => s.Def == pawn.equipment.Primary.def)))
                    {
                        return(new Job(JobDefOf.Equip, closestThing));
                    }
                    // Take items into inventory if needed
                    int numContained = inventory.container.TotalStackCountOfDef(prioritySlot.Def);
                    return(new Job(JobDefOf.TakeInventory, closestThing)
                    {
                        count = Mathf.Min(closestThing.stackCount, prioritySlot.Count - numContained, count)
                    });
                }
            }
            return(null);
        }
예제 #27
0
        /// <summary>
        /// Find an item that should be dropped from the pawn's inventory and how much to drop.
        /// </summary>
        /// <param name="pawn"></param>
        /// <param name="dropThing">The thing which should be dropped.</param>
        /// <param name="dropCount">The amount to drop.</param>
        /// <returns>bool, true indicates that the out variables are filled with something to do work on (drop).</returns>
        // NOTE (ProfoundDarkness): Ended up doing this by nibbling away at the pawn's inventory (or dictionary representation of ThingDefs/Count).
        //  Probably not efficient but was easier to handle atm.
        static public bool GetExcessThing(this Pawn pawn, out Thing dropThing, out int dropCount)
        {
            //(ProfoundDarkness) Thanks to erdelf on the RimWorldMod discord for helping me figure out some dictionary stuff and C# concepts related to 'Primitives' (pass by Value).
            CompInventory     inventory = pawn.TryGetComp <CompInventory>();
            Loadout           loadout   = pawn.GetLoadout();
            List <HoldRecord> records   = LoadoutManager.GetHoldRecords(pawn);

            dropThing = null;
            dropCount = 0;

            if (inventory == null || inventory.container == null || loadout == null || loadout.Slots.NullOrEmpty())
            {
                return(false);
            }

            Dictionary <ThingDef, Integer> listing = GetStorageByThingDef(pawn);

            // iterate over specifics and generics and Chip away at the dictionary.
            foreach (LoadoutSlot slot in loadout.Slots)
            {
                if (slot.thingDef != null && listing.ContainsKey(slot.thingDef))
                {
                    listing[slot.thingDef].value -= slot.count;
                    if (listing[slot.thingDef].value <= 0)
                    {
                        listing.Remove(slot.thingDef);
                    }
                }
                if (slot.genericDef != null)
                {
                    List <ThingDef> killKeys     = new List <ThingDef>();
                    int             desiredCount = slot.count;
                    // find dictionary entries which corespond to covered slot.
                    foreach (ThingDef def in listing.Keys.Where(td => slot.genericDef.lambda(td)))
                    {
                        listing[def].value -= desiredCount;
                        if (listing[def].value <= 0)
                        {
                            desiredCount = 0 - listing[def].value;
                            killKeys.Add(def); // the thing in inventory is exausted, forget about it.
                        }
                        else
                        {
                            break; // we have satisifed this loadout so no need to keep enumerating.
                        }
                    }
                    // cleanup dictionary.
                    foreach (ThingDef def in killKeys)
                    {
                        listing.Remove(def);
                    }
                }
            }

            // if there is something left in the dictionary, that is what is to be dropped.
            // Complicated by the fact that we now consider ammo in guns as part of the inventory...
            if (listing.Any())
            {
                if (records != null && !records.NullOrEmpty())
                {
                    // look at each remaining 'uneaten' thingdef in pawn's inventory.
                    foreach (ThingDef def in listing.Keys)
                    {
                        HoldRecord rec = records.FirstOrDefault(r => r.thingDef == def);
                        if (rec == null)
                        {
                            // the item we have extra of has no HoldRecord, drop it.
                            dropThing = inventory.container.FirstOrDefault(t => t.def == def && !pawn.IsItemQuestLocked(t));
                            if (dropThing != null)
                            {
                                dropCount = listing[def].value > dropThing.stackCount ? dropThing.stackCount : listing[def].value;
                                return(true);
                            }
                        }
                        else if (rec.count < listing[def].value)
                        {
                            // the item we have extra of HAS a HoldRecord but the amount carried is above the limit of the HoldRecord, drop extra.
                            dropThing = pawn.inventory.innerContainer.FirstOrDefault(t => t.def == def && !pawn.IsItemQuestLocked(t));
                            if (dropThing != null)
                            {
                                dropCount = listing[def].value - rec.count;
                                dropCount = dropCount > dropThing.stackCount ? dropThing.stackCount : dropCount;
                                return(true);
                            }
                        }
                    }
                }
                else
                {
                    foreach (ThingDef def in listing.Keys)
                    {
                        dropThing = inventory.container.FirstOrDefault(t => t.GetInnerIfMinified().def == def && !pawn.IsItemQuestLocked(t));
                        if (dropThing != null)
                        {
                            dropCount = listing[def].value > dropThing.stackCount ? dropThing.stackCount : listing[def].value;
                            return(true);
                        }
                    }
                }
            } // else
            return(false);
        }
예제 #28
0
        private LoadoutSlot GetPrioritySlot(Pawn pawn, out ItemPriority priority, out Thing closestThing, out int count)
        {
            priority = ItemPriority.None;
            LoadoutSlot slot = null;

            closestThing = null;
            count        = 0;

            CompInventory inventory = pawn.TryGetComp <CompInventory>();

            if (inventory != null && inventory.container != null)
            {
                Loadout loadout = pawn.GetLoadout();
                if (loadout != null && !loadout.Slots.NullOrEmpty())
                {
                    foreach (LoadoutSlot curSlot in loadout.Slots)
                    {
                        ItemPriority curPriority = ItemPriority.None;
                        Thing        curThing    = null;
                        int          numCarried  = inventory.container.TotalStackCountOfDef(curSlot.Def);

                        // Add currently equipped gun
                        if (pawn.equipment != null && pawn.equipment.Primary != null)
                        {
                            if (pawn.equipment.Primary.def == curSlot.Def)
                            {
                                numCarried++;
                            }
                        }
                        if (numCarried < curSlot.Count)
                        {
                            curThing = GenClosest.ClosestThingReachable(
                                pawn.Position,
                                pawn.Map,
                                ThingRequest.ForDef(curSlot.Def),
                                PathEndMode.ClosestTouch,
                                TraverseParms.For(pawn, Danger.None, TraverseMode.ByPawn),
                                proximitySearchRadius,
                                x => !x.IsForbidden(pawn) && pawn.CanReserve(x));
                            if (curThing != null)
                            {
                                curPriority = ItemPriority.Proximity;
                            }
                            else
                            {
                                curThing = GenClosest.ClosestThingReachable(
                                    pawn.Position,
                                    pawn.Map,
                                    ThingRequest.ForDef(curSlot.Def),
                                    PathEndMode.ClosestTouch,
                                    TraverseParms.For(pawn, Danger.None, TraverseMode.ByPawn),
                                    maximumSearchRadius,
                                    x => !x.IsForbidden(pawn) && pawn.CanReserve(x));
                                if (curThing != null)
                                {
                                    if (!curSlot.Def.IsNutritionGivingIngestible && numCarried / curSlot.Count <= 0.5f)
                                    {
                                        curPriority = ItemPriority.LowStock;
                                    }
                                    else
                                    {
                                        curPriority = ItemPriority.Low;
                                    }
                                }
                            }
                        }
                        if (curPriority > priority && curThing != null && inventory.CanFitInInventory(curThing, out count))
                        {
                            priority     = curPriority;
                            slot         = curSlot;
                            closestThing = curThing;
                        }
                        if (priority >= ItemPriority.LowStock)
                        {
                            break;
                        }
                    }
                }
            }

            return(slot);
        }
        private WorkPriority GetPriorityWork(Pawn pawn)
        {
            #region Traders have no work priority
            if (pawn.kindDef.trader)
            {
                return(WorkPriority.None);
            }
            #endregion

            //#region Pawns with non-idle jobs have no work priority
            //bool hasCurJob = pawn.CurJob != null;
            //JobDef jobDef = hasCurJob ? pawn.CurJob.def : null;

            //if (hasCurJob && !jobDef.isIdle)
            //{
            //    return WorkPriority.None;
            //}
            //#endregion

            bool         hasPrimary      = (pawn.equipment != null && pawn.equipment.Primary != null);
            CompAmmoUser primaryAmmoUser = hasPrimary ? pawn.equipment.Primary.TryGetComp <CompAmmoUser>() : hasWeaponInInventory(pawn) ? weaponInInventory(pawn) : null;

            #region Colonists with primary ammo-user and a loadout have no work priority
            if (pawn.Faction.IsPlayer &&
                primaryAmmoUser != null)
            {
                Loadout loadout = pawn.GetLoadout();
                // if (loadout != null && !loadout.Slots.NullOrEmpty())
                if (loadout != null && loadout.SlotCount > 0)
                {
                    return(WorkPriority.None);
                }
            }
            #endregion

            // Pawns without weapon..
            if (!hasPrimary)
            {
                // With inventory && non-colonist && not stealing && little space left
                if (Unload(pawn))
                {
                    return(WorkPriority.Unloading);
                }
                // Without inventory || colonist || stealing || lots of space left
                if (!hasWeaponInInventory(pawn))
                {
                    return(WorkPriority.Weapon);
                }
            }

            CompInventory compInventory = pawn.TryGetComp <CompInventory>();
            // Pawn with ammo-using weapon..
            if (primaryAmmoUser != null && primaryAmmoUser.UseAmmo)
            {
                // Magazine size
                FloatRange magazineSize = new FloatRange(1f, 2f);
                LoadoutPropertiesExtension loadoutPropertiesExtension = (LoadoutPropertiesExtension)(pawn.kindDef.modExtensions?.FirstOrDefault(x => x is LoadoutPropertiesExtension));
                bool hasWeaponTags = pawn.kindDef.weaponTags?.Any() ?? false;

                if (hasWeaponTags &&
                    primaryAmmoUser.parent.def.weaponTags.Any(pawn.kindDef.weaponTags.Contains) &&
                    loadoutPropertiesExtension != null &&
                    loadoutPropertiesExtension.primaryMagazineCount != FloatRange.Zero)
                {
                    magazineSize.min = loadoutPropertiesExtension.primaryMagazineCount.min;
                    magazineSize.max = loadoutPropertiesExtension.primaryMagazineCount.max;
                }

                magazineSize.min *= primaryAmmoUser.Props.magazineSize;
                magazineSize.max *= primaryAmmoUser.Props.magazineSize;

                // Number of things in inventory that could be put in the weapon
                int   viableAmmoCarried = 0;
                float viableAmmoBulk    = 0;
                foreach (AmmoLink link in primaryAmmoUser.Props.ammoSet.ammoTypes)
                {
                    var count = compInventory.AmmoCountOfDef(link.ammo);
                    viableAmmoCarried += count;
                    viableAmmoBulk    += count * link.ammo.GetStatValueAbstract(CE_StatDefOf.Bulk);
                }

                // ~2/3rds of the inventory bulk minus non-usable and non-ammo bulk could be filled with ammo
                float potentialAmmoBulk = ammoFractionOfNonAmmoInventory * (compInventory.capacityBulk - compInventory.currentBulk + viableAmmoBulk);
                // There's less ammo [bulk] than fits the potential ammo bulk [bulk]
                if (viableAmmoBulk < potentialAmmoBulk)
                {
                    // There's less ammo [nr] than fits a clip [nr]
                    if (primaryAmmoUser.Props.magazineSize == 0 || viableAmmoCarried < magazineSize.min)
                    {
                        return(Unload(pawn) ? WorkPriority.Unloading : WorkPriority.LowAmmo);
                    }

                    // There's less ammo [nr] than fits two clips [nr] && no enemies are close
                    if (viableAmmoCarried < magazineSize.max &&
                        !PawnUtility.EnemiesAreNearby(pawn, 20, true))
                    {
                        return(Unload(pawn) ? WorkPriority.Unloading : WorkPriority.Ammo);
                    }
                }
            }
            return(WorkPriority.None);
        }
예제 #30
0
 public static void AddLoadout(Loadout loadout)
 {
     Instance._loadouts.Add(loadout);
 }