New special powers mechanism. Only cnc Airstrike has been reimplemented so far. Special power crates, and spy bonuses have also been disabled.

This commit is contained in:
Paul Chote
2010-12-05 11:53:42 +13:00
parent c6fad7fe98
commit 76f792bfdf
17 changed files with 366 additions and 252 deletions

View File

@@ -20,10 +20,10 @@ namespace OpenRA.Mods.Cnc
public override object Create(ActorInitializer init) { return new IonCannonPower(init.self, this); }
}
class IonCannonPower : SupportPower, IResolveOrder
class IonCannonPower : SupportPower
{
public IonCannonPower(Actor self, IonCannonPowerInfo info) : base(self, info) { }
/*
public void ResolveOrder(Actor self, Order order)
{
if (!IsReady) return;
@@ -45,6 +45,7 @@ namespace OpenRA.Mods.Cnc
Self.World.OrderGenerator =
new GenericSelectTargetWithBuilding<IonControl>(Owner.PlayerActor, "IonCannon", "ability");
}
*/
}
class IonControlInfo : TraitInfo<IonControl> { }

View File

@@ -26,15 +26,16 @@ namespace OpenRA.Mods.RA.Crates
public override void Activate(Actor collector)
{
throw new System.NotImplementedException();
// shit and broken. if you have a single-use and a multi-use version of the same
// support power, this only works by order-coincidence. that's stupid.
var p = collector.Owner.PlayerActor.TraitsImplementing<SupportPower>()
.FirstOrDefault(sp => sp.GetType().Name == (info as SupportPowerCrateActionInfo).Power);
//var p = collector.Owner.PlayerActor.TraitsImplementing<SupportPower>()
// .FirstOrDefault(sp => sp.GetType().Name == (info as SupportPowerCrateActionInfo).Power);
if (p != null) p.Give(1);
//if (p != null) p.Give(1);
base.Activate(collector);
//base.Activate(collector);
}
}
}

View File

@@ -29,10 +29,11 @@ namespace OpenRA.Mods.RA
public void OnInfiltrate(Actor self, Actor spy)
{
var p = spy.Owner.PlayerActor.TraitsImplementing<SupportPower>()
.FirstOrDefault(sp => sp.GetType().Name == info.Power);
if (p != null) p.Give(1);
throw new System.NotImplementedException();
//var p = spy.Owner.PlayerActor.TraitsImplementing<SupportPower>()
// .FirstOrDefault(sp => sp.GetType().Name == info.Power);
//
//if (p != null) p.Give(1);
}
}
}

View File

@@ -325,6 +325,7 @@
<Compile Include="Effects\RallyPoint.cs" />
<Compile Include="AttackMedic.cs" />
<Compile Include="Activities\Heal.cs" />
<Compile Include="SupportPowers\SupportPowerManager.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
@@ -351,4 +352,8 @@
copy "$(TargetPath)" "$(SolutionDir)mods/ra/"
cd "$(SolutionDir)"</PostBuildEvent>
</PropertyGroup>
<ItemGroup>
<Folder Include="SupportPowers\" />
<Folder Include="Player\" />
</ItemGroup>
</Project>

View File

@@ -26,53 +26,39 @@ namespace OpenRA.Mods.RA
public override object Create(ActorInitializer init) { return new AirstrikePower(init.self, this); }
}
class AirstrikePower : SupportPower, IResolveOrder
class AirstrikePower : SupportPower
{
public AirstrikePower(Actor self, AirstrikePowerInfo info) : base(self, info) { }
protected override void OnActivate()
public override void Activate(Actor self, Order order)
{
Self.World.OrderGenerator = new GenericSelectTarget(Owner.PlayerActor, Info.OrderName, "ability");
}
public void ResolveOrder(Actor self, Order order)
{
if (!IsReady) return;
if (order.OrderString == Info.OrderName)
var startPos = self.World.ChooseRandomEdgeCell();
self.World.AddFrameEndTask(w =>
{
var startPos = Owner.World.ChooseRandomEdgeCell();
var info = (Info as AirstrikePowerInfo);
var flare = info.FlareType != null ? w.CreateActor(info.FlareType, new TypeDictionary
{
new LocationInit( order.TargetLocation ),
new OwnerInit( self.Owner ),
}) : null;
var a = w.CreateActor(info.UnitType, new TypeDictionary
{
new LocationInit( startPos ),
new OwnerInit( self.Owner ),
new FacingInit( Util.GetFacing(order.TargetLocation - startPos, 0) ),
new AltitudeInit( Rules.Info[info.UnitType].Traits.Get<PlaneInfo>().CruiseAltitude ),
});
a.Trait<CarpetBomb>().SetTarget(order.TargetLocation);
Owner.World.AddFrameEndTask(w =>
{
var info = (Info as AirstrikePowerInfo);
var flare = info.FlareType != null ? w.CreateActor(info.FlareType, new TypeDictionary
{
new LocationInit( order.TargetLocation ),
new OwnerInit( Owner ),
}) : null;
var a = w.CreateActor(info.UnitType, new TypeDictionary
{
new LocationInit( startPos ),
new OwnerInit( Owner ),
new FacingInit( Util.GetFacing(order.TargetLocation - startPos, 0) ),
new AltitudeInit( Rules.Info[info.UnitType].Traits.Get<PlaneInfo>().CruiseAltitude ),
});
a.Trait<CarpetBomb>().SetTarget(order.TargetLocation);
a.CancelActivity();
a.QueueActivity(Fly.ToCell(order.TargetLocation));
a.CancelActivity();
a.QueueActivity(Fly.ToCell(order.TargetLocation));
if (flare != null)
a.QueueActivity(new CallFunc(() => flare.Destroy()));
if (flare != null)
a.QueueActivity(new CallFunc(() => flare.Destroy()));
a.QueueActivity(new FlyOffMap { Interruptible = false });
a.QueueActivity(new RemoveSelf());
});
FinishActivate();
}
a.QueueActivity(new FlyOffMap { Interruptible = false });
a.QueueActivity(new RemoveSelf());
});
}
}
}

View File

@@ -15,7 +15,7 @@ using OpenRA.Graphics;
using OpenRA.Mods.RA.Render;
using OpenRA.Traits;
using OpenRA.Mods.RA.Effects;
/*
namespace OpenRA.Mods.RA
{
class ChronoshiftPowerInfo : SupportPowerInfo
@@ -255,3 +255,4 @@ namespace OpenRA.Mods.RA
class ChronosphereInfo : TraitInfo<Chronosphere> {}
class Chronosphere {}
}
*/

View File

@@ -12,7 +12,7 @@ using System.Linq;
using OpenRA.Effects;
using OpenRA.Mods.RA.Effects;
using OpenRA.Traits;
/*
namespace OpenRA.Mods.RA
{
class GpsPowerInfo : SupportPowerInfo
@@ -51,3 +51,4 @@ namespace OpenRA.Mods.RA
class GpsLaunchSiteInfo : TraitInfo<GpsLaunchSite> { }
class GpsLaunchSite { }
}
*/

View File

@@ -16,7 +16,7 @@ using OpenRA.Mods.RA.Effects;
using OpenRA.Mods.RA.Render;
using OpenRA.Traits;
using TUtil = OpenRA.Traits.Util;
/*
namespace OpenRA.Mods.RA
{
class IronCurtainPowerInfo : SupportPowerInfo
@@ -139,3 +139,4 @@ namespace OpenRA.Mods.RA
class IronCurtainInfo : TraitInfo<IronCurtain> { }
class IronCurtain { }
}
*/

View File

