Convert weapon plumbing to use integer damage modifiers.

This commit is contained in:
Paul Chote
2014-08-17 17:33:50 +12:00
parent 8e8e02dae8
commit 57ba1b54b4
27 changed files with 75 additions and 75 deletions

View File

@@ -42,30 +42,31 @@ namespace OpenRA.GameRules
: new Dictionary<string, float>(); : new Dictionary<string, float>();
} }
public override float EffectivenessAgainst(ActorInfo ai) public override int EffectivenessAgainst(ActorInfo ai)
{ {
var health = ai.Traits.GetOrDefault<HealthInfo>(); var health = ai.Traits.GetOrDefault<HealthInfo>();
if (health == null) if (health == null)
return 0f; return 0;
var armor = ai.Traits.GetOrDefault<ArmorInfo>(); var armor = ai.Traits.GetOrDefault<ArmorInfo>();
if (armor == null || armor.Type == null) if (armor == null || armor.Type == null)
return 1f; return 100;
// TODO: Change versus definitions to integer percentages
float versus; float versus;
return Versus.TryGetValue(armor.Type, out versus) ? versus : 1f; return Versus.TryGetValue(armor.Type, out versus) ? (int)(versus * 100) : 100;
} }
public override void DoImpact(Target target, Actor firedBy, float firepowerModifier) public override void DoImpact(Target target, Actor firedBy, IEnumerable<int> damageModifiers)
{ {
// Used by traits that damage a single actor, rather than a position // Used by traits that damage a single actor, rather than a position
if (target.Type == TargetType.Actor) if (target.Type == TargetType.Actor)
DoImpact(target.Actor, firedBy, firepowerModifier); DoImpact(target.Actor, firedBy, damageModifiers);
else else
DoImpact(target.CenterPosition, firedBy, firepowerModifier); DoImpact(target.CenterPosition, firedBy, damageModifiers);
} }
public abstract void DoImpact(Actor target, Actor firedBy, float firepowerModifier); public abstract void DoImpact(Actor target, Actor firedBy, IEnumerable<int> damageModifiers);
public abstract void DoImpact(WPos pos, Actor firedBy, float firepowerModifier); public abstract void DoImpact(WPos pos, Actor firedBy, IEnumerable<int> damageModifiers);
} }
} }

View File

@@ -27,9 +27,9 @@ namespace OpenRA.GameRules
[Desc("Delay in ticks before applying the warhead effect.","0 = instant (old model).")] [Desc("Delay in ticks before applying the warhead effect.","0 = instant (old model).")]
public readonly int Delay = 0; public readonly int Delay = 0;
public abstract void DoImpact(Target target, Actor firedBy, float firepowerModifier); public abstract void DoImpact(Target target, Actor firedBy, IEnumerable<int> damageModifiers);
public virtual float EffectivenessAgainst(ActorInfo ai) { return 0f; } public virtual int EffectivenessAgainst(ActorInfo ai) { return 0; }
public bool IsValidAgainst(Target target, World world, Actor firedBy) public bool IsValidAgainst(Target target, World world, Actor firedBy)
{ {
@@ -59,7 +59,7 @@ namespace OpenRA.GameRules
public bool IsValidAgainst(Actor victim, Actor firedBy) public bool IsValidAgainst(Actor victim, Actor firedBy)
{ {
// If this warhead is ineffective against the target, then it is not a valid target // If this warhead is ineffective against the target, then it is not a valid target
if (EffectivenessAgainst(victim.Info) <= 0f) if (EffectivenessAgainst(victim.Info) <= 0)
return false; return false;
// A target type is valid if it is in the valid targets list, and not in the invalid targets list. // A target type is valid if it is in the valid targets list, and not in the invalid targets list.
@@ -84,7 +84,7 @@ namespace OpenRA.GameRules
public bool IsValidAgainst(FrozenActor victim, Actor firedBy) public bool IsValidAgainst(FrozenActor victim, Actor firedBy)
{ {
// If this warhead is ineffective against the target, then it is not a valid target // If this warhead is ineffective against the target, then it is not a valid target
if (EffectivenessAgainst(victim.Info) <= 0f) if (EffectivenessAgainst(victim.Info) <= 0)
return false; return false;
// A target type is valid if it is in the valid targets list, and not in the invalid targets list. // A target type is valid if it is in the valid targets list, and not in the invalid targets list.

View File

@@ -19,7 +19,7 @@ namespace OpenRA.GameRules
public class ProjectileArgs public class ProjectileArgs
{ {
public WeaponInfo Weapon; public WeaponInfo Weapon;
public float FirepowerModifier = 1.0f; public IEnumerable<int> DamageModifiers;
public int Facing; public int Facing;
public WPos Source; public WPos Source;
public Actor SourceActor; public Actor SourceActor;
@@ -144,13 +144,13 @@ namespace OpenRA.GameRules
return true; return true;
} }
public void Impact(WPos pos, Actor firedBy, float damageModifier) public void Impact(WPos pos, Actor firedBy, IEnumerable<int> damageModifiers)
{ {
foreach (var wh in Warheads) foreach (var wh in Warheads)
{ {
Action a; Action a;
a = () => wh.DoImpact(Target.FromPos(pos), firedBy, damageModifier); a = () => wh.DoImpact(Target.FromPos(pos), firedBy, damageModifiers);
if (wh.Delay > 0) if (wh.Delay > 0)
firedBy.World.AddFrameEndTask( firedBy.World.AddFrameEndTask(
w => w.Add(new DelayedAction(wh.Delay, a))); w => w.Add(new DelayedAction(wh.Delay, a)));

View File

@@ -9,6 +9,7 @@
#endregion #endregion
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using OpenRA.Effects; using OpenRA.Effects;
using OpenRA.GameRules; using OpenRA.GameRules;
using OpenRA.Graphics; using OpenRA.Graphics;
@@ -45,7 +46,7 @@ namespace OpenRA.Mods.Cnc.Effects
if (!impacted && weaponDelay-- <= 0) if (!impacted && weaponDelay-- <= 0)
{ {
var weapon = world.Map.Rules.Weapons[this.weapon.ToLowerInvariant()]; var weapon = world.Map.Rules.Weapons[this.weapon.ToLowerInvariant()];
weapon.Impact(target.CenterPosition, firedBy.PlayerActor, 1f); weapon.Impact(target.CenterPosition, firedBy.PlayerActor, Enumerable.Empty<int>());
impacted = true; impacted = true;
} }
} }

View File

@@ -43,7 +43,7 @@ namespace OpenRA.Mods.Cnc
if (!info.Resources.Contains(r.Info.Name)) return; if (!info.Resources.Contains(r.Info.Name)) return;
var weapon = self.World.Map.Rules.Weapons[info.Weapon.ToLowerInvariant()]; var weapon = self.World.Map.Rules.Weapons[info.Weapon.ToLowerInvariant()];
weapon.Impact(self.CenterPosition, self.World.WorldActor, 1f); weapon.Impact(self.CenterPosition, self.World.WorldActor, Enumerable.Empty<int>());
poisonTicks = weapon.ReloadDelay; poisonTicks = weapon.ReloadDelay;
} }
} }

View File

@@ -65,7 +65,7 @@ namespace OpenRA.Mods.D2k
if (health.HP <= damageThreshold || --damageTicks > 0) if (health.HP <= damageThreshold || --damageTicks > 0)
return; return;
weapon.Impact(self.CenterPosition, self.World.WorldActor, 1f); weapon.Impact(self.CenterPosition, self.World.WorldActor, Enumerable.Empty<int>());
damageTicks = weapon.ReloadDelay; damageTicks = weapon.ReloadDelay;
} }
} }

