Пример #1
0
        public override string GetExplanation(StatRequest req, ToStringNumberSense numberSense)
        {
            StringBuilder stringBuilder = new StringBuilder();

            stringBuilder.Append(base.GetExplanation(req, numberSense));
            if (req.HasThing)
            {
                CompInventory comp = req.Thing.TryGetComp <CompInventory>();
                if (comp != null)
                {
                    stringBuilder.AppendLine();
                    stringBuilder.AppendLine("CE_CarriedBulk".Translate() + ": x" + comp.workSpeedFactor.ToStringPercent());
                }
            }

            return(stringBuilder.ToString());
        }
Пример #2
0
        /// <summary>
        /// Generates a loadout from available ThingDefs with respect to inventory constraints and deposits items straight into inventory
        /// </summary>
        /// <param name="inventory">Inventory comp to fill</param>
        public virtual void GenerateLoadout(CompInventory inventory)
        {
            if (inventory == null)
            {
                Log.Error("Tried generating loadout without inventory");
                return;
            }
            if (UnityEngine.Random.value < skipChance)
            {
                return;
            }
            compInvInt = inventory;

            // Calculate thing count
            int thingsToMake = UnityEngine.Random.Range(minCount, maxCount);

            // Make things
            while (thingsToMake > 0)
            {
                Thing thing = GenerateLoadoutThing(UnityEngine.Random.Range(1, thingsToMake));
                if (thing == null)
                {
                    return;
                }
                int maxCountTemp;
                if (compInvInt.CanFitInInventory(thing, out maxCountTemp))
                {
                    IntVec3 spawnPos = inventory.parent.Position.InBounds(Find.VisibleMap) ? inventory.parent.Position : IntVec3.Zero;
                    GenSpawn.Spawn(thing, spawnPos, Find.VisibleMap);

                    // If we cant fit the whole stack, fit as much as we can and return
                    if (maxCountTemp < thing.stackCount)
                    {
                        thing.stackCount = maxCountTemp;
                        compInvInt.container.TryAdd(thing, thing.stackCount);
                        return;
                    }
                    compInvInt.container.TryAdd(thing, thing.stackCount);
                    thingsToMake -= maxCountTemp;
                }
                else
                {
                    return;
                }
            }
        }
Пример #3
0
        public Thing InventoryAmmo(CompInventory inventory)
        {
            if (inventory == null)
            {
                return(null);
            }

            Thing ammo = inventory.container.FirstOrDefault(x => x.def == CompAmmo.SelectedAmmo);

            // NPC's switch ammo types
            if (ammo == null)
            {
                ammo = inventory.container.FirstOrDefault(x => CompAmmo.Props.ammoSet.ammoTypes.Any(a => a.ammo == x.def));
            }

            return(ammo);
        }
Пример #4
0
        /// <summary>
        /// Reduces ammo count and updates inventory if necessary, call this whenever ammo is consumed by the gun (e.g. firing a shot, clearing a jam)
        /// </summary>
        public bool TryReduceAmmoCount()
        {
            if (Wielder == null && turret == null)
            {
                Log.Error(parent.ToString() + " tried reducing its ammo count without a wielder");
            }

            // Mag-less weapons feed directly from inventory
            if (!HasMagazine)
            {
                if (UseAmmo)
                {
                    if (!TryFindAmmoInInventory(out ammoToBeDeleted))
                    {
                        return(false);
                    }
                    if (ammoToBeDeleted.def != CurrentAmmo)
                    {
                        currentAmmoInt = ammoToBeDeleted.def as AmmoDef;
                    }

                    if (ammoToBeDeleted.stackCount > 1)
                    {
                        ammoToBeDeleted = ammoToBeDeleted.SplitOff(1);
                    }
                }
                return(true);
            }
            // If magazine is empty, return false
            if (curMagCountInt <= 0)
            {
                curMagCountInt = 0;
                return(false);
            }
            // Reduce ammo count and update inventory
            curMagCountInt--;
            if (CompInventory != null)
            {
                CompInventory.UpdateInventory();
            }
            if (curMagCountInt < 0)
            {
                TryStartReload();
            }
            return(true);
        }
Пример #5
0
        /// <summary>
        /// Get all weapons a pawn has.
        /// </summary>
        /// <param name="pawn">Pawn</param>
        /// <param name="weapons">Weapons</param>
        /// <param name="rebuild">(Slow) wether to rebuild the cache</param>
        /// <returns>If this pawn has a CompInventory or not</returns>
        public static bool TryGetAllWeaponsInInventory(this Pawn pawn, out List <ThingWithComps> weapons, bool rebuildInvetory = false)
        {
            weapons = null;
            CompInventory compInventory = pawn.TryGetComp <CompInventory>();

            // check is this pawn has a CompInventory
            if (compInventory == null)
            {
                return(false);
            }
            if (rebuildInvetory)
            {
                compInventory.UpdateInventory();
            }
            // Add all weapons in the inventory
            weapons = compInventory.weapons.ToList();
            return(true);
        }
        public override void DoCell(Rect rect, Pawn pawn, PawnTable table)
        {
            CompInventory inventory = pawn.TryGetComp <CompInventory>();

            if (inventory == null)
            {
                return;
            }
            Rect barRect = new Rect(rect.x, rect.y + 2f, rect.width, rect.height - 4f);

            if (def.defName.Equals(BarBulk))
            {
                Utility_Loadouts.DrawBar(barRect, inventory.currentBulk, inventory.capacityBulk, "", pawn.GetBulkTip());
            }
            if (def.defName.Equals(BarMass))
            {
                Utility_Loadouts.DrawBar(barRect, inventory.currentWeight, inventory.capacityWeight, "", pawn.GetWeightTip());
            }
        }
        public override int Compare(Pawn a, Pawn b)
        {
            CompInventory inventoryA = a.TryGetComp <CompInventory>();
            CompInventory inventoryB = b.TryGetComp <CompInventory>();

            if (inventoryA == null || inventoryB == null)
            {
                return(0);
            }

            if (def.defName.Equals(BarBulk))
            {
                return((inventoryA.capacityBulk - inventoryA.currentBulk).CompareTo(inventoryB.capacityBulk - inventoryB.currentBulk));
            }
            if (def.defName.Equals(BarMass))
            {
                return((inventoryA.capacityWeight - inventoryA.currentWeight).CompareTo(inventoryB.capacityWeight - inventoryB.currentWeight));
            }
            return(0);
        }
        private void TryGenerateAmmoFor(ThingWithComps gun, CompInventory inventory, int ammoCount)
        {
            if (ammoCount <= 0)
            {
                return;
            }
            ThingDef thingToAdd;
            int      unitCount = 1; // How many ammo things to add per ammoCount
            var      compAmmo  = gun.TryGetComp <CompAmmoUser>();

            if (compAmmo == null || !compAmmo.UseAmmo)
            {
                if (gun.TryGetComp <CompEquippable>().PrimaryVerb.verbProps.verbClass == typeof(Verb_ShootCEOneUse))
                {
                    thingToAdd = gun.def;   // For one-time use weapons such as grenades, add duplicates instead of ammo
                }
                else
                {
                    return;
                }
            }
            else
            {
                // Generate currently loaded ammo
                thingToAdd = compAmmo.CurrentAmmo;
                unitCount  = Mathf.Max(1, compAmmo.Props.magazineSize); // Guns use full magazines as units
            }
            var ammoThing = thingToAdd.MadeFromStuff ? ThingMaker.MakeThing(thingToAdd, gun.Stuff) : ThingMaker.MakeThing(thingToAdd);

            ammoThing.stackCount = ammoCount * unitCount;
            int maxCount;

            if (inventory.CanFitInInventory(ammoThing, out maxCount))
            {
                if (maxCount < ammoThing.stackCount)
                {
                    ammoThing.stackCount = maxCount - (maxCount % unitCount);
                }
                inventory.container.TryAdd(ammoThing);
            }
        }
Пример #9
0
        private void TryGenerateWeaponWithAmmoFor(Pawn pawn, CompInventory inventory, SidearmOption option)
        {
            if (option.weaponTags.NullOrEmpty() || !Rand.Chance(option.generateChance))
            {
                return;
            }
            // Generate weapon - mostly based on PawnWeaponGenerator.TryGenerateWeaponFor()
            float money = option.sidearmMoney.RandomInRange;

            foreach (ThingStuffPair cur in allWeaponPairs)
            {
                if (cur.Price <= money &&
                    option.weaponTags.Any(t => cur.thing.weaponTags.Contains(t)) &&
                    (cur.thing.generateAllowChance >= 1f || Rand.ValueSeeded(pawn.thingIDNumber ^ 28554635) <= cur.thing.generateAllowChance))
                {
                    workingWeapons.Add(cur);
                }
            }
            if (workingWeapons.Count == 0)
            {
                return;
            }
            ThingStuffPair pair;

            if (workingWeapons.TryRandomElementByWeight(p => p.Commonality * p.Price, out pair))
            {
                // Create the actual weapon and put it into inventory
                var eq = (ThingWithComps)ThingMaker.MakeThing(pair.thing, pair.stuff);
                LoadWeaponWithRandAmmo(eq);
                int count;
                if (inventory.CanFitInInventory(eq, out count))
                {
                    PawnGenerator.PostProcessGeneratedGear(eq, pawn);
                    if (inventory.container.TryAdd(eq))
                    {
                        TryGenerateAmmoFor(eq, inventory, Mathf.RoundToInt(option.magazineCount.RandomInRange));
                    }
                }
            }
            workingWeapons.Clear();
        }
        /// <summary>
        /// Handles the various yield returns that make up an iterated toil sequence.
        /// </summary>
        /// <returns>IEnumberable of Toil containing the sequence of actions the Pawn should take to fulfill the JobDriver's task.</returns>
        public override IEnumerable <Toil> MakeNewToils()
        {
            this.FailOnDespawnedNullOrForbidden(sourceInd);
            this.FailOnDestroyedOrNull(thingInd);
            this.FailOn(DeadTakePawn);
            // We could set a slightly more sane value here which would prevent a hoard of pawns moving from pack animal to pack animal...
            // Also can enforce limits via JobGiver keeping track of how many things it's given away from each pawn, it's a small case though...
            yield return(Toils_Reserve.Reserve(sourceInd, int.MaxValue, 0, null));

            yield return(Toils_Goto.GotoThing(sourceInd, PathEndMode.Touch));

            yield return(Toils_General.Wait(10));

            yield return(new Toil
            {
                initAction = delegate
                {
                    // if the targetItem is no longer in the takePawn's inventory then another pawn already took it and we fail...
                    if (takePawn == RootHolder(targetItem.holdingOwner.Owner))
                    {
                        int amount = targetItem.stackCount < pawn.CurJob.count ? targetItem.stackCount : pawn.CurJob.count;
                        takePawn.inventory.innerContainer.TryTransferToContainer(targetItem, pawn.inventory.innerContainer, amount);
                        if (doEquip)
                        {
                            CompInventory compInventory = pawn.TryGetComp <CompInventory>();
                            if (compInventory != null)
                            {
                                compInventory.TrySwitchToWeapon((ThingWithComps)targetItem);
                            }
                        }
                    }
                    else
                    {
                        this.EndJobWith(JobCondition.Incompletable);
                    }
                }
            });

            yield return(Toils_Reserve.Release(sourceInd));
        }
        private void TryGenerateShieldFor(Pawn pawn, CompInventory inventory, ThingWithComps primary)
        {
            if ((primary != null && !primary.def.weaponTags.Contains(Apparel_Shield.OneHandedTag)) ||
                shieldTags.NullOrEmpty() ||
                pawn.apparel == null ||
                !Rand.Chance(shieldChance))
            {
                return;
            }

            var money = shieldMoney.RandomInRange;

            foreach (ThingStuffPair cur in allShieldPairs)
            {
                if (cur.Price < money &&
                    shieldTags.Any(t => cur.thing.apparel.tags.Contains(t)) &&
                    (cur.thing.generateAllowChance >= 1f || Rand.ValueSeeded(pawn.thingIDNumber ^ 68715844) <= cur.thing.generateAllowChance) &&
                    pawn.apparel.CanWearWithoutDroppingAnything(cur.thing) &&
                    ApparelUtility.HasPartsToWear(pawn, cur.thing))
                {
                    workingShields.Add(cur);
                }
            }
            if (workingShields.Count == 0)
            {
                return;
            }
            ThingStuffPair pair;

            if (workingShields.TryRandomElementByWeight(p => p.Commonality * p.Price, out pair))
            {
                var shield = (Apparel)ThingMaker.MakeThing(pair.thing, pair.stuff);
                int count;
                if (inventory.CanFitInInventory(shield, out count, false, true))
                {
                    pawn.apparel.Wear(shield);
                }
            }
            workingShields.Clear();
        }
Пример #12
0
        // New methods

        public void OrderReload()
        {
            if (mannableComp == null ||
                !mannableComp.MannedNow ||
                (compAmmo.currentAmmo == compAmmo.selectedAmmo && compAmmo.curMagCount == compAmmo.Props.magazineSize))
            {
                return;
            }
            Job           reloadJob = null;
            CompInventory inventory = mannableComp.ManningPawn.TryGetComp <CompInventory>();

            if (inventory != null)
            {
                Thing ammo = inventory.container.FirstOrDefault(x => x.def == compAmmo.selectedAmmo);
                if (ammo != null)
                {
                    Thing droppedAmmo;
                    int   amount = compAmmo.Props.magazineSize;
                    if (compAmmo.currentAmmo == compAmmo.selectedAmmo)
                    {
                        amount -= compAmmo.curMagCount;
                    }
                    if (inventory.container.TryDrop(ammo, this.Position, this.Map, ThingPlaceMode.Direct, Mathf.Min(ammo.stackCount, amount), out droppedAmmo))
                    {
                        reloadJob = new Job(DefDatabase <JobDef> .GetNamed("ReloadTurret"), this, droppedAmmo)
                        {
                            count = droppedAmmo.stackCount
                        };
                    }
                }
            }
            if (reloadJob == null)
            {
                reloadJob = new WorkGiver_ReloadTurret().JobOnThing(mannableComp.ManningPawn, this);
            }
            if (reloadJob != null)
            {
                mannableComp.ManningPawn.jobs.StartJob(reloadJob, JobCondition.Ongoing, null, true);
            }
        }
