Merge pull request #6030 from UberWaffe/CustomWarheads

Custom Warheads refactor
This commit is contained in:
Taryn Hill
2014-08-03 10:35:36 -05:00
59 changed files with 2275 additions and 1233 deletions

View File

@@ -509,10 +509,16 @@ namespace OpenRA
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))
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;
}

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
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Effects;
@@ -15,83 +16,6 @@ using OpenRA.Traits;
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 WeaponInfo Weapon;
@@ -107,20 +31,38 @@ namespace OpenRA.GameRules
public class WeaponInfo
{
[Desc("The maximum range the weapon can fire.")]
public readonly WRange Range = WRange.Zero;
[Desc("The sound played when the weapon is fired.")]
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;
[Desc("Number of shots in a single ammo magazine.")]
public readonly int Burst = 1;
public readonly bool Charges = false;
public readonly string Palette = "effect";
[Desc("What types of targets are affected.")]
public readonly string[] ValidTargets = { "Ground", "Water" };
[Desc("What types of targets are unaffected.", "Overrules ValidTargets.")]
public readonly string[] InvalidTargets = { };
[Desc("Delay in ticks between firing shots from the same ammo magazine.")]
public readonly int BurstDelay = 5;
[Desc("The minimum range the weapon can fire.")]
public readonly WRange MinRange = WRange.Zero;
[FieldLoader.LoadUsing("LoadProjectile")] public IProjectileInfo Projectile;
[FieldLoader.LoadUsing("LoadWarheads")] public List<WarheadInfo> Warheads;
[FieldLoader.LoadUsing("LoadProjectile")]
public readonly IProjectileInfo Projectile;
[FieldLoader.LoadUsing("LoadWarheads")]
public readonly List<Warhead> Warheads = new List<Warhead>();
public WeaponInfo(string name, MiniYaml content)
{
@@ -139,47 +81,24 @@ namespace OpenRA.GameRules
static object LoadWarheads(MiniYaml yaml)
{
var ret = new List<WarheadInfo>();
foreach (var w in yaml.Nodes)
if (w.Key.Split('@')[0] == "Warhead")
ret.Add(new WarheadInfo(w.Value));
var retList = new List<Warhead>();
foreach (var node in yaml.Nodes.Where(n => n.Key.StartsWith("Warhead")))
{
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)
{
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)
public bool IsValidAgainst(Target target, World world, Actor firedBy)
{
if (target.Type == TargetType.Actor)
return IsValidAgainst(target.Actor);
return IsValidAgainst(target.Actor, firedBy);
if (target.Type == TargetType.FrozenActor)
return IsValidAgainst(target.FrozenActor);
return IsValidAgainst(target.FrozenActor, firedBy);
if (target.Type == TargetType.Terrain)
{
@@ -197,5 +116,47 @@ namespace OpenRA.GameRules
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>
<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="Download.cs" />
<Compile Include="Effects\DelayedAction.cs" />

View File

@@ -98,7 +98,7 @@ namespace OpenRA.Traits
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! */
@@ -177,7 +177,7 @@ namespace OpenRA.Traits
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;
var health = self.TraitOrDefault<Health>();

View File

@@ -27,7 +27,7 @@ namespace OpenRA.Traits
public class AttackInfo
{
public Actor Attacker;
public WarheadInfo Warhead;
public DamageWarhead Warhead;
public int Damage;
public DamageState DamageState;
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 IDamageModifier { float GetDamageModifier(Actor attacker, WarheadInfo warhead); }
public interface IDamageModifier { float GetDamageModifier(Actor attacker, DamageWarhead warhead); }
public interface ISpeedModifier { decimal GetSpeedModifier(); }
public interface IFirepowerModifier { float GetFirepowerModifier(); }
public interface ILoadsPalettes { void LoadPalettes(WorldRenderer wr); }

View File

@@ -10,6 +10,7 @@
using System.Collections.Generic;
using OpenRA.Effects;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Mods.RA;
using OpenRA.Traits;
@@ -44,7 +45,8 @@ namespace OpenRA.Mods.Cnc.Effects
void Finish(World world)
{
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 OpenRA.Traits;
using OpenRA.Mods.RA;
using OpenRA.GameRules;
namespace OpenRA.Mods.Cnc
{
@@ -42,8 +43,7 @@ namespace OpenRA.Mods.Cnc
if (!info.Resources.Contains(r.Info.Name)) return;
var weapon = self.World.Map.Rules.Weapons[info.Weapon.ToLowerInvariant()];
self.InflictDamage(self.World.WorldActor, weapon.Warheads[0].Damage, weapon.Warheads[0]);
weapon.Impact(self.CenterPosition, self.World.WorldActor, 1f);
poisonTicks = weapon.ROF;
}
}

View File

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

View File

@@ -13,6 +13,7 @@ using System.Collections.Generic;
using System.Linq;
using AI.Fuzzy.Library;
using OpenRA.Mods.RA.Move;
using OpenRA.GameRules;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.AI
@@ -195,8 +196,11 @@ namespace OpenRA.Mods.RA.AI
var sumOfDamage = 0;
var arms = a.TraitsImplementing<Armament>();
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;
});
}

View File

@@ -63,7 +63,7 @@ namespace OpenRA.Mods.RA.Activities
mobile.IsMoving = false;
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));
return NextActivity;

View File

@@ -8,6 +8,7 @@
*/
#endregion
using OpenRA.GameRules;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Air
@@ -51,7 +52,10 @@ namespace OpenRA.Mods.RA.Air
if (self.CenterPosition.Z <= 0)
{
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();
return null;

View File

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

View File

@@ -12,6 +12,7 @@ using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.GameRules;
using OpenRA.Mods.RA.Buildings;
using OpenRA.Traits;
@@ -87,11 +88,11 @@ namespace OpenRA.Mods.RA
{
get
{
var armament = Armaments.FirstOrDefault();
var armament = Armaments.FirstOrDefault(a => a.Weapon.Warheads.Any(w => (w is DamageWarhead)));
if (armament == null)
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);
}
}
@@ -134,13 +135,13 @@ namespace OpenRA.Mods.RA
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()
{
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)
{

View File

@@ -22,6 +22,8 @@ namespace OpenRA.Mods.RA
[Desc("How many game ticks should pass before closing the actor's turret.")]
public int CloseDelay = 125;
public int DefaultFacing = 0;
[Desc("The factor damage received is multiplied by while this actor is closed.")]
public float ClosedDamageMultiplier = 0.5f;
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;
}

View File

@@ -11,6 +11,7 @@
using System.Collections.Generic;
using System.Linq;
using OpenRA.Effects;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Primitives;
using OpenRA.Traits;
@@ -294,7 +295,8 @@ namespace OpenRA.Mods.RA
var initialDamage = Health.DamageState;
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.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
using OpenRA.GameRules;
using OpenRA.Traits;
namespace OpenRA.Mods.RA
@@ -28,7 +29,8 @@ namespace OpenRA.Mods.RA
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);
}
}

