Added attack move
This commit is contained in:
19
OpenRA.Mods.RA/Activities/AttackMove.cs
Normal file
19
OpenRA.Mods.RA/Activities/AttackMove.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Traits.Activities;
|
||||
|
||||
namespace OpenRA.Mods.RA.Activities
|
||||
{
|
||||
public class AttackMove : Move
|
||||
{
|
||||
public AttackMove(int2 destination) : base(destination) { }
|
||||
public AttackMove(int2 destination, int nearEnough) : base(destination, nearEnough) { }
|
||||
public AttackMove(int2 destination, Actor ignoreBuilding) : base(destination, ignoreBuilding) { }
|
||||
public AttackMove(Actor target, int range) : base(target, range) { }
|
||||
public AttackMove(Target target, int range) : base(target, range) { }
|
||||
public AttackMove(Func<List<int2>> getPath) : base(getPath) { }
|
||||
}
|
||||
}
|
||||
@@ -36,11 +36,17 @@ namespace OpenRA.Mods.RA
|
||||
public readonly bool AlignIdleTurrets = false;
|
||||
public readonly bool CanAttackGround = true;
|
||||
|
||||
public readonly float ScanTimeAverage = 2f;
|
||||
public readonly float ScanTimeSpread = .5f;
|
||||
|
||||
public virtual object Create(ActorInitializer init) { return new AttackBase(init.self); }
|
||||
}
|
||||
|
||||
public class AttackBase : IIssueOrder, IResolveOrder, ITick, IExplodeModifier, IOrderVoice
|
||||
{
|
||||
[Sync]
|
||||
int nextScanTime = 0;
|
||||
|
||||
public bool IsAttacking { get; internal set; }
|
||||
public Target target;
|
||||
|
||||
@@ -228,6 +234,7 @@ namespace OpenRA.Mods.RA
|
||||
if (self.HasTrait<Turreted>() && self.Info.Traits.Get<AttackBaseInfo>().AlignIdleTurrets)
|
||||
self.Trait<Turreted>().desiredFacing = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
@@ -251,6 +258,48 @@ 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)
|
||||
{
|
||||
var attack = self.Trait<AttackBase>();
|
||||
if (target != null)
|
||||
{
|
||||
if (allowMovement)
|
||||
attack.ResolveOrder(self, new Order("Attack", self, target));
|
||||
else
|
||||
attack.target = Target.FromActor(target); // for turreted things on rails.
|
||||
}
|
||||
}
|
||||
|
||||
public void ScanAndAttack(Actor self, bool allowMovement)
|
||||
{
|
||||
if (--nextScanTime <= 0)
|
||||
{
|
||||
var attack = self.Trait<AttackBase>();
|
||||
var range = attack.GetMaximumRange();
|
||||
|
||||
if (!attack.target.IsValid ||
|
||||
(Util.CellContaining(attack.target.CenterLocation) - self.Location).LengthSquared > range * range)
|
||||
AttackTarget(self, ChooseTarget(self, range), allowMovement);
|
||||
|
||||
var info = self.Info.Traits.Get<AttackBaseInfo>();
|
||||
nextScanTime = (int)(25 * (info.ScanTimeAverage +
|
||||
(self.World.SharedRandom.NextDouble() * 2 - 1) * info.ScanTimeSpread));
|
||||
}
|
||||
}
|
||||
|
||||
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 => !a.HasTrait<Cloak>() || a.Trait<Cloak>().IsVisible(a, self.Owner))
|
||||
.OrderBy(a => (a.Location - self.Location).LengthSquared)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
class AttackOrderTargeter : IOrderTargeter
|
||||
{
|
||||
readonly bool isHeal;
|
||||
@@ -292,6 +341,6 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
74
OpenRA.Mods.RA/AttackMoveTrait.cs
Normal file
74
OpenRA.Mods.RA/AttackMoveTrait.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Effects;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
class AttackMoveInfo : TraitInfo<AttackMove>
|
||||
{
|
||||
//public object Create(ActorInitializer init) { return new AttackMove(init.self); }
|
||||
public readonly bool JustMove = false;
|
||||
}
|
||||
|
||||
class AttackMove : ITick, IResolveOrder, IOrderVoice
|
||||
{
|
||||
public bool AttackMoving { get; set; }
|
||||
|
||||
public string VoicePhraseForOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "AttackMove")
|
||||
{
|
||||
return "AttackMove";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "AttackMove")
|
||||
{
|
||||
self.CancelActivity();
|
||||
//if we are just moving, we don't turn on attackmove and this becomes a regular move order
|
||||
if (!self.Info.Traits.Get<AttackMoveInfo>().JustMove)
|
||||
{
|
||||
AttackMoving = true;
|
||||
}
|
||||
Order newOrder = new Order("Move", order.Subject, order.TargetLocation);
|
||||
self.Trait<Mobile>().ResolveOrder(self, newOrder);
|
||||
|
||||
if (self.Owner == self.World.LocalPlayer)
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
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);
|
||||
});
|
||||
|
||||
if (self.Owner == self.Owner.World.LocalPlayer)
|
||||
self.World.CancelInputMode();
|
||||
}
|
||||
else
|
||||
{
|
||||
AttackMoving = false; //cancel attack move state for other orders
|
||||
}
|
||||
}
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
if (self.Info.Traits.Get<AttackMoveInfo>().JustMove) return;
|
||||
if (!self.HasTrait<AttackBase>())
|
||||
{
|
||||
Game.Debug("AttackMove: {0} has no AttackBase trait".F(self.ToString()));
|
||||
return;
|
||||
}
|
||||
if (!self.IsIdle && (self.HasTrait<AttackMove>() && !(self.Trait<AttackMove>().AttackMoving))) return;
|
||||
|
||||
self.Trait<AttackBase>().ScanAndAttack(self, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,65 +8,22 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
class AutoTargetInfo : TraitInfo<AutoTarget>
|
||||
{
|
||||
public readonly float ScanTimeAverage = 2f;
|
||||
public readonly float ScanTimeSpread = .5f;
|
||||
public readonly bool AllowMovement = true;
|
||||
}
|
||||
|
||||
class AutoTarget : ITick, INotifyDamage
|
||||
{
|
||||
[Sync]
|
||||
int nextScanTime = 0;
|
||||
|
||||
void AttackTarget(Actor self, Actor target)
|
||||
{
|
||||
var attack = self.Trait<AttackBase>();
|
||||
if (target != null)
|
||||
{
|
||||
if (self.Info.Traits.Get<AutoTargetInfo>().AllowMovement)
|
||||
attack.ResolveOrder(self, new Order("Attack", self, target));
|
||||
else
|
||||
attack.target = Target.FromActor(target); // for turreted things on rails.
|
||||
}
|
||||
}
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
if (!self.IsIdle && self.Info.Traits.Get<AutoTargetInfo>().AllowMovement) return;
|
||||
|
||||
if (--nextScanTime <= 0)
|
||||
{
|
||||
var attack = self.Trait<AttackBase>();
|
||||
var range = attack.GetMaximumRange();
|
||||
|
||||
if (!attack.target.IsValid ||
|
||||
(Util.CellContaining(attack.target.CenterLocation) - self.Location).LengthSquared > range * range)
|
||||
AttackTarget(self, ChooseTarget(self, range));
|
||||
|
||||
var info = self.Info.Traits.Get<AutoTargetInfo>();
|
||||
nextScanTime = (int)(25 * (info.ScanTimeAverage +
|
||||
(self.World.SharedRandom.NextDouble() * 2 - 1) * info.ScanTimeSpread));
|
||||
}
|
||||
}
|
||||
|
||||
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 => !a.HasTrait<Cloak>() || a.Trait<Cloak>().IsVisible(a,self.Owner))
|
||||
.OrderBy(a => (a.Location - self.Location).LengthSquared)
|
||||
.FirstOrDefault();
|
||||
self.Trait<AttackBase>().ScanAndAttack(self, self.Info.Traits.Get<AutoTargetInfo>().AllowMovement);
|
||||
}
|
||||
|
||||
public void Damaged(Actor self, AttackInfo e)
|
||||
@@ -83,7 +40,7 @@ namespace OpenRA.Mods.RA
|
||||
|
||||
if (e.Damage < 0) return; // don't retaliate against healers
|
||||
|
||||
AttackTarget(self, e.Attacker);
|
||||
self.Trait<AttackBase>().AttackTarget(self, e.Attacker, self.Info.Traits.Get<AutoTargetInfo>().AllowMovement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
<Compile Include="Activities\UnloadCargo.cs" />
|
||||
<Compile Include="Activities\Wait.cs" />
|
||||
<Compile Include="AttackBase.cs" />
|
||||
<Compile Include="AttackMoveTrait.cs" />
|
||||
<Compile Include="Buildable.cs" />
|
||||
<Compile Include="Combat.cs" />
|
||||
<Compile Include="Crates\CloakCrateAction.cs" />
|
||||
|
||||
Reference in New Issue
Block a user