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

View File

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

View File

@@ -1,7 +1,10 @@
using System;
using System.Linq;
using OpenRa.Effects;
using OpenRa.GameRules;
using OpenRa.Traits.Activities;
using OpenRa.Graphics;
using System.Collections.Generic;
namespace OpenRa.Traits
{
@@ -17,7 +20,6 @@ namespace OpenRa.Traits
public class BuildingInfo : OwnedActorInfo, ITraitInfo
{
public readonly int Power = 0;
public readonly bool RequiresPower = false;
public readonly bool BaseNormal = true;
public readonly int Adjacent = 2;
public readonly bool Bib = false;
@@ -31,24 +33,17 @@ namespace OpenRa.Traits
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;
public readonly BuildingInfo Info;
[Sync]
bool isRepairing = false;
[Sync]
bool manuallyDisabled = false;
public bool ManuallyDisabled { get { return manuallyDisabled; } }
public bool Disabled
{
get
{
return (manuallyDisabled ||
(Info.RequiresPower && self.Owner.GetPowerState() != PowerState.Normal));
}
get { return self.traits.WithInterface<IDisable>().Any(t => t.Disabled); }
}
bool wasDisabled = false;
public Building(Actor self)
{
@@ -60,15 +55,17 @@ namespace OpenRa.Traits
public int GetPowerUsage()
{
if (manuallyDisabled)
return 0;
var modifier = self.traits
.WithInterface<IPowerModifier>()
.Select(t => t.GetPowerModifier())
.Product();
var maxHP = self.Info.Traits.Get<BuildingInfo>().HP;
if (Info.Power > 0)
return (self.Health * Info.Power) / maxHP;
return (int)(modifier*(self.Health * Info.Power) / maxHP);
else
return Info.Power;
return (int)(modifier * Info.Power);
}
public void Damaged(Actor self, AttackInfo e)
@@ -89,23 +86,12 @@ namespace OpenRa.Traits
{
isRepairing = !isRepairing;
}
if (order.OrderString == "PowerDown")
{
manuallyDisabled = !manuallyDisabled;
Sound.Play((manuallyDisabled) ? "bleep12.aud" : "bleep11.aud");
}
}
int remainingTicks;
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 (remainingTicks == 0)
@@ -132,5 +118,15 @@ namespace OpenRa.Traits
else
--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

@@ -27,6 +27,8 @@ namespace OpenRa.Traits
public interface ICustomTerrain { float GetCost(int2 p, UnitMovementType umt); }
public interface IDisable { bool Disabled { get; set; } }
interface IProducer
{
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 IDamageModifier { float GetDamageModifier(); }
public interface ISpeedModifier { float GetSpeedModifier(); }
public interface IPowerModifier { float GetPowerModifier(); }
public interface IPaletteModifier { void AdjustPalette(Bitmap b); }
public interface IPips { IEnumerable<PipType> GetPips(Actor self); }
public interface ITags { IEnumerable<TagType> GetTags(); }

View File

@@ -53,6 +53,7 @@
<Compile Include="C4Demolition.cs" />
<Compile Include="EngineerCapture.cs" />
<Compile Include="InfiltrateForSonarPulse.cs" />
<Compile Include="RequiresPower.cs" />
<Compile Include="Mine.cs" />
<Compile Include="MineImmune.cs" />
<Compile Include="Minelayer.cs" />
@@ -72,6 +73,9 @@
<Name>OpenRa.Game</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Orders\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- 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.

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 {
{ "Power", "Power" },
{ "RequiresPower", "Powered" },
{ "Footprint", "Footprint" },
{ "Dimensions", "Dimensions" },
{ "Capturable", "Capturable" },

View File

@@ -60,6 +60,8 @@ MGG:
Range: 10
GAP:
RequiresPower:
CanPowerDown:
GeneratesGap:
Range: 10
@@ -109,3 +111,18 @@ SPEN:
SYRD:
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
GAP:
RequiresPower:
CanPowerDown:
GeneratesGap:
Range: 10
Inherits: ^Building
@@ -90,7 +92,6 @@ GAP:
LongDesc: Regenerates the Fog of War nearby, \nobscuring the area.\n Unarmed
Building:
Power: -60
RequiresPower: true
Footprint: _ x
Dimensions: 1,2
Capturable: true
@@ -285,6 +286,135 @@ SYRD:
Produces: Ship
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:
Inherits: ^Vehicle
Buildable:
@@ -882,52 +1012,6 @@ U2:
WithShadow:
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:
Inherits: ^Building
Buildable:
@@ -976,32 +1060,6 @@ HBOX:
AutoTarget:
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:
Inherits: ^Building
Buildable:
@@ -1028,34 +1086,6 @@ GUN:
AutoTarget:
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:
Inherits: ^Building
Buildable:
@@ -1251,30 +1281,6 @@ HPAD:
Reservable:
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:
Inherits: ^Building
Buildable: