/// <summary> /// Handles activating aim mode at the start of the burst /// </summary> public override void WarmupComplete() { if (xpTicks <= 0) { xpTicks = Mathf.CeilToInt(verbProps.warmupTime * BaseXPMultiplyer); } if (this.ShouldAim && !this.isAiming) { float targetDist = (this.currentTarget.Cell - this.caster.Position).LengthHorizontal; int aimTicks = (int)Mathf.Lerp(aimTicksMin, aimTicksMax, (targetDist / 100)); if (ShooterPawn != null) { this.ShooterPawn.stances.SetStance(new Stance_Warmup(aimTicks, this.currentTarget, this)); this.isAiming = true; return; } else { Building_TurretGunCE turret = caster as Building_TurretGunCE; if (turret != null) { turret.burstWarmupTicksLeft += aimTicks; this.isAiming = true; return; } } } // Shooty stuff base.WarmupComplete(); this.isAiming = false; }
public void Unregister(Building_TurretGunCE t) { if (Turrets.Contains(t)) { Turrets.Remove(t); } }
public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false) { Building_TurretGunCE turret = t as Building_TurretGunCE; if (turret == null || (!forced && !turret.AllowAutomaticReload)) { return(false); } if (!turret.NeedsReload || !pawn.CanReserveAndReach(turret, PathEndMode.ClosestTouch, Danger.Deadly) || turret.IsForbidden(pawn.Faction)) { return(false); } if (!turret.CompAmmo.UseAmmo) { return(true); } Thing ammo = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForDef(turret.CompAmmo.SelectedAmmo), PathEndMode.ClosestTouch, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn), 80, x => !x.IsForbidden(pawn) && pawn.CanReserve(x)); return(ammo != null); }
private Thing PawnClosestAmmo(Pawn pawn, Building_TurretGunCE turret, out bool fromInventory, bool forced = false) { var testAmmo = turret.nearestViableAmmo; int amount = turret.CompAmmo.Props.magazineSize; if (turret.CompAmmo.CurrentAmmo == turret.CompAmmo.SelectedAmmo) { amount -= turret.CompAmmo.CurMagCount; } if (testAmmo == null || testAmmo.IsForbidden(pawn) || !pawn.CanReserveAndReach(new LocalTargetInfo(testAmmo), PathEndMode.ClosestTouch, forced ? Danger.Deadly : pawn.NormalMaxDanger(), Mathf.Max(1, testAmmo.stackCount - amount), Mathf.Min(testAmmo.stackCount, amount), null, forced)) { testAmmo = turret.InventoryAmmo(pawn?.TryGetComp <CompInventory>()); fromInventory = true; } else { fromInventory = false; } return(testAmmo); }
public override Job JobOnThing(Pawn pawn, Thing t) { Building_TurretGunCE turret = t as Building_TurretGunCE; if (turret == null) { return(null); } Thing ammo = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForDef(turret.compAmmo.selectedAmmo), PathEndMode.ClosestTouch, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn), 80, x => !x.IsForbidden(pawn) && pawn.CanReserve(x)); if (ammo == null) { return(null); } int amountNeeded = turret.compAmmo.Props.magazineSize; if (turret.compAmmo.currentAmmo == turret.compAmmo.selectedAmmo) { amountNeeded -= turret.compAmmo.curMagCount; } return(new Job(DefDatabase <JobDef> .GetNamed("ReloadTurret"), t, ammo) { count = Mathf.Min(amountNeeded, ammo.stackCount) }); }
private float GetThingPriority(Pawn pawn, Thing t, bool forced = false) { Building_TurretGunCE turret = t as Building_TurretGunCE; if (pawn == null) { //Log.Message("Checking " + turret.ThingID + ", found pawn == null"); return(0f); } if (turret == null || turret.IsForbidden(pawn) || !Checks(pawn, turret, forced)) { return(0f); } if (!turret.Active) { return(1f); } if (turret.EmptyMagazine) { return(9f); } if (turret.AutoReloadableMagazine) { return(5f); } return(1f); }
private bool Checks(Pawn pawn, Building_TurretGunCE turret, bool forced) { //WorkTagIsDisabled check inherent to WorkGiver_Scanner //MissingRequiredCapacity check inherent to WorkGiver_Scanner if (turret.isReloading) { //Log.Message(pawn.ThingID + " failed " + turret.ThingID + ": turret is already reloading"); return(false); //Turret is already reloading } if (turret.FullMagazine) { // Log.Message(pawn.ThingID + " failed " + turret.ThingID + ": turret doesn't need reload"); return(false); //Turret doesn't need reload } //if (!forced && !turret.AllowAutomaticReload) return false; //Turret doesn't need auto-reload and isn't forced to reload if (turret.IsBurning()) { // Log.Message(pawn.ThingID + " failed " + turret.ThingID + ": turret on fire"); return(false); //Turret on fire } if (turret.Faction != pawn.Faction && (turret.Faction != null && pawn.Faction != null && turret.Faction.RelationKindWith(pawn.Faction) != FactionRelationKind.Ally)) { // Log.Message(pawn.ThingID + " failed " + turret.ThingID + ": non-allied turret"); return(false); //Allies reload turrets } if ((turret.MannableComp?.ManningPawn != pawn) && !pawn.CanReserveAndReach(turret, PathEndMode.ClosestTouch, forced ? Danger.Deadly : pawn.NormalMaxDanger(), GenClosestAmmo.pawnsPerTurret)) { //Log.Message(pawn.ThingID + " failed " + turret.ThingID + ": turret unreachable"); return(false); //Pawn cannot reach turret } return(true); }
public void Register(Building_TurretGunCE t) { if (!Turrets.Contains(t)) { Turrets.Add(t); } }
//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) }); }
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false) { Building_TurretGunCE turret = t as Building_TurretGunCE; if (turret == null || turret.CompAmmo == null) { return(null); } if (!turret.CompAmmo.UseAmmo) { return(new Job(CE_JobDefOf.ReloadTurret, t, null)); } // Iterate through all possible ammo types for NPC's to find whichever is available, starting with currently selected Thing ammo = null; var ammoTypes = turret.CompAmmo.Props.ammoSet.ammoTypes.Select(l => l.ammo).ToList(); var index = ammoTypes.IndexOf(turret.CompAmmo.SelectedAmmo); for (int i = 0; i < ammoTypes.Count; i++) { index = (index + i) % ammoTypes.Count; ammo = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForDef(ammoTypes[index]), PathEndMode.ClosestTouch, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn), 80, x => !x.IsForbidden(pawn) && pawn.CanReserve(x)); if (ammo != null || pawn.Faction == Faction.OfPlayer) { break; } } if (ammo == null) { return(null); } // Update selected ammo if necessary if (ammo.def != turret.CompAmmo.SelectedAmmo) { turret.CompAmmo.SelectedAmmo = ammo.def as AmmoDef; } // Create the actual job int amountNeeded = turret.CompAmmo.Props.magazineSize; if (turret.CompAmmo.CurrentAmmo == turret.CompAmmo.SelectedAmmo) { amountNeeded -= turret.CompAmmo.CurMagCount; } return(new Job(DefDatabase <JobDef> .GetNamed("ReloadTurret"), t, ammo) { count = Mathf.Min(amountNeeded, ammo.stackCount) }); }
public override bool HasJobOnThing(Pawn pawn, Thing t) { Building_TurretGunCE turret = t as Building_TurretGunCE; if (turret == null || !turret.allowAutomaticReload) { return(false); } return(HasJobOnThingForced(pawn, t)); }
private void InitTurret() { Building_TurretGunCE turret = parent as Building_TurretGunCE; if (turret != null && turret.gun == null) { gun = (Thing)ThingMaker.MakeThing(parent.def.building.turretGunDef); turret.gun = gun; } }
protected override IEnumerable <Toil> MakeNewToils() { if (pawn.Faction != Faction.OfPlayer) { TargetThingB.SetForbidden(false, false); this.FailOnDestroyedOrNull(TargetIndex.A); this.FailOnDestroyedOrNull(TargetIndex.B); } else { this.FailOnDestroyedNullOrForbidden(TargetIndex.A); this.FailOnDestroyedNullOrForbidden(TargetIndex.B); } // Haul ammo yield return(Toils_Reserve.Reserve(TargetIndex.A, 1)); yield return(Toils_Reserve.Reserve(TargetIndex.B, 1)); yield return(Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.ClosestTouch)); yield return(Toils_Haul.StartCarryThing(TargetIndex.B)); yield return(Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.ClosestTouch)); yield return(Toils_Haul.PlaceHauledThingInCell(TargetIndex.A, null, false)); // Wait in place Toil waitToil = new Toil(); waitToil.initAction = delegate { waitToil.actor.pather.StopDead(); compReloader.TryStartReload(); }; waitToil.defaultCompleteMode = ToilCompleteMode.Delay; waitToil.defaultDuration = Mathf.CeilToInt(compReloader.Props.reloadTicks / pawn.GetStatValue(CE_StatDefOf.ReloadSpeed)); yield return(waitToil.WithProgressBarToilDelay(TargetIndex.A)); //Actual reloader Toil reloadToil = new Toil(); reloadToil.defaultCompleteMode = ToilCompleteMode.Instant; reloadToil.initAction = delegate { Building_TurretGunCE turret = TargetThingA as Building_TurretGunCE; if (compReloader != null && turret.compAmmo != null) { compReloader.LoadAmmo(TargetThingB); } }; reloadToil.EndOnDespawnedOrNull(TargetIndex.B); yield return(reloadToil); }
//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) { Building_TurretGunCE turret = t as Building_TurretGunCE; if (turret == null) { CELogger.Error($"{pawn} tried to make a reload job on a {t} which isn't a turret. This should never be reached."); } // NOTE: The removal of the code that used to be here disables reloading turrets directly from one's inventory. // The player would need to drop the ammo the pawn is holding first. return(JobGiverUtils_Reload.MakeReloadJob(pawn, turret)); }
//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) { //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(JobGiverUtils_Reload.MakeReloadJobNoAmmo(turret)); } // NOTE: The removal of the code that used to be here disables reloading turrets directly from one's inventory. // The player would need to drop the ammo the pawn is holding first. return(JobGiverUtils_Reload.MakeReloadJob(pawn, turret)); }
private float GetThingPriority(Pawn pawn, Thing t, bool forced = false) { CELogger.Message($"pawn: {pawn}. t: {t}. forced: {forced}"); Building_TurretGunCE turret = t as Building_TurretGunCE; if (!turret.Active) { return(1f); } if (turret.EmptyMagazine) { return(9f); } if (turret.AutoReloadableMagazine) { return(5f); } return(1f); }
/// <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) { // Should never happen anymore, as only TurretGunCEs should be returned from PotentialWorkThingsGlobal if (!(t is Building_TurretGunCE)) { return(false); } var priority = GetThingPriority(pawn, t, forced); CELogger.Message($"Priority check completed. Got {priority}"); Building_TurretGunCE turret = t as Building_TurretGunCE; CELogger.Message($"Turret uses ammo? {turret.CompAmmo.UseAmmo}"); CELogger.Message($"Total magazine size: {turret.CompAmmo.Props.magazineSize}. Needed: {turret.CompAmmo.MissingToFullMagazine}"); return(JobGiverUtils_Reload.CanReload(pawn, turret, forced)); }
/// <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); }
/// <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) { if (!(t is Building_TurretGunCE)) { return(false); } var priority = GetThingPriority(pawn, t, forced); CELogger.Message($"Priority check completed. Got {priority}"); Building_TurretGunCE turret = t as Building_TurretGunCE; CELogger.Message($"Turret uses ammo? {turret.CompAmmo.UseAmmo}"); if (!turret.CompAmmo.UseAmmo) { return(true); } CELogger.Message($"Total magazine size: {turret.CompAmmo.Props.magazineSize}. Needed: {turret.CompAmmo.MissingToFullMagazine}"); return(JobGiverUtils_Reload.CanReload(pawn, turret, forced)); }
public bool EnoughAmmoAround(Building_TurretGunCE turret) { //Prevent ammo being dropped as a result of the turret being reloaded at the time if (turret.isReloading || turret.FullMagazine) { return(true); } var ammoComp = turret.CompAmmo; int num = GenRadial.NumCellsInRadius(20f); int num2 = ammoComp.CurMagCount; int num3 = Mathf.CeilToInt((float)ammoComp.Props.magazineSize / 6f); for (int i = 0; i < num; i++) { IntVec3 c = parent.Position + GenRadial.RadialPattern[i]; if (c.InBounds(parent.Map)) { List <Thing> thingList = c.GetThingList(parent.Map); for (int j = 0; j < thingList.Count; j++) { if ((ammoComp != null && ammoComp.CurrentAmmo == thingList[j].def)) { num2 += thingList[j].stackCount; if (num2 > num3) { return(true); } } } } } return(false); }
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); }