Custom Warheads refactor

Changes included:

Warhead code split out of weapon code and refactored.
Warhead functionality now split into several classes, each handling one effect/impact.

Additional custom warheads can now be defined and called via yaml.
Custom warheads inherit the abstract class Warhead,
which provides target check functions.

Custom warheads have to define their own impact functions,
and can also define their own replacement for check
functions.
This commit is contained in:
UberWaffe
2014-07-09 17:58:06 +02:00
parent f84b1c145e
commit c972b39687
59 changed files with 2275 additions and 1233 deletions

View File

@@ -509,10 +509,16 @@ namespace OpenRA
internal Func<MiniYaml, object> GetLoader(Type type) internal Func<MiniYaml, object> GetLoader(Type type)
{ {
const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static; const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy;
if (!string.IsNullOrEmpty(Loader)) if (!string.IsNullOrEmpty(Loader))
return (Func<MiniYaml, object>)Delegate.CreateDelegate(typeof(Func<MiniYaml, object>), type.GetMethod(Loader, flags)); {
var method = type.GetMethod(Loader, flags);
if (method == null)
throw new InvalidOperationException("{0} does not specify a loader function '{1}'".F(type.Name, Loader));
return (Func<MiniYaml, object>)Delegate.CreateDelegate(typeof(Func<MiniYaml, object>), method);
}
return null; return null;
} }

View File

@@ -0,0 +1,102 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Effects;
using OpenRA.Traits;
namespace OpenRA.GameRules
{
[Desc("Base warhead class. This can be used to derive other warheads from.")]
public abstract class Warhead
{
[Desc("What types of targets are affected.")]
public readonly string[] ValidTargets = { "Air", "Ground", "Water" };
[Desc("What types of targets are unaffected.", "Overrules ValidTargets.")]
public readonly string[] InvalidTargets = { };
[Desc("Delay in ticks before applying the warhead effect.","0 = instant (old model).")]
public readonly int Delay = 0;
public abstract void DoImpact(Target target, Actor firedBy, float firepowerModifier);
public abstract float EffectivenessAgainst(ActorInfo ai);
public bool IsValidAgainst(Target target, World world, Actor firedBy)
{
if (target.Type == TargetType.Actor)
return IsValidAgainst(target.Actor, firedBy);
if (target.Type == TargetType.FrozenActor)
return IsValidAgainst(target.FrozenActor, firedBy);
if (target.Type == TargetType.Terrain)
{
var cell = world.Map.CellContaining(target.CenterPosition);
if (!world.Map.Contains(cell))
return false;
var cellInfo = world.Map.GetTerrainInfo(cell);
if (!ValidTargets.Intersect(cellInfo.TargetTypes).Any()
|| InvalidTargets.Intersect(cellInfo.TargetTypes).Any())
return false;
return true;
}
return false;
}
public bool IsValidAgainst(Actor victim, Actor firedBy)
{
// A target type is valid if it is in the valid targets list, and not in the invalid targets list.
return InTargetList(victim, firedBy, ValidTargets) &&
!InTargetList(victim, firedBy, InvalidTargets);
}
public static bool InTargetList(Actor victim, Actor firedBy, string[] targetList)
{
if (!targetList.Any())
return false;
var targetable = victim.TraitOrDefault<ITargetable>();
if (targetable == null)
return false;
if (!targetList.Intersect(targetable.TargetTypes).Any())
return false;
return true;
}
public bool IsValidAgainst(FrozenActor victim, Actor firedBy)
{
// A target type is valid if it is in the valid targets list, and not in the invalid targets list.
return InTargetList(victim, firedBy, ValidTargets) &&
!InTargetList(victim, firedBy, InvalidTargets);
}
public static bool InTargetList(FrozenActor victim, Actor firedBy, string[] targetList)
{
// Frozen Actors need to be handled slightly differently. Since FrozenActor.Actor can be null if the Actor is dead.
if (!targetList.Any())
return false;
var targetable = victim.Info.Traits.GetOrDefault<ITargetableInfo>();
if (targetable == null)
return false;
if (!targetList.Intersect(targetable.GetTargetTypes()).Any())
return false;
return true;
}
}
}

View File

@@ -0,0 +1,84 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Effects;
using OpenRA.Traits;
namespace OpenRA.GameRules
{
public class AbsoluteSpreadDamageWarhead : DamageWarhead
{
[Desc("Maximum spread of the associated SpreadFactor.")]
public readonly WRange[] Spread = { new WRange(43) };
[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 override void DoImpact(Target target, Actor firedBy, float firepowerModifier)
{
// Used by traits that damage a single actor, rather than a position
if (target.Type == TargetType.Actor)
DoImpact(target.Actor, firedBy, firepowerModifier);
else
DoImpact(target.CenterPosition, firedBy, firepowerModifier);
}
public void DoImpact(WPos pos, Actor firedBy, float firepowerModifier)
{
var world = firedBy.World;
for (var i = 0; i < Spread.Length; i++)
{
var currentSpread = Spread[i];
var currentFactor = SpreadFactor[i];
var previousSpread = WRange.Zero;
if (i > 0)
previousSpread = Spread[i - 1];
if (currentFactor <= 0f)
continue;
var hitActors = world.FindActorsInCircle(pos, currentSpread);
if (previousSpread.Range > 0)
hitActors.Except(world.FindActorsInCircle(pos, previousSpread));
foreach (var victim in hitActors)
if (IsValidAgainst(victim, firedBy))
{
var damage = GetDamageToInflict(victim, firedBy, firepowerModifier * currentFactor);
victim.InflictDamage(firedBy, damage, this);
}
}
}
public void DoImpact(Actor victim, Actor firedBy, float firepowerModifier)
{
if (IsValidAgainst(victim, firedBy))
{
var currentFactor = SpreadFactor[0];
var damage = (int)GetDamageToInflict(victim, firedBy, firepowerModifier * currentFactor);
victim.InflictDamage(firedBy, damage, this);
}
}
public int GetDamageToInflict(Actor target, Actor firedBy, float modifier)
{
var healthInfo = target.Info.Traits.GetOrDefault<HealthInfo>();
if (healthInfo == null)
return 0;
var rawDamage = (float)Damage;
return (int)(rawDamage * modifier * EffectivenessAgainst(target.Info));
}
}
}

View File

@@ -0,0 +1,59 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Effects;
using OpenRA.Traits;
namespace OpenRA.GameRules
{
public abstract class DamageWarhead : Warhead
{
[Desc("How much (raw) damage to deal")]
public readonly int Damage = 0;
[Desc("Infantry death animation to use")]
public readonly string InfDeath = "1";
[Desc("Whether we should prevent prone response for infantry.")]
public readonly bool PreventProne = false;
[Desc("By what percentage should damage be modified against prone infantry.")]
public readonly int ProneModifier = 50;
[FieldLoader.LoadUsing("LoadVersus")]
[Desc("Damage vs each armortype. 0% = can't target.")]
public readonly Dictionary<string, float> Versus;
public static object LoadVersus(MiniYaml yaml)
{
var nd = yaml.ToDictionary();
return nd.ContainsKey("Versus")
? nd["Versus"].ToDictionary(my => FieldLoader.GetValue<float>("(value)", my.Value))
: new Dictionary<string, float>();
}
public override float EffectivenessAgainst(ActorInfo ai)
{
var health = ai.Traits.GetOrDefault<HealthInfo>();
if (health == null)
return 0f;
var armor = ai.Traits.GetOrDefault<ArmorInfo>();
if (armor == null || armor.Type == null)
return 1f;
float versus;
return Versus.TryGetValue(armor.Type, out versus) ? versus : 1f;
}
}
}

View File

@@ -0,0 +1,71 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Effects;
using OpenRA.Traits;
namespace OpenRA.GameRules
{
public class HealthPercentageDamageWarhead : DamageWarhead
{
[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 override void DoImpact(Target target, Actor firedBy, float firepowerModifier)
{
// Used by traits that damage a single actor, rather than a position
if (target.Type == TargetType.Actor)
DoImpact(target.Actor, firedBy, firepowerModifier);
else
DoImpact(target.CenterPosition, firedBy, firepowerModifier);
}
public void DoImpact(WPos pos, Actor firedBy, float firepowerModifier)
{
var world = firedBy.World;
var range = Spread[0];
var hitActors = world.FindActorsInCircle(pos, range);
if (Spread.Length > 1 && Spread[1].Range > 0)
hitActors.Except(world.FindActorsInCircle(pos, Spread[1]));
foreach (var victim in hitActors)
DoImpact(victim, firedBy, firepowerModifier);
}
public void DoImpact(Actor victim, Actor firedBy, float firepowerModifier)
{
if (IsValidAgainst(victim, firedBy))
{
var damage = GetDamageToInflict(victim, firedBy, firepowerModifier);
if (damage != 0) // will be 0 if the target doesn't have HealthInfo
{
var healthInfo = victim.Info.Traits.Get<HealthInfo>();
damage = (float)(damage / 100 * healthInfo.HP);
}
victim.InflictDamage(firedBy, (int)damage, this);
}
}
public float GetDamageToInflict(Actor target, Actor firedBy, float modifier)
{
var healthInfo = target.Info.Traits.GetOrDefault<HealthInfo>();
if (healthInfo == null)
return 0;
var rawDamage = (float)Damage;
return rawDamage * modifier * EffectivenessAgainst(target.Info);
}
}
}

View File

@@ -0,0 +1,65 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Effects;
using OpenRA.Traits;
namespace OpenRA.GameRules
{
public class PerCellDamageWarhead : DamageWarhead
{
[Desc("Size of the area. Damage will be applied to this area.")]
public readonly int[] Size = { 0, 0 };
public override void DoImpact(Target target, Actor firedBy, float firepowerModifier)
{
// Used by traits that damage a single actor, rather than a position
if (target.Type == TargetType.Actor)
DoImpact(target.Actor, firedBy, firepowerModifier);
else
DoImpact(target.CenterPosition, firedBy, firepowerModifier);
}
public void DoImpact(WPos pos, Actor firedBy, float firepowerModifier)
{
var world = firedBy.World;
var targetTile = world.Map.CellContaining(pos);
var minRange = (Size.Length > 1 && Size[1] > 0) ? Size[1] : 0;
var affectedTiles = world.Map.FindTilesInAnnulus(targetTile, minRange, Size[0]);
foreach (var t in affectedTiles)
foreach (var victim in world.ActorMap.GetUnitsAt(t))
DoImpact(victim, firedBy, firepowerModifier);
}
public void DoImpact(Actor victim, Actor firedBy, float firepowerModifier)
{
if (IsValidAgainst(victim, firedBy))
{
var damage = GetDamageToInflict(victim, firedBy, firepowerModifier);
victim.InflictDamage(firedBy, damage, this);
}
}
public int GetDamageToInflict(Actor target, Actor firedBy, float modifier)
{
var healthInfo = target.Info.Traits.GetOrDefault<HealthInfo>();
if (healthInfo == null)
return 0;
var rawDamage = (float)Damage;
return (int)(rawDamage * modifier * EffectivenessAgainst(target.Info));
}
}
}

View File

@@ -0,0 +1,83 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Effects;
using OpenRA.Traits;
namespace OpenRA.GameRules
{
public class SpreadDamageWarhead : DamageWarhead
{
[Desc("For Normal DamageModel: Distance from the explosion center at which damage is 1/2.")]
public readonly WRange Spread = new WRange(43);
public override void DoImpact(Target target, Actor firedBy, float firepowerModifier)
{
// Used by traits that damage a single actor, rather than a position
if (target.Type == TargetType.Actor)
DoImpact(target.Actor, firedBy, firepowerModifier);
else
DoImpact(target.CenterPosition, firedBy, firepowerModifier);
}
public void DoImpact(WPos pos, Actor firedBy, float firepowerModifier)
{
var world = firedBy.World;
var maxSpread = new WRange((int)(Spread.Range * (float)Math.Log(Math.Abs(Damage), 2)));
var hitActors = world.FindActorsInCircle(pos, maxSpread);
foreach (var victim in hitActors)
if (IsValidAgainst(victim, firedBy))
{
var damage = (int)GetDamageToInflict(pos, victim, firedBy, firepowerModifier);
victim.InflictDamage(firedBy, damage, this);
}
}
public void DoImpact(Actor victim, Actor firedBy, float firepowerModifier)
{
if (IsValidAgainst(victim, firedBy))
{
var damage = GetDamageToInflict(victim.CenterPosition, victim, firedBy, firepowerModifier);
victim.InflictDamage(firedBy, damage, this);
}
}
public int GetDamageToInflict(WPos pos, Actor target, Actor firedBy, float modifier)
{
var healthInfo = target.Info.Traits.GetOrDefault<HealthInfo>();
if (healthInfo == null)
return 0;
var distance = Math.Max(0, (target.CenterPosition - pos).Length - healthInfo.Radius.Range);
var falloff = (float)GetDamageFalloff(distance * 1f / Spread.Range);
var rawDamage = (float)(falloff * Damage);
return (int)(rawDamage * modifier * EffectivenessAgainst(target.Info));
}
static readonly float[] falloff =
{
1f, 0.3678795f, 0.1353353f, 0.04978707f,
0.01831564f, 0.006737947f, 0.002478752f, 0.000911882f
};
static float GetDamageFalloff(float x)
{
var u = (int)x;
if (u >= falloff.Length - 1) return 0;
var t = x - u;
return (falloff[u] * (1 - t)) + (falloff[u + 1] * t);
}
}
}

View File

@@ -8,6 +8,7 @@
*/ */
#endregion #endregion
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA.Effects; using OpenRA.Effects;
@@ -15,83 +16,6 @@ using OpenRA.Traits;
namespace OpenRA.GameRules namespace OpenRA.GameRules
{ {
public class WarheadInfo
{
[Desc("Distance from the explosion center at which damage is 1/2.")]
public readonly WRange Spread = new WRange(43);
[Desc("Maximum Spread. If a value >= Spread is set, this sets a fixed maximum area of damage.")]
public readonly WRange MaxSpread = new WRange(0);
[FieldLoader.LoadUsing("LoadVersus")]
[Desc("Damage vs each armortype. 0% = can't target.")]
public readonly Dictionary<string, float> Versus;
[Desc("Can this damage resource patches?")]
public readonly bool DestroyResources = false;
[Desc("Will this splatter resources and which?")]
public readonly string AddsResourceType = null;
[Desc("Explosion effect to use.")]
public readonly string Explosion = null;
[Desc("Palette to use for explosion effect.")]
public readonly string ExplosionPalette = "effect";
[Desc("Explosion effect on hitting water (usually a splash).")]
public readonly string WaterExplosion = null;
[Desc("Palette to use for effect on hitting water (usually a splash).")]
public readonly string WaterExplosionPalette = "effect";
[Desc("Type of smudge to apply to terrain.")]
public readonly string[] SmudgeType = { };
[Desc("Size of the explosion. provide 2 values for a ring effect (outer/inner).")]
public readonly int[] Size = { 0, 0 };
[Desc("Infantry death animation to use")]
public readonly string InfDeath = "1";
[Desc("Sound to play on impact.")]
public readonly string ImpactSound = null;
[Desc("Sound to play on impact with water")]
public readonly string WaterImpactSound = null;
[Desc("How much (raw) damage to deal")]
public readonly int Damage = 0;
[Desc("Delay in ticks before dealing the damage, 0 = instant (old model).")]
public readonly int Delay = 0;
[Desc("Which damage model to use.")]
public readonly DamageModel DamageModel = DamageModel.Normal;
[Desc("Whether we should prevent prone response for infantry.")]
public readonly bool PreventProne = false;
[Desc("By what percentage should damage be modified against prone infantry.")]
public readonly int ProneModifier = 50;
public float EffectivenessAgainst(ActorInfo ai)
{
var health = ai.Traits.GetOrDefault<HealthInfo>();
if (health == null)
return 0f;
var armor = ai.Traits.GetOrDefault<ArmorInfo>();
if (armor == null || armor.Type == null)
return 1;
float versus;
return Versus.TryGetValue(armor.Type, out versus) ? versus : 1;
}
public WarheadInfo(MiniYaml yaml)
{
FieldLoader.Load(this, yaml);
}
static object LoadVersus(MiniYaml y)
{
var nd = y.ToDictionary();
return nd.ContainsKey("Versus")
? nd["Versus"].ToDictionary(my => FieldLoader.GetValue<float>("(value)", my.Value))
: new Dictionary<string, float>();
}
}
public enum DamageModel
{
Normal, // classic RA damage model: point actors, distance-based falloff
PerCell, // like RA's "nuke damage"
HealthPercentage // for MAD Tank
}
public class ProjectileArgs public class ProjectileArgs
{ {
public WeaponInfo Weapon; public WeaponInfo Weapon;
@@ -107,20 +31,38 @@ namespace OpenRA.GameRules
public class WeaponInfo public class WeaponInfo
{ {
[Desc("The maximum range the weapon can fire.")]
public readonly WRange Range = WRange.Zero; public readonly WRange Range = WRange.Zero;
[Desc("The sound played when the weapon is fired.")]
public readonly string[] Report = null; public readonly string[] Report = null;
[Desc("Rate of Fire")]
[Desc("Rate of Fire = Delay in ticks between reloading ammo magazines.")]
public readonly int ROF = 1; public readonly int ROF = 1;
[Desc("Number of shots in a single ammo magazine.")]
public readonly int Burst = 1; public readonly int Burst = 1;
public readonly bool Charges = false; public readonly bool Charges = false;
public readonly string Palette = "effect"; public readonly string Palette = "effect";
[Desc("What types of targets are affected.")]
public readonly string[] ValidTargets = { "Ground", "Water" }; public readonly string[] ValidTargets = { "Ground", "Water" };
[Desc("What types of targets are unaffected.", "Overrules ValidTargets.")]
public readonly string[] InvalidTargets = { }; public readonly string[] InvalidTargets = { };
[Desc("Delay in ticks between firing shots from the same ammo magazine.")]
public readonly int BurstDelay = 5; public readonly int BurstDelay = 5;
[Desc("The minimum range the weapon can fire.")]
public readonly WRange MinRange = WRange.Zero; public readonly WRange MinRange = WRange.Zero;
[FieldLoader.LoadUsing("LoadProjectile")] public IProjectileInfo Projectile; [FieldLoader.LoadUsing("LoadProjectile")]
[FieldLoader.LoadUsing("LoadWarheads")] public List<WarheadInfo> Warheads; public readonly IProjectileInfo Projectile;
[FieldLoader.LoadUsing("LoadWarheads")]
public readonly List<Warhead> Warheads = new List<Warhead>();
public WeaponInfo(string name, MiniYaml content) public WeaponInfo(string name, MiniYaml content)
{ {
@@ -139,47 +81,24 @@ namespace OpenRA.GameRules
static object LoadWarheads(MiniYaml yaml) static object LoadWarheads(MiniYaml yaml)
{ {
var ret = new List<WarheadInfo>(); var retList = new List<Warhead>();
foreach (var w in yaml.Nodes) foreach (var node in yaml.Nodes.Where(n => n.Key.StartsWith("Warhead")))
if (w.Key.Split('@')[0] == "Warhead") {
ret.Add(new WarheadInfo(w.Value)); var ret = Game.CreateObject<Warhead>(node.Value.Value + "Warhead");
FieldLoader.Load(ret, node.Value);
retList.Add(ret);
}
return ret; return retList;
} }
public bool IsValidAgainst(Actor a) public bool IsValidAgainst(Target target, World world, Actor firedBy)
{
var targetable = a.TraitOrDefault<ITargetable>();
if (targetable == null || !ValidTargets.Intersect(targetable.TargetTypes).Any()
|| InvalidTargets.Intersect(targetable.TargetTypes).Any())
return false;
if (Warheads.All(w => w.EffectivenessAgainst(a.Info) <= 0))
return false;
return true;
}
public bool IsValidAgainst(FrozenActor a)
{
var targetable = a.Info.Traits.GetOrDefault<ITargetableInfo>();
if (targetable == null || !ValidTargets.Intersect(targetable.GetTargetTypes()).Any()
|| InvalidTargets.Intersect(targetable.GetTargetTypes()).Any())
return false;
if (Warheads.All(w => w.EffectivenessAgainst(a.Info) <= 0))
return false;
return true;
}
public bool IsValidAgainst(Target target, World world)
{ {
if (target.Type == TargetType.Actor) if (target.Type == TargetType.Actor)
return IsValidAgainst(target.Actor); return IsValidAgainst(target.Actor, firedBy);
if (target.Type == TargetType.FrozenActor) if (target.Type == TargetType.FrozenActor)
return IsValidAgainst(target.FrozenActor); return IsValidAgainst(target.FrozenActor, firedBy);
if (target.Type == TargetType.Terrain) if (target.Type == TargetType.Terrain)
{ {
@@ -197,5 +116,47 @@ namespace OpenRA.GameRules
return false; return false;
} }
public bool IsValidAgainst(Actor victim, Actor firedBy)
{
if (!Warheads.Any(w => w.IsValidAgainst(victim, firedBy)))
return false;
var targetable = victim.TraitOrDefault<ITargetable>();
if (targetable == null || !ValidTargets.Intersect(targetable.TargetTypes).Any()
|| InvalidTargets.Intersect(targetable.TargetTypes).Any())
return false;
return true;
}
public bool IsValidAgainst(FrozenActor victim, Actor firedBy)
{
// Frozen Actors are treated slightly differently.
if (!Warheads.Any(w => w.IsValidAgainst(victim, firedBy)))
return false;
var targetable = victim.Info.Traits.GetOrDefault<ITargetableInfo>();
if (targetable == null || !ValidTargets.Intersect(targetable.GetTargetTypes()).Any()
|| InvalidTargets.Intersect(targetable.GetTargetTypes()).Any())
return false;
return true;
}
public void Impact(WPos pos, Actor firedBy, float damageModifier)
{
foreach (var wh in Warheads)
{
Action a;
a = () => wh.DoImpact(Target.FromPos(pos), firedBy, damageModifier);
if (wh.Delay > 0)
firedBy.World.AddFrameEndTask(
w => w.Add(new DelayedAction(wh.Delay, a)));
else
a();
}
}
} }
} }

View File

@@ -75,6 +75,12 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Actor.cs" /> <Compile Include="Actor.cs" />
<Compile Include="GameRules\Warhead.cs" />
<Compile Include="GameRules\Warheads\AbsoluteSpreadDamageWarhead.cs" />
<Compile Include="GameRules\Warheads\DamageWarhead.cs" />
<Compile Include="GameRules\Warheads\HealthPercentageDamageWarhead.cs" />
<Compile Include="GameRules\Warheads\PerCellDamageWarhead.cs" />
<Compile Include="GameRules\Warheads\SpreadDamageWarhead.cs" />
<Compile Include="Graphics\QuadRenderer.cs" /> <Compile Include="Graphics\QuadRenderer.cs" />
<Compile Include="Download.cs" /> <Compile Include="Download.cs" />
<Compile Include="Effects\DelayedAction.cs" /> <Compile Include="Effects\DelayedAction.cs" />

View File

@@ -98,7 +98,7 @@ namespace OpenRA.Traits
nd.AppliedDamage(repairer, self, ai); nd.AppliedDamage(repairer, self, ai);
} }
public void InflictDamage(Actor self, Actor attacker, int damage, WarheadInfo warhead, bool ignoreModifiers) public void InflictDamage(Actor self, Actor attacker, int damage, DamageWarhead warhead, bool ignoreModifiers)
{ {
if (IsDead) return; /* overkill! don't count extra hits as more kills! */ if (IsDead) return; /* overkill! don't count extra hits as more kills! */
@@ -177,7 +177,7 @@ namespace OpenRA.Traits
return (health == null) ? DamageState.Undamaged : health.DamageState; return (health == null) ? DamageState.Undamaged : health.DamageState;
} }
public static void InflictDamage(this Actor self, Actor attacker, int damage, WarheadInfo warhead) public static void InflictDamage(this Actor self, Actor attacker, int damage, DamageWarhead warhead)
{ {
if (self.Destroyed) return; if (self.Destroyed) return;
var health = self.TraitOrDefault<Health>(); var health = self.TraitOrDefault<Health>();

View File

@@ -27,7 +27,7 @@ namespace OpenRA.Traits
public class AttackInfo public class AttackInfo
{ {
public Actor Attacker; public Actor Attacker;
public WarheadInfo Warhead; public DamageWarhead Warhead;
public int Damage; public int Damage;
public DamageState DamageState; public DamageState DamageState;
public DamageState PreviousDamageState; public DamageState PreviousDamageState;
@@ -149,7 +149,7 @@ namespace OpenRA.Traits
} }
public interface IRenderModifier { IEnumerable<IRenderable> ModifyRender(Actor self, WorldRenderer wr, IEnumerable<IRenderable> r); } public interface IRenderModifier { IEnumerable<IRenderable> ModifyRender(Actor self, WorldRenderer wr, IEnumerable<IRenderable> r); }
public interface IDamageModifier { float GetDamageModifier(Actor attacker, WarheadInfo warhead); } public interface IDamageModifier { float GetDamageModifier(Actor attacker, DamageWarhead warhead); }
public interface ISpeedModifier { decimal GetSpeedModifier(); } public interface ISpeedModifier { decimal GetSpeedModifier(); }
public interface IFirepowerModifier { float GetFirepowerModifier(); } public interface IFirepowerModifier { float GetFirepowerModifier(); }
public interface ILoadsPalettes { void LoadPalettes(WorldRenderer wr); } public interface ILoadsPalettes { void LoadPalettes(WorldRenderer wr); }

View File

@@ -10,6 +10,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using OpenRA.Effects; using OpenRA.Effects;
using OpenRA.GameRules;
using OpenRA.Graphics; using OpenRA.Graphics;
using OpenRA.Mods.RA; using OpenRA.Mods.RA;
using OpenRA.Traits; using OpenRA.Traits;
@@ -44,7 +45,8 @@ namespace OpenRA.Mods.Cnc.Effects
void Finish(World world) void Finish(World world)
{ {
world.AddFrameEndTask(w => w.Remove(this)); world.AddFrameEndTask(w => w.Remove(this));
Combat.DoExplosion(firedBy.PlayerActor, weapon, target.CenterPosition); var weapon = world.Map.Rules.Weapons[this.weapon.ToLowerInvariant()];
weapon.Impact(target.CenterPosition, firedBy.PlayerActor, 1f);
} }
} }
} }

View File

@@ -11,6 +11,7 @@
using System.Linq; using System.Linq;
using OpenRA.Traits; using OpenRA.Traits;
using OpenRA.Mods.RA; using OpenRA.Mods.RA;
using OpenRA.GameRules;
namespace OpenRA.Mods.Cnc namespace OpenRA.Mods.Cnc
{ {
@@ -42,8 +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);
self.InflictDamage(self.World.WorldActor, weapon.Warheads[0].Damage, weapon.Warheads[0]);
poisonTicks = weapon.ROF; poisonTicks = weapon.ROF;
} }
} }

View File

@@ -65,9 +65,7 @@ namespace OpenRA.Mods.D2k
if (health.HP <= damageThreshold || --damageTicks > 0) if (health.HP <= damageThreshold || --damageTicks > 0)
return; return;
foreach (var w in weapon.Warheads) weapon.Impact(self.CenterPosition, self.World.WorldActor, 1f);
health.InflictDamage(self, self.World.WorldActor, w.Damage, w, false);
damageTicks = weapon.ROF; damageTicks = weapon.ROF;
} }
} }