@@ -20,11 +20,11 @@ namespace OpenRA.Mods.RA
{
public override object Create(ActorInitializer init) { return new NukePower(init.self, this); }
}
class NukePower : SupportPower, IResolveOrder
class NukePower : SupportPower
{
public NukePower(Actor self, NukePowerInfo info) : base(self, info) { }
/*
protected override void OnActivate()
{
Self.World.OrderGenerator =
@@ -52,6 +52,7 @@ namespace OpenRA.Mods.RA
FinishActivate();
}
}
*/
}
// tag trait for the building

View File

@@ -13,7 +13,7 @@ using OpenRA.Orders;
using OpenRA.Traits;
using OpenRA.FileFormats;
using OpenRA.Mods.RA.Air;
/*
namespace OpenRA.Mods.RA
{
class ParatroopersPowerInfo : SupportPowerInfo
@@ -82,3 +82,4 @@ namespace OpenRA.Mods.RA
}
}
}
*/

View File

@@ -9,7 +9,7 @@
#endregion
using OpenRA.Traits;
/*
namespace OpenRA.Mods.RA
{
public class SonarPulsePowerInfo : SupportPowerInfo
@@ -44,3 +44,4 @@ namespace OpenRA.Mods.RA
}
}
}
*/

View File

@@ -14,7 +14,7 @@ using OpenRA.Traits;
using OpenRA.Traits.Activities;
using OpenRA.FileFormats;
using OpenRA.Mods.RA.Air;
/*
namespace OpenRA.Mods.RA
{
class SpyPlanePowerInfo : SupportPowerInfo
@@ -71,3 +71,4 @@ namespace OpenRA.Mods.RA
}
}
}
*/

View File

@@ -14,136 +14,40 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
public abstract class SupportPowerInfo : ITraitInfo, ITraitPrerequisite<TechTreeInfo>, ITraitPrerequisite<PowerManagerInfo>
public abstract class SupportPowerInfo : ITraitInfo
{
public readonly bool RequiresPower = true;
public readonly bool OneShot = false;
public readonly float ChargeTime = 0;
public readonly int ChargeTime = 0;
public readonly string Image = null;
public readonly string Description = "";
public readonly string LongDesc = "";
[ActorReference]
public readonly string[] Prerequisites = { };
public readonly bool GivenAuto = true;
public readonly string OrderName;
public readonly string BeginChargeSound = null;
public readonly string EndChargeSound = null;
public readonly string SelectTargetSound = null;
public readonly string LaunchSound = null;
public readonly bool AllowMultiple = false;
public abstract object Create(ActorInitializer init);
public SupportPowerInfo() { OrderName = GetType().Name + "Order"; }
}
public class SupportPower : ITick, ITechTreeElement
public class SupportPower
{
public readonly Actor self;
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 IsAvailable && RemainingTime == 0; } }
protected readonly Actor Self;
protected readonly Player Owner;
bool notifiedCharging;
bool notifiedReady;
readonly PowerManager PlayerPower;
public SupportPower(Actor self, SupportPowerInfo info)
{
Info = info;
RemainingTime = TotalTime;
Self = self;
Owner = self.Owner;
PlayerPower = self.Trait<PowerManager>();
self.Trait<TechTree>().Add( Info.OrderName, Info.Prerequisites.Select( a => a.ToLowerInvariant() ).ToList(), this );
this.self = self;
}
public void Tick(Actor self)
public virtual void Activate(Actor self, Order order) { }
public virtual IOrderGenerator OrderGenerator(string order, SupportPowerManager manager)
{
if (Info.OneShot && IsUsed)
return;
if (Info.GivenAuto)
IsAvailable = hasPrerequisites;
if (IsAvailable && (!Info.RequiresPower || PlayerPower.PowerState == PowerState.Normal))
{
if (self.World.LobbyInfo.GlobalSettings.AllowCheats && self.Trait<DeveloperMode>().FastCharge) RemainingTime = 0;
if (RemainingTime > 0) --RemainingTime;
if (!notifiedCharging)
{
Sound.PlayToPlayer(Owner, Info.BeginChargeSound);
OnBeginCharging();
notifiedCharging = true;
}
}
if (RemainingTime == 0
&& !notifiedReady)
{
Sound.PlayToPlayer(Owner, Info.EndChargeSound);
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()
{
if (!IsAvailable || !IsReady)
return;
if (Info.RequiresPower && PlayerPower.PowerState != PowerState.Normal)
{
var eva = Owner.World.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
Sound.Play(eva.AbilityInsufficientPower);
return;
}
Sound.PlayToPlayer(Owner, Info.SelectTargetSound);
OnActivate();
}
bool hasPrerequisites;
public void PrerequisitesAvailable(string key)
{
hasPrerequisites = true;
}
public void PrerequisitesUnavailable(string key)
{
hasPrerequisites = false;
Sound.PlayToPlayer(manager.self.Owner, Info.SelectTargetSound);
return new SelectGenericPowerTarget(order, manager, "ability", MouseButton.Left);
}
}
}

