new support power impl

This commit is contained in:
Chris Forbes
2010-01-23 21:07:27 +13:00
parent bbf94fef79
commit d7a2691db3
56 changed files with 409 additions and 489 deletions

View File

@@ -27,13 +27,13 @@ namespace OpenRa.FileFormats
public T Get<T>()
{
var l = innerInherit[ typeof( T ) ];
if( l.Count == 1 )
return (T)l[ 0 ];
else if( l.Count == 0 )
throw new InvalidOperationException( string.Format( "TypeDictionary does not contain instance of type `{0}`", typeof( T ) ) );
var l = innerInherit[typeof(T)];
if (l.Count == 1)
return (T)l[0];
else if (l.Count == 0)
throw new InvalidOperationException(string.Format("TypeDictionary does not contain instance of type `{0}`", typeof(T)));
else
throw new InvalidOperationException( string.Format( "TypeDictionary contains multiple instance of type `{0}`", typeof( T ) ) );
throw new InvalidOperationException(string.Format("TypeDictionary contains multiple instance of type `{0}`", typeof(T)));
}
public T GetOrDefault<T>()

View File

@@ -117,10 +117,10 @@ namespace OpenRa
u => u.Name,
u => SpriteSheetBuilder.LoadAllSprites(u.Traits.Get<BuildableInfo>().Icon ?? (u.Name + "icon"))[0]);
spsprites = Rules.SupportPowerInfo
spsprites = Rules.Info.Values.SelectMany( u => u.Traits.WithInterface<SupportPowerInfo>() )
.ToDictionary(
u => u.Key,
u => SpriteSheetBuilder.LoadAllSprites(u.Value.Image)[0]);
u => u.Image,
u => SpriteSheetBuilder.LoadAllSprites(u.Image)[0]);
var groups = Rules.Info.Values.Select( x => x.Category ).Distinct().Where( g => g != null ).ToList();
@@ -893,8 +893,8 @@ namespace OpenRa
void DrawSupportPowers( World world )
{
var numPowers = world.LocalPlayer.SupportPowers.Values
.Where(a => a.IsAvailable).Count();
var powers = world.LocalPlayer.PlayerActor.traits.WithInterface<SupportPower>();
var numPowers = powers.Count(p => p.IsAvailable);
if (numPowers == 0) return;
@@ -907,38 +907,38 @@ namespace OpenRa
var y = 24;
string tooltipItem = null;
SupportPower tooltipItem = null;
int2 tooltipPos = int2.Zero;
foreach (var sp in world.LocalPlayer.SupportPowers)
foreach (var sp in powers)
{
var image = spsprites[sp.Key];
if (sp.Value.IsAvailable)
var image = spsprites[sp.Info.Image];
if (sp.IsAvailable)
{
var drawPos = new float2(5, y);
shpRenderer.DrawSprite(image, drawPos, PaletteType.Chrome);
clock.PlayFetchIndex("idle",
() => (sp.Value.TotalTime - sp.Value.RemainingTime)
* NumClockFrames / sp.Value.TotalTime);
() => (sp.TotalTime - sp.RemainingTime)
* NumClockFrames / sp.TotalTime);
clock.Tick();
shpRenderer.DrawSprite(clock.Image, drawPos, PaletteType.Chrome);
var rect = new Rectangle(5, y, 64, 48);
if (sp.Value.IsDone)
if (sp.IsReady)
{
ready.Play("ready");
shpRenderer.DrawSprite(ready.Image,
drawPos + new float2((64 - ready.Image.size.X) / 2, 2),
PaletteType.Chrome);
AddButton(rect, HandleSupportPower( sp.Value ));
AddButton(rect, HandleSupportPower( sp ));
}
if (rect.Contains(lastMousePos.ToPoint()))
{
tooltipItem = sp.Key;
tooltipItem = sp;
tooltipPos = drawPos.ToInt2() + new int2(72, 0);
}
@@ -965,25 +965,23 @@ namespace OpenRa
return "{0:D2}:{1:D2}".F(minutes, seconds % 60);
}
void DrawSupportPowerTooltip(World world, string sp, int2 pos)
void DrawSupportPowerTooltip(World world, SupportPower sp, int2 pos)
{
var tooltipSprite = ChromeProvider.GetImage(renderer, chromeCollection, "tooltip-bg");
rgbaRenderer.DrawSprite(tooltipSprite, pos, PaletteType.Chrome);
rgbaRenderer.Flush();
var info = Rules.SupportPowerInfo[sp];
pos += new int2(5, 5);
renderer.DrawText2(info.Description, pos, Color.White);
renderer.DrawText2(sp.Info.Description, pos, Color.White);
var timer = "Charge Time: {0}".F(FormatTime(world.LocalPlayer.SupportPowers[sp].RemainingTime));
var timer = "Charge Time: {0}".F(FormatTime(sp.RemainingTime));
DrawRightAligned(timer, pos + new int2((int)tooltipSprite.size.X - 10, 0), Color.White);
if (info.LongDesc != null)
if (sp.Info.LongDesc != null)
{
pos += new int2(0, 25);
renderer.DrawText(info.LongDesc.Replace("\\n", "\n"), pos, Color.White);
renderer.DrawText(sp.Info.LongDesc.Replace("\\n", "\n"), pos, Color.White);
}
}
}

View File

@@ -274,7 +274,7 @@ namespace OpenRa
if( e.KeyCode == Keys.F8 && !Game.orderManager.GameStarted )
{
Game.orderManager.IssueOrder(
new Order( "ToggleReady", Game.world.LocalPlayer.PlayerActor, null, int2.Zero, "" ) { IsImmediate = true } );
new Order( "ToggleReady", Game.world.LocalPlayer.PlayerActor, "" ) { IsImmediate = true } );
}
/* temporary hack: DO NOT LEAVE IN */

View File

@@ -15,7 +15,6 @@ namespace OpenRa
public static InfoLoader<WarheadInfo> WarheadInfo;
public static InfoLoader<ProjectileInfo> ProjectileInfo;
public static InfoLoader<VoiceInfo> VoiceInfo;
public static InfoLoader<SupportPowerInfo> SupportPowerInfo;
public static GeneralInfo General;
public static AftermathInfo Aftermath;
public static TechTree TechTree;
@@ -40,8 +39,7 @@ namespace OpenRa
"Weapon",
"Warhead",
"Projectile",
"Voice",
"SupportPower");
"Voice");
WeaponInfo = new InfoLoader<WeaponInfo>(
Pair.New<string, Func<string, WeaponInfo>>("Weapon", _ => new WeaponInfo()));
@@ -51,8 +49,6 @@ namespace OpenRa
Pair.New<string, Func<string, ProjectileInfo>>("Projectile", _ => new ProjectileInfo()));
VoiceInfo = new InfoLoader<VoiceInfo>(
Pair.New<string, Func<string, VoiceInfo>>("Voice", _ => new VoiceInfo()));
SupportPowerInfo = new InfoLoader<SupportPowerInfo>(
Pair.New<string, Func<string, SupportPowerInfo>>("SupportPower", _ => new SupportPowerInfo()));
var yamlRules = m.Rules.Reverse().Select(a => MiniYaml.FromFile(a)).Aggregate(MiniYaml.Merge);

View File

@@ -1,17 +0,0 @@

namespace OpenRa.GameRules
{
public class SupportPowerInfo
{
public readonly bool Powered = true;
public readonly bool OneShot = false;
public readonly float ChargeTime = 0;
public readonly string Image;
public readonly string Description = "";
public readonly string LongDesc = "";
public readonly string[] Prerequisite = { };
public readonly int TechLevel = -1;
public readonly bool GivenAuto = true;
public readonly string Impl = null;
}
}

View File

@@ -1,7 +1,6 @@
using System;
using System.IO;
using System.Linq;
using OpenRa.SupportPowers;
namespace OpenRa
{
@@ -26,6 +25,21 @@ namespace OpenRa
this.TargetString = targetString;
}
public Order(string orderString, Actor subject)
: this(orderString, subject, null, int2.Zero, null) { }
public Order(string orderString, Actor subject, Actor targetActor)
: this(orderString, subject, targetActor, int2.Zero, null) { }
public Order(string orderString, Actor subject, int2 targetLocation)
: this(orderString, subject, null, targetLocation, null) { }
public Order(string orderString, Actor subject, string targetString)
: this(orderString, subject, null, int2.Zero, targetString) { }
public Order(string orderString, Actor subject, Actor targetActor, int2 targetLocation)
: this(orderString, subject, targetActor, targetLocation, null) { }
public Order(string orderString, Actor subject, Actor targetActor, string targetString)
: this(orderString, subject, targetActor, int2.Zero, targetString) { }
public Order(string orderString, Actor subject, int2 targetLocation, string targetString)
: this(orderString, subject, null, targetLocation, targetString) { }
public byte[] Serialize()
{
if (IsImmediate) /* chat, whatever */
@@ -99,7 +113,7 @@ namespace OpenRa
var name = r.ReadString();
var data = r.ReadString();
return new Order( name, LookupPlayer( world, playerID ).PlayerActor, null, int2.Zero, data ) { IsImmediate = true };
return new Order( name, LookupPlayer( world, playerID ).PlayerActor, data ) { IsImmediate = true };
}
default:
@@ -136,28 +150,22 @@ namespace OpenRa
// Now that Orders are resolved by individual Actors, these are weird; you unpack orders manually, but not pack them.
public static Order Chat(Player subject, string text)
{
return new Order("Chat", subject.PlayerActor, null, int2.Zero, text)
{ IsImmediate = true };
return new Order("Chat", subject.PlayerActor, text) { IsImmediate = true };
}
public static Order StartProduction(Player subject, string item)
{
return new Order("StartProduction", subject.PlayerActor, null, int2.Zero, item );
return new Order("StartProduction", subject.PlayerActor, item );
}
public static Order PauseProduction(Player subject, string item, bool pause)
{
return new Order("PauseProduction", subject.PlayerActor, null, new int2( pause ? 1 : 0, 0 ), item);
return new Order("PauseProduction", subject.PlayerActor, new int2( pause ? 1 : 0, 0 ), item);
}
public static Order CancelProduction(Player subject, string item)
{
return new Order("CancelProduction", subject.PlayerActor, null, int2.Zero, item);
}
public static Order PlayAnimation(Actor actor, string animationString)
{
return new Order("PlayAnimation", actor, null, int2.Zero, animationString);
return new Order("CancelProduction", subject.PlayerActor, item);
}
}
}

View File

