/// <summary> /// Get all available targets ordered by weight /// </summary> /// <param name="rawTargets"></param> /// <param name="searcher"></param> /// <returns></returns> public static List <Pair <IAttackTarget, float> > GetAvailableShootingTargetsByScore(List <IAttackTarget> rawTargets, VehiclePawn searcher) { List <Pair <IAttackTarget, float> > availableShootingTargets = new List <Pair <IAttackTarget, float> >(); List <float> tmpTargetScores = new List <float>(); List <bool> tmpCanShootAtTarget = new List <bool>(); if (rawTargets.Count == 0) { return(availableShootingTargets); } tmpTargetScores.Clear(); tmpCanShootAtTarget.Clear(); float num = 0f; IAttackTarget attackTarget = null; for (int i = 0; i < rawTargets.Count; i++) { tmpTargetScores.Add(float.MinValue); tmpCanShootAtTarget.Add(false); if (rawTargets[i] != searcher) { bool flag = VehicleTurret.TryFindShootLineFromTo(searcher.Position, new LocalTargetInfo(rawTargets[i].Thing), out ShootLine shootLine); tmpCanShootAtTarget[i] = flag; if (flag) { float shootingTargetScore = GetShootingTargetScore(rawTargets[i], searcher); tmpTargetScores[i] = shootingTargetScore; if (attackTarget == null || shootingTargetScore > num) { attackTarget = rawTargets[i]; num = shootingTargetScore; } } } } if (num < 1f) { if (attackTarget != null) { availableShootingTargets.Add(new Pair <IAttackTarget, float>(attackTarget, 1f)); } } else { float num2 = num - 30f; for (int j = 0; j < rawTargets.Count; j++) { if (rawTargets[j] != searcher && tmpCanShootAtTarget[j]) { float num3 = tmpTargetScores[j]; if (num3 >= num2) { float second = Mathf.InverseLerp(num - 30f, num, num3); availableShootingTargets.Add(new Pair <IAttackTarget, float>(rawTargets[j], second)); } } } } return(availableShootingTargets); }
protected virtual Vector3 Target(VehicleTurret turret) { int shots = shotsFromTurret[turret]; float distFromStart = StrafeAreaDistance * shots / turret.MaxShotsCurrentFireMode; Vector3 target = start.ToVector3Shifted().PointFromAngle(distFromStart, angle); Pair <float, float> turretLoc = RenderHelper.TurretDrawOffset(angle, turret.turretRenderLocation.x, turret.turretRenderLocation.y, out Pair <float, float> renderOffsets, 0, turret.attachedTo); return(new Vector3(target.x + turretLoc.First + renderOffsets.First, target.y + turret.drawLayer, target.z + turretLoc.Second + renderOffsets.Second)); }
public CannonUpgrade(CannonUpgrade reference, VehiclePawn parent) : base(reference, parent) { cannonUpgrades = reference.cannonUpgrades; foreach (KeyValuePair <VehicleTurret, VehicleRole> cu in cannonUpgrades) { VehicleTurret newTurret = CompCannons.CreateTurret(parent, cu.Key); VehicleHandler handler = new VehicleHandler(parent, cu.Value); cannonsUnlocked.Add(newTurret, handler); } }
public override void StopTargeting() { if (actionWhenFinished != null) { Action action = actionWhenFinished; actionWhenFinished = null; action(); } Cannon = null; action = null; }
public void BeginTargeting(TargetingParameters targetParams, Action <LocalTargetInfo> action, VehicleTurret cannon, Action actionWhenFinished = null, Texture2D mouseAttachment = null) { this.action = action; this.targetParams = targetParams; vehicle = cannon.vehicle; Cannon = cannon; Cannon.SetTarget(LocalTargetInfo.Invalid); this.actionWhenFinished = actionWhenFinished; this.mouseAttachment = mouseAttachment; map = cannon.vehicle.Map; }
public void Notify_TurretRecoil(VehicleTurret turret, float angle) { if (!turret.Recoils) { return; } targetRecoil = turret.turretDef.recoil.distanceTotal; recoilStep = turret.turretDef.recoil.distancePerTick; curRecoil = 0; recoilingBack = true; Angle = angle; }
protected virtual Vector3 TurretLocation(VehicleTurret turret) { float locationRotation = 0f; if (turret.attachedTo != null) { locationRotation = turret.attachedTo.TurretRotation; } Vector3 calcPosition = DistanceAtMin; Pair <float, float> turretLoc = RenderHelper.TurretDrawOffset(angle, turret.turretRenderLocation.x, turret.turretRenderLocation.y, out Pair <float, float> renderOffsets, locationRotation, turret.attachedTo); return(new Vector3(calcPosition.x + turretLoc.First + renderOffsets.First, calcPosition.y + turret.drawLayer, calcPosition.z + turretLoc.Second + renderOffsets.Second)); }
/// <summary> /// Find best attack target for VehicleTurret /// </summary> /// <seealso cref="BestAttackTarget(VehicleTurret, TargetScanFlags, Predicate{Thing}, float, float, IntVec3, float, bool, bool)"/> /// <param name="cannon"></param> /// <param name="restrictedAngle"></param> /// <param name="param"></param> public static LocalTargetInfo GetCannonTarget(this VehicleTurret cannon, float restrictedAngle = 0f, TargetingParameters param = null) { if (cannon.vehicle.CompCannons != null && cannon.vehicle.CompCannons.WeaponStatusOnline && cannon.vehicle.Faction != null) //add fire at will option { TargetScanFlags targetScanFlags = TargetScanFlags.NeedLOSToPawns | TargetScanFlags.NeedLOSToNonPawns | TargetScanFlags.NeedThreat | TargetScanFlags.NeedAutoTargetable; Thing thing = (Thing)BestAttackTarget(cannon, targetScanFlags, null, 0f, 9999f, default(IntVec3), float.MaxValue, false, false); if (thing != null) { return(new LocalTargetInfo(thing)); } } return(LocalTargetInfo.Invalid); }
public void Notify_TurretRecoil(VehicleTurret turret, float angle) { if (turret.turretDef.vehicleRecoil is null) { return; } targetRecoil = turret.turretDef.vehicleRecoil.distanceTotal; recoilStep = turret.turretDef.vehicleRecoil.distancePerTick; speedMultiplierPostRecoil = turret.turretDef.vehicleRecoil.speedMultiplierPostRecoil; curRecoil = 0; recoilingBack = true; Angle = angle; }
protected virtual void FireTurret(VehicleTurret turret) { float horizontalOffset = turret.turretDef.projectileShifting.NotNullAndAny() ? turret.turretDef.projectileShifting[turret.CurrentTurretFiring] : 0; Vector3 launchPos = TurretLocation(turret) + new Vector3(horizontalOffset, 1f, turret.turretDef.projectileOffset); Vector3 targetPos = Target(turret); float range = Vector3.Distance(TurretLocation(turret), targetPos); IntVec3 target = targetPos.ToIntVec3() + GenRadial.RadialPattern[Rand.Range(0, GenRadial.NumCellsInRadius(turret.CurrentFireMode.spreadRadius * (range / turret.turretDef.maxRange)))]; if (turret.CurrentTurretFiring >= turret.turretDef.projectileShifting.Count) { turret.CurrentTurretFiring = 0; } ThingDef projectile; if (turret.turretDef.ammunition != null && !turret.turretDef.genericAmmo) { projectile = turret.loadedAmmo?.projectileWhenLoaded; } else { projectile = turret.turretDef.projectile; } try { float speedTicksPerTile = projectile.projectile.SpeedTilesPerTick; if (turret.turretDef.projectileSpeed > 0) { speedTicksPerTile = turret.turretDef.projectileSpeed; } ProjectileSkyfaller projectile2 = ProjectileSkyfallerMaker.WrapProjectile(ProjectileSkyfallerDefOf.ProjectileSkyfaller, projectile, this, launchPos, target.ToVector3Shifted(), speedTicksPerTile); //REDO - RANDOMIZE TARGETED CELLS GenSpawn.Spawn(projectile2, target.ClampInsideMap(Map), Map); if (turret.turretDef.ammunition != null) { turret.ConsumeShellChambered(); } if (turret.turretDef.cannonSound != null) { turret.turretDef.cannonSound.PlayOneShot(new TargetInfo(Position, Map, false)); } turret.PostTurretFire(); } catch (Exception ex) { Log.Error($"Exception when firing Cannon: {turret.turretDef.LabelCap} on Pawn: {vehicle.LabelCap}. Exception: {ex.Message}"); } }
public void RemoveCannons(List <VehicleTurret> cannonList) { if (cannonList.NullOrEmpty()) { return; } foreach (VehicleTurret cannon in cannonList) { VehicleTurret resultingHandler = cannons.FirstOrDefault(c => c.key == cannon.key); if (resultingHandler is null) { Log.Error($"Unable to locate {cannon.key} in cannonList for removal. Is Key missing on upgraded cannon?"); } cannons.Remove(resultingHandler); } }
public VehicleTurret(VehiclePawn vehicle, VehicleTurret reference) { this.vehicle = vehicle; uniqueID = Find.UniqueIDsManager.GetNextThingID(); turretDef = reference.turretDef; turretRenderOffset = reference.turretRenderOffset; turretRenderLocation = reference.turretRenderLocation; defaultAngleRotated = reference.defaultAngleRotated; aimPieOffset = reference.aimPieOffset; angleRestricted = reference.angleRestricted; drawLayer = reference.drawLayer; gizmoLabel = reference.gizmoLabel; key = reference.key; parentKey = reference.parentKey; groupKey = reference.groupKey; targetPersists = reference.targetPersists; autoTargeting = reference.autoTargeting; manualTargeting = reference.manualTargeting; currentFireMode = 0; currentFireIcon = OverheatIcons.FirstOrDefault(); ticksSinceLastShot = 0; childCannons = new List <VehicleTurret>(); if (!string.IsNullOrEmpty(parentKey)) { foreach (VehicleTurret cannon in vehicle.CompCannons.Cannons.Where(c => c.key == parentKey)) { attachedTo = cannon; cannon.childCannons.Add(this); } } ResolveCannonGraphics(vehicle); rTracker = new Turret_RecoilTracker(this); restrictedTheta = (int)Math.Abs(angleRestricted.x - (angleRestricted.y + 360)).ClampAngle(); ResetCannonAngle(); }
public void AddCannons(List <VehicleTurret> cannonList) { if (cannonList.NullOrEmpty()) { return; } foreach (VehicleTurret cannon in cannonList) { VehicleTurret newTurret = CreateTurret(Vehicle, cannon); if (cannons.NotNullAndAny(x => x.turretRenderLocation == newTurret.turretRenderLocation && newTurret.attachedTo != x && x.attachedTo != newTurret)) { cannons.FindAll(x => x.turretRenderLocation == newTurret.turretRenderLocation).ForEach(y => y.TryRemoveShell()); cannons.RemoveAll(x => x.turretRenderLocation == newTurret.turretRenderLocation); } cannons.Add(newTurret); } }
protected virtual void TurretTick() { if (!turrets.NullOrEmpty()) { for (int i = 0; i < turrets.Count; i++) { CompCannons.TurretData turretData = turrets[i]; VehicleTurret turret = turretData.turret; if (!turret.HasAmmo && !DebugSettings.godMode) { turrets.Remove(turretData); shotsFired = turrets.NullOrEmpty(); continue; } if (turret.OnCooldown) { turret.SetTarget(LocalTargetInfo.Invalid); turrets.Remove(turretData); shotsFired = turrets.NullOrEmpty(); continue; } turrets[i].turret.AlignToTargetRestricted(); if (turrets[i].ticksTillShot <= 0) { FireTurret(turret); int shotsIncrement = shotsFromTurret[turret] + 1; shotsFromTurret[turret] = shotsIncrement; turret.CurrentTurretFiring++; turretData.shots--; turretData.ticksTillShot = turret.TicksPerShot; if (turret.OnCooldown || turretData.shots == 0 || (turret.turretDef.ammunition != null && turret.shellCount <= 0)) { turret.SetTarget(LocalTargetInfo.Invalid); turrets.RemoveAll(t => t.turret == turret); shotsFired = turrets.NullOrEmpty(); continue; } } else { turretData.ticksTillShot--; } turrets[i] = turretData; } } }
public static bool TargetMeetsRequirements(VehicleTurret cannon, LocalTargetInfo obj) { float distance = (cannon.TurretLocation.ToIntVec3() - obj.Cell).LengthHorizontal; bool los = false; if (obj.HasThing) { if (!obj.Thing.Spawned || obj.Thing.Destroyed) { return(false); } los = GenSight.LineOfSightToThing(cannon.TurretLocation.ToIntVec3(), obj.Thing, cannon.vehicle.Map); } else { los = GenSight.LineOfSight(cannon.TurretLocation.ToIntVec3(), obj.Cell, cannon.vehicle.Map); } bool result = (distance >= cannon.MinRange && (distance < cannon.MaxRange || cannon.MaxRange <= -1)) && cannon.AngleBetween(obj.CenterVector3) && ((cannon.loadedAmmo?.projectileWhenLoaded?.projectile?.flyOverhead ?? false) || los); return(result); }
public Turret_RecoilTracker(VehicleTurret turret) { this.turret = turret; }
/// <summary> /// Best attack target for VehicleTurret /// </summary> /// <param name="cannon"></param> /// <param name="flags"></param> /// <param name="validator"></param> /// <param name="minDist"></param> /// <param name="maxDist"></param> /// <param name="locus"></param> /// <param name="maxTravelRadiusFromLocus"></param> /// <param name="canBash"></param> /// <param name="canTakeTargetsCloserThanEffectiveMinRange"></param> /// <returns></returns> public static IAttackTarget BestAttackTarget(VehicleTurret cannon, TargetScanFlags flags, Predicate <Thing> validator = null, float minDist = 0f, float maxDist = 9999f, IntVec3 locus = default(IntVec3), float maxTravelRadiusFromLocus = 3.4028235E+38f, bool canBash = false, bool canTakeTargetsCloserThanEffectiveMinRange = true) { VehiclePawn searcherPawn = cannon.vehicle; float minDistSquared = minDist * minDist; float num = maxTravelRadiusFromLocus + cannon.MaxRange; float maxLocusDistSquared = num * num; Func <IntVec3, bool> losValidator = null; if ((flags & TargetScanFlags.LOSBlockableByGas) != TargetScanFlags.None) { losValidator = delegate(IntVec3 vec3) { Gas gas = vec3.GetGas(searcherPawn.Map); return(gas == null || !gas.def.gas.blockTurretTracking); }; } Predicate <IAttackTarget> innerValidator = delegate(IAttackTarget t) { Thing thing = t.Thing; if (t == searcherPawn) { return(false); } if (minDistSquared > 0f && (float)(searcherPawn.Position - thing.Position).LengthHorizontalSquared < minDistSquared) { return(false); } if (!canTakeTargetsCloserThanEffectiveMinRange) { float num2 = cannon.MinRange; if (num2 > 0f && (float)(cannon.vehicle.Position - thing.Position).LengthHorizontalSquared < num2 * num2) { return(false); } } if (maxTravelRadiusFromLocus < 9999f && (thing.Position - locus).LengthHorizontalSquared > maxLocusDistSquared) { return(false); } if (!searcherPawn.HostileTo(thing)) { return(false); } if (validator != null && !validator(thing)) { return(false); } if ((flags & TargetScanFlags.NeedLOSToAll) != TargetScanFlags.None) { if (losValidator != null && (!losValidator(searcherPawn.Position) || !losValidator(thing.Position))) { return(false); } if (!searcherPawn.CanSee(thing, losValidator)) { if (t is Pawn) { if ((flags & TargetScanFlags.NeedLOSToPawns) != TargetScanFlags.None) { return(false); } } else if ((flags & TargetScanFlags.NeedLOSToNonPawns) != TargetScanFlags.None) { return(false); } } } if (((flags & TargetScanFlags.NeedThreat) != TargetScanFlags.None || (flags & TargetScanFlags.NeedAutoTargetable) != TargetScanFlags.None) && t.ThreatDisabled(searcherPawn)) { return(false); } if ((flags & TargetScanFlags.NeedAutoTargetable) != TargetScanFlags.None && !AttackTargetFinder.IsAutoTargetable(t)) { return(false); } if ((flags & TargetScanFlags.NeedActiveThreat) != TargetScanFlags.None && !GenHostility.IsActiveThreatTo(t, searcherPawn.Faction)) { return(false); } Pawn pawn = t as Pawn; if ((flags & TargetScanFlags.NeedNonBurning) != TargetScanFlags.None && thing.IsBurning()) { return(false); } if (thing.def.size.x == 1 && thing.def.size.z == 1) { if (thing.Position.Fogged(thing.Map)) { return(false); } } else { bool flag2 = false; using (CellRect.Enumerator enumerator = thing.OccupiedRect().GetEnumerator()) { while (enumerator.MoveNext()) { if (!enumerator.Current.Fogged(thing.Map)) { flag2 = true; break; } } } if (!flag2) { return(false); } } return(true); }; List <IAttackTarget> tmpTargets = new List <IAttackTarget>(); tmpTargets.AddRange(searcherPawn.Map.attackTargetsCache.GetPotentialTargetsFor(searcherPawn)); bool flag = false; for (int i = 0; i < tmpTargets.Count; i++) { IAttackTarget attackTarget = tmpTargets[i]; if (attackTarget.Thing.Position.InHorDistOf(searcherPawn.Position, maxDist) && innerValidator(attackTarget) && VehicleTurret.TryFindShootLineFromTo(searcherPawn.Position, new LocalTargetInfo(attackTarget.Thing), out ShootLine resultingLine)) { flag = true; break; } } IAttackTarget result; if (flag) { tmpTargets.RemoveAll((IAttackTarget x) => !x.Thing.Position.InHorDistOf(searcherPawn.Position, maxDist) || !innerValidator(x)); result = GetRandomShootingTargetByScore(tmpTargets, searcherPawn); } else { Predicate <Thing> validator2; if ((flags & TargetScanFlags.NeedReachableIfCantHitFromMyPos) != TargetScanFlags.None && (flags & TargetScanFlags.NeedReachable) == TargetScanFlags.None) { validator2 = ((Thing t) => innerValidator((IAttackTarget)t) && VehicleTurret.TryFindShootLineFromTo(searcherPawn.Position, new LocalTargetInfo(t), out ShootLine resultingLine)); } else { validator2 = ((Thing t) => innerValidator((IAttackTarget)t)); } result = (IAttackTarget)GenClosest.ClosestThing_Global(searcherPawn.Position, tmpTargets, maxDist, validator2, null); } tmpTargets.Clear(); return(result); }
/// <summary> /// Calculate VehicleTurret draw offset /// </summary> /// <param name="vehicle"></param> /// <param name="xOffset"></param> /// <param name="yOffset"></param> /// <param name="rotationOffset"></param> /// <param name="turretRotation"></param> /// <param name="attachedTo"></param> public static Pair <float, float> TurretDrawOffset(float angle, float xOffset, float yOffset, out Pair <float, float> rotationOffset, float turretRotation = 0, VehicleTurret attachedTo = null) { rotationOffset = new Pair <float, float>(0, 0); if (attachedTo != null) { return(Ext_Math.RotatePointClockwise(attachedTo.turretRenderLocation.x + xOffset, attachedTo.turretRenderLocation.y + yOffset, turretRotation)); } return(Ext_Math.RotatePointClockwise(xOffset, yOffset, angle)); }
/// <summary> /// Calculate VehicleTurret draw offset given <paramref name="rot"/> /// </summary> /// <param name="rot"></param> /// <param name="xOffset"></param> /// <param name="yOffset"></param> /// <param name="rotationOffset"></param> /// <param name="turretRotation"></param> /// <param name="attachedTo"></param> /// <returns></returns> public static Pair <float, float> ShipDrawOffset(Rot8 rot, float xOffset, float yOffset, out Pair <float, float> rotationOffset, float turretRotation = 0, VehicleTurret attachedTo = null) { rotationOffset = new Pair <float, float>(0, 0); if (attachedTo != null) { return(Ext_Math.RotatePointClockwise(attachedTo.turretRenderLocation.x + xOffset, attachedTo.turretRenderLocation.y + yOffset, turretRotation)); } return(rot.AsInt switch { //North 0 => new Pair <float, float>(xOffset, yOffset), //East 1 => new Pair <float, float>(yOffset, -xOffset), //South 2 => new Pair <float, float>(-xOffset, -yOffset), //West 3 => new Pair <float, float>(-yOffset, xOffset), //NorthEast 4 => Ext_Math.RotatePointClockwise(yOffset, -xOffset, 45f), //SouthEast 5 => Ext_Math.RotatePointCounterClockwise(yOffset, -xOffset, 45f), //SouthWest 6 => Ext_Math.RotatePointClockwise(-yOffset, xOffset, 45f), //NorthWest 7 => Ext_Math.RotatePointCounterClockwise(-yOffset, xOffset, 45f), //Default _ => throw new ArgumentOutOfRangeException("VehicleRotation is not within bounds. RotationInt must be between 0 and 7 for each lateral, longitudinal, and diagonal direction.") });