View File

@@ -49,10 +49,8 @@ namespace OpenRA.Mods.D2k
Weapon = wep, Weapon = wep,
Facing = self.World.SharedRandom.Next(-1, 255), Facing = self.World.SharedRandom.Next(-1, 255),
// TODO: Convert to ints DamageModifiers = self.TraitsImplementing<IFirepowerModifier>()
FirepowerModifier = self.TraitsImplementing<IFirepowerModifier>() .Select(a => a.GetFirepowerModifier()),
.Select(a => a.GetFirepowerModifier() / 100f)
.Product(),
Source = self.CenterPosition, Source = self.CenterPosition,
SourceActor = self, SourceActor = self,

View File

@@ -8,6 +8,7 @@
*/ */
#endregion #endregion
using System.Linq;
using OpenRA.GameRules; using OpenRA.GameRules;
using OpenRA.Traits; using OpenRA.Traits;
@@ -54,7 +55,7 @@ namespace OpenRA.Mods.RA.Air
if (info.Explosion != null) if (info.Explosion != null)
{ {
var weapon = self.World.Map.Rules.Weapons[info.Explosion.ToLowerInvariant()]; var weapon = self.World.Map.Rules.Weapons[info.Explosion.ToLowerInvariant()];
weapon.Impact(self.CenterPosition, self, 1f); weapon.Impact(self.CenterPosition, self, Enumerable.Empty<int>());
} }
self.Destroy(); self.Destroy();

View File

@@ -154,10 +154,8 @@ namespace OpenRA.Mods.RA
Weapon = Weapon, Weapon = Weapon,
Facing = legacyFacing, Facing = legacyFacing,
// TODO: Convert to ints DamageModifiers = self.TraitsImplementing<IFirepowerModifier>()
FirepowerModifier = self.TraitsImplementing<IFirepowerModifier>() .Select(a => a.GetFirepowerModifier()),
.Select(a => a.GetFirepowerModifier() / 100f)
.Product(),
Source = muzzlePosition, Source = muzzlePosition,
SourceActor = self, SourceActor = self,

View File

@@ -299,7 +299,7 @@ namespace OpenRA.Mods.RA
self.World.AddFrameEndTask(w => self.World.AddFrameEndTask(w =>
{ {
var weapon = saboteur.World.Map.Rules.Weapons[Info.DemolishWeapon.ToLowerInvariant()]; var weapon = saboteur.World.Map.Rules.Weapons[Info.DemolishWeapon.ToLowerInvariant()];
weapon.Impact(self.CenterPosition, saboteur, 1f); weapon.Impact(self.CenterPosition, saboteur, Enumerable.Empty<int>());
self.World.WorldActor.Trait<ScreenShaker>().AddEffect(15, self.CenterPosition, 6); self.World.WorldActor.Trait<ScreenShaker>().AddEffect(15, self.CenterPosition, 6);
self.Kill(saboteur); self.Kill(saboteur);
}); });

View File

@@ -8,6 +8,7 @@
*/ */
#endregion #endregion
using System.Linq;
using OpenRA.GameRules; using OpenRA.GameRules;
using OpenRA.Traits; using OpenRA.Traits;
@@ -30,7 +31,7 @@ namespace OpenRA.Mods.RA
public override void Activate(Actor collector) public override void Activate(Actor collector)
{ {
var weapon = self.World.Map.Rules.Weapons[((ExplodeCrateActionInfo)info).Weapon.ToLowerInvariant()]; var weapon = self.World.Map.Rules.Weapons[((ExplodeCrateActionInfo)info).Weapon.ToLowerInvariant()];
weapon.Impact(collector.CenterPosition, self, 1f); weapon.Impact(collector.CenterPosition, self, Enumerable.Empty<int>());
base.Activate(collector); base.Activate(collector);
} }
} }

View File

@@ -172,7 +172,7 @@ namespace OpenRA.Mods.RA.Effects
world.AddFrameEndTask(w => w.Remove(this)); world.AddFrameEndTask(w => w.Remove(this));
args.Weapon.Impact(pos, args.SourceActor, args.FirepowerModifier); args.Weapon.Impact(pos, args.SourceActor, args.DamageModifiers);
} }
} }
} }

View File

@@ -56,7 +56,7 @@ namespace OpenRA.Mods.RA.Effects
{ {
pos += new WVec(0, 0, args.PassiveTarget.Z - pos.Z); pos += new WVec(0, 0, args.PassiveTarget.Z - pos.Z);
world.AddFrameEndTask(w => w.Remove(this)); world.AddFrameEndTask(w => w.Remove(this));
args.Weapon.Impact(pos, args.SourceActor, args.FirepowerModifier); args.Weapon.Impact(pos, args.SourceActor, args.DamageModifiers);
} }
anim.Tick(); anim.Tick();

View File

@@ -69,7 +69,7 @@ namespace OpenRA.Mods.RA.Effects
if (hitanim != null) if (hitanim != null)
hitanim.PlayThen("idle", () => animationComplete = true); hitanim.PlayThen("idle", () => animationComplete = true);
args.Weapon.Impact(target, args.SourceActor, args.FirepowerModifier); args.Weapon.Impact(target, args.SourceActor, args.DamageModifiers);
doneDamage = true; doneDamage = true;
} }

View File

@@ -180,7 +180,7 @@ namespace OpenRA.Mods.RA.Effects
if (ticks <= info.Arm) if (ticks <= info.Arm)
return; return;
args.Weapon.Impact(pos, args.SourceActor, args.FirepowerModifier); args.Weapon.Impact(pos, args.SourceActor, args.DamageModifiers);
} }
public IEnumerable<IRenderable> Render(WorldRenderer wr) public IEnumerable<IRenderable> Render(WorldRenderer wr)

View File

@@ -81,7 +81,7 @@ namespace OpenRA.Mods.RA.Effects
{ {
world.AddFrameEndTask(w => w.Remove(this)); world.AddFrameEndTask(w => w.Remove(this));
var weapon = world.Map.Rules.Weapons[this.weapon.ToLowerInvariant()]; var weapon = world.Map.Rules.Weapons[this.weapon.ToLowerInvariant()];
weapon.Impact(pos, firedBy.PlayerActor, 1f); weapon.Impact(pos, firedBy.PlayerActor, Enumerable.Empty<int>());
world.WorldActor.Trait<ScreenShaker>().AddEffect(20, pos, 5); world.WorldActor.Trait<ScreenShaker>().AddEffect(20, pos, 5);
foreach (var a in world.ActorsWithTrait<NukePaletteEffect>()) foreach (var a in world.ActorsWithTrait<NukePaletteEffect>())

View File

@@ -47,7 +47,7 @@ namespace OpenRA.Mods.RA.Effects
if (!doneDamage) if (!doneDamage)
{ {
var pos = Args.GuidedTarget.IsValidFor(Args.SourceActor) ? Args.GuidedTarget.CenterPosition : Args.PassiveTarget; var pos = Args.GuidedTarget.IsValidFor(Args.SourceActor) ? Args.GuidedTarget.CenterPosition : Args.PassiveTarget;
Args.Weapon.Impact(pos, Args.SourceActor, Args.FirepowerModifier); Args.Weapon.Impact(pos, Args.SourceActor, Args.DamageModifiers);
doneDamage = true; doneDamage = true;
} }
} }

View File

@@ -51,7 +51,7 @@ namespace OpenRA.Mods.RA
if (weapon.Report != null && weapon.Report.Any()) if (weapon.Report != null && weapon.Report.Any())
Sound.Play(weapon.Report.Random(e.Attacker.World.SharedRandom), self.CenterPosition); Sound.Play(weapon.Report.Random(e.Attacker.World.SharedRandom), self.CenterPosition);
weapon.Impact(self.CenterPosition, e.Attacker, 1f); weapon.Impact(self.CenterPosition, e.Attacker, Enumerable.Empty<int>());
} }
} }

