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); }
/* Rough Algorithm * Need Things so the collection of ammo users that use magazines. Also need a collection of ammo (ThingDef is OK here). * For each weapon (that fits above), * -If we have no ammo in inventory that the gun is loaded with, check loadouts/holdtracker for a clip's worth of ammo that the gun contains. * --Find ammo the gun uses that we have a clip's worth in inventory (should check it against loadout/holdtracker as well) * -If weapon is low on ammo and we have enough in inventory to fill it up. * * If either of the above are true, trigger a reload. */ /// <summary> /// Check's the pawn's equipment and inventory for weapons that could use a reload. /// </summary> /// <param name="pawn">Pawn to check the equipment and inventory of.</param> /// <param name="reloadWeapon">Thing weapon which needs to be reloaded.</param> /// <param name="reloadAmmo">AmmoDef ammo to reload the gun with.</param> /// <returns>Bool value indicating if the job needs to be done.</returns> private bool DoReloadCheck(Pawn pawn, out ThingWithComps reloadWeapon, out AmmoDef reloadAmmo) { reloadWeapon = null; reloadAmmo = null; // First need to create the collections that will be searched. List <ThingWithComps> guns = new List <ThingWithComps>(); CompInventory inventory = pawn.TryGetComp <CompInventory>(); CompAmmoUser tmpComp; Loadout loadout = pawn.GetLoadout(); bool pawnHasLoadout = loadout != null && !loadout.Slots.NullOrEmpty(); if (inventory == null) { return(false); // There isn't any work to do since the pawn doesn't have a CE Inventory. } if ((tmpComp = pawn.equipment?.Primary?.TryGetComp <CompAmmoUser>()) != null && tmpComp.HasMagazine) { guns.Add(pawn.equipment.Primary); } // CompInventory doesn't track equipment and it's desired to check the pawn's equipped weapon before inventory items so need to copy stuff from Inventory Cache. guns.AddRange(inventory.rangedWeaponList.Where(t => t.TryGetComp <CompAmmoUser>() != null && t.GetComp <CompAmmoUser>().HasMagazine)); if (guns.NullOrEmpty()) { return(false); // There isn't any work to do since the pawn doesn't have any ammo using guns. } // look at each gun... foreach (ThingWithComps gun in guns) { // Get key stats of the weapon. tmpComp = gun.TryGetComp <CompAmmoUser>(); AmmoDef ammoType = tmpComp.CurrentAmmo; int ammoAmount = tmpComp.CurMagCount; int magazineSize = tmpComp.Props.magazineSize; // Is the gun loaded with ammo not in a Loadout/HoldTracker? if (tmpComp.UseAmmo && pawnHasLoadout && !TrackingSatisfied(pawn, ammoType, magazineSize)) { // Do we have ammo in the inventory that the gun uses which satisfies requirements? (expensive) AmmoDef matchAmmo = tmpComp.Props.ammoSet.ammoTypes .Where(al => al.ammo != ammoType) .Select(al => al.ammo) .FirstOrDefault(ad => TrackingSatisfied(pawn, ad, magazineSize) && inventory.AmmoCountOfDef(ad) >= magazineSize); if (matchAmmo != null) { reloadWeapon = gun; reloadAmmo = matchAmmo; return(true); } } // Is the gun low on ammo? if (tmpComp.CurMagCount < magazineSize) { // Do we have enough ammo in the inventory to top it off? if (!tmpComp.UseAmmo || inventory.AmmoCountOfDef(ammoType) >= (magazineSize - tmpComp.CurMagCount)) { reloadWeapon = gun; reloadAmmo = ammoType; return(true); //} else { // (ProfoundDarkness) I think the idea of this branch was that the JobGiver might initiate fetching ammo but it actually runs AFTER the one that fetches ammo for loadout. // There wasn't enough in the inventory to top it off. At this point we know the loadout is satisfied for this ammo... // We could do a more strict check to see if the pawn's loadout is satisfied to pick up ammo and if not swap to another ammo...? } } } return(false); }