make order queuing work for buildings and turreted units, too
This commit is contained in:
@@ -218,7 +218,7 @@ namespace OpenRA.Traits
|
||||
float2 pos;
|
||||
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 FromCell(int2 c) { return new Target { pos = Util.CenterOfCell(c), valid = true }; }
|
||||
public static Target FromOrder(Order o)
|
||||
|
||||
@@ -61,7 +61,6 @@ namespace OpenRA.Mods.RA.Activities
|
||||
if (facing.Facing != desiredFacing)
|
||||
return Util.SequenceActivities( new Turn( desiredFacing ), this );
|
||||
|
||||
attack.target = Target;
|
||||
attack.DoAttack(self, Target);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -27,10 +27,10 @@ namespace OpenRA.Mods.RA.Air
|
||||
return new FlyAttack( newTarget );
|
||||
}
|
||||
|
||||
protected override bool CanAttack(Actor self)
|
||||
protected override bool CanAttack(Actor self, Target target)
|
||||
{
|
||||
// dont fire while landed
|
||||
return base.CanAttack(self)
|
||||
return base.CanAttack(self, target)
|
||||
&& self.Trait<Aircraft>().Altitude > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ namespace OpenRA.Mods.RA.Air
|
||||
Cancel( self );
|
||||
|
||||
var attack = self.Trait<AttackPlane>();
|
||||
attack.target = Target;
|
||||
attack.DoAttack( self, Target );
|
||||
|
||||
if( inner == null )
|
||||
|
||||
@@ -46,7 +46,6 @@ namespace OpenRA.Mods.RA.Air
|
||||
if( !float2.WithinEpsilon( float2.Zero, dist, range * Game.CellSize ) )
|
||||
aircraft.TickMove( 1024 * aircraft.MovementSpeed, desiredFacing );
|
||||
|
||||
attack.target = target;
|
||||
attack.DoAttack( self, target );
|
||||
|
||||
return this;
|
||||
|
||||
@@ -48,7 +48,6 @@ namespace OpenRA.Mods.RA
|
||||
int nextScanTime = 0;
|
||||
|
||||
public bool IsAttacking { get; internal set; }
|
||||
public Target target;
|
||||
|
||||
public List<Weapon> Weapons = new List<Weapon>();
|
||||
public List<Turret> Turrets = new List<Turret>();
|
||||
@@ -73,7 +72,7 @@ namespace OpenRA.Mods.RA
|
||||
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 (Weapons.All(w => w.IsReloading)) return false;
|
||||
@@ -113,7 +112,7 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
public void DoAttack(Actor self, Target target)
|
||||
{
|
||||
if( !CanAttack( self ) ) return;
|
||||
if( !CanAttack( self, target ) ) return;
|
||||
|
||||
var move = self.TraitOrDefault<IMove>();
|
||||
var facing = self.TraitOrDefault<IFacing>();
|
||||
@@ -121,7 +120,7 @@ namespace OpenRA.Mods.RA
|
||||
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;
|
||||
}
|
||||
@@ -147,31 +146,18 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
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";
|
||||
self.QueueActivity(order.Queued, GetAttackActivity(self, Target.FromOrder(order), allowMove));
|
||||
|
||||
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;
|
||||
/* hack */
|
||||
if (self.HasTrait<Turreted>() && self.Info.Traits.Get<AttackBaseInfo>().AlignIdleTurrets)
|
||||
self.Trait<Turreted>().desiredFacing = null;
|
||||
}
|
||||
}
|
||||
|
||||
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 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)
|
||||
{
|
||||
var attack = self.Trait<AttackBase>();
|
||||
if (target != null)
|
||||
{
|
||||
if (allowMovement)
|
||||
attack.ResolveOrder(self, new Order((holdStill) ? "AttackHold" : "Attack", self, target, false));
|
||||
else
|
||||
attack.target = Target.FromActor(target); // for turreted things on rails.
|
||||
}
|
||||
if (self.Owner == self.World.LocalPlayer)
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
if (self.Destroyed) return;
|
||||
if (target.IsActor)
|
||||
w.Add(new FlashTarget(target.Actor));
|
||||
|
||||
var line = self.TraitOrDefault<DrawLineToTarget>();
|
||||
if (line != null)
|
||||
line.SetTarget(self, target, Color.Red);
|
||||
});
|
||||
}
|
||||
|
||||
public void ScanAndAttack(Actor self, bool allowMovement, bool holdStill)
|
||||
{
|
||||
if (--nextScanTime <= 0)
|
||||
{
|
||||
var targetActor = ScanForTarget(self);
|
||||
var targetActor = ScanForTarget(self, null);
|
||||
|
||||
if (targetActor != null)
|
||||
AttackTarget(self, targetActor, allowMovement, holdStill);
|
||||
AttackTarget(Target.FromActor(targetActor), false, allowMovement && !holdStill);
|
||||
|
||||
var info = self.Info.Traits.Get<AttackBaseInfo>();
|
||||
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 = attack.GetMaximumRange();
|
||||
var range = 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 null;
|
||||
return currentTarget;
|
||||
}
|
||||
|
||||
public void ScanAndAttack(Actor self, bool allowMovement)
|
||||
@@ -237,11 +223,10 @@ namespace OpenRA.Mods.RA
|
||||
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.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))
|
||||
.OrderBy(a => (a.CenterLocation - self.CenterLocation).LengthSquared)
|
||||
.FirstOrDefault();
|
||||
|
||||
@@ -26,9 +26,9 @@ namespace OpenRA.Mods.RA
|
||||
public AttackFrontal(Actor self, AttackFrontalInfo 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;
|
||||
|
||||
var facing = self.Trait<IFacing>().Facing;
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace OpenRA.Mods.RA
|
||||
class AttackLeap : AttackBase
|
||||
{
|
||||
internal bool IsLeaping;
|
||||
protected Target target;
|
||||
|
||||
public AttackLeap(Actor self)
|
||||
: base(self) {}
|
||||
@@ -33,7 +34,7 @@ namespace OpenRA.Mods.RA
|
||||
if (!target.IsValid) 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;
|
||||
|
||||
self.CancelActivity();
|
||||
|
||||
@@ -22,14 +22,15 @@ namespace OpenRA.Mods.RA
|
||||
class AttackOmni : AttackBase, INotifyBuildComplete
|
||||
{
|
||||
bool buildComplete = false;
|
||||
protected Target target;
|
||||
public void BuildingComplete(Actor self) { buildComplete = true; }
|
||||
|
||||
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 );
|
||||
return base.CanAttack( self ) && !isBuilding;
|
||||
return base.CanAttack( self, target ) && !isBuilding;
|
||||
}
|
||||
|
||||
public override void Tick(Actor self)
|
||||
@@ -50,9 +51,11 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
public override IActivity Tick( Actor self )
|
||||
{
|
||||
if( !IsCanceled )
|
||||
self.Trait<AttackBase>().target = target;
|
||||
return NextActivity;
|
||||
if( IsCanceled || !target.IsValid )
|
||||
return NextActivity;
|
||||
|
||||
self.Trait<AttackOmni>().target = target;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,9 +32,9 @@ namespace OpenRA.Mods.RA
|
||||
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 )
|
||||
@@ -53,9 +53,9 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
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)
|
||||
|
||||
@@ -24,9 +24,10 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
class AttackTurreted : AttackBase, INotifyBuildComplete
|
||||
{
|
||||
protected Target target;
|
||||
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 )
|
||||
return false;
|
||||
@@ -37,7 +38,7 @@ namespace OpenRA.Mods.RA
|
||||
if( turreted.desiredFacing != turreted.turretFacing )
|
||||
return false;
|
||||
|
||||
return base.CanAttack( self );
|
||||
return base.CanAttack( self, target );
|
||||
}
|
||||
|
||||
public override void Tick(Actor self)
|
||||
@@ -56,26 +57,27 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
class AttackActivity : CancelableActivity
|
||||
{
|
||||
readonly Target newTarget;
|
||||
public AttackActivity( Target newTarget ) { this.newTarget = newTarget; }
|
||||
readonly Target target;
|
||||
public AttackActivity( Target newTarget ) { this.target = newTarget; }
|
||||
|
||||
public override IActivity Tick( Actor self )
|
||||
{
|
||||
if( IsCanceled ) return NextActivity;
|
||||
if( IsCanceled || !target.IsValid ) return NextActivity;
|
||||
|
||||
if (self.TraitsImplementing<IDisable>().Any(d => d.Disabled))
|
||||
return this;
|
||||
|
||||
var attack = self.Trait<AttackTurreted>();
|
||||
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)
|
||||
{
|
||||
attack.target = newTarget;
|
||||
attack.target = target;
|
||||
|
||||
if (self.HasTrait<Mobile>() && !self.Info.Traits.Get<MobileInfo>().OnRails)
|
||||
self.QueueActivity( new Follow( newTarget,
|
||||
Math.Max( 0, (int)weapon.Info.Range - RangeTolerance ) ) );
|
||||
return Util.SequenceActivities(
|
||||
new Follow( target, Math.Max( 0, (int)weapon.Info.Range - RangeTolerance ) ),
|
||||
this );
|
||||
}
|
||||
return NextActivity;
|
||||
}
|
||||
|
||||
@@ -11,61 +11,76 @@
|
||||
using System.Linq;
|
||||
using OpenRA.Mods.RA.Activities;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Traits.Activities;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
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>();
|
||||
if (target != null)
|
||||
attack.ResolveOrder(self, new Order("Attack", self, target, false));
|
||||
else
|
||||
if (attack.IsAttacking)
|
||||
self.CancelActivity();
|
||||
self.QueueActivity( new IdleHealActivity() );
|
||||
}
|
||||
|
||||
bool NeedsNewTarget(Actor self)
|
||||
class IdleHealActivity : Idle
|
||||
{
|
||||
var attack = self.Trait<AttackBase>();
|
||||
var range = attack.GetMaximumRange();
|
||||
Actor currentTarget;
|
||||
|
||||
if (!attack.target.IsValid)
|
||||
return true; // he's dead.
|
||||
if( !Combat.IsInRange( self.CenterLocation, range, attack.target ) )
|
||||
return true; // wandered off faster than we could follow
|
||||
|
||||
if (attack.target.IsActor
|
||||
&& attack.target.Actor.GetDamageState() == DamageState.Undamaged)
|
||||
return true; // fully healed
|
||||
public override IActivity Tick( Actor self )
|
||||
{
|
||||
if( NextActivity != null )
|
||||
return NextActivity;
|
||||
|
||||
return false;
|
||||
}
|
||||
var attack = self.Trait<AttackBase>();
|
||||
var range = attack.GetMaximumRange();
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
var attack = self.Trait<AttackBase>();
|
||||
var range = attack.GetMaximumRange();
|
||||
if (NeedsNewTarget(self))
|
||||
AttackTarget(self, ChooseTarget(self, range));
|
||||
|
||||
if (NeedsNewTarget(self))
|
||||
AttackTarget(self, ChooseTarget(self, range));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
Actor ChooseTarget(Actor self, float range)
|
||||
{
|
||||
var inRange = self.World.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range);
|
||||
var attack = self.Trait<AttackBase>();
|
||||
void AttackTarget(Actor self, Actor target)
|
||||
{
|
||||
var attack = self.Trait<AttackBase>();
|
||||
if (target != null)
|
||||
attack.AttackTarget(Target.FromActor( target), false, true );
|
||||
else
|
||||
if (attack.IsAttacking)
|
||||
self.CancelActivity();
|
||||
}
|
||||
|
||||
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();
|
||||
bool NeedsNewTarget(Actor self)
|
||||
{
|
||||
var attack = self.Trait<AttackBase>();
|
||||
var range = attack.GetMaximumRange();
|
||||
|
||||
if (currentTarget == null || !currentTarget.IsInWorld)
|
||||
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
|
||||
|
||||
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)
|
||||
{
|
||||
Actors["mig1"].Trait<AttackPlane>().AttackTarget(Actors["mig1"], Actors["greeceweap"], true);
|
||||
Actors["mig2"].Trait<AttackPlane>().AttackTarget(Actors["mig2"], Actors["greeceweap"], true);
|
||||
Actors["mig3"].Trait<AttackPlane>().AttackTarget(Actors["mig3"], Actors["greeceweap"], true);
|
||||
Actors["mig1"].Trait<AttackPlane>().AttackTarget(Target.FromActor(Actors["greeceweap"]), false, true);
|
||||
Actors["mig2"].Trait<AttackPlane>().AttackTarget(Target.FromActor(Actors["greeceweap"]), false, true);
|
||||
Actors["mig3"].Trait<AttackPlane>().AttackTarget(Target.FromActor(Actors["greeceweap"]), false, true);
|
||||
}
|
||||
|
||||
ticks++;
|
||||
|
||||
@@ -8,7 +8,7 @@ using OpenRA.Traits;
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
|
||||
public class UnitStanceInfo : ITraitInfo
|
||||
public class UnitStanceInfo : ITraitInfo, ITraitPrerequisite<AttackBaseInfo>
|
||||
{
|
||||
public readonly bool Default = false;
|
||||
public readonly int ScanDelayMin = 12;
|
||||
@@ -167,12 +167,8 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
public static void AttackTarget(Actor self, Actor target, bool holdStill)
|
||||
{
|
||||
var attack = self.Trait<AttackBase>();
|
||||
|
||||
if (attack != null && target != null)
|
||||
{
|
||||
attack.ResolveOrder(self, new Order((holdStill) ? "AttackHold" : "Attack", self, target, false));
|
||||
}
|
||||
if (target != null)
|
||||
self.Trait<AttackBase>().AttackTarget(Target.FromActor(target), false, !holdStill);
|
||||
}
|
||||
|
||||
public static void StopAttack(Actor self)
|
||||
@@ -199,7 +195,7 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
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)
|
||||
|
||||
@@ -135,7 +135,7 @@ namespace OpenRA.Mods.RA
|
||||
.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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user