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
3 changes: 3 additions & 0 deletions OpenRA.Mods.AS/OpenRA.Mods.AS.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
<Compile Include="Projectiles\InstantExplode.cs" />
<Compile Include="Projectiles\RadBeam.cs" />
<Compile Include="Projectiles\SpriteRailgun.cs" />
<Compile Include="Projectiles\SpriteAthenaLaser.cs" />
<Compile Include="Traits\AIDeployHelper.cs" />
<Compile Include="Traits\ChronoResourceDelivery.cs" />
<Compile Include="Traits\Conditions\GrantConditionAboveAltitude.cs" />
Expand All @@ -115,6 +116,8 @@
<Compile Include="Traits\Warheads\FireClusterWarhead.cs" />
<Compile Include="Traits\Warheads\FireFragmentWarhead.cs" />
<Compile Include="Traits\Warheads\FireShrapnelWarhead.cs" />
<Compile Include="Traits\Warheads\FireRadiusWarhead.cs" />
<Compile Include="Traits\Warheads\FireReverseRadiusWarhead.cs" />
<Compile Include="Traits\Warheads\GlobalExplodeWeaponWarhead.cs" />
<Compile Include="Traits\Warheads\RevealShroudWarhead.cs" />
<Compile Include="Traits\Warheads\ScreenShakerWarhead.cs" />
Expand Down
199 changes: 199 additions & 0 deletions OpenRA.Mods.AS/Projectiles/SpriteAthenaLaser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
#region Copyright & License Information
/*
* Copyright The OpenRA-AS Developers dnqbob
* 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 OpenRA.Effects;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Traits;

namespace OpenRA.Mods.AS.Projectiles
{
[Desc("Generate laser connect by image with different height offset, and trigger warheads on the ground until expires.")]
class SpriteAthenaLaserInfo : IProjectileInfo
{
[FieldLoader.Require]
[Desc("Laser Image to display.")]
public readonly string Image = null;

[SequenceReference("Image")]
[Desc("Laser sprite Sequence of Image from this list while this projectile is moving.")]
public readonly string Sequence = "idle";

[Desc("Number of the laser sprite to form the beam.")]
public readonly int SpriteNumber = 8;

[Desc("Offset of laser sprite to form the beam.")]
public readonly int HeightOffset = 1024;

[Desc("Laser ring image to display.")]
public readonly string RingImage = null;

[SequenceReference("RingImage")]
[Desc("Sequence of laser ring image from this list while this projectile is moving.")]
public readonly string RingSequence = "idle";

[PaletteReference("IsPlayerPalette")]
[Desc("The palette used to draw this projectile.")]
public readonly string Palette = "effect";

[Desc("Palette is a player palette BaseName")]
public readonly bool IsPlayerPalette = false;

[Desc("Projectile speed in WDist / tick.")]
public readonly WDist Speed = new WDist(90);

[Desc("Rotation speed around the target.")]
public readonly WAngle RotSpeed = WAngle.Zero;

[Desc("Rotation speed slowly add to max.")]
public readonly bool RotStartFromZero = true;

[Desc("How many ticks will pass between explosions.")]
public readonly int ExplosionInterval = 3;

[Desc("How many ticks will the projectile pierce even after reach the target location.")]
public readonly int PierceTicks = 0;

[Desc("How many ticks will the projectile stay after motion.")]
public readonly int StayTicks = 8;

public IProjectile Create(ProjectileArgs args) { return new SpriteAthenaLaser(this, args); }
}

class SpriteAthenaLaser : IProjectile
{
readonly int explosionInterval;
readonly ProjectileArgs args;
readonly Animation[] animations;
readonly Animation ringAnim;
readonly int heightoffset;
readonly int rotAcc;
readonly int speed;
readonly World world;
readonly string paletteName;
readonly int length, flightticks, maxticks;
readonly WPos target;
readonly WPos source;

WPos projectilepos;
WAngle rot;
int ticks;
int rotSpeed;

public SpriteAthenaLaser(SpriteAthenaLaserInfo info, ProjectileArgs args)
{
this.args = args;
speed = info.Speed.Length;

world = args.SourceActor.World;
source = new WPos(args.Source.X, args.Source.Y, 0);
target = new WPos(args.PassiveTarget.X, args.PassiveTarget.Y, 0);
length = Math.Max((target - source).Length / Math.Max(speed, 1), 1);
rotSpeed = info.RotStartFromZero ? 0 : info.RotSpeed.Angle * 1000;
rotAcc = info.RotStartFromZero ? info.RotSpeed.Angle * 1000 / length : 0;

projectilepos = source - new WVec(0, 0, world.Map.DistanceAboveTerrain(source).Length);
flightticks = length + info.PierceTicks;
maxticks = length + info.PierceTicks + info.StayTicks;
explosionInterval = Math.Max(info.ExplosionInterval, 1);
heightoffset = info.HeightOffset;

paletteName = info.Palette;
if (paletteName != null && info.IsPlayerPalette)
paletteName += args.SourceActor.Owner.InternalName;

if (!string.IsNullOrEmpty(info.Image))
{
animations = new Animation[info.SpriteNumber];

for (var i = 0; i < animations.Length; i++)
{
animations[i] = new Animation(world, info.Image);
animations[i].PlayRepeating(info.Sequence);
}
}

if (!string.IsNullOrEmpty(info.RingImage))
{
ringAnim = new Animation(world, info.RingImage);
ringAnim.PlayRepeating(info.RingSequence);
}
}

IEnumerable<IRenderable> IEffect.Render(WorldRenderer wr)
{
if (ticks > maxticks)
yield break;

foreach (var r in RenderAnimation(wr))
yield return r;
}

void IEffect.Tick(World world)
{
ticks++;

if (ticks % explosionInterval == 0)
{
args.Weapon.Impact(Target.FromPos(projectilepos), args.SourceActor, args.DamageModifiers);
}

if (ringAnim != null)
ringAnim.Tick();
for (var i = 0; i < animations.Length; i++)
animations[i].Tick();

rotSpeed += rotAcc;
if (ticks <= flightticks) // Flight Length Reached
{
var pos = projectilepos;
if (speed != 0)
pos = WPos.Lerp(source, target, ticks, length);

if (rotSpeed != 0)
{
rot += new WAngle(rotSpeed / 1000);
pos = target + (pos - target).Rotate(WRot.FromYaw(rot));
}

projectilepos = pos - new WVec(0, 0, world.Map.DistanceAboveTerrain(pos).Length);
}

if (ticks > maxticks)
world.AddFrameEndTask(w => w.Remove(this));
}

protected IEnumerable<IRenderable> RenderAnimation(WorldRenderer wr)
{
var renderpos = projectilepos;
var palette = wr.Palette(paletteName);

if (world.FogObscures(projectilepos))
yield break;

if (ringAnim != null)
{
foreach (var r in ringAnim.Render(renderpos, palette))
yield return r;
}

for (var i = 0; i < animations.Length; i++)
{
foreach (var r in animations[i].Render(renderpos, palette))
yield return r;

renderpos += new WVec(0, 0, heightoffset);
}
}
}
}
110 changes: 110 additions & 0 deletions OpenRA.Mods.AS/Traits/Warheads/FireRadiusWarhead.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#region Copyright & License Information
/*
* Copyright 2015- OpenRA.Mods.AS Developers (see AUTHORS)
* This file is a part of a third-party plugin for 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. For more information, see COPYING.
*/
#endregion

