Mods.Common Effects
Moved over more effects to Mods.Common
This commit is contained in:
109
OpenRA.Mods.Common/Effects/Beacon.cs
Normal file
109
OpenRA.Mods.Common/Effects/Beacon.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* 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. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Mods.Common.Effects
|
||||
{
|
||||
public class Beacon : IEffect
|
||||
{
|
||||
readonly Player owner;
|
||||
readonly WPos position;
|
||||
readonly string palettePrefix;
|
||||
readonly string posterPalette;
|
||||
readonly Animation arrow;
|
||||
readonly Animation circles;
|
||||
readonly Animation poster;
|
||||
readonly Animation clock;
|
||||
|
||||
static readonly int maxArrowHeight = 512;
|
||||
int arrowHeight = maxArrowHeight;
|
||||
int arrowSpeed = 50;
|
||||
|
||||
// Player-placed beacons are removed after a delay
|
||||
public Beacon(Player owner, WPos position, int duration, string palettePrefix)
|
||||
{
|
||||
this.owner = owner;
|
||||
this.position = position;
|
||||
this.palettePrefix = palettePrefix;
|
||||
|
||||
arrow = new Animation(owner.World, "beacon");
|
||||
circles = new Animation(owner.World, "beacon");
|
||||
|
||||
arrow.Play("arrow");
|
||||
circles.Play("circles");
|
||||
|
||||
if (duration > 0)
|
||||
owner.World.Add(new DelayedAction(duration, () => owner.World.Remove(this)));
|
||||
}
|
||||
|
||||
// Support power beacons are expected to clean themselves up
|
||||
public Beacon(Player owner, WPos position, string palettePrefix, string posterType, string posterPalette, Func<float> clockFraction)
|
||||
: this(owner, position, -1, palettePrefix)
|
||||
{
|
||||
this.posterPalette = posterPalette;
|
||||
|
||||
if (posterType != null)
|
||||
{
|
||||
poster = new Animation(owner.World, "beacon");
|
||||
poster.Play(posterType);
|
||||
|
||||
if (clockFraction != null)
|
||||
{
|
||||
clock = new Animation(owner.World, "beacon");
|
||||
clock.PlayFetchIndex("clock", () => Exts.Clamp((int)(clockFraction() * (clock.CurrentSequence.Length - 1)), 0, clock.CurrentSequence.Length - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Tick(World world)
|
||||
{
|
||||
arrowHeight += arrowSpeed;
|
||||
var clamped = arrowHeight.Clamp(0, maxArrowHeight);
|
||||
if (arrowHeight != clamped)
|
||||
{
|
||||
arrowHeight = clamped;
|
||||
arrowSpeed *= -1;
|
||||
}
|
||||
|
||||
arrow.Tick();
|
||||
circles.Tick();
|
||||
|
||||
if (clock != null)
|
||||
clock.Tick();
|
||||
}
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer r)
|
||||
{
|
||||
if (!owner.IsAlliedWith(owner.World.RenderPlayer))
|
||||
yield break;
|
||||
|
||||
var palette = r.Palette(palettePrefix + owner.InternalName);
|
||||
foreach (var a in circles.Render(position, palette))
|
||||
yield return a;
|
||||
|
||||
foreach (var a in arrow.Render(position + new WVec(0, 0, arrowHeight), palette))
|
||||
yield return a;
|
||||
|
||||
if (poster != null)
|
||||
{
|
||||
foreach (var a in poster.Render(position, r.Palette(posterPalette)))
|
||||
yield return a;
|
||||
|
||||
if (clock != null)
|
||||
foreach (var a in clock.Render(position, r.Palette(posterPalette)))
|
||||
yield return a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
179
OpenRA.Mods.Common/Effects/Bullet.cs
Normal file
179
OpenRA.Mods.Common/Effects/Bullet.cs
Normal file
@@ -0,0 +1,179 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* 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. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Effects
|
||||
{
|
||||
public class BulletInfo : IProjectileInfo
|
||||
{
|
||||
[Desc("Projectile speed in WRange / tick, two values indicate variable velocity")]
|
||||
public readonly WRange[] Speed = { new WRange(17) };
|
||||
public readonly string Trail = null;
|
||||
[Desc("Maximum offset at the maximum range")]
|
||||
public readonly WRange Inaccuracy = WRange.Zero;
|
||||
public readonly string Image = null;
|
||||
[Desc("Check for whether an actor with BlocksBullets: trait blocks fire")]
|
||||
public readonly bool High = false;
|
||||
public readonly bool Shadow = false;
|
||||
[Desc("Arc in WAngles, two values indicate variable arc.")]
|
||||
public readonly WAngle[] Angle = { WAngle.Zero };
|
||||
public readonly int TrailInterval = 2;
|
||||
public readonly int TrailDelay = 1;
|
||||
public readonly int ContrailLength = 0;
|
||||
public readonly Color ContrailColor = Color.White;
|
||||
public readonly bool ContrailUsePlayerColor = false;
|
||||
public readonly int ContrailDelay = 1;
|
||||
|
||||
public IEffect Create(ProjectileArgs args) { return new Bullet(this, args); }
|
||||
}
|
||||
|
||||
public class Bullet : IEffect, ISync
|
||||
{
|
||||
readonly BulletInfo info;
|
||||
readonly ProjectileArgs args;
|
||||
[Sync] readonly WAngle angle;
|
||||
[Sync] readonly WRange speed;
|
||||
|
||||
ContrailRenderable trail;
|
||||
Animation anim;
|
||||
|
||||
[Sync] WPos pos, target;
|
||||
[Sync] int length;
|
||||
[Sync] int facing;
|
||||
[Sync] int ticks, smokeTicks;
|
||||
|
||||
[Sync] public Actor SourceActor { get { return args.SourceActor; } }
|
||||
|
||||
public Bullet(BulletInfo info, ProjectileArgs args)
|
||||
{
|
||||
this.info = info;
|
||||
this.args = args;
|
||||
this.pos = args.Source;
|
||||
|
||||
var world = args.SourceActor.World;
|
||||
|
||||
if (info.Angle.Length > 1 && info.Speed.Length > 1)
|
||||
{
|
||||
angle = new WAngle(world.SharedRandom.Next(info.Angle[0].Angle, info.Angle[1].Angle));
|
||||
speed = new WRange(world.SharedRandom.Next(info.Speed[0].Range, info.Speed[1].Range));
|
||||
}
|
||||
else
|
||||
{
|
||||
angle = info.Angle[0];
|
||||
speed = info.Speed[0];
|
||||
}
|
||||
|
||||
target = args.PassiveTarget;
|
||||
if (info.Inaccuracy.Range > 0)
|
||||
{
|
||||
var inaccuracy = OpenRA.Traits.Util.ApplyPercentageModifiers(info.Inaccuracy.Range, args.InaccuracyModifiers);
|
||||
var maxOffset = inaccuracy * (target - pos).Length / args.Weapon.Range.Range;
|
||||
target += WVec.FromPDF(world.SharedRandom, 2) * maxOffset / 1024;
|
||||
}
|
||||
|
||||
facing = OpenRA.Traits.Util.GetFacing(target - pos, 0);
|
||||
length = Math.Max((target - pos).Length / speed.Range, 1);
|
||||
|
||||
if (info.Image != null)
|
||||
{
|
||||
anim = new Animation(world, info.Image, GetEffectiveFacing);
|
||||
anim.PlayRepeating("idle");
|
||||
}
|
||||
|
||||
if (info.ContrailLength > 0)
|
||||
{
|
||||
var color = info.ContrailUsePlayerColor ? ContrailRenderable.ChooseColor(args.SourceActor) : info.ContrailColor;
|
||||
trail = new ContrailRenderable(world, color, info.ContrailLength, info.ContrailDelay, 0);
|
||||
}
|
||||
|
||||
smokeTicks = info.TrailDelay;
|
||||
}
|
||||
|
||||
int GetEffectiveFacing()
|
||||
{
|
||||
var at = (float)ticks / (length - 1);
|
||||
var attitude = angle.Tan() * (1 - 2 * at) / (4 * 1024);
|
||||
|
||||
var u = (facing % 128) / 128f;
|
||||
var scale = 512 * u * (1 - u);
|
||||
|
||||
return (int)(facing < 128
|
||||
? facing - scale * attitude
|
||||
: facing + scale * attitude);
|
||||
}
|
||||
|
||||
public void Tick(World world)
|
||||
{
|
||||
if (anim != null)
|
||||
anim.Tick();
|
||||
|
||||
pos = WPos.LerpQuadratic(args.Source, target, angle, ticks, length);
|
||||
|
||||
if (info.Trail != null && --smokeTicks < 0)
|
||||
{
|
||||
var delayedPos = WPos.LerpQuadratic(args.Source, target, angle, ticks - info.TrailDelay, length);
|
||||
world.AddFrameEndTask(w => w.Add(new Smoke(w, delayedPos, info.Trail)));
|
||||
smokeTicks = info.TrailInterval;
|
||||
}
|
||||
|
||||
if (info.ContrailLength > 0)
|
||||
trail.Update(pos);
|
||||
|
||||
if (ticks++ >= length || (!info.High && world.ActorMap
|
||||
.GetUnitsAt(world.Map.CellContaining(pos)).Any(a => a.HasTrait<IBlocksBullets>())))
|
||||
{
|
||||
Explode(world);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
{
|
||||
if (info.ContrailLength > 0)
|
||||
yield return trail;
|
||||
|
||||
if (anim == null || ticks >= length)
|
||||
yield break;
|
||||
|
||||
var cell = wr.world.Map.CellContaining(pos);
|
||||
if (!args.SourceActor.World.FogObscures(cell))
|
||||
{
|
||||
if (info.Shadow)
|
||||
{
|
||||
var shadowPos = pos - new WVec(0, 0, pos.Z);
|
||||
foreach (var r in anim.Render(shadowPos, wr.Palette("shadow")))
|
||||
yield return r;
|
||||
}
|
||||
|
||||
var palette = wr.Palette(args.Weapon.Palette);
|
||||
foreach (var r in anim.Render(pos, palette))
|
||||
yield return r;
|
||||
}
|
||||
}
|
||||
|
||||
void Explode(World world)
|
||||
{
|
||||
if (info.ContrailLength > 0)
|
||||
world.AddFrameEndTask(w => w.Add(new ContrailFader(pos, trail)));
|
||||
|
||||
world.AddFrameEndTask(w => w.Remove(this));
|
||||
|
||||
args.Weapon.Impact(Target.FromPos(pos), args.SourceActor, args.DamageModifiers);
|
||||
}
|
||||
}
|
||||
}
|
||||
64
OpenRA.Mods.Common/Effects/Contrail.cs
Normal file
64
OpenRA.Mods.Common/Effects/Contrail.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* 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. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Effects
|
||||
{
|
||||
[Desc("Draw a colored contrail behind this actor when they move.")]
|
||||
class ContrailInfo : ITraitInfo, Requires<IBodyOrientationInfo>
|
||||
{
|
||||
[Desc("Position relative to body")]
|
||||
public readonly WVec Offset = WVec.Zero;
|
||||
|
||||
[Desc("Measured in pixels.")]
|
||||
public readonly int TrailLength = 25;
|
||||
|
||||
[Desc("RGB color of the contrail.")]
|
||||
public readonly Color Color = Color.White;
|
||||
|
||||
[Desc("Use player remap color instead of a custom color?")]
|
||||
public readonly bool UsePlayerColor = true;
|
||||
|
||||
public object Create(ActorInitializer init) { return new Contrail(init.self, this); }
|
||||
}
|
||||
|
||||
class Contrail : ITick, IRender
|
||||
{
|
||||
ContrailInfo info;
|
||||
ContrailRenderable trail;
|
||||
IBodyOrientation body;
|
||||
|
||||
public Contrail(Actor self, ContrailInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
|
||||
var color = info.UsePlayerColor ? ContrailRenderable.ChooseColor(self) : info.Color;
|
||||
trail = new ContrailRenderable(self.World, color, info.TrailLength, 0, 0);
|
||||
|
||||
body = self.Trait<IBodyOrientation>();
|
||||
}
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
var local = info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation));
|
||||
trail.Update(self.CenterPosition + body.LocalToWorld(local));
|
||||
}
|
||||
|
||||
public IEnumerable<IRenderable> Render(Actor self, WorldRenderer wr)
|
||||
{
|
||||
yield return trail;
|
||||
}
|
||||
}
|
||||
}
|
||||
45
OpenRA.Mods.Common/Effects/Corpse.cs
Normal file
45
OpenRA.Mods.Common/Effects/Corpse.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* 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. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Mods.Common.Effects
|
||||
{
|
||||
public class Corpse : IEffect
|
||||
{
|
||||
readonly World world;
|
||||
readonly WPos pos;
|
||||
readonly CPos cell;
|
||||
readonly string paletteName;
|
||||
readonly Animation anim;
|
||||
|
||||
public Corpse(World world, WPos pos, string image, string sequence, string paletteName)
|
||||
{
|
||||
this.world = world;
|
||||
this.pos = pos;
|
||||
this.cell = world.Map.CellContaining(pos);
|
||||
this.paletteName = paletteName;
|
||||
anim = new Animation(world, image);
|
||||
anim.PlayThen(sequence, () => world.AddFrameEndTask(w => w.Remove(this)));
|
||||
}
|
||||
|
||||
public void Tick(World world) { anim.Tick(); }
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
{
|
||||
if (world.FogObscures(cell))
|
||||
return SpriteRenderable.None;
|
||||
|
||||
return anim.Render(pos, wr.Palette(paletteName));
|
||||
}
|
||||
}
|
||||
}
|
||||
45
OpenRA.Mods.Common/Effects/CrateEffect.cs
Normal file
45
OpenRA.Mods.Common/Effects/CrateEffect.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* 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. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Mods.Common.Effects
|
||||
{
|
||||
public class CrateEffect : IEffect
|
||||
{
|
||||
readonly string palette;
|
||||
readonly Actor a;
|
||||
readonly Animation anim;
|
||||
|
||||
public CrateEffect(Actor a, string seq, string palette)
|
||||
{
|
||||
this.a = a;
|
||||
this.palette = palette;
|
||||
|
||||
anim = new Animation(a.World, "crate-effects");
|
||||
anim.PlayThen(seq, () => a.World.AddFrameEndTask(w => w.Remove(this)));
|
||||
}
|
||||
|
||||
public void Tick(World world)
|
||||
{
|
||||
anim.Tick();
|
||||
}
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
{
|
||||
if (!a.IsInWorld || a.World.FogObscures(a.Location))
|
||||
return SpriteRenderable.None;
|
||||
|
||||
return anim.Render(a.CenterPosition, wr.Palette(palette));
|
||||
}
|
||||
}
|
||||
}
|
||||
84
OpenRA.Mods.Common/Effects/GravityBomb.cs
Normal file
84
OpenRA.Mods.Common/Effects/GravityBomb.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* 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. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Effects
|
||||
{
|
||||
public class GravityBombInfo : IProjectileInfo
|
||||
{
|
||||
public readonly string Image = null;
|
||||
public readonly bool Shadow = false;
|
||||
public readonly WRange Velocity = WRange.Zero;
|
||||
public readonly WRange Acceleration = new WRange(15);
|
||||
|
||||
public IEffect Create(ProjectileArgs args) { return new GravityBomb(this, args); }
|
||||
}
|
||||
|
||||
public class GravityBomb : IEffect
|
||||
{
|
||||
GravityBombInfo info;
|
||||
Animation anim;
|
||||
ProjectileArgs args;
|
||||
WVec velocity;
|
||||
WPos pos;
|
||||
|
||||
public GravityBomb(GravityBombInfo info, ProjectileArgs args)
|
||||
{
|
||||
this.info = info;
|
||||
this.args = args;
|
||||
pos = args.Source;
|
||||
velocity = new WVec(WRange.Zero, WRange.Zero, -info.Velocity);
|
||||
|
||||
anim = new Animation(args.SourceActor.World, info.Image);
|
||||
if (anim.HasSequence("open"))
|
||||
anim.PlayThen("open", () => anim.PlayRepeating("idle"));
|
||||
else
|
||||
anim.PlayRepeating("idle");
|
||||
}
|
||||
|
||||
public void Tick(World world)
|
||||
{
|
||||
velocity -= new WVec(WRange.Zero, WRange.Zero, info.Acceleration);
|
||||
pos += velocity;
|
||||
|
||||
if (pos.Z <= args.PassiveTarget.Z)
|
||||
{
|
||||
pos += new WVec(0, 0, args.PassiveTarget.Z - pos.Z);
|
||||
world.AddFrameEndTask(w => w.Remove(this));
|
||||
args.Weapon.Impact(Target.FromPos(pos), args.SourceActor, args.DamageModifiers);
|
||||
}
|
||||
|
||||
anim.Tick();
|
||||
}
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
{
|
||||
var cell = wr.world.Map.CellContaining(pos);
|
||||
if (!args.SourceActor.World.FogObscures(cell))
|
||||
{
|
||||
if (info.Shadow)
|
||||
{
|
||||
var shadowPos = pos - new WVec(0, 0, pos.Z);
|
||||
foreach (var r in anim.Render(shadowPos, wr.Palette("shadow")))
|
||||
yield return r;
|
||||
}
|
||||
|
||||
var palette = wr.Palette(args.Weapon.Palette);
|
||||
foreach (var r in anim.Render(pos, palette))
|
||||
yield return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
102
OpenRA.Mods.Common/Effects/LaserZap.cs
Normal file
102
OpenRA.Mods.Common/Effects/LaserZap.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* 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. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
|
||||
namespace OpenRA.Mods.Common.Effects
|
||||
{
|
||||
[Desc("Not a sprite, but an engine effect.")]
|
||||
class LaserZapInfo : IProjectileInfo
|
||||
{
|
||||
public readonly int BeamWidth = 2;
|
||||
public readonly int BeamDuration = 10;
|
||||
public readonly bool UsePlayerColor = false;
|
||||
[Desc("Laser color in (A,)R,G,B.")]
|
||||
public readonly Color Color = Color.Red;
|
||||
[Desc("Impact animation. Requires a regular animation with idle: sequence instead of explosion special case.")]
|
||||
public readonly string HitAnim = null;
|
||||
public readonly string HitAnimPalette = "effect";
|
||||
|
||||
public IEffect Create(ProjectileArgs args)
|
||||
{
|
||||
var c = UsePlayerColor ? args.SourceActor.Owner.Color.RGB : Color;
|
||||
return new LaserZap(args, this, c);
|
||||
}
|
||||
}
|
||||
|
||||
class LaserZap : IEffect
|
||||
{
|
||||
ProjectileArgs args;
|
||||
LaserZapInfo info;
|
||||
int ticks = 0;
|
||||
Color color;
|
||||
bool doneDamage;
|
||||
bool animationComplete;
|
||||
Animation hitanim;
|
||||
WPos target;
|
||||
|
||||
public LaserZap(ProjectileArgs args, LaserZapInfo info, Color color)
|
||||
{
|
||||
this.args = args;
|
||||
this.info = info;
|
||||
this.color = color;
|
||||
this.target = args.PassiveTarget;
|
||||
|
||||
if (info.HitAnim != null)
|
||||
this.hitanim = new Animation(args.SourceActor.World, info.HitAnim);
|
||||
}
|
||||
|
||||
public void Tick(World world)
|
||||
{
|
||||
// Beam tracks target
|
||||
if (args.GuidedTarget.IsValidFor(args.SourceActor))
|
||||
target = args.GuidedTarget.CenterPosition;
|
||||
|
||||
if (!doneDamage)
|
||||
{
|
||||
if (hitanim != null)
|
||||
hitanim.PlayThen("idle", () => animationComplete = true);
|
||||
|
||||
args.Weapon.Impact(Target.FromPos(target), args.SourceActor, args.DamageModifiers);
|
||||
doneDamage = true;
|
||||
}
|
||||
|
||||
if (hitanim != null)
|
||||
hitanim.Tick();
|
||||
|
||||
if (++ticks >= info.BeamDuration && animationComplete)
|
||||
world.AddFrameEndTask(w => w.Remove(this));
|
||||
}
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
{
|
||||
if (wr.world.FogObscures(wr.world.Map.CellContaining(target)) &&
|
||||
wr.world.FogObscures(wr.world.Map.CellContaining(args.Source)))
|
||||
yield break;
|
||||
|
||||
if (ticks < info.BeamDuration)
|
||||
{
|
||||
var rc = Color.FromArgb((info.BeamDuration - ticks) * 255 / info.BeamDuration, color);
|
||||
yield return new BeamRenderable(args.Source, 0, target - args.Source, info.BeamWidth, rc);
|
||||
}
|
||||
|
||||
if (hitanim != null)
|
||||
foreach (var r in hitanim.Render(target, wr.Palette(info.HitAnimPalette)))
|
||||
yield return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
220
OpenRA.Mods.Common/Effects/Missile.cs
Normal file
220
OpenRA.Mods.Common/Effects/Missile.cs
Normal file
@@ -0,0 +1,220 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* 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. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common.Graphics;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.Common.Effects
|
||||
{
|
||||
class MissileInfo : IProjectileInfo
|
||||
{
|
||||
[Desc("Projectile speed in WRange / tick")]
|
||||
public readonly WRange Speed = new WRange(8);
|
||||
[Desc("Maximum vertical pitch when changing altitude.")]
|
||||
public readonly WAngle MaximumPitch = WAngle.FromDegrees(30);
|
||||
[Desc("How many ticks before this missile is armed and can explode.")]
|
||||
public readonly int Arm = 0;
|
||||
[Desc("Check for whether an actor with BlocksBullets: trait blocks fire")]
|
||||
public readonly bool High = false;
|
||||
public readonly bool Shadow = false;
|
||||
public readonly string Trail = null;
|
||||
[Desc("Maximum offset at the maximum range")]
|
||||
public readonly WRange Inaccuracy = WRange.Zero;
|
||||
[Desc("Probability of locking onto and following target.")]
|
||||
public readonly int LockOnProbability = 100;
|
||||
public readonly string Image = null;
|
||||
[Desc("Rate of Turning")]
|
||||
public readonly int ROT = 5;
|
||||
[Desc("Explode when following the target longer than this.")]
|
||||
public readonly int RangeLimit = 0;
|
||||
[Desc("If fired at aircraft, increase speed by 50%.")]
|
||||
public readonly bool TurboBoost = false;
|
||||
public readonly int TrailInterval = 2;
|
||||
public readonly int ContrailLength = 0;
|
||||
public readonly Color ContrailColor = Color.White;
|
||||
public readonly bool ContrailUsePlayerColor = false;
|
||||
public readonly int ContrailDelay = 1;
|
||||
public readonly bool Jammable = true;
|
||||
[Desc("Explodes when leaving the following terrain type, e.g., Water for torpedoes.")]
|
||||
public readonly string BoundToTerrainType = "";
|
||||
[Desc("Explodes when inside this proximity radius to target.",
|
||||
"Note: If this value is lower than the missile speed, this check might",
|
||||
"not trigger fast enough, causing the missile to fly past the target.")]
|
||||
public readonly WRange CloseEnough = new WRange(298);
|
||||
|
||||
public IEffect Create(ProjectileArgs args) { return new Missile(this, args); }
|
||||
}
|
||||
|
||||
class Missile : IEffect, ISync
|
||||
{
|
||||
readonly MissileInfo info;
|
||||
readonly ProjectileArgs args;
|
||||
readonly Animation anim;
|
||||
|
||||
int ticksToNextSmoke;
|
||||
ContrailRenderable trail;
|
||||
|
||||
[Sync] WPos pos;
|
||||
[Sync] int facing;
|
||||
|
||||
[Sync] WPos targetPosition;
|
||||
[Sync] WVec offset;
|
||||
[Sync] int ticks;
|
||||
|
||||
[Sync] bool lockOn = false;
|
||||
|
||||
[Sync] public Actor SourceActor { get { return args.SourceActor; } }
|
||||
[Sync] public Target GuidedTarget { get { return args.GuidedTarget; } }
|
||||
|
||||
public Missile(MissileInfo info, ProjectileArgs args)
|
||||
{
|
||||
this.info = info;
|
||||
this.args = args;
|
||||
|
||||
pos = args.Source;
|
||||
facing = args.Facing;
|
||||
|
||||
targetPosition = args.PassiveTarget;
|
||||
|
||||
var world = args.SourceActor.World;
|
||||
|
||||
if (world.SharedRandom.Next(100) <= info.LockOnProbability)
|
||||
lockOn = true;
|
||||
|
||||
if (info.Inaccuracy.Range > 0)
|
||||
{
|
||||
var inaccuracy = OpenRA.Traits.Util.ApplyPercentageModifiers(info.Inaccuracy.Range, args.InaccuracyModifiers);
|
||||
offset = WVec.FromPDF(world.SharedRandom, 2) * inaccuracy / 1024;
|
||||
}
|
||||
|
||||
if (info.Image != null)
|
||||
{
|
||||
anim = new Animation(world, info.Image, () => facing);
|
||||
anim.PlayRepeating("idle");
|
||||
}
|
||||
|
||||
if (info.ContrailLength > 0)
|
||||
{
|
||||
var color = info.ContrailUsePlayerColor ? ContrailRenderable.ChooseColor(args.SourceActor) : info.ContrailColor;
|
||||
trail = new ContrailRenderable(world, color, info.ContrailLength, info.ContrailDelay, 0);
|
||||
}
|
||||
}
|
||||
|
||||
bool JammedBy(TraitPair<JamsMissiles> tp)
|
||||
{
|
||||
if ((tp.Actor.CenterPosition - pos).HorizontalLengthSquared > tp.Trait.Range * tp.Trait.Range)
|
||||
return false;
|
||||
|
||||
if (tp.Actor.Owner.Stances[args.SourceActor.Owner] == Stance.Ally && !tp.Trait.AlliedMissiles)
|
||||
return false;
|
||||
|
||||
return tp.Actor.World.SharedRandom.Next(100 / tp.Trait.Chance) == 0;
|
||||
}
|
||||
|
||||
public void Tick(World world)
|
||||
{
|
||||
ticks++;
|
||||
anim.Tick();
|
||||
|
||||
// Missile tracks target
|
||||
if (args.GuidedTarget.IsValidFor(args.SourceActor) && lockOn)
|
||||
targetPosition = args.GuidedTarget.CenterPosition;
|
||||
|
||||
var dist = targetPosition + offset - pos;
|
||||
var desiredFacing = OpenRA.Traits.Util.GetFacing(dist, facing);
|
||||
var desiredAltitude = targetPosition.Z;
|
||||
var jammed = info.Jammable && world.ActorsWithTrait<JamsMissiles>().Any(JammedBy);
|
||||
|
||||
if (jammed)
|
||||
{
|
||||
desiredFacing = facing + world.SharedRandom.Next(-20, 21);
|
||||
desiredAltitude = world.SharedRandom.Next(-43, 86);
|
||||
}
|
||||
else if (!args.GuidedTarget.IsValidFor(args.SourceActor))
|
||||
desiredFacing = facing;
|
||||
|
||||
facing = OpenRA.Traits.Util.TickFacing(facing, desiredFacing, info.ROT);
|
||||
var move = new WVec(0, -1024, 0).Rotate(WRot.FromFacing(facing)) * info.Speed.Range / 1024;
|
||||
if (targetPosition.Z > 0 && info.TurboBoost)
|
||||
move = (move * 3) / 2;
|
||||
|
||||
if (pos.Z != desiredAltitude)
|
||||
{
|
||||
var delta = move.HorizontalLength * info.MaximumPitch.Tan() / 1024;
|
||||
var dz = (targetPosition.Z - pos.Z).Clamp(-delta, delta);
|
||||
move += new WVec(0, 0, dz);
|
||||
}
|
||||
|
||||
pos += move;
|
||||
|
||||
if (info.Trail != null && --ticksToNextSmoke < 0)
|
||||
{
|
||||
world.AddFrameEndTask(w => w.Add(new Smoke(w, pos - 3 * move / 2, info.Trail)));
|
||||
ticksToNextSmoke = info.TrailInterval;
|
||||
}
|
||||
|
||||
if (info.ContrailLength > 0)
|
||||
trail.Update(pos);
|
||||
|
||||
var cell = world.Map.CellContaining(pos);
|
||||
|
||||
var shouldExplode = (pos.Z < 0) // Hit the ground
|
||||
|| (dist.LengthSquared < info.CloseEnough.Range * info.CloseEnough.Range) // Within range
|
||||
|| (info.RangeLimit != 0 && ticks > info.RangeLimit) // Ran out of fuel
|
||||
|| (!info.High && world.ActorMap.GetUnitsAt(cell).Any(a => a.HasTrait<IBlocksBullets>())) // Hit a wall
|
||||
|| !world.Map.Contains(cell) // This also avoids an IndexOutOfRangeException in GetTerrainInfo below.
|
||||
|| (!string.IsNullOrEmpty(info.BoundToTerrainType) && world.Map.GetTerrainInfo(cell).Type != info.BoundToTerrainType); // Hit incompatible terrain
|
||||
|
||||
if (shouldExplode)
|
||||
Explode(world);
|
||||
}
|
||||
|
||||
void Explode(World world)
|
||||
{
|
||||
if (info.ContrailLength > 0)
|
||||
world.AddFrameEndTask(w => w.Add(new ContrailFader(pos, trail)));
|
||||
|
||||
world.AddFrameEndTask(w => w.Remove(this));
|
||||
|
||||
// Don't blow up in our launcher's face!
|
||||
if (ticks <= info.Arm)
|
||||
return;
|
||||
|
||||
args.Weapon.Impact(Target.FromPos(pos), args.SourceActor, args.DamageModifiers);
|
||||
}
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
{
|
||||
if (info.ContrailLength > 0)
|
||||
yield return trail;
|
||||
|
||||
if (!args.SourceActor.World.FogObscures(wr.world.Map.CellContaining(pos)))
|
||||
{
|
||||
if (info.Shadow)
|
||||
{
|
||||
var shadowPos = new WPos(pos.X, pos.Y, 0);
|
||||
foreach (var r in anim.Render(shadowPos, wr.Palette("shadow")))
|
||||
yield return r;
|
||||
}
|
||||
|
||||
var palette = wr.Palette(args.Weapon.Palette);
|
||||
foreach (var r in anim.Render(pos, palette))
|
||||
yield return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
68
OpenRA.Mods.Common/Effects/RallyPoint.cs
Normal file
68
OpenRA.Mods.Common/Effects/RallyPoint.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* 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. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Mods.Common.Effects
|
||||
{
|
||||
class RallyPoint : IEffect
|
||||
{
|
||||
readonly Actor building;
|
||||
readonly Common.RallyPoint rp;
|
||||
readonly string palettePrefix;
|
||||
readonly Animation flag;
|
||||
readonly Animation circles;
|
||||
|
||||
public RallyPoint(Actor building, string palettePrefix)
|
||||
{
|
||||
this.building = building;
|
||||
this.palettePrefix = palettePrefix;
|
||||
|
||||
rp = building.Trait<Common.RallyPoint>();
|
||||
|
||||
flag = new Animation(building.World, "rallypoint");
|
||||
circles = new Animation(building.World, "rallypoint");
|
||||
|
||||
flag.PlayRepeating("flag");
|
||||
circles.Play("circles");
|
||||
}
|
||||
|
||||
CPos cachedLocation;
|
||||
public void Tick(World world)
|
||||
{
|
||||
flag.Tick();
|
||||
circles.Tick();
|
||||
if (cachedLocation != rp.Location)
|
||||
{
|
||||
cachedLocation = rp.Location;
|
||||
circles.Play("circles");
|
||||
}
|
||||
|
||||
if (!building.IsInWorld || building.IsDead())
|
||||
world.AddFrameEndTask(w => w.Remove(this));
|
||||
}
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
{
|
||||
if (building.Owner != building.World.LocalPlayer)
|
||||
return SpriteRenderable.None;
|
||||
|
||||
if (!building.IsInWorld || !building.World.Selection.Actors.Contains(building))
|
||||
return SpriteRenderable.None;
|
||||
|
||||
var pos = wr.world.Map.CenterOfCell(cachedLocation);
|
||||
var palette = wr.Palette(palettePrefix+building.Owner.InternalName);
|
||||
return circles.Render(pos, palette).Concat(flag.Render(pos, palette));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user