//Checks before called (ONLY when in SCANNER): // - PawnCanUseWorkGiver(pawn, this) // - nonColonistCanDo || isColonist // - !WorkTagIsDisabled(def.workTags) // - !ShouldSkip(pawn, false) // - MissingRequiredCapacity(pawn) == null // - !t.IsForbidden(pawn) // - this.PotentialWorkThingRequest.Accepts(t), /// <summary> /// Called after HasJobOnThing by WorkGiver_Scanner, or by Building_TurretGunCE when turret tryReload with manningPawn /// </summary> /// <param name="pawn"></param> /// <param name="t"></param> /// <param name="forced"></param> /// <returns></returns> public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false) { var priority = GetThingPriority(pawn, t, forced); if (priority == 0f) { return(null); } //Do not check for NeedsReload etc. -- if forced, treat as if NeedsReload && AllowAutomaticReload Building_TurretGunCE turret = t as Building_TurretGunCE; if (!turret.CompAmmo.UseAmmo) { return(new Job(CE_JobDefOf.ReloadTurret, t, null)); } int amountNeeded = turret.CompAmmo.Props.magazineSize; if (turret.CompAmmo.CurrentAmmo == turret.CompAmmo.SelectedAmmo) { amountNeeded -= turret.CompAmmo.CurMagCount; } turret.UpdateNearbyAmmo(); var ammo = PawnClosestAmmo(pawn, turret, out bool fromInventory, forced); if (ammo == null) { return(null); } // Update selected ammo if necessary if (ammo.def != turret.CompAmmo.SelectedAmmo) //New option can fill magazine completely (and is otherwise closer) { if ((priority >= 9f || ammo.stackCount >= amountNeeded)) { turret.CompAmmo.SelectedAmmo = ammo.def as AmmoDef; } else { return(null); } } if (fromInventory && !pawn.TryGetComp <CompInventory>().container.TryDrop(ammo, pawn.Position, pawn.Map, ThingPlaceMode.Direct, Mathf.Min(ammo.stackCount, amountNeeded), out ammo)) { Log.ErrorOnce("Found optimal ammo (" + ammo.LabelCap + "), but could not drop from " + pawn.LabelCap, 8164528); return(null); } return(new Job(CE_JobDefOf.ReloadTurret, t, ammo) { count = Mathf.Min(amountNeeded, ammo.stackCount) }); }
/// <summary> /// Called as a scanner /// </summary> /// <param name="pawn">Never null</param> /// <param name="t">Can be non-turret</param> /// <param name="forced">Generally not true</param> /// <returns></returns> /*public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false) * { * Building_TurretGunCE turret = t as Building_TurretGunCE; * if (turret == null || !Checks(pawn, turret, forced)) return false; * * if (!turret.CompAmmo.UseAmmo) * return true; * * turret.UpdateNearbyAmmo(); * * Thing ammo = turret.nearestViableAmmo; * * int amountNeeded = turret.CompAmmo.Props.magazineSize; * if (turret.CompAmmo.CurrentAmmo == turret.CompAmmo.SelectedAmmo) amountNeeded -= turret.CompAmmo.CurMagCount; * * if (ammo == null || ammo.IsForbidden(pawn) || !pawn.CanReserveAndReach(new LocalTargetInfo(ammo), PathEndMode.ClosestTouch, pawn.NormalMaxDanger(), Mathf.Max(1, ammo.stackCount - amountNeeded), amountNeeded, null, forced)) * { * ammo = turret.InventoryAmmo(pawn.TryGetComp<CompInventory>()); * } * * return ammo != null; * }*/ public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false) { var priority = GetThingPriority(pawn, t, forced); if (priority == 0f) { return(false); } Building_TurretGunCE turret = t as Building_TurretGunCE; if (!turret.CompAmmo.UseAmmo) { return(true); } int amountNeeded = turret.CompAmmo.Props.magazineSize; if (turret.CompAmmo.CurrentAmmo == turret.CompAmmo.SelectedAmmo) { amountNeeded -= turret.CompAmmo.CurMagCount; } turret.UpdateNearbyAmmo(); Thing ammo = PawnClosestAmmo(pawn, turret, out bool _, forced); if (ammo == null) { return(false); } // Update selected ammo if necessary if (ammo.def != turret.CompAmmo.SelectedAmmo && priority < 9f && ammo.stackCount < amountNeeded) //New option can fill magazine completely (and is otherwise closer) { return(false); } return(true); }
public Pawn BestNonJobUser(IEnumerable <Pawn> pawns, Building_TurretGunCE turret, out bool fromInventory, bool forced = false) { fromInventory = false; if (!pawns.Any()) { return(null); } //Cut a significant portion of pawns pawns = pawns.Where(p => !ShouldSkip(p) && !p.Downed && !p.Dead && p.Spawned && (p.mindState?.Active ?? true) && (!p.mindState?.mentalStateHandler?.InMentalState ?? true) && !turret.IsForbidden(p) && (turret.Faction == p.Faction || turret.Faction?.RelationKindWith(p.Faction) == FactionRelationKind.Ally) && p.CanReserveAndReach(new LocalTargetInfo(turret), PathEndMode.InteractionCell, forced ? Danger.Deadly : p.NormalMaxDanger(), GenClosestAmmo.pawnsPerTurret, -1, null, forced)); //No pawns remaining => quit if (!pawns.Any()) { return(null); } //If no ammo is used, minimize distance if (!turret.CompAmmo?.UseAmmo ?? true) { return(pawns.MinBy(x => x.Position.DistanceTo(turret.Position))); } //ELSE: ammo is used, pawns remain turret.UpdateNearbyAmmo(forced); var hasNearbyAmmo = turret.nearestViableAmmo != null; int amount = turret.CompAmmo.Props.magazineSize; if (turret.CompAmmo.CurrentAmmo == turret.CompAmmo.SelectedAmmo) { amount -= turret.CompAmmo.CurMagCount; } if (hasNearbyAmmo) { pawns = pawns.OrderBy(x => x.Position.DistanceTo(turret.Position)); } var bestNonInventoryDistance = 9999f; Pawn bestPawn = null; var minimumDistance = hasNearbyAmmo ? turret.Position.DistanceTo(turret.nearestViableAmmo.Position) : 0f; //Sort through ASCENDING DISTANCE TO TURRET -- e.g, inventory ammo is preferred foreach (var p in pawns) { if (PawnClosestAmmo(p, turret, out fromInventory, forced) == null) { continue; } if (fromInventory) { if (p.Position.DistanceTo(turret.Position) < bestNonInventoryDistance + minimumDistance) { return(p); } } else if (hasNearbyAmmo) { var dist = p.Position.DistanceTo(turret.nearestViableAmmo.Position); if (dist < bestNonInventoryDistance) { bestNonInventoryDistance = dist; bestPawn = p; } } } fromInventory = false; return(bestPawn); }