@@ -93,7 +93,6 @@
<Compile Include="GameRules\ArmorType.cs" />
<Compile Include="GameRules\GeneralInfo.cs" />
<Compile Include="GameRules\ActorInfo.cs" />
<Compile Include="GameRules\SupportPowerInfo.cs" />
<Compile Include="GameRules\TechTree.cs" />
<Compile Include="GameRules\UserSettings.cs" />
<Compile Include="GameRules\VoiceInfo.cs" />
@@ -123,12 +122,6 @@
<Compile Include="Shroud.cs" />
<Compile Include="Smudge.cs" />
<Compile Include="Sound.cs" />
<Compile Include="SupportPower.cs" />
<Compile Include="SupportPowers\ChronospherePower.cs" />
<Compile Include="SupportPowers\GpsSatellite.cs" />
<Compile Include="SupportPowers\IronCurtainPower.cs" />
<Compile Include="SupportPowers\ISupportPowerImpl.cs" />
<Compile Include="SupportPowers\NullPower.cs" />
<Compile Include="Support\OpenAlInterop.cs" />
<Compile Include="Support\PerfHistory.cs" />
<Compile Include="Sync.cs" />
@@ -216,22 +209,24 @@
<Compile Include="Traits\Cargo.cs" />
<Compile Include="Traits\Chronoshiftable.cs" />
<Compile Include="Traits\ChronoshiftPaletteEffect.cs" />
<Compile Include="Traits\Chronosphere.cs" />
<Compile Include="Traits\ChronoshiftPower.cs" />
<Compile Include="Traits\Explodes.cs" />
<Compile Include="Traits\Fake.cs" />
<Compile Include="Traits\GeneratesGap.cs" />
<Compile Include="Traits\GpsLaunchSite.cs" />
<Compile Include="Traits\GpsPower.cs" />
<Compile Include="Traits\Harvester.cs" />
<Compile Include="Traits\Helicopter.cs" />
<Compile Include="Traits\InvisibleToOthers.cs" />
<Compile Include="Traits\ConstructionYard.cs" />
<Compile Include="Traits\IronCurtain.cs" />
<Compile Include="Traits\IronCurtainable.cs" />
<Compile Include="Traits\IronCurtainPower.cs" />
<Compile Include="Traits\JamsRadar.cs" />
<Compile Include="Traits\LightPaletteRotator.cs" />
<Compile Include="Traits\LimitedAmmo.cs" />
<Compile Include="Traits\Passenger.cs" />
<Compile Include="Traits\PlaceBuilding.cs" />
<Compile Include="Traits\SupportPower.cs" />
<Compile Include="Traits\ProvidesRadar.cs" />
<Compile Include="Traits\Repairable.cs" />
<Compile Include="Traits\Reservable.cs" />

View File

@@ -3,19 +3,16 @@ using System.Collections.Generic;
using System.Linq;
using System.Drawing;
using OpenRa.Traits;
using OpenRa.SupportPowers;
namespace OpenRa.Orders
{
class ChronoshiftDestinationOrderGenerator : IOrderGenerator
{
public readonly Actor self;
SupportPower power;
public ChronoshiftDestinationOrderGenerator(Actor self, SupportPower power)
public ChronoshiftDestinationOrderGenerator(Actor self)
{
this.self = self;
this.power = power;
}
public IEnumerable<Order> Order(World world, int2 xy, MouseInput mi)
@@ -25,8 +22,9 @@ namespace OpenRa.Orders
Game.controller.CancelInputMode();
yield break;
}
yield return new Order("Chronoshift", self, null, xy,
power != null ? power.Name : null);
yield return new Order("Chronoshift", self, xy);
yield return new Order("ChronosphereFinish", self.Owner.PlayerActor);
}
public void Tick( World world ) {}

View File

@@ -3,17 +3,12 @@ using System.Collections.Generic;
using System.Linq;
using OpenRa.GameRules;
using OpenRa.Traits;
using OpenRa.SupportPowers;
namespace OpenRa.Orders
{
class ChronosphereSelectOrderGenerator : IOrderGenerator
{
SupportPower power;
public ChronosphereSelectOrderGenerator(SupportPower power)
{
this.power = power;
}
public ChronosphereSelectOrderGenerator() {}
public IEnumerable<Order> Order(World world, int2 xy, MouseInput mi)
{
@@ -34,8 +29,10 @@ namespace OpenRa.Orders
&& a.traits.Contains<Selectable>()).FirstOrDefault();
if (underCursor != null)
yield return new Order("ChronosphereSelect", underCursor, null, int2.Zero, power.Name);
yield return new Order("ChronosphereSelect", world.LocalPlayer.PlayerActor, underCursor);
}
yield break;
}
public void Tick( World world )
@@ -43,8 +40,9 @@ namespace OpenRa.Orders
var hasChronosphere = world.Actors
.Any(a => a.Owner == world.LocalPlayer && a.traits.Contains<Chronosphere>());
if (!hasChronosphere)
Game.controller.CancelInputMode();
// HACK: re-enable this
//if (!hasChronosphere)
// Game.controller.CancelInputMode();
}
public void Render( World world ) { }

View File

@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq;
using OpenRa.GameRules;
using OpenRa.Traits;
using OpenRa.SupportPowers;
namespace OpenRa.Orders
{
@@ -34,8 +33,10 @@ namespace OpenRa.Orders
&& a.traits.Contains<Selectable>()).FirstOrDefault();
if (underCursor != null)
yield return new Order("IronCurtain", underCursor, null, int2.Zero, power.Name);
yield return new Order("IronCurtain", underCursor.Owner.PlayerActor, underCursor);
}
yield break;
}
public void Tick( World world )

View File

@@ -36,7 +36,7 @@ namespace OpenRa.Orders
yield break;
}
yield return new Order("PlaceBuilding", Producer.Owner.PlayerActor, null, topLeft, Building);
yield return new Order("PlaceBuilding", Producer.Owner.PlayerActor, topLeft, Building);
}
}

View File

@@ -28,7 +28,7 @@ namespace OpenRa.Orders
&& a.traits.Contains<Selectable>()).FirstOrDefault();
if (underCursor != null)
yield return new Order("PowerDown", underCursor, null, int2.Zero, null);
yield return new Order("PowerDown", underCursor);
}
}

View File

@@ -30,7 +30,7 @@ namespace OpenRa.Orders
var building = underCursor != null ? underCursor.Info.Traits.Get<BuildingInfo>() : null;
if (building != null && building.Repairable && underCursor.Health < building.HP)
yield return new Order("Repair", underCursor, null, int2.Zero, null);
yield return new Order("Repair", underCursor);
}
}

View File

@@ -30,7 +30,7 @@ namespace OpenRa.Orders
var building = underCursor != null ? underCursor.Info.Traits.Get<BuildingInfo>() : null;
if (building != null && !building.Unsellable)
yield return new Order("Sell", underCursor, null, int2.Zero, null);
yield return new Order("Sell", underCursor);
}
}

View File

@@ -68,7 +68,7 @@ namespace OpenRa
Game.chat.AddLine(Color.White, "Debug", "Requesting package: {0}".F(currentPackage));
Game.orderManager.IssueOrder(
new Order("RequestFile", Game.world.LocalPlayer.PlayerActor, null, int2.Zero, currentPackage) { IsImmediate = true });
new Order("RequestFile", Game.world.LocalPlayer.PlayerActor, currentPackage) { IsImmediate = true });
Fraction = 0f;
}

View File

@@ -29,7 +29,6 @@ namespace OpenRa
public World World { get { return PlayerActor.World; } }
public Shroud Shroud;
public Dictionary<string, SupportPower> SupportPowers;
public Player( World world, int index, Session.Client client )
{
@@ -41,10 +40,6 @@ namespace OpenRa
this.Palette = client != null ? (PaletteType)client.Palette : (PaletteType)index;
this.PlayerName = client != null ? client.Name : "Player {0}".F(index+1);
this.Race = client != null ? (Race)client.Race : Race.Allies;
SupportPowers = Rules.SupportPowerInfo.ToDictionary(
spi => spi.Key,
spi => new SupportPower(spi.Key, spi.Value, this));
}
void UpdatePower()
@@ -134,9 +129,6 @@ namespace OpenRa
UpdateOreCapacity();
Shroud.Tick( World );
foreach (var sp in SupportPowers.Values)
sp.Tick();
if (this == World.LocalPlayer)
{
var totalMoney = Cash + Ore;

View File

@@ -1,104 +0,0 @@
using System;
using System.Linq;
using OpenRa.GameRules;
using OpenRa.SupportPowers;
using OpenRa.Traits;
namespace OpenRa
{
// todo: fix this to route Activate through the orders system (otherwise desync in netplay)
public class SupportPower
{
public readonly SupportPowerInfo Info;
public readonly Player Owner;
public readonly ISupportPowerImpl Impl;
public readonly string Name;
static ISupportPowerImpl ConstructPowerImpl(string implName)
{
var type = typeof(ISupportPowerImpl).Assembly.GetType(
typeof(ISupportPowerImpl).Namespace + "." + implName, true, false);
var ctor = type.GetConstructor(Type.EmptyTypes);
return (ISupportPowerImpl)ctor.Invoke(new object[] { });
}
public SupportPower(string name, SupportPowerInfo info, Player owner)
{
Name = name;
Info = info;
Owner = owner;
RemainingTime = TotalTime = (int)(info.ChargeTime * 60 * 25);
Impl = ConstructPowerImpl(info.Impl);
}
public bool IsUsed;
public bool IsAvailable { get; private set; }
public bool IsDone { get { return RemainingTime == 0; } }
public int RemainingTime { get; private set; }
public int TotalTime { get; private set; }
bool notifiedReady = false;
bool notifiedCharging = false;
public void Tick()
{
if (Info.OneShot && IsUsed)
return;
if (Info.GivenAuto)
{
var buildings = Rules.TechTree.GatherBuildings(Owner);
var effectivePrereq = Info.Prerequisite
.Select( a => a.ToLowerInvariant() )
.Where( a => Rules.Info[a].Traits.Get<BuildableInfo>().Owner.Contains( Owner.Race ));
IsAvailable = Info.TechLevel > -1
&& effectivePrereq.Any()
&& effectivePrereq.All(a => buildings[a].Count > 0);
}
if (IsAvailable && (!Info.Powered || Owner.GetPowerState() == PowerState.Normal))
{
if (RemainingTime > 0) --RemainingTime;
if (!notifiedCharging)
{
Impl.IsChargingNotification(this);
notifiedCharging = true;
}
}
if (RemainingTime == 0
&& Impl != null
&& !notifiedReady)
{
Impl.IsReadyNotification(this);
notifiedReady = true;
}
}
public void Activate()
{
if (Impl != null)
Impl.Activate(this);
}
public void FinishActivate()
{
if (Info.OneShot)
{
IsUsed = true;
IsAvailable = false;
}
RemainingTime = TotalTime;
notifiedReady = false;
notifiedCharging = false;
}
public void Give(bool requireCharge) // called by crate/spy/etc code
{
IsAvailable = true;
IsUsed = false;
RemainingTime = requireCharge ? TotalTime : 0;
}
}
}

View File

@@ -1,39 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;
using OpenRa.Orders;
using OpenRa.Traits;
namespace OpenRa.SupportPowers
{
class ChronospherePower : ISupportPowerImpl
{
public void IsReadyNotification(SupportPower p) { Sound.Play("chrordy1.aud"); }
public void IsChargingNotification(SupportPower p) { Sound.Play("chrochr1.aud"); }
public void OnFireNotification(Actor target, int2 xy)
{
p.FinishActivate();
Game.controller.CancelInputMode();
Sound.Play("chrono2.aud");
// Play chronosphere active anim
var chronosphere = target.World.Actors.Where(a => a.Owner == p.Owner && a.traits.Contains<Chronosphere>()).FirstOrDefault();
if (chronosphere != null)
Game.orderManager.IssueOrder(Order.PlayAnimation(chronosphere, "active"));
// Trigger screen desaturate effect
foreach (var a in target.World.Actors.Where(a => a.traits.Contains<ChronoshiftPaletteEffect>()))
a.traits.Get<ChronoshiftPaletteEffect>().DoChronoshift();
}
SupportPower p;
public void Activate(SupportPower p)
{
this.p = p;
Game.controller.orderGenerator = new ChronosphereSelectOrderGenerator(p);
Sound.Play("slcttgt1.aud");
}
}
}

View File

@@ -1,32 +0,0 @@
using System.Linq;
using OpenRa.Effects;
using OpenRa.Traits;
namespace OpenRa.SupportPowers
{
class GpsSatellite : ISupportPowerImpl
{
const int revealDelay = 15 * 25;
public void OnFireNotification(Actor a, int2 xy) { }
public void IsChargingNotification(SupportPower p) { }
public void IsReadyNotification(SupportPower p)
{
var launchSite = p.Owner.World.Actors
.FirstOrDefault(a => a.Owner == p.Owner && a.traits.Contains<GpsLaunchSite>());
if (launchSite == null)
return;
p.Owner.World.AddFrameEndTask(w =>
{
w.Add(new SatelliteLaunch(launchSite));
w.Add(new DelayedAction(revealDelay, () => p.Owner.Shroud.HasGPS = true));
});
p.FinishActivate();
}
public void Activate(SupportPower p) {}
}
}

View File

@@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OpenRa.SupportPowers
{
public interface ISupportPowerImpl
{
void Activate(SupportPower p);
void OnFireNotification(Actor target, int2 xy);
void IsChargingNotification(SupportPower p);
void IsReadyNotification(SupportPower p);
}
}

View File

@@ -1,44 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRa.Orders;
using OpenRa.Traits;
namespace OpenRa.SupportPowers
{
class IronCurtainPower : ISupportPowerImpl
{
public void IsReadyNotification(SupportPower p)
{
Sound.Play("ironrdy1.aud");
}
public void IsChargingNotification(SupportPower p)
{
Sound.Play("ironchg1.aud");
}
public void OnFireNotification(Actor target, int2 xy)
{
p.FinishActivate();
Game.controller.CancelInputMode();
Sound.Play("ironcur9.aud");
// Play active anim
var ironCurtain = target.World.Actors
.Where(a => a.Owner == p.Owner && a.traits.Contains<IronCurtain>())
.FirstOrDefault();
if (ironCurtain != null)
Game.orderManager.IssueOrder(Order.PlayAnimation(ironCurtain, "active"));
}
SupportPower p;
public void Activate(SupportPower p)
{
this.p = p;
// Pick a building to use
Game.controller.orderGenerator = new IronCurtainOrderGenerator(p);
Sound.Play("slcttgt1.aud");
}
}
}

View File

@@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OpenRa.SupportPowers
{
class NullPower : ISupportPowerImpl
{
public void OnFireNotification(Actor a, int2 xy) { }
public void IsReadyNotification(SupportPower p) { }
public void IsChargingNotification(SupportPower p) { }
public void Activate(SupportPower p)
{
// if this was a real power, i'd do something here!
throw new NotImplementedException();
}
}
}

View File

@@ -195,7 +195,7 @@ namespace OpenRa.Traits
if (!Combat.HasAnyValidWeapons(self, underCursor)) return null;
return new Order(isHeal ? "Heal" : "Attack", self, underCursor, int2.Zero, null);
return new Order(isHeal ? "Heal" : "Attack", self, underCursor);
}
public void ResolveOrder(Actor self, Order order)

View File

@@ -11,7 +11,7 @@ namespace OpenRa.Traits
{
var attack = self.traits.Get<AttackBase>();
if (target != null)
attack.ResolveOrder(self, new Order("Attack", self, target, int2.Zero, null));
attack.ResolveOrder(self, new Order("Attack", self, target));
else
if (self.GetCurrentActivity() is Attack)
self.CancelActivity();

View File

@@ -10,7 +10,7 @@ namespace OpenRa.Traits
{
var attack = self.traits.Get<AttackBase>();
if (target != null)
attack.ResolveOrder(self, new Order("Attack", self, target, int2.Zero, null));
attack.ResolveOrder(self, new Order("Attack", self, target));
}
public void Tick(Actor self)

View File

@@ -26,7 +26,7 @@ namespace OpenRa.Traits
var unit = underCursor.traits.GetOrDefault<Unit>();
if (unit != null && unit.Altitude > 0) return null;
return new Order("Deploy", self, null, int2.Zero, null);
return new Order("Deploy", self);
}
return null;

View File

@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenRa.Orders;
namespace OpenRa.Traits
{
class ChronoshiftPowerInfo : SupportPowerInfo
{
public readonly float Duration = 0f;
public readonly bool KillCargo = true;
public override object Create(Actor self) { return new ChronoshiftPower(self,this); }
}
class ChronoshiftPower : SupportPower, IResolveOrder
{
public ChronoshiftPower(Actor self, ChronoshiftPowerInfo info) : base(self, info) { }
protected override void OnBeginCharging() { Sound.Play("chrochr1.aud"); }
protected override void OnFinishCharging() { Sound.Play("chrordy1.aud"); }
protected override void OnActivate()
{
Game.controller.orderGenerator = new ChronosphereSelectOrderGenerator();
Sound.Play("slcttgt1.aud");
}
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "ChronosphereSelect" && self.Owner == self.World.LocalPlayer)
{
Game.controller.orderGenerator = new ChronoshiftDestinationOrderGenerator(order.TargetActor);
Sound.Play("slcttgt1.aud");
}
if (order.OrderString == "ChronosphereFinish")
{
Game.controller.CancelInputMode();
FinishActivate();
Sound.Play("chrono2.aud");
var chronosphere = self.World.Actors.Where(a => a.Owner == self.Owner
&& a.traits.Contains<Chronosphere>()).FirstOrDefault();
if (chronosphere != null)
Game.orderManager.IssueOrder(new Order("PlayAnimation", chronosphere, "active"));
// Trigger screen desaturate effect
foreach (var a in self.World.Actors.Where(a => a.traits.Contains<ChronoshiftPaletteEffect>()))
a.traits.Get<ChronoshiftPaletteEffect>().DoChronoshift();
}
}
}
// tag trait to identify the building
class ChronosphereInfo : StatelessTraitInfo<Chronosphere> { }
public class Chronosphere { }
}

View File

@@ -10,7 +10,7 @@ namespace OpenRa.Traits
public object Create(Actor self) { return new Chronoshiftable(self); }
}
public class Chronoshiftable : IResolveOrder, ISpeedModifier, ITick
public class Chronoshiftable : IResolveOrder, ITick
{
// Return-to-sender logic
[Sync]
@@ -39,12 +39,6 @@ namespace OpenRa.Traits
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "ChronosphereSelect")
{
var power = self.Owner.SupportPowers[order.TargetString];
Game.controller.orderGenerator = new ChronoshiftDestinationOrderGenerator(self, power);
}
var movement = self.traits.GetOrDefault<IMovement>();
if (order.OrderString == "Chronoshift" && movement.CanEnterCell(order.TargetLocation))
{
@@ -70,16 +64,8 @@ namespace OpenRa.Traits
// Set up the teleport
self.CancelActivity();
self.QueueActivity(new Activities.Teleport(order.TargetLocation));
var power = self.Owner.SupportPowers[order.TargetString].Impl;
power.OnFireNotification(self, self.Location);
}
}
}
public float GetSpeedModifier()
{
// ARGH! You must not do this, it will desync!
return (Game.controller.orderGenerator is ChronoshiftDestinationOrderGenerator) ? 0f : 1f;
}
}
}

View File

@@ -1,18 +0,0 @@

namespace OpenRa.Traits
{
class ChronosphereInfo : StatelessTraitInfo<Chronosphere> { }
public class Chronosphere : IResolveOrder
{
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "PlayAnimation")
{
var rb = self.traits.Get<RenderBuilding>();
if (rb != null)
rb.PlayCustomAnim(self, order.TargetString);
}
}
}
}

View File

@@ -30,7 +30,7 @@ namespace OpenRa.Traits
if (!self.World.IsActorCrushableByActor(underCursor, self)) return null;
}
return new Order("Move", self, null, xy, null);
return new Order("Move", self, xy);
}
public void ResolveOrder(Actor self, Order order)

View File

@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenRa.Effects;
namespace OpenRa.Traits
{
class GpsPowerInfo : SupportPowerInfo
{
public readonly int RevealDelay = 0;
public override object Create(Actor self) { return new GpsPower(self, this); }
}
class GpsPower : SupportPower
{
public GpsPower(Actor self, GpsPowerInfo info) : base(self, info) { }
protected override void OnFinishCharging()
{
var launchSite = Owner.World.Actors
.FirstOrDefault(a => a.Owner == Owner && a.traits.Contains<GpsLaunchSite>());
if (launchSite == null)
return;
Owner.World.AddFrameEndTask(w =>
{
w.Add(new SatelliteLaunch(launchSite));
w.Add(new DelayedAction((Info as GpsPowerInfo).RevealDelay * 25,
() => Owner.Shroud.HasGPS = true));
});
FinishActivate();
}
}
}

View File

@@ -39,10 +39,10 @@ namespace OpenRa.Traits
if (underCursor != null
&& underCursor.Owner == self.Owner
&& underCursor.traits.Contains<AcceptsOre>() && !IsEmpty)
return new Order("Deliver", self, underCursor, int2.Zero, null);
return new Order("Deliver", self, underCursor);
if (underCursor == null && self.World.Map.ContainsResource(xy))
return new Order("Harvest", self, null, xy, null);
return new Order("Harvest", self, xy);
return null;
}

View File

@@ -27,12 +27,12 @@ namespace OpenRa.Traits
if (mi.Button == MouseButton.Left) return null;
if (underCursor == null)
return new Order("Move", self, null, xy, null);
return new Order("Move", self, xy);
if (HeliCanEnter(underCursor)
&& underCursor.Owner == self.Owner
&& !Reservable.IsReserved(underCursor))
return new Order("Enter", self, underCursor, int2.Zero, null);
return new Order("Enter", self, underCursor);
return null;
}

View File

@@ -1,18 +0,0 @@

namespace OpenRa.Traits
{
class IronCurtainInfo : StatelessTraitInfo<IronCurtain> { }
class IronCurtain : IResolveOrder
{
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "PlayAnimation")
{
var rb = self.traits.Get<RenderBuilding>();
if (rb != null)
rb.PlayCustomAnim(self, order.TargetString);
}
}
}
}

View File

@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenRa.Orders;
namespace OpenRa.Traits
{
class IronCurtainPowerInfo : SupportPowerInfo
{
public readonly float Duration = 0f;
public override object Create(Actor self) { return new IronCurtainPower(self, this); }
}
class IronCurtainPower : SupportPower, IResolveOrder
{
public IronCurtainPower(Actor self, IronCurtainPowerInfo info) : base(self, info) { }
protected override void OnBeginCharging() { Sound.Play("ironchg1.aud"); }
protected override void OnFinishCharging() { Sound.Play("ironrdy1.aud"); }
protected override void OnActivate()
{
Game.controller.orderGenerator = new IronCurtainOrderGenerator(this);
Sound.Play("slcttgt1.aud");
}
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "IronCurtain")
{
order.TargetActor.traits.Get<IronCurtainable>().Activate(order.TargetActor,
(int)((Info as IronCurtainPowerInfo).Duration * 25 * 60));
Game.controller.CancelInputMode();
FinishActivate();
}
}
}
// tag trait for the building
class IronCurtainInfo : StatelessTraitInfo<IronCurtain> { }
class IronCurtain { }
}

View File

@@ -8,7 +8,7 @@ namespace OpenRa.Traits
public object Create(Actor self) { return new IronCurtainable(); }
}
class IronCurtainable : IResolveOrder, IDamageModifier, ITick
class IronCurtainable : IDamageModifier, ITick
{
[Sync]
int RemainingTicks = 0;
@@ -18,20 +18,16 @@ namespace OpenRa.Traits
if (RemainingTicks > 0)
RemainingTicks--;
}
public float GetDamageModifier()
{
return (RemainingTicks > 0) ? 0.0f : 1.0f;
}
public void ResolveOrder(Actor self, Order order)
public void Activate(Actor self, int duration)
{
if (order.OrderString == "IronCurtain")
{
var power = self.Owner.SupportPowers[order.TargetString].Impl;
power.OnFireNotification(self, self.Location);
self.World.AddFrameEndTask(w => w.Add(new InvulnEffect(self)));
RemainingTicks = (int)(Rules.General.IronCurtain * 60 * 25);
}
RemainingTicks = duration;
}
}
}

View File

@@ -15,7 +15,7 @@ namespace OpenRa.Traits
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
{
if (mi.Button == MouseButton.Right && self == underCursor)
return new Order("DeployMcv", self, null, int2.Zero, null);
return new Order("DeployMcv", self);
return null;
}

View File

@@ -67,7 +67,7 @@ namespace OpenRa.Traits
if (Util.GetEffectiveSpeed(self) == 0) return null; /* allow disabling move orders from modifiers */
if (xy == toCell) return null;
return new Order("Move", self, null, xy, null);
return new Order("Move", self, xy);
}
public void ResolveOrder(Actor self, Order order)

View File

@@ -23,7 +23,7 @@ namespace OpenRa.Traits
if (!underCursor.Info.Traits.Get<CargoInfo>().PassengerTypes.Contains(umt))
return null;
return new Order("EnterTransport", self, underCursor, int2.Zero, null);
return new Order("EnterTransport", self, underCursor);
}
public void ResolveOrder(Actor self, Order order)

View File

@@ -26,12 +26,12 @@ namespace OpenRa.Traits
{
if (mi.Button == MouseButton.Left) return null;
if (underCursor == null)
return new Order("Move", self, null, xy, null);
return new Order("Move", self, xy);
if (PlaneCanEnter(underCursor)
&& underCursor.Owner == self.Owner
&& !Reservable.IsReserved(underCursor))
return new Order("Enter", self, underCursor, int2.Zero, null);
return new Order("Enter", self, underCursor);
return null;
}

View File

@@ -65,7 +65,7 @@ namespace OpenRa.Traits
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
{
if (mi.Button == MouseButton.Right && underCursor == self)
return new Order("Deploy", self, null, int2.Zero, null);
return new Order("Deploy", self);
return null;
}

View File

@@ -36,7 +36,7 @@ namespace OpenRa.Traits
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
{
if (mi.Button == MouseButton.Left || underCursor != null) return null;
return new Order("SetRallyPoint", self, null, xy, null);
return new Order("SetRallyPoint", self, xy);
}
public void ResolveOrder( Actor self, Order order )

View File

@@ -8,7 +8,7 @@ namespace OpenRa.Traits
public override object Create(Actor self) { return new RenderBuilding(self); }
}
class RenderBuilding : RenderSimple, INotifyDamage, INotifySold
class RenderBuilding : RenderSimple, INotifyDamage, INotifySold, IResolveOrder
{
const int SmallBibStart = 1;
const int LargeBibStart = 5;
@@ -99,5 +99,11 @@ namespace OpenRa.Traits
}
public void Sold(Actor self) { DoBib(self, true); }
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "PlayAnimation")
PlayCustomAnim(self, order.TargetString);
}
}
}

View File

@@ -24,7 +24,7 @@ namespace OpenRa.Traits
if (underCursor.Info.Name == "fix"
&& underCursor.Owner == self.Owner
&& !Reservable.IsReserved(underCursor))
return new Order("Enter", self, underCursor, int2.Zero, null);
return new Order("Enter", self, underCursor);
return null;
}

View File

@@ -0,0 +1,103 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OpenRa.Traits
{
abstract class SupportPowerInfo : ITraitInfo
{
public readonly bool RequiresPower = true;
public readonly bool OneShot = false;
public readonly float ChargeTime = 0;
public readonly string Image = null;
public readonly string Description = "";
public readonly string LongDesc = "";
public readonly string[] Prerequisites = { };
public readonly int TechLevel = -1;
public readonly bool GivenAuto = true;
public abstract object Create(Actor self);
}
class SupportPower : ITick
{
public readonly SupportPowerInfo Info;
public int RemainingTime { get; private set; }
public int TotalTime { get { return (int)(Info.ChargeTime * 60 * 25); } }
public bool IsUsed;
public bool IsAvailable;
public bool IsReady { get { return RemainingTime == 0; } }
public readonly Player Owner;
bool notifiedCharging;
bool notifiedReady;
public SupportPower(Actor self, SupportPowerInfo info)
{
Info = info;
RemainingTime = TotalTime;
Owner = self.Owner;
}
public void Tick(Actor self)
{
if (Info.OneShot && IsUsed)
return;
if (Info.GivenAuto)
{
var buildings = Rules.TechTree.GatherBuildings(self.Owner);
var effectivePrereq = Info.Prerequisites
.Select(a => a.ToLowerInvariant())
.Where(a => Rules.Info[a].Traits.Get<BuildableInfo>().Owner.Contains(self.Owner.Race));
IsAvailable = Info.TechLevel > -1
&& effectivePrereq.Any()
&& effectivePrereq.All(a => buildings[a].Count > 0);
}
if (IsAvailable && (!Info.RequiresPower || self.Owner.GetPowerState() == PowerState.Normal))
{
if (RemainingTime > 0) --RemainingTime;
if (!notifiedCharging)
{
OnBeginCharging();
notifiedCharging = true;
}
}
if (RemainingTime == 0
&& !notifiedReady)
{
OnFinishCharging();
notifiedReady = true;
}
}
public void FinishActivate()
{
if (Info.OneShot)
{
IsUsed = true;
IsAvailable = false;
}
RemainingTime = TotalTime;
notifiedReady = false;
notifiedCharging = false;
}
public void Give(float charge)
{
IsAvailable = true;
IsUsed = false;
RemainingTime = (int)(charge * TotalTime);
}
protected virtual void OnBeginCharging() { }
protected virtual void OnFinishCharging() { }
protected virtual void OnActivate() { }
public void Activate() { OnActivate(); } // todo: some more hax
}
}

View File

@@ -29,7 +29,7 @@ namespace OpenRa.Mods.Aftermath
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
{
if (mi.Button == MouseButton.Right && xy == self.Location && chargeTick <= 0)
return new Order("Deploy", self, null, int2.Zero, null);
return new Order("Deploy", self);
return null;
}

View File

@@ -21,7 +21,7 @@ namespace OpenRa.Mods.Aftermath.Orders
yield break;
}
yield return new Order("ChronoshiftSelf", self, null, xy, null);
yield return new Order("ChronoshiftSelf", self, xy);
}
public void Tick( World world ) { }

View File

@@ -15,7 +15,7 @@ namespace OpenRa.Mods.RA
if (underCursor.Owner == self.Owner && !mi.Modifiers.HasModifier(Modifiers.Ctrl)) return null;
if (!underCursor.traits.Contains<Building>()) return null;
return new Order("C4", self, underCursor, int2.Zero, null);
return new Order("C4", self, underCursor);
}
public void ResolveOrder(Actor self, Order order)

View File

@@ -20,7 +20,7 @@ namespace OpenRa.Mods.RA
if (underCursor.Owner == null) return null; // don't allow capturing of bridges, etc.
return new Order(underCursor.Health <= EngineerDamage ? "Capture" : "Infiltrate",
self, underCursor, int2.Zero, null);
self, underCursor);
}
public void ResolveOrder(Actor self, Order order)

View File

@@ -21,7 +21,7 @@ namespace OpenRa.Mods.RA
return null;
if (mi.Button == MouseButton.Right && underCursor == self)
return new Order("Deploy", self, null, int2.Zero, null);
return new Order("Deploy", self);
return null;
}

View File

@@ -19,7 +19,7 @@ namespace OpenRa.Mods.RA
if (underCursor.Owner == self.Owner &&
(underCursor.Info.Name == "spen" || underCursor.Info.Name == "syrd") &&
self.Health < self.GetMaxHP())
return new Order("Enter", self, underCursor, int2.Zero, null);
return new Order("Enter", self, underCursor);
return null;
}

View File

@@ -19,7 +19,7 @@ namespace OpenRa.Mods.RA
if (underCursor.Owner == self.Owner) return null;
if (!underCursor.traits.Contains<IAcceptSpy>()) return null;
return new Order("Infiltrate", self, underCursor, int2.Zero, null);
return new Order("Infiltrate", self, underCursor);
}
public void ResolveOrder(Actor self, Order order)

View File

@@ -14,7 +14,7 @@ namespace OpenRa.Mods.RA
if (underCursor == null) return null;
if (!underCursor.traits.Contains<IAcceptThief>()) return null;
return new Order("Steal", self, underCursor, int2.Zero, null);
return new Order("Steal", self, underCursor);
}
public void ResolveOrder(Actor self, Order order)

View File

@@ -1,6 +1,32 @@
Player:
ProductionQueue:
PlaceBuilding:
GpsPower:
Image: gpssicon
OneShot: yes
ChargeTime: 8
Description: GPS Satellite
LongDesc: Reveals the entire map
Prerequisites: ATEK
TechLevel: 12
RevealDelay: 15
ChronoshiftPower:
Image: warpicon
ChargeTime: 7
Description: Chronoshift
LongDesc: Temporarily teleports a vehicle across \nthe map.
Prerequisites: PDOX
TechLevel: 12
Duration: 3
KillCargo: yes
IronCurtainPower:
Image: infxicon
ChargeTime: 11
Description: Invulnerability
LongDesc: Makes a single unit invulnerable for a \nshort time.
Prerequisites: IRON
TechLevel: 12
Duration: .75
World:
WaterPaletteRotation:

View File

@@ -1,6 +1,32 @@
Player:
ProductionQueue:
PlaceBuilding:
GpsPower:
Image: gpssicon
OneShot: yes
ChargeTime: 8
Description: GPS Satellite
LongDesc: Reveals the entire map
Prerequisites: ATEK
TechLevel: 12
RevealDelay: 15
ChronoshiftPower:
Image: warpicon
ChargeTime: 7
Description: Chronoshift
LongDesc: Temporarily teleports a vehicle across \nthe map.
Prerequisites: PDOX
TechLevel: 12
Duration: 3
KillCargo: yes
IronCurtainPower:
Image: infxicon
ChargeTime: 11
Description: Invulnerability
LongDesc: Makes a single unit invulnerable for a \nshort time.
Prerequisites: IRON
TechLevel: 12
Duration: .75
World:
WaterPaletteRotation:

View File

@@ -849,20 +849,6 @@ Move=girlokay
Select=einah1,einok1,einyes1
Move=einah1,einok1,einyes1
;; todo: where there are different variants of the same power,
;; split them here. SonarPulse is the obvious one.
[SupportPowerTypes]
ParadropPower
ParabombPower
SonarPulsePower
ChronoshiftPower
SpyPlanePower
NukePower
GpsSatellitePower
InvulnerabilityPower
[ParadropPower] ; comes free with first AFLD
ChargeTime=7
Description=Paratroopers
@@ -894,15 +880,6 @@ TechLevel=5
GivenAuto=no
Impl=NullPower
[ChronoshiftPower] ; free with Chronosphere... sortof the point.
ChargeTime=7
Description=Chronoshift
LongDesc=Temporarily teleports a vehicle across \nthe map.
Prerequisite=PDOX
Image=warpicon
TechLevel=12
Impl=ChronospherePower
[SpyPlanePower] ; free with first AFLD
ChargeTime=3
TechLevel=5
@@ -921,21 +898,3 @@ Image=atomicon
TechLevel=12
Impl=NullPower
[GpsSatellitePower] ; free with ATEK
ChargeTime=8
Description=GPS Satellite
LongDesc=Reveals the entire map
OneShot=yes
Prerequisite=ATEK
Image=gpssicon
TechLevel=12
Impl=GpsSatellite
[InvulnerabilityPower] ; the point of IRON
ChargeTime=11
Description=Invulnerability
LongDesc=Makes a single unit invulnerable for a \nshort time.
Image=infxicon
Prerequisite=IRON
TechLevel=12
Impl=IronCurtainPower