View File

@@ -13,6 +13,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using AI.Fuzzy.Library; using AI.Fuzzy.Library;
using OpenRA.Mods.RA.Move; using OpenRA.Mods.RA.Move;
using OpenRA.GameRules;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.RA.AI namespace OpenRA.Mods.RA.AI
@@ -195,8 +196,11 @@ namespace OpenRA.Mods.RA.AI
var sumOfDamage = 0; var sumOfDamage = 0;
var arms = a.TraitsImplementing<Armament>(); var arms = a.TraitsImplementing<Armament>();
foreach (var arm in arms) foreach (var arm in arms)
if (arm.Weapon.Warheads[0] != null) {
sumOfDamage += arm.Weapon.Warheads[0].Damage; var warhead = arm.Weapon.Warheads.Select(w => w as DamageWarhead).FirstOrDefault(w => w != null);
if (warhead != null)
sumOfDamage += warhead.Damage;
}
return sumOfDamage; return sumOfDamage;
}); });
} }

View File

@@ -63,7 +63,7 @@ namespace OpenRA.Mods.RA.Activities
mobile.IsMoving = false; mobile.IsMoving = false;
self.World.ActorMap.GetUnitsAt(mobile.toCell, mobile.toSubCell) self.World.ActorMap.GetUnitsAt(mobile.toCell, mobile.toSubCell)
.Except(new []{self}).Where(t => weapon.IsValidAgainst(t)) .Except(new []{self}).Where(t => weapon.IsValidAgainst(t, self))
.Do(t => t.Kill(self)); .Do(t => t.Kill(self));
return NextActivity; return NextActivity;

View File

@@ -8,6 +8,7 @@
*/ */
#endregion #endregion
using OpenRA.GameRules;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.RA.Air namespace OpenRA.Mods.RA.Air
@@ -51,7 +52,10 @@ namespace OpenRA.Mods.RA.Air
if (self.CenterPosition.Z <= 0) if (self.CenterPosition.Z <= 0)
{ {
if (info.Explosion != null) if (info.Explosion != null)
Combat.DoExplosion(self, info.Explosion, self.CenterPosition); {
var weapon = self.World.Map.Rules.Weapons[info.Explosion.ToLowerInvariant()];
weapon.Impact(self.CenterPosition, self, 1f);
}
self.Destroy(); self.Destroy();
return null; return null;

View File

@@ -142,7 +142,7 @@ namespace OpenRA.Mods.RA
if (Weapon.MinRange != WRange.Zero && target.IsInRange(self.CenterPosition, Weapon.MinRange)) if (Weapon.MinRange != WRange.Zero && target.IsInRange(self.CenterPosition, Weapon.MinRange))
return null; return null;
if (!Weapon.IsValidAgainst(target, self.World)) if (!Weapon.IsValidAgainst(target, self.World, self))
return null; return null;
var barrel = Barrels[Burst % Barrels.Length]; var barrel = Barrels[Burst % Barrels.Length];

View File

@@ -12,6 +12,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using OpenRA.GameRules;
using OpenRA.Mods.RA.Buildings; using OpenRA.Mods.RA.Buildings;
using OpenRA.Traits; using OpenRA.Traits;
@@ -87,11 +88,11 @@ namespace OpenRA.Mods.RA
{ {
get get
{ {
var armament = Armaments.FirstOrDefault(); var armament = Armaments.FirstOrDefault(a => a.Weapon.Warheads.Any(w => (w is DamageWarhead)));
if (armament == null) if (armament == null)
yield break; yield break;
var negativeDamage = armament.Weapon.Warheads[0].Damage < 0; var negativeDamage = (armament.Weapon.Warheads.FirstOrDefault(w => (w is DamageWarhead)) as DamageWarhead).Damage < 0;
yield return new AttackOrderTargeter(this, "Attack", 6, negativeDamage); yield return new AttackOrderTargeter(this, "Attack", 6, negativeDamage);
} }
} }
@@ -134,13 +135,13 @@ namespace OpenRA.Mods.RA
public abstract Activity GetAttackActivity(Actor self, Target newTarget, bool allowMove); public abstract Activity GetAttackActivity(Actor self, Target newTarget, bool allowMove);
public bool HasAnyValidWeapons(Target t) { return Armaments.Any(a => a.Weapon.IsValidAgainst(t, self.World)); } public bool HasAnyValidWeapons(Target t) { return Armaments.Any(a => a.Weapon.IsValidAgainst(t, self.World, self)); }
public WRange GetMaximumRange() public WRange GetMaximumRange()
{ {
return Armaments.Select(a => a.Weapon.Range).Append(WRange.Zero).Max(); return Armaments.Select(a => a.Weapon.Range).Append(WRange.Zero).Max();
} }
public Armament ChooseArmamentForTarget(Target t) { return Armaments.FirstOrDefault(a => a.Weapon.IsValidAgainst(t, self.World)); } public Armament ChooseArmamentForTarget(Target t) { return Armaments.FirstOrDefault(a => a.Weapon.IsValidAgainst(t, self.World, self)); }
public void AttackTarget(Target target, bool queued, bool allowMove) public void AttackTarget(Target target, bool queued, bool allowMove)
{ {

View File

@@ -22,6 +22,8 @@ namespace OpenRA.Mods.RA
[Desc("How many game ticks should pass before closing the actor's turret.")] [Desc("How many game ticks should pass before closing the actor's turret.")]
public int CloseDelay = 125; public int CloseDelay = 125;
public int DefaultFacing = 0; public int DefaultFacing = 0;
[Desc("The factor damage received is multiplied by while this actor is closed.")]
public float ClosedDamageMultiplier = 0.5f; public float ClosedDamageMultiplier = 0.5f;
public override object Create(ActorInitializer init) { return new AttackPopupTurreted(init, this); } public override object Create(ActorInitializer init) { return new AttackPopupTurreted(init, this); }
@@ -103,7 +105,7 @@ namespace OpenRA.Mods.RA
} }
} }
public float GetDamageModifier(Actor attacker, WarheadInfo warhead) public float GetDamageModifier(Actor attacker, DamageWarhead warhead)
{ {
return state == PopupState.Closed ? info.ClosedDamageMultiplier : 1f; return state == PopupState.Closed ? info.ClosedDamageMultiplier : 1f;
} }

View File

@@ -11,6 +11,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA.Effects; using OpenRA.Effects;
using OpenRA.GameRules;
using OpenRA.Graphics; using OpenRA.Graphics;
using OpenRA.Primitives; using OpenRA.Primitives;
using OpenRA.Traits; using OpenRA.Traits;
@@ -294,7 +295,8 @@ namespace OpenRA.Mods.RA
var initialDamage = Health.DamageState; var initialDamage = Health.DamageState;
self.World.AddFrameEndTask(w => self.World.AddFrameEndTask(w =>
{ {
Combat.DoExplosion(saboteur, "Demolish", self.CenterPosition); var weapon = saboteur.World.Map.Rules.Weapons["demolish"];
weapon.Impact(self.CenterPosition, saboteur, 1f);
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

@@ -1,232 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Effects;
using OpenRA.GameRules;
using OpenRA.Mods.RA.Effects;
using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
// some utility bits that are shared between various things
public static class Combat
{
static string GetImpactSound(WarheadInfo warhead, bool isWater)
{
if (isWater && warhead.WaterImpactSound != null)
return warhead.WaterImpactSound;
if (warhead.ImpactSound != null)
return warhead.ImpactSound;
return null;
}
public static void DoImpact(WPos pos, WarheadInfo warhead, WeaponInfo weapon, Actor firedBy, float firepowerModifier)
{
var world = firedBy.World;
var targetTile = world.Map.CellContaining(pos);
if (!world.Map.Contains(targetTile))
return;
var isWater = pos.Z <= 0 && world.Map.GetTerrainInfo(targetTile).IsWater;
var explosionType = isWater ? warhead.WaterExplosion : warhead.Explosion;
var explosionTypePalette = isWater ? warhead.WaterExplosionPalette : warhead.ExplosionPalette;
if (explosionType != null)
world.AddFrameEndTask(w => w.Add(new Explosion(w, pos, explosionType, explosionTypePalette)));
Sound.Play(GetImpactSound(warhead, isWater), pos);
var smudgeLayers = world.WorldActor.TraitsImplementing<SmudgeLayer>().ToDictionary(x => x.Info.Type);
var resLayer = warhead.DestroyResources || !string.IsNullOrEmpty(warhead.AddsResourceType) ? world.WorldActor.Trait<ResourceLayer>() : null;
if (warhead.Size[0] > 0)
{
var allCells = world.Map.FindTilesInCircle(targetTile, warhead.Size[0]).ToList();
// `smudgeCells` might want to just be an outer shell of the cells:
IEnumerable<CPos> smudgeCells = allCells;
if (warhead.Size.Length == 2)
smudgeCells = smudgeCells.Except(world.Map.FindTilesInCircle(targetTile, warhead.Size[1]));
// Draw the smudges:
foreach (var sc in smudgeCells)
{
var smudgeType = world.Map.GetTerrainInfo(sc).AcceptsSmudgeType.FirstOrDefault(t => warhead.SmudgeType.Contains(t));
if (smudgeType == null) continue;
SmudgeLayer smudgeLayer;
if (!smudgeLayers.TryGetValue(smudgeType, out smudgeLayer))
throw new NotImplementedException("Unknown smudge type `{0}`".F(smudgeType));
smudgeLayer.AddSmudge(sc);
if (warhead.DestroyResources)
resLayer.Destroy(sc);
}
// Destroy all resources in range, not just the outer shell:
if (warhead.DestroyResources)
foreach (var cell in allCells)
resLayer.Destroy(cell);
// Splatter resources:
if (!string.IsNullOrEmpty(warhead.AddsResourceType))
{
var resourceType = world.WorldActor.TraitsImplementing<ResourceType>()
.FirstOrDefault(t => t.Info.Name == warhead.AddsResourceType);
if (resourceType == null)
Log.Write("debug", "Warhead defines an invalid resource type '{0}'".F(warhead.AddsResourceType));
else
{
foreach (var cell in allCells)
{
if (!resLayer.CanSpawnResourceAt(resourceType, cell))
continue;
var splash = world.SharedRandom.Next(1, resourceType.Info.MaxDensity - resLayer.GetResourceDensity(cell));
resLayer.AddResource(resourceType, cell, splash);
}
}
}
}
else
{
var smudgeType = world.Map.GetTerrainInfo(targetTile).AcceptsSmudgeType.FirstOrDefault(t => warhead.SmudgeType.Contains(t));
if (smudgeType != null)
{
SmudgeLayer smudgeLayer;
if (!smudgeLayers.TryGetValue(smudgeType, out smudgeLayer))
throw new NotImplementedException("Unknown smudge type `{0}`".F(smudgeType));
smudgeLayer.AddSmudge(targetTile);
}
}
if (warhead.DestroyResources)
world.WorldActor.Trait<ResourceLayer>().Destroy(targetTile);
switch (warhead.DamageModel)
{
case DamageModel.Normal:
{
var spreadMax = warhead.MaxSpread.Range;
var maxSpreadCalculation = spreadMax >= warhead.Spread.Range ? spreadMax : (warhead.Spread.Range * (float)Math.Log(Math.Abs(warhead.Damage), 2));
var maxSpread = new WRange((int)(maxSpreadCalculation));
var hitActors = world.FindActorsInCircle(pos, maxSpread);
foreach (var victim in hitActors)
{
var damage = (int)GetDamageToInflict(pos, victim, warhead, weapon, firepowerModifier, true);
victim.InflictDamage(firedBy, damage, warhead);
}
}
break;
case DamageModel.PerCell:
{
foreach (var t in world.Map.FindTilesInCircle(targetTile, warhead.Size[0]))
{
foreach (var unit in world.ActorMap.GetUnitsAt(t))
{
var damage = (int)GetDamageToInflict(pos, unit, warhead, weapon, firepowerModifier, false);
unit.InflictDamage(firedBy, damage, warhead);
}
}
}
break;
case DamageModel.HealthPercentage:
{
var range = new WRange(warhead.Size[0] * 1024);
var hitActors = world.FindActorsInCircle(pos, range);
foreach (var victim in hitActors)
{
var damage = GetDamageToInflict(pos, victim, warhead, weapon, firepowerModifier, false);
if (damage != 0) // will be 0 if the target doesn't have HealthInfo
{
var healthInfo = victim.Info.Traits.Get<HealthInfo>();
damage = (float)(damage / 100 * healthInfo.HP);
}
victim.InflictDamage(firedBy, (int)damage, warhead);
}
}
break;
}
}
public static void DoImpacts(WPos pos, Actor firedBy, WeaponInfo weapon, float damageModifier)
{
foreach (var wh in weapon.Warheads)
{
var warhead = wh;
Action a = () => DoImpact(pos, warhead, weapon, firedBy, damageModifier);
if (warhead.Delay > 0)
firedBy.World.AddFrameEndTask(
w => w.Add(new DelayedAction(warhead.Delay, a)));
else
a();
}
}
public static void DoExplosion(Actor attacker, string weapontype, WPos pos)
{
var weapon = attacker.World.Map.Rules.Weapons[weapontype.ToLowerInvariant()];
if (weapon.Report != null && weapon.Report.Any())
Sound.Play(weapon.Report.Random(attacker.World.SharedRandom), pos);
DoImpacts(pos, attacker, weapon, 1f);
}
static readonly float[] falloff =
{
1f, 0.3678795f, 0.1353353f, 0.04978707f,
0.01831564f, 0.006737947f, 0.002478752f, 0.000911882f
};
static float GetDamageFalloff(float x)
{
var u = (int)x;
if (u >= falloff.Length - 1) return 0;
var t = x - u;
return (falloff[u] * (1 - t)) + (falloff[u + 1] * t);
}
static float GetDamageToInflict(WPos pos, Actor target, WarheadInfo warhead, WeaponInfo weapon, float modifier, bool withFalloff)
{
// don't hit air units with splash from ground explosions, etc
if (!weapon.IsValidAgainst(target))
return 0;
var healthInfo = target.Info.Traits.GetOrDefault<HealthInfo>();
if (healthInfo == null)
return 0;
var rawDamage = (float)warhead.Damage;
if (withFalloff)
{
var distance = Math.Max(0, (target.CenterPosition - pos).Length - healthInfo.Radius.Range);
var falloff = (float)GetDamageFalloff(distance * 1f / warhead.Spread.Range);
rawDamage = (float)(falloff * rawDamage);
}
return (float)(rawDamage * modifier * (float)warhead.EffectivenessAgainst(target.Info));
}
}
}

View File

@@ -8,6 +8,7 @@
*/ */
#endregion #endregion
using OpenRA.GameRules;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.RA namespace OpenRA.Mods.RA
@@ -28,7 +29,8 @@ namespace OpenRA.Mods.RA
public override void Activate(Actor collector) public override void Activate(Actor collector)
{ {
Combat.DoExplosion(self, ((ExplodeCrateActionInfo)info).Weapon, collector.CenterPosition); var weapon = self.World.Map.Rules.Weapons[((ExplodeCrateActionInfo)info).Weapon.ToLowerInvariant()];
weapon.Impact(collector.CenterPosition, self, 1f);
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));
Combat.DoImpacts(pos, args.SourceActor, args.Weapon, args.FirepowerModifier); args.Weapon.Impact(pos, args.SourceActor, args.FirepowerModifier);
} }
} }
} }

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));
Combat.DoImpacts(pos, args.SourceActor, args.Weapon, args.FirepowerModifier); args.Weapon.Impact(pos, args.SourceActor, args.FirepowerModifier);
} }
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);
Combat.DoImpacts(target, args.SourceActor, args.Weapon, args.FirepowerModifier); args.Weapon.Impact(target, args.SourceActor, args.FirepowerModifier);
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;
Combat.DoImpacts(pos, args.SourceActor, args.Weapon, args.FirepowerModifier); args.Weapon.Impact(pos, args.SourceActor, args.FirepowerModifier);
} }
public IEnumerable<IRenderable> Render(WorldRenderer wr) public IEnumerable<IRenderable> Render(WorldRenderer wr)

View File

@@ -11,6 +11,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA.Effects; using OpenRA.Effects;
using OpenRA.GameRules;
using OpenRA.Graphics; using OpenRA.Graphics;
using OpenRA.Traits; using OpenRA.Traits;
@@ -79,7 +80,8 @@ namespace OpenRA.Mods.RA.Effects
void Explode(World world) void Explode(World world)
{ {
world.AddFrameEndTask(w => w.Remove(this)); world.AddFrameEndTask(w => w.Remove(this));
Combat.DoExplosion(firedBy.PlayerActor, weapon, pos); var weapon = world.Map.Rules.Weapons[this.weapon.ToLowerInvariant()];
weapon.Impact(pos, firedBy.PlayerActor, 1f);
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;
Combat.DoImpacts(pos, Args.SourceActor, Args.Weapon, Args.FirepowerModifier); Args.Weapon.Impact(pos, Args.SourceActor, Args.FirepowerModifier);
doneDamage = true; doneDamage = true;
} }
} }

View File

@@ -9,6 +9,7 @@
#endregion #endregion
using System.Linq; using System.Linq;
using OpenRA.GameRules;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.RA namespace OpenRA.Mods.RA
@@ -43,9 +44,15 @@ namespace OpenRA.Mods.RA
if (explodesInfo.InfDeath != null && e.Warhead != null && !explodesInfo.InfDeath.Contains(e.Warhead.InfDeath)) if (explodesInfo.InfDeath != null && e.Warhead != null && !explodesInfo.InfDeath.Contains(e.Warhead.InfDeath))
return; return;
var weapon = ChooseWeaponForExplosion(self); var weaponName = ChooseWeaponForExplosion(self);
if (weapon != null) if (weaponName != null)
Combat.DoExplosion(e.Attacker, weapon, self.CenterPosition); {
var weapon = e.Attacker.World.Map.Rules.Weapons[weaponName.ToLowerInvariant()];
if (weapon.Report != null && weapon.Report.Any())
Sound.Play(weapon.Report.Random(e.Attacker.World.SharedRandom), self.CenterPosition);
weapon.Impact(self.CenterPosition, e.Attacker, 1f);
}
} }
string ChooseWeaponForExplosion(Actor self) string ChooseWeaponForExplosion(Actor self)

View File

@@ -82,7 +82,7 @@ namespace OpenRA.Mods.RA
} }
} }
public float GetDamageModifier(Actor attacker, WarheadInfo warhead) public float GetDamageModifier(Actor attacker, DamageWarhead warhead)
{ {
return Level > 0 ? 1 / info.ArmorModifier[Level - 1] : 1; return Level > 0 ? 1 / info.ArmorModifier[Level - 1] : 1;
} }

View File

@@ -67,7 +67,7 @@ namespace OpenRA.Mods.RA
return FirepowerLevel > 0 ? (1 + FirepowerLevel * info.FirepowerModifier) : 1; return FirepowerLevel > 0 ? (1 + FirepowerLevel * info.FirepowerModifier) : 1;
} }
public float GetDamageModifier(Actor attacker, WarheadInfo warhead) public float GetDamageModifier(Actor attacker, DamageWarhead warhead)
{ {
return ArmorLevel > 0 ? (1 / (1 + ArmorLevel * info.ArmorModifier)) : 1; return ArmorLevel > 0 ? (1 / (1 + ArmorLevel * info.ArmorModifier)) : 1;
} }

View File

@@ -18,6 +18,6 @@ namespace OpenRA.Mods.RA
class Invulnerable : IDamageModifier class Invulnerable : IDamageModifier
{ {
public float GetDamageModifier(Actor attacker, WarheadInfo warhead) { return 0.0f; } public float GetDamageModifier(Actor attacker, DamageWarhead warhead) { return 0.0f; }
} }
} }

View File

@@ -28,7 +28,7 @@ namespace OpenRA.Mods.RA
RemainingTicks--; RemainingTicks--;
} }
public float GetDamageModifier(Actor attacker, WarheadInfo warhead) public float GetDamageModifier(Actor attacker, DamageWarhead warhead)
{ {
return (RemainingTicks > 0) ? 0.0f : 1.0f; return (RemainingTicks > 0) ? 0.0f : 1.0f;
} }

View File

@@ -10,6 +10,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using OpenRA.GameRules;
using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Move; using OpenRA.Mods.RA.Move;
using OpenRA.Mods.RA.Orders; using OpenRA.Mods.RA.Orders;
@@ -68,7 +69,10 @@ namespace OpenRA.Mods.RA
if (++tick >= info.ThumpInterval) if (++tick >= info.ThumpInterval)
{ {
if (info.ThumpDamageWeapon != null) if (info.ThumpDamageWeapon != null)
Combat.DoExplosion(self, info.ThumpDamageWeapon, self.CenterPosition); {
var weapon = self.World.Map.Rules.Weapons[info.ThumpDamageWeapon.ToLowerInvariant()];
weapon.Impact(self.CenterPosition, self, 1f);
}
screenShaker.AddEffect(info.ThumpShakeTime, self.CenterPosition, info.ThumpShakeIntensity, info.ThumpShakeMultiplier); screenShaker.AddEffect(info.ThumpShakeTime, self.CenterPosition, info.ThumpShakeIntensity, info.ThumpShakeMultiplier);
tick = 0; tick = 0;
} }
@@ -104,7 +108,10 @@ namespace OpenRA.Mods.RA
self.World.AddFrameEndTask(w => self.World.AddFrameEndTask(w =>
{ {
if (info.DetonationWeapon != null) if (info.DetonationWeapon != null)
Combat.DoExplosion(self, info.DetonationWeapon, self.CenterPosition); {
var weapon = self.World.Map.Rules.Weapons[info.DetonationWeapon.ToLowerInvariant()];
weapon.Impact(self.CenterPosition, self, 1f);
}
self.Kill(self); self.Kill(self);
}); });
} }

View File

@@ -188,7 +188,6 @@
<Compile Include="ChronoshiftPaletteEffect.cs" /> <Compile Include="ChronoshiftPaletteEffect.cs" />
<Compile Include="Chronoshiftable.cs" /> <Compile Include="Chronoshiftable.cs" />
<Compile Include="Cloak.cs" /> <Compile Include="Cloak.cs" />
<Compile Include="Combat.cs" />
<Compile Include="ConquestVictoryConditions.cs" /> <Compile Include="ConquestVictoryConditions.cs" />
<Compile Include="ContainsCrate.cs" /> <Compile Include="ContainsCrate.cs" />
<Compile Include="Crate.cs" /> <Compile Include="Crate.cs" />
@@ -288,6 +287,10 @@
<Compile Include="Player\ProductionQueue.cs" /> <Compile Include="Player\ProductionQueue.cs" />
<Compile Include="Player\ProvidesTechPrerequisite.cs" /> <Compile Include="Player\ProvidesTechPrerequisite.cs" />
<Compile Include="PortableChrono.cs" /> <Compile Include="PortableChrono.cs" />
<Compile Include="Warheads\DestroyResourceWarhead.cs" />
<Compile Include="Warheads\CreateEffectWarhead.cs" />
<Compile Include="Warheads\CreateResourceWarhead.cs" />
<Compile Include="Warheads\LeaveSmudgeWarhead.cs" />
<Compile Include="World\RadarPings.cs" /> <Compile Include="World\RadarPings.cs" />
<Compile Include="Player\TechTree.cs" /> <Compile Include="Player\TechTree.cs" />
<Compile Include="PrimaryBuilding.cs" /> <Compile Include="PrimaryBuilding.cs" />

View File

@@ -20,7 +20,7 @@ namespace OpenRA.Mods.RA
{ {
public bool Invulnerable = false; public bool Invulnerable = false;
public float GetDamageModifier(Actor attacker, WarheadInfo warhead) public float GetDamageModifier(Actor attacker, DamageWarhead warhead)
{ {
return Invulnerable ? 0.0f : 1.0f; return Invulnerable ? 0.0f : 1.0f;
} }

View File

@@ -61,7 +61,7 @@ namespace OpenRA.Mods.RA
LocalOffset = WVec.Zero; LocalOffset = WVec.Zero;
} }
public float GetDamageModifier(Actor attacker, WarheadInfo warhead) public float GetDamageModifier(Actor attacker, DamageWarhead warhead)
{ {
return IsProne && warhead != null ? warhead.ProneModifier / 100f : 1f; return IsProne && warhead != null ? warhead.ProneModifier / 100f : 1f;
} }

View File

@@ -0,0 +1,86 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Effects;
using OpenRA.GameRules;
using OpenRA.Traits;
using OpenRA.Mods.RA.Effects;
namespace OpenRA.Mods.RA
{
public class CreateEffectWarhead : Warhead
{
[Desc("Size of the area. An explosion animation will be created in each tile.", "Provide 2 values for a ring effect (outer/inner).")]
public readonly int[] Size = { 0, 0 };
[Desc("Explosion effect to use.")]
public readonly string Explosion = null;
[Desc("Palette to use for explosion effect.")]
public readonly string ExplosionPalette = "effect";
[Desc("Explosion effect on hitting water (usually a splash).")]
public readonly string WaterExplosion = null;
[Desc("Palette to use for effect on hitting water (usually a splash).")]
public readonly string WaterExplosionPalette = "effect";
[Desc("Sound to play on impact.")]
public readonly string ImpactSound = null;
[Desc("Sound to play on impact with water")]
public readonly string WaterImpactSound = null;
public override void DoImpact(Target target, Actor firedBy, float firepowerModifier)
{
DoImpact(target.CenterPosition, firedBy, firepowerModifier);
}
public void DoImpact(WPos pos, Actor firedBy, float firepowerModifier)
{
var world = firedBy.World;
var targetTile = world.Map.CellContaining(pos);
if (!world.Map.Contains(targetTile))
return;
var minRange = (Size.Length > 1 && Size[1] > 0) ? Size[1] : 0;
var allCells = world.Map.FindTilesInAnnulus(targetTile, minRange, Size[0]);
// Draw the effects
foreach (var currentCell in allCells)
{
var currentPos = world.Map.CenterOfCell(currentCell);
// TODO: #5937 should go in here after rebase.
var isWater = currentPos.Z <= 0 && world.Map.GetTerrainInfo(currentCell).IsWater;
var explosionType = isWater ? WaterExplosion : Explosion;
var explosionTypePalette = isWater ? WaterExplosionPalette : ExplosionPalette;
if (explosionType != null)
world.AddFrameEndTask(w => w.Add(new Explosion(w, currentPos, explosionType, explosionTypePalette)));
}
string sound = null;
var isTargetWater = pos.Z <= 0 && world.Map.GetTerrainInfo(targetTile).IsWater;
if (isTargetWater && WaterImpactSound != null)
sound = WaterImpactSound;
if (ImpactSound != null)
sound = ImpactSound;
Sound.Play(sound, pos);
}
public override float EffectivenessAgainst(ActorInfo ai) { return 1f; }
}
}

View File

@@ -0,0 +1,66 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Effects;
using OpenRA.GameRules;
using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
public class CreateResourceWarhead : Warhead
{
[Desc("Size of the area. The resources are seeded within this area.", "Provide 2 values for a ring effect (outer/inner).")]
public readonly int[] Size = { 0, 0 };
[Desc("Will this splatter resources and which?")]
public readonly string AddsResourceType = null;
// TODO: Allow maximum resource splatter to be defined. (Per tile, and in total).
public override void DoImpact(Target target, Actor firedBy, float firepowerModifier)
{
DoImpact(target.CenterPosition, firedBy, firepowerModifier);
}
public void DoImpact(WPos pos, Actor firedBy, float firepowerModifier)
{
if (string.IsNullOrEmpty(AddsResourceType))
return;
var world = firedBy.World;
var targetTile = world.Map.CellContaining(pos);
var resLayer = world.WorldActor.Trait<ResourceLayer>();
var minRange = (Size.Length > 1 && Size[1] > 0) ? Size[1] : 0;
var allCells = world.Map.FindTilesInAnnulus(targetTile, minRange, Size[0]);
var resourceType = world.WorldActor.TraitsImplementing<ResourceType>()
.FirstOrDefault(t => t.Info.Name == AddsResourceType);
if (resourceType == null)
Log.Write("debug", "Warhead defines an invalid resource type '{0}'".F(AddsResourceType));
else
{
foreach (var cell in allCells)
{
if (!resLayer.CanSpawnResourceAt(resourceType, cell))
continue;
var splash = world.SharedRandom.Next(1, resourceType.Info.MaxDensity - resLayer.GetResourceDensity(cell));
resLayer.AddResource(resourceType, cell, splash);
}
}
}
public override float EffectivenessAgainst(ActorInfo ai) { return 1f; }
}
}

View File

@@ -0,0 +1,47 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Effects;
using OpenRA.GameRules;
using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
public class DestroyResourceWarhead : Warhead
{
[Desc("Size of the area. The resources are seeded within this area.", "Provide 2 values for a ring effect (outer/inner).")]
public readonly int[] Size = { 0, 0 };
// TODO: Allow maximum resource removal to be defined. (Per tile, and in total).
public override void DoImpact(Target target, Actor firedBy, float firepowerModifier)
{
DoImpact(target.CenterPosition, firedBy, firepowerModifier);
}
public void DoImpact(WPos pos, Actor firedBy, float firepowerModifier)
{
var world = firedBy.World;
var targetTile = world.Map.CellContaining(pos);
var resLayer = world.WorldActor.Trait<ResourceLayer>();
var minRange = (Size.Length > 1 && Size[1] > 0) ? Size[1] : 0;
var allCells = world.Map.FindTilesInAnnulus(targetTile, minRange, Size[0]);
// Destroy all resources in the selected tiles
foreach (var cell in allCells)
resLayer.Destroy(cell);
}
public override float EffectivenessAgainst(ActorInfo ai) { return 1f; }
}
}

View File

@@ -0,0 +1,58 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Effects;
using OpenRA.GameRules;
using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
public class LeaveSmudgeWarhead : Warhead
{
[Desc("Size of the area. A smudge will be created in each tile.", "Provide 2 values for a ring effect (outer/inner).")]
public readonly int[] Size = { 0, 0 };
[Desc("Type of smudge to apply to terrain.")]
public readonly string[] SmudgeType = { };
public override void DoImpact(Target target, Actor firedBy, float firepowerModifier)
{
DoImpact(target.CenterPosition, firedBy, firepowerModifier);
}
public void DoImpact(WPos pos, Actor firedBy, float firepowerModifier)
{
var world = firedBy.World;
var targetTile = world.Map.CellContaining(pos);
var smudgeLayers = world.WorldActor.TraitsImplementing<SmudgeLayer>().ToDictionary(x => x.Info.Type);
var minRange = (Size.Length > 1 && Size[1] > 0) ? Size[1] : 0;
var allCells = world.Map.FindTilesInAnnulus(targetTile, minRange, Size[0]);
// Draw the smudges:
foreach (var sc in allCells)
{
var smudgeType = world.Map.GetTerrainInfo(sc).AcceptsSmudgeType.FirstOrDefault(t => SmudgeType.Contains(t));
if (smudgeType == null) continue;
SmudgeLayer smudgeLayer;
if (!smudgeLayers.TryGetValue(smudgeType, out smudgeLayer))
throw new NotImplementedException("Unknown smudge type `{0}`".F(smudgeType));
smudgeLayer.AddSmudge(sc);
}
}
public override float EffectivenessAgainst(ActorInfo ai) { return 1f; }
}
}

View File

@@ -396,6 +396,180 @@ namespace OpenRA.Utility
node.Key = "DestroyResources"; node.Key = "DestroyResources";
} }
if (engineVersion < 20140720)
{
// Split out the warheads to individual warhead types.
if (depth == 0)
{
var warheadCounter = 0;
foreach(var curNode in node.Value.Nodes.ToArray())
{
if (curNode.Key.Contains("Warhead") && curNode.Value.Value == null)
{
var newNodes = new List<MiniYamlNode>();
var oldNodeAtName = "";
if (curNode.Key.Contains('@'))
oldNodeAtName = "_" + curNode.Key.Split('@')[1];
// Per Cell Damage Model
if (curNode.Value.Nodes.Where(n => n.Key.Contains("DamageModel") &&
n.Value.Value.Contains("PerCell")).Any())
{
warheadCounter++;
var newYaml = new List<MiniYamlNode>();
var keywords = new List<String>{ "Size","Damage","InfDeath","PreventProne","ProneModifier","Delay","ValidTargets","InvalidTargets" };
foreach(var keyword in keywords)
{
var temp = curNode.Value.Nodes.FirstOrDefault(n => n.Key == keyword);
if (temp != null)
newYaml.Add(new MiniYamlNode(keyword, temp.Value.Value));
}
var tempVersus = curNode.Value.Nodes.FirstOrDefault(n => n.Key == "Versus");
if (tempVersus != null)
newYaml.Add(new MiniYamlNode("Versus", tempVersus.Value));
newNodes.Add(new MiniYamlNode("Warhead@" + warheadCounter.ToString() + "Dam" + oldNodeAtName, "PerCellDamage", newYaml));
}
// HealthPercentage damage model
if (curNode.Value.Nodes.Where(n => n.Key.Contains("DamageModel") &&
n.Value.Value.Contains("HealthPercentage")).Any())
{
warheadCounter++;
var newYaml = new List<MiniYamlNode>();
var temp = curNode.Value.Nodes.FirstOrDefault(n => n.Key == "Size"); // New HealthPercentage warhead allows spreads, as opposed to size
if (temp != null)
{
var newValue = temp.Value.Value.Split(',').First() + "c0";
if (temp.Value.Value.Contains(','))
newValue = newValue + "," + temp.Value.Value.Split(',')[1] + "c0"; ;
newYaml.Add(new MiniYamlNode("Spread", newValue));
}
var keywords = new List<String>{ "Damage","InfDeath","PreventProne","ProneModifier","Delay","ValidTargets","InvalidTargets" };
foreach(var keyword in keywords)
{
var temp2 = curNode.Value.Nodes.FirstOrDefault(n => n.Key == keyword);
if (temp2 != null)
newYaml.Add(new MiniYamlNode(keyword, temp2.Value.Value));
}
var tempVersus = curNode.Value.Nodes.FirstOrDefault(n => n.Key == "Versus");
if (tempVersus != null)
newYaml.Add(new MiniYamlNode("Versus", tempVersus.Value));
newNodes.Add(new MiniYamlNode("Warhead@" + warheadCounter.ToString() + "Dam" + oldNodeAtName, "HealthPercentageDamage", newYaml));
}
// SpreadDamage
{ // Always occurs, since by definition all warheads were SpreadDamage warheads before
warheadCounter++;
var newYaml = new List<MiniYamlNode>();
var keywords = new List<String>{ "Spread","Damage","InfDeath","PreventProne","ProneModifier","Delay","ValidTargets","InvalidTargets" };
foreach(var keyword in keywords)
{
var temp = curNode.Value.Nodes.FirstOrDefault(n => n.Key == keyword);
if (temp != null)
newYaml.Add(new MiniYamlNode(keyword, temp.Value.Value));
}
var tempVersus = curNode.Value.Nodes.FirstOrDefault(n => n.Key == "Versus");
if (tempVersus != null)
newYaml.Add(new MiniYamlNode("Versus", tempVersus.Value));
newNodes.Add(new MiniYamlNode("Warhead@" + warheadCounter.ToString() + "Dam" + oldNodeAtName, "SpreadDamage", newYaml));
}
// DestroyResource
if (curNode.Value.Nodes.Where(n => n.Key.Contains("DestroyResources") ||
n.Key.Contains("Ore")).Any())
{
warheadCounter++;
var newYaml = new List<MiniYamlNode>();
var keywords = new List<String>{ "Size","Delay","ValidTargets","InvalidTargets" };
foreach(var keyword in keywords)
{
var temp = curNode.Value.Nodes.FirstOrDefault(n => n.Key == keyword);
if (temp != null)
newYaml.Add(new MiniYamlNode(keyword, temp.Value.Value));
}
newNodes.Add(new MiniYamlNode("Warhead@" + warheadCounter.ToString() + "Res" + oldNodeAtName, "DestroyResource", newYaml));
}
// CreateResource
if (curNode.Value.Nodes.Where(n => n.Key.Contains("AddsResourceType")).Any())
{
warheadCounter++;
var newYaml = new List<MiniYamlNode>();
var keywords = new List<String>{ "AddsResourceType","Size","Delay","ValidTargets","InvalidTargets" };
foreach(var keyword in keywords)
{
var temp = curNode.Value.Nodes.FirstOrDefault(n => n.Key == keyword);
if (temp != null)
newYaml.Add(new MiniYamlNode(keyword, temp.Value.Value));
}
newNodes.Add(new MiniYamlNode("Warhead@" + warheadCounter.ToString() + "Res" + oldNodeAtName, "CreateResource", newYaml));
}
// LeaveSmudge
if (curNode.Value.Nodes.Where(n => n.Key.Contains("SmudgeType")).Any())
{
warheadCounter++;
var newYaml = new List<MiniYamlNode>();
var keywords = new List<String>{ "SmudgeType","Size","Delay","ValidTargets","InvalidTargets" };
foreach(var keyword in keywords)
{
var temp = curNode.Value.Nodes.FirstOrDefault(n => n.Key == keyword);
if (temp != null)
newYaml.Add(new MiniYamlNode(keyword, temp.Value.Value));
}
newNodes.Add(new MiniYamlNode("Warhead@" + warheadCounter.ToString() + "Smu" + oldNodeAtName, "LeaveSmudge", newYaml));
}
// CreateEffect
if (curNode.Value.Nodes.Where(n => n.Key.Contains("Explosion") ||
n.Key.Contains("WaterExplosion") ||
n.Key.Contains("ImpactSound") ||
n.Key.Contains("WaterImpactSound")).Any())
{
warheadCounter++;
var newYaml = new List<MiniYamlNode>();
var keywords = new List<String>{ "Explosion","WaterExplosion","ImpactSound","WaterImpactSound","Delay","ValidTargets","InvalidTargets" };
foreach(var keyword in keywords)
{
var temp = curNode.Value.Nodes.FirstOrDefault(n => n.Key == keyword);
if (temp != null)
newYaml.Add(new MiniYamlNode(keyword, temp.Value.Value));
}
newNodes.Add(new MiniYamlNode("Warhead@" + warheadCounter.ToString() + "Eff" + oldNodeAtName, "CreateEffect", newYaml));
}
node.Value.Nodes.InsertRange(node.Value.Nodes.IndexOf(curNode),newNodes);
node.Value.Nodes.Remove(curNode);
}
}
}
}
UpgradeWeaponRules(engineVersion, ref node.Value.Nodes, node, depth + 1); UpgradeWeaponRules(engineVersion, ref node.Value.Nodes, node, depth + 1);
} }
} }

View File

@@ -535,10 +535,10 @@ VoxelSequences:
Weapons: Weapons:
BoatMissile: BoatMissile:
Warhead: Warhead: SpreadDamage
Versus: Versus:
Heavy: 50% Heavy: 50%
Damage: 50 Damage: 50
Voices: Voices:

View File

@@ -572,7 +572,7 @@ VoxelSequences:
Weapons: Weapons:
Tiberium: Tiberium:
Warhead: Warhead: SpreadDamage
Damage: 6 Damage: 6
Voices: Voices:

View File

@@ -653,7 +653,7 @@ VoxelSequences:
Weapons: Weapons:
Tiberium: Tiberium:
Warhead: Warhead: SpreadDamage
Damage: 4 Damage: 4
Voices: Voices:

View File

@@ -913,7 +913,7 @@ VoxelSequences:
Weapons: Weapons:
Rockets: Rockets:
Warhead: Warhead: SpreadDamage
Versus: Versus:
None: 20% None: 20%

File diff suppressed because it is too large Load Diff

View File

@@ -8,16 +8,17 @@ LMG:
TrailInterval: 1 TrailInterval: 1
ContrailDelay: 0 ContrailDelay: 0
ContrailUsePlayerColor: true ContrailUsePlayerColor: true
Warhead: Warhead@1Dam: SpreadDamage
Spread: 96 Spread: 96
Damage: 15
InfDeath: 2
Versus: Versus:
Wood: 25% Wood: 25%
Light: 40% Light: 40%
Heavy: 10% Heavy: 10%
Concrete: 20% Concrete: 20%
Warhead@2Eff: CreateEffect
Explosion: piffs Explosion: piffs
InfDeath: 2
Damage: 15
Bazooka: Bazooka:
ROF: 50 ROF: 50
@@ -32,18 +33,20 @@ Bazooka:
Image: RPG Image: RPG
ROT: 5 ROT: 5
RangeLimit: 35 RangeLimit: 35
Warhead: Warhead@1Dam: SpreadDamage
Spread: 96 Spread: 96
Damage: 50
InfDeath: 4
Versus: Versus:
None: 10% None: 10%
Wood: 75% Wood: 75%
Light: 60% Light: 60%
Heavy: 90% Heavy: 90%
Concrete: 40% Concrete: 40%
Explosion: small_explosion Warhead@2Smu: LeaveSmudge
InfDeath: 4
SmudgeType: SandCrater, RockCrater SmudgeType: SandCrater, RockCrater
Damage: 50 Warhead@3Eff: CreateEffect
Explosion: small_explosion
ImpactSound: EXPLSML1.WAV ImpactSound: EXPLSML1.WAV
Sniper: Sniper:
@@ -56,16 +59,16 @@ Sniper:
TrailInterval: 1 TrailInterval: 1
ContrailDelay: 0 ContrailDelay: 0
ContrailUsePlayerColor: true ContrailUsePlayerColor: true
Warhead: Warhead@1Dam: SpreadDamage
Damage: 60
Spread: 32 Spread: 32
Damage: 60
InfDeath: 2
Versus: Versus:
None: 100% None: 100%
Wood: 0% Wood: 0%
Light: 1% Light: 1%
Heavy: 0% Heavy: 0%
Concrete: 0% Concrete: 0%
InfDeath: 2
Vulcan: Vulcan:
ROF: 30 ROF: 30
@@ -78,16 +81,17 @@ Vulcan:
TrailInterval: 1 TrailInterval: 1
ContrailDelay: 0 ContrailDelay: 0
ContrailUsePlayerColor: true ContrailUsePlayerColor: true
Warhead: Warhead@1Dam: SpreadDamage
Spread: 96 Spread: 96
Damage: 30
InfDeath: 2
Versus: Versus:
Wood: 0% Wood: 0%
Light: 60% Light: 60%
Heavy: 10% Heavy: 10%
Concrete: 0% Concrete: 0%
Warhead@2Eff: CreateEffect
Explosion: piffs Explosion: piffs
InfDeath: 2
Damage: 30
Slung: Slung:
ROF: 60 ROF: 60
@@ -102,17 +106,18 @@ Slung:
Angle: 88 Angle: 88
Inaccuracy: 384 Inaccuracy: 384
Image: MISSILE Image: MISSILE
Warhead: Warhead@1Dam: SpreadDamage
Spread: 192 Spread: 192
Damage: 30
InfDeath: 4
Versus: Versus:
None: 0% None: 0%
Wood: 75% Wood: 75%
Light: 40% Light: 40%
Heavy: 90% Heavy: 90%
Concrete: 50% Concrete: 50%
Warhead@2Eff: CreateEffect
Explosion: small_explosion Explosion: small_explosion
InfDeath: 4
Damage: 30
ImpactSound: EXPLLG5.WAV ImpactSound: EXPLLG5.WAV
HMG: HMG:
@@ -127,16 +132,17 @@ HMG:
TrailInterval: 1 TrailInterval: 1
ContrailDelay: 0 ContrailDelay: 0
ContrailUsePlayerColor: true ContrailUsePlayerColor: true
Warhead: Warhead@1Dam: SpreadDamage
Spread: 96 Spread: 96
Damage: 30
InfDeath: 2
Versus: Versus:
Wood: 15% Wood: 15%
Light: 45% Light: 45%
Heavy: 20% Heavy: 20%
Concrete: 20% Concrete: 20%
Warhead@2Eff: CreateEffect
Explosion: piffs Explosion: piffs
InfDeath: 2
Damage: 30
HMGo: HMGo:
ROF: 30 ROF: 30
@@ -150,16 +156,17 @@ HMGo:
TrailInterval: 1 TrailInterval: 1
ContrailDelay: 0 ContrailDelay: 0
ContrailUsePlayerColor: true ContrailUsePlayerColor: true
Warhead: Warhead@1Dam: SpreadDamage
Spread: 96 Spread: 96
Damage: 40
InfDeath: 2
Versus: Versus:
Wood: 15% Wood: 15%
Light: 45% Light: 45%
Heavy: 25% Heavy: 25%
Concrete: 20% Concrete: 20%
Warhead@2Eff: CreateEffect
Explosion: piffs Explosion: piffs
InfDeath: 2
Damage: 40
QuadRockets: QuadRockets:
ROF: 40 ROF: 40
@@ -175,19 +182,21 @@ QuadRockets:
ROT: 10 ROT: 10
Speed: 256 Speed: 256
RangeLimit: 40 RangeLimit: 40
Warhead: Warhead@1Dam: SpreadDamage
Spread: 96 Spread: 96
Damage: 25
InfDeath: 4
Versus: Versus:
None: 35% None: 35%
Wood: 45% Wood: 45%
Light: 100% Light: 100%
Heavy: 100% Heavy: 100%
Concrete: 35% Concrete: 35%
InfDeath: 4 Warhead@2Smu: LeaveSmudge
SmudgeType: SandCrater, RockCrater
Warhead@3Eff: CreateEffect
Explosion: med_explosion Explosion: med_explosion
ImpactSound: EXPLSML1.WAV ImpactSound: EXPLSML1.WAV
SmudgeType: SandCrater, RockCrater
Damage: 25
TurretGun: TurretGun:
ROF: 35 ROF: 35
@@ -199,18 +208,20 @@ TurretGun:
Shadow: no Shadow: no
Inaccuracy: 288 Inaccuracy: 288
Image: 120mm Image: 120mm
Warhead: Warhead@1Dam: SpreadDamage
Spread: 256 Spread: 256
Damage: 55
InfDeath: 4
Versus: Versus:
None: 50% None: 50%
Wood: 75% Wood: 75%
Light: 100% Light: 100%
Concrete: 65% Concrete: 65%
Warhead@2Smu: LeaveSmudge
SmudgeType: SandCrater, RockCrater
Warhead@3Eff: CreateEffect
Explosion: small_napalm Explosion: small_napalm
ImpactSound: EXPLSML4.WAV ImpactSound: EXPLSML4.WAV
InfDeath: 4
SmudgeType: SandCrater, RockCrater
Damage: 55
TowerMissile: TowerMissile:
ROF: 35 ROF: 35
@@ -230,19 +241,21 @@ TowerMissile:
Speed: 256 Speed: 256
RangeLimit: 50 RangeLimit: 50
Angle: 110 Angle: 110
Warhead: Warhead@1Dam: SpreadDamage
Spread: 384 Spread: 384
Damage: 50
InfDeath: 3
Versus: Versus:
None: 50% None: 50%
Wood: 45% Wood: 45%
Light: 100% Light: 100%
Heavy: 50% Heavy: 50%
Concrete: 35% Concrete: 35%
InfDeath: 3 Warhead@2Smu: LeaveSmudge
SmudgeType: SandCrater, RockCrater
Warhead@3Eff: CreateEffect
Explosion: small_explosion Explosion: small_explosion
ImpactSound: EXPLMD1.WAV ImpactSound: EXPLMD1.WAV
SmudgeType: SandCrater, RockCrater
Damage: 50
90mm: 90mm:
ROF: 50 ROF: 50
@@ -252,18 +265,20 @@ TowerMissile:
Speed: 640 Speed: 640
Inaccuracy: 384 Inaccuracy: 384
Image: 120mm Image: 120mm
Warhead: Warhead@1Dam: SpreadDamage
Spread: 256 Spread: 256
Damage: 40
InfDeath: 4
Versus: Versus:
None: 50% None: 50%
Wood: 50% Wood: 50%
Light: 100% Light: 100%
Concrete: 50% Concrete: 50%
Warhead@2Smu: LeaveSmudge
SmudgeType: SandCrater, RockCrater
Warhead@3Eff: CreateEffect
Explosion: small_napalm Explosion: small_napalm
ImpactSound: EXPLSML4.WAV ImpactSound: EXPLSML4.WAV
InfDeath: 4
SmudgeType: SandCrater, RockCrater
Damage: 40
90mma: 90mma:
ROF: 50 ROF: 50
@@ -273,18 +288,20 @@ TowerMissile:
Speed: 704 Speed: 704
Inaccuracy: 352 Inaccuracy: 352
Image: 120mm Image: 120mm
Warhead: Warhead@1Dam: SpreadDamage
Spread: 256 Spread: 256
Damage: 40
InfDeath: 4
Versus: Versus:
None: 50% None: 50%
Wood: 50% Wood: 50%
Light: 100% Light: 100%
Concrete: 50% Concrete: 50%
Warhead@2Smu: LeaveSmudge
SmudgeType: SandCrater, RockCrater
Warhead@3Eff: CreateEffect
Explosion: small_napalm Explosion: small_napalm
ImpactSound: EXPLSML4.WAV ImpactSound: EXPLSML4.WAV
InfDeath: 4
SmudgeType: SandCrater, RockCrater
Damage: 40
DevBullet: DevBullet:
ROF: 50 ROF: 50
@@ -293,18 +310,20 @@ DevBullet:
Projectile: Bullet Projectile: Bullet
Speed: 640 Speed: 640
Image: doubleblastbullet Image: doubleblastbullet
Warhead: Warhead@1Dam: SpreadDamage
Spread: 256 Spread: 256
Damage: 100
InfDeath: 4
Versus: Versus:
None: 100% None: 100%
Wood: 50% Wood: 50%
Light: 100% Light: 100%
Heavy: 100% Heavy: 100%
Concrete: 80% Concrete: 80%
Explosion: shockwave Warhead@2Smu: LeaveSmudge
InfDeath: 4
SmudgeType: SandCrater, RockCrater SmudgeType: SandCrater, RockCrater
Damage: 100 Warhead@3Eff: CreateEffect
Explosion: shockwave
227mm: 227mm:
ROF: 100 ROF: 100
@@ -324,19 +343,21 @@ DevBullet:
Image: MISSILE2 Image: MISSILE2
ROT: 5 ROT: 5
ContrailLength: 5 ContrailLength: 5
Warhead: Warhead@1Dam: SpreadDamage
Spread: 384 Spread: 384
Damage: 60
InfDeath: 4
Versus: Versus:
None: 20% None: 20%
Wood: 50% Wood: 50%
Light: 100% Light: 100%
Heavy: 50% Heavy: 50%
Concrete: 80% Concrete: 80%
InfDeath: 4 Warhead@2Smu: LeaveSmudge
SmudgeType: SandCrater, RockCrater
Warhead@3Eff: CreateEffect
Explosion: mini_explosion Explosion: mini_explosion
ImpactSound: EXPLMD3.WAV ImpactSound: EXPLMD3.WAV
SmudgeType: SandCrater, RockCrater
Damage: 60
FakeMissile: FakeMissile:
ROF: 120 ROF: 120
@@ -352,15 +373,17 @@ FakeMissile:
Image: MISSILE Image: MISSILE
ContrailLength: 15 ContrailLength: 15
ContrailUsePlayerColor: True ContrailUsePlayerColor: True
Warhead: Warhead@1Dam: SpreadDamage
Spread: 96 Spread: 96
Damage: 10
Versus: Versus:
None: 0% None: 0%
Wood: 0% Wood: 0%
Concrete: 0% Concrete: 0%
Explosion: deviator Warhead@2Smu: LeaveSmudge
SmudgeType: SandCrater, RockCrater SmudgeType: SandCrater, RockCrater
Damage: 10 Warhead@3Eff: CreateEffect
Explosion: deviator
ImpactSound: EXPLSML2.WAV ImpactSound: EXPLSML2.WAV
155mm: 155mm:
@@ -376,19 +399,21 @@ FakeMissile:
Inaccuracy: 1c256 Inaccuracy: 1c256
ContrailLength: 20 ContrailLength: 20
Image: 155mm Image: 155mm
Warhead: Warhead@1Dam: SpreadDamage
Spread: 384 Spread: 384
Damage: 100
InfDeath: 3
Versus: Versus:
None: 100% None: 100%
Wood: 80% Wood: 80%
Light: 75% Light: 75%
Heavy: 50% Heavy: 50%
Concrete: 100% Concrete: 100%
Warhead@2Smu: LeaveSmudge
SmudgeType: SandCrater, RockCrater
Warhead@3Eff: CreateEffect
Explosion: large_explosion Explosion: large_explosion
ImpactSound: EXPLLG3.WAV ImpactSound: EXPLLG3.WAV
InfDeath: 3
SmudgeType: SandCrater, RockCrater
Damage: 100
Sound: Sound:
ROF: 100 ROF: 100
@@ -399,15 +424,15 @@ Sound:
HitAnim: laserfire HitAnim: laserfire
BeamDuration: 8 BeamDuration: 8
UsePlayerColor: true UsePlayerColor: true
Warhead: Warhead@1Dam: SpreadDamage
Spread: 32 Spread: 32
Damage: 150
InfDeath: 6
Versus: Versus:
None: 60% None: 60%
Wood: 85% Wood: 85%
Light: 80% Light: 80%
Concrete: 75% Concrete: 75%
InfDeath: 6
Damage: 150
ChainGun: ChainGun:
ROF: 10 ROF: 10
@@ -417,16 +442,17 @@ ChainGun:
Projectile: Bullet Projectile: Bullet
Speed: 1c256 Speed: 1c256
High: true High: true
Warhead: Warhead@1Dam: SpreadDamage
Spread: 96 Spread: 96
Damage: 20
InfDeath: 2
Versus: Versus:
Wood: 50% Wood: 50%
Light: 60% Light: 60%
Heavy: 25% Heavy: 25%
Concrete: 25% Concrete: 25%
Warhead@2Eff: CreateEffect
Explosion: piffs Explosion: piffs
InfDeath: 2
Damage: 20
Heal: Heal:
ROF: 160 ROF: 160
@@ -434,26 +460,26 @@ Heal:
Report: Report:
Projectile: Bullet Projectile: Bullet
Speed: 1c256 Speed: 1c256
Warhead: Warhead@1Dam: SpreadDamage
Spread: 160 Spread: 160
Damage: -50
InfDeath: 1
Versus: Versus:
Wood: 0% Wood: 0%
Light: 0% Light: 0%
Heavy: 0% Heavy: 0%
Concrete: 0% Concrete: 0%
InfDeath: 1
Damage: -50
WormJaw: WormJaw:
ROF: 10 ROF: 10
Range: 3c0 Range: 3c0
Report: WORM.WAV Report: WORM.WAV
Warhead: Warhead@1Dam: SpreadDamage
Spread: 160 Spread: 160
Damage: 100
Versus: Versus:
Wood: 0% Wood: 0%
Concrete: 0% Concrete: 0%
Damage: 100
ParaBomb: ParaBomb:
ROF: 10 ROF: 10
@@ -461,17 +487,19 @@ ParaBomb:
Report: Report:
Projectile: GravityBomb Projectile: GravityBomb
Image: BOMBS Image: BOMBS
Warhead: Warhead@1Dam: SpreadDamage
Spread: 192 Spread: 192
Damage: 500
InfDeath: 4
Versus: Versus:
None: 30% None: 30%
Wood: 75% Wood: 75%
Light: 75% Light: 75%
Concrete: 50% Concrete: 50%
Explosion: self_destruct Warhead@2Smu: LeaveSmudge
InfDeath: 4
SmudgeType: Crater SmudgeType: Crater
Damage: 500 Warhead@3Eff: CreateEffect
Explosion: self_destruct
ImpactSound: EXPLLG3.WAV ImpactSound: EXPLLG3.WAV
Napalm: Napalm:
@@ -479,121 +507,132 @@ Napalm:
Range: 3c0 Range: 3c0
Projectile: GravityBomb Projectile: GravityBomb
Image: BOMBS Image: BOMBS
Warhead: Warhead@1Dam: SpreadDamage
Spread: 640 Spread: 640
Damage: 300
InfDeath: 4
Versus: Versus:
None: 20% None: 20%
Wood: 100% Wood: 100%
Light: 30% Light: 30%
Heavy: 20% Heavy: 20%
Concrete: 70% Concrete: 70%
InfDeath: 4 Warhead@2Smu: LeaveSmudge
SmudgeType: Crater
Warhead@3Eff: CreateEffect
Explosion: artillery Explosion: artillery
ImpactSound: NAPALM1.WAV ImpactSound: NAPALM1.WAV
SmudgeType: Crater
Damage: 300
Crush: Crush:
Warhead: Warhead@1Dam: SpreadDamage
ImpactSound: CRUSH1.WAV
Damage: 100 Damage: 100
Warhead@2Eff: CreateEffect
ImpactSound: CRUSH1.WAV
Demolish: Demolish:
Warhead: Warhead@1Dam: SpreadDamage
ImpactSound: EXPLLG2.WAV Warhead@2Eff: CreateEffect
Explosion: building Explosion: building
ImpactSound: EXPLLG2.WAV
Atomic: Atomic:
Warhead: Warhead@1Dam: SpreadDamage
Damage: 1800
Spread: 2c0 Spread: 2c0
Damage: 1800
InfDeath: 5
Versus: Versus:
None: 100% None: 100%
Wood: 100% Wood: 100%
Light: 100% Light: 100%
Heavy: 50% Heavy: 50%
Concrete: 50% Concrete: 50%
Warhead@2Eff: CreateEffect
Explosion: nuke Explosion: nuke
InfDeath: 5
ImpactSound: EXPLLG2.WAV ImpactSound: EXPLLG2.WAV
CrateNuke: CrateNuke:
Warhead: Warhead@1Dam: SpreadDamage
Damage: 800
Spread: 1c576 Spread: 1c576
Damage: 800
InfDeath: 5
Versus: Versus:
None: 20% None: 20%
Wood: 75% Wood: 75%
Light: 25% Light: 25%
Heavy: 25% Heavy: 25%
Concrete: 50% Concrete: 50%
Warhead@2Eff: CreateEffect
Explosion: nuke Explosion: nuke
InfDeath: 5
ImpactSound: EXPLLG2.WAV ImpactSound: EXPLLG2.WAV
CrateExplosion: CrateExplosion:
Warhead: Warhead@1Dam: SpreadDamage
Damage: 400
Spread: 320 Spread: 320
Damage: 400
InfDeath: 4
Versus: Versus:
None: 90% None: 90%
Wood: 75% Wood: 75%
Light: 60% Light: 60%
Heavy: 25% Heavy: 25%
Warhead@2Eff: CreateEffect
Explosion: building Explosion: building
InfDeath: 4
ImpactSound: EXPLSML4.WAV ImpactSound: EXPLSML4.WAV
UnitExplode: UnitExplode:
Warhead: Warhead@1Dam: SpreadDamage
Damage: 500
Spread: 320 Spread: 320
Damage: 500
InfDeath: 4
Versus: Versus:
None: 90% None: 90%
Wood: 75% Wood: 75%
Light: 60% Light: 60%
Heavy: 25% Heavy: 25%
Warhead@2Eff: CreateEffect
Explosion: building Explosion: building
InfDeath: 4
ImpactSound: EXPLMD1.WAV ImpactSound: EXPLMD1.WAV
UnitExplodeSmall: UnitExplodeSmall:
Warhead: Warhead@1Dam: SpreadDamage
Damage: 60
Spread: 320 Spread: 320
Damage: 60
InfDeath: 4
Versus: Versus:
None: 90% None: 90%
Wood: 75% Wood: 75%
Light: 60% Light: 60%
Heavy: 25% Heavy: 25%
Warhead@2Eff: CreateEffect
Explosion: self_destruct Explosion: self_destruct
InfDeath: 4
ImpactSound: EXPLHG1.WAV, EXPLLG1.WAV, EXPLMD1.WAV, EXPLSML4.WAV ImpactSound: EXPLHG1.WAV, EXPLLG1.WAV, EXPLMD1.WAV, EXPLSML4.WAV
UnitExplodeTiny: UnitExplodeTiny:
Warhead: Warhead@1Dam: SpreadDamage
Damage: 30
Spread: 224 Spread: 224
Damage: 30
InfDeath: 4
Versus: Versus:
None: 90% None: 90%
Wood: 75% Wood: 75%
Light: 60% Light: 60%
Heavy: 25% Heavy: 25%
Warhead@2Eff: CreateEffect
Explosion: med_explosion Explosion: med_explosion
InfDeath: 4
ImpactSound: EXPLMD2.WAV, EXPLSML1.WAV, EXPLSML2.WAV, EXPLSML3.WAV ImpactSound: EXPLMD2.WAV, EXPLSML1.WAV, EXPLSML2.WAV, EXPLSML3.WAV
UnitExplodeScale: UnitExplodeScale:
Warhead: Warhead@1Dam: SpreadDamage
Damage: 90
Spread: 416 Spread: 416
Damage: 90
InfDeath: 4
Versus: Versus:
None: 90% None: 90%
Wood: 75% Wood: 75%
Light: 60% Light: 60%
Heavy: 25% Heavy: 25%
Warhead@2Eff: CreateEffect
Explosion: building Explosion: building
InfDeath: 4
ImpactSound: EXPLLG2.WAV, EXPLLG3.WAV, EXPLLG5.WAV ImpactSound: EXPLLG2.WAV, EXPLLG3.WAV, EXPLLG5.WAV
Grenade: Grenade:
@@ -606,22 +645,24 @@ Grenade:
Angle: 62 Angle: 62
Inaccuracy: 416 Inaccuracy: 416
Image: BOMBS Image: BOMBS
Warhead: Warhead@1Dam: SpreadDamage
Spread: 192 Spread: 192
Damage: 60
InfDeath: 3
Versus: Versus:
None: 50% None: 50%
Wood: 100% Wood: 100%
Light: 25% Light: 25%
Heavy: 5% Heavy: 5%
Explosion: med_explosion Warhead@2Smu: LeaveSmudge
InfDeath: 3
SmudgeType: SandCrater SmudgeType: SandCrater
Damage: 60 Warhead@3Eff: CreateEffect
Explosion: med_explosion
ImpactSound: EXPLLG5.WAV ImpactSound: EXPLLG5.WAV
Weathering: Weathering:
ROF: 100 ROF: 100
Warhead: Warhead@1Dam: SpreadDamage
Damage: 5 Damage: 5
Shrapnel: Shrapnel:
@@ -634,31 +675,35 @@ Shrapnel:
Angle: 91, 264 Angle: 91, 264
Inaccuracy: 416 Inaccuracy: 416
Image: bombs Image: bombs
Warhead: Warhead@1Dam: SpreadDamage
Spread: 192 Spread: 192
Damage: 60
InfDeath: 3
Versus: Versus:
None: 50% None: 50%
Wood: 100% Wood: 100%
Light: 25% Light: 25%
Heavy: 5% Heavy: 5%
Explosion: med_explosion Warhead@2Smu: LeaveSmudge
InfDeath: 3
SmudgeType: SandCrater SmudgeType: SandCrater
Damage: 60 Warhead@3Eff: CreateEffect
Explosion: med_explosion
ImpactSound: EXPLLG5.WAV ImpactSound: EXPLLG5.WAV
SpiceExplosion: SpiceExplosion:
Warhead: Warhead@1Dam: SpreadDamage
Damage: 10
Spread: 9 Spread: 9
Size: 2,2 Damage: 10
InfDeath: 3
Versus: Versus:
None: 90% None: 90%
Wood: 75% Wood: 75%
Light: 60% Light: 60%
Heavy: 25% Heavy: 25%
Explosion: med_explosion Warhead@2Res: CreateResource
InfDeath: 3
ImpactSound: EXPLLG5.WAV
AddsResourceType: Spice AddsResourceType: Spice
Size: 2,2
Warhead@3Eff: CreateEffect
Explosion: med_explosion
ImpactSound: EXPLLG5.WAV

View File

@@ -615,7 +615,7 @@ Weapons:
Range: 5c0 Range: 5c0
ROF: 20 ROF: 20
Burst: 1 Burst: 1
Warhead: Warhead: SpreadDamage
Damage: 20 Damage: 20
Voices: Voices:

View File

@@ -951,7 +951,7 @@ Weapons:
Range: 5c0 Range: 5c0
ROF: 20 ROF: 20
Burst: 1 Burst: 1
Warhead: Warhead: SpreadDamage
Damage: 20 Damage: 20
Voices: Voices:

View File

@@ -364,7 +364,7 @@ Weapons:
PortaTesla: PortaTesla:
ROF: 20 ROF: 20
Range: 10c0 Range: 10c0
Warhead: Warhead: SpreadDamage
Spread: 42 Spread: 42
InfDeath: 5 InfDeath: 5
Damage: 80 Damage: 80

View File

@@ -313,20 +313,22 @@ Weapons:
Inaccuracy: 3c341 Inaccuracy: 3c341
Image: 120MM Image: 120MM
ContrailLength: 30 ContrailLength: 30
Warhead: Warhead: SpreadDamage
Spread: 128 Spread: 128
Versus: Versus:
None: 60% None: 60%
Wood: 75% Wood: 75%
Light: 60% Light: 60%
Heavy: 25% Heavy: 25%
InfDeath: 2
Damage: 250
Warhead@1Eff: CreateEffect
Explosion: large_explosion Explosion: large_explosion
WaterExplosion: large_splash WaterExplosion: large_splash
InfDeath: 2
SmudgeType: Crater
Damage: 250
ImpactSound: kaboom12.aud ImpactSound: kaboom12.aud
WaterImpactSound: splash9.aud WaterImpactSound: splash9.aud
Warhead@2Smu: LeaveSmudge
SmudgeType: Crater
SubMissile: SubMissile:
ROF: 250 ROF: 250
Range: 32c0 Range: 32c0
@@ -340,19 +342,21 @@ Weapons:
Image: MISSILE Image: MISSILE
Trail: smokey Trail: smokey
ContrailLength: 30 ContrailLength: 30
Warhead: Warhead: SpreadDamage
Spread: 426 Spread: 426
Versus: Versus:
None: 40% None: 40%
Light: 30% Light: 30%
Heavy: 30% Heavy: 30%
InfDeath: blownaway
Damage: 400
Warhead@1Eff: CreateEffect
Explosion: large_explosion Explosion: large_explosion
WaterExplosion: large_splash WaterExplosion: large_splash
InfDeath: blownaway
SmudgeType: Crater
Damage: 400
ImpactSound: kaboom12.aud ImpactSound: kaboom12.aud
WaterImpactSound: splash9.aud WaterImpactSound: splash9.aud
Warhead@2Smu: LeaveSmudge
SmudgeType: Crater
Voices: Voices:

View File

@@ -259,7 +259,7 @@ Weapons:
PortaTesla: PortaTesla:
ROF: 20 ROF: 20
Range: 10c0 Range: 10c0
Warhead: Warhead: SpreadDamage
Spread: 42 Spread: 42
InfDeath: 5 InfDeath: 5
Damage: 80 Damage: 80

View File

@@ -771,24 +771,26 @@ Weapons:
Inaccuracy: 1c682 Inaccuracy: 1c682
Image: 120MM Image: 120MM
ContrailLength: 50 ContrailLength: 50
Warhead: Warhead: SpreadDamage
Spread: 256 Spread: 256
Versus: Versus:
None: 75% None: 75%
Wood: 75% Wood: 75%
Light: 75% Light: 75%
Concrete: 100% Concrete: 100%
InfDeath: 4
Damage: 150
Warhead@2Smu: LeaveSmudge
SmudgeType: Crater
Warhead@3Eff: CreateEffect
Explosion: self_destruct Explosion: self_destruct
WaterExplosion: self_destruct WaterExplosion: self_destruct
InfDeath: 4
SmudgeType: Crater
Damage: 150
MammothTusk: MammothTusk:
ROF: 300 ROF: 300
Range: 10c0 Range: 10c0
Report: MISSILE6.AUD Report: MISSILE6.AUD
Burst: 2 Burst: 2
ValidTargets: Ground, Air ValidTargets: Ground, Air, Enemy, Neutral, Ally
Projectile: Missile Projectile: Missile
Speed: 128 Speed: 128
Arm: 2 Arm: 2
@@ -801,7 +803,7 @@ Weapons:
Image: DRAGON Image: DRAGON
ROT: 10 ROT: 10
RangeLimit: 80 RangeLimit: 80
Warhead: Warhead: SpreadDamage
Spread: 640 Spread: 640
Versus: Versus:
None: 125% None: 125%
@@ -809,16 +811,18 @@ Weapons:
Light: 110% Light: 110%
Heavy: 100% Heavy: 100%
Concrete: 200% Concrete: 200%
InfDeath: 3
Damage: 250
Warhead@2Smu: LeaveSmudge
SmudgeType: Crater
Warhead@3Eff: CreateEffect
Explosion: nuke Explosion: nuke
WaterExplosion: nuke WaterExplosion: nuke
InfDeath: 3
SmudgeType: Crater
Damage: 250
TankNapalm: TankNapalm:
ROF: 40 ROF: 40
Range: 8c0 Range: 8c0
Report: AACANON3.AUD Report: AACANON3.AUD
ValidTargets: Ground ValidTargets: Ground, Enemy, Neutral, Ally
Burst: 6 Burst: 6
BurstDelay: 1 BurstDelay: 1
Projectile: Bullet Projectile: Bullet
@@ -827,7 +831,7 @@ Weapons:
Inaccuracy: 2c512 Inaccuracy: 2c512
Trail: smokey Trail: smokey
ContrailLength: 2 ContrailLength: 2
Warhead: Warhead: SpreadDamage
Spread: 341 Spread: 341
Versus: Versus:
None: 90% None: 90%
@@ -835,31 +839,35 @@ Weapons:
Light: 100% Light: 100%
Heavy: 100% Heavy: 100%
Concrete: 100% Concrete: 100%
InfDeath: 4
Damage: 15
Warhead@2Smu: LeaveSmudge
SmudgeType: Scorch
Warhead@3Eff: CreateEffect
Explosion: small_explosion Explosion: small_explosion
WaterExplosion: small_explosion WaterExplosion: small_explosion
InfDeath: 4
SmudgeType: Scorch
ImpactSound: firebl3.aud ImpactSound: firebl3.aud
Damage: 15
ParaBomb: ParaBomb:
ROF: 5 ROF: 5
Range: 5c0 Range: 5c0
Report: CHUTE1.AUD Report: CHUTE1.AUD
Projectile: GravityBomb Projectile: GravityBomb
Image: BOMBLET Image: BOMBLET
Warhead: Warhead: SpreadDamage
Spread: 426 Spread: 426
Versus: Versus:
None: 125% None: 125%
Wood: 100% Wood: 100%
Light: 60% Light: 60%
Concrete: 25% Concrete: 25%
InfDeath: 5
Damage: 200
Warhead@2Smu: LeaveSmudge
SmudgeType: Crater
Warhead@3Eff: CreateEffect
Explosion: napalm Explosion: napalm
ImpactSound: firebl3.aud ImpactSound: firebl3.aud
WaterExplosion: napalm WaterExplosion: napalm
InfDeath: 5
SmudgeType: Crater
Damage: 200
155mm: 155mm:
ROF: 10 ROF: 10
Range: 7c5 Range: 7c5
@@ -874,7 +882,7 @@ Weapons:
Angle: 30 Angle: 30
Inaccuracy: 1c682 Inaccuracy: 1c682
ContrailLength: 2 ContrailLength: 2
Warhead: Warhead: SpreadDamage
Spread: 426 Spread: 426
Versus: Versus:
None: 80% None: 80%
@@ -882,21 +890,23 @@ Weapons:
Light: 60% Light: 60%
Heavy: 75% Heavy: 75%
Concrete: 35% Concrete: 35%
InfDeath: 5
Damage: 10
Warhead@2Smu: LeaveSmudge
SmudgeType: Scorch
Warhead@3Eff: CreateEffect
Explosion: small_napalm Explosion: small_napalm
WaterExplosion: small_napalm WaterExplosion: small_napalm
InfDeath: 5
SmudgeType: Scorch
ImpactSound: firebl3.aud ImpactSound: firebl3.aud
Damage: 10
FLAK-23: FLAK-23:
ROF: 10 ROF: 10
Range: 8c0 Range: 8c0
Report: AACANON3.AUD Report: AACANON3.AUD
ValidTargets: Air,Ground ValidTargets: Air, Ground, Enemy, Neutral, Ally
Projectile: Bullet Projectile: Bullet
Speed: 1c682 Speed: 1c682
High: true High: true
Warhead: Warhead: SpreadDamage
Spread: 213 Spread: 213
Versus: Versus:
None: 35% None: 35%
@@ -904,8 +914,11 @@ Weapons:
Light: 30% Light: 30%
Heavy: 40% Heavy: 40%
Concrete: 30% Concrete: 30%
Explosion: med_explosion
Damage: 25 Damage: 25
Warhead@2Smu: LeaveSmudge
SmudgeType: Scorch
Warhead@3Eff: CreateEffect
Explosion: med_explosion
SCUD: SCUD:
ROF: 280 ROF: 280
Range: 7c0 Range: 7c0
@@ -921,18 +934,20 @@ Weapons:
Inaccuracy: 426 Inaccuracy: 426
Image: V2 Image: V2
Angle: 216 Angle: 216
Warhead: Warhead: SpreadDamage
Spread: 853 Spread: 853
Versus: Versus:
None: 100% None: 100%
Wood: 90% Wood: 90%
Light: 80% Light: 80%
Heavy: 70% Heavy: 70%
InfDeath: 3
Damage: 500
Warhead@2Smu: LeaveSmudge
SmudgeType: Crater
Warhead@3Eff: CreateEffect
Explosion: nuke Explosion: nuke
WaterExplosion: large_splash WaterExplosion: large_splash
InfDeath: 3
SmudgeType: Crater
Damage: 500
ImpactSound: kaboom1.aud ImpactSound: kaboom1.aud
WaterImpactSound: kaboom1.aud WaterImpactSound: kaboom1.aud
SilencedPPK: SilencedPPK:
@@ -941,16 +956,17 @@ Weapons:
Report: silppk.aud Report: silppk.aud
Projectile: Bullet Projectile: Bullet
Speed: 1c682 Speed: 1c682
Warhead: Warhead: SpreadDamage
Spread: 128 Spread: 128
Versus: Versus:
Wood: 0% Wood: 0%
Light: 0% Light: 0%
Heavy: 50% Heavy: 50%
Concrete: 0% Concrete: 0%
Explosion: piffs
InfDeath: 2 InfDeath: 2
Damage: 150 Damage: 150
Warhead@2Eff: CreateEffect
Explosion: piffs
Voices: Voices:

View File

@@ -2333,7 +2333,7 @@ Weapons:
Nike: Nike:
Range: 9c0 Range: 9c0
Maverick: Maverick:
Warhead: Warhead: SpreadDamage
Damage: 175 Damage: 175
Voices: Voices:

View File

@@ -1076,12 +1076,10 @@ VoxelSequences:
Weapons: Weapons:
CrateNuke: CrateNuke:
Warhead@areanuke2: Warhead@areanuke2: SpreadDamage
DamageModel: PerCell DamageModel: PerCell
Damage: 250 Damage: 250
SmudgeType: Scorch Size: 4
Size: 4,3
Ore: true
Versus: Versus:
None: 90% None: 90%
Light: 60% Light: 60%
@@ -1089,13 +1087,21 @@ Weapons:
Concrete: 50% Concrete: 50%
Delay: 12 Delay: 12
InfDeath: 4 InfDeath: 4
Warhead@areanuke2Smu: LeaveSmudge
SmudgeType: Scorch
Size: 4,3
Delay: 12
Warhead@areanuke2Res: DestroyResource
DestroyResources: true
Size: 4,3
Delay: 12
Warhead@areanuke2Eff: CreateEffect
ImpactSound: kaboom22 ImpactSound: kaboom22
Warhead@areanuke3: Delay: 12
Warhead@areanuke3: SpreadDamage
DamageModel: PerCell DamageModel: PerCell
Damage: 250 Damage: 250
SmudgeType: Scorch Size: 3
Size: 3,2
Ore: true
Versus: Versus:
None: 90% None: 90%
Light: 60% Light: 60%
@@ -1103,13 +1109,20 @@ Weapons:
Concrete: 50% Concrete: 50%
Delay: 24 Delay: 24
InfDeath: 4 InfDeath: 4
Warhead@areanuke3Smu: LeaveSmudge
SmudgeType: Scorch
Size: 3,2
Delay: 24
Warhead@areanuke3Res: DestroyResource
DestroyResources: true
Size: 3,2
Delay: 24
Warhead@areanuke3Eff: CreateEffect
ImpactSound: kaboom22 ImpactSound: kaboom22
Warhead@areanuke4: Delay: 24
Warhead@areanuke4: SpreadDamage
DamageModel: PerCell DamageModel: PerCell
Damage: 250 Damage: 250
SmudgeType: Scorch
Size: 2,1
Ore: true
Versus: Versus:
None: 90% None: 90%
Light: 60% Light: 60%
@@ -1117,7 +1130,17 @@ Weapons:
Concrete: 50% Concrete: 50%
Delay: 36 Delay: 36
InfDeath: 4 InfDeath: 4
Warhead@areanuke4Smu: LeaveSmudge
SmudgeType: Scorch
Size: 2,1
Delay: 36
Warhead@areanuke4Res: DestroyResource
DestroyResources: true
Size: 2,1
Delay: 36
Warhead@areanuke4Eff: CreateEffect
ImpactSound: kaboom22 ImpactSound: kaboom22
Delay: 36
Voices: Voices:

File diff suppressed because it is too large Load Diff

View File