View File

@@ -0,0 +1,194 @@
#region Copyright & License Information
/*
* Copyright 2007-2010 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 LICENSE.
*/
#endregion
using System.Linq;
using OpenRA.Mods.RA.Buildings;
using OpenRA.Traits;
using System.Collections.Generic;
using OpenRA.Graphics;
namespace OpenRA.Mods.RA
{
public class SupportPowerManagerInfo : ITraitInfo
{
public object Create(ActorInitializer init) { return new SupportPowerManager(init); }
}
public class SupportPowerManager : ITick, IResolveOrder
{
public readonly Actor self;
public Dictionary<string, SupportPowerInstance> Powers = new Dictionary<string, SupportPowerInstance>();
public SupportPowerManager(ActorInitializer init)
{
self = init.self;
init.world.ActorAdded += ActorAdded;
init.world.ActorRemoved += ActorRemoved;
}
void ActorAdded(Actor a)
{
if (a.Owner != self.Owner || !a.HasTrait<SupportPower>())
return;
foreach (var t in a.TraitsImplementing<SupportPower>())
{
var key = (t.Info.AllowMultiple) ? t.Info.OrderName+"_"+a.ActorID : t.Info.OrderName;
if (Powers.ContainsKey(key))
{
Powers[key].Instances.Add(t);
}
else
{
var si = new SupportPowerInstance(this)
{
Instances = new List<SupportPower>() { t },
RemainingTime = t.Info.ChargeTime * 25,
TotalTime = t.Info.ChargeTime * 25,
};
Powers.Add(key, si);
}
}
}
void ActorRemoved(Actor a)
{
if (a.Owner != self.Owner || !a.HasTrait<SupportPower>())
return;
foreach (var t in a.TraitsImplementing<SupportPower>())
{
var key = (t.Info.AllowMultiple) ? t.Info.OrderName+"_"+a.ActorID : t.Info.OrderName;
Powers[key].Instances.Remove(t);
if (Powers[key].Instances.Count == 0)
Powers.Remove(key);
}
}
public void Tick(Actor self)
{
foreach(var power in Powers.Values)
power.Tick();
}
public void ResolveOrder(Actor self, Order order)
{
// order.OrderString is the key of the support power
if (Powers.ContainsKey(order.OrderString))
Powers[order.OrderString].Activate(order);
}
public void Target(string key)
{
if (Powers.ContainsKey(key))
Powers[key].Target(key);
}
public class SupportPowerInstance
{
SupportPowerManager Manager;
public List<SupportPower> Instances;
public int RemainingTime;
public int TotalTime;
public bool Active;
public SupportPowerInfo Info { get { return Instances.First().Info; } }
public bool Ready { get { return Active && RemainingTime == 0; } }
public SupportPowerInstance(SupportPowerManager manager)
{
Manager = manager;
}
bool notifiedCharging;
bool notifiedReady;
public void Tick()
{
Active = Instances.Any(i => !i.self.TraitsImplementing<IDisable>().Any(d => d.Disabled));
if (Active)
{
if (RemainingTime > 0) --RemainingTime;
if (!notifiedCharging)
{
Sound.PlayToPlayer(Instances.First().self.Owner, Info.BeginChargeSound);
//instance.OnBeginCharging();
notifiedCharging = true;
}
}
if (RemainingTime == 0
&& !notifiedReady)
{
Sound.PlayToPlayer(Instances.First().self.Owner, Info.EndChargeSound);
//instance.FinishCharging();
notifiedReady = true;
}
}
public void Target(string key)
{
if (!Ready)
return;
Manager.self.World.OrderGenerator = Instances.First().OrderGenerator(key, Manager);
}
public void Activate(Order order)
{
if (!Ready)
return;
var power = Instances.First();
// Note: order.Subject is the *player* actor
power.Activate(power.self, order);
RemainingTime = TotalTime;
notifiedCharging = notifiedReady = false;
}
}
}
public class SelectGenericPowerTarget : IOrderGenerator
{
readonly SupportPowerManager manager;
readonly string order;
readonly string cursor;
readonly MouseButton expectedButton;
public SelectGenericPowerTarget(string order, SupportPowerManager manager, string cursor, MouseButton button)
{
this.manager = manager;
this.order = order;
this.cursor = cursor;
expectedButton = button;
}
public IEnumerable<Order> Order(World world, int2 xy, MouseInput mi)
{
world.CancelInputMode();
if (mi.Button == expectedButton && world.Map.IsInMap(xy))
yield return new Order(order, manager.self, false) { TargetLocation = xy };
}
public virtual void Tick(World world)
{
// Cancel the OG if we can't use the power
if (!manager.Powers.ContainsKey(order))
world.CancelInputMode();
}
public void RenderBeforeWorld(WorldRenderer wr, World world) { }
public void RenderAfterWorld(WorldRenderer wr, World world) { }
public string GetCursor(World world, int2 xy, MouseInput mi) { return world.Map.IsInMap(xy) ? cursor : "generic-blocked"; }
}
}