View File

@@ -10,6 +10,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Linq;
using OpenRA.GameRules; using OpenRA.GameRules;
using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Move; using OpenRA.Mods.RA.Move;
@@ -71,7 +72,7 @@ namespace OpenRA.Mods.RA
if (info.ThumpDamageWeapon != null) if (info.ThumpDamageWeapon != null)
{ {
var weapon = self.World.Map.Rules.Weapons[info.ThumpDamageWeapon.ToLowerInvariant()]; var weapon = self.World.Map.Rules.Weapons[info.ThumpDamageWeapon.ToLowerInvariant()];
weapon.Impact(self.CenterPosition, self, 1f); weapon.Impact(self.CenterPosition, self, Enumerable.Empty<int>());
} }
screenShaker.AddEffect(info.ThumpShakeTime, self.CenterPosition, info.ThumpShakeIntensity, info.ThumpShakeMultiplier); screenShaker.AddEffect(info.ThumpShakeTime, self.CenterPosition, info.ThumpShakeIntensity, info.ThumpShakeMultiplier);
tick = 0; tick = 0;
@@ -110,7 +111,7 @@ namespace OpenRA.Mods.RA
if (info.DetonationWeapon != null) if (info.DetonationWeapon != null)
{ {
var weapon = self.World.Map.Rules.Weapons[info.DetonationWeapon.ToLowerInvariant()]; var weapon = self.World.Map.Rules.Weapons[info.DetonationWeapon.ToLowerInvariant()];
weapon.Impact(self.CenterPosition, self, 1f); weapon.Impact(self.CenterPosition, self, Enumerable.Empty<int>());
} }
self.Kill(self); self.Kill(self);
}); });

View File

@@ -25,7 +25,7 @@ namespace OpenRA.Mods.RA
[Desc("What factor to multiply the Damage by for this spread range.", "Each factor specified must have an associated Spread defined.")] [Desc("What factor to multiply the Damage by for this spread range.", "Each factor specified must have an associated Spread defined.")]
public readonly float[] SpreadFactor = { 1f }; public readonly float[] SpreadFactor = { 1f };
public override void DoImpact(WPos pos, Actor firedBy, float firepowerModifier) public override void DoImpact(WPos pos, Actor firedBy, IEnumerable<int> damageModifiers)
{ {
var world = firedBy.World; var world = firedBy.World;
@@ -44,33 +44,35 @@ namespace OpenRA.Mods.RA
hitActors.Except(world.FindActorsInCircle(pos, previousSpread)); hitActors.Except(world.FindActorsInCircle(pos, previousSpread));
foreach (var victim in hitActors) foreach (var victim in hitActors)
{
if (IsValidAgainst(victim, firedBy)) if (IsValidAgainst(victim, firedBy))
{ {
var damage = GetDamageToInflict(victim, firedBy, firepowerModifier * currentFactor); // TODO: Keep currentFactor as int from the start
var damage = GetDamageToInflict(victim, firedBy, damageModifiers.Append((int)(currentFactor * 100)));
victim.InflictDamage(firedBy, damage, this); victim.InflictDamage(firedBy, damage, this);
} }
}
} }
} }
public override void DoImpact(Actor victim, Actor firedBy, float firepowerModifier) public override void DoImpact(Actor victim, Actor firedBy, IEnumerable<int> damageModifiers)
{ {
if (IsValidAgainst(victim, firedBy)) if (IsValidAgainst(victim, firedBy))
{ {
// TODO: Keep currentFactor as int from the start
var currentFactor = SpreadFactor[0]; var currentFactor = SpreadFactor[0];
var damage = (int)GetDamageToInflict(victim, firedBy, firepowerModifier * currentFactor); var damage = GetDamageToInflict(victim, firedBy, damageModifiers.Append((int)(currentFactor * 100)));
victim.InflictDamage(firedBy, damage, this); victim.InflictDamage(firedBy, damage, this);
} }
} }
public int GetDamageToInflict(Actor target, Actor firedBy, float modifier) public int GetDamageToInflict(Actor target, Actor firedBy, IEnumerable<int> damageModifiers)
{ {
var healthInfo = target.Info.Traits.GetOrDefault<HealthInfo>(); var healthInfo = target.Info.Traits.GetOrDefault<HealthInfo>();
if (healthInfo == null) if (healthInfo == null)
return 0; return 0;
var rawDamage = (float)Damage; return Util.ApplyPercentageModifiers(Damage, damageModifiers.Append(EffectivenessAgainst(target.Info)));
return (int)(rawDamage * modifier * EffectivenessAgainst(target.Info));
} }
} }
} }