@@ -1,27 +1,29 @@
UnitExplode: UnitExplode:
Warhead: Warhead@1Dam: SpreadDamage
Damage: 500
Spread: 426 Spread: 426
Damage: 500
InfDeath: 2
Versus: Versus:
None: 90% None: 90%
Wood: 75% Wood: 75%
Light: 60% Light: 60%
Heavy: 25% Heavy: 25%
Warhead@2Eff: CreateEffect
Explosion: large_twlt Explosion: large_twlt
InfDeath: 2
ImpactSound: expnew09.aud ImpactSound: expnew09.aud
UnitExplodeSmall: UnitExplodeSmall:
Warhead: Warhead@1Dam: SpreadDamage
Damage: 40
Spread: 426 Spread: 426
Damage: 40
InfDeath: 2
Versus: Versus:
None: 90% None: 90%
Wood: 75% Wood: 75%
Light: 60% Light: 60%
Heavy: 25% Heavy: 25%
Warhead@2Eff: CreateEffect
Explosion: medium_brnl Explosion: medium_brnl
InfDeath: 2
ImpactSound: expnew13.aud ImpactSound: expnew13.aud
Minigun: Minigun:
@@ -30,17 +32,18 @@ Minigun:
Report: INFGUN3.AUD Report: INFGUN3.AUD
Projectile: Bullet Projectile: Bullet
Speed: 1c682 Speed: 1c682
Warhead: Warhead@1Dam: SpreadDamage
Spread: 128 Spread: 128
Damage: 12
InfDeath: 1
ProneModifier: 70
Versus: Versus:
Wood: 60% Wood: 60%
Light: 40% Light: 40%
Heavy: 25% Heavy: 25%
Concrete: 10% Concrete: 10%
Warhead@2Eff: CreateEffect
Explosion: piffpiff Explosion: piffpiff
InfDeath: 1
Damage: 12
ProneModifier: 70
Grenade: Grenade:
ROF: 60 ROF: 60
@@ -52,17 +55,18 @@ Grenade:
Angle: 62 Angle: 62
Inaccuracy: 554 Inaccuracy: 554
Image: DISCUS Image: DISCUS
Warhead: Warhead@1Dam: SpreadDamage
Spread: 171 Spread: 171
Damage: 40
InfDeath: 3
ProneModifier: 70
Versus: Versus:
None: 100% None: 100%
Wood: 85% Wood: 85%
Light: 70% Light: 70%
Heavy: 35% Heavy: 35%
Concrete: 28% Concrete: 28%
InfDeath: 3 Warhead@2Eff: CreateEffect
Damage: 40
ProneModifier: 70
Explosion: large_grey_explosion Explosion: large_grey_explosion
ImpactSound: expnew13.aud ImpactSound: expnew13.aud
@@ -81,16 +85,17 @@ Bazooka:
Image: DRAGON Image: DRAGON
ROT: 8 ROT: 8
RangeLimit: 35 RangeLimit: 35
Warhead: Warhead@1Dam: SpreadDamage
Spread: 128 Spread: 128
Damage: 25
InfDeath: 2
Versus: Versus:
None: 25% None: 25%
Wood: 65% Wood: 65%
Light: 75% Light: 75%
Heavy: 100% Heavy: 100%
Concrete: 60% Concrete: 60%
InfDeath: 2 Warhead@2Eff: CreateEffect
Damage: 25
Explosion: small_clsn Explosion: small_clsn
ImpactSound: expnew12.aud ImpactSound: expnew12.aud
@@ -109,16 +114,17 @@ MultiCluster:
Image: DRAGON Image: DRAGON
ROT: 8 ROT: 8
RangeLimit: 35 RangeLimit: 35
Warhead: Warhead@1Dam: SpreadDamage
Spread: 128 Spread: 128
Damage: 65
InfDeath: 3
Versus: Versus:
None: 25% None: 25%
Wood: 65% Wood: 65%
Light: 75% Light: 75%
Heavy: 100% Heavy: 100%
Concrete: 60% Concrete: 60%
InfDeath: 3 Warhead@2Eff: CreateEffect
Damage: 65
Explosion: large_explosion Explosion: large_explosion
ImpactSound: expnew09.aud ImpactSound: expnew09.aud
@@ -128,16 +134,16 @@ Heal:
Report: HEALER1.AUD Report: HEALER1.AUD
Projectile: Bullet Projectile: Bullet
Speed: 1c682 Speed: 1c682
Warhead: Warhead@1Dam: SpreadDamage
Spread: 213 Spread: 213
Damage: -50
InfDeath: 1
ProneModifier: 100
Versus: Versus:
Wood: 0% Wood: 0%
Light: 0% Light: 0%
Heavy: 0% Heavy: 0%
Concrete: 0% Concrete: 0%
InfDeath: 1
Damage: -50
ProneModifier: 100
Sniper: Sniper:
ROF: 60 ROF: 60
@@ -145,17 +151,17 @@ Sniper:
Report: SILENCER.AUD Report: SILENCER.AUD
Projectile: Bullet Projectile: Bullet
Speed: 1c682 Speed: 1c682
Warhead: Warhead@1Dam: SpreadDamage
Damage: 150
ProneModifier: 100
Spread: 42 Spread: 42
Damage: 150
InfDeath: 1
ProneModifier: 100
Versus: Versus:
None: 100% None: 100%
Wood: 0% Wood: 0%
Light: 0% Light: 0%
Heavy: 0% Heavy: 0%
Concrete: 0% Concrete: 0%
InfDeath: 1
M1Carbine: M1Carbine:
ROF: 20 ROF: 20
@@ -163,17 +169,18 @@ M1Carbine:
Report: INFGUN3.AUD Report: INFGUN3.AUD
Projectile: Bullet Projectile: Bullet
Speed: 1c682 Speed: 1c682
Warhead: Warhead@1Dam: SpreadDamage
Spread: 128 Spread: 128
Damage: 15
InfDeath: 1
ProneModifier: 70
Versus: Versus:
Wood: 60% Wood: 60%
Light: 40% Light: 40%
Heavy: 25% Heavy: 25%
Concrete: 10% Concrete: 10%
Warhead@2Eff: CreateEffect
Explosion: piffpiff Explosion: piffpiff
InfDeath: 1
Damage: 15
ProneModifier: 70
LtRail: LtRail:
ROF: 60 ROF: 60
@@ -184,17 +191,17 @@ LtRail:
BeamWidth: 1 BeamWidth: 1
BeamDuration: 10 BeamDuration: 10
Color: 200,0,128,255 Color: 200,0,128,255
Warhead: Warhead@1Dam: SpreadDamage
Damage: 150
ProneModifier: 100
Spread: 42 Spread: 42
Damage: 150
InfDeath: 2
ProneModifier: 100
Versus: Versus:
None: 100% None: 100%
Wood: 130% Wood: 130%
Light: 150% Light: 150%
Heavy: 110% Heavy: 110%
Concrete: 5% Concrete: 5%
InfDeath: 2
CyCannon: CyCannon:
ROF: 50 ROF: 50
@@ -206,17 +213,18 @@ CyCannon:
High: yes High: yes
Shadow: true Shadow: true
Image: TORPEDO Image: TORPEDO
Warhead: Warhead@1Dam: SpreadDamage
Spread: 256 Spread: 256
Damage: 120
InfDeath: 6
ProneModifier: 100
Versus: Versus:
None: 100% None: 100%
Wood: 65% Wood: 65%
Light: 75% Light: 75%
Heavy: 50% Heavy: 50%
Concrete: 40% Concrete: 40%
InfDeath: 6 Warhead@2Eff: CreateEffect
Damage: 120
ProneModifier: 100
Explosion: large_bang Explosion: large_bang
ImpactSound: expnew12.aud ImpactSound: expnew12.aud
@@ -227,17 +235,18 @@ Vulcan3:
Report: CYGUN1.AUD Report: CYGUN1.AUD
Projectile: Bullet Projectile: Bullet
Speed: 1c682 Speed: 1c682
Warhead: Warhead@1Dam: SpreadDamage
Spread: 128 Spread: 128
Damage: 10
InfDeath: 1
ProneModifier: 70
Versus: Versus:
Wood: 60% Wood: 60%
Light: 40% Light: 40%
Heavy: 25% Heavy: 25%
Concrete: 10% Concrete: 10%
Warhead@2Eff: CreateEffect
Explosion: piffpiff Explosion: piffpiff
InfDeath: 1
Damage: 10
ProneModifier: 70
Vulcan2: Vulcan2:
ROF: 50 ROF: 50
@@ -246,18 +255,19 @@ Vulcan2:
Report: TSGUN4.AUD Report: TSGUN4.AUD
Projectile: Bullet Projectile: Bullet
Speed: 1c682 Speed: 1c682
Warhead: Warhead@1Dam: SpreadDamage
Spread: 128 Spread: 128
Damage: 50
InfDeath: 1
ProneModifier: 70
Versus: Versus:
None: 100% None: 100%
Wood: 60% Wood: 60%
Light: 40% Light: 40%
Heavy: 25% Heavy: 25%
Concrete: 10% Concrete: 10%
Warhead@2Eff: CreateEffect
Explosion: piffpiff Explosion: piffpiff
InfDeath: 1
Damage: 50
ProneModifier: 70
Vulcan: Vulcan:
ROF: 60 ROF: 60
@@ -265,17 +275,18 @@ Vulcan:
Report: CHAINGN1.AUD Report: CHAINGN1.AUD
Projectile: Bullet Projectile: Bullet
Speed: 1c682 Speed: 1c682
Warhead: Warhead@1Dam: SpreadDamage
Spread: 128 Spread: 128
Damage: 20
InfDeath: 1
ProneModifier: 70
Versus: Versus:
Wood: 60% Wood: 60%
Light: 40% Light: 40%
Heavy: 25% Heavy: 25%
Concrete: 10% Concrete: 10%
Warhead@2Eff: CreateEffect
Explosion: piffpiff Explosion: piffpiff
InfDeath: 1
Damage: 20
ProneModifier: 70
FiendShard: FiendShard:
ROF: 30 ROF: 30
@@ -289,15 +300,15 @@ FiendShard:
Inaccuracy: 512 Inaccuracy: 512
Shadow: true Shadow: true
Angle: 88 Angle: 88
Warhead: Warhead@1Dam: SpreadDamage
Damage: 35
InfDeath: 1
ProneModifier: 100
Versus: Versus:
Wood: 60% Wood: 60%
Light: 40% Light: 40%
Heavy: 25% Heavy: 25%
Concrete: 10% Concrete: 10%
InfDeath: 1
Damage: 35
ProneModifier: 100
JumpCannon: JumpCannon:
ROF: 40 ROF: 40
@@ -306,17 +317,18 @@ JumpCannon:
Report: JUMPJET1.AUD Report: JUMPJET1.AUD
Projectile: Bullet Projectile: Bullet
Speed: 1c682 Speed: 1c682
Warhead: Warhead@1Dam: SpreadDamage
Spread: 128 Spread: 128
Damage: 15
InfDeath: 1
ProneModifier: 70
Versus: Versus:
Wood: 60% Wood: 60%
Light: 40% Light: 40%
Heavy: 25% Heavy: 25%
Concrete: 10% Concrete: 10%
Warhead@2Eff: CreateEffect
Explosion: piffpiff Explosion: piffpiff
InfDeath: 1
Damage: 15
ProneModifier: 70
HoverMissile: HoverMissile:
ROF: 68 ROF: 68
@@ -334,16 +346,17 @@ HoverMissile:
Image: DRAGON Image: DRAGON
ROT: 8 ROT: 8
RangeLimit: 35 RangeLimit: 35
Warhead: Warhead@1Dam: SpreadDamage
Spread: 128 Spread: 128
Damage: 30
InfDeath: 2
Versus: Versus:
None: 25% None: 25%
Wood: 65% Wood: 65%
Light: 75% Light: 75%
Heavy: 100% Heavy: 100%
Concrete: 60% Concrete: 60%
InfDeath: 2 Warhead@2Eff: CreateEffect
Damage: 30
Explosion: small_clsn Explosion: small_clsn
ImpactSound: expnew12.aud ImpactSound: expnew12.aud
@@ -359,16 +372,17 @@ HoverMissile:
Image: 120mm Image: 120mm
Shadow: true Shadow: true
Angle: 62 Angle: 62
Warhead: Warhead@1Dam: SpreadDamage
Spread: 128 Spread: 128
Damage: 50
InfDeath: 2
Versus: Versus:
None: 25% None: 25%
Wood: 65% Wood: 65%
Light: 75% Light: 75%
Heavy: 100% Heavy: 100%
Concrete: 60% Concrete: 60%
InfDeath: 2 Warhead@2Eff: CreateEffect
Damage: 50
Explosion: medium_clsn Explosion: medium_clsn
ImpactSound: expnew14.aud ImpactSound: expnew14.aud
@@ -388,17 +402,18 @@ MammothTusk:
ROT: 10 ROT: 10
Speed: 170 Speed: 170
RangeLimit: 35 RangeLimit: 35
Warhead: Warhead@1Dam: SpreadDamage
Spread: 171 Spread: 171
Damage: 40
InfDeath: 3
ProneModifier: 70
Versus: Versus:
None: 100% None: 100%
Wood: 85% Wood: 85%
Light: 70% Light: 70%
Heavy: 35% Heavy: 35%
Concrete: 28% Concrete: 28%
InfDeath: 3 Warhead@2Eff: CreateEffect
Damage: 40
ProneModifier: 70
Explosion: medium_bang Explosion: medium_bang
ImpactSound: expnew12.aud ImpactSound: expnew12.aud
@@ -408,17 +423,17 @@ Repair:
Report: REPAIR11.AUD Report: REPAIR11.AUD
Projectile: Bullet Projectile: Bullet
Speed: 1c682 Speed: 1c682
Warhead: Warhead@1Dam: SpreadDamage
Spread: 213 Spread: 213
Damage: -50
InfDeath: 1
ProneModifier: 100
Versus: Versus:
None: 0% None: 0%
Wood: 0% Wood: 0%
Light: 100% Light: 100%
Heavy: 100% Heavy: 100%
Concrete: 0% Concrete: 0%
InfDeath: 1
Damage: -50
ProneModifier: 100
SlimeAttack: SlimeAttack:
ROF: 80 ROF: 80
@@ -427,30 +442,30 @@ SlimeAttack:
Report: VICER1.AUD Report: VICER1.AUD
Projectile: Bullet Projectile: Bullet
Speed: 426 Speed: 426
Warhead: Warhead@1Dam: SpreadDamage
Damage: 100
InfDeath: 2
ProneModifier: 100
Versus: Versus:
Wood: 25% Wood: 25%
Light: 30% Light: 30%
Heavy: 10% Heavy: 10%
Concrete: 10% Concrete: 10%
InfDeath: 2
Damage: 100
ProneModifier: 100
SuicideBomb: SuicideBomb:
ROF: 1 ROF: 1
Range: 0c512 Range: 0c512
Report: HUNTER2.AUD Report: HUNTER2.AUD
Warhead: Warhead@1Dam: SpreadDamage
Damage: 11000
Spread: 256 Spread: 256
DestroyResources: true Damage: 11000
InfDeath: 5
Versus: Versus:
None: 90% None: 90%
Light: 60% Light: 60%
Heavy: 25% Heavy: 25%
Concrete: 50% Concrete: 50%
InfDeath: 5 Warhead@2Res: DestroyResource
120mm: 120mm:
ROF: 80 ROF: 80
@@ -458,16 +473,17 @@ SuicideBomb:
Report: 120MMF.AUD Report: 120MMF.AUD
Projectile: Bullet Projectile: Bullet
Speed: 1c512 Speed: 1c512
Warhead: Warhead@1Dam: SpreadDamage
Spread: 128 Spread: 128
Damage: 70
InfDeath: 2
Versus: Versus:
None: 25% None: 25%
Wood: 65% Wood: 65%
Light: 75% Light: 75%
Heavy: 100% Heavy: 100%
Concrete: 60% Concrete: 60%
InfDeath: 2 Warhead@2Eff: CreateEffect
Damage: 70
Explosion: large_clsn Explosion: large_clsn
ImpactSound: expnew14.aud ImpactSound: expnew14.aud
@@ -480,17 +496,17 @@ MechRailgun:
Projectile: LaserZap Projectile: LaserZap
Color: 200,0,255,255 Color: 200,0,255,255
BeamWidth: 3 BeamWidth: 3
Warhead: Warhead@1Dam: SpreadDamage
Spread: 42 Spread: 42
Damage: 200
InfDeath: 5
ProneModifier: 100
Versus: Versus:
None: 200% None: 200%
Wood: 175% Wood: 175%
Light: 160% Light: 160%
Heavy: 100% Heavy: 100%
Concrete: 25% Concrete: 25%
InfDeath: 5
Damage: 200
ProneModifier: 100
AssaultCannon: AssaultCannon:
ROF: 50 ROF: 50
@@ -498,17 +514,18 @@ AssaultCannon:
Report: TSGUN4.AUD Report: TSGUN4.AUD
Projectile: Bullet Projectile: Bullet
Speed: 1c682 Speed: 1c682
Warhead: Warhead@1Dam: SpreadDamage
Spread: 128 Spread: 128
Damage: 40
InfDeath: 1
ProneModifier: 70
Versus: Versus:
Wood: 60% Wood: 60%
Light: 40% Light: 40%
Heavy: 25% Heavy: 25%
Concrete: 10% Concrete: 10%
Warhead@2Eff: CreateEffect
Explosion: piffpiff Explosion: piffpiff
InfDeath: 1
Damage: 40
ProneModifier: 70
BikeMissile: BikeMissile:
ROF: 60 ROF: 60
@@ -527,38 +544,40 @@ BikeMissile:
ROT: 8 ROT: 8
Speed: 213 Speed: 213
RangeLimit: 35 RangeLimit: 35
Warhead: Warhead@1Dam: SpreadDamage
Spread: 256 Spread: 256
Damage: 40
InfDeath: 2
Versus: Versus:
None: 25% None: 25%
Wood: 65% Wood: 65%
Light: 75% Light: 75%
Heavy: 100% Heavy: 100%
Concrete: 60% Concrete: 60%
InfDeath: 2 Warhead@2Eff: CreateEffect
Damage: 40
Explosion: small_clsn Explosion: small_clsn
ImpactSound: expnew12.aud ImpactSound: expnew12.aud
RaiderCannon: RaiderCannon:
ROF: 55 ROF: 55
Range: 4c0 Range: 4c0
Burst: 2 #purely cosmetical, for alternate muzzle position Burst: 2
BurstDelay: 55 BurstDelay: 55
Report: CHAINGN1.AUD Report: CHAINGN1.AUD
Projectile: Bullet Projectile: Bullet
Speed: 1c682 Speed: 1c682
Warhead: Warhead@1Dam: SpreadDamage
Spread: 128 Spread: 128
Damage: 40
InfDeath: 1
ProneModifier: 70
Versus: Versus:
Wood: 60% Wood: 60%
Light: 40% Light: 40%
Heavy: 25% Heavy: 25%
Concrete: 10% Concrete: 10%
Warhead@2Eff: CreateEffect
Explosion: piffpiff Explosion: piffpiff
InfDeath: 1
Damage: 40
ProneModifier: 70
FireballLauncher: FireballLauncher:
ROF: 50 ROF: 50
@@ -570,17 +589,17 @@ FireballLauncher:
Inacuracy: 384 Inacuracy: 384
Burst: 5 Burst: 5
BurstDelay: 5 BurstDelay: 5
Warhead: Warhead@1Dam: SpreadDamage
Spread: 341 Spread: 341
Damage: 25
InfDeath: 5
ProneModifier: 100
Versus: Versus:
None: 600% None: 600%
Wood: 148% Wood: 148%
Light: 59% Light: 59%
Heavy: 6% Heavy: 6%
Concrete: 2% Concrete: 2%
InfDeath: 5
Damage: 25
ProneModifier: 100
SonicZap: SonicZap:
ROF: 120 ROF: 120
@@ -591,13 +610,13 @@ SonicZap:
Color: 200,0,255,255 Color: 200,0,255,255
BeamWidth: 12 BeamWidth: 12
BeamDuration: 50 BeamDuration: 50
Warhead: Warhead@1Dam: SpreadDamage
Spread: 42 Spread: 42
Damage: 100
InfDeath: 5
Versus: Versus:
Heavy: 80% Heavy: 80%
Concrete: 60% Concrete: 60%
InfDeath: 5
Damage: 100
Dragon: Dragon:
ROF: 50 ROF: 50
@@ -615,16 +634,17 @@ Dragon:
Image: DRAGON Image: DRAGON
ROT: 8 ROT: 8
RangeLimit: 35 RangeLimit: 35
Warhead: Warhead@1Dam: SpreadDamage
Spread: 128 Spread: 128
Damage: 30
InfDeath: 2
Versus: Versus:
None: 25% None: 25%
Wood: 65% Wood: 65%
Light: 75% Light: 75%
Heavy: 100% Heavy: 100%
Concrete: 60% Concrete: 60%
InfDeath: 2 Warhead@2Eff: CreateEffect
Damage: 30
Explosion: small_clsn Explosion: small_clsn
ImpactSound: expnew12.aud ImpactSound: expnew12.aud
@@ -638,16 +658,17 @@ Dragon:
Image: 120mm Image: 120mm
Shadow: true Shadow: true
Angle: 62 Angle: 62
Warhead: Warhead@1Dam: SpreadDamage
Spread: 128 Spread: 128
Damage: 36
InfDeath: 2
Versus: Versus:
None: 25% None: 25%
Wood: 65% Wood: 65%
Light: 75% Light: 75%
Heavy: 100% Heavy: 100%
Concrete: 60% Concrete: 60%
InfDeath: 2 Warhead@2Eff: CreateEffect
Damage: 36
Explosion: medium_clsn Explosion: medium_clsn
ImpactSound: expnew14.aud ImpactSound: expnew14.aud
@@ -663,17 +684,18 @@ Dragon:
Shadow: true Shadow: true
High: yes High: yes
MinRange: 5c0 MinRange: 5c0
Warhead: Warhead@1Dam: SpreadDamage
Spread: 298 Spread: 298
Damage: 150
InfDeath: 3
ProneModifier: 100
Versus: Versus:
None: 100% None: 100%
Wood: 85% Wood: 85%
Light: 68% Light: 68%
Heavy: 35% Heavy: 35%
Concrete: 35% Concrete: 35%
InfDeath: 3 Warhead@2Eff: CreateEffect
Damage: 150
ProneModifier: 100
Explosion: large_explosion Explosion: large_explosion
ImpactSound: expnew09.aud ImpactSound: expnew09.aud
@@ -693,16 +715,17 @@ Hellfire:
Image: DRAGON Image: DRAGON
ROT: 8 ROT: 8
RangeLimit: 35 RangeLimit: 35
Warhead: Warhead@1Dam: SpreadDamage
Spread: 85 Spread: 85
Damage: 30
InfDeath: 2
Versus: Versus:
None: 30% None: 30%
Wood: 65% Wood: 65%
Light: 150% Light: 150%
Heavy: 100% Heavy: 100%
Concrete: 30% Concrete: 30%
InfDeath: 2 Warhead@2Eff: CreateEffect
Damage: 30
Explosion: small_bang Explosion: small_bang
ImpactSound: expnew12.aud ImpactSound: expnew12.aud
@@ -714,17 +737,18 @@ Bomb:
Speed: 170 Speed: 170
Image: canister Image: canister
Shadow: true Shadow: true
Warhead: Warhead@1Dam: SpreadDamage
Spread: 298 Spread: 298
Damage: 160
InfDeath: 3
ProneModifier: 100
Versus: Versus:
None: 200% None: 200%
Wood: 90% Wood: 90%
Light: 75% Light: 75%
Heavy: 32% Heavy: 32%
Concrete: 100% Concrete: 100%
InfDeath: 3 Warhead@2Eff: CreateEffect
Damage: 160
ProneModifier: 100
Explosion: large_explosion Explosion: large_explosion
ImpactSound: expnew09.aud ImpactSound: expnew09.aud
@@ -743,16 +767,17 @@ Proton:
Image: TORPEDO Image: TORPEDO
ROT: 1 ROT: 1
RangeLimit: 35 RangeLimit: 35
Warhead: Warhead@1Dam: SpreadDamage
Spread: 128 Spread: 128
Damage: 20
InfDeath: 3
Versus: Versus:
None: 25% None: 25%
Wood: 65% Wood: 65%
Light: 75% Light: 75%
Heavy: 100% Heavy: 100%
Concrete: 60% Concrete: 60%
InfDeath: 3 Warhead@2Eff: CreateEffect
Damage: 20
Explosion: small_bang Explosion: small_bang
ImpactSound: expnew12.aud ImpactSound: expnew12.aud
@@ -763,17 +788,18 @@ HarpyClaw:
Projectile: Bullet Projectile: Bullet
Speed: 1c682 Speed: 1c682
ValidTargets: Ground, Air ValidTargets: Ground, Air
Warhead: Warhead@1Dam: SpreadDamage
Spread: 128 Spread: 128
Damage: 60
InfDeath: 1
ProneModifier: 70
Versus: Versus:
Wood: 60% Wood: 60%
Light: 40% Light: 40%
Heavy: 25% Heavy: 25%
Concrete: 10% Concrete: 10%
Warhead@2Eff: CreateEffect
Explosion: piffpiff Explosion: piffpiff
InfDeath: 1
Damage: 60
ProneModifier: 70
Pistola: Pistola:
ROF: 20 ROF: 20
@@ -781,49 +807,57 @@ Pistola:
Report: GUN18.AUD Report: GUN18.AUD
Projectile: Bullet Projectile: Bullet
Speed: 1c682 Speed: 1c682
Warhead: Warhead@1Dam: SpreadDamage
Spread: 128 Spread: 128
Damage: 2
InfDeath: 1
ProneModifier: 70
Versus: Versus:
Wood: 60% Wood: 60%
Light: 40% Light: 40%
Heavy: 25% Heavy: 25%
Concrete: 10% Concrete: 10%
Warhead@2Eff: CreateEffect
Explosion: piff Explosion: piff
InfDeath: 1
Damage: 2
ProneModifier: 70
Tiberium: Tiberium:
ROF: 16 ROF: 16
Warhead: Warhead@1Dam: SpreadDamage
Spread: 42 Spread: 42
InfDeath: 6
Damage: 2 Damage: 2
InfDeath: 6
PreventProne: yes PreventProne: yes
TiberiumHeal: TiberiumHeal:
ROF: 16 ROF: 16
Warhead: Warhead@1Dam: SpreadDamage
Spread: 42 Spread: 42
InfDeath: 6
Damage: -2 Damage: -2
InfDeath: 6
PreventProne: yes PreventProne: yes
IonCannon: IonCannon:
ValidTargets: Ground, Air ValidTargets: Ground, Air
Warhead@impact: Warhead@1Dam_impact: SpreadDamage
Damage: 1000
Spread: 1c0 Spread: 1c0
Damage: 1000
InfDeath: 5 InfDeath: 5
Explosion: ring1
ProneModifier: 100 ProneModifier: 100
Warhead@area: Warhead@2Eff_impact: CreateEffect
DamageModel: PerCell Explosion: ring1
Warhead@3Dam_area: PerCellDamage
Size: 2,1
Damage: 250 Damage: 250
InfDeath: 5
Delay: 3
Warhead@4Dam_area: SpreadDamage
Damage: 250
InfDeath: 5
Delay: 3
Warhead@5Smu_area: LeaveSmudge
SmudgeType: Scorch SmudgeType: Scorch
Size: 2,1 Size: 2,1
Delay: 3 Delay: 3
InfDeath: 5
VulcanTower: VulcanTower:
ROF: 26 ROF: 26
@@ -831,16 +865,17 @@ VulcanTower:
Report: CHAINGN1.AUD Report: CHAINGN1.AUD
Projectile: Bullet Projectile: Bullet
Speed: 1c682 Speed: 1c682
Warhead: Warhead@1Dam: SpreadDamage
Spread: 128 Spread: 128
Damage: 18
InfDeath: 1
Versus: Versus:
Wood: 60% Wood: 60%
Light: 40% Light: 40%
Heavy: 25% Heavy: 25%
Concrete: 10% Concrete: 10%
Warhead@2Eff: CreateEffect
Explosion: piffpiff Explosion: piffpiff
InfDeath: 1
Damage: 18
RPGTower: RPGTower:
ROF: 80 ROF: 80
@@ -853,17 +888,18 @@ RPGTower:
Shadow: true Shadow: true
Angle: 62 Angle: 62
Image: canister Image: canister
Warhead: Warhead@1Dam: SpreadDamage
Spread: 128 Spread: 128
Damage: 110
InfDeath: 2
ProneModifier: 70
Versus: Versus:
None: 30% None: 30%
Wood: 75% Wood: 75%
Light: 90% Light: 90%
Heavy: 100% Heavy: 100%
Concrete: 70% Concrete: 70%
InfDeath: 2 Warhead@2Eff: CreateEffect
Damage: 110
ProneModifier: 70
Explosion: large_clsn Explosion: large_clsn
ImpactSound: expnew14.aud ImpactSound: expnew14.aud
@@ -882,10 +918,11 @@ SAMTower:
Image: DRAGON Image: DRAGON
ROT: 5 ROT: 5
RangeLimit: 60 RangeLimit: 60
Warhead: Warhead@1Dam: SpreadDamage
Spread: 128 Spread: 128
InfDeath: 2
Damage: 33 Damage: 33
InfDeath: 2
Warhead@2Eff: CreateEffect
Explosion: small_clsn Explosion: small_clsn
ImpactSound: expnew12.aud ImpactSound: expnew12.aud
@@ -896,12 +933,13 @@ ObeliskLaser:
Report: OBELRAY1.AUD Report: OBELRAY1.AUD
Projectile: LaserZap Projectile: LaserZap
BeamWidth: 4 BeamWidth: 4
Warhead: Warhead@1Dam: SpreadDamage
Spread: 42 Spread: 42
InfDeath: 5
SmudgeType: Scorch
Damage: 250 Damage: 250
InfDeath: 5
ProneModifier: 60 ProneModifier: 60
Warhead@2Smu: LeaveSmudge
SmudgeType: Scorch
TurretLaser: TurretLaser:
ROF: 40 ROF: 40
@@ -910,24 +948,28 @@ TurretLaser:
Projectile: LaserZap Projectile: LaserZap
BeamWidth: 2 BeamWidth: 2
BeamDuration: 5 BeamDuration: 5
Warhead: Warhead@1Dam: SpreadDamage
Spread: 42 Spread: 42
InfDeath: 5
SmudgeType: Scorch
Damage: 30 Damage: 30
InfDeath: 5
ProneModifier: 60 ProneModifier: 60
Warhead@2Smu: LeaveSmudge
SmudgeType: Scorch
TiberiumExplosion: TiberiumExplosion:
Warhead: Warhead@1Dam: SpreadDamage
Damage: 10
Spread: 9 Spread: 9
Size: 1,1 Damage: 10
InfDeath: 3
Versus: Versus:
None: 90% None: 90%
Wood: 75% Wood: 75%
Light: 60% Light: 60%
Heavy: 25% Heavy: 25%
InfDeath: 3 Warhead@2Res: CreateResource
AddsResourceType: Tiberium
Size: 1,1
Warhead@3Eff: CreateEffect
Explosion: large_explosion Explosion: large_explosion
ImpactSound: expnew09.aud ImpactSound: expnew09.aud
AddsResourceType: Tiberium