Added: UnitStanceDefensive
This commit is contained in:
@@ -59,6 +59,7 @@
|
|||||||
<Compile Include="Activities\Demolish.cs" />
|
<Compile Include="Activities\Demolish.cs" />
|
||||||
<Compile Include="Activities\Enter.cs" />
|
<Compile Include="Activities\Enter.cs" />
|
||||||
<Compile Include="Activities\EnterTransport.cs" />
|
<Compile Include="Activities\EnterTransport.cs" />
|
||||||
|
<Compile Include="UnitStances\UnitStanceDefensive.cs" />
|
||||||
<Compile Include="UnitStances\UnitStanceAggressive.cs" />
|
<Compile Include="UnitStances\UnitStanceAggressive.cs" />
|
||||||
<Compile Include="Air\Fly.cs" />
|
<Compile Include="Air\Fly.cs" />
|
||||||
<Compile Include="Air\FlyAttack.cs" />
|
<Compile Include="Air\FlyAttack.cs" />
|
||||||
|
|||||||
163
OpenRA.Mods.RA/UnitStances/UnitStanceDefensive.cs
Normal file
163
OpenRA.Mods.RA/UnitStances/UnitStanceDefensive.cs
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using OpenRA.Mods.RA.Move;
|
||||||
|
using OpenRA.Traits;
|
||||||
|
|
||||||
|
namespace OpenRA.Mods.RA
|
||||||
|
{
|
||||||
|
public class UnitStanceDefensiveInfo : UnitStanceInfo
|
||||||
|
{
|
||||||
|
public override object Create(ActorInitializer init) { return new UnitStanceDefensive(init.self, this); }
|
||||||
|
public readonly int MaxDistance = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return Fire
|
||||||
|
///
|
||||||
|
/// Will fire only when fired upon
|
||||||
|
/// </summary>
|
||||||
|
public class UnitStanceDefensive : UnitStance, INotifyDamage
|
||||||
|
{
|
||||||
|
public enum ETargetType
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Location,
|
||||||
|
Actor
|
||||||
|
}
|
||||||
|
|
||||||
|
[Sync] public int MaxDistance;
|
||||||
|
public Target DefendTarget = Target.None;
|
||||||
|
public ETargetType TargetType = ETargetType.None;
|
||||||
|
public bool WaitingForIdle = false;
|
||||||
|
[Sync]
|
||||||
|
public bool IsReturning { get; protected set; }
|
||||||
|
|
||||||
|
public UnitStanceDefensive(Actor self, UnitStanceDefensiveInfo info)
|
||||||
|
: base(self, info)
|
||||||
|
{
|
||||||
|
MaxDistance = info.MaxDistance;
|
||||||
|
|
||||||
|
base.AllowMultiTrigger = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnActivate(Actor self)
|
||||||
|
{
|
||||||
|
DefendThis(self.CenterLocation);
|
||||||
|
|
||||||
|
if (!self.IsIdle)
|
||||||
|
WaitForIdle();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void DefendThis(float2 target)
|
||||||
|
{
|
||||||
|
DefendTarget = Target.FromPos(target);
|
||||||
|
TargetType = ETargetType.Location;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void DefendThis(Actor target)
|
||||||
|
{
|
||||||
|
DefendTarget = Target.FromActor(target);
|
||||||
|
TargetType = ETargetType.Actor;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnScan(Actor self)
|
||||||
|
{
|
||||||
|
if (TargetType == ETargetType.None) return;
|
||||||
|
if (IsReturning) return;
|
||||||
|
if (!self.IsIdle) return;
|
||||||
|
if (!self.HasTrait<AttackBase>()) return;
|
||||||
|
|
||||||
|
var target = ScanForTarget(self);
|
||||||
|
if (target == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
AttackTarget(self, target, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnTick(Actor self)
|
||||||
|
{
|
||||||
|
if (!self.HasTrait<AttackBase>()) return;
|
||||||
|
|
||||||
|
// when the unit is doing nothing or the target actor is gone, tell him to defend the current location
|
||||||
|
if ((WaitingForIdle && self.IsIdle) || (self.IsIdle && (TargetType == ETargetType.Actor && !DefendTarget.IsValid)))
|
||||||
|
{
|
||||||
|
IsReturning = false;
|
||||||
|
WaitingForIdle = false;
|
||||||
|
DefendThis(self.CenterLocation);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (IsReturning && self.IsIdle)
|
||||||
|
{
|
||||||
|
IsReturning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TargetType != ETargetType.None)
|
||||||
|
{
|
||||||
|
if ((self.CenterLocation - DefendTarget.CenterLocation).Length > MaxDistance * Game.CellSize)
|
||||||
|
{
|
||||||
|
Return(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnOrder(Actor self, Order order)
|
||||||
|
{
|
||||||
|
WaitForIdle();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WaitForIdle()
|
||||||
|
{
|
||||||
|
// could be an attack or move order ... => 'disable' the stance for now (invalidate the target)
|
||||||
|
DefendTarget = Target.None;
|
||||||
|
TargetType = ETargetType.None;
|
||||||
|
WaitingForIdle = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Damaged(Actor self, AttackInfo e)
|
||||||
|
{
|
||||||
|
if (!Active) return;
|
||||||
|
if (TargetType == ETargetType.None) return;
|
||||||
|
if (IsReturning) return;
|
||||||
|
if (!self.HasTrait<AttackBase>()) return;
|
||||||
|
|
||||||
|
ReturnFire(self, e, false); // only triggers when standing still
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string OrderString
|
||||||
|
{
|
||||||
|
get { return "StanceDefensive"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Color SelectionColor
|
||||||
|
{
|
||||||
|
get { return Color.LightGoldenrodYellow; }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string Shape
|
||||||
|
{
|
||||||
|
get { return "xxxx\nxxxx"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void Return(Actor self)
|
||||||
|
{
|
||||||
|
if ((TargetType == ETargetType.None) || (!DefendTarget.IsValid && (TargetType == ETargetType.Actor && !DefendTarget.IsValid))) return;
|
||||||
|
IsReturning = true;
|
||||||
|
|
||||||
|
var attackBase = self.TraitOrDefault<AttackBase>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Reset the attack target => otherwise it will not pick up enemies anymore!
|
||||||
|
|
||||||
|
// This should result in unsetting the target (could do it directly, this seems more 'valid')
|
||||||
|
self.World.AddFrameEndTask(w =>
|
||||||
|
{
|
||||||
|
self.CancelActivity();
|
||||||
|
attackBase.ResolveOrder(self, new Order("Stop", self));
|
||||||
|
self.QueueActivity(self.Trait<Mobile>().MoveWithinRange(DefendTarget, 1));
|
||||||
|
WaitForIdle();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,10 +14,10 @@ namespace OpenRA.Mods.RA.Widgets
|
|||||||
|
|
||||||
public char AttackMoveKey = 'a';
|
public char AttackMoveKey = 'a';
|
||||||
public char HoldGroundKey = 'g'; // Hold (G)round
|
public char HoldGroundKey = 'g'; // Hold (G)round
|
||||||
// public char DefensiveKey = 'd'; // (D)efensive
|
public char DefensiveKey = 'd'; // (D)efensive
|
||||||
public char AggressiveKey = 'a'; // (A)ggressive
|
public char AggressiveKey = 'a'; // (A)ggressive
|
||||||
public char ReturnFireKey = 'r'; // (R)eturn Fire
|
public char ReturnFireKey = 'r'; // (R)eturn Fire
|
||||||
public char HoldFire = 'h'; // (h)old fire
|
public char HoldFireKey = 'h'; // (h)old fire
|
||||||
public readonly OrderManager OrderManager;
|
public readonly OrderManager OrderManager;
|
||||||
|
|
||||||
[ObjectCreator.UseCtor]
|
[ObjectCreator.UseCtor]
|
||||||
@@ -73,11 +73,17 @@ namespace OpenRA.Mods.RA.Widgets
|
|||||||
|
|
||||||
// stance: Hold Fire
|
// stance: Hold Fire
|
||||||
// description: Prevents attacking (ie no autotarget is being done)
|
// description: Prevents attacking (ie no autotarget is being done)
|
||||||
if (e.KeyChar == HoldFire && (e.Modifiers.HasModifier(Modifiers.Alt)))
|
if (e.KeyChar == HoldFireKey && (e.Modifiers.HasModifier(Modifiers.Alt)))
|
||||||
{
|
{
|
||||||
return EnableStance<UnitStanceHoldFire>();
|
return EnableStance<UnitStanceHoldFire>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// stance: Defensive
|
||||||
|
if (e.KeyChar == DefensiveKey && (e.Modifiers.HasModifier(Modifiers.Alt)))
|
||||||
|
{
|
||||||
|
return EnableStance<UnitStanceDefensive>();
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user