View File

@@ -74,7 +74,7 @@ namespace OpenRA.Mods.RA
return false; return false;
} }
public override void DoImpact(Target target, Actor firedBy, float firepowerModifier) public override void DoImpact(Target target, Actor firedBy, IEnumerable<int> damageModifiers)
{ {
var pos = target.CenterPosition; var pos = target.CenterPosition;
var world = firedBy.World; var world = firedBy.World;

View File

@@ -26,7 +26,7 @@ namespace OpenRA.Mods.RA
// TODO: Allow maximum resource splatter to be defined. (Per tile, and in total). // TODO: Allow maximum resource splatter to be defined. (Per tile, and in total).
public override void DoImpact(Target target, Actor firedBy, float firepowerModifier) public override void DoImpact(Target target, Actor firedBy, IEnumerable<int> damageModifiers)
{ {
if (string.IsNullOrEmpty(AddsResourceType)) if (string.IsNullOrEmpty(AddsResourceType))
return; return;

View File

@@ -23,7 +23,7 @@ namespace OpenRA.Mods.RA
// TODO: Allow maximum resource removal to be defined. (Per tile, and in total). // TODO: Allow maximum resource removal to be defined. (Per tile, and in total).
public override void DoImpact(Target target, Actor firedBy, float firepowerModifier) public override void DoImpact(Target target, Actor firedBy, IEnumerable<int> damageModifiers)
{ {
var world = firedBy.World; var world = firedBy.World;
var targetTile = world.Map.CellContaining(target.CenterPosition); var targetTile = world.Map.CellContaining(target.CenterPosition);

View File

@@ -22,7 +22,7 @@ namespace OpenRA.Mods.RA
[Desc("Size of the area. Damage will be applied to this area.", "If two spreads are defined, the area of effect is a ring, where the second value is the inner radius.")] [Desc("Size of the area. Damage will be applied to this area.", "If two spreads are defined, the area of effect is a ring, where the second value is the inner radius.")]
public readonly WRange[] Spread = { new WRange(43), WRange.Zero }; public readonly WRange[] Spread = { new WRange(43), WRange.Zero };
public override void DoImpact(WPos pos, Actor firedBy, float firepowerModifier) public override void DoImpact(WPos pos, Actor firedBy, IEnumerable<int> damageModifiers)
{ {
var world = firedBy.World; var world = firedBy.World;
var range = Spread[0]; var range = Spread[0];
@@ -31,14 +31,14 @@ namespace OpenRA.Mods.RA
hitActors.Except(world.FindActorsInCircle(pos, Spread[1])); hitActors.Except(world.FindActorsInCircle(pos, Spread[1]));
foreach (var victim in hitActors) foreach (var victim in hitActors)
DoImpact(victim, firedBy, firepowerModifier); DoImpact(victim, firedBy, damageModifiers);
} }
public override void DoImpact(Actor victim, Actor firedBy, float firepowerModifier) public override void DoImpact(Actor victim, Actor firedBy, IEnumerable<int> damageModifiers)
{ {
if (IsValidAgainst(victim, firedBy)) if (IsValidAgainst(victim, firedBy))
{ {
var damage = GetDamageToInflict(victim, firedBy, firepowerModifier); var damage = GetDamageToInflict(victim, firedBy, damageModifiers);
if (damage != 0) // will be 0 if the target doesn't have HealthInfo if (damage != 0) // will be 0 if the target doesn't have HealthInfo
{ {
var healthInfo = victim.Info.Traits.Get<HealthInfo>(); var healthInfo = victim.Info.Traits.Get<HealthInfo>();
@@ -49,15 +49,13 @@ namespace OpenRA.Mods.RA
} }
} }
public float GetDamageToInflict(Actor target, Actor firedBy, float modifier) public float GetDamageToInflict(Actor target, Actor firedBy, IEnumerable<int> damageModifiers)
{ {
var healthInfo = target.Info.Traits.GetOrDefault<HealthInfo>(); var healthInfo = target.Info.Traits.GetOrDefault<HealthInfo>();
if (healthInfo == null) if (healthInfo == null)
return 0; return 0;
var rawDamage = (float)Damage; return Util.ApplyPercentageModifiers(Damage, damageModifiers.Append(EffectivenessAgainst(target.Info)));
return rawDamage * modifier * EffectivenessAgainst(target.Info);
} }
} }
} }

View File

@@ -25,7 +25,7 @@ namespace OpenRA.Mods.RA
[Desc("Type of smudge to apply to terrain.")] [Desc("Type of smudge to apply to terrain.")]
public readonly string[] SmudgeType = { }; public readonly string[] SmudgeType = { };
public override void DoImpact(Target target, Actor firedBy, float firepowerModifier) public override void DoImpact(Target target, Actor firedBy, IEnumerable<int> damageModifiers)
{ {
var world = firedBy.World; var world = firedBy.World;
var targetTile = world.Map.CellContaining(target.CenterPosition); var targetTile = world.Map.CellContaining(target.CenterPosition);

View File

@@ -22,7 +22,7 @@ namespace OpenRA.Mods.RA
[Desc("Size of the area. Damage will be applied to this area.")] [Desc("Size of the area. Damage will be applied to this area.")]
public readonly int[] Size = { 0, 0 }; public readonly int[] Size = { 0, 0 };
public override void DoImpact(WPos pos, Actor firedBy, float firepowerModifier) public override void DoImpact(WPos pos, Actor firedBy, IEnumerable<int> damageModifiers)
{ {
var world = firedBy.World; var world = firedBy.World;
var targetTile = world.Map.CellContaining(pos); var targetTile = world.Map.CellContaining(pos);
@@ -31,27 +31,25 @@ namespace OpenRA.Mods.RA
foreach (var t in affectedTiles) foreach (var t in affectedTiles)
foreach (var victim in world.ActorMap.GetUnitsAt(t)) foreach (var victim in world.ActorMap.GetUnitsAt(t))
DoImpact(victim, firedBy, firepowerModifier); DoImpact(victim, firedBy, damageModifiers);
} }
public override void DoImpact(Actor victim, Actor firedBy, float firepowerModifier) public override void DoImpact(Actor victim, Actor firedBy, IEnumerable<int> damageModifiers)
{ {
if (IsValidAgainst(victim, firedBy)) if (IsValidAgainst(victim, firedBy))
{ {
var damage = GetDamageToInflict(victim, firedBy, firepowerModifier); var damage = GetDamageToInflict(victim, firedBy, damageModifiers);
victim.InflictDamage(firedBy, damage, this); victim.InflictDamage(firedBy, damage, this);
} }
} }
public int GetDamageToInflict(Actor target, Actor firedBy, float modifier) public int GetDamageToInflict(Actor target, Actor firedBy, IEnumerable<int> damageModifiers)
{ {
var healthInfo = target.Info.Traits.GetOrDefault<HealthInfo>(); var healthInfo = target.Info.Traits.GetOrDefault<HealthInfo>();
if (healthInfo == null) if (healthInfo == null)
return 0; return 0;
var rawDamage = (float)Damage; return Util.ApplyPercentageModifiers(Damage, damageModifiers.Append(EffectivenessAgainst(target.Info)));
return (int)(rawDamage * modifier * EffectivenessAgainst(target.Info));
} }
} }
} }

View File

@@ -22,40 +22,41 @@ namespace OpenRA.Mods.RA
[Desc("For Normal DamageModel: Distance from the explosion center at which damage is 1/2.")] [Desc("For Normal DamageModel: Distance from the explosion center at which damage is 1/2.")]
public readonly WRange Spread = new WRange(43); public readonly WRange Spread = new WRange(43);
public override void DoImpact(WPos pos, Actor firedBy, float firepowerModifier) public override void DoImpact(WPos pos, Actor firedBy, IEnumerable<int> damageModifiers)
{ {
var world = firedBy.World; var world = firedBy.World;
var maxSpread = new WRange((int)(Spread.Range * (float)Math.Log(Math.Abs(Damage), 2))); var maxSpread = new WRange((int)(Spread.Range * (float)Math.Log(Math.Abs(Damage), 2)));
var hitActors = world.FindActorsInCircle(pos, maxSpread); var hitActors = world.FindActorsInCircle(pos, maxSpread);
foreach (var victim in hitActors) foreach (var victim in hitActors)
{
if (IsValidAgainst(victim, firedBy)) if (IsValidAgainst(victim, firedBy))
{ {
var damage = (int)GetDamageToInflict(pos, victim, firedBy, firepowerModifier); var damage = (int)GetDamageToInflict(pos, victim, firedBy, damageModifiers);
victim.InflictDamage(firedBy, damage, this); victim.InflictDamage(firedBy, damage, this);
} }
}
} }
public override void DoImpact(Actor victim, Actor firedBy, float firepowerModifier) public override void DoImpact(Actor victim, Actor firedBy, IEnumerable<int> damageModifiers)
{ {
if (IsValidAgainst(victim, firedBy)) if (IsValidAgainst(victim, firedBy))
{ {
var damage = GetDamageToInflict(victim.CenterPosition, victim, firedBy, firepowerModifier); var damage = GetDamageToInflict(victim.CenterPosition, victim, firedBy, damageModifiers);
victim.InflictDamage(firedBy, damage, this); victim.InflictDamage(firedBy, damage, this);
} }
} }
public int GetDamageToInflict(WPos pos, Actor target, Actor firedBy, float modifier) public int GetDamageToInflict(WPos pos, Actor target, Actor firedBy, IEnumerable<int> damageModifiers)
{ {
var healthInfo = target.Info.Traits.GetOrDefault<HealthInfo>(); var healthInfo = target.Info.Traits.GetOrDefault<HealthInfo>();
if (healthInfo == null) if (healthInfo == null)
return 0; return 0;
var distance = Math.Max(0, (target.CenterPosition - pos).Length - healthInfo.Radius.Range); var distance = Math.Max(0, (target.CenterPosition - pos).Length - healthInfo.Radius.Range);
var falloff = (float)GetDamageFalloff(distance * 1f / Spread.Range); var falloff = (int)(100 * GetDamageFalloff(distance * 1f / Spread.Range));
var rawDamage = (float)(falloff * Damage);
return (int)(rawDamage * modifier * EffectivenessAgainst(target.Info)); return Util.ApplyPercentageModifiers(Damage, damageModifiers.Append(EffectivenessAgainst(target.Info), falloff));
} }
static readonly float[] falloff = static readonly float[] falloff =