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()); }
/// <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; } } }
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); }
/// <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); }
/// <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); } }
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(); }
// 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); } }
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); }
/// <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); }
/// <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); } } }
/// <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); }
/// <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); }
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; }
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)); } }
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); }
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 }
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); }
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); }
/// <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); }
/// <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); }
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; }
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 }
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); }