Moves some misc traits/activities to Mods.Common, moves some RA traits into the Traits folder

This commit is contained in:
reaperrr
2015-01-11 12:08:47 +01:00
parent be9d37f30e
commit e8fbfc366a
14 changed files with 23 additions and 29 deletions

View File

@@ -0,0 +1,24 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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 OpenRA.Traits;
namespace OpenRA.Mods.RA.Traits
{
[Desc("Actors with the \"ClonesProducedUnits\" trait will produce a free duplicate of me.")]
public class CloneableInfo : TraitInfo<Cloneable>
{
[Desc("This unit's cloneable type is:")]
public readonly string[] Types = { };
}
public class Cloneable { }
}

View File

@@ -0,0 +1,138 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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.Mods.Common.Orders;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Traits
{
[Desc("Overrides the default ToolTip when this actor is disguised (aids in deceiving enemy players).")]
class DisguiseToolTipInfo : TooltipInfo, Requires<DisguiseInfo>
{
public override object Create(ActorInitializer init) { return new DisguiseToolTip(init.Self, this); }
}
class DisguiseToolTip : IToolTip
{
Actor self;
TooltipInfo info;
Disguise disguise;
public DisguiseToolTip(Actor self, TooltipInfo info)
{
this.self = self;
this.info = info;
disguise = self.Trait<Disguise>();
}
public ITooltipInfo TooltipInfo
{
get
{
return disguise.Disguised ? disguise.AsTooltipInfo : info;
}
}
public Player Owner
{
get
{
if (disguise.Disguised)
{
if (self.Owner == self.World.LocalPlayer)
return self.Owner;
return disguise.AsPlayer;
}
return self.Owner;
}
}
}
[Desc("Provides access to the disguise command, which makes the actor appear to be another player's actor.")]
class DisguiseInfo : TraitInfo<Disguise> { }
class Disguise : IEffectiveOwner, IIssueOrder, IResolveOrder, IOrderVoice, IRadarColorModifier, INotifyAttack
{
public Player AsPlayer { get; private set; }
public string AsSprite { get; private set; }
public ITooltipInfo AsTooltipInfo { get; private set; }
public bool Disguised { get { return AsPlayer != null; } }
public Player Owner { get { return AsPlayer; } }
public IEnumerable<IOrderTargeter> Orders
{
get
{
yield return new TargetTypeOrderTargeter(new[] { "Disguise" }, "Disguise", 7, "ability", true, true) { ForceAttack = false };
}
}
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
{
if (order.OrderID == "Disguise")
return new Order(order.OrderID, self, queued) { TargetActor = target.Actor };
return null;
}
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "Disguise")
{
var target = order.TargetActor != self && order.TargetActor.IsInWorld ? order.TargetActor : null;
DisguiseAs(self, target);
}
}
public string VoicePhraseForOrder(Actor self, Order order)
{
return order.OrderString == "Disguise" ? "Attack" : null;
}
public Color RadarColorOverride(Actor self)
{
if (!Disguised || self.Owner.IsAlliedWith(self.World.RenderPlayer))
return self.Owner.Color.RGB;
return AsPlayer.Color.RGB;
}
void DisguiseAs(Actor self, Actor target)
{
var oldEffectiveOwner = AsPlayer;
if (target != null)
{
var tooltip = target.TraitsImplementing<IToolTip>().FirstOrDefault();
AsTooltipInfo = tooltip.TooltipInfo;
AsPlayer = tooltip.Owner;
AsSprite = target.Trait<RenderSprites>().GetImage(target);
}
else
{
AsTooltipInfo = null;
AsPlayer = null;
AsSprite = null;
}
foreach (var t in self.TraitsImplementing<INotifyEffectiveOwnerChanged>())
t.OnEffectiveOwnerChanged(self, oldEffectiveOwner, AsPlayer);
}
public void Attacking(Actor self, Target target, Armament a, Barrel barrel) { DisguiseAs(self, null); }
}
}

View File

@@ -0,0 +1,76 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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.Mods.Common.Traits;
using OpenRA.Mods.RA.Effects;
using OpenRA.Primitives;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Traits
{
[Desc("Eject a ground soldier or a paratrooper while in the air.")]
public class EjectOnDeathInfo : TraitInfo<EjectOnDeath>
{
[ActorReference]
public readonly string PilotActor = "E1";
public readonly int SuccessRate = 50;
public readonly string ChuteSound = "chute1.aud";
public readonly bool EjectInAir = false;
public readonly bool EjectOnGround = false;
[Desc("Risks stuck units when they don't have the Paratrooper trait.")]
public readonly bool AllowUnsuitableCell = false;
}
public class EjectOnDeath : INotifyKilled
{
public void Killed(Actor self, AttackInfo e)
{
if (self.Owner.WinState == WinState.Lost || !self.World.Map.Contains(self.Location))
return;
var r = self.World.SharedRandom.Next(1, 100);
var info = self.Info.Traits.Get<EjectOnDeathInfo>();
if (r <= 100 - info.SuccessRate)
return;
var cp = self.CenterPosition;
if ((cp.Z > 0 && !info.EjectInAir) || (cp.Z == 0 && !info.EjectOnGround))
return;
var pilot = self.World.CreateActor(false, info.PilotActor.ToLowerInvariant(),
new TypeDictionary { new OwnerInit(self.Owner), new LocationInit(self.Location) });
if (info.AllowUnsuitableCell || IsSuitableCell(self, pilot))
{
if (cp.Z > 0)
{
self.World.AddFrameEndTask(w => w.Add(new Parachute(pilot, cp)));
Sound.Play(info.ChuteSound, cp);
}
else
{
self.World.AddFrameEndTask(w => w.Add(pilot));
var pilotMobile = pilot.TraitOrDefault<Mobile>();
if (pilotMobile != null)
pilotMobile.Nudge(pilot, pilot, true);
}
}
else
pilot.Destroy();
}
static bool IsSuitableCell(Actor self, Actor actorToDrop)
{
return actorToDrop.Trait<IPositionable>().CanEnterCell(self.Location, self, true);
}
}
}

View File

@@ -0,0 +1,101 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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.Mods.Common.Traits;
using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Effects;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Traits
{
[Desc("This unit can spawn and eject other actors while flying.")]
public class ParaDropInfo : ITraitInfo, Requires<CargoInfo>
{
[Desc("Distance around the drop-point to unload troops.")]
public readonly WRange DropRange = WRange.FromCells(4);
[Desc("Sound to play when dropping.")]
public readonly string ChuteSound = "chute1.aud";
public object Create(ActorInitializer init) { return new ParaDrop(init.Self, this); }
}
public class ParaDrop : ITick, INotifyRemovedFromWorld
{
readonly ParaDropInfo info;
readonly Actor self;
readonly Cargo cargo;
readonly HashSet<CPos> droppedAt = new HashSet<CPos>();
public event Action<Actor> OnRemovedFromWorld = self => { };
public event Action<Actor> OnEnteredDropRange = self => { };
public event Action<Actor> OnExitedDropRange = self => { };
[Sync] bool inDropRange;
[Sync] Target target;
bool checkForSuitableCell;
public ParaDrop(Actor self, ParaDropInfo info)
{
this.info = info;
this.self = self;
cargo = self.Trait<Cargo>();
}
public void SetLZ(CPos lz, bool checkLandingCell)
{
droppedAt.Clear();
target = Target.FromCell(self.World, lz);
checkForSuitableCell = checkLandingCell;
}
public void Tick(Actor self)
{
var wasInDropRange = inDropRange;
inDropRange = target.IsInRange(self.CenterPosition, info.DropRange);
if (inDropRange && !wasInDropRange)
OnEnteredDropRange(self);
if (!inDropRange && wasInDropRange)
OnExitedDropRange(self);
// Are we able to drop the next trooper?
if (!inDropRange || cargo.IsEmpty(self))
return;
if (droppedAt.Contains(self.Location) || (checkForSuitableCell && !IsSuitableCell(cargo.Peek(self), self.Location)))
return;
if (!self.World.Map.Contains(self.Location))
return;
// unload a dude here
droppedAt.Add(self.Location);
var a = cargo.Unload(self);
self.World.AddFrameEndTask(w => w.Add(new Parachute(a, self.CenterPosition)));
Sound.Play(info.ChuteSound, self.CenterPosition);
}
static bool IsSuitableCell(Actor actorToDrop, CPos p)
{
return actorToDrop.Trait<IPositionable>().CanEnterCell(p);
}
public void RemovedFromWorld(Actor self)
{
OnRemovedFromWorld(self);
}
}
}

View File

@@ -0,0 +1,88 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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.Mods.Common.Effects;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Traits
{
[Desc("Can be paradropped by a ParaDrop actor.")]
class ParachutableInfo : ITraitInfo
{
[Desc("If we land on invalid terrain for my actor type should we be killed?")]
public readonly bool KilledOnImpassableTerrain = true;
public readonly string GroundImpactSound = null;
public readonly string GroundCorpseSequence = "corpse";
public readonly string GroundCorpsePalette = "effect";
public readonly string WaterImpactSound = null;
public readonly string WaterCorpseSequence = "small_splash";
public readonly string WaterCorpsePalette = "effect";
[Desc("Requires the sub-sequences \"open\" and \"idle\".")]
public readonly string ParachuteSequence = null;
[Desc("Optional, otherwise defaults to the palette the actor is using.")]
public readonly string ParachutePalette = null;
[Desc("Used to clone the actor with this palette and render it with a visual offset below.")]
public readonly string ParachuteShadowPalette = "shadow";
public readonly WVec ParachuteOffset = WVec.Zero;
public readonly int FallRate = 13;
[Desc("Alternative to ParachuteShadowPalette which disables it and allows to set a custom sprite sequence instead.")]
public readonly string ShadowSequence = null;
[Desc("Optional, otherwise defaults to the palette the actor is using.")]
public readonly string ShadowPalette = null;
public object Create(ActorInitializer init) { return new Parachutable(init, this); }
}
class Parachutable : INotifyParachuteLanded
{
readonly Actor self;
readonly ParachutableInfo info;
readonly IPositionable positionable;
public Parachutable(ActorInitializer init, ParachutableInfo info)
{
this.self = init.Self;
this.info = info;
positionable = self.TraitOrDefault<IPositionable>();
}
public void OnLanded()
{
if (!info.KilledOnImpassableTerrain)
return;
if (positionable.CanEnterCell(self.Location, self))
return;
var terrain = self.World.Map.GetTerrainInfo(self.Location);
var sound = terrain.IsWater ? info.WaterImpactSound : info.GroundImpactSound;
Sound.Play(sound, self.CenterPosition);
var sequence = terrain.IsWater ? info.WaterCorpseSequence : info.GroundCorpseSequence;
var palette = terrain.IsWater ? info.WaterCorpsePalette : info.GroundCorpsePalette;
if (sequence != null && palette != null)
self.World.AddFrameEndTask(w => w.Add(new Explosion(w, self.OccupiesSpace.CenterPosition, sequence, palette)));
self.Kill(self);
}
}
}

View File

@@ -0,0 +1,55 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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.Linq;
using OpenRA.Mods.Common.Activities;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Traits
{
public class TransformOnPassengerInfo : ITraitInfo
{
[ActorReference] public readonly string[] PassengerTypes = { };
[ActorReference] public readonly string OnEnter = null;
[ActorReference] public readonly string OnExit = null;
public readonly bool SkipMakeAnims = false;
public readonly bool BecomeNeutral = false;
public object Create(ActorInitializer init) { return new TransformOnPassenger(this); }
}
public class TransformOnPassenger : INotifyPassengerEntered, INotifyPassengerExited
{
TransformOnPassengerInfo info;
public TransformOnPassenger(TransformOnPassengerInfo info) { this.info = info; }
void MaybeTransform(Actor self, Actor passenger, string transformTo)
{
if (info.PassengerTypes.Contains(passenger.Info.Name) && transformTo != null)
{
self.World.AddFrameEndTask(w =>
{
var facing = self.TraitOrDefault<IFacing>();
var transform = new Transform(self, transformTo) { SkipMakeAnims = info.SkipMakeAnims };
if (facing != null) transform.Facing = facing.Facing;
self.CancelActivity();
self.QueueActivity(transform);
if (info.BecomeNeutral) self.ChangeOwner(self.World.WorldActor.Owner);
});
}
}
public void PassengerEntered(Actor self, Actor passenger) { MaybeTransform(self, passenger, info.OnEnter); }
public void PassengerExited(Actor self, Actor passenger) { MaybeTransform(self, passenger, info.OnExit); }
}
}