diff --git a/Source/CombatExtended/CombatExtended/Projectiles/ProjectileCE.cs b/Source/CombatExtended/CombatExtended/Projectiles/ProjectileCE.cs
index 7864ba1464..51cfc13b77 100644
--- a/Source/CombatExtended/CombatExtended/Projectiles/ProjectileCE.cs
+++ b/Source/CombatExtended/CombatExtended/Projectiles/ProjectileCE.cs
@@ -1510,26 +1510,7 @@ protected float GetHeightAtTicks(int ticks)
/// Distance in cells that the projectile will fly at the given arc.
protected float DistanceTraveled => TrajectoryWorker.DistanceTraveled(shotHeight, shotSpeed, shotAngle, GravityFactor);
- ///
- /// Calculates the shot angle necessary to reach range with a projectile of speed velocity at a height difference of heightDifference, returning either the upper or lower arc in radians. Does not take into account air resistance.
- ///
- /// Projectile velocity in cells per second.
- /// Cells between shooter and target.
- /// Difference between initial shot height and target height in vertical cells.
- /// Whether to take the lower (False) or upper (True) arc angle.
- /// Arc angle in radians off the ground.
- public static float GetShotAngle(float velocity, float range, float heightDifference, bool flyOverhead, float gravity)
- {
- float squareRootCheck = Mathf.Sqrt(Mathf.Pow(velocity, 4f) - gravity * (gravity * Mathf.Pow(range, 2f) + 2f * heightDifference * Mathf.Pow(velocity, 2f)));
- if (float.IsNaN(squareRootCheck))
- {
- //Target is too far to hit with given velocity/range/gravity params
- //set firing angle for maximum distance
- Log.Warning("[CE] Tried to fire projectile to unreachable target cell, truncating to maximum distance.");
- return 45.0f * Mathf.Deg2Rad;
- }
- return Mathf.Atan((Mathf.Pow(velocity, 2f) + (flyOverhead ? 1f : -1f) * squareRootCheck) / (gravity * range));
- }
+
#endregion
protected static Material[] GetShadowMaterial(Graphic_Collection g)
diff --git a/Source/CombatExtended/CombatExtended/Projectiles/TrajectoryWorkers/BaseTrajectoryWorker.cs b/Source/CombatExtended/CombatExtended/Projectiles/TrajectoryWorkers/BaseTrajectoryWorker.cs
index f686e01864..7db3b7beab 100644
--- a/Source/CombatExtended/CombatExtended/Projectiles/TrajectoryWorkers/BaseTrajectoryWorker.cs
+++ b/Source/CombatExtended/CombatExtended/Projectiles/TrajectoryWorkers/BaseTrajectoryWorker.cs
@@ -101,5 +101,44 @@ public virtual Vector3 GetVelocity(float shotSpeed, float rotation, float angle)
angle = angle * Mathf.Rad2Deg; // transform to degrees
return Vector2.up.RotatedBy(rotation).ToVector3().RotatedBy(angle) * shotSpeed / GenTicks.TicksPerRealSecond;
}
+
+ ///
+ /// Shot angle in radians
+ ///
+ /// Source shot, including shot height
+ /// Target position, including target height
+ /// angle in radians
+ public virtual float ShotAngle(ProjectilePropertiesCE projectilePropsCE, Vector3 source, Vector3 targetPos, float? velocity = null)
+ {
+ var targetHeight = targetPos.y;
+ var shotHeight = source.y;
+ var newTargetLoc = new Vector2(targetPos.x, targetPos.z);
+ var sourceV2 = new Vector2(source.x, source.z);
+ if (projectilePropsCE.isInstant)
+ {
+ return Mathf.Atan2(targetHeight - shotHeight, (newTargetLoc - sourceV2).magnitude);
+ }
+ else
+ {
+ var _velocity = velocity ?? projectilePropsCE.speed;
+ var gravity = projectilePropsCE.Gravity;
+ var heightDifference = targetHeight - shotHeight;
+ var range = (newTargetLoc - sourceV2).magnitude;
+ float squareRootCheck = Mathf.Sqrt(Mathf.Pow(_velocity, 4f) - gravity * (gravity * Mathf.Pow(range, 2f) + 2f * heightDifference * Mathf.Pow(_velocity, 2f)));
+ if (float.IsNaN(squareRootCheck))
+ {
+ //Target is too far to hit with given velocity/range/gravity params
+ //set firing angle for maximum distance
+ Log.Warning("[CE] Tried to fire projectile to unreachable target cell, truncating to maximum distance.");
+ return 45.0f * Mathf.Deg2Rad;
+ }
+ return Mathf.Atan((Mathf.Pow(_velocity, 2f) + (projectilePropsCE.flyOverhead ? 1f : -1f) * squareRootCheck) / (gravity * range));
+ }
+ }
+ public virtual float ShotRotation(ProjectilePropertiesCE projectilePropertiesCE, Vector3 source, Vector3 targetPos)
+ {
+ var w = targetPos - source;
+ return ( - 90 + Mathf.Rad2Deg * Mathf.Atan2(w.z, w.x)) % 360;
+ }
}
}
diff --git a/Source/CombatExtended/CombatExtended/Verbs/Verb_LaunchProjectileCE.cs b/Source/CombatExtended/CombatExtended/Verbs/Verb_LaunchProjectileCE.cs
index 0e4e516aef..b2d0c01c0a 100644
--- a/Source/CombatExtended/CombatExtended/Verbs/Verb_LaunchProjectileCE.cs
+++ b/Source/CombatExtended/CombatExtended/Verbs/Verb_LaunchProjectileCE.cs
@@ -610,16 +610,7 @@ protected float ShotAngle(Vector3 targetPos)
/// angle in radians
protected virtual float ShotAngle(Vector3 source, Vector3 targetPos)
{
- var targetHeight = targetPos.y;
- var newTargetLoc = new Vector2(targetPos.x, targetPos.z);
- if (projectilePropsCE.isInstant)
- {
- return Mathf.Atan2(targetHeight - ShotHeight, (newTargetLoc - sourceLoc).magnitude);
- }
- else
- {
- return ProjectileCE.GetShotAngle(ShotSpeed, (newTargetLoc - sourceLoc).magnitude, targetHeight - ShotHeight, Projectile.projectile.flyOverhead, projectilePropsCE.Gravity);
- }
+ return projectilePropsCE.TrajectoryWorker.ShotAngle(projectilePropsCE, source, targetPos);
}
protected float ShotRotation(Vector3 targetPos)
{
diff --git a/Source/CombatExtended/CombatExtended/WorldObjects/TravelingShell.cs b/Source/CombatExtended/CombatExtended/WorldObjects/TravelingShell.cs
index ce5a108318..01ca8b45d4 100644
--- a/Source/CombatExtended/CombatExtended/WorldObjects/TravelingShell.cs
+++ b/Source/CombatExtended/CombatExtended/WorldObjects/TravelingShell.cs
@@ -151,20 +151,18 @@ private bool TryShell(WorldObject worldObject)
private void LaunchProjectile(IntVec3 sourceCell, LocalTargetInfo target, Map map, float shotSpeed = 20, float shotHeight = 200)
{
- IntVec3 targetCell = target.Cell;
- Vector2 source = new Vector2(sourceCell.x, sourceCell.z);
- Vector2 destination = new Vector2(targetCell.x, targetCell.z);
- Vector2 w = (destination - source);
+ Vector3 source = new Vector3(sourceCell.x, shotHeight, sourceCell.z);
+ Vector3 targetPos = target.Cell.ToVector3Shifted();
ProjectileCE projectile = (ProjectileCE)ThingMaker.MakeThing(shellDef);
ProjectilePropertiesCE pprops = projectile.def.projectile as ProjectilePropertiesCE;
- float shotRotation = (-90 + Mathf.Rad2Deg * Mathf.Atan2(w.y, w.x)) % 360;
- float shotAngle = ProjectileCE.GetShotAngle(shotSpeed, (destination - source).magnitude, -shotHeight, false, pprops.Gravity);
+ float shotRotation = pprops.TrajectoryWorker.ShotRotation(pprops, source, targetPos);
+ float shotAngle = pprops.TrajectoryWorker.ShotAngle(pprops, source, targetPos, shotSpeed);
projectile.canTargetSelf = false;
projectile.Position = sourceCell;
projectile.SpawnSetup(map, false);
- projectile.Launch(launcher, source, shotAngle, shotRotation, shotHeight, shotSpeed);
+ projectile.Launch(launcher, new Vector2(source.x, source.z), shotAngle, shotRotation, shotHeight, shotSpeed);
//projectile.cameraShakingInit = Rand.Range(0f, 2f);
}
diff --git a/Source/CombatExtended/Harmony/Harmony_CompAbilityEffect_LaunchProjectile.cs b/Source/CombatExtended/Harmony/Harmony_CompAbilityEffect_LaunchProjectile.cs
index 55bc11d5cc..ad41171f69 100644
--- a/Source/CombatExtended/Harmony/Harmony_CompAbilityEffect_LaunchProjectile.cs
+++ b/Source/CombatExtended/Harmony/Harmony_CompAbilityEffect_LaunchProjectile.cs
@@ -24,26 +24,14 @@ internal static bool Prefix(CompAbilityEffect_LaunchProjectile __instance, Local
if (projectileDef.projectile is ProjectilePropertiesCE ppce)
{
Pawn pawn = __instance.parent.pawn;
- var u = pawn.TrueCenter();
- var sourceLoc = new Vector2();
- sourceLoc.Set(u.x, u.z);
- var targetLocation = new Vector2();
+ var u = pawn.TrueCenter().WithY((new CollisionVertical(pawn)).shotHeight);
+ var targetPos = target.Thing != null ? target.Thing.TrueCenter() : target.Cell.ToVector3Shifted();
+ targetPos = targetPos.WithY((new CollisionVertical(target.Thing)).shotHeight);
- if (target.HasThing)
- {
- targetLocation.Set(target.Thing.TrueCenter().x, target.Thing.TrueCenter().z);
- }
- else
- {
- targetLocation.Set(target.Cell.ToIntVec2.x, target.Cell.ToIntVec2.z);
- }
- var w = (targetLocation - sourceLoc);
- float shotRotation = (-90 + Mathf.Rad2Deg * Mathf.Atan2(w.y, w.x)) % 360;
-
- var targetVert = new CollisionVertical(target.Thing);
- var angle = ProjectileCE.GetShotAngle(ppce.speed, (target.Cell - pawn.Position).LengthHorizontal, targetVert.HeightRange.Average - 1, ppce.flyOverhead, ppce.Gravity);
- CE_Utility.LaunchProjectileCE(projectileDef, sourceLoc, target, pawn, angle, shotRotation, 1, ppce.speed);
+ var angle = ppce.TrajectoryWorker.ShotAngle(ppce, u, targetPos);
+ float shotRotation = ppce.TrajectoryWorker.ShotRotation(ppce, u, targetPos);
+ CE_Utility.LaunchProjectileCE(projectileDef, new Vector2(u.x, u.z), target, pawn, angle, shotRotation, u.y, ppce.speed);
return false;
}
}