/// <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);
        }
Esempio n. 2
0
        /// <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();
                        }
                    }
                }
            }
        }
Esempio n. 3
0
        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));
        }
Esempio n. 4
0
        private void MakeGun()
        {
            this.gunInt   = ThingMaker.MakeThing(this.def.building.turretGunDef, null);
            this.compAmmo = gunInt.TryGetComp <CompAmmoUser>();

            InitGun();
        }
Esempio n. 5
0
        /// <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();
                        }
                    }
                }
            }
        }
Esempio n. 6
0
        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));
        }
Esempio n. 7
0
        /// <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);
        }
Esempio n. 8
0
        /// <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);
        }
Esempio n. 9
0
        /// <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);
        }
Esempio n. 10
0
        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);
        }
Esempio n. 11
0
        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);
        }
Esempio n. 13
0
        /// <summary>
        /// Gets the total count of a thingDef in a pawn's inventory.
        /// If thingDef is an ammo type, result will include rounds inside weapons magazines, matching behaviour in GetExcessThing.
        /// </summary>
        /// <param name="pawn">The pawn to check for stack count.</param>
        /// <param name="thingDef">The thingDef to look for.</param>
        /// <returns>Inventory count for specified item.</returns>
        static private int GetMagazineAwareStackCount(Pawn pawn, ThingDef thingDef)
        {
            int itemCount = 0;

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

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

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

                //Add stack count from inventory stored weapons (magazine ammo)
                if (inventory?.container != null)
                {
                    foreach (Thing inventoryItem in inventory.container)
                    {
                        CompAmmoUser ammoUser = inventoryItem.TryGetComp <CompAmmoUser>();
                        if (ammoUser != null && ammoUser.HasMagazine && ammoUser.CurrentAmmo == thingDef)
                        {
                            itemCount += ammoUser.CurMagCount;
                        }
                    }
                }
            }
            return(itemCount);
        }
Esempio n. 14
0
        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);
        }
Esempio n. 17
0
        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);
        }
Esempio n. 20
0
        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);
        }