/// <summary> /// If RimWorld decides the pawn should do this job, this is called to get the pawn working on it. /// </summary> /// <param name="pawn">Pawn that the job is supposed to take place on.</param> /// <returns>Job that the pawn is to be working on.</returns> protected override Job TryGiveJob(Pawn pawn) { ThingWithComps gun; AmmoDef ammo; Job reloadJob = null; if (DoReloadCheck(pawn, out gun, out ammo)) { CompAmmoUser comp = gun.TryGetComp <CompAmmoUser>(); CompInventory compInventory = pawn.TryGetComp <CompInventory>(); // we relied on DoReloadCheck() to do error checking of many variables. if (!comp.TryUnload()) { return(null); // unload the weapon or stop trying if there was a problem. } // change ammo type if necessary. if (comp.UseAmmo && comp.CurrentAmmo != ammo) { comp.SelectedAmmo = ammo; } // Get the reload job from the comp. reloadJob = comp.TryMakeReloadJob(); } return(reloadJob); }
/// <summary> /// Attempts to equip a weapon from the inventory, puts currently equipped weapon into inventory if it exists /// </summary> /// <param name="useFists">Whether to put the currently equipped weapon away even if no replacement is found</param> public void SwitchToNextViableWeapon(bool useFists = true) { ThingWithComps newEq = null; // Stop current job if (parentPawn.jobs != null) { parentPawn.jobs.StopAll(); } // Cycle through available ranged weapons foreach (ThingWithComps gun in rangedWeaponListCached) { if (parentPawn.equipment == null || parentPawn.equipment.Primary != gun) { CompAmmoUser compAmmo = gun.TryGetComp <CompAmmoUser>(); if (compAmmo == null || !compAmmo.useAmmo || compAmmo.curMagCount > 0 || compAmmo.hasAmmo) { newEq = gun; break; } } } // If no ranged weapon was found, use first available melee weapons if (newEq == null) { newEq = meleeWeaponListCached.FirstOrDefault(); } // Equip the weapon if (newEq != null) { TrySwitchToWeapon(newEq); } else if (useFists && parentPawn.equipment?.Primary != null) { ThingWithComps oldEq; if (!parentPawn.equipment.TryTransferEquipmentToContainer(parentPawn.equipment.Primary, container, out oldEq)) { if (parentPawn.Position.InBounds(parentPawn.Map)) { ThingWithComps unused; parentPawn.equipment.TryDropEquipment(oldEq, out unused, parentPawn.Position); } else { #if DEBUG Log.Message("CE :: CompInventory :: SwitchToNextViableWeapon :: destroying out of bounds equipment" + oldEq.ToString()); #endif if (!oldEq.Destroyed) { oldEq.Destroy(); } } } } }
private Job TryGetAttackNearbyEnemyJob(Pawn pawn) { if (pawn.story != null && pawn.WorkTagIsDisabled(WorkTags.Violent)) { return(null); } bool flag = pawn.equipment.Primary == null || pawn.equipment.Primary.def.IsMeleeWeapon; float num = 8f; if (!flag) { num = Mathf.Clamp(pawn.equipment.PrimaryEq.PrimaryVerb.verbProps.range * 0.66f, 2f, 20f); } float maxDist = num; Thing thing = (Thing)AttackTargetFinder.BestAttackTarget(pawn, TargetScanFlags.NeedLOSToPawns | TargetScanFlags.NeedLOSToNonPawns | TargetScanFlags.NeedReachableIfCantHitFromMyPos | TargetScanFlags.NeedThreat, null, 0f, maxDist, default(IntVec3), 3.40282347E+38f, false); // TODO evaluate if this is necessary? Pawn o = thing as Pawn; if (o != null) { if (o.Downed || o.health.InPainShock) { return(null); } } if (thing == null) { return(null); } if (flag || thing.Position.AdjacentTo8Way(pawn.Position)) { return(new Job(JobDefOf.AttackMelee, thing)); } // Check for reload before attacking bool allowManualCastWeapons = !pawn.IsColonist; //TODO: Is this correct? Verb verb = pawn.TryGetAttackVerb(thing, allowManualCastWeapons); if (pawn.equipment.Primary != null && pawn.equipment.PrimaryEq != null && verb != null && verb == pawn.equipment.PrimaryEq.PrimaryVerb) { CompAmmoUser compAmmo = pawn.equipment.Primary.TryGetComp <CompAmmoUser>(); if (compAmmo != null && !compAmmo.CanBeFiredNow) { if (compAmmo.HasAmmo) { Job job = new Job(CE_JobDefOf.ReloadWeapon, pawn, pawn.equipment.Primary); if (job != null) { return(job); } } return(new Job(JobDefOf.AttackMelee, thing)); } } return(new Job(JobDefOf.AttackStatic, thing)); }
private void MakeGun() { this.gunInt = ThingMaker.MakeThing(this.def.building.turretGunDef, null); this.compAmmo = gunInt.TryGetComp <CompAmmoUser>(); InitGun(); }
/// <summary> /// Attempts to equip a weapon from the inventory, puts currently equipped weapon into inventory if it exists /// </summary> /// <param name="useFists">Whether to put the currently equipped weapon away even if no replacement is found</param> public void SwitchToNextViableWeapon(bool useFists = true) { ThingWithComps newEq = null; // Stop current job if (parentPawn.jobs != null) { parentPawn.jobs.StopAll(); } // Cycle through available ranged weapons foreach (ThingWithComps gun in rangedWeaponListCached) { if (parentPawn.equipment != null && parentPawn.equipment.Primary != gun) { CompAmmoUser compAmmo = gun.TryGetComp <CompAmmoUser>(); if (compAmmo == null || compAmmo.HasAndUsesAmmoOrMagazine) { newEq = gun; break; } } } // If no ranged weapon was found, use first available melee weapons if (newEq == null) { newEq = meleeWeaponListCached.FirstOrDefault(); } // Equip the weapon if (newEq != null) { TrySwitchToWeapon(newEq); } else if (useFists) { // Put away current weapon ThingWithComps eq = parentPawn.equipment?.Primary; if (eq != null && !parentPawn.equipment.TryTransferEquipmentToContainer(eq, container)) { // If we can't put it into our inventory, drop it if (parentPawn.Position.InBounds(parentPawn.Map)) { ThingWithComps unused; parentPawn.equipment.TryDropEquipment(eq, out unused, parentPawn.Position); } else { #if DEBUG Log.Warning("CE :: CompInventory :: SwitchToNextViableWeapon :: destroying out of bounds equipment" + eq.ToString()); #endif if (!eq.Destroyed) { eq.Destroy(); } } } } }
private Job TryGetAttackNearbyEnemyJob(Pawn pawn) { if (pawn.story != null && pawn.story.WorkTagIsDisabled(WorkTags.Violent)) { return(null); } bool isMeleeAttack = pawn.CurrentEffectiveVerb.IsMeleeAttack; float num = 8f; if (!isMeleeAttack) { num = Mathf.Clamp(pawn.CurrentEffectiveVerb.verbProps.range * 0.66f, 2f, 20f); } float maxDist = num; Thing thing = (Thing)AttackTargetFinder.BestAttackTarget(pawn, TargetScanFlags.NeedLOSToPawns | TargetScanFlags.NeedLOSToNonPawns | TargetScanFlags.NeedReachableIfCantHitFromMyPos | TargetScanFlags.NeedThreat, null, 0f, maxDist, default(IntVec3), 3.40282347E+38f, false); // TODO evaluate if this is necessary? Pawn o = thing as Pawn; if (o != null) { if (o.Downed || o.health.InPainShock) { return(null); } } if (thing == null) { return(null); } if (isMeleeAttack || pawn.CanReachImmediate(thing, PathEndMode.Touch)) { return(new Job(JobDefOf.AttackMelee, thing)); } // Check for reload before attacking Verb verb = pawn.TryGetAttackVerb(thing); if (pawn.equipment.Primary != null && pawn.equipment.PrimaryEq != null && verb != null && verb == pawn.CurrentEffectiveVerb) { CompAmmoUser compAmmo = pawn.equipment.Primary.TryGetComp <CompAmmoUser>(); if (compAmmo != null && !compAmmo.CanBeFiredNow) { if (compAmmo.HasAmmo) { Job job = new Job(CE_JobDefOf.ReloadWeapon, pawn, pawn.equipment.Primary); if (job != null) { return(job); } } return(new Job(JobDefOf.AttackMelee, thing)); } } return(new Job(JobDefOf.AttackStatic, thing)); }
/// <summary> /// THIS IS A VERY SLOW FUNCTION!! USE IT CAREFULY! /// Try to find a random weapon in inventory that has ammo and is ready combat. /// This will first check ranged weapons then melee weapons. /// </summary> /// <param name="pawn">Pawn</param> /// <param name="weapon">out The random weapons (if no ranged weapons are found and includeMelee it will return a melee weapon)</param> /// <param name="includeMelee">Return a random melee weapon if no ranged weapons found</param> /// <param name="includeAOE">Include explosive weapons</param> /// <returns>If a weapon is found</returns> public static bool TryGetRandomUsableWeapon(this Pawn pawn, out ThingWithComps weapon, bool includeMelee = true, bool includeAOE = false, bool rebuildInvetory = false) { weapon = null; CompInventory compInventory = pawn.TryGetComp <CompInventory>(); if (compInventory == null) { return(false); } if (rebuildInvetory) { compInventory.UpdateInventory(); } List <ThingWithComps> rangedGuns = compInventory.rangedWeaponList; if (rangedGuns == null || rangedGuns.Count == 0) { if (!includeMelee) { return(false); } List <ThingWithComps> meleeWeapons = compInventory.meleeWeaponList; if (meleeWeapons == null || meleeWeapons.Count == 0) { return(false); } weapon = meleeWeapons.RandomElement(); return(true); } if (!Controller.settings.EnableAmmoSystem) { weapon = rangedGuns.RandomElement(); return(true); } foreach (ThingWithComps gun in rangedGuns.InRandomOrder()) { CompAmmoUser compAmmo = gun.GetComp <CompAmmoUser>(); if (compAmmo == null || compAmmo.IsEquippedGun) { continue; } // check if this is an explosive weapon if (!includeAOE && (compAmmo.Props?.ammoSet?.ammoTypes?.RandomElement().ammo?.detonateProjectile != null)) { continue; } // check readiness if (compAmmo.CanBeFiredNow || compAmmo.TryFindAmmoInInventory(out Thing _)) { weapon = gun; return(true); } } return(false); }
/// <summary> /// Extension method to determine whether a ranged weapon has ammo available to it /// </summary> /// <returns>True if the gun has no CompAmmoUser, doesn't use ammo or has ammo in its magazine or carrier inventory, false otherwise</returns> public static bool HasAmmo(this ThingWithComps gun) { CompAmmoUser comp = gun.TryGetComp <CompAmmoUser>(); if (comp == null) { return(true); } return(!comp.UseAmmo || comp.CurMagCount > 0 || comp.HasAmmo); }
/// <summary> /// Used to get or check if this pawn has a CE (ammo enabled weapon) weapon equiped. /// </summary> /// <param name="pawn">Pawn</param> /// <param name="gun">out the Primary ammo enabled weapon/equipment</param> /// <returns>If the primary equipment is ammo enabled weapon has been found</returns> public static bool TryGetPrimaryCEWeapon(this Pawn pawn, out Thing gun) { gun = pawn.equipment?.Primary; CompAmmoUser ammoUser = gun?.TryGetComp <CompAmmoUser>() ?? null; if (ammoUser == null || !ammoUser.HasMagazine || ammoUser.CurMagCount > 0) { return(false); // gun isn't an ammo user that stores ammo internally or isn't out of bullets. } return(true); }
private bool HasNoGunOrAmmo() { if (TargetThingB.DestroyedOrNull() || pawn.equipment == null || pawn.equipment.Primary == null || pawn.equipment.Primary != TargetThingB) { return(true); } CompAmmoUser comp = pawn.equipment.Primary.TryGetComp <CompAmmoUser>(); return(comp != null && comp.useAmmo && !comp.hasAmmo); }
public static void GetEquipmentStats(ThingWithComps eq, out float weight, out float bulk) { weight = eq.GetStatValue(StatDefOf.Mass); //old weight = eq.GetStatValue(CE_StatDefOf.Weight); bulk = eq.GetStatValue(CE_StatDefOf.Bulk); CompAmmoUser comp = eq.TryGetComp <CompAmmoUser>(); if (comp != null && comp.CurrentAmmo != null) { weight += comp.CurrentAmmo.GetStatValueAbstract(StatDefOf.Mass) * comp.CurMagCount; //old weight += comp.currentAmmo.GetStatValueAbstract(CE_StatDefOf.Weight) * comp.curMagCount; bulk += comp.CurrentAmmo.GetStatValueAbstract(CE_StatDefOf.Bulk) * comp.CurMagCount; } }
private void LoadWeaponWithRandAmmo(ThingWithComps gun) { CompAmmoUser compAmmo = gun.TryGetComp <CompAmmoUser>(); if (compAmmo == null) { return; } if (!compAmmo.UseAmmo) { compAmmo.ResetAmmoCount(); return; } // Determine ammo IEnumerable <AmmoDef> availableAmmo = compAmmo.Props.ammoSet.ammoTypes.Where(a => a.ammo.alwaysHaulable).Select(a => a.ammo); //Running out of options. alwaysHaulable does exist in xml. AmmoDef ammoToLoad = availableAmmo.RandomElementByWeight(a => a.generateCommonality); compAmmo.ResetAmmoCount(ammoToLoad); }
/// <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); }
protected void AddAvailableAmmoFor(ThingWithComps eq) { if (eq == null || availableDefs == null) { return; } CompAmmoUser compAmmo = eq.TryGetComp <CompAmmoUser>(); if (compAmmo != null && !compAmmo.Props.ammoSet.ammoTypes.NullOrEmpty()) { List <ThingDef> listammo = (from ThingDef g in compAmmo.Props.ammoSet.ammoTypes where g.canBeSpawningInventory select g).ToList <ThingDef>(); if (!listammo.NullOrEmpty()) { ThingDef randomammo = GenCollection.RandomElement <ThingDef>(listammo); availableDefs.Add(randomammo); } else { return; } } }
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); }
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); }
protected override Job TryGiveJob(Pawn pawn) { if (!pawn.RaceProps.Humanlike || (pawn.story != null && pawn.story.WorkTagIsDisabled(WorkTags.Violent))) { return(null); } if (pawn.Faction.IsPlayer && pawn.Drafted) { return(null); } /* * Log.Message(pawn.ToString() + " priority:" + (GetPriorityWork(pawn)).ToString()); * Log.Message(pawn.ToString() + " capacityWeight: " + pawn.TryGetComp<CompInventory>().capacityWeight.ToString()); * Log.Message(pawn.ToString() + " currentWeight: " + pawn.TryGetComp<CompInventory>().currentWeight.ToString()); * Log.Message(pawn.ToString() + "capacityBulk: " + pawn.TryGetComp<CompInventory>().capacityBulk.ToString()); * Log.Message(pawn.ToString() + "currentBulk: " + pawn.TryGetComp<CompInventory>().currentBulk.ToString()); */ var brawler = pawn.story.traits.HasTrait(TraitDefOf.Brawler); CompInventory inventory = pawn.TryGetComp <CompInventory>(); CompAmmoUser ammouser = pawn.TryGetComp <CompAmmoUser>(); CompAmmoUser primaryammouser = pawn.equipment.Primary.TryGetComp <CompAmmoUser>(); if (inventory != null) { Room room = RoomQuery.RoomAtFast(pawn.Position, pawn.Map); // Prefer ranged weapon in inventory if (!pawn.Faction.IsPlayer && pawn.equipment != null) { if (pawn.equipment.Primary != null && pawn.equipment.Primary.def.IsMeleeWeapon && !brawler && (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); if (InvListGun3 != null) { Thing ammoInvListGun3 = null; foreach (ThingDef InvListGunDef3 in InvListGun3.TryGetComp <CompAmmoUser>().Props.ammoSet.ammoTypes) { ammoInvListGun3 = inventory.ammoList.Find(thing => thing.def == InvListGunDef3); break; } if (ammoInvListGun3 != null) { inventory.TrySwitchToWeapon(InvListGun3); } } } } // Drop excess ranged weapon if (!pawn.Faction.IsPlayer && pawn.equipment.Primary != null && primaryammouser != null && GetPriorityWork(pawn) == WorkPriority.Unloading && inventory.rangedWeaponList.Count >= 1) { Thing ListGun = inventory.rangedWeaponList.Find(thing => pawn.equipment != null && pawn.equipment.Primary != null && thing.TryGetComp <CompAmmoUser>() != null && thing.def != pawn.equipment.Primary.def); if (ListGun != null) { Thing ammoListGun = null; foreach (ThingDef ListGunDef in ListGun.TryGetComp <CompAmmoUser>().Props.ammoSet.ammoTypes) { if (inventory.ammoList.Find(thing => thing.def == ListGunDef) == 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 && inventory.ammoList.Count > 1 && GetPriorityWork(pawn) == WorkPriority.Unloading) { Thing WrongammoThing = null; foreach (ThingDef WrongammoDef in primaryammouser.Props.ammoSet.ammoTypes) { WrongammoThing = inventory.ammoList.Find(thing => thing.def != WrongammoDef); break; } if (WrongammoThing != null) { Thing InvListGun = inventory.rangedWeaponList.Find(thing => pawn.equipment != null && pawn.equipment.Primary != null && thing.TryGetComp <CompAmmoUser>() != null && thing.def != pawn.equipment.Primary.def); if (InvListGun != null) { Thing ammoInvListGun = null; foreach (ThingDef InvListGunDef in InvListGun.TryGetComp <CompAmmoUser>().Props.ammoSet.ammoTypes) { ammoInvListGun = inventory.ammoList.Find(thing => thing.def == InvListGunDef); 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)); } } } } // Find weapon in inventory and try to switch if any ammo in inventory. if (GetPriorityWork(pawn) == WorkPriority.Weapon && pawn.equipment.Primary == null) { ThingWithComps InvListGun2 = inventory.rangedWeaponList.Find(thing => thing.TryGetComp <CompAmmoUser>() != null); if (InvListGun2 != null) { Thing ammoInvListGun2 = null; foreach (ThingDef InvListGunDef2 in InvListGun2.TryGetComp <CompAmmoUser>().Props.ammoSet.ammoTypes) { ammoInvListGun2 = inventory.ammoList.Find(thing => thing.def == InvListGunDef2); break; } if (ammoInvListGun2 != null) { inventory.TrySwitchToWeapon(InvListGun2); } } // Find weapon with near ammo for ai. if (!pawn.Faction.IsPlayer && pawn.equipment.Primary == null) { Predicate <Thing> validatorWS = (Thing w) => w.def.IsWeapon && w.MarketValue > 500 && pawn.CanReserve(w, 1) && pawn.CanReach(w, PathEndMode.Touch, Danger.Deadly, true) && (!pawn.Faction.HostileTo(Faction.OfPlayer) && pawn.Map.areaManager.Home[w.Position]) || (pawn.Faction.HostileTo(Faction.OfPlayer)) && (w.Position.DistanceToSquared(pawn.Position) < 15f || room == RoomQuery.RoomAtFast(w.Position, pawn.Map)); List <Thing> weapon = ( 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(); if (weapon != null && weapon.Count > 0) { foreach (Thing thing in weapon) { List <ThingDef> thingDefAmmoList = (from ThingDef g in thing.TryGetComp <CompAmmoUser>().Props.ammoSet.ammoTypes select g).ToList <ThingDef>(); Predicate <Thing> validatorA = (Thing t) => t.def.category == ThingCategory.Item && t is AmmoThing && pawn.CanReserve(t, 1) && pawn.CanReach(t, PathEndMode.Touch, Danger.Deadly, true) && (t.Position.DistanceToSquared(pawn.Position) < 20f || room == RoomQuery.RoomAtFast(t.Position, pawn.Map)); 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) { foreach (Thing th in thingAmmoList) { foreach (ThingDef thd in thingDefAmmoList) { if (thd == th.def) { int ammothingcount = 0; foreach (ThingDef ammoDef in thing.TryGetComp <CompAmmoUser>().Props.ammoSet.ammoTypes) { ammothingcount += th.stackCount; } if (ammothingcount > thing.TryGetComp <CompAmmoUser>().Props.magazineSize * 2) { int numToThing = 0; if (inventory.CanFitInInventory(thing, out numToThing)) { if (thing.Position == pawn.Position || thing.Position.AdjacentToCardinal(pawn.Position)) { return(new Job(JobDefOf.Equip, thing) { checkOverrideOnExpire = true, expiryInterval = 100, canBash = true, locomotionUrgency = LocomotionUrgency.Sprint }); } return(GotoForce(pawn, thing, PathEndMode.Touch)); } } } } } } } } } } // Find ammo if ((GetPriorityWork(pawn) == WorkPriority.Ammo || GetPriorityWork(pawn) == WorkPriority.LowAmmo) && pawn.equipment != null && pawn.equipment.Primary != null && primaryammouser != null) { List <ThingDef> curAmmoList = (from ThingDef g in primaryammouser.Props.ammoSet.ammoTypes select g).ToList <ThingDef>(); 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 && (!pawn.Faction.HostileTo(Faction.OfPlayer) && pawn.Map.areaManager.Home[t.Position]) || (pawn.Faction.HostileTo(Faction.OfPlayer)))) && (t.Position.DistanceToSquared(pawn.Position) < 20f || room == RoomQuery.RoomAtFast(t.Position, pawn.Map)); 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 { if (th.Position == pawn.Position || th.Position.AdjacentToCardinal(pawn.Position)) { 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, canBash = true, locomotionUrgency = LocomotionUrgency.Sprint }); } } return(GotoForce(pawn, th, PathEndMode.Touch)); } } } } } } } 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, locomotionUrgency = LocomotionUrgency.Sprint }); } } } 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, locomotionUrgency = LocomotionUrgency.Sprint }); } } } /* * 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) { #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); }
private WorkPriority GetPriorityWork(Pawn pawn) { CompAmmoUser primaryammouser = pawn.equipment.Primary.TryGetComp <CompAmmoUser>(); if (pawn.Faction.IsPlayer && pawn.equipment.Primary != null && pawn.equipment.Primary.TryGetComp <CompAmmoUser>() != null) { Loadout loadout = pawn.GetLoadout(); // if (loadout != null && !loadout.Slots.NullOrEmpty()) if (loadout != null && loadout.SlotCount > 0) { return(WorkPriority.None); } } if (pawn.kindDef.trader) { return(WorkPriority.None); } if (pawn.CurJob != null && pawn.CurJob.def == JobDefOf.Tame) { return(WorkPriority.None); } if (pawn.equipment.Primary == null) { if (Unload(pawn)) { return(WorkPriority.Unloading); } else { return(WorkPriority.Weapon); } } if (pawn.equipment.Primary != null && primaryammouser != null) { int ammocount = 0; foreach (AmmoLink link in primaryammouser.Props.ammoSet.ammoTypes) { Thing ammoThing; ammoThing = pawn.TryGetComp <CompInventory>().ammoList.Find(thing => thing.def == link.ammo); if (ammoThing != null) { ammocount += ammoThing.stackCount; } } float atw = primaryammouser.CurrentAmmo.GetStatValueAbstract(CE_StatDefOf.Bulk); if ((ammocount < (1.5f / atw)) && ((1.5f / atw) > 3)) { if (Unload(pawn)) { return(WorkPriority.Unloading); } else { return(WorkPriority.LowAmmo); } } if (!PawnUtility.EnemiesAreNearby(pawn, 30, true)) { if ((ammocount < (3.5f / atw)) && ((3.5f / atw) > 4)) { if (Unload(pawn)) { return(WorkPriority.Unloading); } else { return(WorkPriority.Ammo); } } } } /* * if (!pawn.Faction.IsPlayer && pawn.equipment.Primary != null * && !PawnUtility.EnemiesAreNearby(pawn, 30, true) || (!pawn.apparel.BodyPartGroupIsCovered(BodyPartGroupDefOf.Torso) || !pawn.apparel.BodyPartGroupIsCovered(BodyPartGroupDefOf.Legs))) ||{ || return WorkPriority.Apparel; ||} */ return(WorkPriority.None); }
public static Thing ClosestAmmoReachable(IntVec3 root, Map map, CompAmmoUser user, TraverseParms traverseParams, PathEndMode peMode = PathEndMode.ClosestTouch, float maxDistance = 9999f, Predicate <Thing> validator = null, IEnumerable <Thing> customGlobalSearchSet = null, int searchRegionsMin = 0, int searchRegionsMax = -1, bool forceAllowGlobalSearch = false, RegionType traversableRegionTypes = RegionType.Set_Passable, bool ignoreEntirelyForbiddenRegions = false) { //selectedAmmo //currentAmmo //others if (user == null) { Log.ErrorOnce("ClosestAmmoReachable with null CompAmmoUser", 724492); return(null); } if (user.Props.ammoSet?.ammoTypes.NullOrEmpty() ?? true) { return(null); } bool flag = searchRegionsMax < 0 | forceAllowGlobalSearch; if (!flag && customGlobalSearchSet != null) { Log.ErrorOnce("searchRegionsMax >= 0 && customGlobalSearchSet != null && !forceAllowGlobalSearch. customGlobalSearchSet will never be used.", 6568764, false); } #region EarlyOutSearch-like var findAny = user.Props.ammoSet?.ammoTypes?.Any(x => map.listerThings.ThingsOfDef(x.ammo).Any()) ?? false; if (!findAny) { return(null); } var mDsq = maxDistance * maxDistance; if (maxDistance != 9999f) { var mDsqMax = Math.Max( Math.Max(root.DistanceToSquared(IntVec3.Zero), root.DistanceToSquared(map.Size)), Math.Max(root.DistanceToSquared(new IntVec3(0, 0, map.Size.z)), root.DistanceToSquared(new IntVec3(map.Size.x, 0, 0)))); //maxDistance smaller than the maximum distance possible within the map -- already exclude some of the ammo if (mDsq < mDsqMax) { if (!user.Props.ammoSet.ammoTypes.Any(x => map.listerThings.ThingsOfDef(x.ammo).Any(y => y.Position.DistanceToSquared(root) <= mDsq))) { return(null); } } else if (!user.Props.ammoSet.ammoTypes.Any(x => map.listerThings.ThingsOfDef(x.ammo).Any())) { return(null); } } #endregion #region Preparing list to search through List <Thing> thingList = new List <Thing>(); foreach (var ammo in user.Props.ammoSet.ammoTypes.Select(x => x.ammo)) { thingList.AddRange(map.listerThings.ThingsOfDef(ammo).Where(y => y.Position.DistanceToSquared(root) <= mDsq && (!(y as AmmoThing)?.IsCookingOff ?? true) && !y.IsBurning())); } #endregion Func <Thing, float> priorityGetter = (x => { if (x.def == user.SelectedAmmo) { return(3f); } else if (x.def == user.CurrentAmmo) { return(2f); } else { return(1f); } }); int num = (searchRegionsMax > 0) ? searchRegionsMax : 30; var thing = RegionwiseBFSWorker(root, map, thingList, peMode, traverseParams, validator, priorityGetter, searchRegionsMin, num, mDsq, out int num2, traversableRegionTypes, ignoreEntirelyForbiddenRegions); var flag2 = (thing == null && num2 < num); if ((thing == null & flag) && !flag2) { if (traversableRegionTypes != RegionType.Set_Passable) { Log.ErrorOnce("ClosestAmmoReachable had to do a global search, but traversableRegionTypes is not set to passable only. It's not supported, because Reachability is based on passable regions only.", 14345767, false); } Predicate <Thing> validator2 = (Thing t) => map.reachability.CanReach(root, t, peMode, traverseParams) && (validator == null || validator(t)); thing = GenClosest.ClosestThing_Global(root, thingList, maxDistance, validator2, null); } return(thing); }