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; } } 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) 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! */ if (IsDead) return; /* overkill! don't count extra hits as more kills! */
var oldState = GetDamageState();
/* apply the damage modifiers, if we have any. */ /* apply the damage modifiers, if we have any. */
damage = (int)traits.WithInterface<IDamageModifier>().Aggregate( damage = (int)traits.WithInterface<IDamageModifier>().Aggregate(
(float)damage, (a, t) => t.GetDamageModifier() * a); (float)damage, (a, t) => t.GetDamageModifier() * a);
@@ -126,24 +133,19 @@ namespace OpenRa.Game
attacker.Owner.Kills++; attacker.Owner.Kills++;
Game.world.AddFrameEndTask(w => w.Remove(this)); 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; var newState = GetDamageState();
if (Health < halfStrength && (Health + damage) >= halfStrength)
{
/* we just went below half health! */
foreach (var nd in traits.WithInterface<INotifyDamage>())
nd.Damaged(this, DamageState.Half);
}
foreach (var ndx in traits.WithInterface<INotifyDamageEx>()) foreach (var nd in traits.WithInterface<INotifyDamage>())
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 ) public void QueueActivity( IActivity nextActivity )

View File

@@ -158,9 +158,11 @@
<Compile Include="Traits\Activities\Follow.cs" /> <Compile Include="Traits\Activities\Follow.cs" />
<Compile Include="Traits\Activities\Turn.cs" /> <Compile Include="Traits\Activities\Turn.cs" />
<Compile Include="Traits\AttackBase.cs" /> <Compile Include="Traits\AttackBase.cs" />
<Compile Include="Traits\AttackInfo.cs" />
<Compile Include="Traits\AttackTurreted.cs" /> <Compile Include="Traits\AttackTurreted.cs" />
<Compile Include="Traits\AutoTarget.cs" /> <Compile Include="Traits\AutoTarget.cs" />
<Compile Include="Traits\Building.cs" /> <Compile Include="Traits\Building.cs" />
<Compile Include="Traits\Explodes.cs" />
<Compile Include="Traits\Harvester.cs" /> <Compile Include="Traits\Harvester.cs" />
<Compile Include="Traits\Helicopter.cs" /> <Compile Include="Traits\Helicopter.cs" />
<Compile Include="Traits\ProductionQueue.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 namespace OpenRa.Game.Traits
{ {
class Building : ITick class Building : ITick, INotifyDamage
{ {
public readonly BuildingInfo unitInfo; public readonly BuildingInfo unitInfo;
@@ -19,5 +19,11 @@ namespace OpenRa.Game.Traits
first = false; 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); 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: case DamageState.Normal:
anim.ReplaceAnim("idle"); anim.ReplaceAnim("idle");

View File

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

View File

@@ -51,11 +51,12 @@ namespace OpenRa.Game.Traits
roof.PlayThen(prefix + "build-top", () => isOpen = true); 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: case DamageState.Normal:
prefix = ""; prefix = "";

View File

@@ -8,7 +8,7 @@ using OpenRa.Game.Effects;
namespace OpenRa.Game.Traits namespace OpenRa.Game.Traits
{ {
class RenderInfantry : RenderSimple, INotifyAttack, INotifyDamageEx class RenderInfantry : RenderSimple, INotifyAttack, INotifyDamage
{ {
public RenderInfantry(Actor self) public RenderInfantry(Actor self)
: base(self) : base(self)
@@ -75,12 +75,10 @@ namespace OpenRa.Game.Traits
yield return Util.Centered(self, anim.Image, self.CenterLocation); 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) if (e.DamageState == DamageState.Dead)
Game.world.AddFrameEndTask(w => w.Add(new Corpse(self, warhead.InfDeath))); 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 namespace OpenRa.Game.Traits
{ {
class RenderUnit : RenderSimple, INotifyDamageEx class RenderUnit : RenderSimple, INotifyDamage
{ {
public RenderUnit(Actor self) public RenderUnit(Actor self)
: base(self) : base(self)
@@ -33,24 +33,20 @@ namespace OpenRa.Game.Traits
} }
bool isSmoking; bool isSmoking;
DamageState currentDs;
Animation smoke; Animation smoke;
public void Damaged(Actor self, DamageState ds) { currentDs = ds; } public void Damaged(Actor self, AttackInfo e)
public void Damaged(Actor self, int damage, WarheadInfo warhead)
{ {
if (currentDs != DamageState.Half) return; if (e.DamageState != DamageState.Half) return;
if (!isSmoking) if (isSmoking) return;
{
isSmoking = true;
smoke.PlayThen("idle",
() => smoke.PlayThen("loop",
() => smoke.PlayBackwardsThen("end",
() => isSmoking = false)));
}
}
isSmoking = true;
smoke.PlayThen("idle",
() => smoke.PlayThen("loop",
() => smoke.PlayBackwardsThen("end",
() => isSmoking = false)));
}
public override void Tick(Actor self) public override void Tick(Actor self)
{ {
base.Tick(self); base.Tick(self);

View File

@@ -7,7 +7,7 @@ using OpenRa.Game.GameRules;
namespace OpenRa.Game.Traits namespace OpenRa.Game.Traits
{ {
// infantry prone behavior // infantry prone behavior
class TakeCover : ITick, INotifyDamageEx, IDamageModifier, ISpeedModifier class TakeCover : ITick, INotifyDamage, IDamageModifier, ISpeedModifier
{ {
const int defaultProneTime = 100; /* ticks, =4s */ const int defaultProneTime = 100; /* ticks, =4s */
const float proneDamage = .5f; const float proneDamage = .5f;
@@ -19,9 +19,10 @@ namespace OpenRa.Game.Traits
public TakeCover(Actor self) {} 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) public void Tick(Actor self)

View File

@@ -8,8 +8,7 @@ namespace OpenRa.Game.Traits
interface ITick { void Tick(Actor self); } interface ITick { void Tick(Actor self); }
interface IRender { IEnumerable<Tuple<Sprite, float2, int>> Render(Actor self); } interface IRender { IEnumerable<Tuple<Sprite, float2, int>> Render(Actor self); }
interface INotifyDamage { void Damaged(Actor self, DamageState ds); } interface INotifyDamage { void Damaged(Actor self, AttackInfo e); }
interface INotifyDamageEx { void Damaged(Actor self, int damage, WarheadInfo warhead); }
interface INotifyBuildComplete { void BuildingComplete (Actor self); } interface INotifyBuildComplete { void BuildingComplete (Actor self); }
interface IOrder interface IOrder
{ {

View File

@@ -1,11 +1,18 @@
 
namespace OpenRa.Game.Traits namespace OpenRa.Game.Traits
{ {
class Unit class Unit : INotifyDamage
{ {
public int Facing; public int Facing;
public int Altitude; public int Altitude;
public Unit( Actor self ) { } 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,13 +21,8 @@ namespace OpenRa.Game
public void AddFrameEndTask( Action<World> a ) { frameEndActions.Add( a ); } public void AddFrameEndTask( Action<World> a ) { frameEndActions.Add( a ); }
public event Action<Actor> ActorAdded = _ => { }; public event Action<Actor> ActorAdded = _ => { };
public event Action<Actor> ActorRemoved = a => public event Action<Actor> ActorRemoved = _ => { };
{
a.Health = 0; /* make sure everyone sees it as dead */
foreach (var nr in a.traits.WithInterface<INotifyDamage>())
nr.Damaged(a, DamageState.Dead);
};
public void Tick() public void Tick()
{ {
foreach (var a in actors) a.Tick(); foreach (var a in actors) a.Tick();

View File

@@ -523,6 +523,7 @@
<sequence name="4w" start="0" length="10" src="h2o_exp2" /> <sequence name="4w" start="0" length="10" src="h2o_exp2" />
<sequence name="2w" start="0" length="10" src="h2o_exp3" /> <sequence name="2w" start="0" length="10" src="h2o_exp3" />
<sequence name="7" start="0" length="18" src="fball1" /> <sequence name="7" start="0" length="18" src="fball1" />
<sequence name="8" start="0" length="22" src="art-exp1" />
</unit> </unit>
<unit name="lst"> <unit name="lst">
<sequence name="idle" start="0" length="1" /> <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 LongDesc=Regenerates Fog of War in a small area \naround the unit.\n Unarmed
[ARTY] [ARTY]
Description=Artillery Description=Artillery
Traits=Unit, Mobile, AttackBase, RenderUnit Traits=Unit, Mobile, AttackBase, RenderUnit, Explodes
Voice=VehicleVoice Voice=VehicleVoice
LongDesc=Long-range artillery.\n Strong vs Infantry, Buildings\n Weak vs Tanks, Aircraft LongDesc=Long-range artillery.\n Strong vs Infantry, Buildings\n Weak vs Tanks, Aircraft
[HARV] [HARV]
@@ -607,10 +607,17 @@ ParaBomb
DogJaw DogJaw
Heal Heal
SCUD SCUD
UnitExplode
[TeslaZap] [TeslaZap]
RenderAsTesla=true RenderAsTesla=true
[UnitExplode]
Damage=500
Speed=100
Projectile=Invisible
Warhead=UnitExplodeWarhead
@@ -646,11 +653,19 @@ HollowPoint
Super Super
Organic Organic
Nuke Nuke
UnitExplodeWarhead
[HE] [HE]
ImpactSound=kaboom25 ImpactSound=kaboom25
WaterImpactSound=splash9 WaterImpactSound=splash9
[UnitExplodeWarhead]
Spread=10
Verses=90%,75%,60%,25%,100%
Explosion=8
InfDeath=3
ImpactSound=kaboom15
[General] [General]
OreChance=.02 OreChance=.02
LowPowerSlowdown=3 LowPowerSlowdown=3