View File

@@ -172,7 +172,7 @@ namespace OpenRA.Mods.RA.Effects
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);
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();

View File

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

View File

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

View File

@@ -11,6 +11,7 @@
using System.Collections.Generic;
using System.Linq;
using OpenRA.Effects;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Traits;
@@ -79,7 +80,8 @@ namespace OpenRA.Mods.RA.Effects
void Explode(World world)
{
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);
foreach (var a in world.ActorsWithTrait<NukePaletteEffect>())

View File

@@ -47,7 +47,7 @@ namespace OpenRA.Mods.RA.Effects
if (!doneDamage)
{
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;
}
}

View File

@@ -9,6 +9,7 @@
#endregion
using System.Linq;
using OpenRA.GameRules;
using OpenRA.Traits;
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))
return;
var weapon = ChooseWeaponForExplosion(self);
if (weapon != null)
Combat.DoExplosion(e.Attacker, weapon, self.CenterPosition);
var weaponName = ChooseWeaponForExplosion(self);
if (weaponName != null)
{
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)

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

View File

@@ -67,7 +67,7 @@ namespace OpenRA.Mods.RA
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;
}

View File

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

View File

@@ -10,6 +10,7 @@
using System.Collections.Generic;
using System.Drawing;
using OpenRA.GameRules;
using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Move;
using OpenRA.Mods.RA.Orders;
@@ -68,7 +69,10 @@ namespace OpenRA.Mods.RA
if (++tick >= info.ThumpInterval)
{
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);
tick = 0;
}
@@ -104,7 +108,10 @@ namespace OpenRA.Mods.RA
self.World.AddFrameEndTask(w =>
{
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);
});
}

View File

@@ -189,7 +189,6 @@
<Compile Include="ChronoshiftPaletteEffect.cs" />
<Compile Include="Chronoshiftable.cs" />
<Compile Include="Cloak.cs" />
<Compile Include="Combat.cs" />
<Compile Include="ConquestVictoryConditions.cs" />
<Compile Include="ContainsCrate.cs" />
<Compile Include="Crate.cs" />
@@ -289,6 +288,10 @@
<Compile Include="Player\ProductionQueue.cs" />
<Compile Include="Player\ProvidesTechPrerequisite.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="Player\TechTree.cs" />
<Compile Include="PrimaryBuilding.cs" />

View File

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

View File

@@ -61,7 +61,7 @@ namespace OpenRA.Mods.RA
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;
}

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

@@ -422,6 +422,180 @@ namespace OpenRA.Utility
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);
}
}

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1076,12 +1076,10 @@ VoxelSequences:
Weapons:
CrateNuke:
Warhead@areanuke2:
Warhead@areanuke2: SpreadDamage
DamageModel: PerCell
Damage: 250
SmudgeType: Scorch
Size: 4,3
Ore: true
Size: 4
Versus:
None: 90%
Light: 60%
@@ -1089,13 +1087,21 @@ Weapons:
Concrete: 50%
Delay: 12
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
Warhead@areanuke3:
Delay: 12
Warhead@areanuke3: SpreadDamage
DamageModel: PerCell
Damage: 250
SmudgeType: Scorch
Size: 3,2
Ore: true
Size: 3
Versus:
None: 90%
Light: 60%
@@ -1103,13 +1109,20 @@ Weapons:
Concrete: 50%
Delay: 24
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
Warhead@areanuke4:
Delay: 24
Warhead@areanuke4: SpreadDamage
DamageModel: PerCell
Damage: 250
SmudgeType: Scorch
Size: 2,1
Ore: true
Versus:
None: 90%
Light: 60%
@@ -1117,7 +1130,17 @@ Weapons:
Concrete: 50%
Delay: 36
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
Delay: 36
Voices:

File diff suppressed because it is too large Load Diff

View File

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