/// <summary> /// Generates a loadout from available ThingDefs with respect to inventory constraints and deposits items straight into inventory /// </summary> /// <param name="inventory">Inventory comp to fill</param> public virtual void GenerateLoadout(CompInventory inventory) { if (inventory == null) { Log.Error("Tried generating loadout without inventory"); return; } if (UnityEngine.Random.value < skipChance) { return; } compInvInt = inventory; // Calculate thing count int thingsToMake = UnityEngine.Random.Range(minCount, maxCount); // Make things while (thingsToMake > 0) { Thing thing = GenerateLoadoutThing(UnityEngine.Random.Range(1, thingsToMake)); if (thing == null) { return; } int maxCountTemp; if (compInvInt.CanFitInInventory(thing, out maxCountTemp)) { IntVec3 spawnPos = inventory.parent.Position.InBounds(Find.VisibleMap) ? inventory.parent.Position : IntVec3.Zero; GenSpawn.Spawn(thing, spawnPos, Find.VisibleMap); // If we cant fit the whole stack, fit as much as we can and return if (maxCountTemp < thing.stackCount) { thing.stackCount = maxCountTemp; compInvInt.container.TryAdd(thing, thing.stackCount); return; } compInvInt.container.TryAdd(thing, thing.stackCount); thingsToMake -= maxCountTemp; } else { return; } } }
private LoadoutSlot GetPrioritySlot(Pawn pawn, out ItemPriority priority, out Thing closestThing, out int count) { priority = ItemPriority.None; LoadoutSlot slot = null; closestThing = null; count = 0; CompInventory inventory = pawn.TryGetComp <CompInventory>(); if (inventory != null && inventory.container != null) { Loadout loadout = pawn.GetLoadout(); if (loadout != null && !loadout.Slots.NullOrEmpty()) { foreach (LoadoutSlot curSlot in loadout.Slots) { ItemPriority curPriority = ItemPriority.None; Thing curThing = null; int numCarried = inventory.container.TotalStackCountOfDef(curSlot.Def); // Add currently equipped gun if (pawn.equipment != null && pawn.equipment.Primary != null) { if (pawn.equipment.Primary.def == curSlot.Def) { numCarried++; } } if (numCarried < curSlot.Count) { curThing = GenClosest.ClosestThingReachable( pawn.Position, pawn.Map, ThingRequest.ForDef(curSlot.Def), PathEndMode.ClosestTouch, TraverseParms.For(pawn, Danger.None, TraverseMode.ByPawn), proximitySearchRadius, x => !x.IsForbidden(pawn) && pawn.CanReserve(x)); if (curThing != null) { curPriority = ItemPriority.Proximity; } else { curThing = GenClosest.ClosestThingReachable( pawn.Position, pawn.Map, ThingRequest.ForDef(curSlot.Def), PathEndMode.ClosestTouch, TraverseParms.For(pawn, Danger.None, TraverseMode.ByPawn), maximumSearchRadius, x => !x.IsForbidden(pawn) && pawn.CanReserve(x)); if (curThing != null) { if (!curSlot.Def.IsNutritionGivingIngestible && numCarried / curSlot.Count <= 0.5f) { curPriority = ItemPriority.LowStock; } else { curPriority = ItemPriority.Low; } } } } if (curPriority > priority && curThing != null && inventory.CanFitInInventory(curThing, out count)) { priority = curPriority; slot = curSlot; closestThing = curThing; } if (priority >= ItemPriority.LowStock) { break; } } } } return(slot); }
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) where w.def.IsRangedWeapon // added this since what we are doing with the weapon list is looking for ammo. 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)); } } } } } } } } // else if we didn't find a ranged weapon with available ammo above, lets try a melee weapon. Thing meleeWeapon = ( from w in pawn.Map.listerThings.ThingsInGroup(ThingRequestGroup.HaulableAlways) where validatorWS(w) where !w.def.IsRangedWeapon // Looking for non-ranged weapons. where w.def.IsMeleeWeapon // Make sure it's melee capable. orderby w.MarketValue - w.Position.DistanceToSquared(pawn.Position) * 2f descending select w ).FirstOrDefault(); if (meleeWeapon != null) { if (meleeWeapon.Position == pawn.Position || meleeWeapon.Position.AdjacentToCardinal(pawn.Position)) { return(new Job(JobDefOf.Equip, meleeWeapon) { checkOverrideOnExpire = true, expiryInterval = 100, canBash = true, locomotionUrgency = LocomotionUrgency.Sprint }); } return(GotoForce(pawn, meleeWeapon, 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(CR_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); }