revamp of damage notifs; added Explodes

This commit is contained in:
Chris Forbes
2009-12-19 10:42:35 +13:00
parent 10431a5038
commit 07b5b4c164
16 changed files with 128 additions and 60 deletions

View File

@@ -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<IDamageModifier>().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<Building>())
Sound.Play("unitlst1.aud");
if (traits.Contains<Building>())
Sound.Play("kaboom22.aud");
}
var halfStrength = Info.Strength * Rules.General.ConditionYellow;
if (Health < halfStrength && (Health + damage) >= halfStrength)
{
/* we just went below half health! */
var newState = GetDamageState();
foreach (var nd in traits.WithInterface<INotifyDamage>())
nd.Damaged(this, DamageState.Half);
}
foreach (var ndx in traits.WithInterface<INotifyDamageEx>())
ndx.Damaged(this, damage, warhead);
nd.Damaged(this, new AttackInfo
{
Attacker = attacker,
Damage = damage,
DamageState = newState,
DamageStateChanged = newState != oldState,
Warhead = warhead
});
}
public void QueueActivity( IActivity nextActivity )

View File

@@ -158,9 +158,11 @@
<Compile Include="Traits\Activities\Follow.cs" />
<Compile Include="Traits\Activities\Turn.cs" />
<Compile Include="Traits\AttackBase.cs" />
<Compile Include="Traits\AttackInfo.cs" />
<Compile Include="Traits\AttackTurreted.cs" />
<Compile Include="Traits\AutoTarget.cs" />
<Compile Include="Traits\Building.cs" />
<Compile Include="Traits\Explodes.cs" />
<Compile Include="Traits\Harvester.cs" />
<Compile Include="Traits\Helicopter.cs" />
<Compile Include="Traits\ProductionQueue.cs" />

View File

@@ -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;
}
}

View File

@@ -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");
}
}
}

View File

@@ -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())));
}
}
}
}

View File

@@ -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");

View File

@@ -14,9 +14,11 @@ namespace OpenRa.Game.Traits
anim.PlayFacing(a, () => self.traits.Get<Turreted>().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");

View File

@@ -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 = "";

View File

@@ -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) {}
}
}

View File

@@ -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,23 +33,19 @@ namespace OpenRa.Game.Traits
}
bool isSmoking;
DamageState currentDs;
Animation smoke;
public void Damaged(Actor self, DamageState ds) { currentDs = ds; }
public void Damaged(Actor self, AttackInfo e)
{
if (e.DamageState != DamageState.Half) return;
if (isSmoking) return;
public void Damaged(Actor self, int damage, WarheadInfo warhead)
{
if (currentDs != DamageState.Half) return;
if (!isSmoking)
{
isSmoking = true;
smoke.PlayThen("idle",
() => smoke.PlayThen("loop",
() => smoke.PlayBackwardsThen("end",
() => isSmoking = false)));
}
}
public override void Tick(Actor self)
{

View File

@@ -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,8 +19,9 @@ namespace OpenRa.Game.Traits
public TakeCover(Actor self) {}
public void Damaged(Actor self, int damage, WarheadInfo warhead)
public void Damaged(Actor self, AttackInfo e)
{
if (e.Damage > 0) /* fix to allow healing via `damage` */
remainingProneTime = defaultProneTime;
}

View File

@@ -8,8 +8,7 @@ namespace OpenRa.Game.Traits
interface ITick { void Tick(Actor self); }
interface IRender { IEnumerable<Tuple<Sprite, float2, int>> 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
{

View File

@@ -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");
}
}
}

View File

@@ -21,12 +21,7 @@ namespace OpenRa.Game
public void AddFrameEndTask( Action<World> a ) { frameEndActions.Add( a ); }
public event Action<Actor> ActorAdded = _ => { };
public event Action<Actor> ActorRemoved = a =>
{
a.Health = 0; /* make sure everyone sees it as dead */
foreach (var nr in a.traits.WithInterface<INotifyDamage>())
nr.Damaged(a, DamageState.Dead);
};
public event Action<Actor> ActorRemoved = _ => { };
public void Tick()
{

View File

@@ -523,6 +523,7 @@
<sequence name="4w" start="0" length="10" src="h2o_exp2" />
<sequence name="2w" start="0" length="10" src="h2o_exp3" />
<sequence name="7" start="0" length="18" src="fball1" />
<sequence name="8" start="0" length="22" src="art-exp1" />
</unit>
<unit name="lst">
<sequence name="idle" start="0" length="1" />

View File

@@ -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