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:
@@ -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> { }
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -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());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {}
|
||||
}
|
||||
*/
|
||||
@@ -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 { }
|
||||
}
|
||||
*/
|
||||
@@ -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 { }
|
||||
}
|
||||
*/
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -9,7 +9,7 @@
|
||||
#endregion
|
||||
|
||||
using OpenRA.Traits;
|
||||
|
||||
/*
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
public class SonarPulsePowerInfo : SupportPowerInfo
|
||||
@@ -44,3 +44,4 @@ namespace OpenRA.Mods.RA
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
194
OpenRA.Mods.RA/SupportPowers/SupportPowerManager.cs
Executable file
194
OpenRA.Mods.RA/SupportPowers/SupportPowerManager.cs
Executable 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"; }
|
||||
}
|
||||
}
|
||||
@@ -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); };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user