New extendable mechanism for disabling units

This commit is contained in:
Paul Chote
2010-01-25 20:18:12 +13:00
parent 3aa40c36cf
commit f0ae162fb0
11 changed files with 254 additions and 211 deletions

View File

@@ -1,50 +0,0 @@
using System.Collections.Generic;
using OpenRa.Graphics;
using OpenRa.Traits;
namespace OpenRa.Effects
{
class PowerDownIndicator : IEffect
{
Actor a;
Building b;
Animation anim = new Animation("powerdown");
bool removeNextFrame = false;
bool indicatorState = true;
int stateTicks = 0;
public PowerDownIndicator(Actor a)
{
this.a = a;
this.b = a.traits.Get<Building>();
anim.PlayRepeating("disabled");
}
public void Tick( World world )
{
if (removeNextFrame == true)
world.AddFrameEndTask(w => w.Remove(this));
// Fix off-by one frame bug with undisabling causing low-power
if (!b.Disabled || a.IsDead)
removeNextFrame = true;
// Flash power icon
if (++stateTicks == 15)
{
stateTicks = 0;
indicatorState = !indicatorState;
}
}
public IEnumerable<Renderable> Render()
{
foreach (var r in a.Render())
yield return r.WithPalette(PaletteType.Disabled);
if (b.ManuallyDisabled && indicatorState)
yield return new Renderable(anim.Image,
a.CenterLocation - .5f * anim.Image.size, PaletteType.Chrome);
}
}
}

View File

@@ -83,7 +83,6 @@
<Compile Include="Effects\GpsSatellite.cs" /> <Compile Include="Effects\GpsSatellite.cs" />
<Compile Include="Effects\InvulnEffect.cs" /> <Compile Include="Effects\InvulnEffect.cs" />
<Compile Include="Effects\MoveFlash.cs" /> <Compile Include="Effects\MoveFlash.cs" />
<Compile Include="Effects\PowerDownIndicator.cs" />
<Compile Include="Effects\RepairIndicator.cs" /> <Compile Include="Effects\RepairIndicator.cs" />
<Compile Include="Effects\SatelliteLaunch.cs" /> <Compile Include="Effects\SatelliteLaunch.cs" />
<Compile Include="Effects\Smoke.cs" /> <Compile Include="Effects\Smoke.cs" />
@@ -101,6 +100,7 @@
<Compile Include="Graphics\MappedImage.cs" /> <Compile Include="Graphics\MappedImage.cs" />
<Compile Include="Graphics\Minimap.cs" /> <Compile Include="Graphics\Minimap.cs" />
<Compile Include="Network\Connection.cs" /> <Compile Include="Network\Connection.cs" />
<Compile Include="Orders\PowerDownOrderGenerator.cs" />
<Compile Include="Resources1.Designer.cs"> <Compile Include="Resources1.Designer.cs">
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
@@ -109,7 +109,6 @@
<Compile Include="Effects\Missile.cs" /> <Compile Include="Effects\Missile.cs" />
<Compile Include="Network\OrderIO.cs" /> <Compile Include="Network\OrderIO.cs" />
<Compile Include="Network\OrderManager.cs" /> <Compile Include="Network\OrderManager.cs" />
<Compile Include="Orders\PowerDownOrderGenerator.cs" />
<Compile Include="Orders\RepairOrderGenerator.cs" /> <Compile Include="Orders\RepairOrderGenerator.cs" />
<Compile Include="Orders\SellOrderGenerator.cs" /> <Compile Include="Orders\SellOrderGenerator.cs" />
<Compile Include="Ore.cs" /> <Compile Include="Ore.cs" />
@@ -204,6 +203,7 @@
<Compile Include="Traits\Bridge.cs" /> <Compile Include="Traits\Bridge.cs" />
<Compile Include="Traits\Buildable.cs" /> <Compile Include="Traits\Buildable.cs" />
<Compile Include="Traits\Building.cs" /> <Compile Include="Traits\Building.cs" />
<Compile Include="Traits\CanPowerDown.cs" />
<Compile Include="Traits\Cargo.cs" /> <Compile Include="Traits\Cargo.cs" />
<Compile Include="Traits\Chronoshiftable.cs" /> <Compile Include="Traits\Chronoshiftable.cs" />
<Compile Include="Traits\ChronoshiftPaletteEffect.cs" /> <Compile Include="Traits\ChronoshiftPaletteEffect.cs" />

View File

@@ -24,8 +24,8 @@ namespace OpenRa.Orders
var loc = mi.Location + Game.viewport.Location; var loc = mi.Location + Game.viewport.Location;
var underCursor = world.FindUnits(loc, loc) var underCursor = world.FindUnits(loc, loc)
.Where(a => a.Owner == world.LocalPlayer .Where(a => a.Owner == world.LocalPlayer
&& a.traits.Contains<Building>() && a.traits.Contains<CanPowerDown>())
&& a.traits.Contains<Selectable>()).FirstOrDefault(); .FirstOrDefault();
if (underCursor != null) if (underCursor != null)
yield return new Order("PowerDown", underCursor); yield return new Order("PowerDown", underCursor);
@@ -39,7 +39,7 @@ namespace OpenRa.Orders
{ {
mi.Button = MouseButton.Left; mi.Button = MouseButton.Left;
return OrderInner(world, xy, mi).Any() return OrderInner(world, xy, mi).Any()
? Cursor.PowerDown : Cursor.PowerDown; ? Cursor.PowerDown : Cursor.RepairBlocked;
} }
} }
} }

View File

@@ -1,7 +1,10 @@
using System; using System;
using System.Linq;
using OpenRa.Effects; using OpenRa.Effects;
using OpenRa.GameRules; using OpenRa.GameRules;
using OpenRa.Traits.Activities; using OpenRa.Traits.Activities;
using OpenRa.Graphics;
using System.Collections.Generic;
namespace OpenRa.Traits namespace OpenRa.Traits
{ {
@@ -17,7 +20,6 @@ namespace OpenRa.Traits
public class BuildingInfo : OwnedActorInfo, ITraitInfo public class BuildingInfo : OwnedActorInfo, ITraitInfo
{ {
public readonly int Power = 0; public readonly int Power = 0;
public readonly bool RequiresPower = false;
public readonly bool BaseNormal = true; public readonly bool BaseNormal = true;
public readonly int Adjacent = 2; public readonly int Adjacent = 2;
public readonly bool Bib = false; public readonly bool Bib = false;
@@ -31,25 +33,18 @@ namespace OpenRa.Traits
public object Create(Actor self) { return new Building(self); } public object Create(Actor self) { return new Building(self); }
} }
public class Building : INotifyDamage, IResolveOrder, ITick public class Building : INotifyDamage, IResolveOrder, ITick, IRenderModifier
{ {
readonly Actor self; readonly Actor self;
public readonly BuildingInfo Info; public readonly BuildingInfo Info;
[Sync] [Sync]
bool isRepairing = false; bool isRepairing = false;
[Sync]
bool manuallyDisabled = false;
public bool ManuallyDisabled { get { return manuallyDisabled; } }
public bool Disabled public bool Disabled
{ {
get get { return self.traits.WithInterface<IDisable>().Any(t => t.Disabled); }
{
return (manuallyDisabled ||
(Info.RequiresPower && self.Owner.GetPowerState() != PowerState.Normal));
}
} }
bool wasDisabled = false;
public Building(Actor self) public Building(Actor self)
{ {
this.self = self; this.self = self;
@@ -60,15 +55,17 @@ namespace OpenRa.Traits
public int GetPowerUsage() public int GetPowerUsage()
{ {
if (manuallyDisabled) var modifier = self.traits
return 0; .WithInterface<IPowerModifier>()
.Select(t => t.GetPowerModifier())
.Product();
var maxHP = self.Info.Traits.Get<BuildingInfo>().HP; var maxHP = self.Info.Traits.Get<BuildingInfo>().HP;
if (Info.Power > 0) if (Info.Power > 0)
return (self.Health * Info.Power) / maxHP; return (int)(modifier*(self.Health * Info.Power) / maxHP);
else else
return Info.Power; return (int)(modifier * Info.Power);
} }
public void Damaged(Actor self, AttackInfo e) public void Damaged(Actor self, AttackInfo e)
@@ -89,23 +86,12 @@ namespace OpenRa.Traits
{ {
isRepairing = !isRepairing; isRepairing = !isRepairing;
} }
if (order.OrderString == "PowerDown")
{
manuallyDisabled = !manuallyDisabled;
Sound.Play((manuallyDisabled) ? "bleep12.aud" : "bleep11.aud");
}
} }
int remainingTicks; int remainingTicks;
public void Tick(Actor self) public void Tick(Actor self)
{ {
// If the disabled state has changed since the last frame
if (Disabled ^ wasDisabled
&& (wasDisabled = Disabled)) // Yes, I mean assignment
self.World.AddFrameEndTask(w => w.Add(new PowerDownIndicator(self)));
if (!isRepairing) return; if (!isRepairing) return;
if (remainingTicks == 0) if (remainingTicks == 0)
@@ -132,5 +118,15 @@ namespace OpenRa.Traits
else else
--remainingTicks; --remainingTicks;
} }
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r)
{
foreach (var a in r)
{
yield return a;
if (Disabled)
yield return a.WithPalette(PaletteType.Disabled);
}
}
} }
} }