using System.Collections.Generic;
using System;
using System.Linq;
using OpenRA.GameRules;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;

namespace OpenRA.Mods.AS.Warheads
{
[Desc("Fires a defined amount of weapons with their maximum range in a wave pattern.")]
public class FireRadiusWarhead : WarheadAS, IRulesetLoaded<WeaponInfo>
{
[WeaponReference]
[FieldLoader.Require]
[Desc("Has to be defined in weapons.yaml as well.")]
public readonly string Weapon = null;

[Desc("Amount of weapons fired.")]
public readonly int[] Amount = { 1 };

[Desc("Should the weapons be fired around the intended target or at the explosion's epicenter.")]
public readonly bool AroundTarget = false;

WeaponInfo weapon;

public void RulesetLoaded(Ruleset rules, WeaponInfo info)
{
if (!rules.Weapons.TryGetValue(Weapon.ToLowerInvariant(), out weapon))
throw new YamlException("Weapons Ruleset does not contain an entry '" + Weapon.ToLowerInvariant() + "'");
}

public override void DoImpact(Target target, Actor firedBy, IEnumerable<int> damageModifiers)
{
if (!target.IsValidFor(firedBy))
return;

var world = firedBy.World;
var map = world.Map;

if (!IsValidImpact(target.CenterPosition, firedBy))
return;

var epicenter = target.CenterPosition;

var amount = Amount.Length == 2
? world.SharedRandom.Next(Amount[0], Amount[1])
: Amount[0];

var offset = 1024 / amount;

for (var i = 0; i < amount; i++)
{
var radiusTarget = Target.Invalid;

var rotation = WRot.FromYaw(new WAngle(i * offset));
var targetpos = epicenter + new WVec(weapon.Range.Length, 0, 0).Rotate(rotation);
var tpos = Target.FromPos(new WPos(targetpos.X, targetpos.Y, map.CenterOfCell(map.CellContaining(targetpos)).Z));
if (weapon.IsValidAgainst(tpos, firedBy.World, firedBy))
radiusTarget = tpos;

if (radiusTarget.Type == TargetType.Invalid)
continue;

// Lambdas can't use 'in' variables, so capture a copy for later
var centerPosition = target.CenterPosition;

var projectileArgs = new ProjectileArgs
{
Weapon = weapon,
Facing = (radiusTarget.CenterPosition - target.CenterPosition).Yaw.Facing,

DamageModifiers = !firedBy.IsDead ? firedBy.TraitsImplementing<IFirepowerModifier>()
.Select(a => a.GetFirepowerModifier()).ToArray() : new int[0],

InaccuracyModifiers = !firedBy.IsDead ? firedBy.TraitsImplementing<IInaccuracyModifier>()
.Select(a => a.GetInaccuracyModifier()).ToArray() : new int[0],

RangeModifiers = !firedBy.IsDead ? firedBy.TraitsImplementing<IRangeModifier>()
.Select(a => a.GetRangeModifier()).ToArray() : new int[0],

Source = target.CenterPosition,
CurrentSource = () => centerPosition,
SourceActor = firedBy,
GuidedTarget = radiusTarget,
PassiveTarget = radiusTarget.CenterPosition
};

if (projectileArgs.Weapon.Projectile != null)
{
var projectile = projectileArgs.Weapon.Projectile.Create(projectileArgs);
if (projectile != null)
firedBy.World.AddFrameEndTask(w => w.Add(projectile));

if (projectileArgs.Weapon.Report != null && projectileArgs.Weapon.Report.Any())
Game.Sound.Play(SoundType.World, projectileArgs.Weapon.Report.Random(firedBy.World.SharedRandom), target.CenterPosition);
}
}
}
}
}
Loading