Files
OpenRA/OpenRA.Mods.Common/Traits/ThrowsShrapnel.cs
Raffael Zica f2b5040d30 YamlException is now thrown if WeaponInfo can not be found in Ruleset.Weapons
Removed invalid spacing at the end of the line 36 in ThrowsShrapnel

Prevented NullReferenceException in cases where weapons aren't optional
2017-10-14 14:12:08 +02:00

103 lines
3.2 KiB
C#

#region Copyright & License Information
/*
* Copyright 2007-2017 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, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System.Linq;
using OpenRA.GameRules;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
[Desc("Throws particles when the actor is destroyed that do damage on impact.")]
public class ThrowsShrapnelInfo : ITraitInfo, IRulesetLoaded
{
[WeaponReference, FieldLoader.Require]
[Desc("The weapons used for shrapnel.")]
public readonly string[] Weapons = { };
[Desc("The amount of pieces of shrapnel to expel. Two values indicate a range.")]
public readonly int[] Pieces = { 3, 10 };
[Desc("The minimum and maximum distances the shrapnel may travel.")]
public readonly WDist[] Range = { WDist.FromCells(2), WDist.FromCells(5) };
public WeaponInfo[] WeaponInfos { get; private set; }
public object Create(ActorInitializer actor) { return new ThrowsShrapnel(this); }
public void RulesetLoaded(Ruleset rules, ActorInfo ai)
{
WeaponInfos = Weapons.Select(w =>
{
WeaponInfo weapon;
var weaponToLower = w.ToLowerInvariant();
if (!rules.Weapons.TryGetValue(weaponToLower, out weapon))
throw new YamlException("Weapons Ruleset does not contain an entry '{0}'".F(weaponToLower));
return weapon;
}).ToArray();
}
}
class ThrowsShrapnel : INotifyKilled
{
readonly ThrowsShrapnelInfo info;
public ThrowsShrapnel(ThrowsShrapnelInfo info)
{
this.info = info;
}
public void Killed(Actor self, AttackInfo attack)
{
foreach (var wep in info.WeaponInfos)
{
var pieces = self.World.SharedRandom.Next(info.Pieces[0], info.Pieces[1]);
var range = self.World.SharedRandom.Next(info.Range[0].Length, info.Range[1].Length);
for (var i = 0; pieces > i; i++)
{
var rotation = WRot.FromFacing(self.World.SharedRandom.Next(1024));
var args = new ProjectileArgs
{
Weapon = wep,
Facing = self.World.SharedRandom.Next(-1, 255),
DamageModifiers = self.TraitsImplementing<IFirepowerModifier>()
.Select(a => a.GetFirepowerModifier()).ToArray(),
InaccuracyModifiers = self.TraitsImplementing<IInaccuracyModifier>()
.Select(a => a.GetInaccuracyModifier()).ToArray(),
RangeModifiers = self.TraitsImplementing<IRangeModifier>()
.Select(a => a.GetRangeModifier()).ToArray(),
Source = self.CenterPosition,
CurrentSource = () => self.CenterPosition,
SourceActor = self,
PassiveTarget = self.CenterPosition + new WVec(range, 0, 0).Rotate(rotation)
};
self.World.AddFrameEndTask(x =>
{
if (args.Weapon.Projectile != null)
{
var projectile = args.Weapon.Projectile.Create(args);
if (projectile != null)
self.World.Add(projectile);
if (args.Weapon.Report != null && args.Weapon.Report.Any())
Game.Sound.Play(SoundType.World, args.Weapon.Report.Random(self.World.SharedRandom), self.CenterPosition);
}
});
}
}
}
}
}