View File

@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRa.Traits;
namespace OpenRa.Traits
{
public class CanPowerDownInfo : ITraitInfo
{
public object Create(Actor self) { return new CanPowerDown(self); }
}
public class CanPowerDown : IDisable, IPowerModifier, IResolveOrder
{
readonly Actor self;
[Sync]
bool IsDisabled = false;
public CanPowerDown(Actor self)
{
this.self = self;
}
public bool Disabled
{
get { return IsDisabled; }
set { IsDisabled = value; }
}
public float GetPowerModifier() { return (IsDisabled) ? 0.0f : 1.0f; }
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "PowerDown")
{
IsDisabled = !IsDisabled;
Sound.Play((IsDisabled) ? "bleep12.aud" : "bleep11.aud");
}
}
}
}

View File

@@ -26,7 +26,9 @@ namespace OpenRa.Traits
public interface IAcceptSpy { void OnInfiltrate(Actor self, Actor spy); } public interface IAcceptSpy { void OnInfiltrate(Actor self, Actor spy); }
public interface ICustomTerrain { float GetCost(int2 p, UnitMovementType umt); } public interface ICustomTerrain { float GetCost(int2 p, UnitMovementType umt); }
public interface IDisable { bool Disabled { get; set; } }
interface IProducer interface IProducer
{ {
bool Produce( Actor self, ActorInfo producee ); bool Produce( Actor self, ActorInfo producee );
@@ -37,6 +39,7 @@ namespace OpenRa.Traits
public interface IRenderModifier { IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r); } public interface IRenderModifier { IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r); }
public interface IDamageModifier { float GetDamageModifier(); } public interface IDamageModifier { float GetDamageModifier(); }
public interface ISpeedModifier { float GetSpeedModifier(); } public interface ISpeedModifier { float GetSpeedModifier(); }
public interface IPowerModifier { float GetPowerModifier(); }
public interface IPaletteModifier { void AdjustPalette(Bitmap b); } public interface IPaletteModifier { void AdjustPalette(Bitmap b); }
public interface IPips { IEnumerable<PipType> GetPips(Actor self); } public interface IPips { IEnumerable<PipType> GetPips(Actor self); }
public interface ITags { IEnumerable<TagType> GetTags(); } public interface ITags { IEnumerable<TagType> GetTags(); }

View File

@@ -53,6 +53,7 @@
<Compile Include="C4Demolition.cs" /> <Compile Include="C4Demolition.cs" />
<Compile Include="EngineerCapture.cs" /> <Compile Include="EngineerCapture.cs" />
<Compile Include="InfiltrateForSonarPulse.cs" /> <Compile Include="InfiltrateForSonarPulse.cs" />
<Compile Include="RequiresPower.cs" />
<Compile Include="Mine.cs" /> <Compile Include="Mine.cs" />
<Compile Include="MineImmune.cs" /> <Compile Include="MineImmune.cs" />
<Compile Include="Minelayer.cs" /> <Compile Include="Minelayer.cs" />
@@ -72,6 +73,9 @@
<Name>OpenRa.Game</Name> <Name>OpenRa.Game</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Orders\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRa.Traits;
namespace OpenRa.Mods.RA
{
class RequiresPowerInfo : ITraitInfo
{
public object Create(Actor self) { return new RequiresPower(self); }
}
class RequiresPower : IDisable
{
readonly Actor self;
public RequiresPower( Actor self )
{
this.self = self;
}
public bool Disabled
{
get { return (self.Owner.GetPowerState() != PowerState.Normal); }
set {} // Cannot explicity set
}
}
}

View File

