diff --git a/OpenRa.Game/Actor.cs b/OpenRa.Game/Actor.cs index 9d998a2280..42c22fdafc 100755 --- a/OpenRa.Game/Actor.cs +++ b/OpenRa.Game/Actor.cs @@ -7,7 +7,8 @@ using IjwFramework.Types; using OpenRa.FileFormats; using OpenRa.Game.GameRules; using OpenRa.Game.Graphics; -using System.Drawing; +using System.Drawing; +using OpenRa.Game.Traits; namespace OpenRa.Game { @@ -105,10 +106,22 @@ namespace OpenRa.Game Game.world.AddFrameEndTask(w => w.Remove(this)); - if (Owner == Game.LocalPlayer) - Game.PlaySound("unitlst1.aud", false); - - /* todo: explosion */ + if (Owner == Game.LocalPlayer && !traits.Contains()) + Game.PlaySound("unitlst1.aud", false); + + if (traits.Contains()) + { + Game.PlaySound("kaboom22.aud", false); + // todo: spawn explosion sprites + } + } + + var halfStrength = unitInfo.Strength / 2; + if (Health < halfStrength && (Health + damage) >= halfStrength) + { + /* we just went below half health! */ + foreach (var nd in traits.WithInterface()) + nd.Damaged(this, DamageState.Half); } } } diff --git a/OpenRa.Game/Cursor.cs b/OpenRa.Game/Cursor.cs index 811720a8d8..2a5d138fc6 100644 --- a/OpenRa.Game/Cursor.cs +++ b/OpenRa.Game/Cursor.cs @@ -24,5 +24,6 @@ namespace OpenRa.Game public static Cursor MoveBlocked { get { return new Cursor("move-blocked"); } } public static Cursor Attack { get { return new Cursor("attack"); } } public static Cursor Deploy { get { return new Cursor("deploy"); } } + public static Cursor Enter { get { return new Cursor("enter"); } } } } diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index 34349e70fc..981ec18d40 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -76,6 +76,7 @@ + @@ -129,6 +130,7 @@ + diff --git a/OpenRa.Game/Order.cs b/OpenRa.Game/Order.cs index 112998a518..5b99845060 100644 --- a/OpenRa.Game/Order.cs +++ b/OpenRa.Game/Order.cs @@ -111,5 +111,10 @@ namespace OpenRa.Game { return new Order(subject, "BuildUnit", null, null, int2.Zero, unitName, Cursor.Default); } + + public static Order DeliverOre(Actor subject, Actor target) + { + return new Order(subject.Owner, "DeliverOre", subject, target, int2.Zero, null, Cursor.Enter); + } } } diff --git a/OpenRa.Game/Sidebar.cs b/OpenRa.Game/Sidebar.cs index 4394317049..27bf82e4be 100644 --- a/OpenRa.Game/Sidebar.cs +++ b/OpenRa.Game/Sidebar.cs @@ -218,6 +218,8 @@ namespace OpenRa.Game * (25 * 60) /* frames per min */ /* todo: build acceleration, if we do that */ / 1000; + time = .05f * time; /* temporary hax so we can build stuff fast for test */ + Action complete = null; if (IsAutoCompleting(group)) complete = () => Build(item); diff --git a/OpenRa.Game/Traits/AcceptsOre.cs b/OpenRa.Game/Traits/AcceptsOre.cs new file mode 100644 index 0000000000..0ee0922f2d --- /dev/null +++ b/OpenRa.Game/Traits/AcceptsOre.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa.Game.Traits +{ + class AcceptsOre + { + public AcceptsOre(Actor self) + { + /* create the free harvester! */ + Game.world.AddFrameEndTask( + w => + { + var harvester = new Actor("harv", self.Location + new int2(1, 2), self.Owner); + harvester.traits.Get().facing = 64; + w.Add(harvester); + }); + } + } +} diff --git a/OpenRa.Game/Traits/Harvester.cs b/OpenRa.Game/Traits/Harvester.cs new file mode 100644 index 0000000000..a41b70b40d --- /dev/null +++ b/OpenRa.Game/Traits/Harvester.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa.Game.Traits +{ + class Harvester : IOrder + { + public Order Order(Actor self, int2 xy, bool lmb, Actor underCursor) + { + if (underCursor != null + && underCursor.Owner == self.Owner + && underCursor.traits.Contains()) + return OpenRa.Game.Order.DeliverOre(self, underCursor); + + /* todo: harvest order when on ore */ + + return null; + } + + public Harvester(Actor self) { } + } +} diff --git a/OpenRa.Game/Traits/RenderBuilding.cs b/OpenRa.Game/Traits/RenderBuilding.cs index b294327c18..7b981103c2 100644 --- a/OpenRa.Game/Traits/RenderBuilding.cs +++ b/OpenRa.Game/Traits/RenderBuilding.cs @@ -10,7 +10,7 @@ using OpenRa.Game; namespace OpenRa.Game.Traits { - class RenderBuilding : RenderSimple, INotifyRemoved + class RenderBuilding : RenderSimple, INotifyDamage { const int SmallBibStart = 1; const int LargeBibStart = 5; @@ -51,6 +51,21 @@ namespace OpenRa.Game.Traits yield return Pair.New(anim.Image, 24f * (float2)self.Location); } - public void Removed(Actor self) { DoBib(self, true); } + public void Damaged(Actor self, DamageState state) + { + switch( state ) + { + case DamageState.Normal: + anim.PlayRepeating("idle"); /* todo: make interaction?? this should only get called on half->ok */ + break; + case DamageState.Half: + anim.PlayRepeating("damaged-idle"); + Game.PlaySound("kaboom1.aud", false); /* todo: maybe sep. sound stuff from visual ?? */ + break; + case DamageState.Dead: + DoBib(self, true); + break; + } + } } } diff --git a/OpenRa.Game/Traits/TraitsInterfaces.cs b/OpenRa.Game/Traits/TraitsInterfaces.cs index 3b90e629d9..07964cb483 100644 --- a/OpenRa.Game/Traits/TraitsInterfaces.cs +++ b/OpenRa.Game/Traits/TraitsInterfaces.cs @@ -7,8 +7,10 @@ using IjwFramework.Types; namespace OpenRa.Game.Traits { + enum DamageState { Normal, Half, Dead }; + interface ITick { void Tick(Actor self); } interface IRender { IEnumerable> Render(Actor self); } interface IOrder { Order Order(Actor self, int2 xy, bool lmb, Actor underCursor); } - interface INotifyRemoved { void Removed(Actor self); } + interface INotifyDamage { void Damaged(Actor self, DamageState ds); } } diff --git a/OpenRa.Game/UnitOrders.cs b/OpenRa.Game/UnitOrders.cs index 0eb187d92e..f4712ef228 100755 --- a/OpenRa.Game/UnitOrders.cs +++ b/OpenRa.Game/UnitOrders.cs @@ -50,6 +50,14 @@ namespace OpenRa.Game mobile.QueueActivity( new Traits.Activities.DeployMcv() ); break; } + case "DeliverOre": + { + var mobile = order.Subject.traits.Get(); + mobile.QueueActivity(new Mobile.MoveTo(order.TargetActor.Location + new int2(1, 2))); + mobile.QueueActivity(new Mobile.Turn(64)); + /* todo: actual deliver activity! */ + break; + } case "PlaceBuilding": { Game.world.AddFrameEndTask( _ => diff --git a/OpenRa.Game/World.cs b/OpenRa.Game/World.cs index 22f2e14e03..d31a26c47c 100644 --- a/OpenRa.Game/World.cs +++ b/OpenRa.Game/World.cs @@ -24,8 +24,8 @@ namespace OpenRa.Game public event Action ActorRemoved = a => { a.Health = 0; /* make sure everyone sees it as dead */ - foreach (var nr in a.traits.WithInterface()) - nr.Removed(a); + foreach (var nr in a.traits.WithInterface()) + nr.Damaged(a, DamageState.Dead); }; public void Tick() @@ -36,8 +36,9 @@ namespace OpenRa.Game Renderer.waterFrame += 0.00125f * Game.timestep; Game.viewport.Tick(); - foreach (Action a in frameEndActions) a(this); - frameEndActions.Clear(); + var acts = frameEndActions; + frameEndActions = new List>(); + foreach (var a in acts) a(this); } public IEnumerable Actors { get { return actors; } } diff --git a/units.ini b/units.ini index 78311be792..d28f4f7e4a 100755 --- a/units.ini +++ b/units.ini @@ -42,7 +42,7 @@ Description=Artillery Traits=Mobile, RenderUnit [HARV] Description=Ore Truck -Traits=Mobile, RenderUnit +Traits=Mobile, Harvester, RenderUnit [MCV] Description=Mobile Construction Vehicle Traits=Mobile, McvDeploy, RenderUnit @@ -242,7 +242,7 @@ Footprint=xxx xxx xxx Produces=Building [PROC] Description=Ore Refinery -Traits=Building, RenderBuilding +Traits=Building, RenderBuilding, AcceptsOre Dimensions=3,3 Footprint=_x_ xxx x== [SILO]