Пример #13
0
        public override string GetExplanation(StatRequest req, ToStringNumberSense numberSense)
        {
            StringBuilder stringBuilder = new StringBuilder();

            stringBuilder.Append(base.GetExplanation(req, numberSense));
            if (req.HasThing)
            {
                CompInventory comp = req.Thing.TryGetComp <CompInventory>();
                if (comp != null)
                {
                    stringBuilder.AppendLine();
                    stringBuilder.AppendLine("CE_CarriedWeight".Translate() + ": x" + comp.moveSpeedFactor.ToStringPercent());
                    if (comp.encumberPenalty > 0)
                    {
                        stringBuilder.AppendLine("CE_Encumbered".Translate() + ": -" + comp.encumberPenalty.ToStringPercent());
                        stringBuilder.AppendLine("CE_FinalModifier".Translate() + ": x" + GetStatFactor(req.Thing).ToStringPercent());
                    }
                }
            }

            return(stringBuilder.ToString());
        }
        private float GetStatFactor(Thing thing)
        {
            float factor = 1f;

            // Apply inventory penalties
            CompInventory inventory = thing.TryGetComp <CompInventory>();

            if (inventory != null)
            {
                factor = Mathf.Clamp(inventory.moveSpeedFactor - inventory.encumberPenalty, 0.5f, 1f);
            }

            // Apply crouch walk penalty
            var suppressComp = thing.TryGetComp <CompSuppressable>();

            if (suppressComp?.IsCrouchWalking ?? false)
            {
                factor *= CrouchWalkFactor;
            }

            return(factor);
        }
Пример #15
0
        /// <summary>
        /// Gets a priority value of how important it is for a pawn to do pickup/drop activities.
        /// </summary>
        /// <param name="pawn">Pawn to fetch priority for</param>
        /// <returns>float indicating priority of pickup/drop job</returns>
        public override float GetPriority(Pawn pawn)
        {
            CompInventory comp = pawn.TryGetComp <CompInventory>();

            if (comp == null)
            {
                return(0f);
            }
            else if (comp.ForcedLoadoutUpdate)
            {
                return(35f);
            }
            else if (comp.SkipUpdateLoadout)
            {
                return(0f);
            }
            if (pawn.HasExcessThing())
            {
                return(9.2f);
            }
            LoadoutSlot slot = GetPrioritySlot(pawn, out ItemPriority priority, out _, out _, out _);

            if (slot == null)
            {
                return(0f);
            }
            if (priority == ItemPriority.Low)
            {
                return(1f);
            }
            TimeAssignmentDef assignment = (pawn.timetable != null) ? pawn.timetable.CurrentAssignment : TimeAssignmentDefOf.Anything;

            if (assignment == TimeAssignmentDefOf.Sleep)
            {
                return(1f);
            }
            return(2.8f);
        }
Пример #16
0
        /// <summary>
        /// This should be called periodically so that HoldTracker can remove items that are no longer in the inventory via a method which isn't being watched.
        /// </summary>
        /// <param name="pawn">The pawn who's tracker should be checked.</param>
        public static void HoldTrackerCleanUp(this Pawn pawn)
        {
            if (_tickLastPurge <= GenTicks.TicksAbs)
            {
                LoadoutManager.PurgeHoldTrackerRolls();
                _tickLastPurge = GenTicks.TicksAbs + GenDate.TicksPerDay;
            }
            List <HoldRecord> recs      = LoadoutManager.GetHoldRecords(pawn);
            CompInventory     inventory = pawn.TryGetComp <CompInventory>();

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

            for (int i = recs.Count - 1; i > 0; i--)
            {
                if (recs[i].pickedUp && inventory.container.TotalStackCountOfDef(recs[i].thingDef) <= 0)
                {
                    recs.RemoveAt(i);
                }
            }
        }
Пример #17
0
        /// <summary>
        /// Gets the total count of a thingDef in a pawn's inventory.
        /// If thingDef is an ammo type, result will include rounds inside weapons magazines, matching behaviour in GetExcessThing.
        /// </summary>
        /// <param name="pawn">The pawn to check for stack count.</param>
        /// <param name="thingDef">The thingDef to look for.</param>
        /// <returns>Inventory count for specified item.</returns>
        static private int GetMagazineAwareStackCount(Pawn pawn, ThingDef thingDef)
        {
            int itemCount = 0;

            //Add stack count from inventory
            CompInventory inventory = pawn?.TryGetComp <CompInventory>();

            itemCount += inventory?.container?.TotalStackCountOfDef(thingDef) ?? 0;

            if (thingDef is AmmoDef)
            {
                //Add stack count from equipped primary (magazine ammo)
                if (pawn?.equipment?.Primary != null)
                {
                    CompAmmoUser ammoUser = pawn.equipment.Primary.TryGetComp <CompAmmoUser>();
                    if (ammoUser != null && ammoUser.HasMagazine && ammoUser.CurrentAmmo == thingDef)
                    {
                        itemCount += ammoUser.CurMagCount;
                    }
                }

                //Add stack count from inventory stored weapons (magazine ammo)
                if (inventory?.container != null)
                {
                    foreach (Thing inventoryItem in inventory.container)
                    {
                        CompAmmoUser ammoUser = inventoryItem.TryGetComp <CompAmmoUser>();
                        if (ammoUser != null && ammoUser.HasMagazine && ammoUser.CurrentAmmo == thingDef)
                        {
                            itemCount += ammoUser.CurMagCount;
                        }
                    }
                }
            }
            return(itemCount);
        }
Пример #18
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);
        }
        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);
        }
Пример #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);

                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;
        }
Пример #21
0
        public void LoadAmmo(Thing ammo = null)
        {
            if (Holder == null && turret == null)
            {
                Log.Error(parent.ToString() + " tried loading ammo with no owner");
                return;
            }

            int newMagCount;

            if (UseAmmo)
            {
                Thing ammoThing;
                bool  ammoFromInventory = false;
                if (ammo == null)
                {
                    if (!TryFindAmmoInInventory(out ammoThing))
                    {
                        DoOutOfAmmoAction();
                        return;
                    }
                    ammoFromInventory = true;
                }
                else
                {
                    ammoThing = ammo;
                }
                currentAmmoInt = (AmmoDef)ammoThing.def;
                if (Props.magazineSize < ammoThing.stackCount)
                {
                    newMagCount           = Props.magazineSize;
                    ammoThing.stackCount -= Props.magazineSize;
                    if (CompInventory != null)
                    {
                        CompInventory.UpdateInventory();
                    }
                }
                else
                {
                    newMagCount = ammoThing.stackCount;
                    if (ammoFromInventory)
                    {
                        CompInventory.container.Remove(ammoThing);
                    }
                    else if (!ammoThing.Destroyed)
                    {
                        ammoThing.Destroy();
                    }
                }
            }
            else
            {
                newMagCount = Props.magazineSize;
            }
            curMagCountInt = newMagCount;
            if (turret != null)
            {
                turret.isReloading = false;
            }
            if (parent.def.soundInteract != null)
            {
                parent.def.soundInteract.PlayOneShot(new TargetInfo(Position, Find.VisibleMap, false));
            }
        }
Пример #22
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);
        }
Пример #23
0
        private void DrawThingRow(ref float y, float width, Thing thing, bool showDropButtonIfPrisoner = false)
        {
            Rect rect = new Rect(0f, y, width, _thingRowHeight);

            Widgets.InfoCardButton(rect.width - 24f, y, thing);
            rect.width -= 24f;
            if (CanControl || (SelPawnForGear.Faction == Faction.OfPlayer && SelPawnForGear.RaceProps.packAnimal) || (showDropButtonIfPrisoner && SelPawnForGear.IsPrisonerOfColony))
            {
                Rect dropRect = new Rect(rect.width - 24f, y, 24f, 24f);
                TooltipHandler.TipRegion(dropRect, "DropThing".Translate());
                if (Widgets.ButtonImage(dropRect, TexButton.Drop))
                {
                    SoundDefOf.TickHigh.PlayOneShotOnCamera();
                    InterfaceDrop(thing);
                }
                rect.width -= 24f;
            }
            if (this.CanControl && thing.IngestibleNow && base.SelPawn.RaceProps.CanEverEat(thing))
            {
                Rect   rect3     = new Rect(rect.width - 24f, y, 24f, 24f);
                string tipString = thing.def.ingestible.ingestCommandString.NullOrEmpty() ? "ConsumeThing".Translate(new object[] { thing.LabelShort }) : string.Format(thing.def.ingestible.ingestCommandString, thing.LabelShort);
                TooltipHandler.TipRegion(rect3, tipString);
                if (Widgets.ButtonImage(rect3, TexButton.Ingest))
                {
                    SoundDefOf.TickHigh.PlayOneShotOnCamera();
                    this.InterfaceEatThis(thing);
                }
                rect.width -= 24f;
            }
            if (Mouse.IsOver(rect))
            {
                GUI.color = _highlightColor;
                GUI.DrawTexture(rect, TexUI.HighlightTex);
            }

            if (thing.def.DrawMatSingle != null && thing.def.DrawMatSingle.mainTexture != null)
            {
                Widgets.ThingIcon(new Rect(4f, y, _thingIconSize, _thingIconSize), thing);
            }
            Text.Anchor = TextAnchor.MiddleLeft;
            GUI.color   = _thingLabelColor;
            Rect   thingLabelRect = new Rect(_thingLeftX, y, rect.width - _thingLeftX, _thingRowHeight);
            string thingLabel     = thing.LabelCap;

            if ((thing is Apparel && SelPawnForGear.outfits != null && SelPawnForGear.outfits.forcedHandler.IsForced((Apparel)thing)) ||
                (SelPawnForGear.inventory != null && SelPawnForGear.HoldTrackerIsHeld(thing)))
            {
                thingLabel = thingLabel + ", " + "ApparelForcedLower".Translate();
            }
            Widgets.Label(thingLabelRect, thingLabel);
            y += _thingRowHeight;

            TooltipHandler.TipRegion(thingLabelRect, thing.GetWeightAndBulkTip());
            // RMB menu
            if (Widgets.ButtonInvisible(thingLabelRect) && Event.current.button == 1)
            {
                List <FloatMenuOption> floatOptionList = new List <FloatMenuOption>();
                floatOptionList.Add(new FloatMenuOption("ThingInfo".Translate(), delegate
                {
                    Find.WindowStack.Add(new Dialog_InfoCard(thing));
                }, MenuOptionPriority.Default, null, null));
                if (CanControl)
                {
                    // Equip option
                    ThingWithComps eq = thing as ThingWithComps;
                    if (eq != null && eq.TryGetComp <CompEquippable>() != null)
                    {
                        CompInventory compInventory = SelPawnForGear.TryGetComp <CompInventory>();
                        if (compInventory != null)
                        {
                            FloatMenuOption equipOption;
                            string          eqLabel = GenLabel.ThingLabel(eq.def, eq.Stuff, 1);
                            if (SelPawnForGear.equipment.AllEquipmentListForReading.Contains(eq) && SelPawnForGear.inventory != null)
                            {
                                equipOption = new FloatMenuOption("CE_PutAway".Translate(new object[] { eqLabel }),
                                                                  new Action(delegate
                                {
                                    SelPawnForGear.equipment.TryTransferEquipmentToContainer(SelPawnForGear.equipment.Primary, SelPawnForGear.inventory.innerContainer);
                                }));
                            }
                            else if (!SelPawnForGear.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation))
                            {
                                equipOption = new FloatMenuOption("CannotEquip".Translate(new object[] { eqLabel }), null);
                            }
                            else
                            {
                                string equipOptionLabel = "Equip".Translate(new object[] { eqLabel });
                                if (eq.def.IsRangedWeapon && SelPawnForGear.story != null && SelPawnForGear.story.traits.HasTrait(TraitDefOf.Brawler))
                                {
                                    equipOptionLabel = equipOptionLabel + " " + "EquipWarningBrawler".Translate();
                                }
                                equipOption = new FloatMenuOption(equipOptionLabel, new Action(delegate
                                {
                                    compInventory.TrySwitchToWeapon(eq);
                                }));
                            }
                            floatOptionList.Add(equipOption);
                        }
                    }
                    // Drop option
                    Action dropApparel = delegate
                    {
                        SoundDefOf.TickHigh.PlayOneShotOnCamera();
                        InterfaceDrop(thing);
                    };
                    Action dropApparelHaul = delegate
                    {
                        SoundDefOf.TickHigh.PlayOneShotOnCamera();
                        InterfaceDropHaul(thing);
                    };
                    if (this.CanControl && thing.IngestibleNow && base.SelPawn.RaceProps.CanEverEat(thing))
                    {
                        Action eatFood = delegate
                        {
                            SoundDefOf.TickHigh.PlayOneShotOnCamera();
                            InterfaceEatThis(thing);
                        };
                        string label = thing.def.ingestible.ingestCommandString.NullOrEmpty() ? "ConsumeThing".Translate(new object[] { thing.LabelShort }) : string.Format(thing.def.ingestible.ingestCommandString, thing.LabelShort);
                        floatOptionList.Add(new FloatMenuOption(label, eatFood));
                    }
                    floatOptionList.Add(new FloatMenuOption("DropThing".Translate(), dropApparel));
                    floatOptionList.Add(new FloatMenuOption("CE_DropThingHaul".Translate(), dropApparelHaul));
                    if (this.CanControl && SelPawnForGear.HoldTrackerIsHeld(thing))
                    {
                        Action forgetHoldTracker = delegate
                        {
                            SoundDefOf.TickHigh.PlayOneShotOnCamera();
                            SelPawnForGear.HoldTrackerForget(thing);
                        };
                        floatOptionList.Add(new FloatMenuOption("CE_HoldTrackerForget".Translate(), forgetHoldTracker));
                    }
                }
                FloatMenu window = new FloatMenu(floatOptionList, thing.LabelCap, false);
                Find.WindowStack.Add(window);
            }
            // end menu
        }
Пример #24
0
        protected override Job TryGiveJob(Pawn pawn)
        {
            if (!Controller.settings.EnableAmmoSystem || !Controller.settings.AutoTakeAmmo)
            {
                return(null);
            }

            if (!pawn.RaceProps.Humanlike || (pawn.story != null && pawn.story.WorkTagIsDisabled(WorkTags.Violent)))
            {
                return(null);
            }
            if (pawn.Faction.IsPlayer && pawn.Drafted)
            {
                return(null);
            }

            if (!Rand.MTBEventOccurs(60, 1, 30))
            {
                return(null);
            }

            // Log.Message(pawn.ToString() +  " - priority:" + (GetPriorityWork(pawn)).ToString() + " capacityWeight: " + pawn.TryGetComp<CompInventory>().capacityWeight.ToString() + " currentWeight: " + pawn.TryGetComp<CompInventory>().currentWeight.ToString() + " capacityBulk: " + pawn.TryGetComp<CompInventory>().capacityBulk.ToString() + " currentBulk: " + pawn.TryGetComp<CompInventory>().currentBulk.ToString());

            var           brawler         = (pawn.story != null && pawn.story.traits != null && pawn.story.traits.HasTrait(TraitDefOf.Brawler));
            CompInventory inventory       = pawn.TryGetComp <CompInventory>();
            bool          hasPrimary      = (pawn.equipment != null && pawn.equipment.Primary != null);
            CompAmmoUser  primaryammouser = hasPrimary ? pawn.equipment.Primary.TryGetComp <CompAmmoUser>() : null;

            if (inventory != null)
            {
                // Prefer ranged weapon in inventory
                if (!pawn.Faction.IsPlayer && hasPrimary && pawn.equipment.Primary.def.IsMeleeWeapon && !brawler)
                {
                    if ((pawn.skills.GetSkill(SkillDefOf.Shooting).Level >= pawn.skills.GetSkill(SkillDefOf.Melee).Level ||
                         pawn.skills.GetSkill(SkillDefOf.Shooting).Level >= 6))
                    {
                        ThingWithComps InvListGun3 = inventory.rangedWeaponList.Find(thing => thing.TryGetComp <CompAmmoUser>() != null && thing.TryGetComp <CompAmmoUser>().HasAmmoOrMagazine);
                        if (InvListGun3 != null)
                        {
                            inventory.TrySwitchToWeapon(InvListGun3);
                        }
                    }
                }

                // Drop excess ranged weapon
                if (!pawn.Faction.IsPlayer && primaryammouser != null && GetPriorityWork(pawn) == WorkPriority.Unloading && inventory.rangedWeaponList.Count >= 1)
                {
                    Thing ListGun = inventory.rangedWeaponList.Find(thing => thing.TryGetComp <CompAmmoUser>() != null && thing.def != pawn.equipment.Primary.def);
                    if (ListGun != null)
                    {
                        Thing ammoListGun = null;
                        if (!ListGun.TryGetComp <CompAmmoUser>().HasAmmoOrMagazine)
                        {
                            foreach (AmmoLink link in ListGun.TryGetComp <CompAmmoUser>().Props.ammoSet.ammoTypes)
                            {
                                if (inventory.ammoList.Find(thing => thing.def == link.ammo) == null)
                                {
                                    ammoListGun = ListGun;
                                    break;
                                }
                            }
                        }
                        if (ammoListGun != null)
                        {
                            Thing droppedWeapon;
                            if (inventory.container.TryDrop(ListGun, pawn.Position, pawn.Map, ThingPlaceMode.Near, ListGun.stackCount, out droppedWeapon))
                            {
                                pawn.jobs.EndCurrentJob(JobCondition.None, true);
                                pawn.jobs.TryTakeOrderedJob(new Job(JobDefOf.DropEquipment, droppedWeapon, 30, true));
                            }
                        }
                    }
                }

                // Find and drop not need ammo from inventory
                if (!pawn.Faction.IsPlayer && hasPrimary && inventory.ammoList.Count > 1 && GetPriorityWork(pawn) == WorkPriority.Unloading)
                {
                    Thing WrongammoThing = null;
                    WrongammoThing = primaryammouser != null
                        ? inventory.ammoList.Find(thing => !primaryammouser.Props.ammoSet.ammoTypes.Any(a => a.ammo == thing.def))
                        : inventory.ammoList.RandomElement <Thing>();

                    if (WrongammoThing != null)
                    {
                        Thing InvListGun = inventory.rangedWeaponList.Find(thing => hasPrimary && thing.TryGetComp <CompAmmoUser>() != null && thing.def != pawn.equipment.Primary.def);
                        if (InvListGun != null)
                        {
                            Thing ammoInvListGun = null;
                            foreach (AmmoLink link in InvListGun.TryGetComp <CompAmmoUser>().Props.ammoSet.ammoTypes)
                            {
                                ammoInvListGun = inventory.ammoList.Find(thing => thing.def == link.ammo);
                                break;
                            }
                            if (ammoInvListGun != null && ammoInvListGun != WrongammoThing)
                            {
                                Thing droppedThingAmmo;
                                if (inventory.container.TryDrop(ammoInvListGun, pawn.Position, pawn.Map, ThingPlaceMode.Near, ammoInvListGun.stackCount, out droppedThingAmmo))
                                {
                                    pawn.jobs.EndCurrentJob(JobCondition.None, true);
                                    pawn.jobs.TryTakeOrderedJob(new Job(JobDefOf.DropEquipment, 30, true));
                                }
                            }
                        }
                        else
                        {
                            Thing droppedThing;
                            if (inventory.container.TryDrop(WrongammoThing, pawn.Position, pawn.Map, ThingPlaceMode.Near, WrongammoThing.stackCount, out droppedThing))
                            {
                                pawn.jobs.EndCurrentJob(JobCondition.None, true);
                                pawn.jobs.TryTakeOrderedJob(new Job(JobDefOf.DropEquipment, 30, true));
                            }
                        }
                    }
                }

                Room room = RegionAndRoomQuery.RoomAtFast(pawn.Position, pawn.Map);

                // Find weapon in inventory and try to switch if any ammo in inventory.
                if (GetPriorityWork(pawn) == WorkPriority.Weapon && !hasPrimary)
                {
                    ThingWithComps InvListGun2 = inventory.rangedWeaponList.Find(thing => thing.TryGetComp <CompAmmoUser>() != null);

                    if (InvListGun2 != null)
                    {
                        Thing ammoInvListGun2 = null;
                        foreach (AmmoLink link in InvListGun2.TryGetComp <CompAmmoUser>().Props.ammoSet.ammoTypes)
                        {
                            ammoInvListGun2 = inventory.ammoList.Find(thing => thing.def == link.ammo);
                            break;
                        }
                        if (ammoInvListGun2 != null)
                        {
                            inventory.TrySwitchToWeapon(InvListGun2);
                        }
                    }

                    // Find weapon with near ammo for ai.
                    if (!pawn.Faction.IsPlayer)
                    {
                        Predicate <Thing> validatorWS = (Thing w) => w.def.IsWeapon &&
                                                        w.MarketValue > 500 && pawn.CanReserve(w, 1) &&
                                                        (DangerInPosRadius(pawn, w.Position, pawn.Map, 30f).Count() <= 0
                                                    ? pawn.Position.InHorDistOf(w.Position, 25f)
                                                    : pawn.Position.InHorDistOf(w.Position, 6f)) &&
                                                        pawn.CanReach(w, PathEndMode.Touch, Danger.Deadly, true) &&
                                                        (pawn.Faction.HostileTo(Faction.OfPlayer) || pawn.Faction == Faction.OfPlayer || !pawn.Map.areaManager.Home[w.Position]);

                        // generate a list of all weapons (this includes melee weapons)
                        List <Thing> allWeapons = (
                            from w in pawn.Map.listerThings.ThingsInGroup(ThingRequestGroup.HaulableAlways)
                            where validatorWS(w)
                            orderby w.MarketValue - w.Position.DistanceToSquared(pawn.Position) * 2f descending
                            select w
                            ).ToList();

                        // now just get the ranged weapons out...
                        List <Thing> rangedWeapons = allWeapons.Where(w => w.def.IsRangedWeapon).ToList();

                        if (!rangedWeapons.NullOrEmpty())
                        {
                            foreach (Thing thing in rangedWeapons)
                            {
                                if (thing.TryGetComp <CompAmmoUser>() == null)
                                {
                                    // pickup a non-CE ranged weapon...
                                    int numToThing = 0;
                                    if (inventory.CanFitInInventory(thing, out numToThing))
                                    {
                                        return(new Job(JobDefOf.Equip, thing)
                                        {
                                            checkOverrideOnExpire = true,
                                            expiryInterval = 100
                                        });
                                    }
                                }
                                else
                                {
                                    // pickup a CE ranged weapon...
                                    List <ThingDef> thingDefAmmoList = thing.TryGetComp <CompAmmoUser>().Props.ammoSet.ammoTypes.Select(g => g.ammo as ThingDef).ToList();

                                    Predicate <Thing> validatorA = (Thing t) => t.def.category == ThingCategory.Item &&
                                                                   t is AmmoThing && pawn.CanReserve(t, 1) &&
                                                                   (DangerInPosRadius(pawn, t.Position, pawn.Map, 30f).Count() <= 0
                                                                ? pawn.Position.InHorDistOf(t.Position, 25f)
                                                                : pawn.Position.InHorDistOf(t.Position, 6f)) &&
                                                                   pawn.CanReach(t, PathEndMode.Touch, Danger.Deadly, true) &&
                                                                   (pawn.Faction.HostileTo(Faction.OfPlayer) || pawn.Faction == Faction.OfPlayer || !pawn.Map.areaManager.Home[t.Position]);

                                    List <Thing> thingAmmoList = (
                                        from t in pawn.Map.listerThings.ThingsInGroup(ThingRequestGroup.HaulableAlways)
                                        where validatorA(t)
                                        select t
                                        ).ToList();

                                    if (thingAmmoList.Count > 0 && thingDefAmmoList.Count > 0)
                                    {
                                        int   desiredStackSize = thing.TryGetComp <CompAmmoUser>().Props.magazineSize * 2;
                                        Thing th = thingAmmoList.FirstOrDefault(x => thingDefAmmoList.Contains(x.def) && x.stackCount > desiredStackSize);
                                        if (th != null)
                                        {
                                            int numToThing = 0;
                                            if (inventory.CanFitInInventory(thing, out numToThing))
                                            {
                                                return(new Job(JobDefOf.Equip, thing)
                                                {
                                                    checkOverrideOnExpire = true,
                                                    expiryInterval = 100
                                                });
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        // else if no ranged weapons with nearby ammo was found, lets consider a melee weapon.
                        if (allWeapons != null && allWeapons.Count > 0)
                        {
                            // since we don't need to worry about ammo, just pick one.
                            Thing meleeWeapon = allWeapons.FirstOrDefault(w => !w.def.IsRangedWeapon && w.def.IsMeleeWeapon);

                            if (meleeWeapon != null)
                            {
                                return(new Job(JobDefOf.Equip, meleeWeapon)
                                {
                                    checkOverrideOnExpire = true,
                                    expiryInterval = 100
                                });
                            }
                        }
                    }
                }

                // Find ammo
                if ((GetPriorityWork(pawn) == WorkPriority.Ammo || GetPriorityWork(pawn) == WorkPriority.LowAmmo) &&
                    primaryammouser != null)
                {
                    List <ThingDef> curAmmoList = (from AmmoLink g in primaryammouser.Props.ammoSet.ammoTypes
                                                   select g.ammo as ThingDef).ToList();

                    if (curAmmoList.Count > 0)
                    {
                        Predicate <Thing> validator = (Thing t) => t is AmmoThing && pawn.CanReserve(t, 1) &&
                                                      pawn.CanReach(t, PathEndMode.Touch, Danger.Deadly, true) &&
                                                      ((pawn.Faction.IsPlayer && !ForbidUtility.IsForbidden(t, pawn)) || (!pawn.Faction.IsPlayer && DangerInPosRadius(pawn, t.Position, Find.VisibleMap, 30f).Count() <= 0
                                                                ? pawn.Position.InHorDistOf(t.Position, 25f)
                                                                : pawn.Position.InHorDistOf(t.Position, 6f))) &&
                                                      (pawn.Faction.HostileTo(Faction.OfPlayer) || pawn.Faction == Faction.OfPlayer || !pawn.Map.areaManager.Home[t.Position]);
                        List <Thing> curThingList = (
                            from t in pawn.Map.listerThings.ThingsInGroup(ThingRequestGroup.HaulableAlways)
                            where validator(t)
                            select t
                            ).ToList();
                        foreach (Thing th in curThingList)
                        {
                            foreach (ThingDef thd in curAmmoList)
                            {
                                if (thd == th.def)
                                {
                                    //Defence from low count loot spam
                                    float thw = (th.GetStatValue(CE_StatDefOf.Bulk)) * th.stackCount;
                                    if (thw > 0.5f)
                                    {
                                        if (pawn.Faction.IsPlayer)
                                        {
                                            int SearchRadius = 0;
                                            if (GetPriorityWork(pawn) == WorkPriority.LowAmmo)
                                            {
                                                SearchRadius = 70;
                                            }
                                            else
                                            {
                                                SearchRadius = 30;
                                            }

                                            Thing closestThing = GenClosest.ClosestThingReachable(
                                                pawn.Position,
                                                pawn.Map,
                                                ThingRequest.ForDef(th.def),
                                                PathEndMode.ClosestTouch,
                                                TraverseParms.For(pawn, Danger.None, TraverseMode.ByPawn),
                                                SearchRadius,
                                                x => !x.IsForbidden(pawn) && pawn.CanReserve(x));

                                            if (closestThing != null)
                                            {
                                                int numToCarry = 0;
                                                if (inventory.CanFitInInventory(th, out numToCarry))
                                                {
                                                    return(new Job(JobDefOf.TakeInventory, th)
                                                    {
                                                        count = numToCarry
                                                    });
                                                }
                                            }
                                        }
                                        else
                                        {
                                            int numToCarry = 0;
                                            if (inventory.CanFitInInventory(th, out numToCarry))
                                            {
                                                return(new Job(JobDefOf.TakeInventory, th)
                                                {
                                                    count = Mathf.RoundToInt(numToCarry * 0.8f),
                                                    expiryInterval = 150,
                                                    checkOverrideOnExpire = true
                                                });
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                /*
                 * if (!pawn.Faction.IsPlayer && pawn.apparel != null && GetPriorityWork(pawn) == WorkPriority.Apparel)
                 * {
                 *  if (!pawn.apparel.BodyPartGroupIsCovered(BodyPartGroupDefOf.Torso))
                 *  {
                 *      Apparel apparel = this.FindGarmentCoveringPart(pawn, BodyPartGroupDefOf.Torso);
                 *      if (apparel != null)
                 *      {
                 *          int numToapparel = 0;
                 *          if (inventory.CanFitInInventory(apparel, out numToapparel))
                 *          {
                 *              return new Job(JobDefOf.Wear, apparel)
                 *              {
                 *                  ignoreForbidden = true
                 *              };
                 *          }
                 *      }
                 *  }
                 *  if (!pawn.apparel.BodyPartGroupIsCovered(BodyPartGroupDefOf.Legs))
                 *  {
                 *      Apparel apparel2 = this.FindGarmentCoveringPart(pawn, BodyPartGroupDefOf.Legs);
                 *      if (apparel2 != null)
                 *      {
                 *          int numToapparel2 = 0;
                 *          if (inventory.CanFitInInventory(apparel2, out numToapparel2))
                 *          {
                 *              return new Job(JobDefOf.Wear, apparel2)
                 *              {
                 *                  ignoreForbidden = true
                 *              };
                 *          }
                 *      }
                 *  }
                 *  if (!pawn.apparel.BodyPartGroupIsCovered(BodyPartGroupDefOf.FullHead))
                 *  {
                 *      Apparel apparel3 = this.FindGarmentCoveringPart(pawn, BodyPartGroupDefOf.FullHead);
                 *      if (apparel3 != null)
                 *      {
                 *          int numToapparel3 = 0;
                 *          if (inventory.CanFitInInventory(apparel3, out numToapparel3))
                 *          {
                 *              return new Job(JobDefOf.Wear, apparel3)
                 *              {
                 *                  ignoreForbidden = true,
                 *                  locomotionUrgency = LocomotionUrgency.Sprint
                 *              };
                 *          }
                 *      }
                 *  }
                 * }
                 */
                return(null);
            }
            return(null);
        }
Пример #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
        /// <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);
        }
Пример #27
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);
        }
Пример #28
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;
        }
Пример #29
0
        private void DrawThingRow(ref float y, float width, Thing thing, bool showDropButtonIfPrisoner = false)
        {
            Rect rect = new Rect(0f, y, width, _thingRowHeight);

            Widgets.InfoCardButton(rect.width - 24f, y, thing);
            rect.width -= 24f;
            if (CanControl || (SelPawnForGear.Faction == Faction.OfPlayer && SelPawnForGear.RaceProps.packAnimal) || (showDropButtonIfPrisoner && SelPawnForGear.IsPrisonerOfColony))
            {
                var   dropForbidden  = IsItemDropForbidden(thing);
                Color color          = dropForbidden ? Color.grey : Color.white;
                Color mouseoverColor = dropForbidden ? Color.grey : GenUI.MouseoverColor;
                Rect  dropRect       = new Rect(rect.width - 24f, y, 24f, 24f);
                TooltipHandler.TipRegion(dropRect, dropForbidden ? "DropThingLocked".Translate() : "DropThing".Translate());
                if (Widgets.ButtonImage(dropRect, TexButton.Drop, color, mouseoverColor) && !dropForbidden)
                {
                    SoundDefOf.Tick_High.PlayOneShotOnCamera();
                    InterfaceDrop(thing);
                }
                rect.width -= 24f;
            }
            if (CanControlColonist)
            {
                if ((thing.def.IsNutritionGivingIngestible || thing.def.IsNonMedicalDrug) && thing.IngestibleNow && base.SelPawn.WillEat(thing, null) && (!SelPawnForGear.IsTeetotaler() || !thing.def.IsNonMedicalDrug))
                {
                    Rect rect3 = new Rect(rect.width - 24f, y, 24f, 24f);
                    TooltipHandler.TipRegion(rect3, "ConsumeThing".Translate(thing.LabelNoCount, thing));
                    if (Widgets.ButtonImage(rect3, TexButton.Ingest))
                    {
                        SoundDefOf.Tick_High.PlayOneShotOnCamera(null);
                        InterfaceIngest(thing);
                    }
                }
                rect.width -= 24f;
            }
            Rect rect4 = rect;

            rect4.xMin = rect4.xMax - 60f;
            CaravanThingsTabUtility.DrawMass(thing, rect4);
            rect.width -= 60f;
            if (Mouse.IsOver(rect))
            {
                GUI.color = _highlightColor;
                GUI.DrawTexture(rect, TexUI.HighlightTex);
            }

            if (thing.def.DrawMatSingle != null && thing.def.DrawMatSingle.mainTexture != null)
            {
                Widgets.ThingIcon(new Rect(4f, y, _thingIconSize, _thingIconSize), thing, 1f);
            }
            Text.Anchor = TextAnchor.MiddleLeft;
            GUI.color   = ThingLabelColor;
            Rect   thingLabelRect = new Rect(_thingLeftX, y, rect.width - _thingLeftX, _thingRowHeight);
            string thingLabel     = thing.LabelCap;

            if ((thing is Apparel && SelPawnForGear.outfits != null && SelPawnForGear.outfits.forcedHandler.IsForced((Apparel)thing)) ||
                (SelPawnForGear.inventory != null && SelPawnForGear.HoldTrackerIsHeld(thing)))
            {
                thingLabel = thingLabel + ", " + "ApparelForcedLower".Translate();
            }

            Text.WordWrap = false;
            Widgets.Label(thingLabelRect, thingLabel.Truncate(thingLabelRect.width, null));
            Text.WordWrap = true;
            string text2 = string.Concat(new object[]
            {
                thing.LabelCap,
                "\n",
                thing.DescriptionDetailed,
                "\n",
                thing.GetWeightAndBulkTip()
            });

            if (thing.def.useHitPoints)
            {
                string text3 = text2;
                text2 = string.Concat(new object[]
                {
                    text3,
                    "\n",
                    "HitPointsBasic".Translate().CapitalizeFirst(),
                    ": ",
                    thing.HitPoints,
                    " / ",
                    thing.MaxHitPoints
                });
            }
            TooltipHandler.TipRegion(thingLabelRect, text2);
            y += 28f;

            // RMB menu
            if (Widgets.ButtonInvisible(thingLabelRect) && Event.current.button == 1)
            {
                List <FloatMenuOption> floatOptionList = new List <FloatMenuOption>();
                floatOptionList.Add(new FloatMenuOption("ThingInfo".Translate(), delegate
                {
                    Find.WindowStack.Add(new Dialog_InfoCard(thing));
                }, MenuOptionPriority.Default, null, null));
                if (CanControl)
                {
                    // Equip option
                    ThingWithComps eq = thing as ThingWithComps;
                    if (eq != null && eq.TryGetComp <CompEquippable>() != null)
                    {
                        CompInventory  compInventory = SelPawnForGear.TryGetComp <CompInventory>();
                        CompBiocodable compBiocoded  = eq.TryGetComp <CompBiocodable>();
                        if (compInventory != null)
                        {
                            FloatMenuOption equipOption;
                            string          eqLabel = GenLabel.ThingLabel(eq.def, eq.Stuff, 1);
                            if (compBiocoded != null && compBiocoded.Biocoded && compBiocoded.CodedPawn != SelPawnForGear)
                            {
                                equipOption = new FloatMenuOption("CannotEquip".Translate(eqLabel) + ": " + "BiocodedCodedForSomeoneElse".Translate(), null);
                            }
                            else if (SelPawnForGear.IsQuestLodger() && !EquipmentUtility.QuestLodgerCanEquip(eq, SelPawnForGear))
                            {
                                var forbiddenEquipOrPutAway = SelPawnForGear.equipment.AllEquipmentListForReading.Contains(eq) ? "CE_CannotPutAway".Translate(eqLabel) : "CannotEquip".Translate(eqLabel);
                                equipOption = new FloatMenuOption(forbiddenEquipOrPutAway + ": " + "CE_CannotChangeEquipment".Translate(), null);
                            }
                            else if (SelPawnForGear.equipment.AllEquipmentListForReading.Contains(eq) && SelPawnForGear.inventory != null)
                            {
                                equipOption = new FloatMenuOption("CE_PutAway".Translate(eqLabel),
                                                                  new Action(delegate
                                {
                                    SelPawnForGear.equipment.TryTransferEquipmentToContainer(SelPawnForGear.equipment.Primary, SelPawnForGear.inventory.innerContainer);
                                }));
                            }
                            else if (!SelPawnForGear.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation))
                            {
                                equipOption = new FloatMenuOption("CannotEquip".Translate(eqLabel), null);
                            }
                            else
                            {
                                string equipOptionLabel = "Equip".Translate(eqLabel);
                                if (eq.def.IsRangedWeapon && SelPawnForGear.story != null && SelPawnForGear.story.traits.HasTrait(TraitDefOf.Brawler))
                                {
                                    equipOptionLabel = equipOptionLabel + " " + "EquipWarningBrawler".Translate();
                                }
                                equipOption = new FloatMenuOption(
                                    equipOptionLabel,
                                    (SelPawnForGear.story != null && SelPawnForGear.WorkTagIsDisabled(WorkTags.Violent))
                                    ? null
                                    : new Action(delegate
                                {
                                    compInventory.TrySwitchToWeapon(eq);
                                }));
                            }
                            floatOptionList.Add(equipOption);
                        }
                    }
                    //Reload apparel option
                    IEnumerable <Apparel> worn_apparel = SelPawnForGear?.apparel?.WornApparel ?? Enumerable.Empty <Apparel>();
                    foreach (var apparel in worn_apparel)
                    {
                        var compReloadable = apparel.TryGetComp <CompReloadable>();
                        if (compReloadable != null && compReloadable.AmmoDef == thing.def && compReloadable.NeedsReload(true))
                        {
                            if (!SelPawnForGear.Drafted)    //TODO-1.2 This should be doable for drafted pawns as well, but the job does nothing. Figure out what's wrong and remove this condition.
                            {
                                FloatMenuOption reloadApparelOption = new FloatMenuOption(
                                    "CE_ReloadApparel".Translate(apparel.Label, thing.Label),
                                    new Action(delegate
                                {
                                    //var reloadJob = JobMaker.MakeJob(JobDefOf.Reload, apparel, thing);
                                    //SelPawnForGear.jobs.StartJob(reloadJob, JobCondition.InterruptForced, null, SelPawnForGear.CurJob?.def != reloadJob.def, true);

                                    SelPawnForGear.jobs.TryTakeOrderedJob(JobMaker.MakeJob(JobDefOf.Reload, apparel, thing));
                                })
                                    );
                                floatOptionList.Add(reloadApparelOption);
                            }
                        }
                    }
                    // Consume option
                    if (CanControl && thing.IngestibleNow && base.SelPawn.RaceProps.CanEverEat(thing))
                    {
                        Action eatFood = delegate
                        {
                            SoundDefOf.Tick_High.PlayOneShotOnCamera();
                            InterfaceIngest(thing);
                        };
                        string label = thing.def.ingestible.ingestCommandString.NullOrEmpty() ? (string)"ConsumeThing".Translate(thing.LabelShort, thing) : string.Format(thing.def.ingestible.ingestCommandString, thing.LabelShort);
                        if (SelPawnForGear.IsTeetotaler() && thing.def.IsNonMedicalDrug)
                        {
                            floatOptionList.Add(new FloatMenuOption(label + ": " + TraitDefOf.DrugDesire.degreeDatas.Where(x => x.degree == -1).First()?.label, null));
                        }
                        else
                        {
                            floatOptionList.Add(new FloatMenuOption(label, eatFood));
                        }
                    }
                    // Drop, and drop&haul options
                    if (IsItemDropForbidden(eq))
                    {
                        floatOptionList.Add(new FloatMenuOption("CE_CannotDropThing".Translate() + ": " + "DropThingLocked".Translate(), null));
                        floatOptionList.Add(new FloatMenuOption("CE_CannotDropThingHaul".Translate() + ": " + "DropThingLocked".Translate(), null));
                    }
                    else
                    {
                        floatOptionList.Add(new FloatMenuOption("DropThing".Translate(), new Action(delegate
                        {
                            SoundDefOf.Tick_High.PlayOneShotOnCamera();
                            InterfaceDrop(thing);
                        })));
                        floatOptionList.Add(new FloatMenuOption("CE_DropThingHaul".Translate(), new Action(delegate
                        {
                            SoundDefOf.Tick_High.PlayOneShotOnCamera();
                            InterfaceDropHaul(thing);
                        })));
                    }
                    // Stop holding in inventory option
                    if (CanControl && SelPawnForGear.HoldTrackerIsHeld(thing))
                    {
                        Action forgetHoldTracker = delegate
                        {
                            SoundDefOf.Tick_High.PlayOneShotOnCamera();
                            SelPawnForGear.HoldTrackerForget(thing);
                        };
                        floatOptionList.Add(new FloatMenuOption("CE_HoldTrackerForget".Translate(), forgetHoldTracker));
                    }
                }
                FloatMenu window = new FloatMenu(floatOptionList, thing.LabelCap, false);
                Find.WindowStack.Add(window);
            }
            // end menu
        }
Пример #30
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);
        }