Mods.Common Effects

Moved over more effects to Mods.Common
This commit is contained in:
steelphase
2014-10-04 16:01:20 -04:00
parent 2f4a267ba7
commit 3c60794e2e
24 changed files with 51 additions and 50 deletions

View 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;
}
}
}
}

View 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);
}
}
}

View 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;
}
}
}

View 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));
}
}
}

View 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));
}
}
}

View 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;
}
}
}
}

View 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;
}
}
}

View 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;
}
}
}
}

View 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));
}
}
}

View File

@@ -42,9 +42,18 @@
</ItemGroup>
<ItemGroup>
<Compile Include="CommonTraitsInterfaces.cs" />
<Compile Include="Effects\Beacon.cs" />
<Compile Include="Effects\Bullet.cs" />
<Compile Include="Effects\Contrail.cs" />
<Compile Include="Effects\ContrailFader.cs" />
<Compile Include="Effects\Corpse.cs" />
<Compile Include="Effects\CrateEffect.cs" />
<Compile Include="Effects\Explosion.cs" />
<Compile Include="Effects\FloatingText.cs" />
<Compile Include="Effects\GravityBomb.cs" />
<Compile Include="Effects\LaserZap.cs" />
<Compile Include="Effects\Missile.cs" />
<Compile Include="Effects\RallyPoint.cs" />
<Compile Include="Effects\Smoke.cs" />
<Compile Include="Console\ChatCommands.cs" />
<Compile Include="Console\DevCommands.cs" />
@@ -60,9 +69,11 @@
<Compile Include="Graphics\VoxelRenderable.cs" />
<Compile Include="ModChooserLoadScreen.cs" />
<Compile Include="PaletteFromFile.cs" />
<Compile Include="RallyPoint.cs" />
<Compile Include="ServerTraits\ColorValidator.cs" />
<Compile Include="ServerTraits\MasterServerPinger.cs" />
<Compile Include="ServerTraits\PlayerPinger.cs" />
<Compile Include="Traits\JamsMissiles.cs" />
<Compile Include="Traits\ProvidesRadar.cs" />
<Compile Include="UtilityCommands\ConvertPngToShpCommand.cs" />
<Compile Include="UtilityCommands\ConvertSpriteToPngCommand.cs" />

View File

@@ -0,0 +1,77 @@
#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.Traits;
namespace OpenRA.Mods.Common
{
[Desc("Used to waypoint units after production or repair is finished.")]
public class RallyPointInfo : ITraitInfo
{
public readonly CVec RallyPoint = new CVec(1, 3);
public readonly string IndicatorPalettePrefix = "player";
public object Create(ActorInitializer init) { return new RallyPoint(init.self, this); }
}
public class RallyPoint : IIssueOrder, IResolveOrder, ISync
{
[Sync] public CPos Location;
public RallyPoint(Actor self, RallyPointInfo info)
{
Location = self.Location + info.RallyPoint;
self.World.AddFrameEndTask(w => w.Add(new Effects.RallyPoint(self, info.IndicatorPalettePrefix)));
}
public IEnumerable<IOrderTargeter> Orders
{
get { yield return new RallyPointOrderTargeter(); }
}
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
{
if (order.OrderID == "SetRallyPoint")
return new Order(order.OrderID, self, false) { TargetLocation = self.World.Map.CellContaining(target.CenterPosition), SuppressVisualFeedback = true };
return null;
}
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "SetRallyPoint")
Location = order.TargetLocation;
}
class RallyPointOrderTargeter : IOrderTargeter
{
public string OrderID { get { return "SetRallyPoint"; } }
public int OrderPriority { get { return 0; } }
public bool CanTarget(Actor self, Target target, List<Actor> othersAtTarget, TargetModifiers modifiers, ref string cursor)
{
if (target.Type != TargetType.Terrain)
return false;
var location = self.World.Map.CellContaining(target.CenterPosition);
if (self.World.Map.Contains(location))
{
cursor = "ability";
return true;
}
return false;
}
public bool IsQueued { get { return false; } } // unused
}
}
}

View File

@@ -0,0 +1,35 @@
#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 OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
public class JamsMissilesInfo : ITraitInfo
{
public readonly int Range = 0;
public readonly bool AlliedMissiles = true;
public readonly int Chance = 100;
public object Create(ActorInitializer init) { return new JamsMissiles(this); }
}
class JamsMissiles
{
readonly JamsMissilesInfo info;
// Convert cells to world units
public int Range { get { return 1024 * info.Range; } }
public bool AlliedMissiles { get { return info.AlliedMissiles; } }
public int Chance { get { return info.Chance; } }
public JamsMissiles(JamsMissilesInfo info) { this.info = info; }
}
}