@@ -95,7 +95,6 @@ namespace RulesConverter
{ "Building", new PL { { "Building", new PL {
{ "Power", "Power" }, { "Power", "Power" },
{ "RequiresPower", "Powered" },
{ "Footprint", "Footprint" }, { "Footprint", "Footprint" },
{ "Dimensions", "Dimensions" }, { "Dimensions", "Dimensions" },
{ "Capturable", "Capturable" }, { "Capturable", "Capturable" },

View File

@@ -60,6 +60,8 @@ MGG:
Range: 10 Range: 10
GAP: GAP:
RequiresPower:
CanPowerDown:
GeneratesGap: GeneratesGap:
Range: 10 Range: 10
@@ -108,4 +110,19 @@ SPEN:
InfiltrateForSonarPulse: InfiltrateForSonarPulse:
SYRD: SYRD:
InfiltrateForSonarPulse: InfiltrateForSonarPulse:
IRON:
RequiresPower:
CanPowerDown:
PDOX:
RequiresPower:
CanPowerDown:
TSLA:
RequiresPower:
CanPowerDown:
AGUN:
RequiresPower:
CanPowerDown:
DOME:
RequiresPower:
CanPowerDown:

View File

@@ -78,6 +78,8 @@ MGG:
Offset: 0,6,0,-3 Offset: 0,6,0,-3
GAP: GAP:
RequiresPower:
CanPowerDown:
GeneratesGap: GeneratesGap:
Range: 10 Range: 10
Inherits: ^Building Inherits: ^Building
@@ -90,7 +92,6 @@ GAP:
LongDesc: Regenerates the Fog of War nearby, \nobscuring the area.\n Unarmed LongDesc: Regenerates the Fog of War nearby, \nobscuring the area.\n Unarmed
Building: Building:
Power: -60 Power: -60
RequiresPower: true
Footprint: _ x Footprint: _ x
Dimensions: 1,2 Dimensions: 1,2
Capturable: true Capturable: true
@@ -285,6 +286,135 @@ SYRD:
Produces: Ship Produces: Ship
IronCurtainable: IronCurtainable:
IRON:
RequiresPower:
CanPowerDown:
Inherits: ^Building
Buildable:
TechLevel: 12
Prerequisites: stek
Owner: soviet
Cost: 2800
Description: Iron Curtain
LongDesc: Makes a group of units invulnerable for a \nshort time.\n Special Ability: Invulnerability
Building:
Power: -200
Footprint: xx xx
Dimensions: 2,2
Capturable: true
HP: 400
Armor: wood
Crewed: yes
Sight: 10
RenderBuilding:
IronCurtainable:
IronCurtain:
PDOX:
RequiresPower:
CanPowerDown:
Inherits: ^Building
Buildable:
TechLevel: 12
Prerequisites: atek
Owner: allies
Cost: 2800
Description: Chronosphere
LongDesc: Teleports a unit from one place \nto another, for a limited time.\n Special Ability: Chronoshift
Building:
Power: -200
Footprint: xx xx
Dimensions: 2,2
Capturable: true
HP: 400
Armor: wood
Crewed: yes
Sight: 10
RenderBuilding:
Chronosphere:
IronCurtainable:
TSLA:
RequiresPower:
CanPowerDown:
Inherits: ^Building
Buildable:
TechLevel: 7
Prerequisites: weap
Owner: soviet
Cost: 1500
Description: Tesla Coil
LongDesc: Advanced base defense. Requires power\nto operate.\n Strong vs Tanks, Infantry\n Weak vs Aircraft
Building:
Power: -150
Footprint: _ x
Dimensions: 1,2
HP: 400
Armor: heavy
Crewed: yes
Sight: 8
Turreted:
RenderBuildingCharge:
AttackTurreted:
PrimaryWeapon: TeslaZap
FireDelay: 8
AutoTarget:
IronCurtainable:
AGUN:
RequiresPower:
CanPowerDown:
Inherits: ^Building
Buildable:
TechLevel: 5
Prerequisites: dome
Owner: allies
Cost: 600
Description: AA Gun
LongDesc: Anti-Air base defense.\n Strong vs Aircraft\n Weak vs Infantry, Tanks
Building:
Power: -50
Footprint: _ x
Dimensions: 1,2
HP: 400
Armor: heavy
Crewed: yes
Sight: 6
Turreted:
ROT: 15
InitialFacing: 224
RenderBuildingTurreted:
AttackTurreted:
PrimaryWeapon: ZSU-23
SecondaryWeapon: ZSU-23
AutoTarget:
IronCurtainable:
DOME:
RequiresPower:
CanPowerDown:
Inherits: ^Building
Buildable:
TechLevel: 3
Prerequisites: proc
Owner: allies,soviet
Cost: 1000
Description: Radar Dome
LongDesc: Provides an overview of the battlefield.\n Requires power to operate.
Building:
Power: -40
Footprint: xx xx
Dimensions: 2,2
Capturable: true
Bib: yes
HP: 1000
Armor: wood
Crewed: yes
Sight: 10
RenderBuilding:
ProvidesRadar:
IronCurtainable:
V2RL: V2RL:
Inherits: ^Vehicle Inherits: ^Vehicle
Buildable: Buildable:
@@ -882,52 +1012,6 @@ U2:
WithShadow: WithShadow:
IronCurtainable: IronCurtainable:
IRON:
Inherits: ^Building
Buildable:
TechLevel: 12
Prerequisites: stek
Owner: soviet
Cost: 2800
Description: Iron Curtain
LongDesc: Makes a group of units invulnerable for a \nshort time.\n Special Ability: Invulnerability
Building:
Power: -200
RequiresPower: true
Footprint: xx xx
Dimensions: 2,2
Capturable: true
HP: 400
Armor: wood
Crewed: yes
Sight: 10
RenderBuilding:
IronCurtainable:
IronCurtain:
PDOX:
Inherits: ^Building
Buildable:
TechLevel: 12
Prerequisites: atek
Owner: allies
Cost: 2800
Description: Chronosphere
LongDesc: Teleports a unit from one place \nto another, for a limited time.\n Special Ability: Chronoshift
Building:
Power: -200
RequiresPower: true
Footprint: xx xx
Dimensions: 2,2
Capturable: true
HP: 400
Armor: wood
Crewed: yes
Sight: 10
RenderBuilding:
Chronosphere:
IronCurtainable:
PBOX: PBOX:
Inherits: ^Building Inherits: ^Building
Buildable: Buildable:
@@ -976,32 +1060,6 @@ HBOX:
AutoTarget: AutoTarget:
IronCurtainable: IronCurtainable:
TSLA:
Inherits: ^Building
Buildable:
TechLevel: 7
Prerequisites: weap
Owner: soviet
Cost: 1500
Description: Tesla Coil
LongDesc: Advanced base defense. Requires power\nto operate.\n Strong vs Tanks, Infantry\n Weak vs Aircraft
Building:
Power: -150
RequiresPower: true
Footprint: _ x
Dimensions: 1,2
HP: 400
Armor: heavy
Crewed: yes
Sight: 8
Turreted:
RenderBuildingCharge:
AttackTurreted:
PrimaryWeapon: TeslaZap
FireDelay: 8
AutoTarget:
IronCurtainable:
GUN: GUN:
Inherits: ^Building Inherits: ^Building
Buildable: Buildable:
@@ -1028,34 +1086,6 @@ GUN:
AutoTarget: AutoTarget:
IronCurtainable: IronCurtainable:
AGUN:
Inherits: ^Building
Buildable:
TechLevel: 5
Prerequisites: dome
Owner: allies
Cost: 600
Description: AA Gun
LongDesc: Anti-Air base defense.\n Strong vs Aircraft\n Weak vs Infantry, Tanks
Building:
Power: -50
RequiresPower: true
Footprint: _ x
Dimensions: 1,2
HP: 400
Armor: heavy
Crewed: yes
Sight: 6
Turreted:
ROT: 15
InitialFacing: 224
RenderBuildingTurreted:
AttackTurreted:
PrimaryWeapon: ZSU-23
SecondaryWeapon: ZSU-23
AutoTarget:
IronCurtainable:
FTUR: FTUR:
Inherits: ^Building Inherits: ^Building
Buildable: Buildable:
@@ -1251,30 +1281,6 @@ HPAD:
Reservable: Reservable:
IronCurtainable: IronCurtainable:
DOME:
Inherits: ^Building
Buildable:
TechLevel: 3
Prerequisites: proc
Owner: allies,soviet
Cost: 1000
Description: Radar Dome
LongDesc: Provides an overview of the battlefield.\n Requires power to operate.
Building:
Power: -40
RequiresPower: true
Footprint: xx xx
Dimensions: 2,2
Capturable: true
Bib: yes
HP: 1000
Armor: wood
Crewed: yes
Sight: 10
RenderBuilding:
ProvidesRadar:
IronCurtainable:
AFLD: AFLD:
Inherits: ^Building Inherits: ^Building
Buildable: Buildable: