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:
@@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>())
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -188,7 +188,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" />
|
||||
@@ -288,6 +287,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" />
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
86
OpenRA.Mods.RA/Warheads/CreateEffectWarhead.cs
Normal file
86
OpenRA.Mods.RA/Warheads/CreateEffectWarhead.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
66
OpenRA.Mods.RA/Warheads/CreateResourceWarhead.cs
Normal file
66
OpenRA.Mods.RA/Warheads/CreateResourceWarhead.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
47
OpenRA.Mods.RA/Warheads/DestroyResourceWarhead.cs
Normal file
47
OpenRA.Mods.RA/Warheads/DestroyResourceWarhead.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
58
OpenRA.Mods.RA/Warheads/LeaveSmudgeWarhead.cs
Normal file
58
OpenRA.Mods.RA/Warheads/LeaveSmudgeWarhead.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user