View File

@@ -74,9 +74,10 @@ namespace OpenRA.Mods.RA.Widgets
if( world.LocalPlayer == null ) return;
var powers = world.LocalPlayer.PlayerActor.TraitsImplementing<SupportPower>();
var numPowers = powers.Count(p => p.IsAvailable);
var manager = world.LocalPlayer.PlayerActor.Trait<SupportPowerManager>();
var numPowers = manager.Powers.Count;
if (numPowers == 0) return;
var rectBounds = RenderBounds;
WidgetUtils.DrawRGBA(WidgetUtils.GetChromeImage(world, "specialbin-top"),new float2(rectBounds.X,rectBounds.Y));
for (var i = 1; i < numPowers; i++)
@@ -88,74 +89,78 @@ namespace OpenRA.Mods.RA.Widgets
rectBounds.Height = 10 + numPowers * 51 + 21;
var y = rectBounds.Y + 10;
foreach (var sp in powers)
foreach (var kv in manager.Powers)
{
var sp = kv.Value;
var image = spsprites[sp.Info.Image];
if (sp.IsAvailable)
var drawPos = new float2(rectBounds.X + 5, y);
var rect = new Rectangle(rectBounds.X + 5, y, 64, 48);
if (rect.Contains(Viewport.LastMousePos.ToPoint()))
{
var drawPos = new float2(rectBounds.X + 5, y);
var rect = new Rectangle(rectBounds.X + 5, y, 64, 48);
var pos = drawPos.ToInt2();
var tl = new int2(pos.X-3,pos.Y-3);
var m = new int2(pos.X+64+3,pos.Y+48+3);
var br = tl + new int2(64+3+20,60);
if (sp.Info.LongDesc != null)
br += Game.Renderer.RegularFont.Measure(sp.Info.LongDesc.Replace("\\n", "\n"));
else
br += new int2(300,0);
if (rect.Contains(Viewport.LastMousePos.ToPoint()))
var border = WidgetUtils.GetBorderSizes("dialog4");
WidgetUtils.DrawPanelPartial("dialog4", Rectangle.FromLTRB(tl.X, tl.Y, m.X + border[3], m.Y),
PanelSides.Left | PanelSides.Top | PanelSides.Bottom);
WidgetUtils.DrawPanelPartial("dialog4", Rectangle.FromLTRB(m.X - border[2], tl.Y, br.X, m.Y + border[1]),
PanelSides.Top | PanelSides.Right);
WidgetUtils.DrawPanelPartial("dialog4", Rectangle.FromLTRB(m.X, m.Y - border[1], br.X, br.Y),
PanelSides.Left | PanelSides.Right | PanelSides.Bottom);
pos += new int2(77, 5);
Game.Renderer.BoldFont.DrawText(sp.Info.Description, pos, Color.White);
pos += new int2(0,20);
Game.Renderer.BoldFont.DrawText(WidgetUtils.FormatTime(sp.RemainingTime).ToString(), pos, Color.White);
Game.Renderer.BoldFont.DrawText("/ {0}".F(WidgetUtils.FormatTime(sp.TotalTime)), pos + new int2(45,0), Color.White);
if (sp.Info.LongDesc != null)
{
var pos = drawPos.ToInt2();
var tl = new int2(pos.X-3,pos.Y-3);
var m = new int2(pos.X+64+3,pos.Y+48+3);
var br = tl + new int2(64+3+20,60);
if (sp.Info.LongDesc != null)
br += Game.Renderer.RegularFont.Measure(sp.Info.LongDesc.Replace("\\n", "\n"));
else
br += new int2(300,0);
var border = WidgetUtils.GetBorderSizes("dialog4");
WidgetUtils.DrawPanelPartial("dialog4", Rectangle.FromLTRB(tl.X, tl.Y, m.X + border[3], m.Y),
PanelSides.Left | PanelSides.Top | PanelSides.Bottom);
WidgetUtils.DrawPanelPartial("dialog4", Rectangle.FromLTRB(m.X - border[2], tl.Y, br.X, m.Y + border[1]),
PanelSides.Top | PanelSides.Right);
WidgetUtils.DrawPanelPartial("dialog4", Rectangle.FromLTRB(m.X, m.Y - border[1], br.X, br.Y),
PanelSides.Left | PanelSides.Right | PanelSides.Bottom);
pos += new int2(77, 5);
Game.Renderer.BoldFont.DrawText(sp.Info.Description, pos, Color.White);
pos += new int2(0,20);
Game.Renderer.BoldFont.DrawText(WidgetUtils.FormatTime(sp.RemainingTime).ToString(), pos, Color.White);
Game.Renderer.BoldFont.DrawText("/ {0}".F(WidgetUtils.FormatTime(sp.TotalTime)), pos + new int2(45,0), Color.White);
if (sp.Info.LongDesc != null)
{
pos += new int2(0, 20);
Game.Renderer.RegularFont.DrawText(sp.Info.LongDesc.Replace("\\n", "\n"), pos, Color.White);
}
pos += new int2(0, 20);
Game.Renderer.RegularFont.DrawText(sp.Info.LongDesc.Replace("\\n", "\n"), pos, Color.White);
}
WidgetUtils.DrawSHP(image, drawPos, wr);
clock.PlayFetchIndex("idle",
() => (sp.TotalTime - sp.RemainingTime)
* (clock.CurrentSequence.Length - 1) / sp.TotalTime);
clock.Tick();
WidgetUtils.DrawSHP(clock.Image, drawPos, wr);
if (sp.IsReady)
{
ready.Play("ready");
WidgetUtils.DrawSHP(ready.Image, drawPos + new float2((64 - ready.Image.size.X) / 2, 2), wr);
}
buttons.Add(Pair.New(rect,HandleSupportPower(sp)));
y += 51;
}
WidgetUtils.DrawSHP(image, drawPos, wr);
clock.PlayFetchIndex("idle",
() => (sp.TotalTime - sp.RemainingTime)
* (clock.CurrentSequence.Length - 1) / sp.TotalTime);
clock.Tick();
WidgetUtils.DrawSHP(clock.Image, drawPos, wr);
if (sp.Ready)
{
ready.Play("ready");
WidgetUtils.DrawSHP(ready.Image, drawPos + new float2((64 - ready.Image.size.X) / 2, 2), wr);
}
else if (!sp.Active)
{
ready.Play("hold");
WidgetUtils.DrawSHP(ready.Image, drawPos + new float2((64 - ready.Image.size.X) / 2, 2), wr);
}
buttons.Add(Pair.New(rect,HandleSupportPower(kv.Key, manager)));
y += 51;
}
}
Action<MouseInput> HandleSupportPower(SupportPower sp)
Action<MouseInput> HandleSupportPower(string key, SupportPowerManager manager)
{
return mi => { if (mi.Button == MouseButton.Left) sp.Activate(); };
return mi => { if (mi.Button == MouseButton.Left) manager.Target(key); };
}
}
}

