make order queuing work for buildings and turreted units, too
This commit is contained in:
@@ -218,7 +218,7 @@ namespace OpenRA.Traits
|
|||||||
float2 pos;
|
float2 pos;
|
||||||
bool valid;
|
bool valid;
|
||||||
|
|
||||||
public static Target FromActor(Actor a) { return new Target { actor = a, valid = true }; }
|
public static Target FromActor(Actor a) { return new Target { actor = a, valid = (a != null) }; }
|
||||||
public static Target FromPos(float2 p) { return new Target { pos = p, valid = true }; }
|
public static Target FromPos(float2 p) { return new Target { pos = p, valid = true }; }
|
||||||
public static Target FromCell(int2 c) { return new Target { pos = Util.CenterOfCell(c), valid = true }; }
|
public static Target FromCell(int2 c) { return new Target { pos = Util.CenterOfCell(c), valid = true }; }
|
||||||
public static Target FromOrder(Order o)
|
public static Target FromOrder(Order o)
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ namespace OpenRA.Mods.RA.Activities
|
|||||||
if (facing.Facing != desiredFacing)
|
if (facing.Facing != desiredFacing)
|
||||||
return Util.SequenceActivities( new Turn( desiredFacing ), this );
|
return Util.SequenceActivities( new Turn( desiredFacing ), this );
|
||||||
|
|
||||||
attack.target = Target;
|
|
||||||
attack.DoAttack(self, Target);
|
attack.DoAttack(self, Target);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,10 +27,10 @@ namespace OpenRA.Mods.RA.Air
|
|||||||
return new FlyAttack( newTarget );
|
return new FlyAttack( newTarget );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool CanAttack(Actor self)
|
protected override bool CanAttack(Actor self, Target target)
|
||||||
{
|
{
|
||||||
// dont fire while landed
|
// dont fire while landed
|
||||||
return base.CanAttack(self)
|
return base.CanAttack(self, target)
|
||||||
&& self.Trait<Aircraft>().Altitude > 0;
|
&& self.Trait<Aircraft>().Altitude > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ namespace OpenRA.Mods.RA.Air
|
|||||||
Cancel( self );
|
Cancel( self );
|
||||||
|
|
||||||
var attack = self.Trait<AttackPlane>();
|
var attack = self.Trait<AttackPlane>();
|
||||||
attack.target = Target;
|
|
||||||
attack.DoAttack( self, Target );
|
attack.DoAttack( self, Target );
|
||||||
|
|
||||||
if( inner == null )
|
if( inner == null )
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ namespace OpenRA.Mods.RA.Air
|
|||||||
if( !float2.WithinEpsilon( float2.Zero, dist, range * Game.CellSize ) )
|
if( !float2.WithinEpsilon( float2.Zero, dist, range * Game.CellSize ) )
|
||||||
aircraft.TickMove( 1024 * aircraft.MovementSpeed, desiredFacing );
|
aircraft.TickMove( 1024 * aircraft.MovementSpeed, desiredFacing );
|
||||||
|
|
||||||
attack.target = target;
|
|
||||||
attack.DoAttack( self, target );
|
attack.DoAttack( self, target );
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ namespace OpenRA.Mods.RA
|
|||||||
int nextScanTime = 0;
|
int nextScanTime = 0;
|
||||||
|
|
||||||
public bool IsAttacking { get; internal set; }
|
public bool IsAttacking { get; internal set; }
|
||||||
public Target target;
|
|
||||||
|
|
||||||
public List<Weapon> Weapons = new List<Weapon>();
|
public List<Weapon> Weapons = new List<Weapon>();
|
||||||
public List<Turret> Turrets = new List<Turret>();
|
public List<Turret> Turrets = new List<Turret>();
|
||||||
@@ -73,7 +72,7 @@ namespace OpenRA.Mods.RA
|
|||||||
info.SecondaryOffset != null ? Turrets[1] : Turrets[0], info.SecondaryLocalOffset));
|
info.SecondaryOffset != null ? Turrets[1] : Turrets[0], info.SecondaryLocalOffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual bool CanAttack(Actor self)
|
protected virtual bool CanAttack(Actor self, Target target)
|
||||||
{
|
{
|
||||||
if (!target.IsValid) return false;
|
if (!target.IsValid) return false;
|
||||||
if (Weapons.All(w => w.IsReloading)) return false;
|
if (Weapons.All(w => w.IsReloading)) return false;
|
||||||
@@ -113,7 +112,7 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public void DoAttack(Actor self, Target target)
|
public void DoAttack(Actor self, Target target)
|
||||||
{
|
{
|
||||||
if( !CanAttack( self ) ) return;
|
if( !CanAttack( self, target ) ) return;
|
||||||
|
|
||||||
var move = self.TraitOrDefault<IMove>();
|
var move = self.TraitOrDefault<IMove>();
|
||||||
var facing = self.TraitOrDefault<IFacing>();
|
var facing = self.TraitOrDefault<IFacing>();
|
||||||
@@ -121,7 +120,7 @@ namespace OpenRA.Mods.RA
|
|||||||
w.CheckFire(self, this, move, facing, target);
|
w.CheckFire(self, this, move, facing, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual int FireDelay( Actor self, AttackBaseInfo info )
|
public virtual int FireDelay( Actor self, Target target, AttackBaseInfo info )
|
||||||
{
|
{
|
||||||
return info.FireDelay;
|
return info.FireDelay;
|
||||||
}
|
}
|
||||||
@@ -147,31 +146,18 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public void ResolveOrder(Actor self, Order order)
|
public void ResolveOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
if (order.OrderString == "Attack" || order.OrderString == "AttackHold")
|
if (order.OrderString == "Attack")
|
||||||
|
AttackTarget( Target.FromOrder( order ), order.Queued, true );
|
||||||
|
|
||||||
|
else if(order.OrderString == "AttackHold")
|
||||||
|
AttackTarget( Target.FromOrder( order ), order.Queued, false );
|
||||||
|
|
||||||
|
else
|
||||||
{
|
{
|
||||||
bool allowMove = order.OrderString == "Attack";
|
/* hack */
|
||||||
self.QueueActivity(order.Queued, GetAttackActivity(self, Target.FromOrder(order), allowMove));
|
if (self.HasTrait<Turreted>() && self.Info.Traits.Get<AttackBaseInfo>().AlignIdleTurrets)
|
||||||
|
self.Trait<Turreted>().desiredFacing = null;
|
||||||
if (self.Owner == self.World.LocalPlayer)
|
}
|
||||||
self.World.AddFrameEndTask(w =>
|
|
||||||
{
|
|
||||||
if (self.Destroyed) return;
|
|
||||||
if (order.TargetActor != null)
|
|
||||||
w.Add(new FlashTarget(order.TargetActor));
|
|
||||||
|
|
||||||
var line = self.TraitOrDefault<DrawLineToTarget>();
|
|
||||||
if (line != null)
|
|
||||||
if (order.TargetActor != null) line.SetTarget(self, Target.FromOrder(order), Color.Red);
|
|
||||||
else line.SetTarget(self, Target.FromOrder(order), Color.Red);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
} // else not an attack order
|
|
||||||
|
|
||||||
target = Target.None;
|
|
||||||
|
|
||||||
/* hack */
|
|
||||||
if (self.HasTrait<Turreted>() && self.Info.Traits.Get<AttackBaseInfo>().AlignIdleTurrets)
|
|
||||||
self.Trait<Turreted>().desiredFacing = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string VoicePhraseForOrder(Actor self, Order order)
|
public string VoicePhraseForOrder(Actor self, Order order)
|
||||||
@@ -186,31 +172,32 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public Weapon ChooseWeaponForTarget(Target t) { return Weapons.FirstOrDefault(w => w.IsValidAgainst(self.World, t)); }
|
public Weapon ChooseWeaponForTarget(Target t) { return Weapons.FirstOrDefault(w => w.IsValidAgainst(self.World, t)); }
|
||||||
|
|
||||||
public void AttackTarget(Actor self, Actor target, bool allowMovement)
|
public void AttackTarget( Target target, bool queued, bool allowMove )
|
||||||
{
|
{
|
||||||
AttackTarget(self, target, allowMovement, false);
|
if( !target.IsValid ) return;
|
||||||
}
|
self.QueueActivity(queued, GetAttackActivity(self, target, allowMove));
|
||||||
|
|
||||||
public void AttackTarget(Actor self, Actor target, bool allowMovement, bool holdStill)
|
if (self.Owner == self.World.LocalPlayer)
|
||||||
{
|
self.World.AddFrameEndTask(w =>
|
||||||
var attack = self.Trait<AttackBase>();
|
{
|
||||||
if (target != null)
|
if (self.Destroyed) return;
|
||||||
{
|
if (target.IsActor)
|
||||||
if (allowMovement)
|
w.Add(new FlashTarget(target.Actor));
|
||||||
attack.ResolveOrder(self, new Order((holdStill) ? "AttackHold" : "Attack", self, target, false));
|
|
||||||
else
|
var line = self.TraitOrDefault<DrawLineToTarget>();
|
||||||
attack.target = Target.FromActor(target); // for turreted things on rails.
|
if (line != null)
|
||||||
}
|
line.SetTarget(self, target, Color.Red);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ScanAndAttack(Actor self, bool allowMovement, bool holdStill)
|
public void ScanAndAttack(Actor self, bool allowMovement, bool holdStill)
|
||||||
{
|
{
|
||||||
if (--nextScanTime <= 0)
|
if (--nextScanTime <= 0)
|
||||||
{
|
{
|
||||||
var targetActor = ScanForTarget(self);
|
var targetActor = ScanForTarget(self, null);
|
||||||
|
|
||||||
if (targetActor != null)
|
if (targetActor != null)
|
||||||
AttackTarget(self, targetActor, allowMovement, holdStill);
|
AttackTarget(Target.FromActor(targetActor), false, allowMovement && !holdStill);
|
||||||
|
|
||||||
var info = self.Info.Traits.Get<AttackBaseInfo>();
|
var info = self.Info.Traits.Get<AttackBaseInfo>();
|
||||||
nextScanTime = (int)(25 * (info.ScanTimeAverage +
|
nextScanTime = (int)(25 * (info.ScanTimeAverage +
|
||||||
@@ -218,15 +205,14 @@ namespace OpenRA.Mods.RA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Actor ScanForTarget(Actor self)
|
public Actor ScanForTarget(Actor self, Actor currentTarget)
|
||||||
{
|
{
|
||||||
var attack = self.Trait<AttackBase>();
|
var range = GetMaximumRange();
|
||||||
var range = attack.GetMaximumRange();
|
|
||||||
|
|
||||||
if ((!attack.target.IsValid || self.IsIdle) || !Combat.IsInRange(self.CenterLocation, range, attack.target))
|
if (self.IsIdle || currentTarget == null || !Combat.IsInRange(self.CenterLocation, range, currentTarget))
|
||||||
return ChooseTarget(self, range);
|
return ChooseTarget(self, range);
|
||||||
|
|
||||||
return null;
|
return currentTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ScanAndAttack(Actor self, bool allowMovement)
|
public void ScanAndAttack(Actor self, bool allowMovement)
|
||||||
@@ -237,11 +223,10 @@ namespace OpenRA.Mods.RA
|
|||||||
Actor ChooseTarget(Actor self, float range)
|
Actor ChooseTarget(Actor self, float range)
|
||||||
{
|
{
|
||||||
var inRange = self.World.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range);
|
var inRange = self.World.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range);
|
||||||
var attack = self.Trait<AttackBase>();
|
|
||||||
|
|
||||||
return inRange
|
return inRange
|
||||||
.Where(a => a.Owner != null && self.Owner.Stances[a.Owner] == Stance.Enemy)
|
.Where(a => a.Owner != null && self.Owner.Stances[a.Owner] == Stance.Enemy)
|
||||||
.Where(a => attack.HasAnyValidWeapons(Target.FromActor(a)))
|
.Where(a => HasAnyValidWeapons(Target.FromActor(a)))
|
||||||
.Where(a => !a.HasTrait<Cloak>() || a.Trait<Cloak>().IsVisible(a, self.Owner))
|
.Where(a => !a.HasTrait<Cloak>() || a.Trait<Cloak>().IsVisible(a, self.Owner))
|
||||||
.OrderBy(a => (a.CenterLocation - self.CenterLocation).LengthSquared)
|
.OrderBy(a => (a.CenterLocation - self.CenterLocation).LengthSquared)
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ namespace OpenRA.Mods.RA
|
|||||||
public AttackFrontal(Actor self, AttackFrontalInfo info)
|
public AttackFrontal(Actor self, AttackFrontalInfo info)
|
||||||
: base( self ) { this.info = info; }
|
: base( self ) { this.info = info; }
|
||||||
|
|
||||||
protected override bool CanAttack( Actor self )
|
protected override bool CanAttack( Actor self, Target target )
|
||||||
{
|
{
|
||||||
if( !base.CanAttack( self ) )
|
if( !base.CanAttack( self, target ) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var facing = self.Trait<IFacing>().Facing;
|
var facing = self.Trait<IFacing>().Facing;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ namespace OpenRA.Mods.RA
|
|||||||
class AttackLeap : AttackBase
|
class AttackLeap : AttackBase
|
||||||
{
|
{
|
||||||
internal bool IsLeaping;
|
internal bool IsLeaping;
|
||||||
|
protected Target target;
|
||||||
|
|
||||||
public AttackLeap(Actor self)
|
public AttackLeap(Actor self)
|
||||||
: base(self) {}
|
: base(self) {}
|
||||||
@@ -33,7 +34,7 @@ namespace OpenRA.Mods.RA
|
|||||||
if (!target.IsValid) return;
|
if (!target.IsValid) return;
|
||||||
if (IsLeaping) return;
|
if (IsLeaping) return;
|
||||||
|
|
||||||
var weapon = self.Trait<AttackBase>().Weapons[0].Info;
|
var weapon = Weapons[0].Info;
|
||||||
if( !Combat.IsInRange( self.CenterLocation, weapon.Range, target ) ) return;
|
if( !Combat.IsInRange( self.CenterLocation, weapon.Range, target ) ) return;
|
||||||
|
|
||||||
self.CancelActivity();
|
self.CancelActivity();
|
||||||
|
|||||||
@@ -22,14 +22,15 @@ namespace OpenRA.Mods.RA
|
|||||||
class AttackOmni : AttackBase, INotifyBuildComplete
|
class AttackOmni : AttackBase, INotifyBuildComplete
|
||||||
{
|
{
|
||||||
bool buildComplete = false;
|
bool buildComplete = false;
|
||||||
|
protected Target target;
|
||||||
public void BuildingComplete(Actor self) { buildComplete = true; }
|
public void BuildingComplete(Actor self) { buildComplete = true; }
|
||||||
|
|
||||||
public AttackOmni(Actor self) : base(self) { }
|
public AttackOmni(Actor self) : base(self) { }
|
||||||
|
|
||||||
protected override bool CanAttack( Actor self )
|
protected override bool CanAttack( Actor self, Target target )
|
||||||
{
|
{
|
||||||
var isBuilding = ( self.HasTrait<Building>() && !buildComplete );
|
var isBuilding = ( self.HasTrait<Building>() && !buildComplete );
|
||||||
return base.CanAttack( self ) && !isBuilding;
|
return base.CanAttack( self, target ) && !isBuilding;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Tick(Actor self)
|
public override void Tick(Actor self)
|
||||||
@@ -50,9 +51,11 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public override IActivity Tick( Actor self )
|
public override IActivity Tick( Actor self )
|
||||||
{
|
{
|
||||||
if( !IsCanceled )
|
if( IsCanceled || !target.IsValid )
|
||||||
self.Trait<AttackBase>().target = target;
|
return NextActivity;
|
||||||
return NextActivity;
|
|
||||||
|
self.Trait<AttackOmni>().target = target;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ namespace OpenRA.Mods.RA
|
|||||||
charges = self.Info.Traits.Get<AttackTeslaInfo>().MaxCharges;
|
charges = self.Info.Traits.Get<AttackTeslaInfo>().MaxCharges;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool CanAttack( Actor self )
|
protected override bool CanAttack( Actor self, Target target )
|
||||||
{
|
{
|
||||||
return base.CanAttack( self ) && ( charges > 0 );
|
return base.CanAttack( self, target ) && ( charges > 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Tick( Actor self )
|
public override void Tick( Actor self )
|
||||||
@@ -53,9 +53,9 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
Actor previousTarget;
|
Actor previousTarget;
|
||||||
|
|
||||||
public override int FireDelay( Actor self, AttackBaseInfo info )
|
public override int FireDelay( Actor self, Target target, AttackBaseInfo info )
|
||||||
{
|
{
|
||||||
return target.Actor == previousTarget ? 3 : base.FireDelay(self, info);
|
return target.Actor == previousTarget ? 3 : base.FireDelay(self, target, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Attacking(Actor self)
|
public void Attacking(Actor self)
|
||||||
|
|||||||
@@ -24,9 +24,10 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
class AttackTurreted : AttackBase, INotifyBuildComplete
|
class AttackTurreted : AttackBase, INotifyBuildComplete
|
||||||
{
|
{
|
||||||
|
protected Target target;
|
||||||
public AttackTurreted(Actor self) : base(self) { }
|
public AttackTurreted(Actor self) : base(self) { }
|
||||||
|
|
||||||
protected override bool CanAttack( Actor self )
|
protected override bool CanAttack( Actor self, Target target )
|
||||||
{
|
{
|
||||||
if( self.HasTrait<Building>() && !buildComplete )
|
if( self.HasTrait<Building>() && !buildComplete )
|
||||||
return false;
|
return false;
|
||||||
@@ -37,7 +38,7 @@ namespace OpenRA.Mods.RA
|
|||||||
if( turreted.desiredFacing != turreted.turretFacing )
|
if( turreted.desiredFacing != turreted.turretFacing )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return base.CanAttack( self );
|
return base.CanAttack( self, target );
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Tick(Actor self)
|
public override void Tick(Actor self)
|
||||||
@@ -56,26 +57,27 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
class AttackActivity : CancelableActivity
|
class AttackActivity : CancelableActivity
|
||||||
{
|
{
|
||||||
readonly Target newTarget;
|
readonly Target target;
|
||||||
public AttackActivity( Target newTarget ) { this.newTarget = newTarget; }
|
public AttackActivity( Target newTarget ) { this.target = newTarget; }
|
||||||
|
|
||||||
public override IActivity Tick( Actor self )
|
public override IActivity Tick( Actor self )
|
||||||
{
|
{
|
||||||
if( IsCanceled ) return NextActivity;
|
if( IsCanceled || !target.IsValid ) return NextActivity;
|
||||||
|
|
||||||
if (self.TraitsImplementing<IDisable>().Any(d => d.Disabled))
|
if (self.TraitsImplementing<IDisable>().Any(d => d.Disabled))
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
var attack = self.Trait<AttackTurreted>();
|
var attack = self.Trait<AttackTurreted>();
|
||||||
const int RangeTolerance = 1; /* how far inside our maximum range we should try to sit */
|
const int RangeTolerance = 1; /* how far inside our maximum range we should try to sit */
|
||||||
var weapon = attack.ChooseWeaponForTarget(newTarget);
|
var weapon = attack.ChooseWeaponForTarget(target);
|
||||||
if (weapon != null)
|
if (weapon != null)
|
||||||
{
|
{
|
||||||
attack.target = newTarget;
|
attack.target = target;
|
||||||
|
|
||||||
if (self.HasTrait<Mobile>() && !self.Info.Traits.Get<MobileInfo>().OnRails)
|
if (self.HasTrait<Mobile>() && !self.Info.Traits.Get<MobileInfo>().OnRails)
|
||||||
self.QueueActivity( new Follow( newTarget,
|
return Util.SequenceActivities(
|
||||||
Math.Max( 0, (int)weapon.Info.Range - RangeTolerance ) ) );
|
new Follow( target, Math.Max( 0, (int)weapon.Info.Range - RangeTolerance ) ),
|
||||||
|
this );
|
||||||
}
|
}
|
||||||
return NextActivity;
|
return NextActivity;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,61 +11,76 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenRA.Mods.RA.Activities;
|
using OpenRA.Mods.RA.Activities;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
|
using OpenRA.Traits.Activities;
|
||||||
|
|
||||||
namespace OpenRA.Mods.RA
|
namespace OpenRA.Mods.RA
|
||||||
{
|
{
|
||||||
class AutoHealInfo : TraitInfo<AutoHeal> { }
|
class AutoHealInfo : TraitInfo<AutoHeal> { }
|
||||||
|
|
||||||
class AutoHeal : ITick
|
class AutoHeal : INotifyIdle
|
||||||
{
|
{
|
||||||
void AttackTarget(Actor self, Actor target)
|
public void Idle( Actor self )
|
||||||
{
|
{
|
||||||
var attack = self.Trait<AttackBase>();
|
self.QueueActivity( new IdleHealActivity() );
|
||||||
if (target != null)
|
|
||||||
attack.ResolveOrder(self, new Order("Attack", self, target, false));
|
|
||||||
else
|
|
||||||
if (attack.IsAttacking)
|
|
||||||
self.CancelActivity();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NeedsNewTarget(Actor self)
|
class IdleHealActivity : Idle
|
||||||
{
|
{
|
||||||
var attack = self.Trait<AttackBase>();
|
Actor currentTarget;
|
||||||
var range = attack.GetMaximumRange();
|
|
||||||
|
|
||||||
if (!attack.target.IsValid)
|
public override IActivity Tick( Actor self )
|
||||||
return true; // he's dead.
|
{
|
||||||
if( !Combat.IsInRange( self.CenterLocation, range, attack.target ) )
|
if( NextActivity != null )
|
||||||
return true; // wandered off faster than we could follow
|
return NextActivity;
|
||||||
|
|
||||||
if (attack.target.IsActor
|
|
||||||
&& attack.target.Actor.GetDamageState() == DamageState.Undamaged)
|
|
||||||
return true; // fully healed
|
|
||||||
|
|
||||||
return false;
|
var attack = self.Trait<AttackBase>();
|
||||||
}
|
var range = attack.GetMaximumRange();
|
||||||
|
|
||||||
public void Tick(Actor self)
|
if (NeedsNewTarget(self))
|
||||||
{
|
AttackTarget(self, ChooseTarget(self, range));
|
||||||
var attack = self.Trait<AttackBase>();
|
|
||||||
var range = attack.GetMaximumRange();
|
|
||||||
|
|
||||||
if (NeedsNewTarget(self))
|
return this;
|
||||||
AttackTarget(self, ChooseTarget(self, range));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Actor ChooseTarget(Actor self, float range)
|
void AttackTarget(Actor self, Actor target)
|
||||||
{
|
{
|
||||||
var inRange = self.World.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range);
|
var attack = self.Trait<AttackBase>();
|
||||||
var attack = self.Trait<AttackBase>();
|
if (target != null)
|
||||||
|
attack.AttackTarget(Target.FromActor( target), false, true );
|
||||||
|
else
|
||||||
|
if (attack.IsAttacking)
|
||||||
|
self.CancelActivity();
|
||||||
|
}
|
||||||
|
|
||||||
return inRange
|
bool NeedsNewTarget(Actor self)
|
||||||
.Where(a => a != self && self.Owner.Stances[a.Owner] == Stance.Ally)
|
{
|
||||||
.Where(a => a.IsInWorld && !a.IsDead())
|
var attack = self.Trait<AttackBase>();
|
||||||
.Where(a => a.HasTrait<Health>() && a.GetDamageState() > DamageState.Undamaged)
|
var range = attack.GetMaximumRange();
|
||||||
.Where(a => attack.HasAnyValidWeapons(Target.FromActor(a)))
|
|
||||||
.OrderBy(a => (a.CenterLocation - self.CenterLocation).LengthSquared)
|
if (currentTarget == null || !currentTarget.IsInWorld)
|
||||||
.FirstOrDefault();
|
return true; // he's dead.
|
||||||
|
if( !Combat.IsInRange( self.CenterLocation, range, currentTarget ) )
|
||||||
|
return true; // wandered off faster than we could follow
|
||||||
|
|
||||||
|
if (currentTarget.GetDamageState() == DamageState.Undamaged)
|
||||||
|
return true; // fully healed
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Actor ChooseTarget(Actor self, float range)
|
||||||
|
{
|
||||||
|
var inRange = self.World.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range);
|
||||||
|
var attack = self.Trait<AttackBase>();
|
||||||
|
|
||||||
|
return inRange
|
||||||
|
.Where(a => a != self && self.Owner.Stances[a.Owner] == Stance.Ally)
|
||||||
|
.Where(a => a.IsInWorld && !a.IsDead())
|
||||||
|
.Where(a => a.HasTrait<Health>() && a.GetDamageState() > DamageState.Undamaged)
|
||||||
|
.Where(a => attack.HasAnyValidWeapons(Target.FromActor(a)))
|
||||||
|
.OrderBy(a => (a.CenterLocation - self.CenterLocation).LengthSquared)
|
||||||
|
.FirstOrDefault();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
if (e.Damage < 0) return; // don't retaliate against healers
|
if (e.Damage < 0) return; // don't retaliate against healers
|
||||||
|
|
||||||
self.Trait<AttackBase>().AttackTarget(self, e.Attacker, self.Info.Traits.Get<AutoTargetInfo>().AllowMovement);
|
self.Trait<AttackBase>().AttackTarget(Target.FromActor(e.Attacker), false, self.Info.Traits.Get<AutoTargetInfo>().AllowMovement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,9 +58,9 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
if (ticks == 430)
|
if (ticks == 430)
|
||||||
{
|
{
|
||||||
Actors["mig1"].Trait<AttackPlane>().AttackTarget(Actors["mig1"], Actors["greeceweap"], true);
|
Actors["mig1"].Trait<AttackPlane>().AttackTarget(Target.FromActor(Actors["greeceweap"]), false, true);
|
||||||
Actors["mig2"].Trait<AttackPlane>().AttackTarget(Actors["mig2"], Actors["greeceweap"], true);
|
Actors["mig2"].Trait<AttackPlane>().AttackTarget(Target.FromActor(Actors["greeceweap"]), false, true);
|
||||||
Actors["mig3"].Trait<AttackPlane>().AttackTarget(Actors["mig3"], Actors["greeceweap"], true);
|
Actors["mig3"].Trait<AttackPlane>().AttackTarget(Target.FromActor(Actors["greeceweap"]), false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ticks++;
|
ticks++;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using OpenRA.Traits;
|
|||||||
namespace OpenRA.Mods.RA
|
namespace OpenRA.Mods.RA
|
||||||
{
|
{
|
||||||
|
|
||||||
public class UnitStanceInfo : ITraitInfo
|
public class UnitStanceInfo : ITraitInfo, ITraitPrerequisite<AttackBaseInfo>
|
||||||
{
|
{
|
||||||
public readonly bool Default = false;
|
public readonly bool Default = false;
|
||||||
public readonly int ScanDelayMin = 12;
|
public readonly int ScanDelayMin = 12;
|
||||||
@@ -167,12 +167,8 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public static void AttackTarget(Actor self, Actor target, bool holdStill)
|
public static void AttackTarget(Actor self, Actor target, bool holdStill)
|
||||||
{
|
{
|
||||||
var attack = self.Trait<AttackBase>();
|
if (target != null)
|
||||||
|
self.Trait<AttackBase>().AttackTarget(Target.FromActor(target), false, !holdStill);
|
||||||
if (attack != null && target != null)
|
|
||||||
{
|
|
||||||
attack.ResolveOrder(self, new Order((holdStill) ? "AttackHold" : "Attack", self, target, false));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void StopAttack(Actor self)
|
public static void StopAttack(Actor self)
|
||||||
@@ -199,7 +195,7 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public static Actor ScanForTarget(Actor self)
|
public static Actor ScanForTarget(Actor self)
|
||||||
{
|
{
|
||||||
return self.Trait<AttackBase>().ScanForTarget(self);
|
return self.Trait<AttackBase>().ScanForTarget(self, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResolveOrder(Actor self, Order order)
|
public void ResolveOrder(Actor self, Order order)
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ namespace OpenRA.Mods.RA
|
|||||||
.Product()
|
.Product()
|
||||||
};
|
};
|
||||||
|
|
||||||
attack.ScheduleDelayedAction( attack.FireDelay( self, self.Info.Traits.Get<AttackBaseInfo>() ), () =>
|
attack.ScheduleDelayedAction( attack.FireDelay( self, target, self.Info.Traits.Get<AttackBaseInfo>() ), () =>
|
||||||
{
|
{
|
||||||
if (args.weapon.Projectile != null)
|
if (args.weapon.Projectile != null)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user