1 #region Copyright & License Information 2 /* 3 * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) 4 * This file is part of OpenRA, which is free software. It is made 5 * available to you under the terms of the GNU General Public License 6 * as published by the Free Software Foundation, either version 3 of 7 * the License, or (at your option) any later version. For more 8 * information, see COPYING. 9 */ 10 #endregion 11 12 using System.Linq; 13 using OpenRA.GameRules; 14 using OpenRA.Traits; 15 16 namespace OpenRA.Mods.Common.Traits 17 { 18 [Desc("Throws particles when the actor is destroyed that do damage on impact.")] 19 public class ThrowsShrapnelInfo : ConditionalTraitInfo, IRulesetLoaded 20 { 21 [WeaponReference] 22 [FieldLoader.Require] 23 [Desc("The weapons used for shrapnel.")] 24 public readonly string[] Weapons = { }; 25 26 [Desc("The amount of pieces of shrapnel to expel. Two values indicate a range.")] 27 public readonly int[] Pieces = { 3, 10 }; 28 29 [Desc("The minimum and maximum distances the shrapnel may travel.")] 30 public readonly WDist[] Range = { WDist.FromCells(2), WDist.FromCells(5) }; 31 32 public WeaponInfo[] WeaponInfos { get; private set; } 33 Create(ActorInitializer actor)34 public override object Create(ActorInitializer actor) { return new ThrowsShrapnel(this); } RulesetLoaded(Ruleset rules, ActorInfo ai)35 public override void RulesetLoaded(Ruleset rules, ActorInfo ai) 36 { 37 base.RulesetLoaded(rules, ai); 38 39 WeaponInfos = Weapons.Select(w => 40 { 41 WeaponInfo weapon; 42 var weaponToLower = w.ToLowerInvariant(); 43 if (!rules.Weapons.TryGetValue(weaponToLower, out weapon)) 44 throw new YamlException("Weapons Ruleset does not contain an entry '{0}'".F(weaponToLower)); 45 return weapon; 46 }).ToArray(); 47 } 48 } 49 50 class ThrowsShrapnel : ConditionalTrait<ThrowsShrapnelInfo>, INotifyKilled 51 { ThrowsShrapnel(ThrowsShrapnelInfo info)52 public ThrowsShrapnel(ThrowsShrapnelInfo info) 53 : base(info) { } 54 Killed(Actor self, AttackInfo attack)55 public void Killed(Actor self, AttackInfo attack) 56 { 57 if (IsTraitDisabled) 58 return; 59 60 foreach (var wep in Info.WeaponInfos) 61 { 62 var pieces = self.World.SharedRandom.Next(Info.Pieces[0], Info.Pieces[1]); 63 var range = self.World.SharedRandom.Next(Info.Range[0].Length, Info.Range[1].Length); 64 65 for (var i = 0; pieces > i; i++) 66 { 67 var rotation = WRot.FromFacing(self.World.SharedRandom.Next(1024)); 68 var args = new ProjectileArgs 69 { 70 Weapon = wep, 71 Facing = self.World.SharedRandom.Next(-1, 255), 72 CurrentMuzzleFacing = () => 0, 73 74 DamageModifiers = self.TraitsImplementing<IFirepowerModifier>() 75 .Select(a => a.GetFirepowerModifier()).ToArray(), 76 77 InaccuracyModifiers = self.TraitsImplementing<IInaccuracyModifier>() 78 .Select(a => a.GetInaccuracyModifier()).ToArray(), 79 80 RangeModifiers = self.TraitsImplementing<IRangeModifier>() 81 .Select(a => a.GetRangeModifier()).ToArray(), 82 83 Source = self.CenterPosition, 84 CurrentSource = () => self.CenterPosition, 85 SourceActor = self, 86 PassiveTarget = self.CenterPosition + new WVec(range, 0, 0).Rotate(rotation) 87 }; 88 89 self.World.AddFrameEndTask(x => 90 { 91 if (args.Weapon.Projectile != null) 92 { 93 var projectile = args.Weapon.Projectile.Create(args); 94 if (projectile != null) 95 self.World.Add(projectile); 96 97 if (args.Weapon.Report != null && args.Weapon.Report.Any()) 98 Game.Sound.Play(SoundType.World, args.Weapon.Report, self.World, self.CenterPosition); 99 } 100 }); 101 } 102 } 103 } 104 } 105 } 106