View File

@@ -33,6 +33,15 @@ FACT:
BuildSpeed: .4
LowPowerSlowdown: 3
BaseBuilding:
AirstrikePower:
Image: bombicnh
ChargeTime: 10
Description: Airstrike
LongDesc: Delivers a load of napalm on your target.
EndChargeSound: airredy1.aud
SelectTargetSound: select1.aud
UnitType: a10
# AllowMultiple: true
NUKE:
Inherits: ^Building

View File

@@ -1,35 +1,36 @@
Player:
PlaceBuilding:
TechTree:
NukePower:
Image: atomicnh
ChargeTime: 5
Description: Atom Bomb
LongDesc: Launches a nuclear missile at a target location.
Prerequisites: TMPL
BeginChargeSound:
EndChargeSound: nukavail.aud
SelectTargetSound: select1.aud
LaunchSound: nukemisl.aud
IonCannonPower:
Image: ionicnh
ChargeTime: 3
Description: Ion Cannon
LongDesc: Discharges the orbital Ion Cannon at your target.
Prerequisites: EYE
BeginChargeSound: ionchrg1.aud
EndChargeSound: ionredy1.aud
LaunchSound: ion1.aud
SelectTargetSound: select1.aud
AirstrikePower:
Image: bombicnh
ChargeTime: 4
Description: Airstrike
LongDesc: Delivers a load of napalm on your target.
Prerequisites: hq
EndChargeSound: airredy1.aud
SelectTargetSound: select1.aud
UnitType: a10
# NukePower:
# Image: atomicnh
# ChargeTime: 5
# Description: Atom Bomb
# LongDesc: Launches a nuclear missile at a target location.
# Prerequisites: TMPL
# BeginChargeSound:
# EndChargeSound: nukavail.aud
# SelectTargetSound: select1.aud
# LaunchSound: nukemisl.aud
# IonCannonPower:
# Image: ionicnh
# ChargeTime: 3
# Description: Ion Cannon
# LongDesc: Discharges the orbital Ion Cannon at your target.
# Prerequisites: EYE
# BeginChargeSound: ionchrg1.aud
# EndChargeSound: ionredy1.aud
# LaunchSound: ion1.aud
# SelectTargetSound: select1.aud
# AirstrikePower:
# Image: bombicnh
# ChargeTime: 4
# Description: Airstrike
# LongDesc: Delivers a load of napalm on your target.
# Prerequisites: hq
# EndChargeSound: airredy1.aud
# SelectTargetSound: select1.aud
# UnitType: a10
SupportPowerManager:
ConquestVictoryConditions:
PowerManager:
PlayerResources: