diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index faf8a1449f..b543fbf5ca 100755 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -124,7 +124,6 @@ namespace OpenRA.Traits } } - public interface INotifyAttack { void Attacking(Actor self, Target target); } public interface IRenderModifier { IEnumerable ModifyRender(Actor self, WorldRenderer wr, IEnumerable r); } public interface IDamageModifier { float GetDamageModifier(Actor attacker, WarheadInfo warhead); } public interface ISpeedModifier { decimal GetSpeedModifier(); } diff --git a/OpenRA.Mods.RA/Activities/LayMines.cs b/OpenRA.Mods.RA/Activities/LayMines.cs index 777bcd7671..1cd5bfbeda 100644 --- a/OpenRA.Mods.RA/Activities/LayMines.cs +++ b/OpenRA.Mods.RA/Activities/LayMines.cs @@ -74,7 +74,8 @@ namespace OpenRA.Mods.RA.Activities void LayMine(Actor self) { var limitedAmmo = self.TraitOrDefault(); - if (limitedAmmo != null) limitedAmmo.Attacking(self, Target.FromCell(self.Location)); + if (limitedAmmo != null) + limitedAmmo.TakeAmmo(); self.World.AddFrameEndTask( w => w.CreateActor(self.Info.Traits.Get().Mine, new TypeDictionary diff --git a/OpenRA.Mods.RA/Armament.cs b/OpenRA.Mods.RA/Armament.cs index 5e3c018146..b888a08757 100755 --- a/OpenRA.Mods.RA/Armament.cs +++ b/OpenRA.Mods.RA/Armament.cs @@ -151,7 +151,7 @@ namespace OpenRA.Mods.RA }); foreach (var na in self.TraitsImplementing()) - na.Attacking(self, target); + na.Attacking(self, target, this, barrel); Recoil = Info.Recoil; diff --git a/OpenRA.Mods.RA/Attack/AttackTesla.cs b/OpenRA.Mods.RA/Attack/AttackTesla.cs index fe0ae52b9c..034fc66dcf 100644 --- a/OpenRA.Mods.RA/Attack/AttackTesla.cs +++ b/OpenRA.Mods.RA/Attack/AttackTesla.cs @@ -40,7 +40,7 @@ namespace OpenRA.Mods.RA base.Tick( self ); } - public void Attacking(Actor self, Target target) + public void Attacking(Actor self, Target target, Armament a, Barrel barrel) { --charges; timeToRecharge = self.Info.Traits.Get().ReloadTime; diff --git a/OpenRA.Mods.RA/Cloak.cs b/OpenRA.Mods.RA/Cloak.cs index 6e6a08f6a9..e2dc8ccc3d 100644 --- a/OpenRA.Mods.RA/Cloak.cs +++ b/OpenRA.Mods.RA/Cloak.cs @@ -56,7 +56,7 @@ namespace OpenRA.Mods.RA remainingTime = Math.Max(remainingTime, time); } - public void Attacking(Actor self, Target target) { Uncloak(); } + public void Attacking(Actor self, Target target, Armament a, Barrel barrel) { Uncloak(); } public bool Cloaked { get { return remainingTime <= 0; } } diff --git a/OpenRA.Mods.RA/LimitedAmmo.cs b/OpenRA.Mods.RA/LimitedAmmo.cs index da5dee09ce..2444163c1e 100644 --- a/OpenRA.Mods.RA/LimitedAmmo.cs +++ b/OpenRA.Mods.RA/LimitedAmmo.cs @@ -44,6 +44,7 @@ namespace OpenRA.Mods.RA ++ammo; return true; } + public bool TakeAmmo() { if (ammo <= 0) return false; @@ -53,7 +54,7 @@ namespace OpenRA.Mods.RA public int ReloadTimePerAmmo() { return Info.ReloadTicks; } - public void Attacking(Actor self, Target target) { TakeAmmo(); } + public void Attacking(Actor self, Target target, Armament a, Barrel barrel) { TakeAmmo(); } public IEnumerable GetPips(Actor self) { diff --git a/OpenRA.Mods.RA/Render/RenderInfantry.cs b/OpenRA.Mods.RA/Render/RenderInfantry.cs index 542811b779..529d93c3bb 100644 --- a/OpenRA.Mods.RA/Render/RenderInfantry.cs +++ b/OpenRA.Mods.RA/Render/RenderInfantry.cs @@ -74,6 +74,11 @@ namespace OpenRA.Mods.RA.Render anim.PlayThen(NormalizeInfantrySequence(self, "heal"), () => State = AnimationState.Idle); } + public void Attacking(Actor self, Target target, Armament a, Barrel barrel) + { + Attacking(self, target); + } + public override void Tick(Actor self) { base.Tick(self); diff --git a/OpenRA.Mods.RA/Render/WithMuzzleFlash.cs b/OpenRA.Mods.RA/Render/WithMuzzleFlash.cs index f7945d75ac..91bcc97833 100644 --- a/OpenRA.Mods.RA/Render/WithMuzzleFlash.cs +++ b/OpenRA.Mods.RA/Render/WithMuzzleFlash.cs @@ -11,69 +11,84 @@ using System; using System.Collections.Generic; using System.Linq; +using OpenRA.FileFormats; using OpenRA.Graphics; using OpenRA.Traits; using OpenRA.Mods.RA; namespace OpenRA.Mods.RA.Render { - class WithMuzzleFlashInfo : ITraitInfo, Requires, Requires + class WithMuzzleFlashInfo : ITraitInfo, Requires, Requires, Requires { - public object Create(ActorInitializer init) { return new WithMuzzleFlash(init.self); } + [Desc("Sequence name to use")] + public readonly string Sequence = "muzzle"; + + [Desc("Armament name")] + public readonly string Armament = "primary"; + + public object Create(ActorInitializer init) { return new WithMuzzleFlash(init.self, this); } } class WithMuzzleFlash : INotifyAttack, IRender, ITick { - Dictionary muzzleFlashes = new Dictionary(); - bool isShowing; + readonly WithMuzzleFlashInfo info; + Dictionary visible = new Dictionary(); + Dictionary anims = new Dictionary(); - public WithMuzzleFlash(Actor self) + public WithMuzzleFlash(Actor self, WithMuzzleFlashInfo info) { + this.info = info; var render = self.Trait(); var facing = self.TraitOrDefault(); - var arms = self.TraitsImplementing(); - foreach (var a in arms) - foreach(var b in a.Barrels) - { - var barrel = b; - var turreted = self.TraitsImplementing() - .FirstOrDefault(t => t.Name == a.Info.Turret); - var getFacing = turreted != null ? () => turreted.turretFacing : - facing != null ? (Func)(() => facing.Facing) : () => 0; + var arm = self.TraitsImplementing() + .Single(a => a.Info.Name == info.Armament); - var muzzleFlash = new Animation(render.GetImage(self), getFacing); - muzzleFlash.Play("muzzle"); + foreach (var b in arm.Barrels) + { + var barrel = b; + var turreted = self.TraitsImplementing() + .FirstOrDefault(t => t.Name == arm.Info.Turret); - muzzleFlashes.Add("muzzle{0}".F(muzzleFlashes.Count), - new AnimationWithOffset(muzzleFlash, - () => a.MuzzleOffset(self, barrel), - () => !isShowing)); - } + var getFacing = turreted != null ? () => turreted.turretFacing : + facing != null ? (Func)(() => facing.Facing) : () => 0; + + var muzzleFlash = new Animation(render.GetImage(self), getFacing); + visible.Add(barrel, false); + anims.Add(barrel, + new AnimationWithOffset(muzzleFlash, + () => arm.MuzzleOffset(self, barrel), + () => !visible[barrel])); + } } - public void Attacking(Actor self, Target target) + public void Attacking(Actor self, Target target, Armament a, Barrel barrel) { - isShowing = true; - foreach( var mf in muzzleFlashes.Values ) - mf.Animation.PlayThen("muzzle", () => isShowing = false); + if (a.Info.Name != info.Armament) + return; + + visible[barrel] = true; + anims[barrel].Animation.PlayThen(info.Sequence, () => visible[barrel] = false); } public IEnumerable Render(Actor self, WorldRenderer wr) { - foreach (var a in muzzleFlashes.Values) + foreach (var kv in anims) { - if (a.DisableFunc != null && a.DisableFunc()) + if (!visible[kv.Key]) continue; - foreach (var r in a.Render(self, wr, wr.Palette("effect"), 1f)) + if (kv.Value.DisableFunc != null && kv.Value.DisableFunc()) + continue; + + foreach (var r in kv.Value.Render(self, wr, wr.Palette("effect"), 1f)) yield return r; } } public void Tick(Actor self) { - foreach (var a in muzzleFlashes.Values) + foreach (var a in anims.Values) a.Animation.Tick(); } } diff --git a/OpenRA.Mods.RA/ScaredyCat.cs b/OpenRA.Mods.RA/ScaredyCat.cs index 2696e6c637..33a536c1dc 100644 --- a/OpenRA.Mods.RA/ScaredyCat.cs +++ b/OpenRA.Mods.RA/ScaredyCat.cs @@ -67,7 +67,7 @@ namespace OpenRA.Mods.RA Panic(); } - public void Attacking(Actor self, Target target) + public void Attacking(Actor self, Target target, Armament a, Barrel barrel) { if (self.World.SharedRandom.Next(100 / Info.AttackPanicChance) == 0) Panic(); diff --git a/OpenRA.Mods.RA/Spy.cs b/OpenRA.Mods.RA/Spy.cs index 883c31c34d..7b7553ae60 100644 --- a/OpenRA.Mods.RA/Spy.cs +++ b/OpenRA.Mods.RA/Spy.cs @@ -137,7 +137,7 @@ namespace OpenRA.Mods.RA } /* lose our disguise if we attack anything */ - public void Attacking(Actor self, Target target) { DropDisguise(); } + public void Attacking(Actor self, Target target, Armament a, Barrel barrel) { DropDisguise(); } } class IgnoresDisguiseInfo : TraitInfo {} diff --git a/OpenRA.Mods.RA/TraitsInterfaces.cs b/OpenRA.Mods.RA/TraitsInterfaces.cs index b672a11345..3a0db48bc9 100755 --- a/OpenRA.Mods.RA/TraitsInterfaces.cs +++ b/OpenRA.Mods.RA/TraitsInterfaces.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using OpenRA.Mods.RA.Activities; +using OpenRA.Traits; namespace OpenRA.Mods.RA { @@ -46,4 +47,5 @@ namespace OpenRA.Mods.RA public interface INotifyParachuteLanded { void OnLanded(); } public interface INotifyTransform { void OnTransform(Actor self); } public interface INotifyTransformed { void OnTransformed(Actor toActor); } + public interface INotifyAttack { void Attacking(Actor self, Target target, Armament a, Barrel barrel); } } diff --git a/mods/cnc/rules/aircraft.yaml b/mods/cnc/rules/aircraft.yaml index b2f3e7c779..49fd8db64c 100644 --- a/mods/cnc/rules/aircraft.yaml +++ b/mods/cnc/rules/aircraft.yaml @@ -69,6 +69,7 @@ HELI: Weapon: HeliAGGun LocalOffset: 128,-213,-85, 128,213,-85 Armament@SECONDARY: + Name: secondary Weapon: HeliAAGun LocalOffset: 128,-213,-85, 128,213,-85 AttackHeli: @@ -82,7 +83,9 @@ HELI: RenderUnit: WithRotor: Offset: 0,0,85 - WithMuzzleFlash: + WithMuzzleFlash@PRIMARY: + WithMuzzleFlash@SECONDARY: + Armament: secondary WithShadow: LeavesHusk: HuskActor: HELI.Husk diff --git a/mods/cnc/rules/vehicles.yaml b/mods/cnc/rules/vehicles.yaml index 82743f763a..da0d043cd9 100644 --- a/mods/cnc/rules/vehicles.yaml +++ b/mods/cnc/rules/vehicles.yaml @@ -106,12 +106,15 @@ APC: RecoilRecovery: 18 LocalOffset: 85,85,299, 85,-85,299 Armament@SECONDARY: + Name: secondary Weapon: APCGun.AA Recoil: 96 RecoilRecovery: 18 LocalOffset: 85,85,299, 85,-85,299 AttackTurreted: - WithMuzzleFlash: + WithMuzzleFlash@PRIMARY: + WithMuzzleFlash@SECONDARY: + Armament: secondary RenderUnit: WithTurret: AutoTarget: @@ -404,6 +407,7 @@ HTNK: Recoil: 170 RecoilRecovery: 42 Armament@SECONDARY: + Name: secondary Weapon: MammothMissiles LocalOffset: -85, 384, 340, -85, -384, 340 LocalYaw: -100, 100 diff --git a/mods/ra/maps/drop-zone-w/map.yaml b/mods/ra/maps/drop-zone-w/map.yaml index 393027a6e5..0aee39dc1d 100644 --- a/mods/ra/maps/drop-zone-w/map.yaml +++ b/mods/ra/maps/drop-zone-w/map.yaml @@ -248,9 +248,12 @@ Rules: Armament@PRIMARY: Weapon:M60mg Armament@SECONDARY: + Name: secondary Weapon:M60mg AttackFrontal: - WithMuzzleFlash: + WithMuzzleFlash@PRIMARY: + WithMuzzleFlash@SECONDARY: + Armament: secondary MustBeDestroyed: -GivesBounty: PT: diff --git a/mods/ra/rules/aircraft.yaml b/mods/ra/rules/aircraft.yaml index 80ecedea64..94e827516d 100644 --- a/mods/ra/rules/aircraft.yaml +++ b/mods/ra/rules/aircraft.yaml @@ -145,6 +145,7 @@ YAK: Weapon: ChainGun.Yak LocalOffset: 256,-213,0 Armament@SECONDARY: + Name: secondary Weapon: ChainGun.Yak LocalOffset: 256,213,0 AttackPlane: @@ -163,7 +164,9 @@ YAK: ReloadTicks: 11 IronCurtainable: ReturnOnIdle: - WithMuzzleFlash: + WithMuzzleFlash@PRIMARY: + WithMuzzleFlash@SECONDARY: + Armament: secondary Contrail: Offset: -853,0,0 LeavesHusk: @@ -294,6 +297,7 @@ HIND: Weapon: ChainGun LocalOffset: 85,-213,-85 Armament@SECONDARY: + Name: secondary Weapon: ChainGun LocalOffset: 85,213,-85 AttackHeli: @@ -314,7 +318,9 @@ HIND: IronCurtainable: Selectable: Bounds: 38,32,0,0 - WithMuzzleFlash: + WithMuzzleFlash@PRIMARY: + WithMuzzleFlash@SECONDARY: + Armament: secondary LeavesHusk: HuskActor: HIND.Husk SmokeTrailWhenDamaged: