Implemented: Stances

Added: Basic stances (Aggressive, Guard (Hold Ground), Hold Fire, None (dummy), Return Fire)
Added: WorldCommandWidget (to be able to set said stances)
Added: WorldCommandWidget to ra (cnc will follow, later on)
Changed: Added support to AttackBase for firing with movement disabled + utility method ScanForTarget (used by stances)
Added: AssignUnitStance (attach this to unit-producing actors, together with what stances can be picked as 'default')
This commit is contained in:
geckosoft
2010-11-11 04:28:11 +01:00
committed by Bob
parent 6d67ab2240
commit 6b40abb58c
18 changed files with 640 additions and 29 deletions

View File

@@ -147,9 +147,10 @@ namespace OpenRA.Mods.RA
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "Attack")
if (order.OrderString == "Attack" || order.OrderString == "AttackHold")
{
self.QueueActivity(order.Queued, GetAttackActivity(self, Target.FromOrder(order)));
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 =>
@@ -163,24 +164,29 @@ namespace OpenRA.Mods.RA
if (order.TargetActor != null) line.SetTarget(self, Target.FromOrder(order), Color.Red);
else line.SetTarget(self, Target.FromOrder(order), Color.Red);
});
}
else
return;
} // else not an attack order
// StopAttack order cancels the current activity IF it is an attack one
if (order.OrderString == "StopAttack")
{
target = Target.None;
/* hack */
if (self.HasTrait<Turreted>() && self.Info.Traits.Get<AttackBaseInfo>().AlignIdleTurrets)
self.Trait<Turreted>().desiredFacing = null;
if (self.GetCurrentActivity() is Activities.Attack)
self.GetCurrentActivity().Cancel(self);
}
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)
{
return (order.OrderString == "Attack") ? "Attack" : null;
return (order.OrderString == "Attack" || order.OrderString == "AttackHold") ? "Attack" : null;
}
protected abstract IActivity GetAttackActivity(Actor self, Target newTarget);
protected abstract IActivity 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); }
@@ -188,26 +194,30 @@ 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)
{
AttackTarget(self, target, allowMovement, false);
}
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("Attack", self, target, false));
attack.ResolveOrder(self, new Order((holdStill) ? "AttackHold" : "Attack", self, target, false));
else
attack.target = Target.FromActor(target); // for turreted things on rails.
}
}
public void ScanAndAttack(Actor self, bool allowMovement)
public void ScanAndAttack(Actor self, bool allowMovement, bool holdStill)
{
if (--nextScanTime <= 0)
{
var attack = self.Trait<AttackBase>();
var range = attack.GetMaximumRange();
var targetActor = ScanForTarget(self);
if (!attack.target.IsValid || !Combat.IsInRange( self.CenterLocation, range, attack.target ))
AttackTarget(self, ChooseTarget(self, range), allowMovement);
if (targetActor != null)
AttackTarget(self, targetActor, allowMovement, holdStill);
var info = self.Info.Traits.Get<AttackBaseInfo>();
nextScanTime = (int)(25 * (info.ScanTimeAverage +
@@ -215,6 +225,22 @@ namespace OpenRA.Mods.RA
}
}
public Actor ScanForTarget(Actor self)
{
var attack = self.Trait<AttackBase>();
var range = attack.GetMaximumRange();
if ((!attack.target.IsValid || self.IsIdle) || !Combat.IsInRange(self.CenterLocation, range, attack.target))
return ChooseTarget(self, range);
return null;
}
public void ScanAndAttack(Actor self, bool allowMovement)
{
ScanAndAttack(self, allowMovement, false);
}
Actor ChooseTarget(Actor self, float range)
{
var inRange = self.World.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range);