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.
This commit is contained in:
@@ -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<Weapon> Weapons = new List<Weapon>();
|
||||
public List<Turret> Turrets = new List<Turret>();
|
||||
|
||||
readonly Actor self;
|
||||
|
||||
Lazy<IEnumerable<Armament>> armaments;
|
||||
protected IEnumerable<Armament> Armaments { get { return armaments.Value; } }
|
||||
|
||||
public AttackBase(Actor self)
|
||||
{
|
||||
this.self = self;
|
||||
var info = self.Info.Traits.Get<AttackBaseInfo>();
|
||||
|
||||
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<Armament>());
|
||||
}
|
||||
|
||||
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<ITargetable>() &&
|
||||
@@ -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<Pair<int, Action>> delayedActions = new List<Pair<int, Action>>();
|
||||
|
||||
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<IMove>();
|
||||
var facing = self.TraitOrDefault<IFacing>();
|
||||
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<IOrderTargeter> 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<Turreted>() && self.Info.Traits.Get<AttackBaseInfo>().AlignIdleTurrets)
|
||||
self.Trait<Turreted>().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 )
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<IMove>();
|
||||
var facing = self.TraitOrDefault<IFacing>();
|
||||
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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<SkipMakeAnimsInit>();
|
||||
turret = turrets.FirstOrDefault();
|
||||
}
|
||||
|
||||
protected override bool CanAttack( Actor self, Target target )
|
||||
|
||||
@@ -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<Turreted> turrets;
|
||||
[Sync] protected bool buildComplete;
|
||||
|
||||
public AttackTurreted(Actor self) : base(self)
|
||||
{
|
||||
turret = self.Trait<Turreted>();
|
||||
turrets = self.TraitsImplementing<Turreted>();
|
||||
}
|
||||
|
||||
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<AttackTurreted>();
|
||||
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<Mobile>() && !self.Info.Traits.Get<MobileInfo>().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 );
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user