From cbfd70b924a8be6f0b0d600953902c8a5ea8e4b0 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Sat, 19 Dec 2009 09:31:17 +1300 Subject: [PATCH 1/3] oops. that crashed when there were no mods --- OpenRa.Game/Exts.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenRa.Game/Exts.cs b/OpenRa.Game/Exts.cs index cc04e81a91..3de1b767a5 100644 --- a/OpenRa.Game/Exts.cs +++ b/OpenRa.Game/Exts.cs @@ -25,7 +25,7 @@ namespace OpenRa.Game public static float Product(this IEnumerable xs) { - return xs.Aggregate((a, x) => a * x); + return xs.Aggregate(1f, (a, x) => a * x); } } } From 10431a5038049a5b771ad8f414992fce20e53959 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Sat, 19 Dec 2009 09:33:14 +1300 Subject: [PATCH 2/3] fixed chrisf/#6: base defenses attacking before finished --- OpenRa.Game/Traits/AttackTurreted.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/OpenRa.Game/Traits/AttackTurreted.cs b/OpenRa.Game/Traits/AttackTurreted.cs index 286d97bb2c..67e9f022a1 100755 --- a/OpenRa.Game/Traits/AttackTurreted.cs +++ b/OpenRa.Game/Traits/AttackTurreted.cs @@ -3,7 +3,7 @@ using OpenRa.Game.GameRules; namespace OpenRa.Game.Traits { - class AttackTurreted : AttackBase + class AttackTurreted : AttackBase, INotifyBuildComplete { public AttackTurreted( Actor self ) : base(self) { self.traits.Get(); } @@ -13,6 +13,9 @@ namespace OpenRa.Game.Traits if( !CanAttack( self ) ) return; + if (self.traits.Contains() && !buildComplete) + return; /* base defenses can't do anything until they finish building !*/ + var turreted = self.traits.Get(); turreted.desiredFacing = Util.GetFacing( target.CenterLocation - self.CenterLocation, turreted.turretFacing ); if( turreted.desiredFacing != turreted.turretFacing ) @@ -38,5 +41,8 @@ namespace OpenRa.Game.Traits Math.Max( 0, (int)Rules.WeaponInfo[ weapon ].Range - RangeTolerance ) ) ); self.traits.Get().target = order.TargetActor; } + + bool buildComplete = false; + public void BuildingComplete(Actor self) { buildComplete = true; } } } From 07b5b4c164ae7441f2c2ef4d8247250025bafd7b Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Sat, 19 Dec 2009 10:42:35 +1300 Subject: [PATCH 3/3] revamp of damage notifs; added Explodes --- OpenRa.Game/Actor.cs | 36 ++++++++++--------- OpenRa.Game/OpenRa.Game.csproj | 2 ++ OpenRa.Game/Traits/AttackInfo.cs | 17 +++++++++ OpenRa.Game/Traits/Building.cs | 8 ++++- OpenRa.Game/Traits/Explodes.cs | 23 ++++++++++++ OpenRa.Game/Traits/RenderBuilding.cs | 7 ++-- OpenRa.Game/Traits/RenderBuildingTurreted.cs | 6 ++-- .../Traits/RenderBuildingWarFactory.cs | 7 ++-- OpenRa.Game/Traits/RenderInfantry.cs | 10 +++--- OpenRa.Game/Traits/RenderUnit.cs | 26 ++++++-------- OpenRa.Game/Traits/TakeCover.cs | 7 ++-- OpenRa.Game/Traits/TraitsInterfaces.cs | 3 +- OpenRa.Game/Traits/Unit.cs | 9 ++++- OpenRa.Game/World.cs | 9 ++--- sequences.xml | 1 + units.ini | 17 ++++++++- 16 files changed, 128 insertions(+), 60 deletions(-) create mode 100644 OpenRa.Game/Traits/AttackInfo.cs create mode 100644 OpenRa.Game/Traits/Explodes.cs diff --git a/OpenRa.Game/Actor.cs b/OpenRa.Game/Actor.cs index 7399465b2f..85f15b5c24 100755 --- a/OpenRa.Game/Actor.cs +++ b/OpenRa.Game/Actor.cs @@ -108,12 +108,19 @@ namespace OpenRa.Game public bool IsDead { get { return Health <= 0; } } + DamageState GetDamageState() + { + if (Health <= 0) return DamageState.Dead; + var halfStrength = Info.Strength * Rules.General.ConditionYellow; + return Health < halfStrength ? DamageState.Half : DamageState.Normal; + } + public void InflictDamage(Actor attacker, int damage, WarheadInfo warhead) { - /* todo: auto-retaliate, etc */ - if (IsDead) return; /* overkill! don't count extra hits as more kills! */ + var oldState = GetDamageState(); + /* apply the damage modifiers, if we have any. */ damage = (int)traits.WithInterface().Aggregate( (float)damage, (a, t) => t.GetDamageModifier() * a); @@ -126,24 +133,19 @@ namespace OpenRa.Game attacker.Owner.Kills++; Game.world.AddFrameEndTask(w => w.Remove(this)); - - if (Owner == Game.LocalPlayer && !traits.Contains()) - Sound.Play("unitlst1.aud"); - - if (traits.Contains()) - Sound.Play("kaboom22.aud"); } - var halfStrength = Info.Strength * Rules.General.ConditionYellow; - if (Health < halfStrength && (Health + damage) >= halfStrength) - { - /* we just went below half health! */ - foreach (var nd in traits.WithInterface()) - nd.Damaged(this, DamageState.Half); - } + var newState = GetDamageState(); - foreach (var ndx in traits.WithInterface()) - ndx.Damaged(this, damage, warhead); + foreach (var nd in traits.WithInterface()) + nd.Damaged(this, new AttackInfo + { + Attacker = attacker, + Damage = damage, + DamageState = newState, + DamageStateChanged = newState != oldState, + Warhead = warhead + }); } public void QueueActivity( IActivity nextActivity ) diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index ba20ebf291..b75781e02e 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -158,9 +158,11 @@ + + diff --git a/OpenRa.Game/Traits/AttackInfo.cs b/OpenRa.Game/Traits/AttackInfo.cs new file mode 100644 index 0000000000..52ad8177d5 --- /dev/null +++ b/OpenRa.Game/Traits/AttackInfo.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRa.Game.GameRules; + +namespace OpenRa.Game.Traits +{ + class AttackInfo + { + public Actor Attacker; + public WarheadInfo Warhead; + public int Damage; + public DamageState DamageState; + public bool DamageStateChanged; + } +} diff --git a/OpenRa.Game/Traits/Building.cs b/OpenRa.Game/Traits/Building.cs index a0f9b8b786..df080e2188 100644 --- a/OpenRa.Game/Traits/Building.cs +++ b/OpenRa.Game/Traits/Building.cs @@ -2,7 +2,7 @@ namespace OpenRa.Game.Traits { - class Building : ITick + class Building : ITick, INotifyDamage { public readonly BuildingInfo unitInfo; @@ -19,5 +19,11 @@ namespace OpenRa.Game.Traits first = false; } + + public void Damaged(Actor self, AttackInfo e) + { + if (e.DamageState == DamageState.Dead) + Sound.Play("kaboom22.aud"); + } } } diff --git a/OpenRa.Game/Traits/Explodes.cs b/OpenRa.Game/Traits/Explodes.cs new file mode 100644 index 0000000000..7392d08712 --- /dev/null +++ b/OpenRa.Game/Traits/Explodes.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRa.Game.Effects; + +namespace OpenRa.Game.Traits +{ + class Explodes : INotifyDamage + { + public Explodes(Actor self) {} + + public void Damaged(Actor self, AttackInfo e) + { + if (self.IsDead) + { + Game.world.AddFrameEndTask( + w => w.Add(new Bullet("UnitExplode", e.Attacker.Owner, e.Attacker, + self.CenterLocation.ToInt2(), self.CenterLocation.ToInt2()))); + } + } + } +} diff --git a/OpenRa.Game/Traits/RenderBuilding.cs b/OpenRa.Game/Traits/RenderBuilding.cs index 0975f20921..f580d9fcce 100644 --- a/OpenRa.Game/Traits/RenderBuilding.cs +++ b/OpenRa.Game/Traits/RenderBuilding.cs @@ -65,9 +65,12 @@ namespace OpenRa.Game.Traits yield return Tuple.New(anim.Image, 24f * (float2)self.Location, pal); } - public virtual void Damaged(Actor self, DamageState state) + public virtual void Damaged(Actor self, AttackInfo e) { - switch( state ) + if (!e.DamageStateChanged) + return; + + switch( e.DamageState ) { case DamageState.Normal: anim.ReplaceAnim("idle"); diff --git a/OpenRa.Game/Traits/RenderBuildingTurreted.cs b/OpenRa.Game/Traits/RenderBuildingTurreted.cs index aa759a16db..61819c3dec 100644 --- a/OpenRa.Game/Traits/RenderBuildingTurreted.cs +++ b/OpenRa.Game/Traits/RenderBuildingTurreted.cs @@ -14,9 +14,11 @@ namespace OpenRa.Game.Traits anim.PlayFacing(a, () => self.traits.Get().turretFacing); } - public override void Damaged(Actor self, DamageState ds) + public override void Damaged(Actor self, AttackInfo e) { - switch (ds) + if (!e.DamageStateChanged) return; + + switch (e.DamageState) { case DamageState.Normal: PlayTurretAnim(self, "idle"); diff --git a/OpenRa.Game/Traits/RenderBuildingWarFactory.cs b/OpenRa.Game/Traits/RenderBuildingWarFactory.cs index 10dd2e334c..03b88929c2 100644 --- a/OpenRa.Game/Traits/RenderBuildingWarFactory.cs +++ b/OpenRa.Game/Traits/RenderBuildingWarFactory.cs @@ -51,11 +51,12 @@ namespace OpenRa.Game.Traits roof.PlayThen(prefix + "build-top", () => isOpen = true); } - public override void Damaged(Actor self, DamageState ds) + public override void Damaged(Actor self, AttackInfo e) { - base.Damaged(self, ds); + base.Damaged(self, e); - switch (ds) + if (!e.DamageStateChanged) return; + switch (e.DamageState) { case DamageState.Normal: prefix = ""; diff --git a/OpenRa.Game/Traits/RenderInfantry.cs b/OpenRa.Game/Traits/RenderInfantry.cs index 7a643f3cff..735577a635 100644 --- a/OpenRa.Game/Traits/RenderInfantry.cs +++ b/OpenRa.Game/Traits/RenderInfantry.cs @@ -8,7 +8,7 @@ using OpenRa.Game.Effects; namespace OpenRa.Game.Traits { - class RenderInfantry : RenderSimple, INotifyAttack, INotifyDamageEx + class RenderInfantry : RenderSimple, INotifyAttack, INotifyDamage { public RenderInfantry(Actor self) : base(self) @@ -75,12 +75,10 @@ namespace OpenRa.Game.Traits yield return Util.Centered(self, anim.Image, self.CenterLocation); } - public void Damaged(Actor self, int damage, WarheadInfo warhead) + public void Damaged(Actor self, AttackInfo e) { - if (self.Health <= 0) - Game.world.AddFrameEndTask(w => w.Add(new Corpse(self, warhead.InfDeath))); + if (e.DamageState == DamageState.Dead) + Game.world.AddFrameEndTask(w => w.Add(new Corpse(self, e.Warhead.InfDeath))); } - - public void Damaged(Actor self, DamageState ds) {} } } diff --git a/OpenRa.Game/Traits/RenderUnit.cs b/OpenRa.Game/Traits/RenderUnit.cs index d4bd96505c..5d6522a651 100644 --- a/OpenRa.Game/Traits/RenderUnit.cs +++ b/OpenRa.Game/Traits/RenderUnit.cs @@ -5,7 +5,7 @@ using OpenRa.Game.GameRules; namespace OpenRa.Game.Traits { - class RenderUnit : RenderSimple, INotifyDamageEx + class RenderUnit : RenderSimple, INotifyDamage { public RenderUnit(Actor self) : base(self) @@ -33,24 +33,20 @@ namespace OpenRa.Game.Traits } bool isSmoking; - DamageState currentDs; Animation smoke; - public void Damaged(Actor self, DamageState ds) { currentDs = ds; } - - public void Damaged(Actor self, int damage, WarheadInfo warhead) + public void Damaged(Actor self, AttackInfo e) { - if (currentDs != DamageState.Half) return; - if (!isSmoking) - { - isSmoking = true; - smoke.PlayThen("idle", - () => smoke.PlayThen("loop", - () => smoke.PlayBackwardsThen("end", - () => isSmoking = false))); - } - } + if (e.DamageState != DamageState.Half) return; + if (isSmoking) return; + isSmoking = true; + smoke.PlayThen("idle", + () => smoke.PlayThen("loop", + () => smoke.PlayBackwardsThen("end", + () => isSmoking = false))); + } + public override void Tick(Actor self) { base.Tick(self); diff --git a/OpenRa.Game/Traits/TakeCover.cs b/OpenRa.Game/Traits/TakeCover.cs index e0f70665f3..a8aafe9ca8 100644 --- a/OpenRa.Game/Traits/TakeCover.cs +++ b/OpenRa.Game/Traits/TakeCover.cs @@ -7,7 +7,7 @@ using OpenRa.Game.GameRules; namespace OpenRa.Game.Traits { // infantry prone behavior - class TakeCover : ITick, INotifyDamageEx, IDamageModifier, ISpeedModifier + class TakeCover : ITick, INotifyDamage, IDamageModifier, ISpeedModifier { const int defaultProneTime = 100; /* ticks, =4s */ const float proneDamage = .5f; @@ -19,9 +19,10 @@ namespace OpenRa.Game.Traits public TakeCover(Actor self) {} - public void Damaged(Actor self, int damage, WarheadInfo warhead) + public void Damaged(Actor self, AttackInfo e) { - remainingProneTime = defaultProneTime; + if (e.Damage > 0) /* fix to allow healing via `damage` */ + remainingProneTime = defaultProneTime; } public void Tick(Actor self) diff --git a/OpenRa.Game/Traits/TraitsInterfaces.cs b/OpenRa.Game/Traits/TraitsInterfaces.cs index 32f4781c73..0d6bc21376 100644 --- a/OpenRa.Game/Traits/TraitsInterfaces.cs +++ b/OpenRa.Game/Traits/TraitsInterfaces.cs @@ -8,8 +8,7 @@ namespace OpenRa.Game.Traits interface ITick { void Tick(Actor self); } interface IRender { IEnumerable> Render(Actor self); } - interface INotifyDamage { void Damaged(Actor self, DamageState ds); } - interface INotifyDamageEx { void Damaged(Actor self, int damage, WarheadInfo warhead); } + interface INotifyDamage { void Damaged(Actor self, AttackInfo e); } interface INotifyBuildComplete { void BuildingComplete (Actor self); } interface IOrder { diff --git a/OpenRa.Game/Traits/Unit.cs b/OpenRa.Game/Traits/Unit.cs index 53d1cff06b..98f005c8d3 100755 --- a/OpenRa.Game/Traits/Unit.cs +++ b/OpenRa.Game/Traits/Unit.cs @@ -1,11 +1,18 @@  namespace OpenRa.Game.Traits { - class Unit + class Unit : INotifyDamage { public int Facing; public int Altitude; public Unit( Actor self ) { } + + public void Damaged(Actor self, AttackInfo e) + { + if (e.DamageState == DamageState.Dead) + if (self.Owner == Game.LocalPlayer) + Sound.Play("unitlst1.aud"); + } } } diff --git a/OpenRa.Game/World.cs b/OpenRa.Game/World.cs index fff8797889..da2905de3e 100644 --- a/OpenRa.Game/World.cs +++ b/OpenRa.Game/World.cs @@ -21,13 +21,8 @@ namespace OpenRa.Game public void AddFrameEndTask( Action a ) { frameEndActions.Add( a ); } public event Action ActorAdded = _ => { }; - public event Action ActorRemoved = a => - { - a.Health = 0; /* make sure everyone sees it as dead */ - foreach (var nr in a.traits.WithInterface()) - nr.Damaged(a, DamageState.Dead); - }; - + public event Action ActorRemoved = _ => { }; + public void Tick() { foreach (var a in actors) a.Tick(); diff --git a/sequences.xml b/sequences.xml index f32518a523..c07e576fb2 100644 --- a/sequences.xml +++ b/sequences.xml @@ -523,6 +523,7 @@ + diff --git a/units.ini b/units.ini index 2ef769949d..29e0c4f346 100755 --- a/units.ini +++ b/units.ini @@ -57,7 +57,7 @@ Voice=VehicleVoice LongDesc=Regenerates Fog of War in a small area \naround the unit.\n Unarmed [ARTY] Description=Artillery -Traits=Unit, Mobile, AttackBase, RenderUnit +Traits=Unit, Mobile, AttackBase, RenderUnit, Explodes Voice=VehicleVoice LongDesc=Long-range artillery.\n Strong vs Infantry, Buildings\n Weak vs Tanks, Aircraft [HARV] @@ -607,10 +607,17 @@ ParaBomb DogJaw Heal SCUD +UnitExplode [TeslaZap] RenderAsTesla=true +[UnitExplode] +Damage=500 +Speed=100 +Projectile=Invisible +Warhead=UnitExplodeWarhead + @@ -646,11 +653,19 @@ HollowPoint Super Organic Nuke +UnitExplodeWarhead [HE] ImpactSound=kaboom25 WaterImpactSound=splash9 +[UnitExplodeWarhead] +Spread=10 +Verses=90%,75%,60%,25%,100% +Explosion=8 +InfDeath=3 +ImpactSound=kaboom15 + [General] OreChance=.02 LowPowerSlowdown=3