Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Defs/WorldObjectDefs/WorldObjects.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,14 @@
<expandingIconTexture>Things/WorldObjects/Munitions/Shell</expandingIconTexture>
</WorldObjectDef>

<WorldObjectDef ParentName="TravelingThing">
<defName>TravelingRaycast</defName>
<label>Artillery Raycast</label>
<description>An artillery beam.</description>
<worldObjectClass>CombatExtended.TravelingRaycast</worldObjectClass>
<texture>Things/WorldObjects/Munitions/Shell_Invisible</texture>
<useDynamicDrawer>true</useDynamicDrawer>
<expandingIcon>false</expandingIcon>
</WorldObjectDef>

</Defs>
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ static CE_WorldObjectDefOf()
DefOfHelper.EnsureInitializedInCtor(typeof(CE_WorldObjectDefOf));
}
public static WorldObjectDef TravelingShell;
public static WorldObjectDef TravelingRaycast;
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ void TriggerEffect(EffecterDef effect, IntVec3 dest)
effecter.Cleanup();
}

public void SpawnBeam(Vector3 a, Vector3 b)
public virtual void SpawnBeam(Vector3 a, Vector3 b)
{
LaserBeamGraphicCE graphic = ThingMaker.MakeThing(laserBeamDef.beamGraphic, null) as LaserBeamGraphicCE;
if (graphic == null)
Expand Down
103 changes: 101 additions & 2 deletions Source/CombatExtended/CombatExtended/Projectiles/ProjectileCE.cs
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,19 @@ public virtual void Throw(Thing launcher, Vector3 origin, Vector3 heading, Thing
#endregion

#region Raycast
public virtual void RayCast(Thing launcher, VerbProperties verbProps, Vector2 origin, float shotAngle, float shotRotation, float shotHeight = 0f, float shotSpeed = -1f, float spreadDegrees = 0f, float aperatureSize = 0.03f, Thing equipment = null)
public virtual void RayCast(
Thing launcher,
VerbProperties verbProps,
Vector2 origin,
float shotAngle,
float shotRotation,
float shotHeight = 0f,
float shotSpeed = -1f,
float spreadDegrees = 0f,
float aperatureSize = 0.03f,
Thing equipment = null,
bool useSameHeight = false
)
{

float magicSpreadFactor = Mathf.Sin(0.06f / 2 * Mathf.Deg2Rad) + aperatureSize;
Expand Down Expand Up @@ -522,6 +534,11 @@ public virtual void RayCast(Thing launcher, VerbProperties verbProps, Vector2 or
LastPos = destination;
Position = ExactPosition.ToIntVec3();

if (useSameHeight)
{
muzzle.y = destination.y;
}

lbce.SpawnBeam(muzzle, destination);
RayCastSuppression(muzzle.ToIntVec3(), destination.ToIntVec3());
lbce.Impact(null, muzzle);
Expand Down Expand Up @@ -564,9 +581,13 @@ public virtual void RayCast(Thing launcher, VerbProperties verbProps, Vector2 or
LastPos = destination;
Position = ExactPosition.ToIntVec3();

if (useSameHeight)
{
muzzle.y = destination.y;
}

lbce.SpawnBeam(muzzle, destination);
RayCastSuppression(muzzle.ToIntVec3(), destination.ToIntVec3());

lbce.Impact(thing, muzzle);

return;
Expand All @@ -576,13 +597,91 @@ public virtual void RayCast(Thing launcher, VerbProperties verbProps, Vector2 or
}
if (lbce != null)
{
if (useSameHeight)
{
muzzle.y = destination.y;
}

lbce.SpawnBeam(muzzle, destination);
RayCastSuppression(muzzle.ToIntVec3(), destination.ToIntVec3());
Destroy(DestroyMode.Vanish);
return;
}
}

public void RayCastWorldTarget(
Thing launcher,
Verb_ShootCE verbToUse,
Vector2 originLocal,
float shotAngle,
float shotHeight,
float shotSpeed = -1f,
float spreadDegrees = 0f,
float aperatureSize = 0.03f,
Thing equipment = null
)
{
if (!globalTargetInfo.IsValid)
{
Log.Warning("Cannot Raycast on a world target without globalTargetInfo");
return;
}

// --- Graphical part

// Let's fire only on the exit cell
Vector3 u = verbToUse.Caster.TrueCenter();
Vector3 v = verbToUse.currentTarget.Cell.ToVector3Shifted();
var d = v - u;
var precisedShotRotation = (-90 + Mathf.Rad2Deg * Mathf.Atan2(d.z, d.x)) % 360;

// create the local raycast
this.RayCast(
launcher,
verbToUse.verbProps,
originLocal,
0, // set angle to 0 so the raycast goes straight (it won't touch anything so it doesn't matter)
precisedShotRotation,
shotHeight,
shotSpeed,
0, // no need
0, // no need
equipment
);

// --- Creating shell to use linked mechanics

Props.shellingProps.tilesPerTick = 99999; // instant speeeeed !

TravelingRaycast travelingRaycast = (TravelingRaycast)WorldObjectMaker.MakeWorldObject(CE_WorldObjectDefOf.TravelingRaycast);
if (launcher?.Faction != null)
{
travelingRaycast.SetFaction(launcher.Faction);
}
travelingRaycast.Tile = launcher.Map.Tile;
travelingRaycast.SpawnSetup();
Find.World.worldObjects.Add(travelingRaycast);
travelingRaycast.launcher = launcher;
travelingRaycast.equipmentDef = equipmentDef;
travelingRaycast.globalSource = new GlobalTargetInfo(OriginIV3, launcher.Map);
travelingRaycast.globalSource.tileInt = launcher.Map.Tile;
travelingRaycast.globalSource.mapInt = launcher.Map;
travelingRaycast.globalSource.worldObjectInt = launcher.Map.Parent;
travelingRaycast.shellDef = def;
travelingRaycast.globalTarget = globalTargetInfo;

travelingRaycast.verbToUse = verbToUse;
travelingRaycast.spreadDegrees = spreadDegrees;
travelingRaycast.aperatureSize = aperatureSize;
travelingRaycast.equipement = equipment;

if (!travelingRaycast.TryTravel(launcher.Map.Tile, globalTargetInfo.Tile))
{
Log.Error($"CE: Travling raycast {this.def} failed to launch!");
travelingRaycast.Destroy();
}
}

protected void RayCastSuppression(IntVec3 muzzle, IntVec3 destination, Map map = null)
{
if (muzzle == destination)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public CompFireModes CompFireModes
return compFireModes;
}
}
private ProjectilePropertiesCE ProjectileProps => (ProjectilePropertiesCE)compAmmo?.CurAmmoProjectile?.projectile ?? null;
private ProjectilePropertiesCE ProjectileProps => (ProjectilePropertiesCE)Projectile?.projectile;
public float MaxWorldRange => ProjectileProps?.shellingProps.range ?? -1f;
public bool EmptyMagazine => CompAmmo?.EmptyMagazine ?? false;
public bool FullMagazine => CompAmmo?.FullMagazine ?? false;
Expand Down Expand Up @@ -740,7 +740,7 @@ public override IEnumerable<Gizmo> GetGizmos() // Modified
yield return com;
}
}
if (IsMortar && Active && Faction.IsPlayerSafe() && (compAmmo?.UseAmmo ?? false) && ProjectileProps?.shellingProps != null)
if (IsMortar && Active && Faction.IsPlayerSafe() && ProjectileProps?.shellingProps != null)
{
Command_ArtilleryTarget wt = new Command_ArtilleryTarget()
{
Expand Down
16 changes: 16 additions & 0 deletions Source/CombatExtended/CombatExtended/Verbs/Verb_ShootCE.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,22 @@ public float AimAngle

public override ThingDef Projectile => CompAmmo?.CurrentAmmo != null ? CompAmmo.CurAmmoProjectile : base.Projectile;

public override float ShotHeight
{
get
{
if (projectilePropsCE.isInstant && projectilePropsCE.flyOverhead)
{
// - Set the height to be above roofs as a instant projectile with flyOverhead should bypass roofs. Think big lasers for example.
// - Equivelant to 7m
// - Use for VGE patch
// - see also CombatExtended.Compatibility.SOS2Compat.Verb_ShootShip_CE.ShotHeight
return 4f;
}
return base.ShotHeight;
}
}

#endregion

#region Methods
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,13 @@ public virtual bool TryCastGlobalShot()
return false;
}
bool instant = false;
float spreadDegrees = 0;
float aperatureSize = 0;
if (Projectile.projectile is ProjectilePropertiesCE pprop)
{
instant = pprop.isInstant;
spreadDegrees = (EquipmentSource?.GetStatValue(CE_StatDefOf.ShotSpread) ?? 0) * pprop.spreadMult;
aperatureSize = 0.03f;
}

ShiftVecReport reportGlobal = ShiftVecReportFor(globalTargetInfo);
Expand All @@ -180,6 +184,7 @@ public virtual bool TryCastGlobalShot()
ShiftTarget(report, pelletMechanicsOnly, instant);

float shotSpeed = ShotSpeed * 5;
var intendedTarget = globalTargetInfo.Thing ?? currentTarget;
//The projectile shouldn't care about the target thing
projectile.globalTargetInfo = new GlobalTargetInfo();
projectile.globalTargetInfo.cellInt = shiftedGlobalCell;
Expand All @@ -191,15 +196,31 @@ public virtual bool TryCastGlobalShot()
projectile.globalSourceInfo = globalSourceInfo;
projectile.mount = caster.Position.GetThingList(caster.Map).FirstOrDefault(t => t is Pawn && t != caster);
projectile.AccuracyFactor = report.accuracyFactor * report.swayDegrees * ((numShotsFired + 1) * 0.75f);
projectile.Launch(
Shooter, //Shooter instead of caster to give turret operators' records the damage/kills obtained
sourceLoc,
shotAngle,
shotRotation,
ShotHeight,
shotSpeed,
EquipmentSource);
pelletMechanicsOnly = true;

if (instant)
{
projectile.RayCastWorldTarget(
Shooter,
this,
sourceLoc,
shotAngle,
ShotHeight,
ShotSpeed,
spreadDegrees,
aperatureSize,
EquipmentSource);
}
else
{
projectile.Launch(
Shooter, //Shooter instead of caster to give turret operators' records the damage/kills obtained
sourceLoc,
shotAngle,
shotRotation,
ShotHeight,
shotSpeed,
EquipmentSource);
}
}

/*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using Verse;

namespace CombatExtended;

public class TravelingRaycast : TravelingShell
{
public Verb_ShootCE verbToUse;
public float spreadDegrees;
public float aperatureSize;
public Thing equipement;

protected override void LaunchProjectile(IntVec3 sourceCell, LocalTargetInfo target, Map map, float shotSpeed = 20, float shotHeight = 200)
{
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 = 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);

if (pprops.isInstant)
{
if (verbToUse == null)
{
Log.Warning("Instant shelling needs a ShootingCE Verb in order to work.");
return;
}

float tsa = verbToUse.AdjustShotHeight(launcher, target, ref shotHeight);
projectile.RayCast(launcher,
verbToUse.verbProps,
new Vector2(source.x, source.z),
shotAngle,
shotRotation,
shotHeight + tsa,
shotSpeed,
spreadDegrees,
aperatureSize,
null,
true // Allow beam to be drawn correctly
);
}
else
{
// classic shell behavior
Log.Warning("TravellingRaycast called for a classic projectile. Aborted.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public override bool ExpandingIconFlipHorizontal
{
get => GenWorldUI.WorldToUIPosition(Start).x > GenWorldUI.WorldToUIPosition(End).x;
}
public bool IsInstant => (shellDef.projectile as ProjectilePropertiesCE).isInstant;

public override float ExpandingIconRotation
{
Expand Down Expand Up @@ -124,12 +125,8 @@ private bool TryShell(WorldObject worldObject)
Ray ray = new Ray(targetCell.ToVector3(), -1 * direction);
Bounds mapBounds = new Bounds((mapSize / 2f).Yto0(), mapSize);
mapBounds.IntersectRay(ray, out float distanceToEdge);
IntVec3 sourceCell = ray.GetPoint(distanceToEdge * 0.75f).ToIntVec3();
LaunchProjectile(
sourceCell,
targetCell,
map: map,
shotSpeed: 55f);
IntVec3 sourceCell = ray.GetPoint(distanceToEdge * (IsInstant ? 1f : 0.75f)).ToIntVec3(); // Instant shells should start at the edge of the map
LaunchProjectile(sourceCell, targetCell, map);
}
WorldObjects.HostilityComp hostility = worldObject.GetComponent<WorldObjects.HostilityComp>();
WorldObjects.HealthComp healthComp = worldObject.GetComponent<WorldObjects.HealthComp>();
Expand All @@ -148,7 +145,7 @@ private bool TryShell(WorldObject worldObject)
return shelled;
}

private void LaunchProjectile(IntVec3 sourceCell, LocalTargetInfo target, Map map, float shotSpeed = 20, float shotHeight = 200)
protected virtual void LaunchProjectile(IntVec3 sourceCell, LocalTargetInfo target, Map map, float shotSpeed = 20, float shotHeight = 200)
{
Vector3 source = new Vector3(sourceCell.x, shotHeight, sourceCell.z);
Vector3 targetPos = target.Cell.ToVector3Shifted();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ public class TravelingShellProperties
/// </summary>
public string iconPath;

/// <summary>
/// Projectile arrive at the same height and same speed they're launched.
/// </summary>
public bool arrivedAtSameProps = false;

public Type workerClass = typeof(WorldObjectDamageWorker);
public WorldObjectDamageWorker Worker
{
Expand Down
Loading