From 0167bbfbaaf4a951c952b7ea5a434c08189a2160 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Thu, 14 Mar 2013 03:55:34 +1300 Subject: [PATCH] Move weapon/turret definitions out of AttackBase. Weapons are now defined with the Armament trait and turret parameters live in Turreted. This has the side effect of allowing any number and distribution of weapons and turrets. --- OpenRA.Mods.Cnc/RenderGunboat.cs | 3 +- OpenRA.Mods.RA/AI/AttackOrFleeFuzzy.cs | 7 +- OpenRA.Mods.RA/AI/HackyAI.cs | 14 +- OpenRA.Mods.RA/Armament.cs | 198 +++ OpenRA.Mods.RA/Attack/AttackBase.cs | 83 +- OpenRA.Mods.RA/Attack/AttackFrontal.cs | 6 +- OpenRA.Mods.RA/Attack/AttackLeap.cs | 18 +- OpenRA.Mods.RA/Attack/AttackLoyalty.cs | 15 +- OpenRA.Mods.RA/Attack/AttackMedic.cs | 6 +- OpenRA.Mods.RA/Attack/AttackPopupTurreted.cs | 3 + OpenRA.Mods.RA/Attack/AttackTurreted.cs | 16 +- OpenRA.Mods.RA/Combat.cs | 42 - OpenRA.Mods.RA/Effects/Contrail.cs | 2 +- OpenRA.Mods.RA/LeavesHusk.cs | 4 +- OpenRA.Mods.RA/OpenRA.Mods.RA.csproj | 2 +- .../Render/RenderBuildingSeparateTurret.cs | 20 +- .../Render/RenderBuildingTurreted.cs | 4 +- OpenRA.Mods.RA/Render/RenderUnitSpinner.cs | 3 +- OpenRA.Mods.RA/Render/RenderUnitTurreted.cs | 34 +- OpenRA.Mods.RA/Render/WithMuzzleFlash.cs | 20 +- OpenRA.Mods.RA/Render/WithRotor.cs | 3 +- OpenRA.Mods.RA/RenderRangeCircle.cs | 11 +- OpenRA.Mods.RA/SmokeTrailWhenDamaged.cs | 2 +- OpenRA.Mods.RA/TakeCover.cs | 41 +- OpenRA.Mods.RA/ThrowsParticle.cs | 2 +- OpenRA.Mods.RA/Turreted.cs | 52 +- OpenRA.Mods.RA/Weapon.cs | 162 --- mods/cnc-classic/rules/aircraft.yaml | 12 +- mods/cnc-classic/rules/civilian.yaml | 3 +- mods/cnc-classic/rules/defaults.yaml | 3 +- mods/cnc-classic/rules/infantry.yaml | 34 +- mods/cnc-classic/rules/ships.yaml | 7 +- mods/cnc-classic/rules/structures.yaml | 33 +- mods/cnc-classic/rules/vehicles.yaml | 94 +- mods/cnc/rules/aircraft.yaml | 24 +- mods/cnc/rules/civilian.yaml | 3 +- mods/cnc/rules/defaults.yaml | 5 +- mods/cnc/rules/infantry.yaml | 34 +- mods/cnc/rules/ships.yaml | 7 +- mods/cnc/rules/structures.yaml | 27 +- mods/cnc/rules/vehicles.yaml | 99 +- mods/d2k/rules/aircraft.yaml | 5 +- mods/d2k/rules/atreides.yaml | 17 +- mods/d2k/rules/harkonnen.yaml | 18 +- mods/d2k/rules/infantry.yaml | 15 +- mods/d2k/rules/ordos.yaml | 11 +- mods/d2k/rules/structures.yaml | 10 +- mods/d2k/rules/system.yaml | 3 +- mods/d2k/rules/vehicles.yaml | 36 +- mods/ra-classic/rules/aircraft.yaml | 30 +- mods/ra-classic/rules/defaults.yaml | 3 +- mods/ra-classic/rules/infantry.yaml | 46 +- mods/ra-classic/rules/ships.yaml | 61 +- mods/ra-classic/rules/structures.yaml | 34 +- mods/ra-classic/rules/vehicles.yaml | 68 +- mods/ra/maps/bomber-john.oramap | Bin 6889 -> 0 bytes mods/ra/maps/bomber-john/brick.shp | Bin 0 -> 86 bytes mods/ra/maps/bomber-john/jmin.shp | Bin 0 -> 2535 bytes mods/ra/maps/bomber-john/map.bin | Bin 0 -> 15685 bytes mods/ra/maps/bomber-john/map.yaml | 959 ++++++++++++++ mods/ra/maps/bomber-john/miner.shp | Bin 0 -> 4668 bytes .../maps/drop-zone-battle-of-tikiaki.oramap | Bin 3124 -> 0 bytes .../maps/drop-zone-battle-of-tikiaki/map.bin | Bin 0 -> 20485 bytes .../maps/drop-zone-battle-of-tikiaki/map.yaml | 341 +++++ mods/ra/maps/drop-zone-w.oramap | Bin 2873 -> 0 bytes mods/ra/maps/drop-zone-w/map.bin | Bin 0 -> 20485 bytes mods/ra/maps/drop-zone-w/map.yaml | 333 +++++ mods/ra/maps/drop-zone.oramap | Bin 2614 -> 0 bytes mods/ra/maps/drop-zone/map.bin | Bin 0 -> 20485 bytes mods/ra/maps/drop-zone/map.yaml | 236 ++++ mods/ra/maps/monster-tank-madness/map.yaml | 15 +- mods/ra/maps/training-camp.oramap | Bin 4315 -> 0 bytes mods/ra/maps/training-camp/map.bin | Bin 0 -> 20485 bytes mods/ra/maps/training-camp/map.yaml | 1121 +++++++++++++++++ mods/ra/rules/aircraft.yaml | 35 +- mods/ra/rules/civilian.yaml | 5 +- mods/ra/rules/defaults.yaml | 3 +- mods/ra/rules/infantry.yaml | 59 +- mods/ra/rules/ships.yaml | 60 +- mods/ra/rules/structures.yaml | 84 +- mods/ra/rules/vehicles.yaml | 77 +- 81 files changed, 4023 insertions(+), 820 deletions(-) create mode 100755 OpenRA.Mods.RA/Armament.cs delete mode 100644 OpenRA.Mods.RA/Weapon.cs delete mode 100644 mods/ra/maps/bomber-john.oramap create mode 100755 mods/ra/maps/bomber-john/brick.shp create mode 100755 mods/ra/maps/bomber-john/jmin.shp create mode 100755 mods/ra/maps/bomber-john/map.bin create mode 100755 mods/ra/maps/bomber-john/map.yaml create mode 100755 mods/ra/maps/bomber-john/miner.shp delete mode 100644 mods/ra/maps/drop-zone-battle-of-tikiaki.oramap create mode 100755 mods/ra/maps/drop-zone-battle-of-tikiaki/map.bin create mode 100755 mods/ra/maps/drop-zone-battle-of-tikiaki/map.yaml delete mode 100644 mods/ra/maps/drop-zone-w.oramap create mode 100755 mods/ra/maps/drop-zone-w/map.bin create mode 100755 mods/ra/maps/drop-zone-w/map.yaml delete mode 100644 mods/ra/maps/drop-zone.oramap create mode 100755 mods/ra/maps/drop-zone/map.bin create mode 100755 mods/ra/maps/drop-zone/map.yaml delete mode 100644 mods/ra/maps/training-camp.oramap create mode 100755 mods/ra/maps/training-camp/map.bin create mode 100755 mods/ra/maps/training-camp/map.yaml diff --git a/OpenRA.Mods.Cnc/RenderGunboat.cs b/OpenRA.Mods.Cnc/RenderGunboat.cs index c11c5ab13e..708d29a405 100644 --- a/OpenRA.Mods.Cnc/RenderGunboat.cs +++ b/OpenRA.Mods.Cnc/RenderGunboat.cs @@ -9,6 +9,7 @@ #endregion using System; +using System.Linq; using OpenRA.Graphics; using OpenRA.Traits; @@ -26,7 +27,7 @@ namespace OpenRA.Mods.RA.Render string lastDamage = ""; public RenderGunboat(Actor self) - : base(self, () => self.HasTrait() ? self.Trait().turretFacing : 0) + : base(self, () => self.HasTrait() ? self.TraitsImplementing().First().turretFacing : 0) { facing = self.Trait(); anim.Play("left"); diff --git a/OpenRA.Mods.RA/AI/AttackOrFleeFuzzy.cs b/OpenRA.Mods.RA/AI/AttackOrFleeFuzzy.cs index 4aabf6d32f..3f6786bb5c 100644 --- a/OpenRA.Mods.RA/AI/AttackOrFleeFuzzy.cs +++ b/OpenRA.Mods.RA/AI/AttackOrFleeFuzzy.cs @@ -200,9 +200,10 @@ namespace OpenRA.Mods.RA.AI return RelativeValue(own, enemy, 100, SumOfValues, (Actor a) => { int sumOfDamage = 0; - foreach (var weap in a.Trait().Weapons) - if (weap.Info.Warheads[0] != null) - sumOfDamage += weap.Info.Warheads[0].Damage; + var arms = a.TraitsImplementing(); + foreach (var arm in arms) + if (arm.Weapon.Warheads[0] != null) + sumOfDamage += arm.Weapon.Warheads[0].Damage; return sumOfDamage; }); } diff --git a/OpenRA.Mods.RA/AI/HackyAI.cs b/OpenRA.Mods.RA/AI/HackyAI.cs index f2b6cfe53b..75b85cad2f 100644 --- a/OpenRA.Mods.RA/AI/HackyAI.cs +++ b/OpenRA.Mods.RA/AI/HackyAI.cs @@ -230,12 +230,13 @@ namespace OpenRA.Mods.RA.AI if (!target.HasTrait>() && !target.HasTrait()) return false; - foreach (var weap in a.Trait().Weapons) + var arms = a.TraitsImplementing(); + foreach (var arm in arms) if (target.HasTrait>() && - weap.Info.ValidTargets.Intersect(target.Trait>().TargetTypes) != null) + arm.Weapon.ValidTargets.Intersect(target.Trait>().TargetTypes) != null) return true; else if (target.HasTrait() && - weap.Info.ValidTargets.Intersect(target.Trait().TargetTypes) != null) + arm.Weapon.ValidTargets.Intersect(target.Trait().TargetTypes) != null) return true; return false; } @@ -253,12 +254,15 @@ namespace OpenRA.Mods.RA.AI foreach (var unit in units) if (unit != null && unit.HasTrait() && !unit.HasTrait() && !unit.IsDisabled()) - foreach (var weap in unit.Trait().Weapons) - if (weap.Info.ValidTargets.Contains("Air")) + { + var arms = unit.TraitsImplementing(); + foreach (var a in arms) + if (a.Weapon.ValidTargets.Contains("Air")) { missileUnitsCount++; break; } + } return missileUnitsCount; } diff --git a/OpenRA.Mods.RA/Armament.cs b/OpenRA.Mods.RA/Armament.cs new file mode 100755 index 0000000000..a6d9f168df --- /dev/null +++ b/OpenRA.Mods.RA/Armament.cs @@ -0,0 +1,198 @@ +#region Copyright & License Information +/* + * Copyright 2007-2011 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.FileFormats; +using OpenRA.GameRules; +using OpenRA.Mods.RA.Render; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class Barrel + { + public PVecInt TurretSpaceOffset; // position in turret space + public PVecInt ScreenSpaceOffset; // screen-space hack to make things line up good. + public int Facing; // deviation from turret facing + } + + public class ArmamentInfo : ITraitInfo, Requires + { + [WeaponReference] + [Desc("Has to be defined here and in weapons.yaml.")] + public readonly string Weapon = null; + public readonly string Turret = "primary"; + public readonly int Recoil = 0; + public readonly int FireDelay = 0; + + public readonly float RecoilRecovery = 0.2f; + public readonly int[] LocalOffset = { }; + + public object Create(ActorInitializer init) { return new Armament(init.self, this); } + } + + public class Armament : ITick + { + public readonly ArmamentInfo Info; + public readonly WeaponInfo Weapon; + public readonly Barrel[] Barrels; + Lazy Turret; + + public float Recoil { get; private set; } + public int FireDelay { get; private set; } + public int Burst { get; private set; } + + public Armament(Actor self, ArmamentInfo info) + { + Info = info; + + // We can't soft-depend on TraitInfo, so we have to wait + // until runtime to cache this + Turret = Lazy.New(() => self.TraitsImplementing().FirstOrDefault(t => t.info.Turret == info.Turret)); + + Weapon = Rules.Weapons[info.Weapon.ToLowerInvariant()]; + Burst = Weapon.Burst; + + var barrels = new List(); + for (var i = 0; i < info.LocalOffset.Length / 5; i++) + barrels.Add(new Barrel + { + TurretSpaceOffset = new PVecInt(info.LocalOffset[5 * i], info.LocalOffset[5 * i + 1]), + ScreenSpaceOffset = new PVecInt(info.LocalOffset[5 * i + 2], info.LocalOffset[5 * i + 3]), + Facing = info.LocalOffset[5 * i + 4], + }); + + // if no barrels specified, the default is "turret position; turret facing". + if (barrels.Count == 0) + barrels.Add(new Barrel { TurretSpaceOffset = PVecInt.Zero, ScreenSpaceOffset = PVecInt.Zero, Facing = 0 }); + + Barrels = barrels.ToArray(); + } + + public void Tick(Actor self) + { + if (FireDelay > 0) + --FireDelay; + Recoil = Math.Max(0f, Recoil - Info.RecoilRecovery); + } + + public void CheckFire(Actor self, AttackBase attack, IMove move, IFacing facing, Target target) + { + if (FireDelay > 0) return; + + var limitedAmmo = self.TraitOrDefault(); + if (limitedAmmo != null && !limitedAmmo.HasAmmo()) + return; + + if (!Combat.IsInRange(self.CenterLocation, Weapon.Range, target)) return; + if (Combat.IsInRange(self.CenterLocation, Weapon.MinRange, target)) return; + if (!IsValidAgainst(self.World, target)) return; + + var barrel = Barrels[Burst % Barrels.Length]; + var destMove = target.IsActor ? target.Actor.TraitOrDefault() : null; + + var args = new ProjectileArgs + { + weapon = Weapon, + firedBy = self, + target = target, + + src = (self.CenterLocation + (PVecInt)MuzzlePxPosition(self, facing, barrel).ToInt2()), + srcAltitude = move != null ? move.Altitude : 0, + dest = target.CenterLocation, + destAltitude = destMove != null ? destMove.Altitude : 0, + + facing = barrel.Facing + + (Turret.Value != null ? Turret.Value.turretFacing : + facing != null ? facing.Facing : Util.GetFacing(target.CenterLocation - self.CenterLocation, 0)), + + firepowerModifier = self.TraitsImplementing() + .Select(a => a.GetFirepowerModifier()) + .Product() + }; + + attack.ScheduleDelayedAction(Info.FireDelay, () => + { + 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()) + Sound.Play(args.weapon.Report.Random(self.World.SharedRandom) + ".aud", self.CenterLocation); + } + }); + + foreach (var na in self.TraitsImplementing()) + na.Attacking(self, target); + + Recoil = Info.Recoil; + + if (--Burst > 0) + FireDelay = Weapon.BurstDelay; + else + { + FireDelay = Weapon.ROF; + Burst = Weapon.Burst; + } + } + + public bool IsValidAgainst(World world, Target target) + { + if (target.IsActor) + return Combat.WeaponValidForTarget(Weapon, target.Actor); + else + return Combat.WeaponValidForTarget(Weapon, world, target.CenterLocation.ToCPos()); + } + + public bool IsReloading { get { return FireDelay > 0; } } + + PVecFloat GetUnitspaceBarrelOffset(Actor self, IFacing facing, Barrel b) + { + if (Turret.Value == null && facing == null) + return PVecFloat.Zero; + + var turretFacing = Turret.Value != null ? Turret.Value.turretFacing : facing.Facing; + return (PVecFloat)Util.RotateVectorByFacing(b.TurretSpaceOffset.ToFloat2(), turretFacing, .7f); + } + + public PVecFloat MuzzlePxPosition(Actor self, IFacing facing, Barrel b) + { + PVecFloat pos = b.ScreenSpaceOffset; + + // local facing offset doesn't make sense for actors that don't rotate + if (Turret.Value == null && facing == null) + return pos; + + if (Turret.Value != null) + pos += Turret.Value.PxPosition(self, facing); + + // Add local unitspace/turretspace offset + var f = Turret.Value != null ? Turret.Value.turretFacing : facing.Facing; + + // This is going away, so no point adding unnecessary usings + var ru = self.TraitOrDefault(); + var numDirs = (ru != null) ? ru.anim.CurrentSequence.Facings : 8; + var quantizedFacing = Util.QuantizeFacing(f, numDirs) * (256 / numDirs); + + pos += (PVecFloat)Util.RotateVectorByFacing(b.TurretSpaceOffset.ToFloat2(), quantizedFacing, .7f); + return pos; + } + + public PVecFloat RecoilPxOffset(Actor self, int facing) + { + var localRecoil = new float2(0, Recoil); + return (PVecFloat)Util.RotateVectorByFacing(localRecoil, facing, .7f); + } + } +} diff --git a/OpenRA.Mods.RA/Attack/AttackBase.cs b/OpenRA.Mods.RA/Attack/AttackBase.cs index 399f5af28c..2b47bd84ea 100644 --- a/OpenRA.Mods.RA/Attack/AttackBase.cs +++ b/OpenRA.Mods.RA/Attack/AttackBase.cs @@ -19,70 +19,34 @@ namespace OpenRA.Mods.RA { public abstract class AttackBaseInfo : ITraitInfo { - [WeaponReference] - [Desc("Has to be defined here and in weapons.yaml.")] - public readonly string PrimaryWeapon = null; - [WeaponReference] - public readonly string SecondaryWeapon = null; - public readonly int PrimaryRecoil = 0; - public readonly int SecondaryRecoil = 0; - public readonly float PrimaryRecoilRecovery = 0.2f; - public readonly float SecondaryRecoilRecovery = 0.2f; - public readonly int[] PrimaryLocalOffset = { }; - public readonly int[] SecondaryLocalOffset = { }; - public readonly int[] PrimaryOffset = { 0, 0 }; - public readonly int[] SecondaryOffset = null; - public readonly int FireDelay = 0; - - public readonly bool AlignIdleTurrets = false; public readonly bool CanAttackGround = true; public readonly int MinimumScanTimeInterval = 30; public readonly int MaximumScanTimeInterval = 60; public abstract object Create(ActorInitializer init); - - public float GetMaximumRange() - { - var priRange = PrimaryWeapon != null ? Rules.Weapons[PrimaryWeapon.ToLowerInvariant()].Range : 0; - var secRange = SecondaryWeapon != null ? Rules.Weapons[SecondaryWeapon.ToLowerInvariant()].Range : 0; - - return Math.Max(priRange, secRange); - } } public abstract class AttackBase : IIssueOrder, IResolveOrder, ITick, IExplodeModifier, IOrderVoice, ISync { [Sync] public bool IsAttacking { get; internal set; } - public List Weapons = new List(); - public List Turrets = new List(); - readonly Actor self; + Lazy> armaments; + protected IEnumerable Armaments { get { return armaments.Value; } } + public AttackBase(Actor self) { this.self = self; - var info = self.Info.Traits.Get(); - - Turrets.Add(new Turret(info.PrimaryOffset, info.PrimaryRecoilRecovery)); - if (info.SecondaryOffset != null) - Turrets.Add(new Turret(info.SecondaryOffset, info.SecondaryRecoilRecovery)); - - if (info.PrimaryWeapon != null) - Weapons.Add(new Weapon(info.PrimaryWeapon, - Turrets[0], info.PrimaryLocalOffset, info.PrimaryRecoil)); - - if (info.SecondaryWeapon != null) - Weapons.Add(new Weapon(info.SecondaryWeapon, - info.SecondaryOffset != null ? Turrets[1] : Turrets[0], info.SecondaryLocalOffset, info.SecondaryRecoil)); + armaments = Lazy.New(() => self.TraitsImplementing()); } protected virtual bool CanAttack(Actor self, Target target) { if (!self.IsInWorld) return false; if (!target.IsValid) return false; - if (Weapons.All(w => w.IsReloading)) return false; + if (Armaments.All(a => a.IsReloading)) return false; if (self.IsDisabled()) return false; if (target.IsActor && target.Actor.HasTrait() && @@ -94,15 +58,12 @@ namespace OpenRA.Mods.RA public bool ShouldExplode(Actor self) { return !IsReloading(); } - public bool IsReloading() { return Weapons.Any(w => w.IsReloading); } + public bool IsReloading() { return Armaments.Any(a => a.IsReloading); } List> delayedActions = new List>(); public virtual void Tick(Actor self) { - foreach (var w in Weapons) - w.Tick(); - for (var i = 0; i < delayedActions.Count; i++) { var x = delayedActions[i]; @@ -127,20 +88,20 @@ namespace OpenRA.Mods.RA var move = self.TraitOrDefault(); var facing = self.TraitOrDefault(); - foreach (var w in Weapons) - w.CheckFire(self, this, move, facing, target); + foreach (var a in Armaments) + a.CheckFire(self, this, move, facing, target); } - public virtual int FireDelay( Actor self, Target target, AttackBaseInfo info ) - { - return info.FireDelay; - } - - bool IsHeal { get { return Weapons[ 0 ].Info.Warheads[ 0 ].Damage < 0; } } - public IEnumerable Orders { - get { yield return new AttackOrderTargeter( "Attack", 6, IsHeal ); } + get + { + if (Armaments.Count() == 0) + yield break; + + bool isHeal = Armaments.First().Weapon.Warheads[0].Damage < 0; + yield return new AttackOrderTargeter("Attack", 6, isHeal); + } } public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) @@ -163,12 +124,6 @@ namespace OpenRA.Mods.RA self.SetTargetLine(target, Color.Red); AttackTarget(target, order.Queued, order.OrderString == "Attack"); } - else - { - /* hack */ - if (self.HasTrait() && self.Info.Traits.Get().AlignIdleTurrets) - self.Trait().desiredFacing = null; - } } public string VoicePhraseForOrder(Actor self, Order order) @@ -178,10 +133,10 @@ namespace OpenRA.Mods.RA public abstract Activity GetAttackActivity(Actor self, Target newTarget, bool allowMove); - public bool HasAnyValidWeapons(Target t) { return Weapons.Any(w => w.IsValidAgainst(self.World, t)); } - public float GetMaximumRange() { return Weapons.Max(w => w.Info.Range); } + public bool HasAnyValidWeapons(Target t) { return Armaments.Any(a => a.IsValidAgainst(self.World, t)); } + public float GetMaximumRange() { return Armaments.Select(a => a.Weapon.Range).Aggregate(0f, Math.Max); } - public Weapon ChooseWeaponForTarget(Target t) { return Weapons.FirstOrDefault(w => w.IsValidAgainst(self.World, t)); } + public Armament ChooseArmamentForTarget(Target t) { return Armaments.FirstOrDefault(a => a.IsValidAgainst(self.World, t)); } public void AttackTarget( Target target, bool queued, bool allowMove ) { diff --git a/OpenRA.Mods.RA/Attack/AttackFrontal.cs b/OpenRA.Mods.RA/Attack/AttackFrontal.cs index 95a6876625..dfcd4bb2e5 100644 --- a/OpenRA.Mods.RA/Attack/AttackFrontal.cs +++ b/OpenRA.Mods.RA/Attack/AttackFrontal.cs @@ -42,10 +42,10 @@ namespace OpenRA.Mods.RA public override Activity GetAttackActivity(Actor self, Target newTarget, bool allowMove) { - var weapon = ChooseWeaponForTarget(newTarget); - if( weapon == null ) + var weapon = ChooseArmamentForTarget(newTarget); + if (weapon == null) return null; - return new Activities.Attack(newTarget, Math.Max(0, (int)weapon.Info.Range), allowMove); + return new Activities.Attack(newTarget, Math.Max(0, (int)weapon.Weapon.Range), allowMove); } } } diff --git a/OpenRA.Mods.RA/Attack/AttackLeap.cs b/OpenRA.Mods.RA/Attack/AttackLeap.cs index c5c86db63a..b9acc3a097 100644 --- a/OpenRA.Mods.RA/Attack/AttackLeap.cs +++ b/OpenRA.Mods.RA/Attack/AttackLeap.cs @@ -9,6 +9,7 @@ #endregion using System; +using System.Linq; using OpenRA.Mods.RA.Activities; using OpenRA.Traits; @@ -28,10 +29,15 @@ namespace OpenRA.Mods.RA public override void DoAttack(Actor self, Target target) { - if( !CanAttack( self, target ) ) return; + if (!CanAttack(self, target)) + return; - var weapon = Weapons[0].Info; - if( !Combat.IsInRange( self.CenterLocation, weapon.Range, target ) ) return; + var a = ChooseArmamentForTarget(target); + if (a == null) + return; + + if (!Combat.IsInRange(self.CenterLocation, a.Weapon.Range, target)) + return; self.CancelActivity(); self.QueueActivity(new Leap(self, target)); @@ -39,10 +45,10 @@ namespace OpenRA.Mods.RA public override Activity GetAttackActivity(Actor self, Target newTarget, bool allowMove) { - var weapon = ChooseWeaponForTarget(newTarget); - if( weapon == null ) + var a = ChooseArmamentForTarget(newTarget); + if (a == null) return null; - return new Activities.Attack(newTarget, Math.Max(0, (int)weapon.Info.Range), allowMove); + return new Activities.Attack(newTarget, Math.Max(0, (int)a.Weapon.Range), allowMove); } } } diff --git a/OpenRA.Mods.RA/Attack/AttackLoyalty.cs b/OpenRA.Mods.RA/Attack/AttackLoyalty.cs index 0b371cb4fa..3559fe52fb 100644 --- a/OpenRA.Mods.RA/Attack/AttackLoyalty.cs +++ b/OpenRA.Mods.RA/Attack/AttackLoyalty.cs @@ -9,6 +9,7 @@ #endregion using System; +using System.Linq; using OpenRA.Traits; using OpenRA.Mods.RA.Activities; @@ -26,15 +27,19 @@ namespace OpenRA.Mods.RA public override void DoAttack(Actor self, Target target) { - if (!CanAttack (self, target)) return; + if (!CanAttack(self, target)) return; - var weapon = Weapons[0].Info; - if (!Combat.IsInRange(self.CenterLocation, weapon.Range, target)) return; + var arm = Armaments.FirstOrDefault(); + if (arm == null) + return; + + if (!Combat.IsInRange(self.CenterLocation, arm.Weapon.Range, target)) + return; var move = self.TraitOrDefault(); var facing = self.TraitOrDefault(); - foreach (var w in Weapons) - w.CheckFire(self, this, move, facing, target); + foreach (var a in Armaments) + a.CheckFire(self, this, move, facing, target); if (target.Actor != null) target.Actor.ChangeOwner(self.Owner); diff --git a/OpenRA.Mods.RA/Attack/AttackMedic.cs b/OpenRA.Mods.RA/Attack/AttackMedic.cs index 6261d6745c..e8399eaaf2 100644 --- a/OpenRA.Mods.RA/Attack/AttackMedic.cs +++ b/OpenRA.Mods.RA/Attack/AttackMedic.cs @@ -29,10 +29,10 @@ namespace OpenRA.Mods.RA public override Activity GetAttackActivity(Actor self, Target newTarget, bool allowMove) { - var weapon = ChooseWeaponForTarget(newTarget); - if( weapon == null ) + var weapon = ChooseArmamentForTarget(newTarget); + if (weapon == null) return null; - return new Activities.Heal(newTarget, Math.Max(0, (int)weapon.Info.Range), allowMove); + return new Activities.Heal(newTarget, Math.Max(0, (int)weapon.Weapon.Range), allowMove); } } } diff --git a/OpenRA.Mods.RA/Attack/AttackPopupTurreted.cs b/OpenRA.Mods.RA/Attack/AttackPopupTurreted.cs index a9181b5005..b0a993d610 100644 --- a/OpenRA.Mods.RA/Attack/AttackPopupTurreted.cs +++ b/OpenRA.Mods.RA/Attack/AttackPopupTurreted.cs @@ -8,6 +8,7 @@ */ #endregion +using System.Linq; using OpenRA.GameRules; using OpenRA.Mods.RA.Buildings; using OpenRA.Mods.RA.Render; @@ -30,11 +31,13 @@ namespace OpenRA.Mods.RA AttackPopupTurretedInfo Info; int IdleTicks = 0; PopupState State = PopupState.Open; + Turreted turret; public AttackPopupTurreted(ActorInitializer init, AttackPopupTurretedInfo info) : base(init.self) { Info = info; buildComplete = init.Contains(); + turret = turrets.FirstOrDefault(); } protected override bool CanAttack( Actor self, Target target ) diff --git a/OpenRA.Mods.RA/Attack/AttackTurreted.cs b/OpenRA.Mods.RA/Attack/AttackTurreted.cs index 3a16af2d93..24d35c868d 100644 --- a/OpenRA.Mods.RA/Attack/AttackTurreted.cs +++ b/OpenRA.Mods.RA/Attack/AttackTurreted.cs @@ -9,6 +9,7 @@ #endregion using System; +using System.Collections.Generic; using System.Linq; using OpenRA.Mods.RA.Activities; using OpenRA.Mods.RA.Buildings; @@ -25,12 +26,12 @@ namespace OpenRA.Mods.RA class AttackTurreted : AttackBase, INotifyBuildComplete, ISync { protected Target target; - protected Turreted turret; + protected IEnumerable turrets; [Sync] protected bool buildComplete; public AttackTurreted(Actor self) : base(self) { - turret = self.Trait(); + turrets = self.TraitsImplementing(); } protected override bool CanAttack( Actor self, Target target ) @@ -39,7 +40,12 @@ namespace OpenRA.Mods.RA return false; if (!target.IsValid) return false; - if (!turret.FaceTarget(self, target)) return false; + + bool canAttack = false; + foreach (var t in turrets) + if (t.FaceTarget(self, target)) + canAttack = true; + if (!canAttack) return false; return base.CanAttack( self, target ); } @@ -85,7 +91,7 @@ namespace OpenRA.Mods.RA var attack = self.Trait(); const int RangeTolerance = 1; /* how far inside our maximum range we should try to sit */ - var weapon = attack.ChooseWeaponForTarget(target); + var weapon = attack.ChooseArmamentForTarget(target); if (weapon != null) { @@ -93,7 +99,7 @@ namespace OpenRA.Mods.RA if (allowMove && self.HasTrait() && !self.Info.Traits.Get().OnRails) return Util.SequenceActivities( - new Follow( target, Math.Max( 0, (int)weapon.Info.Range - RangeTolerance ) ), + new Follow( target, Math.Max( 0, (int)weapon.Weapon.Range - RangeTolerance ) ), this ); } diff --git a/OpenRA.Mods.RA/Combat.cs b/OpenRA.Mods.RA/Combat.cs index b21034c93b..9194791857 100755 --- a/OpenRA.Mods.RA/Combat.cs +++ b/OpenRA.Mods.RA/Combat.cs @@ -208,48 +208,6 @@ namespace OpenRA.Mods.RA return false; } - static PVecFloat GetRecoil(Actor self, float recoil) - { - if (!self.HasTrait()) - return PVecFloat.Zero; - - var facing = self.Trait().turretFacing; - var localRecoil = new float2(0, recoil); // vector in turret-space. - - return (PVecFloat)Util.RotateVectorByFacing(localRecoil, facing, .7f); - } - - public static PVecFloat GetTurretPosition(Actor self, IFacing facing, Turret turret) - { - if (facing == null) return turret.ScreenSpacePosition; /* things that don't have a rotating base don't need the turrets repositioned */ - - var ru = self.TraitOrDefault(); - var numDirs = (ru != null) ? ru.anim.CurrentSequence.Facings : 8; - var bodyFacing = facing.Facing; - var quantizedFacing = Util.QuantizeFacing(bodyFacing, numDirs) * (256 / numDirs); - - return (PVecFloat)Util.RotateVectorByFacing(turret.UnitSpacePosition.ToFloat2(), quantizedFacing, .7f) - + GetRecoil(self, turret.Recoil) - + (PVecFloat)turret.ScreenSpacePosition.ToFloat2(); - } - - static PVecFloat GetUnitspaceBarrelOffset(Actor self, IFacing facing, Turret turret, Barrel barrel) - { - var turreted = self.TraitOrDefault(); - if (turreted == null && facing == null) - return PVecFloat.Zero; - - var turretFacing = turreted != null ? turreted.turretFacing : facing.Facing; - return (PVecFloat)Util.RotateVectorByFacing(barrel.TurretSpaceOffset.ToFloat2(), turretFacing, .7f); - } - - // gets the screen-space position of a barrel. - public static PVecFloat GetBarrelPosition(Actor self, IFacing facing, Turret turret, Barrel barrel) - { - return GetTurretPosition(self, facing, turret) + barrel.ScreenSpaceOffset - + GetUnitspaceBarrelOffset(self, facing, turret, barrel); - } - public static bool IsInRange( PPos attackOrigin, float range, Actor target ) { var rsq = range * range * Game.CellSize * Game.CellSize; diff --git a/OpenRA.Mods.RA/Effects/Contrail.cs b/OpenRA.Mods.RA/Effects/Contrail.cs index 95de6f5b33..046d5d5ffc 100755 --- a/OpenRA.Mods.RA/Effects/Contrail.cs +++ b/OpenRA.Mods.RA/Effects/Contrail.cs @@ -45,7 +45,7 @@ namespace OpenRA.Mods.RA public void Tick(Actor self) { - history.Tick(self.CenterLocation - new PVecInt(0, move.Altitude) - (PVecInt)Combat.GetTurretPosition(self, facing, contrailTurret).ToInt2()); + history.Tick(self.CenterLocation - new PVecInt(0, move.Altitude) - (PVecInt)contrailTurret.PxPosition(self, facing).ToInt2()); } public void RenderAfterWorld(WorldRenderer wr, Actor self) { history.Render(self); } diff --git a/OpenRA.Mods.RA/LeavesHusk.cs b/OpenRA.Mods.RA/LeavesHusk.cs index a125ba1341..8bcaade2f1 100644 --- a/OpenRA.Mods.RA/LeavesHusk.cs +++ b/OpenRA.Mods.RA/LeavesHusk.cs @@ -55,7 +55,9 @@ namespace OpenRA.Mods.RA if (facing != null) td.Add(new FacingInit( facing.Facing )); - var turreted = self.TraitOrDefault(); + // TODO: This will only take the first turret if there are multiple + // This isn't a problem with the current units, but may be a problem for mods + var turreted = self.TraitsImplementing().FirstOrDefault(); if (turreted != null) td.Add( new TurretFacingInit(turreted.turretFacing) ); diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index bd437e02fa..4d8584b9a2 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -368,7 +368,6 @@ - @@ -420,6 +419,7 @@ + diff --git a/OpenRA.Mods.RA/Render/RenderBuildingSeparateTurret.cs b/OpenRA.Mods.RA/Render/RenderBuildingSeparateTurret.cs index 345b116947..54927b7612 100644 --- a/OpenRA.Mods.RA/Render/RenderBuildingSeparateTurret.cs +++ b/OpenRA.Mods.RA/Render/RenderBuildingSeparateTurret.cs @@ -24,19 +24,17 @@ namespace OpenRA.Mods.RA.Render public RenderBuildingSeparateTurret(ActorInitializer init, RenderBuildingInfo info) : base(init, info) { - var turreted = init.self.Trait(); - var attack = init.self.Trait(); + var self = init.self; + var turreted = self.TraitsImplementing(); - var turretAnim = new Animation(GetImage(init.self), () => turreted.turretFacing); - turretAnim.Play("turret"); - - for( var i = 0; i < attack.Turrets.Count; i++ ) + var i = 0; + foreach (var t in turreted) { - var turret = attack.Turrets[i]; - anims.Add( "turret_{0}".F(i), - new AnimationWithOffset(turretAnim, - () => Combat.GetTurretPosition(init.self, null, turret).ToFloat2(), - null)); + var anim = new Animation(GetImage(self), () => t.turretFacing); + anim.Play("turret"); + + anims.Add("turret_{0}".F(i++), new AnimationWithOffset(anim, + () => t.PxPosition(self, null).ToFloat2(), null)); } } } diff --git a/OpenRA.Mods.RA/Render/RenderBuildingTurreted.cs b/OpenRA.Mods.RA/Render/RenderBuildingTurreted.cs index 450d682704..daeeb3d00b 100644 --- a/OpenRA.Mods.RA/Render/RenderBuildingTurreted.cs +++ b/OpenRA.Mods.RA/Render/RenderBuildingTurreted.cs @@ -9,6 +9,7 @@ #endregion using System; +using System.Linq; using OpenRA.Mods.RA.Buildings; using OpenRA.Traits; @@ -26,7 +27,8 @@ namespace OpenRA.Mods.RA.Render static Func MakeTurretFacingFunc(Actor self) { - var turreted = self.Trait(); + // Turret artwork is baked into the sprite, so only the first turret makes sense. + var turreted = self.TraitsImplementing().FirstOrDefault(); return () => turreted.turretFacing; } } diff --git a/OpenRA.Mods.RA/Render/RenderUnitSpinner.cs b/OpenRA.Mods.RA/Render/RenderUnitSpinner.cs index 89573ea115..7089f599a3 100755 --- a/OpenRA.Mods.RA/Render/RenderUnitSpinner.cs +++ b/OpenRA.Mods.RA/Render/RenderUnitSpinner.cs @@ -31,9 +31,10 @@ namespace OpenRA.Mods.RA.Render spinnerAnim.PlayRepeating("spinner"); + var turret = new Turret(info.Offset); anims.Add("spinner", new AnimationWithOffset( spinnerAnim, - () => Combat.GetTurretPosition( self, facing, new Turret(info.Offset)).ToFloat2(), + () => turret.PxPosition(self, facing).ToFloat2(), null ) { ZOffset = 1 } ); } } diff --git a/OpenRA.Mods.RA/Render/RenderUnitTurreted.cs b/OpenRA.Mods.RA/Render/RenderUnitTurreted.cs index 665f35e608..683b539246 100755 --- a/OpenRA.Mods.RA/Render/RenderUnitTurreted.cs +++ b/OpenRA.Mods.RA/Render/RenderUnitTurreted.cs @@ -8,6 +8,8 @@ */ #endregion +using System; +using System.Linq; using OpenRA.Graphics; using OpenRA.Traits; @@ -24,20 +26,30 @@ namespace OpenRA.Mods.RA.Render : base(self) { var facing = self.Trait(); - var turreted = self.Trait(); - var attack = self.Trait(); + var turreted = self.TraitsImplementing(); - var turretAnim = new Animation(GetImage(self), () => turreted.turretFacing ); - turretAnim.Play( "turret" ); - - for( var i = 0; i < attack.Turrets.Count; i++ ) + var i = 0; + foreach (var t in turreted) { - var turret = attack.Turrets[i]; - anims.Add( "turret_{0}".F(i), - new AnimationWithOffset( turretAnim, - () => Combat.GetTurretPosition( self, facing, turret ).ToFloat2(), - null)); + var turret = t; + + var anim = new Animation(GetImage(self), () => turret.turretFacing); + anim.Play("turret"); + + anims.Add("turret_{0}".F(i++), new AnimationWithOffset(anim, + () => turret.PxPosition(self, facing).ToFloat2() + RecoilOffset(self, turret), null)); } } + + float2 RecoilOffset(Actor self, Turreted t) + { + var a = self.TraitsImplementing() + .OrderByDescending(w => w.Recoil) + .FirstOrDefault(w => w.Info.Turret == t.info.Turret); + if (a == null) + return float2.Zero; + + return a.RecoilPxOffset(self, t.turretFacing).ToFloat2(); + } } } diff --git a/OpenRA.Mods.RA/Render/WithMuzzleFlash.cs b/OpenRA.Mods.RA/Render/WithMuzzleFlash.cs index 084b48156f..69933b27a4 100644 --- a/OpenRA.Mods.RA/Render/WithMuzzleFlash.cs +++ b/OpenRA.Mods.RA/Render/WithMuzzleFlash.cs @@ -8,10 +8,12 @@ */ #endregion +using System; using System.Collections.Generic; +using System.Linq; using OpenRA.Graphics; using OpenRA.Traits; -using System; +using OpenRA.Mods.RA; namespace OpenRA.Mods.RA.Render { @@ -27,25 +29,25 @@ namespace OpenRA.Mods.RA.Render public WithMuzzleFlash(Actor self) { - var attack = self.Trait(); var render = self.Trait(); var facing = self.TraitOrDefault(); - var turreted = self.TraitOrDefault(); - var getFacing = turreted != null ? () => turreted.turretFacing : - facing != null ? (Func)(() => facing.Facing) : () => 0; - foreach (var w in attack.Weapons) - foreach( var b in w.Barrels ) + var arms = self.TraitsImplementing(); + foreach (var a in arms) + foreach(var b in a.Barrels) { var barrel = b; - var turret = w.Turret; + var turreted = self.TraitsImplementing() + .FirstOrDefault(t => t.info.Turret == a.Info.Turret); + var getFacing = turreted != null ? () => turreted.turretFacing : + facing != null ? (Func)(() => facing.Facing) : () => 0; var muzzleFlash = new Animation(render.GetImage(self), getFacing); muzzleFlash.Play("muzzle"); muzzleFlashes.Add("muzzle{0}".F(muzzleFlashes.Count), new AnimationWithOffset( muzzleFlash, - () => Combat.GetBarrelPosition(self, facing, turret, barrel).ToFloat2(), + () => a.MuzzlePxPosition(self, facing, barrel).ToFloat2(), () => !isShowing)); } } diff --git a/OpenRA.Mods.RA/Render/WithRotor.cs b/OpenRA.Mods.RA/Render/WithRotor.cs index bb7ae40ddf..e394e6b884 100755 --- a/OpenRA.Mods.RA/Render/WithRotor.cs +++ b/OpenRA.Mods.RA/Render/WithRotor.cs @@ -30,9 +30,10 @@ namespace OpenRA.Mods.RA.Render rotorAnim = new Animation(rs.GetImage(self)); rotorAnim.PlayRepeating("rotor"); + var turret = new Turret(info.Offset); rs.anims.Add(info.Id, new AnimationWithOffset( rotorAnim, - () => Combat.GetTurretPosition( self, facing, new Turret(info.Offset)).ToFloat2(), + () => turret.PxPosition(self, facing).ToFloat2(), null ) { ZOffset = 1 } ); } diff --git a/OpenRA.Mods.RA/RenderRangeCircle.cs b/OpenRA.Mods.RA/RenderRangeCircle.cs index 8a869fdc55..e0ca291fe7 100644 --- a/OpenRA.Mods.RA/RenderRangeCircle.cs +++ b/OpenRA.Mods.RA/RenderRangeCircle.cs @@ -9,6 +9,7 @@ #endregion using System.Drawing; +using System.Linq; using OpenRA.Graphics; using OpenRA.Traits; @@ -26,11 +27,11 @@ namespace OpenRA.Mods.RA public void Render(WorldRenderer wr, World w, ActorInfo ai, PPos centerLocation) { wr.DrawRangeCircleWithContrast( - Color.FromArgb(128, Color.Yellow), - centerLocation.ToFloat2(), - ai.Traits.Get().GetMaximumRange(), - Color.FromArgb(96, Color.Black), - 1); + Color.FromArgb(128, Color.Yellow), centerLocation.ToFloat2(), + ai.Traits.WithInterface() + .Select(a => Rules.Weapons[a.Weapon.ToLowerInvariant()].Range).Max(), + Color.FromArgb(96, Color.Black), 1 + ); foreach (var a in w.ActorsWithTrait()) if (a.Actor.Owner == a.Actor.World.LocalPlayer) diff --git a/OpenRA.Mods.RA/SmokeTrailWhenDamaged.cs b/OpenRA.Mods.RA/SmokeTrailWhenDamaged.cs index 70419e5d24..9e2dd66a21 100644 --- a/OpenRA.Mods.RA/SmokeTrailWhenDamaged.cs +++ b/OpenRA.Mods.RA/SmokeTrailWhenDamaged.cs @@ -43,7 +43,7 @@ namespace OpenRA.Mods.RA { var facing = self.Trait(); var altitude = new PVecInt(0, move.Altitude); - position = (self.CenterLocation - (PVecInt)Combat.GetTurretPosition(self, facing, smokeTurret).ToInt2()); + position = (self.CenterLocation - (PVecInt)smokeTurret.PxPosition(self, facing).ToInt2()); if (self.World.RenderedShroud.IsVisible(position.ToCPos())) self.World.AddFrameEndTask( diff --git a/OpenRA.Mods.RA/TakeCover.cs b/OpenRA.Mods.RA/TakeCover.cs index 96ac4e50da..6e3651598f 100644 --- a/OpenRA.Mods.RA/TakeCover.cs +++ b/OpenRA.Mods.RA/TakeCover.cs @@ -14,23 +14,24 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA { - public class TakeCoverInfo : ITraitInfo + public class TakeCoverInfo : TurretedInfo { public readonly int ProneTime = 100; /* ticks, =4s */ public readonly float ProneDamage = .5f; public readonly decimal ProneSpeed = .5m; - public readonly int[] BarrelOffset = null; + public readonly int[] ProneOffset = {0,-2,0,4}; - public object Create(ActorInitializer init) { return new TakeCover(this); } + public override object Create(ActorInitializer init) { return new TakeCover(init, this); } } // Infantry prone behavior - public class TakeCover : ITick, INotifyDamage, IDamageModifier, ISpeedModifier, ISync + public class TakeCover : Turreted, ITick, INotifyDamage, IDamageModifier, ISpeedModifier, ISync { TakeCoverInfo Info; [Sync] int remainingProneTime = 0; - public TakeCover(TakeCoverInfo info) + public TakeCover(ActorInitializer init, TakeCoverInfo info) + : base(init, info) { Info = info; } @@ -42,36 +43,16 @@ namespace OpenRA.Mods.RA if (e.Damage > 0 && (e.Warhead == null || !e.Warhead.PreventProne)) /* Don't go prone when healed */ { if (!IsProne) - ApplyBarrelOffset(self, true); + turret = new Turret(Info.ProneOffset); remainingProneTime = Info.ProneTime; } } - public void Tick(Actor self) + public override void Tick(Actor self) { - if (IsProne) - { - if (--remainingProneTime == 0) - ApplyBarrelOffset(self, false); - } - } - - public void ApplyBarrelOffset(Actor self, bool isProne) - { - if (Info.BarrelOffset == null) - return; - - var ab = self.TraitOrDefault(); - if (ab == null) - return; - - var sign = isProne ? 1 : -1; - foreach (var w in ab.Weapons) - foreach (var b in w.Barrels) - { - b.TurretSpaceOffset += sign * new PVecInt(Info.BarrelOffset[0], Info.BarrelOffset[1]); - b.ScreenSpaceOffset += sign * new PVecInt(Info.BarrelOffset[2], Info.BarrelOffset[3]); - } + base.Tick(self); + if (IsProne && --remainingProneTime == 0) + turret = new Turret(Info.Offset); } public float GetDamageModifier(Actor attacker, WarheadInfo warhead ) diff --git a/OpenRA.Mods.RA/ThrowsParticle.cs b/OpenRA.Mods.RA/ThrowsParticle.cs index 351dfb899e..3ce1f252f3 100644 --- a/OpenRA.Mods.RA/ThrowsParticle.cs +++ b/OpenRA.Mods.RA/ThrowsParticle.cs @@ -46,7 +46,7 @@ namespace OpenRA.Mods.RA alt = 0; facing = Turreted.GetInitialTurretFacing( init, 0 ); - pos = Combat.GetTurretPosition(self, ifacing, new Turret(info.Offset)).ToFloat2(); + pos = new Turret(info.Offset).PxPosition(self, ifacing).ToFloat2(); v = Game.CosmeticRandom.Gauss2D(1) * info.Spread.RelOffset(); dfacing = Game.CosmeticRandom.Gauss1D(2) * info.ROT; diff --git a/OpenRA.Mods.RA/Turreted.cs b/OpenRA.Mods.RA/Turreted.cs index 60e364981f..f9c305f755 100755 --- a/OpenRA.Mods.RA/Turreted.cs +++ b/OpenRA.Mods.RA/Turreted.cs @@ -8,23 +8,29 @@ */ #endregion +using System.Collections.Generic; +using OpenRA.Mods.RA.Render; using OpenRA.Traits; namespace OpenRA.Mods.RA { public class TurretedInfo : ITraitInfo, UsesInit { + public readonly string Turret = "primary"; public readonly int ROT = 255; public readonly int InitialFacing = 128; + public readonly int[] Offset = {0,0}; + public readonly bool AlignWhenIdle = false; - public object Create(ActorInitializer init) { return new Turreted(init, this); } + public virtual object Create(ActorInitializer init) { return new Turreted(init, this); } } - public class Turreted : ITick, ISync + public class Turreted : ITick, ISync, IResolveOrder { [Sync] public int turretFacing = 0; public int? desiredFacing; - TurretedInfo info; + public TurretedInfo info; + protected Turret turret; IFacing facing; public static int GetInitialTurretFacing(ActorInitializer init, int def) @@ -43,9 +49,10 @@ namespace OpenRA.Mods.RA this.info = info; turretFacing = GetInitialTurretFacing(init, info.InitialFacing); facing = init.self.TraitOrDefault(); + turret = new Turret(info.Offset); } - public void Tick(Actor self) + public virtual void Tick(Actor self) { var df = desiredFacing ?? ( facing != null ? facing.Facing : turretFacing ); turretFacing = Util.TickFacing(turretFacing, df, info.ROT); @@ -56,5 +63,42 @@ namespace OpenRA.Mods.RA desiredFacing = Util.GetFacing( target.CenterLocation - self.CenterLocation, turretFacing ); return turretFacing == desiredFacing; } + + public virtual void ResolveOrder(Actor self, Order order) + { + if (info.AlignWhenIdle && order.OrderString != "Attack" && order.OrderString != "AttackHold") + desiredFacing = null; + } + + public PVecFloat PxPosition(Actor self, IFacing facing) + { + return turret.PxPosition(self, facing); + } + } + + public class Turret + { + public PVecInt UnitSpacePosition; // where, in the unit's local space. + public PVecInt ScreenSpacePosition; // screen-space hack to make things line up good. + + public Turret(int[] offset) + { + ScreenSpacePosition = (PVecInt) offset.AbsOffset().ToInt2(); + UnitSpacePosition = (PVecInt) offset.RelOffset().ToInt2(); + } + + public PVecFloat PxPosition(Actor self, IFacing facing) + { + // Things that don't have a rotating base don't need the turrets repositioned + if (facing == null) return ScreenSpacePosition; + + var ru = self.TraitOrDefault(); + var numDirs = (ru != null) ? ru.anim.CurrentSequence.Facings : 8; + var bodyFacing = facing.Facing; + var quantizedFacing = Util.QuantizeFacing(bodyFacing, numDirs) * (256 / numDirs); + + return (PVecFloat)Util.RotateVectorByFacing(UnitSpacePosition.ToFloat2(), quantizedFacing, .7f) + + (PVecFloat)ScreenSpacePosition.ToFloat2(); + } } } diff --git a/OpenRA.Mods.RA/Weapon.cs b/OpenRA.Mods.RA/Weapon.cs deleted file mode 100644 index 606df63f75..0000000000 --- a/OpenRA.Mods.RA/Weapon.cs +++ /dev/null @@ -1,162 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2011 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.GameRules; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - public class Barrel - { - public PVecInt TurretSpaceOffset; // position in turret space - public PVecInt ScreenSpaceOffset; // screen-space hack to make things line up good. - public int Facing; // deviation from turret facing - } - - public class Turret - { - public float Recoil = 0.0f; // remaining recoil - public float RecoilRecovery = 0.2f; // recoil recovery rate - public PVecInt UnitSpacePosition; // where, in the unit's local space. - public PVecInt ScreenSpacePosition; // screen-space hack to make things line up good. - - public Turret(int[] offset, float recoilRecovery) - { - ScreenSpacePosition = (PVecInt) offset.AbsOffset().ToInt2(); - UnitSpacePosition = (PVecInt) offset.RelOffset().ToInt2(); - RecoilRecovery = recoilRecovery; - } - - public Turret(int[] offset) : this(offset, 0) {} - } - - public class Weapon - { - public WeaponInfo Info; - public int FireDelay = 0; // time (in frames) until the weapon can fire again - public int Burst = 0; // burst counter - public int Recoil = 0; - - public Barrel[] Barrels; // where projectiles are spawned, in local turret space. - public Turret Turret; // where this weapon is mounted -- possibly shared - - public Weapon(string weaponName, Turret turret, int[] localOffset, int recoil) - { - Info = Rules.Weapons[weaponName.ToLowerInvariant()]; - Burst = Info.Burst; - Turret = turret; - Recoil = recoil; - - var barrels = new List(); - for (var i = 0; i < localOffset.Length / 5; i++) - barrels.Add(new Barrel - { - TurretSpaceOffset = new PVecInt(localOffset[5 * i], localOffset[5 * i + 1]), - ScreenSpaceOffset = new PVecInt(localOffset[5 * i + 2], localOffset[5 * i + 3]), - Facing = localOffset[5 * i + 4] - }); - - // if no barrels specified, the default is "turret position; turret facing". - if (barrels.Count == 0) - barrels.Add(new Barrel { TurretSpaceOffset = PVecInt.Zero, ScreenSpaceOffset = PVecInt.Zero, Facing = 0 }); - - Barrels = barrels.ToArray(); - } - - public bool IsReloading { get { return FireDelay > 0; } } - - public void Tick() - { - if (FireDelay > 0) --FireDelay; - Turret.Recoil = Math.Max(0f, Turret.Recoil - Turret.RecoilRecovery); - } - - public bool IsValidAgainst(World world, Target target) - { - if( target.IsActor ) - return Combat.WeaponValidForTarget( Info, target.Actor ); - else - return Combat.WeaponValidForTarget( Info, world, target.CenterLocation.ToCPos() ); - } - - public void FiredShot() - { - Turret.Recoil = this.Recoil; - - if (--Burst > 0) - FireDelay = Info.BurstDelay; - else - { - FireDelay = Info.ROF; - Burst = Info.Burst; - } - } - - public void CheckFire(Actor self, AttackBase attack, IMove move, IFacing facing, Target target) - { - if (FireDelay > 0) return; - - var limitedAmmo = self.TraitOrDefault(); - if (limitedAmmo != null && !limitedAmmo.HasAmmo()) - return; - - if (!Combat.IsInRange(self.CenterLocation, Info.Range, target)) return; - if (Combat.IsInRange(self.CenterLocation, Info.MinRange, target)) return; - - if (!IsValidAgainst(self.World, target)) return; - - var barrel = Barrels[Burst % Barrels.Length]; - var destMove = target.IsActor ? target.Actor.TraitOrDefault() : null; - var turreted = self.TraitOrDefault(); - - var args = new ProjectileArgs - { - weapon = Info, - - firedBy = self, - target = target, - - src = (self.CenterLocation + (PVecInt)Combat.GetBarrelPosition(self, facing, Turret, barrel).ToInt2()), - srcAltitude = move != null ? move.Altitude : 0, - dest = target.CenterLocation, - destAltitude = destMove != null ? destMove.Altitude : 0, - - facing = barrel.Facing + - (turreted != null ? turreted.turretFacing : - facing != null ? facing.Facing : Util.GetFacing(target.CenterLocation - self.CenterLocation, 0)), - - firepowerModifier = self.TraitsImplementing() - .Select(a => a.GetFirepowerModifier()) - .Product() - }; - - attack.ScheduleDelayedAction( attack.FireDelay( self, target, self.Info.Traits.Get() ), () => - { - 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()) - Sound.Play(args.weapon.Report.Random(self.World.SharedRandom) + ".aud", self.CenterLocation); - } - }); - - foreach (var na in self.TraitsImplementing()) - na.Attacking(self, target); - - FiredShot(); - } - } -} diff --git a/mods/cnc-classic/rules/aircraft.yaml b/mods/cnc-classic/rules/aircraft.yaml index 41607ab3f1..6ef0dee633 100644 --- a/mods/cnc-classic/rules/aircraft.yaml +++ b/mods/cnc-classic/rules/aircraft.yaml @@ -63,10 +63,10 @@ HELI: Type: Light RevealsShroud: Range: 8 + Armament: + Weapon: HeliAGGun + LocalOffset: -5,-3,0,2,0, 5,-3,0,2,0 AttackHeli: - PrimaryWeapon: HeliAGGun - PrimaryOffset: 0,-3,0,2 - PrimaryLocalOffset: -5,0,0,0,0, 5,0,0,0,0 FacingTolerance: 20 LimitedAmmo: Ammo: 10 @@ -105,10 +105,10 @@ ORCA: Type: Light RevealsShroud: Range: 8 + Armament: + Weapon: OrcaAGMissiles + LocalOffset: -4,-10,0,5,0, 4,-10,0,5,0 AttackHeli: - PrimaryWeapon: OrcaAGMissiles - PrimaryOffset: 0,-10,0,5 - PrimaryLocalOffset: -4,0,0,0,0, 4,0,0,0,0 FacingTolerance: 20 LimitedAmmo: Ammo: 10 diff --git a/mods/cnc-classic/rules/civilian.yaml b/mods/cnc-classic/rules/civilian.yaml index abaa743803..5eb8bb9d40 100644 --- a/mods/cnc-classic/rules/civilian.yaml +++ b/mods/cnc-classic/rules/civilian.yaml @@ -247,8 +247,9 @@ VICE: Cost: 1000 Tooltip: Name: Viceroid + Armament: + Weapon: Chemspray AttackFrontal: - PrimaryWeapon: Chemspray AttackWander: RenderUnit: WithMuzzleFlash: \ No newline at end of file diff --git a/mods/cnc-classic/rules/defaults.yaml b/mods/cnc-classic/rules/defaults.yaml index 1302ead0fb..ea5e62f743 100644 --- a/mods/cnc-classic/rules/defaults.yaml +++ b/mods/cnc-classic/rules/defaults.yaml @@ -151,8 +151,9 @@ RevealsShroud: Range: 3 #arbitrary. Assuming it should be 1, like infantry. # In practice, it seems that OpenRA renders vision range differently. Assuming it should be 1 for this unit. + Armament: + Weapon: Pistol AttackFrontal: - PrimaryWeapon: Pistol ActorLostNotification: Notification: civdead1.aud NotifyAll: true diff --git a/mods/cnc-classic/rules/infantry.yaml b/mods/cnc-classic/rules/infantry.yaml index a5f940838a..d6f41b03c1 100644 --- a/mods/cnc-classic/rules/infantry.yaml +++ b/mods/cnc-classic/rules/infantry.yaml @@ -15,8 +15,9 @@ E1: Speed: 4 Health: HP: 50 + Armament: + Weapon: M16 AttackFrontal: - PrimaryWeapon: M16 RenderInfantryProne: IdleAnimations: idle1,idle2,idle3,idle4 @@ -38,10 +39,11 @@ E2: Speed: 5 Health: HP: 50 - AttackFrontal: - PrimaryWeapon: Grenade - PrimaryOffset: 0,0,0,-10 + Armament: + Weapon: Grenade + LocalOffset: 0,0,0,-10,0 FireDelay: 15 + AttackFrontal: RenderInfantryProne: IdleAnimations: idle1,idle2 Explodes: @@ -77,10 +79,11 @@ E3: RevealsShroud: Range: 3 # range value is 1 in C&C, but OpenRA renders vision slightly differently - AttackFrontal: - PrimaryWeapon: Rockets - PrimaryOffset: 1,-6,0,-8 + Armament: + Weapon: Rockets + LocalOffset: 1,-6,0,-8,0 FireDelay: 5 + AttackFrontal: RenderInfantryProne: IdleAnimations: idle1,idle2 @@ -102,10 +105,11 @@ E4: Speed: 5 Health: HP: 70 - AttackFrontal: - PrimaryWeapon: Flamethrower - PrimaryOffset: 0,-2,2,-4 + Armament: + Weapon: Flamethrower + LocalOffset: 0,-2,2,-4,0 FireDelay: 3 + AttackFrontal: WithMuzzleFlash: RenderInfantryProne: IdleAnimations: idle1,idle2 @@ -134,10 +138,11 @@ E5: PathingCost: 100 Health: HP: 70 - AttackFrontal: - PrimaryWeapon: Chemspray - PrimaryOffset: 0,-2,2,-9 + Armament: + Weapon: Chemspray + LocalOffset: 0,-2,2,-9 FireDelay: 3 + AttackFrontal: WithMuzzleFlash: -PoisonedByTiberium: RenderInfantryProne: @@ -202,8 +207,9 @@ RMBO: ScanRadius: 5 C4Demolition: C4Delay: 45 + Armament: + Weapon: Sniper AttackFrontal: - PrimaryWeapon: Sniper RenderInfantryProne: IdleAnimations: idle1,idle2,idle3 AnnounceOnBuild: diff --git a/mods/cnc-classic/rules/ships.yaml b/mods/cnc-classic/rules/ships.yaml index 93d8c6cb4e..834c3997a4 100644 --- a/mods/cnc-classic/rules/ships.yaml +++ b/mods/cnc-classic/rules/ships.yaml @@ -18,10 +18,11 @@ BOAT: Range: 7 Turreted: ROT: 7 + Offset: 0,-15,0,-4 + Armament: + Weapon: BoatMissile + LocalOffset: -3,-5,0,0,0, 3,-5,0,0,0, 0,-5,0,0,0 AttackTurreted: - PrimaryWeapon: BoatMissile - PrimaryOffset: 0,-15,0,-4 - PrimaryLocalOffset: -3,-5,0,0,0, 3,-5,0,0,0, 0,-5,0,0,0 RenderGunboat: AutoTarget: AllowMovement: false diff --git a/mods/cnc-classic/rules/structures.yaml b/mods/cnc-classic/rules/structures.yaml index 976e6c6b0b..f0059002e2 100644 --- a/mods/cnc-classic/rules/structures.yaml +++ b/mods/cnc-classic/rules/structures.yaml @@ -556,12 +556,13 @@ OBLI: # (Range of Obelisk laser is 7.5) RenderBuildingCharge: ChargeAudio: obelpowr.aud - AttackTurreted: - PrimaryWeapon: Laser - PrimaryOffset: 0,0,-2,-17 - FireDelay: 8 Turreted: ROT:255 + Offset: 0,0,-2,-17 + Armament: + Weapon: Laser + FireDelay: 8 + AttackTurreted: AutoTarget: -RenderBuilding: RenderRangeCircle: @@ -663,9 +664,10 @@ GUN: ROT: 12 InitialFacing: 50 RenderBuildingTurreted: + Armament: + Weapon: TurretGun + LocalOffset: 0,4,0,-2,0 AttackTurreted: - PrimaryWeapon: TurretGun - PrimaryLocalOffset: 0,4,0,-2,0 AutoTarget: -AutoTargetIgnore: -RenderBuilding: @@ -706,8 +708,9 @@ SAM: ROT: 7 InitialFacing: 0 RenderBuildingTurreted: + Armament: + Weapon: SAMMissile AttackPopupTurreted: - PrimaryWeapon: SAMMissile WithMuzzleFlash: AutoTarget: -RenderBuilding: @@ -736,10 +739,10 @@ GTWR: Range: 6 # Range: 3 # RevealShroud range was set to equal 1 + its weapon range (due to possible rendering issues with shroud for OpenRA) + Armament: + Weapon: HighV + LocalOffset: 0,-6,0,0,0 AttackTurreted: - PrimaryWeapon: HighV - PrimaryOffset: 0,0,0,-6 - PrimaryLocalOffset: 0,-6,0,0,0 AutoTarget: -AutoTargetIgnore: DetectCloaked: @@ -749,6 +752,7 @@ GTWR: WithMuzzleFlash: Turreted: ROT:255 + Offset: 0,0,0,-6 ATWR: Inherits: ^Building @@ -777,12 +781,13 @@ ATWR: Range: 7 # Range: 4 # RevealShroud range was set to equal its weapon range +1 (due to possible rendering issues with shroud for OpenRA) - AttackTurreted: - PrimaryWeapon: TowerMissle - PrimaryOffset: 0,0,5,2 - PrimaryLocalOffset: 7,-7,0,0,-25, -7,-7,0,0,25 Turreted: ROT:255 + Offset: 0,0,5,2 + Armament: + Weapon: TowerMissle + LocalOffset: 7,-7,0,0,-25, -7,-7,0,0,25 + AttackTurreted: AutoTarget: -AutoTargetIgnore: DetectCloaked: diff --git a/mods/cnc-classic/rules/vehicles.yaml b/mods/cnc-classic/rules/vehicles.yaml index 6d378bd2c9..c71638a756 100644 --- a/mods/cnc-classic/rules/vehicles.yaml +++ b/mods/cnc-classic/rules/vehicles.yaml @@ -99,9 +99,10 @@ JEEP: # In practice, it seems that OpenRA renders vision range differently. Will set at +2 from C&C Gold values for now to properly emulate. Turreted: ROT: 10 + Offset: 0,2,0,-4 + Armament: + Weapon: MachineGun AttackTurreted: - PrimaryWeapon: MachineGun - PrimaryOffset: 0,2,0,-4 WithMuzzleFlash: RenderUnitTurreted: AutoTarget: @@ -131,9 +132,9 @@ APC: # In practice, it seems that OpenRA renders vision range differently. Will set at +2 from C&C Gold values for now to properly emulate. Turreted: ROT: 10 + Armament: + Weapon: MachineGun AttackTurreted: - PrimaryWeapon: MachineGun - PrimaryOffset: 0,0,0,0 WithMuzzleFlash: RenderUnitTurreted: AutoTarget: @@ -168,9 +169,10 @@ BGGY: # In practice, it seems that OpenRA renders vision range differently. Will set at +2 from C&C Gold values for now to properly emulate. Turreted: ROT: 10 + Offset: 0,1,0,-3 + Armament: + Weapon: MachineGun AttackTurreted: - PrimaryWeapon: MachineGun - PrimaryOffset: 0,1,0,-3 WithMuzzleFlash: RenderUnitTurreted: AutoTarget: @@ -198,10 +200,10 @@ BIKE: Range: 4 # Range: 2 # In practice, it seems that OpenRA renders vision range differently. Will set at +2 from C&C Gold values for now to properly emulate. + Armament: + Weapon: BikeRockets + LocalOffset: -4,0,0,-2,25, 4,0,0,-2,-25 AttackFrontal: - PrimaryWeapon: BikeRockets - PrimaryOffset: 0,0,0,-2 - PrimaryLocalOffset: -4,0,0,0,25, 4,0,0,0,-25 RenderUnit: AutoTarget: @@ -228,9 +230,10 @@ ARTY: Range: 6 # Range: 4 # In practice, it seems that OpenRA renders vision range differently. Will set at +2 from C&C Gold values for now to properly emulate. + Armament: + Weapon: ArtilleryShell + LocalOffset: 0,-7,0,-3,0 AttackFrontal: - PrimaryWeapon: ArtilleryShell - PrimaryOffset: 0,-7,0,-3 RenderUnit: AutoTarget: Explodes: @@ -260,10 +263,10 @@ FTNK: Range: 6 # Range: 4 # In practice, it seems that OpenRA renders vision range differently. Will set at +2 from C&C Gold values for now to properly emulate. + Armament: + Weapon: BigFlamer + LocalOffset: 2,-5,3,2,0, -2,-5,3,2,0 AttackFrontal: - PrimaryWeapon: BigFlamer - PrimaryOffset: 0,-5,3,2 - PrimaryLocalOffset: 2,0,0,0,0, -2,0,0,0,0 RenderUnit: AutoTarget: WithMuzzleFlash: @@ -295,11 +298,12 @@ LTNK: # In practice, it seems that OpenRA renders vision range differently. Will set at +2 from C&C Gold values for now to properly emulate. Turreted: ROT: 5 + Armament: + Weapon: 70mm + Recoil: 2 + RecoilRecovery: 0.4 + LocalOffset: 0,3,0,-2,0 AttackTurreted: - PrimaryWeapon: 70mm - PrimaryRecoil: 2 - PrimaryRecoilRecovery: 0.4 - PrimaryLocalOffset: 0,3,0,-2,0 RenderUnitTurreted: AutoTarget: @@ -327,12 +331,13 @@ MTNK: # In practice, it seems that OpenRA renders vision range differently. Will set at +2 from C&C Gold values for now to properly emulate. Turreted: ROT: 5 + Armament: + # Weapon: 120mm + Weapon: 105mm + Recoil: 3 + RecoilRecovery: 0.6 + LocalOffset: 0,0,0,-1,0 AttackTurreted: - # PrimaryWeapon: 120mm - PrimaryWeapon: 105mm - PrimaryRecoil: 3 - PrimaryRecoilRecovery: 0.6 - PrimaryLocalOffset: 0,0,0,-1,0 RenderUnitTurreted: AutoTarget: Selectable: @@ -363,14 +368,16 @@ HTNK: # In practice, it seems that OpenRA renders vision range differently. Will set at +2 from C&C Gold values for now to properly emulate. Turreted: ROT: 2 + Armament@PRIMARY: + Weapon: 120mmDual + LocalOffset: -5,-5,0,-10,0, 5,-5,0,-10,0 + Recoil: 4 + RecoilRecovery: 1 + Armament@SECONDARY: + Weapon: MammothMissiles + LocalOffset: -9,2,0,0,25, 9,2,0,0,-25 + Recoil: 1 AttackTurreted: - PrimaryWeapon: 120mmDual - SecondaryWeapon: MammothMissiles - PrimaryLocalOffset: -5,-5,0,-10,0, 5,-5,0,-10,0 - SecondaryLocalOffset: -9,2,0,0,25, 9,2,0,0,-25 - PrimaryRecoil: 4 - SecondaryRecoil: 1 - PrimaryRecoilRecovery: 1 RenderUnitTurreted: AutoTarget: SelfHealing: @@ -405,10 +412,11 @@ MSAM: # In practice, it seems that OpenRA renders vision range differently. Will set at +2 from C&C Gold values for now to properly emulate. Turreted: ROT: 255 + Offset: 0,6,0,-3 + Armament: + Weapon: 227mm + LocalOffset: 3,-5,0,0,0, -3,-5,0,0,0 AttackFrontal: - PrimaryWeapon: 227mm - PrimaryOffset: 0,6,0,-3 - PrimaryLocalOffset: 3,-5,0,0,0, -3,-5,0,0,0 RenderUnitTurretedAim: AutoTarget: Explodes: @@ -438,13 +446,15 @@ MLRS: # In practice, it seems that OpenRA renders vision range differently. Will set at +2 from C&C Gold values for now to properly emulate. Turreted: ROT: 5 + Offset: 0,3,0,-3 + # AlignWhenIdle: true + Armament@PRIMARY: + Weapon: HonestJohn + LocalOffset: -4,0,0,0,0 + Armament@SECONDARY: + Weapon: HonestJohn + LocalOffset: 4,0,0,0,0 AttackFrontal: - PrimaryWeapon: HonestJohn - SecondaryWeapon: HonestJohn - PrimaryOffset: 0,3,0,-3 - PrimaryLocalOffset: -4,0,0,0,0 - SecondaryLocalOffset: 4,0,0,0,0 - # AlignIdleTurrets: true RenderUnitTurretedAim: AutoTarget: Explodes: @@ -478,10 +488,10 @@ STNK: CloakDelay: 125 CloakSound: trans1.aud UncloakSound: appear1.aud + Armament: + Weapon: 227mm.stnk + LocalOffset: 1,-5,0,-3,0, -1,-5,0,-3,0 AttackFrontal: - PrimaryWeapon: 227mm.stnk - PrimaryOffset: 0,-5,0,-3 - PrimaryLocalOffset: 1,0,0,0,0, -1,0,0,0,0 RenderUnit: AutoTarget: InitialStance: HoldFire diff --git a/mods/cnc/rules/aircraft.yaml b/mods/cnc/rules/aircraft.yaml index aa4bf9e50e..e932c49510 100644 --- a/mods/cnc/rules/aircraft.yaml +++ b/mods/cnc/rules/aircraft.yaml @@ -68,13 +68,13 @@ HELI: Type: Light RevealsShroud: Range: 8 + Armament@PRIMARY: + Weapon: HeliAGGun + LocalOffset: -5,-3,0,2,0, 5,-3,0,2,0 + Armament@SECONDARY: + Weapon: HeliAGGun + LocalOffset: -5,-3,0,2,0, 5,-3,0,2,0 AttackHeli: - PrimaryWeapon: HeliAGGun - PrimaryOffset: 0,-3,0,2 - PrimaryLocalOffset: -5,0,0,0,0, 5,0,0,0,0 - SecondaryWeapon: HeliAAGun - SecondaryOffset: 0,-3,0,2 - SecondaryLocalOffset: -5,0,0,0,0, 5,0,0,0,0 FacingTolerance: 20 LimitedAmmo: Ammo: 10 @@ -119,13 +119,13 @@ ORCA: Type: Light RevealsShroud: Range: 8 + Armament@PRIMARY: + Weapon: OrcaAGMissiles + LocalOffset: -4,-10,0,5,0, 4,-10,0,5,0 + Armament@SECONDARY: + Weapon: OrcaAAMissiles + LocalOffset: -4,-10,0,5,0, 4,-10,0,5,0 AttackHeli: - PrimaryWeapon: OrcaAGMissiles - PrimaryOffset: 0,-10,0,5 - PrimaryLocalOffset: -4,0,0,0,0, 4,0,0,0,0 - SecondaryWeapon: OrcaAAMissiles - SecondaryOffset: 0,-10,0,5 - SecondaryLocalOffset: -4,0,0,0,0, 4,0,0,0,0 FacingTolerance: 20 LimitedAmmo: Ammo: 10 diff --git a/mods/cnc/rules/civilian.yaml b/mods/cnc/rules/civilian.yaml index 046d2df6cd..81e020a1d6 100644 --- a/mods/cnc/rules/civilian.yaml +++ b/mods/cnc/rules/civilian.yaml @@ -404,8 +404,9 @@ VICE: Cost: 1000 Tooltip: Name: Viceroid + Armament: + Weapon: Chemspray AttackFrontal: - PrimaryWeapon: Chemspray AttackWander: RenderUnit: WithMuzzleFlash: \ No newline at end of file diff --git a/mods/cnc/rules/defaults.yaml b/mods/cnc/rules/defaults.yaml index f7d4b53413..e5f3e685b6 100644 --- a/mods/cnc/rules/defaults.yaml +++ b/mods/cnc/rules/defaults.yaml @@ -124,7 +124,7 @@ Buildable: Queue: Infantry TakeCover: - BarrelOffset: 0,-2,0,4 + ProneOffset: 0,-2,0,4 RenderInfantryProne: AttackMove: Passenger: @@ -164,8 +164,9 @@ HP: 25 RevealsShroud: Range: 2 + Armament: + Weapon: Pistol AttackFrontal: - PrimaryWeapon: Pistol ActorLostNotification: Notification: civdead1.aud NotifyAll: true diff --git a/mods/cnc/rules/infantry.yaml b/mods/cnc/rules/infantry.yaml index 779e4ab6ab..46e09af527 100644 --- a/mods/cnc/rules/infantry.yaml +++ b/mods/cnc/rules/infantry.yaml @@ -15,8 +15,9 @@ E1: Speed: 4 Health: HP: 50 + Armament: + Weapon: M16 AttackFrontal: - PrimaryWeapon: M16 RenderInfantryProne: IdleAnimations: idle1,idle2,idle3,idle4 DetectCloaked: @@ -40,10 +41,11 @@ E2: Speed: 5 Health: HP: 50 - AttackFrontal: - PrimaryWeapon: Grenade - PrimaryOffset: 0,0,0,-10 + Armament: + Weapon: Grenade + LocalOffset: 0,0,0,-10,0 FireDelay: 15 + AttackFrontal: RenderInfantryProne: IdleAnimations: idle1,idle2 Explodes: @@ -70,10 +72,11 @@ E3: Speed: 3 Health: HP: 45 - AttackFrontal: - PrimaryWeapon: Rockets - PrimaryOffset: 1,-6,0,-8 + Armament: + Weapon: Rockets + LocalOffset: 1,-6,0,-8,0 FireDelay: 5 + AttackFrontal: RenderInfantryProne: IdleAnimations: idle1,idle2 DetectCloaked: @@ -97,10 +100,11 @@ E4: Speed: 5 Health: HP: 90 - AttackFrontal: - PrimaryWeapon: Flamethrower - PrimaryOffset: 0,-2,2,-4 + Armament: + Weapon: Flamethrower + LocalOffset: 0,-2,2,-4,0 FireDelay: 3 + AttackFrontal: WithMuzzleFlash: RenderInfantryProne: IdleAnimations: idle1,idle2 @@ -130,10 +134,11 @@ E5: PathingCost: 80 Health: HP: 90 - AttackFrontal: - PrimaryWeapon: Chemspray - PrimaryOffset: 0,-2,2,-9 + Armament: + Weapon: Chemspray + LocalOffset: 0,-2,2,-9,0 FireDelay: 3 + AttackFrontal: WithMuzzleFlash: -PoisonedByTiberium: RenderInfantryProne: @@ -197,8 +202,9 @@ RMBO: ScanRadius: 5 C4Demolition: C4Delay: 45 + Armament: + Weapon: Sniper AttackFrontal: - PrimaryWeapon: Sniper RenderInfantryProne: IdleAnimations: idle1,idle2,idle3 AnnounceOnBuild: diff --git a/mods/cnc/rules/ships.yaml b/mods/cnc/rules/ships.yaml index 2d06993486..d79930ca1c 100644 --- a/mods/cnc/rules/ships.yaml +++ b/mods/cnc/rules/ships.yaml @@ -18,10 +18,11 @@ BOAT: Range: 7 Turreted: ROT: 7 + Offset: 0,-15,0,-4 + Armament: + Weapon: BoatMissile + LocalOffset: -3,-5,0,0,0, 3,-5,0,0,0, 0,-5,0,0,0 AttackTurreted: - PrimaryWeapon: BoatMissile - PrimaryOffset: 0,-15,0,-4 - PrimaryLocalOffset: -3,-5,0,0,0, 3,-5,0,0,0, 0,-5,0,0,0 RenderGunboat: AutoTarget: AllowMovement: false diff --git a/mods/cnc/rules/structures.yaml b/mods/cnc/rules/structures.yaml index d22ef37875..c6bcdd480f 100644 --- a/mods/cnc/rules/structures.yaml +++ b/mods/cnc/rules/structures.yaml @@ -510,9 +510,10 @@ GUN: ROT: 12 InitialFacing: 50 RenderBuildingTurreted: + Armament: + Weapon: TurretGun + LocalOffset: 0,4,0,-2,0 AttackTurreted: - PrimaryWeapon: TurretGun - PrimaryLocalOffset: 0,4,0,-2,0 AutoTarget: -AutoTargetIgnore: -RenderBuilding: @@ -551,8 +552,9 @@ SAM: ROT: 7 InitialFacing: 0 RenderBuildingTurreted: + Armament: + Weapon: SAMMissile AttackPopupTurreted: - PrimaryWeapon: SAMMissile WithMuzzleFlash: AutoTarget: -RenderBuilding: @@ -585,10 +587,11 @@ OBLI: Range: 8 RenderBuildingCharge: ChargeAudio: obelpowr.aud - AttackTurreted: - PrimaryWeapon: Laser - PrimaryOffset: 0,0,-2,-17 + Armament: + Weapon: Laser + LocalOffset: 0,0,-2,-17,0 FireDelay: 8 + AttackTurreted: Turreted: ROT:255 AutoTarget: @@ -620,10 +623,10 @@ GTWR: HP: 600 RevealsShroud: Range: 7 + Armament: + Weapon: HighV + LocalOffset: 0,-6,0,-6,0 AttackTurreted: - PrimaryWeapon: HighV - PrimaryOffset: 0,0,0,-6 - PrimaryLocalOffset: 0,-6,0,0,0 AutoTarget: -AutoTargetIgnore: DetectCloaked: @@ -659,10 +662,10 @@ ATWR: Type: Heavy RevealsShroud: Range: 9 + Armament: + Weapon: TowerMissle + LocalOffset: 7,-7,5,2,-25, -7,-7,5,2,25 AttackTurreted: - PrimaryWeapon: TowerMissle - PrimaryOffset: 0,0,5,2 - PrimaryLocalOffset: 7,-7,0,0,-25, -7,-7,0,0,25 Turreted: ROT:255 AutoTarget: diff --git a/mods/cnc/rules/vehicles.yaml b/mods/cnc/rules/vehicles.yaml index 8460c76f32..f72bfdd894 100644 --- a/mods/cnc/rules/vehicles.yaml +++ b/mods/cnc/rules/vehicles.yaml @@ -100,13 +100,13 @@ APC: Range: 7 Turreted: ROT: 10 + Armament@PRIMARY: + Weapon: APCGun + LocalOffset: 2,-2,0,-7,0, -2,-2,0,-7,0 + Armament@SECONDARY: + Weapon: APCGun.AA + LocalOffset: 2,-2,0,-7,0, -2,-2,0,-7,0 AttackTurreted: - PrimaryWeapon: APCGun - PrimaryOffset: 0,0,0,0 - PrimaryLocalOffset: 2,-2,0,-7,0, -2,-2,0,-7,0 - SecondaryWeapon: APCGun.AA - SecondaryOffset: 0,0,0,0 - SecondaryLocalOffset: 2,-2,0,-7,0, -2,-2,0,-7,0 WithMuzzleFlash: RenderUnitTurreted: AutoTarget: @@ -139,9 +139,10 @@ ARTY: Type: Light RevealsShroud: Range: 9 + Armament: + Weapon: ArtilleryShell + LocalOffset: 0,-7,0,-3,0 AttackFrontal: - PrimaryWeapon: ArtilleryShell - PrimaryOffset: 0,-7,0,-3 RenderUnit: Explodes: AutoTarget: @@ -170,10 +171,10 @@ FTNK: Type: Light RevealsShroud: Range: 5 + Armament: + Weapon: BigFlamer + LocalOffset: 5,-5,3,2,0, -5,-5,3,2,0 AttackFrontal: - PrimaryWeapon: BigFlamer - PrimaryOffset: 0,-5,3,2 - PrimaryLocalOffset: 5,0,0,0,0, -5,0,0,0,0 RenderUnit: AutoTarget: WithMuzzleFlash: @@ -206,9 +207,10 @@ BGGY: Range: 7 Turreted: ROT: 10 + Offset: 0,1,0,-3 + Armament: + Weapon: MachineGun AttackTurreted: - PrimaryWeapon: MachineGun - PrimaryOffset: 0,1,0,-3 WithMuzzleFlash: RenderUnitTurreted: AutoTarget: @@ -243,10 +245,10 @@ BIKE: Type: Light RevealsShroud: Range: 8 + Armament: + Weapon: BikeRockets + LocalOffset: -4,0,0,-2,25, 4,0,0,-2,-25 AttackFrontal: - PrimaryWeapon: BikeRockets - PrimaryOffset: 0,0,0,-2 - PrimaryLocalOffset: -4,0,0,0,25, 4,0,0,0,-25 RenderUnit: AutoTarget: LeavesHusk: @@ -275,9 +277,10 @@ JEEP: Range: 8 Turreted: ROT: 10 + Offset: 0,2,0,-4 + Armament: + Weapon: MachineGun AttackTurreted: - PrimaryWeapon: MachineGun - PrimaryOffset: 0,2,0,-4 WithMuzzleFlash: RenderUnitTurreted: AutoTarget: @@ -307,11 +310,12 @@ LTNK: Range: 6 Turreted: ROT: 5 + Armament: + Weapon: 70mm + Recoil: 2 + RecoilRecovery: 0.4 + LocalOffset: 0,3,0,-2,0 AttackTurreted: - PrimaryWeapon: 70mm - PrimaryRecoil: 2 - PrimaryRecoilRecovery: 0.4 - PrimaryLocalOffset: 0,3,0,-2,0 RenderUnitTurreted: AutoTarget: LeavesHusk: @@ -333,7 +337,6 @@ MTNK: Prerequisites: hq Owner: gdi Mobile: - Speed: 6 Health: HP: 400 @@ -343,11 +346,12 @@ MTNK: Range: 6 Turreted: ROT: 5 + Armament: + Weapon: 120mm + Recoil: 3 + RecoilRecovery: 0.6 + LocalOffset: 0,0,0,-1,0 AttackTurreted: - PrimaryWeapon: 120mm - PrimaryRecoil: 3 - PrimaryRecoilRecovery: 0.6 - PrimaryLocalOffset: 0,0,0,-1,0 RenderUnitTurreted: AutoTarget: LeavesHusk: @@ -381,14 +385,16 @@ HTNK: Range: 6 Turreted: ROT: 2 + Armament@PRIMARY: + Weapon: 120mmDual + LocalOffset: -5,-5,0,-10,0, 5,-5,0,-10,0 + Recoil: 4 + RecoilRecovery: 1 + Armament@SECONDARY: + Weapon: MammothMissiles + LocalOffset: -9,2,0,0,25, 9,2,0,0,-25 + Recoil: 1 AttackTurreted: - PrimaryWeapon: 120mmDual - SecondaryWeapon: MammothMissiles - PrimaryLocalOffset: -5,-5,0,-10,0, 5,-5,0,-10,0 - SecondaryLocalOffset: -9,2,0,0,25, 9,2,0,0,-25 - PrimaryRecoil: 4 - SecondaryRecoil: 1 - PrimaryRecoilRecovery: 1 RenderUnitTurreted: AutoTarget: SelfHealing: @@ -425,10 +431,11 @@ MSAM: Range: 10 Turreted: ROT: 255 + Offset: 0,6,0,-3 + Armament: + Weapon: 227mm + LocalOffset: 3,-5,0,0,0, -3,-5,0,0,0 AttackFrontal: - PrimaryWeapon: 227mm - PrimaryOffset: 0,6,0,-3 - PrimaryLocalOffset: 3,-5,0,0,0, -3,-5,0,0,0 RenderUnitTurretedAim: AutoTarget: LeavesHusk: @@ -456,11 +463,15 @@ MLRS: Range: 10 Turreted: ROT: 5 + Offset: 0,3,0,-3 + AlignWhenIdle: true + Armament@PRIMARY: + Weapon: Patriot + LocalOffset: -4,0,0,0,0 + Armament@SECONDARY: + Weapon: Patriot + LocalOffset: 4,0,0,0,0 AttackTurreted: - PrimaryWeapon: Patriot - PrimaryOffset: 0,3,0,-3 - PrimaryLocalOffset: -4,0,0,0,0, 4,0,0,0,0 - AlignIdleTurrets: true RenderUnitTurretedAim: AutoTarget: Explodes: @@ -497,10 +508,10 @@ STNK: CloakDelay: 80 CloakSound: trans1.aud UncloakSound: trans1.aud + Armament: + Weapon: 227mm.stnk + LocalOffset: 1,-5,0,-3,0, -1,-5,0,-3,0 AttackFrontal: - PrimaryWeapon: 227mm.stnk - PrimaryOffset: 0,-5,0,-3 - PrimaryLocalOffset: 1,0,0,0,0, -1,0,0,0,0 RenderUnit: AutoTarget: InitialStance: HoldFire diff --git a/mods/d2k/rules/aircraft.yaml b/mods/d2k/rules/aircraft.yaml index 65905d635b..3bbea60e52 100644 --- a/mods/d2k/rules/aircraft.yaml +++ b/mods/d2k/rules/aircraft.yaml @@ -82,9 +82,10 @@ ORNI: Type: Light RevealsShroud: Range: 10 + Armament: + Weapon: ChainGun + LocalOffset: -5,-2,0,2,0 AttackHeli: - PrimaryWeapon: ChainGun - PrimaryOffset: -5,-2,0,2 FacingTolerance: 20 Helicopter: LandWhenIdle: false diff --git a/mods/d2k/rules/atreides.yaml b/mods/d2k/rules/atreides.yaml index d0b32bde23..1ed244ec1c 100644 --- a/mods/d2k/rules/atreides.yaml +++ b/mods/d2k/rules/atreides.yaml @@ -143,11 +143,12 @@ COMBATA: Prerequisites: heavya Owner: atreides BuiltAt: heavya + Armament: + Weapon: 90mma + Recoil: 4 + RecoilRecovery: 0.8 + LocalOffset: 0,-2,0,-3,0 AttackTurreted: - PrimaryWeapon: 90mma - PrimaryRecoil: 4 - PrimaryRecoilRecovery: 0.8 - PrimaryLocalOffset: 0,-2,0,-3,0 RenderUnitTurreted: Image: COMBATA LeavesHusk: @@ -196,9 +197,10 @@ SONICTANK: Range: 6 RenderUnit: Image: SONICTANK + Armament: + Weapon: TTankZap + LocalOffset: 0,-15,0,-10,0 AttackFrontal: - PrimaryWeapon: TTankZap - PrimaryLocalOffset: 0,-15,0,-10,0 AutoTarget: InitialStance: Defend Explodes: @@ -239,8 +241,9 @@ FREMEN: Range: 7 AutoTarget: ScanRadius: 7 + Armament: + Weapon: Sniper AttackFrontal: - PrimaryWeapon: Sniper RenderInfantryProne: -RenderInfantry: TakeCover: diff --git a/mods/d2k/rules/harkonnen.yaml b/mods/d2k/rules/harkonnen.yaml index 4f1c30be0a..a075e72be4 100644 --- a/mods/d2k/rules/harkonnen.yaml +++ b/mods/d2k/rules/harkonnen.yaml @@ -38,9 +38,10 @@ REFH: # Mobile: # ROT: 9 # Speed: 11 +# Armament: +# Weapon: M60mg +# LocalOffset: 0,-1,0,-3,0 # AttackFrontal: -# PrimaryWeapon: M60mg -# PrimaryLocalOffset: 0,-1,0,-3,0 # RenderUnit: # Image: QUAD @@ -213,9 +214,10 @@ DEVAST: RevealsShroud: Range: 7 RenderUnit: + Armament: + Weapon: 120mm + LocalOffset: 5,-16,0,-2,0, -4,-16,0,-2,0 AttackFrontal: - PrimaryWeapon: 120mm - PrimaryLocalOffset: 5,-16,0,-2,0, -4,-16,0,-2,0 AutoTarget: InitialStance: Defend Explodes: @@ -260,6 +262,8 @@ SARDAUKAR: TakeCover: -RenderInfantry: RenderInfantryProne: - AttackFrontal: - PrimaryWeapon: Vulcan - SecondaryWeapon: Slung \ No newline at end of file + Armament@PRIMARY: + Weapon: Vulcan + Armament@SECONDARY: + Weapon: Slung + AttackFrontal: \ No newline at end of file diff --git a/mods/d2k/rules/infantry.yaml b/mods/d2k/rules/infantry.yaml index 3e082b3a6b..96b5d2eb37 100644 --- a/mods/d2k/rules/infantry.yaml +++ b/mods/d2k/rules/infantry.yaml @@ -16,8 +16,9 @@ RIFLE: HP: 50 Mobile: Speed: 5 + Armament: + Weapon: M1Carbine AttackFrontal: - PrimaryWeapon: M1Carbine TakeCover: -RenderInfantry: RenderInfantryProne: @@ -69,10 +70,13 @@ BAZOOKA: HP: 45 Mobile: Speed: 4 + Armament@PRIMARY: + Weapon: RedEye + LocalOffset: 0,0,0,-13,0 + Armament@SECONDARY: + Weapon: Dragon + LocalOffset: 0,0,0,-13,0 AttackFrontal: - PrimaryWeapon: RedEye - SecondaryWeapon: Dragon - PrimaryOffset: 0,0,0,-13 TakeCover: -RenderInfantry: RenderInfantryProne: @@ -100,8 +104,9 @@ MEDIC: Mobile: Speed: 4 AutoHeal: + Armament: + Weapon: Heal AttackMedic: - PrimaryWeapon: Heal Passenger: PipType: Blue -AutoTarget: diff --git a/mods/d2k/rules/ordos.yaml b/mods/d2k/rules/ordos.yaml index 921ea2ba56..5260429370 100644 --- a/mods/d2k/rules/ordos.yaml +++ b/mods/d2k/rules/ordos.yaml @@ -158,10 +158,10 @@ TRIKEO: Speed: 14 RenderUnit: Image: RAIDER + Armament: + Weapon: M60mgo + LocalOffset: 0,-6,0,-3,0 AttackFrontal: - PrimaryWeapon: M60mgo - PrimaryOffset: 0,-6,0,-3 - #PrimaryLocalOffset: 1,0,0,-3,0, -1,0,0,-3,0 @@ -212,9 +212,10 @@ DEVIATORTANK: RevealsShroud: Range: 5 RenderUnit: + Armament: + Weapon: FakeMissile + LocalOffset: 0,7,0,-2,0 #7 AttackLoyalty: - PrimaryWeapon: FakeMissile - PrimaryLocalOffset: 0,7,0,-2,0 #7 AutoTarget: InitialStance: Defend Explodes: diff --git a/mods/d2k/rules/structures.yaml b/mods/d2k/rules/structures.yaml index 6c4fa4720d..e65417c105 100644 --- a/mods/d2k/rules/structures.yaml +++ b/mods/d2k/rules/structures.yaml @@ -474,9 +474,10 @@ GUNTOWER: Turreted: ROT: 6 InitialFacing: 128 + Armament: + Weapon: TurretGun + LocalOffset: 0,-11,0,-7,0 AttackTurreted: - PrimaryWeapon: TurretGun - PrimaryLocalOffset: 0,-11,0,-7,0 AutoTarget: LeavesHusk: HuskActor: Guntower.Husk @@ -529,9 +530,10 @@ ROCKETTOWER: #-AutoTargetIgnore: RenderBuildingSeparateTurret: # HasMakeAnimation: false + Armament: + Weapon: TowerMissile + LocalOffset: 14,-2,0,-11,0, -14,-2,0,-11,0 AttackTurreted: - PrimaryWeapon: TowerMissile - PrimaryLocalOffset: 14,-2,0,-11,0, -14,-2,0,-11,0 Turreted: ROT: 8 InitialFacing: 128 diff --git a/mods/d2k/rules/system.yaml b/mods/d2k/rules/system.yaml index 249ccc16e9..7d0dd0623b 100644 --- a/mods/d2k/rules/system.yaml +++ b/mods/d2k/rules/system.yaml @@ -541,8 +541,9 @@ SPICEBLOOM: # AttackMove: # JustMove: true # AttackWander: +# Armament: +# Weapon: WormJaw # AttackLeap: -# PrimaryWeapon: WormJaw # CanAttackGround: no # RenderInfantry: # BelowUnits: diff --git a/mods/d2k/rules/vehicles.yaml b/mods/d2k/rules/vehicles.yaml index cc26f42ab6..6041a96efa 100644 --- a/mods/d2k/rules/vehicles.yaml +++ b/mods/d2k/rules/vehicles.yaml @@ -131,10 +131,10 @@ HARVESTER.starport: Range: 8 RenderUnit: WithMuzzleFlash: + Armament: + Weapon: M60mg + LocalOffset: 0,-6,0,-3, 0 AttackFrontal: - PrimaryWeapon: M60mg - PrimaryOffset: 0,-6,0,-3 - #PrimaryLocalOffset: 1,-1,0,-3,0, -1,-1,0,-3,0 AutoTarget: InitialStance: Defend Explodes: @@ -172,9 +172,10 @@ QUAD: Range: 7 RenderUnit: Image: QUAD + Armament: + Weapon: QuadRockets + LocalOffset: 0,-3,0,-2,0 #-4 AttackFrontal: - PrimaryWeapon: QuadRockets - PrimaryLocalOffset: 0,-3,0,-2,0 #-4 AutoTarget: InitialStance: Defend Explodes: @@ -213,12 +214,13 @@ QUAD.starport: Range: 6 Turreted: ROT: 6 + AlignWhenIdle: true + Armament: + Weapon: 90mm + Recoil: 4 + RecoilRecovery: 0.8 + LocalOffset: 0,-2,0,-3,0 AttackTurreted: - AlignIdleTurrets: true - PrimaryWeapon: 90mm - PrimaryRecoil: 4 - PrimaryRecoilRecovery: 0.8 - PrimaryLocalOffset: 0,-2,0,-3,0 RenderUnitTurreted: AutoTarget: InitialStance: Defend @@ -265,11 +267,12 @@ SIEGETANK: Range: 5 Turreted: ROT: 3 + Armament: + Weapon: 155mm + Recoil: 7 + RecoilRecovery: 0.45 + LocalOffset: 0,-4,0,-7,0 AttackFrontal: - PrimaryWeapon: 155mm - PrimaryRecoil: 7 - PrimaryRecoilRecovery: 0.45 - PrimaryLocalOffset: 0,-4,0,-7,0 RenderUnitTurreted: Image: SIEGETANK Explodes: @@ -328,9 +331,10 @@ MISSILETANK: Range: 6 RenderUnit: Image: MISSILETANK + Armament: + Weapon: 227mm + LocalOffset: 3,5,0,-4,0, -6,5,0,-4,0 AttackFrontal: - PrimaryWeapon: 227mm - PrimaryLocalOffset: 3,5,0,-4,0, -6,5,0,-4,0 AutoTarget: InitialStance: Defend Explodes: diff --git a/mods/ra-classic/rules/aircraft.yaml b/mods/ra-classic/rules/aircraft.yaml index df66667650..212037e996 100644 --- a/mods/ra-classic/rules/aircraft.yaml +++ b/mods/ra-classic/rules/aircraft.yaml @@ -83,9 +83,10 @@ MIG: Type: Light RevealsShroud: Range: 12 + Armament: + Weapon: Maverick + LocalOffset: -15,0,0,0,-10, 15,0,0,0,6 AttackPlane: - PrimaryWeapon: Maverick - PrimaryLocalOffset: -15,0,0,0,-10, 15,0,0,0,6 FacingTolerance: 20 Plane: InitialFacing: 192 @@ -127,11 +128,13 @@ YAK: Type: Light RevealsShroud: Range: 10 + Armament@PRIMARY: + Weapon: ChainGun + LocalOffset: -5,-6,0,0,0 + Armament@SECONDARY: + Weapon: ChainGun + LocalOffset: 5,-6,0,0,0 AttackPlane: - PrimaryWeapon: ChainGun - SecondaryWeapon: ChainGun - PrimaryOffset: -5,-6,0,0 - SecondaryOffset: 5,-6,0,0 FacingTolerance: 20 Plane: RearmBuildings: afld @@ -215,9 +218,10 @@ HELI: Type: Heavy RevealsShroud: Range: 12 + Armament: + Weapon: HellfireAG + LocalOffset: -5,0,0,2,0 AttackHeli: - PrimaryWeapon: HellfireAG - PrimaryOffset: -5,0,0,2 FacingTolerance: 20 Helicopter: RearmBuildings: hpad @@ -256,11 +260,13 @@ HIND: Type: Heavy RevealsShroud: Range: 10 + Armament@PRIMARY: + Weapon: ChainGun + LocalOffset: -5,-2,0,2,0 + Armament@SECONDARY: + Weapon: ChainGun + LocalOffset: 5,-2,0,2,0 AttackHeli: - PrimaryWeapon: ChainGun - SecondaryWeapon: ChainGun - PrimaryOffset: -5,-2,0,2 - SecondaryOffset: 5,-2,0,2 FacingTolerance: 20 Helicopter: RearmBuildings: hpad diff --git a/mods/ra-classic/rules/defaults.yaml b/mods/ra-classic/rules/defaults.yaml index ad82b4119e..5c7bd24429 100644 --- a/mods/ra-classic/rules/defaults.yaml +++ b/mods/ra-classic/rules/defaults.yaml @@ -249,8 +249,9 @@ Speed: 4 RevealsShroud: Range: 2 + Armament: + Weapon: Pistol AttackFrontal: - PrimaryWeapon: Pistol ProximityCaptor: Types:CivilianInfantry -RenderInfantry: diff --git a/mods/ra-classic/rules/infantry.yaml b/mods/ra-classic/rules/infantry.yaml index 1079d02e8b..f2f9ad31b9 100644 --- a/mods/ra-classic/rules/infantry.yaml +++ b/mods/ra-classic/rules/infantry.yaml @@ -20,8 +20,9 @@ DOG: RevealsShroud: Range: 5 AutoTarget: + Armament: + Weapon: DogJaw AttackLeap: - PrimaryWeapon: DogJaw CanAttackGround: no RenderInfantry: IdleAnimations: idle1,idle2 @@ -44,8 +45,9 @@ E1: HP: 50 Mobile: Speed: 4 + Armament: + Weapon: M1Carbine AttackFrontal: - PrimaryWeapon: M1Carbine TakeCover: -RenderInfantry: RenderInfantryProne: @@ -69,10 +71,11 @@ E2: HP: 50 Mobile: Speed: 5 - AttackFrontal: - PrimaryWeapon: Grenade - PrimaryOffset: 0,0,0,-13 + Armament: + Weapon: Grenade + LocalOffset: 0,0,0,-13,0 FireDelay: 15 + AttackFrontal: TakeCover: -RenderInfantry: RenderInfantryProne: @@ -98,10 +101,13 @@ E3: HP: 45 Mobile: Speed: 3 + Armament@PRIMARY: + Weapon: RedEye + LocalOffset: 0,0,0,-13,0 + Armament@SECONDARY: + Weapon: Dragon + LocalOffset: 0,0,0,-13,0 AttackFrontal: - PrimaryWeapon: RedEye - SecondaryWeapon: Dragon - PrimaryOffset: 0,0,0,-13 TakeCover: -RenderInfantry: RenderInfantryProne: @@ -125,10 +131,11 @@ E4: HP: 40 Mobile: Speed: 3 - AttackFrontal: - PrimaryWeapon: Flamer - PrimaryOffset: 0,-10,0,-8 + Armament: + Weapon: Flamer + LocalOffset: 0,-10,0,-8,0 FireDelay: 8 + AttackFrontal: TakeCover: -RenderInfantry: RenderInfantryProne: @@ -254,9 +261,11 @@ E7: C4Delay: 45 Passenger: PipType: Red + Armament@PRIMARY: + Weapon: Colt45 + Armament@SECONDARY: + Weapon: Colt45 AttackFrontal: - PrimaryWeapon: Colt45 - SecondaryWeapon: Colt45 TakeCover: -RenderInfantry: RenderInfantryProne: @@ -286,8 +295,9 @@ MEDI: Passenger: PipType: Yellow AutoHeal: + Armament: + Weapon: Heal AttackMedic: - PrimaryWeapon: Heal TakeCover: -AutoTarget: AttackMove: @@ -320,8 +330,9 @@ MECH: Passenger: PipType: Yellow AutoHeal: + Armament: + Weapon: Repair AttackMedic: - PrimaryWeapon: Repair TakeCover: -AutoTarget: AttackMove: @@ -371,9 +382,10 @@ SHOK: Speed: 3 RevealsShroud: Range: 4 + Armament: + Weapon: PortaTesla + LocalOffset: 0,-10,0,-8,0 AttackFrontal: - PrimaryWeapon: PortaTesla - PrimaryOffset: 0,-10,0,-8 TakeCover: -RenderInfantry: RenderInfantryProne: diff --git a/mods/ra-classic/rules/ships.yaml b/mods/ra-classic/rules/ships.yaml index 124aab938b..33b1f9fc9b 100644 --- a/mods/ra-classic/rules/ships.yaml +++ b/mods/ra-classic/rules/ships.yaml @@ -30,10 +30,11 @@ SS: CloakDelay: 50 CloakSound: subshow1.aud UncloakSound: subshow1.aud - AttackFrontal: - PrimaryWeapon: TorpTube - PrimaryLocalOffset: -4,0,0,0,0, 4,0,0,0,0 + Armament: + Weapon: TorpTube + LocalOffset: -4,0,0,0,0, 4,0,0,0,0 FireDelay: 2 + AttackFrontal: Selectable: Bounds: 38,38 Chronoshiftable: @@ -76,9 +77,10 @@ MSUB: CloakDelay: 100 CloakSound: subshow1.aud UncloakSound: subshow1.aud - AttackFrontal: - PrimaryWeapon: SubMissile + Armament: + Weapon: SubMissile FireDelay: 2 + AttackFrontal: Selectable: Bounds: 44,44 Chronoshiftable: @@ -113,11 +115,14 @@ DD: Range: 6 Turreted: ROT: 7 + Offset: 0,-8,0,-3 + Armament@PRIMARY: + Weapon: Stinger + LocalOffset: -4,0,0,0,-20, 4,0,0,0,20 + Armament@SECONDARY: + Weapon: DepthCharge + LocalOffset: -4,0,0,0,-20, 4,0,0,0,20 AttackTurreted: - PrimaryWeapon: Stinger - SecondaryWeapon: DepthCharge - PrimaryOffset: 0,-8,0,-3 - PrimaryLocalOffset: -4,0,0,0,-20, 4,0,0,0,20 Selectable: Bounds: 38,38 RenderUnitTurreted: @@ -151,19 +156,27 @@ CA: Speed: 4 RevealsShroud: Range: 7 - Turreted: + Turreted@PRIMARY: + Turret: primary + Offset: 0,17,0,-2 ROT: 3 + Turreted@SECONDARY: + Turret: secondary + Offset: 0,-17,0,-2 + ROT: 3 + Armament@PRIMARY: + Turret: primary + Weapon: 8Inch + LocalOffset: -4,-5,0,0,0, 4,-5,0,0,0 + Recoil: 4 + RecoilRecovery: 0.8 + Armament@SECONDARY: + Turret: secondary + Weapon: 8Inch + LocalOffset: -4,-5,0,0,0, 4,-5,0,0,0 + Recoil: 4 + RecoilRecovery: 0.8 AttackTurreted: - PrimaryWeapon: 8Inch - SecondaryWeapon: 8Inch - PrimaryOffset: 0,17,0,-2 - SecondaryOffset: 0,-17,0,-2 - PrimaryLocalOffset: -4,-5,0,0,0, 4,-5,0,0,0 - SecondaryLocalOffset: -4,-5,0,0,0, 4,-5,0,0,0 - PrimaryRecoil: 4 - SecondaryRecoil: 4 - PrimaryRecoilRecovery: 0.8 - SecondaryRecoilRecovery: 0.8 Selectable: Bounds: 44,44 RenderUnitTurreted: @@ -226,10 +239,12 @@ PT: Range: 7 Turreted: ROT: 7 + Offset: 0,-6,0,-1 + Armament@PRIMARY: + Weapon: 2Inch + Armament@SECONDARY: + Weapon: DepthCharge AttackTurreted: - PrimaryWeapon: 2Inch - SecondaryWeapon: DepthCharge - PrimaryOffset: 0,-6,0,-1 Selectable: Bounds: 32,32 RenderUnitTurreted: diff --git a/mods/ra-classic/rules/structures.yaml b/mods/ra-classic/rules/structures.yaml index 1bbfced3e2..c9ca061999 100644 --- a/mods/ra-classic/rules/structures.yaml +++ b/mods/ra-classic/rules/structures.yaml @@ -315,10 +315,11 @@ TSLA: RevealsShroud: Range: 8 RenderBuildingCharge: + Armament: + Weapon: TeslaZap + LocalOffset: 0,0,0,-10,0 AttackTesla: - PrimaryWeapon: TeslaZap ReloadTime: 120 - PrimaryOffset: 0,0,0,-10 AutoTarget: IronCurtainable: -RenderBuilding: @@ -354,9 +355,11 @@ AGUN: ROT: 15 InitialFacing: 224 RenderBuildingTurreted: + Armament@PRIMARY: + Weapon: ZSU-23 + Armament@SECONDARY: + Weapon: ZSU-23 AttackTurreted: - PrimaryWeapon: ZSU-23 - SecondaryWeapon: ZSU-23 AutoTarget: IronCurtainable: -RenderBuilding: @@ -419,9 +422,10 @@ PBOX: IronCurtainable: RenderRangeCircle: AutoTarget: + Armament: + Weapon: Vulcan + LocalOffset: 0,-11,0,0,0 AttackTurreted: - PrimaryWeapon: Vulcan - PrimaryLocalOffset: 0,-11,0,0,0 WithMuzzleFlash: Turreted: ROT: 255 @@ -452,9 +456,10 @@ HBOX: IronCurtainable: RenderRangeCircle: AutoTarget: + Armament: + Weapon: Vulcan + LocalOffset: 0,-11,0,0,0 AttackTurreted: - PrimaryWeapon: Vulcan - PrimaryLocalOffset: 0,-11,0,0,0 WithMuzzleFlash: Turreted: ROT: 255 @@ -485,8 +490,9 @@ GUN: ROT: 12 InitialFacing: 50 RenderBuildingTurreted: + Armament: + Weapon: TurretGun AttackTurreted: - PrimaryWeapon: TurretGun AutoTarget: IronCurtainable: -RenderBuilding: @@ -516,10 +522,11 @@ FTUR: Range: 6 Turreted: ROT: 255 + Offset: 0,0,0,-2 + Armament: + Weapon: FireballLauncher + LocalOffset: 0,-12,0,0,0 AttackTurreted: - PrimaryWeapon: FireballLauncher - PrimaryOffset: 0,0,0,-2 - PrimaryLocalOffset: 0,-12,0,0,0 AutoTarget: IronCurtainable: RenderRangeCircle: @@ -552,8 +559,9 @@ SAM: ROT: 30 InitialFacing: 0 RenderBuildingTurreted: + Armament: + Weapon: Nike AttackTurreted: - PrimaryWeapon: Nike WithMuzzleFlash: AutoTarget: IronCurtainable: diff --git a/mods/ra-classic/rules/vehicles.yaml b/mods/ra-classic/rules/vehicles.yaml index e90d246c3c..fb71ff842a 100644 --- a/mods/ra-classic/rules/vehicles.yaml +++ b/mods/ra-classic/rules/vehicles.yaml @@ -18,8 +18,9 @@ V2RL: Speed: 7 RevealsShroud: Range: 5 + Armament: + Weapon: SCUD AttackFrontal: - PrimaryWeapon: SCUD RenderUnitReload: AutoTarget: Explodes: @@ -48,10 +49,11 @@ V2RL: Range: 4 Turreted: ROT: 5 + Armament: + Weapon: 25mm + Recoil: 2 + RecoilRecovery: 0.5 AttackTurreted: - PrimaryWeapon: 25mm - PrimaryRecoil: 2 - PrimaryRecoilRecovery: 0.5 RenderUnitTurreted: AutoTarget: Explodes: @@ -80,10 +82,11 @@ V2RL: Range: 5 Turreted: ROT: 5 + Armament: + Weapon: 90mm + Recoil: 3 + RecoilRecovery: 0.9 AttackTurreted: - PrimaryWeapon: 90mm - PrimaryRecoil: 3 - PrimaryRecoilRecovery: 0.9 RenderUnitTurreted: AutoTarget: Explodes: @@ -114,11 +117,12 @@ V2RL: Range: 5 Turreted: ROT: 5 + Armament: + Weapon: 105mm + Recoil: 3 + RecoilRecovery: 0.9 + LocalOffset: 2,0,0,0,0, -2,0,0,0,0 AttackTurreted: - PrimaryWeapon: 105mm - PrimaryRecoil: 3 - PrimaryRecoilRecovery: 0.9 - PrimaryLocalOffset: 2,0,0,0,0, -2,0,0,0,0 RenderUnitTurreted: AutoTarget: Explodes: @@ -150,13 +154,15 @@ V2RL: Range: 6 Turreted: ROT: 2 + Armament@PRIMARY: + Weapon: 120mm + LocalOffset: -4,-5,0,0,0, 4,-5,0,0,0 + Recoil: 4 + RecoilRecovery: 0.7 + Armament@SECONDARY: + Weapon: MammothTusk + LocalOffset: -7,2,0,0,25, 7,2,0,0,-25 AttackTurreted: - PrimaryWeapon: 120mm - SecondaryWeapon: MammothTusk - PrimaryLocalOffset: -4,-5,0,0,0, 4,-5,0,0,0 - SecondaryLocalOffset: -7,2,0,0,25, 7,2,0,0,-25 - PrimaryRecoil: 4 - PrimaryRecoilRecovery: 0.7 RenderUnitTurreted: AutoTarget: Explodes: @@ -190,8 +196,9 @@ ARTY: Speed: 6 RevealsShroud: Range: 5 + Armament: + Weapon: 155mm AttackFrontal: - PrimaryWeapon: 155mm RenderUnit: Explodes: Weapon: UnitExplode @@ -298,9 +305,10 @@ JEEP: Range: 6 Turreted: ROT: 10 + Offset: 0,0,0,-2 + Armament: + Weapon: M60mg AttackTurreted: - PrimaryWeapon: M60mg - PrimaryOffset: 0,0,0,-2 WithMuzzleFlash: RenderUnitTurreted: Explodes: @@ -328,9 +336,10 @@ APC: Crushes: wall, atmine, crate, infantry RevealsShroud: Range: 5 + Armament: + Weapon: M60mg + LocalOffset: 0,0,0,-4,0 AttackFrontal: - PrimaryWeapon: M60mg - PrimaryOffset: 0,0,0,-4 RenderUnit: WithMuzzleFlash: AutoTarget: @@ -434,9 +443,10 @@ TTNK: Crushes: wall, atmine, crate, infantry RevealsShroud: Range: 7 + Armament: + Weapon: TTankZap + LocalOffset: 0,0,0,-5,0 AttackFrontal: - PrimaryWeapon: TTankZap - PrimaryOffset: 0,0,0,-5 RenderUnitSpinner: Selectable: Bounds: 28,28,0,0 @@ -500,10 +510,12 @@ CTNK: Range: 6 RenderUnit: AutoTarget: + Armament@PRIMARY: + Weapon: ChronoTusk + LocalOffset: -4,0,0,0,0, -4,0,0,0,0 + Armament@SECONDARY: + Weapon: ChronoTusk + LocalOffset: 4,0,0,0,25, 4,0,0,0,-25 AttackFrontal: - PrimaryWeapon: ChronoTusk - SecondaryWeapon: ChronoTusk - PrimaryLocalOffset: -4,0,0,0,0, -4,0,0,0,0 - SecondaryLocalOffset: 4,0,0,0,25, 4,0,0,0,-25 ChronoshiftDeploy: EmptyWeapon: UnitExplodeSmall \ No newline at end of file diff --git a/mods/ra/maps/bomber-john.oramap b/mods/ra/maps/bomber-john.oramap deleted file mode 100644 index 69d5763f515248046fac87cca7eea066eb47e508..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6889 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 G+W!GMA(RLJ diff --git a/mods/ra/maps/bomber-john/brick.shp b/mods/ra/maps/bomber-john/brick.shp new file mode 100755 index 0000000000000000000000000000000000000000..9f900584125a903d102fa29b516c03f1cd021ea0 GIT binary patch literal 86 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 R6E__Kt3mL&n;Cye+J9dIXpsN_ literal 0 HcmV?d00001 diff --git a/mods/ra/maps/drop-zone-battle-of-tikiaki.oramap b/mods/ra/maps/drop-zone-battle-of-tikiaki.oramap deleted file mode 100644 index e760d57bbd4e111b8b3e7420536018779b5c5cb4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3124 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 diff --git a/mods/ra/maps/drop-zone-w/map.bin b/mods/ra/maps/drop-zone-w/map.bin new file mode 100755 index 0000000000000000000000000000000000000000..5924bbf570895aab6ba88aae1c943a4cccf118af GIT binary patch literal 20485 zcmeI0+iDw05QhKm(MY!AoUo)f5W2I#%FPA`M1<{N$HwO)#wJ(0?-2B^c>q0w_OJP; zTgvXtSy0aw5ka0OfeSHKl;1zdsuRv-cqMY33R z;sfx2c!6+%Ry7lDKxw#iFxVw3>b& zsrW5~KP(XOhX>G#3k#vFCJ9ff@*3e9#TCL8ic5q`6t@VsMjnP}4beGAI7gvipMWRC z=J_dps2~Y1eg-0|x1-tu&d`lUf331p$2&wEq8wr)ZI%W5gz&^&X!w0F<&W6NqgdDy zl0%wkH59*E1tK50ab8O{{BE`${dqgW&@zCSIb=ukY83_jZRyCYxC8F$NVBIod^cO0 z{-#((B{s<@cv8u1=^nU8JOmCAj}VT~xS$d(A%6g0%(7d3;kxplS{2Ib1KH3?gD+pA5NRk|0%*0tykbRl?0E#qa}k-v#MgYSSn+u&=WdAm{^Q?Ne(ze zJVWF4!xV9f@)hAVl?0Eq)Ryg)nV75Cd8iC|2A-E$r>nvlXvG=Irhk7`aV5=HfwSP8 z6hB)|a;S)y9+n}`2+zx`<0|#fhyOafPPGF3(C?^%aq(BdzIru9#WO=eM&+RQ>%LJECt-Ok*R3>rKE??Of%`h(WZ=PSbBYYg89ATqxKl^Io*L2ke<*#Q^01n*+QZBaG1+qf
IuDl?; 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 Ecgw=)M*si- diff --git a/mods/ra/maps/drop-zone/map.bin b/mods/ra/maps/drop-zone/map.bin new file mode 100755 index 0000000000000000000000000000000000000000..5def5e9738ad06dc5990947043a410b6691b7c0e GIT binary patch literal 20485 zcmeI0%}yIj5QR_Ak8MmGzf#@`!p`0S8(;%$fE_I0MdrGvEyTKLc0Nm5OueJkMv+ zS+-aG7t%%ce~wx8q{vI@QpLKzN3ImERGurG=lM+GEZeL83x$j9{~WXGNs*Tdmnzqd ze^1&omNph@E!116UZ@{0yV0g<7|g70#wB8^h20Vs>O{L8V-nRki6p*rBAu+C|2>60 zV=3YJve4HEETzL`!VDgg!e;btRo<#~YbkdgmiKZONfDM9;Ku%m!pZvi-y`YwQtpZPpF&E-D|25=XVv`_teX4M}e*Sl*T?5H;`;Q8b#yP;2vXAhr98U^Q z1_o?al;|fxT9fVKoH($l0%17WyiN3nHA}Ij7dbC8AsFF4!q>X_zP&u$wNG3Z< zLl&f9$>zjU3*x6N!DjkT?*9M-5=;UQ0N8-3wxlf;KMi~ss2Zq^{oMvJM3O0C7~E(T zj5bwZ^qc8Fx&QO%-m~<))Dki<&z8cL%AW?l7^ohogZmT0Wzx$%_vT|$<6^5#Y zYR?pAs%C2cW8jz0bpDQ2j8%`9{U7Dn=4EcC|788cKVm3eY+%&s*cz%BsvfE{Q!!IL ziy%Loz%vl+E;?{QhHt$uQCew8ogF-dX9NANoi6YzM;+;c??oK?H^l z=}z5d`cHoUN&4?Z7}y8^MTKo?`&0kik#-Cr;6Y0;ksNU8bT;HMBi`Sdc>l@zheo7Z zW*A^2h2FNM@O%H;pb+&*qwhaFkwY^wNs?gB)SMEQ^z)JtF`dyuS75BDVfz(e2@l?fB^;Dhs{fnPq zaJD&r=PKqF%%D=KYZ0)~Z2#fWCfdAh4SCuTnN=i#u#r7}X6umo66LVpNhj^@L`6gA zZ~p!QJP5%L1`sAOCxmGWgPA4#=@Nr@W(MH7g;jopyznzO^#6x^{-%e*FpmZjGhnC! zXt9}7S3x$Q1uE$&t$XiyJ literal 0 HcmV?d00001 diff --git a/mods/ra/maps/drop-zone/map.yaml b/mods/ra/maps/drop-zone/map.yaml new file mode 100755 index 0000000000..e8ea59dee0 --- /dev/null +++ b/mods/ra/maps/drop-zone/map.yaml @@ -0,0 +1,236 @@ +Selectable: True + +MapFormat: 5 + +Title: Drop Zone + +Description: Pick up the crates with the APC to get units to kill the other players. + +Author: Holloweye + +Tileset: TEMPERAT + +MapSize: 64,64 + +Bounds: 16,16,32,32 + +UseAsShellmap: False + +Type: Minigame + +Players: + PlayerReference@Neutral: + Name: Neutral + OwnsWorld: True + NonCombatant: True + Race: allies + PlayerReference@Creeps: + Name: Creeps + NonCombatant: True + Race: allies + PlayerReference@Multi0: + Name: Multi0 + Playable: True + LockRace: True + Race: soviet + Enemies: Multi1,Multi2,Multi3,Multi4,Multi5,Multi6,Multi17 + PlayerReference@Multi1: + Name: Multi1 + Playable: True + LockRace: True + Race: soviet + Enemies: Multi0,Multi2,Multi3,Multi4,Multi5,Multi6,Multi17 + PlayerReference@Multi2: + Name: Multi2 + Playable: True + LockRace: True + Race: soviet + Enemies: Multi0,Multi1,Multi3,Multi4,Multi5,Multi6,Multi17 + PlayerReference@Multi3: + Name: Multi3 + Playable: True + LockRace: True + Race: soviet + Enemies: Multi0,Multi1,Multi2,Multi4,Multi5,Multi6,Multi17 + PlayerReference@Multi4: + Name: Multi4 + Playable: True + LockRace: True + Race: soviet + Enemies: Multi0,Multi1,Multi2,Multi3,Multi5,Multi6,Multi17 + PlayerReference@Multi5: + Name: Multi5 + Playable: True + LockRace: True + Race: soviet + Enemies: Multi0,Multi2,Multi3,Multi4,Multi1,Multi6,Multi17 + PlayerReference@Multi6: + Name: Multi6 + Playable: True + LockRace: True + Race: soviet + Enemies: Multi0,Multi2,Multi3,Multi4,Multi5,Multi1,Multi17 + PlayerReference@Multi7: + Name: Multi7 + Playable: True + LockRace: True + Race: soviet + Enemies: Multi0,Multi2,Multi3,Multi4,Multi5,Multi6,Multi11 + +Actors: + Actor0: apc + Location: 28,28 + Owner: Multi0 + Actor1: apc + Location: 30,28 + Owner: Multi1 + Actor2: apc + Location: 32,28 + Owner: Multi2 + Actor3: apc + Location: 32,30 + Owner: Multi3 + Actor4: apc + Location: 32,32 + Owner: Multi4 + Actor5: apc + Location: 30,32 + Owner: Multi5 + Actor6: apc + Location: 28,32 + Owner: Multi6 + Actor7: apc + Location: 28,30 + Owner: Multi7 + Actor9: tc04 + Location: 18,43 + Owner: Neutral + Actor10: tc02 + Location: 44,44 + Owner: Neutral + Actor11: t10 + Location: 23,24 + Owner: Neutral + Actor12: t08 + Location: 34,23 + Owner: Neutral + Actor13: t12 + Location: 38,27 + Owner: Neutral + Actor14: t12 + Location: 35,35 + Owner: Neutral + Actor15: tc04 + Location: 43,18 + Owner: Neutral + Actor16: tc05 + Location: 18,18 + Owner: Neutral + Actor17: t12 + Location: 22,35 + Owner: Neutral + Actor18: t07 + Location: 18,28 + Owner: Neutral + Actor19: t07 + Location: 45,39 + Owner: Neutral + Actor20: t07 + Location: 40,18 + Owner: Neutral + Actor8: mpspawn + Location: 29,29 + Owner: Neutral + Actor21: mpspawn + Location: 29,30 + Owner: Neutral + Actor22: mpspawn + Location: 29,31 + Owner: Neutral + Actor23: mpspawn + Location: 30,31 + Owner: Neutral + Actor24: mpspawn + Location: 31,31 + Owner: Neutral + Actor25: mpspawn + Location: 31,30 + Owner: Neutral + Actor26: mpspawn + Location: 31,29 + Owner: Neutral + Actor27: mpspawn + Location: 30,29 + Owner: Neutral + +Smudges: + +Rules: + World: + CrateDrop: + Maximum: 3 + SpawnInterval: 5 + -SpawnMPUnits: + -MPStartLocations: + CRATE: + -LevelUpCrateAction: + -GiveMcvCrateAction: + -RevealMapCrateAction: + -HideMapCrateAction: + -ExplodeCrateAction@nuke: + -ExplodeCrateAction@boom: + -ExplodeCrateAction@fire: + -SupportPowerCrateAction@parabombs: + -GiveCashCrateAction: + GiveUnitCrateAction@ttnk: + SelectionShares: 4 + Unit: ttnk + GiveUnitCrateAction@ftrk: + SelectionShares: 6 + Unit: ftrk + GiveUnitCrateAction@harv: + SelectionShares: 1 + Unit: harv + GiveUnitCrateAction@shok: + SelectionShares: 1 + Unit: shok + GiveUnitCrateAction@dog: + SelectionShares: 1 + Unit: dog + APC: + Health: + HP: 1000 + RevealsShroud: + Range: 40 + MustBeDestroyed: + -AttackMove: + HARV: + Tooltip: + Name: Bomb Truck + Description: Explodes like a damn nuke! + Health: + HP: 100 + Explodes: + Weapon: CrateNuke + EmptyWeapon: + SHOK: + Health: + HP: 800 + DOG: + Health: + HP: 120 + Mobile: + Speed: 7 + +Sequences: + +Weapons: + PortaTesla: + ROF: 20 + Range: 10 + Warhead: + Spread: 1 + InfDeath: 5 + Damage: 80 + +Voices: diff --git a/mods/ra/maps/monster-tank-madness/map.yaml b/mods/ra/maps/monster-tank-madness/map.yaml index c41b565b40..d2c82a25dd 100644 --- a/mods/ra/maps/monster-tank-madness/map.yaml +++ b/mods/ra/maps/monster-tank-madness/map.yaml @@ -2568,13 +2568,16 @@ Rules: Range: 6 Turreted: ROT: 1 + Armament@PRIMARY: + Weapon: SuperTankPrimary + LocalOffset: -4,-5,0,0,0, 4,-5,0,0,0 + Recoil: 4 + RecoilRecovery: 0.7 + Armament@SECONDARY: + Weapon: MammothTusk + LocalOffset: -7,2,0,0,25, 7,2,0,0,-25 + Recoil: 1 AttackTurreted: - PrimaryWeapon: SuperTankPrimary - SecondaryWeapon: MammothTusk - PrimaryLocalOffset: -4,-5,0,0,0, 4,-5,0,0,0 - SecondaryLocalOffset: -7,2,0,0,25, 7,2,0,0,-25 - PrimaryRecoil: 4 - PrimaryRecoilRecovery: 0.7 RenderUnitTurreted: Image: 4TNK AutoTarget: diff --git a/mods/ra/maps/training-camp.oramap b/mods/ra/maps/training-camp.oramap deleted file mode 100644 index 44c519cd1368373f4c88d8c3942cbe5db2f78ac9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4315 zcmaJ_XHXMdmrg8 zQCjFo4}=y%3GKt#cXq#-o!xV1?s-o8@!TKho;k>e6qIZL000c2wKKXG2MVNlNeKW@ zAproI3$N2NS8*#lXF`UFGhBw@b!qZ)@Z>L?PWsBCY>%~-OTGlbP?zaW9$N2xP*o@h z23ASFotyWEkj@(1&2+?J^gl8d^83_8&XfFh$3%Lh3xcmn>{&9Q&Y?wP`nAaF81lOf zW5K%Jo9c2$jwh*Mj;*7@ab{g&T!LQ(&}JI*WpYnEKd)>3LJ=_L+Eqcm(r1h%v5ekS z%eW^bPEl$2el#87)Z{+LIgsXB~ziOP+oz62Uv@GK|m6v#rwVX#I^T!WM zCc4Q_Pdtq;3pIw-oaT*hCrsQnpgoIV#=Y{vk8}Tns2^dg739NN@!HDnhP{W zHK-GzYkG@%e^%_)be5`F>u$}UhX*LnGorJ#`VwqTQkEZ17}=S7VPo4l?d}N#@*3_j z$C-Li2TBe7gbzOo@LK$M&6g~bTvLUP(|=e%$8^F3r&gc1@0lTkYCuLRA2dj{aP+_T zPu=#G{z|+37Se05=s&?Ka&~nQ2XYT%RLBZp+?df>l4%QklT%~e%2029OQA{gJ8zMb zTJ!i}>C4UiW7uin>)GI_z>^^8Bslj+(gVAW z+b@v=dles}+gBDW++MPLP~DMHpI=z)VcCAm8RkH(^D|kl;ZM;w%@Z1F`?*H#A-2w} z_AJk45n{7?gSyYqQ~z||ds!QlAyL^w8*#Pzcbd5roIi-uQ_gYC!lq!;h36t`(0TX3 zea?(c*3Fbnl&H3E8HJy4rh3F#8pSn>I8jrGyq2xYt&=zV?uKU+#8ae0CEQVRC?p-4 z_WJq`U-#gy<6RC^kCups&kZ@b6v2$}6@9$@*SUnjX`Fai`lS_g!$oJng&z)jpaekc`VoP0<$RFQs5Y>8BC+^uxSQffWKmHlFJ_{>6`g=oj zFbZZ(Gc?_=;d;Hajn&`3?l|X>U3**M3xl<+;l0M^Uu32?Rky^6Rv1hZr)Pa{p?%XY zjkh)yjcGHRb<-b2jMOSIDe~(9Djp7=OVcaIZIT(dne-WKW237Pfj(0IYAV|d7NIe= z|2c4)z_>pmC_$d7m)9oV^>8u0Qz{ZK=5Z&p?>@1$(%UBaWMHomxvz{PG+_^LbsGVq z8@ThZ$@A&W$X^UUJ30&347bQLA9Wt02*Ie@Xs;v8%*28*dQ1E9etphzMXguu4cyO$ zTIpl-VCiX*hm!;$fJta$XHOh{Z%M5#xI3;9Iv~DFh%fgvRLIR<)e%!L#u5gT_B%6^FP6tLFJMTR(w*0{c08g-tK~NZCBPdC6dK z_qs36zazLG^LfeO@PYl^fKK?xuIA~Gbhl$o6MDBUwd_1fZMJ?$ZHNt>^(Cy77o|OG zAEUxgqu3V8EEdWW3INEiYv4eKKrm2|QsHtnzzx6#P^Yi9PNIQ?g?{cbpa(N5G61I% zT*V-PfOlIekGqP){UIA9zmys7;@kKy;GvhTV+F=bEhJWTJpThwQ?3Ziiq=%(u=G6A zmts6*{@RFeIH4d-x%G^mFL~TBI_9X$9p@Ty<6L&d7Tvx^5?yuM^IxV2&4H*1w*V5` zav2_n=7FF^05`gELx`&)D3kz~rK5cR(AO{{t@i0rWsV@Uf)0}H?#sra7!?Jz3QYpC z$R0RAWd$jdP5J@K+%l^it-vrEHhw@GX_`*JMmuWZR^asn0960cpISO#n>Q7=gbFbH zxBUHRFeE%biVN~7%+xZx#N@l2_s{Z>K{Pyj5pj>&kw=Mii5uX!u>Dvu8x%&lC}P=l zC!wA#6u{yM{?5iSq9P2joh+Nbsp?uk#~@%8wHR7R??Aa};hjhH3ckE(PbiQBW*=8}P0x)07 z!GvA$QU@v?U@5MzKD8U6j^cX1X~H6)>U`TAHk(lJLLuQ212iyZ4*b%dllEQ9q$-RB z#B8Qmc!kl z(jb7VGk|B=gOWuS%1mj2K4w+oN}vQQhx4_8XMWtY;0Fh5UAf-_o#!`vy%szgSK*nFVc9ANOb5lJ?Ba*39qGvlI5#q~qjVo;K^xYgd z?BK0(3wTI~J{oeE1OrjFZvBp7R*HhbDf!zHEyKBzsq&jzXb{mQi39iFsSbAuacV*F z3o_u03(To>f%OuB%%teZ%dC(2n$22a`G}@*6zgLPR^5v<`d|(SzM$737J^?mz#E5_ zB+d$10`n0&U}44Ki*J%66dwr#q4|=)B~7pk+Dg#(w5yeU>&D~rXywEvg=hhQxeK@Hc);Hslej8&jZbMCaYuRdSapDpe?7=5Fgl5ZxEZ6? z?Vra5zvkGO$n=M$az<#``ky-=ag#6hg6PqcxROVGT~?|=RtS!3_)El_HPH_Ba38X` z!@-wusV}M`$~m$vBBt+U+eJ(Zp7667hx`E-gPE+u^Lg>^vk!!objuC(k4JgyxMn@O zf*6@M_qF0!LD0a!SL_D@%C2v~mKCrc(jSiaRksU*(Q3k>u6l3wgH?9aRhjukpwwWI z?SF-5A6?+ER!SE*mpm)CAf*bex(DrW%64*+>*Cad3!_zsmZYwjNuLL0+b)z7bQX7| z-T=6oL~WNLMG@0wKS~04vyWRAT=Smnx%UIY^d`$>X~1~gjTMmKHdfCxcUhA>OfAOf zNa;G@Ok1HG3f2G(PC4~J+}T?xKRjTNS1;a|a0l9M?yJlP)ms9T6x8NHgQl9lFyz)} z6BF3ZsAw=J_8Xy^=dP5d7w6TUL!9N>Rhq538!+=R+^>y3j^F>0B!WyHIj63!76IIa|p6SI_S z@?S3xMtMGUvfrHkv=!0R+d0`9IJ1Q~L^i_)3G&yyeQ8RMq@xpGsZn>o-IYuhJm!o-U)>uXiimPfPBG)SlefS{UW18X{GdGZd!| zRdHgMf5)OEp2k%a4VX*43-UM5?Qq{a!^Mhsod?fstvz}pefj)Sd+jl>H7dwB|i@C=>;7Z2aKAUG}X>qKPw32xCCJ$F)k`v#a z5&ybh?}+vOk273hg%Eu#Zbh=*IE$xL(j=`PZzILstfGZ1vhTKwLG3F=k z<~2i}-fa8%XU4(jfHqTiD(379cUQ=-j?PumRWq&}oCj&KSaP_Zq|qd8H=C95r>$`9 z_faH%c1_BMKeJlQ(C^E{FlwFeYO+Fla(}h$EhG(Th;3=ckmaD}c%JdtVB@?1fv(!5 z?p+?dPCA`Q`^{~>h(q593COjEpE@ W!UB;Gsi^GEVpb{=hM6MadyqJGqo1w(+}?hO!N41$j%z?j;b^AWZ0Jb4V3z(^*rBv#DWIGD{*WmZNqU|IxbH9kWgT}$%=(*kzd z!GmGAeT0$$CIp)}glH{6l{ajs9d`0+qS4aQ{2J+-8;7K0gpgp#Cn2z-f>@Q1Y{@%O z2HuQZ(v4VEBXEw)()_xh!ii8{%sNW)6S+LjB$cVL^iiWNk_=BWsxOtlhCi0R|J;#7oc8gtEhL21X)Q?8AW7am zS3QsS5YCY~Jr4nXD$p`H10M3+Ci2|ELd;jkqQanQUa}w<_s=yw4_Cb(yV*Y> zk)Weq*qomy0Ur7Ea(*5PKyp~I0_5vm-R;gVBoE0JCLs6eSX+$Qfv*n4gB;T3x&h!E z=KrYrF|ftTB;C|mh<~l`SEJqum#b002M5~XLa*A*{s}2pz%-m@O)&>)`Y}H7m;)~W z3_e#wwI8gc0a&H7T$5O4cHpZ6!Ne#e=?k8Uz4&d8Etq;TG zC?#A#0xP1(95=4o&Hky8*12)krD>kZ!@j0{ZT5Bdy*AsLwqw5A*8QQTLv0S{x8$aB zYvhpTK%NMo%FGUYbs*C&4&2|m>bvMP>1Thxdz@XirChZah+Yj)tP12xLiMaZuF5@o;y z*bIpxz~dj8`DS6dy_D=w)kg$uNX5GP?#a0b*tOlQAU$h#42GGf4nTgX!vTg7jQy6p0K(HNym!{=W|UJk?aJbdcQ zNtTk9i$F*qs;J14?YT0=QQ^~4^jck-A57k@?%J6F0}z|7!iJzsEe7IXtfpu zjDbe@^Xx6d!P~Mle4pPAv;*xxJJ1fa1MNUN&