SonicBlast projectile
-add sonicblast projectile - Adjust Sonic tank to match original D2k
This commit is contained in:
162
OpenRA.Mods.D2k/Projectiles/SonicBlast.cs
Normal file
162
OpenRA.Mods.D2k/Projectiles/SonicBlast.cs
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
#region Copyright & License Information
|
||||||
|
/*
|
||||||
|
* Copyright (c) The OpenRA Developers and Contributors
|
||||||
|
* This file is part of OpenRA, which is free software. It is made
|
||||||
|
* available to you under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version. For more
|
||||||
|
* information, see COPYING.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using OpenRA.GameRules;
|
||||||
|
using OpenRA.Graphics;
|
||||||
|
using OpenRA.Mods.Common;
|
||||||
|
using OpenRA.Mods.Common.Graphics;
|
||||||
|
using OpenRA.Mods.Common.Traits;
|
||||||
|
using OpenRA.Primitives;
|
||||||
|
using OpenRA.Traits;
|
||||||
|
|
||||||
|
namespace OpenRA.Mods.D2k.Projectiles
|
||||||
|
{
|
||||||
|
[Desc("Blast projectile that travels in a straight line.")]
|
||||||
|
public class SonicBlastInfo : IProjectileInfo
|
||||||
|
{
|
||||||
|
[Desc("Projectile speed in WDist / tick, two values indicate a randomly picked velocity per blast.")]
|
||||||
|
public readonly WDist[] Speed = { new(128) };
|
||||||
|
|
||||||
|
[Desc("The number of ticks between the blast causing warhead impacts in its area of effect.")]
|
||||||
|
public readonly int DamageInterval = 1;
|
||||||
|
|
||||||
|
[Desc("Equivalent to sequence ZOffset. Controls Z sorting.")]
|
||||||
|
public readonly int ZOffset = 0;
|
||||||
|
|
||||||
|
[Desc("The minimum distance the blast travels.")]
|
||||||
|
public readonly WDist MinDistance = WDist.Zero;
|
||||||
|
|
||||||
|
[Desc("Width of projectile (used for finding blocking actors).")]
|
||||||
|
public readonly WDist Width = new(650);
|
||||||
|
|
||||||
|
[Desc("Damage modifier applied at each range step.")]
|
||||||
|
public readonly int[] Falloff = { 100, 100 };
|
||||||
|
|
||||||
|
[Desc("Ranges at which each Falloff step is defined.")]
|
||||||
|
public readonly WDist[] Range = { WDist.Zero, new(int.MaxValue) };
|
||||||
|
|
||||||
|
[Desc("The maximum/constant/incremental inaccuracy used in conjunction with the InaccuracyType property.")]
|
||||||
|
public readonly WDist Inaccuracy = WDist.Zero;
|
||||||
|
|
||||||
|
[Desc("Controls the way inaccuracy is calculated. Possible values are" +
|
||||||
|
"'Maximum' - scale from 0 to max with range," +
|
||||||
|
"'PerCellIncrement' - scale from 0 with range" +
|
||||||
|
"'Absolute' - use set value regardless of range.")]
|
||||||
|
public readonly InaccuracyType InaccuracyType = InaccuracyType.Maximum;
|
||||||
|
|
||||||
|
[Desc("Can this projectile be blocked when hitting actors with an nameof(BlocksProjectiles) trait.")]
|
||||||
|
public readonly bool Blockable = false;
|
||||||
|
|
||||||
|
[Desc("Color of the blast.")]
|
||||||
|
public readonly Color Color = Color.SkyBlue;
|
||||||
|
|
||||||
|
public IProjectile Create(ProjectileArgs args)
|
||||||
|
{
|
||||||
|
return new SonicBlast(this, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SonicBlast : IProjectile, ISync
|
||||||
|
{
|
||||||
|
readonly SonicBlastInfo info;
|
||||||
|
readonly ProjectileArgs args;
|
||||||
|
|
||||||
|
readonly WDist speed;
|
||||||
|
|
||||||
|
[Sync]
|
||||||
|
WPos pos, lastPos;
|
||||||
|
readonly WPos target;
|
||||||
|
int length;
|
||||||
|
|
||||||
|
int ticks;
|
||||||
|
|
||||||
|
public SonicBlast(SonicBlastInfo info, ProjectileArgs args)
|
||||||
|
{
|
||||||
|
this.info = info;
|
||||||
|
this.args = args;
|
||||||
|
var world = args.SourceActor.World;
|
||||||
|
if (info.Speed.Length > 1)
|
||||||
|
speed = new WDist(world.SharedRandom.Next(info.Speed[0].Length, info.Speed[1].Length));
|
||||||
|
else
|
||||||
|
speed = info.Speed[0];
|
||||||
|
pos = args.Source;
|
||||||
|
target = args.PassiveTarget;
|
||||||
|
if (info.Inaccuracy.Length > 0)
|
||||||
|
{
|
||||||
|
var maxInaccuracyOffset = Common.Util.GetProjectileInaccuracy(info.Inaccuracy.Length, info.InaccuracyType, args);
|
||||||
|
target += WVec.FromPDF(world.SharedRandom, 2) * maxInaccuracyOffset / 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
var dir = new WVec(0, -1024, 0).Rotate(WRot.FromYaw((target - pos).Yaw));
|
||||||
|
var dist = (args.SourceActor.CenterPosition - target).Length;
|
||||||
|
var extraDist = 0;
|
||||||
|
if (info.MinDistance.Length > dist)
|
||||||
|
extraDist = info.MinDistance.Length - dist;
|
||||||
|
target += dir * extraDist / 1024;
|
||||||
|
length = Math.Max((target - pos).Length / speed.Length, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Tick(World world)
|
||||||
|
{
|
||||||
|
if (ticks++ >= length)
|
||||||
|
world.AddFrameEndTask(w => w.Remove(this));
|
||||||
|
|
||||||
|
lastPos = pos;
|
||||||
|
pos = WPos.LerpQuadratic(args.Source, target, WAngle.Zero, ticks, length);
|
||||||
|
|
||||||
|
if (info.Blockable && BlocksProjectiles.AnyBlockingActorsBetween(world, args.SourceActor.Owner, lastPos, pos, info.Width, out var blockedPos))
|
||||||
|
{
|
||||||
|
pos = blockedPos;
|
||||||
|
length = Math.Min(ticks, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ticks % info.DamageInterval == 0)
|
||||||
|
{
|
||||||
|
var adjustedModifiers = args.DamageModifiers.Append(GetFalloff((args.Source - pos).Length));
|
||||||
|
var warheadArgs = new WarheadArgs(args)
|
||||||
|
{
|
||||||
|
ImpactOrientation = new WRot(WAngle.Zero, Common.Util.GetVerticalAngle(args.Source, target), args.CurrentMuzzleFacing()),
|
||||||
|
ImpactPosition = pos,
|
||||||
|
DamageModifiers = adjustedModifiers.ToArray(),
|
||||||
|
};
|
||||||
|
args.Weapon.Impact(Target.FromPos(pos), warheadArgs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetFalloff(int distance)
|
||||||
|
{
|
||||||
|
var inner = info.Range[0].Length;
|
||||||
|
for (var i = 1; i < info.Range.Length; i++)
|
||||||
|
{
|
||||||
|
var outer = info.Range[i].Length;
|
||||||
|
if (outer > distance)
|
||||||
|
return int2.Lerp(info.Falloff[i - 1], info.Falloff[i], distance - inner, outer - inner);
|
||||||
|
|
||||||
|
inner = outer;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||||
|
{
|
||||||
|
if (!wr.World.FogObscures(pos))
|
||||||
|
{
|
||||||
|
var blastRender = new BeamRenderable(pos, info.ZOffset, lastPos - pos, BeamRenderableShape.Cylindrical, info.Width, info.Color);
|
||||||
|
return new[] { (IRenderable)blastRender };
|
||||||
|
}
|
||||||
|
|
||||||
|
return SpriteRenderable.None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,36 +2,32 @@ Sound:
|
|||||||
ReloadDelay: 90
|
ReloadDelay: 90
|
||||||
Range: 5c0
|
Range: 5c0
|
||||||
Report: SONIC1.WAV
|
Report: SONIC1.WAV
|
||||||
Projectile: AreaBeam
|
Projectile: SonicBlast
|
||||||
Speed: 0c128
|
Speed: 0c128
|
||||||
Inaccuracy: 128
|
Inaccuracy: 135
|
||||||
InaccuracyType: PerCellIncrement
|
InaccuracyType: PerCellIncrement
|
||||||
Duration: 4 # Has a length of 0c512
|
DamageInterval: 1
|
||||||
DamageInterval: 3 # Travels 0c384 between impacts, will hit a target roughly three times
|
|
||||||
Width: 0c756 # in original d2k width is 2c0, but damage is 100% only at the center and fades out linearly towards the edges
|
|
||||||
Shape: Cylindrical
|
|
||||||
Falloff: 0, 0, 100, 0
|
Falloff: 0, 0, 100, 0
|
||||||
Range: 0, 0c450, 4c0, 8c0
|
Range: 0, 0c512, 4c0, 6c0
|
||||||
BeyondTargetRange: 1c0
|
|
||||||
MinDistance: 5c0
|
MinDistance: 5c0
|
||||||
Color: 00FFFFC8
|
Color: 00FFFFC8
|
||||||
Warhead@1Dam: SpreadDamage
|
Warhead@1Dam: SpreadDamage
|
||||||
Range: 0, 32
|
Falloff: 100, 0
|
||||||
Falloff: 100, 100
|
Spread: 1c756
|
||||||
Damage: 960
|
Damage: 800
|
||||||
AffectsParent: false
|
AffectsParent: false
|
||||||
ValidRelationships: Neutral, Enemy, Ally
|
ValidRelationships: Neutral, Enemy, Ally
|
||||||
Versus:
|
Versus:
|
||||||
none: 200
|
none: 100
|
||||||
wall: 50
|
wall: 50
|
||||||
building: 60
|
building: 60
|
||||||
wood: 110
|
wood: 100
|
||||||
light: 110
|
light: 100
|
||||||
heavy: 60
|
heavy: 60
|
||||||
invulnerable: 0
|
invulnerable: 0
|
||||||
cy: 20
|
cy: 20
|
||||||
harvester: 50
|
harvester: 50
|
||||||
DamageTypes: Prone50Percent, TriggerProne, SoundDeath
|
DamageTypes: TriggerProne, SoundDeath
|
||||||
Warhead@3Concrete: DamagesConcrete
|
Warhead@3Concrete: DamagesConcrete
|
||||||
Damage: 1720
|
Damage: 1720
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user