Some thoughts towards improving our bogus idle handling. Untested.
This commit is contained in:
@@ -68,7 +68,7 @@ namespace OpenRA
|
|||||||
|
|
||||||
public void Tick()
|
public void Tick()
|
||||||
{
|
{
|
||||||
if (currentActivity == null)
|
if (currentActivity == null || currentActivity is Idle)
|
||||||
foreach (var ni in TraitsImplementing<INotifyIdle>())
|
foreach (var ni in TraitsImplementing<INotifyIdle>())
|
||||||
ni.TickIdle(this);
|
ni.TickIdle(this);
|
||||||
|
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
#region Copyright & License Information
|
|
||||||
/*
|
|
||||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
|
||||||
* This file is part of OpenRA, which is free software. It is made
|
|
||||||
* available to you under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation. For more information,
|
|
||||||
* see LICENSE.
|
|
||||||
*/
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using OpenRA.Mods.RA.Render;
|
|
||||||
using OpenRA.Traits;
|
|
||||||
using OpenRA.Traits.Activities;
|
|
||||||
|
|
||||||
namespace OpenRA.Mods.RA.Activities
|
|
||||||
{
|
|
||||||
public class IdleAnimation : Idle
|
|
||||||
{
|
|
||||||
string sequence;
|
|
||||||
int delay;
|
|
||||||
|
|
||||||
public IdleAnimation(string sequence, int delay)
|
|
||||||
{
|
|
||||||
this.sequence = sequence;
|
|
||||||
this.delay = delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool active = true;
|
|
||||||
public override IActivity Tick(Actor self)
|
|
||||||
{
|
|
||||||
if (!active) return NextActivity;
|
|
||||||
|
|
||||||
if (delay > 0 && --delay == 0)
|
|
||||||
self.Trait<RenderInfantry>().anim.PlayThen(sequence, () => active = false);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnCancel( Actor self )
|
|
||||||
{
|
|
||||||
active = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -18,71 +18,47 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
class AutoHeal : INotifyIdle
|
class AutoHeal : INotifyIdle
|
||||||
{
|
{
|
||||||
public void TickIdle( Actor self )
|
bool NeedsNewTarget(Actor self)
|
||||||
{
|
{
|
||||||
self.QueueActivity( new IdleHealActivity() );
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
class IdleHealActivity : Idle
|
Actor ChooseTarget(Actor self, float range)
|
||||||
{
|
{
|
||||||
Actor currentTarget;
|
var inRange = self.World.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range);
|
||||||
IActivity inner;
|
var attack = self.Trait<AttackBase>();
|
||||||
|
|
||||||
public override IActivity Tick( Actor self )
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
Actor currentTarget;
|
||||||
|
public void TickIdle( Actor self )
|
||||||
|
{
|
||||||
|
var attack = self.Trait<AttackBase>();
|
||||||
|
var range = attack.GetMaximumRange();
|
||||||
|
|
||||||
|
if (NeedsNewTarget(self))
|
||||||
{
|
{
|
||||||
if( inner == null )
|
var currentTarget = ChooseTarget(self, range);
|
||||||
{
|
if( currentTarget != null )
|
||||||
if( NextActivity != null )
|
self.QueueActivity(self.Trait<AttackBase>().GetAttackActivity(self, Target.FromActor( currentTarget ), false ));
|
||||||
return NextActivity;
|
|
||||||
|
|
||||||
var attack = self.Trait<AttackBase>();
|
|
||||||
var range = attack.GetMaximumRange();
|
|
||||||
|
|
||||||
if (NeedsNewTarget(self))
|
|
||||||
{
|
|
||||||
currentTarget = ChooseTarget(self, range);
|
|
||||||
if( currentTarget != null )
|
|
||||||
inner = self.Trait<AttackBase>().GetAttackActivity(self, Target.FromActor( currentTarget ), false );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( inner != null )
|
|
||||||
{
|
|
||||||
if( NeedsNewTarget(self) )
|
|
||||||
inner.Cancel( self );
|
|
||||||
inner = Util.RunActivity( self, inner );
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,33 +39,13 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public void TickIdle( Actor self )
|
public void TickIdle( Actor self )
|
||||||
{
|
{
|
||||||
self.QueueActivity( new IdleAttackActivity() );
|
var attack = self.Trait<AttackBase>();
|
||||||
}
|
var currentTarget = attack.ScanForTarget(self, null);
|
||||||
|
if( currentTarget != null )
|
||||||
class IdleAttackActivity : Idle
|
self.QueueActivity(attack.GetAttackActivity( self,
|
||||||
{
|
Target.FromActor(currentTarget),
|
||||||
Actor currentTarget;
|
self.Info.Traits.Get<AutoTargetInfo>().AllowMovement
|
||||||
IActivity inner;
|
));
|
||||||
|
|
||||||
public override IActivity Tick( Actor self )
|
|
||||||
{
|
|
||||||
if( NextActivity != null && inner != null )
|
|
||||||
inner.Cancel( self );
|
|
||||||
if( inner == null )
|
|
||||||
{
|
|
||||||
if( NextActivity != null )
|
|
||||||
return NextActivity;
|
|
||||||
|
|
||||||
var attack = self.Trait<AttackBase>();
|
|
||||||
currentTarget = attack.ScanForTarget(self, null);
|
|
||||||
if( currentTarget != null )
|
|
||||||
inner = attack.GetAttackActivity( self, Target.FromActor(currentTarget), self.Info.Traits.Get<AutoTargetInfo>().AllowMovement );
|
|
||||||
}
|
|
||||||
if( inner != null )
|
|
||||||
inner = Util.RunActivity( self, inner );
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
|
using OpenRA.Mods.RA.Render;
|
||||||
|
|
||||||
namespace OpenRA.Mods.RA
|
namespace OpenRA.Mods.RA
|
||||||
{
|
{
|
||||||
@@ -20,24 +21,61 @@ namespace OpenRA.Mods.RA
|
|||||||
}
|
}
|
||||||
|
|
||||||
// infantry prone behavior
|
// infantry prone behavior
|
||||||
class IdleAnimation : INotifyDamage, INotifyIdle
|
class IdleAnimation : ITick, INotifyIdle
|
||||||
{
|
{
|
||||||
IdleAnimationInfo Info;
|
IdleAnimationInfo Info;
|
||||||
|
string sequence;
|
||||||
|
int delay;
|
||||||
|
bool active, waiting;
|
||||||
|
|
||||||
public IdleAnimation(IdleAnimationInfo info)
|
public IdleAnimation(IdleAnimationInfo info)
|
||||||
{
|
{
|
||||||
Info = info;
|
Info = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Damaged(Actor self, AttackInfo e)
|
|
||||||
{
|
|
||||||
if (self.GetCurrentActivity() is Activities.IdleAnimation)
|
|
||||||
self.CancelActivity();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public void Tick(Actor self)
|
||||||
|
{
|
||||||
|
if (active)
|
||||||
|
{
|
||||||
|
//System.Console.WriteLine("active: {0} ({1})", self.Info.Name, self.ActorID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!self.IsIdle)
|
||||||
|
{
|
||||||
|
//System.Console.WriteLine("notidle: {0} ({1}) ",self.Info.Name, self.ActorID);
|
||||||
|
active = false;
|
||||||
|
waiting = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delay > 0 && --delay == 0)
|
||||||
|
{
|
||||||
|
System.Console.WriteLine("activate: {0} ({1})",self.Info.Name, self.ActorID);
|
||||||
|
active = true;
|
||||||
|
waiting = false;
|
||||||
|
self.Trait<RenderInfantry>().anim.PlayThen(sequence, () =>
|
||||||
|
{
|
||||||
|
//System.Console.WriteLine("finished: {0} ({1}) ",self.Info.Name, self.ActorID);
|
||||||
|
active = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void TickIdle(Actor self)
|
public void TickIdle(Actor self)
|
||||||
{
|
{
|
||||||
self.QueueActivity(new Activities.IdleAnimation(Info.Animations.Random(self.World.SharedRandom),
|
//if (active)
|
||||||
Info.IdleWaitTicks));
|
// System.Console.WriteLine("idleactive: {0} ({1}) ",self.Info.Name, self.ActorID);
|
||||||
|
|
||||||
|
//if (waiting)
|
||||||
|
// System.Console.WriteLine("idlewaiting: {0} ({1}) ",self.Info.Name, self.ActorID);
|
||||||
|
if (active || waiting)
|
||||||
|
return;
|
||||||
|
|
||||||
|
waiting = true;
|
||||||
|
sequence = Info.Animations.Random(self.World.SharedRandom);
|
||||||
|
delay = Info.IdleWaitTicks;
|
||||||
|
//System.Console.WriteLine("TickIdle: {2} ({3}) set {0} {1}",sequence,delay, self.Info.Name, self.ActorID);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -299,7 +299,6 @@
|
|||||||
<Compile Include="HackyAI.cs" />
|
<Compile Include="HackyAI.cs" />
|
||||||
<Compile Include="RALoadScreen.cs" />
|
<Compile Include="RALoadScreen.cs" />
|
||||||
<Compile Include="NullLoadScreen.cs" />
|
<Compile Include="NullLoadScreen.cs" />
|
||||||
<Compile Include="Activities\IdleAnimation.cs" />
|
|
||||||
<Compile Include="IdleAnimation.cs" />
|
<Compile Include="IdleAnimation.cs" />
|
||||||
<Compile Include="World\GotoNextBase.cs" />
|
<Compile Include="World\GotoNextBase.cs" />
|
||||||
<Compile Include="World\SmudgeLayer.cs" />
|
<Compile Include="World\SmudgeLayer.cs" />
|
||||||
|
|||||||
@@ -67,14 +67,16 @@ namespace OpenRA.Mods.RA.Render
|
|||||||
{
|
{
|
||||||
base.Tick(self);
|
base.Tick(self);
|
||||||
if (inAttack) return;
|
if (inAttack) return;
|
||||||
if (self.GetCurrentActivity() is Activities.IdleAnimation) return;
|
if (self.IsIdle) return;
|
||||||
if (ChooseMoveAnim(self)) return;
|
if (ChooseMoveAnim(self)) return;
|
||||||
|
|
||||||
if (IsProne(self))
|
// TODO: Pick new animation only on damage or idle notifications
|
||||||
anim.PlayFetchIndex("crawl", () => 0); /* what a hack. */
|
//if (IsProne(self))
|
||||||
else
|
// anim.PlayFetchIndex("crawl", () => 0); /* what a hack. */
|
||||||
anim.Play("stand");
|
//else
|
||||||
|
// anim.Play("stand");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Damaged(Actor self, AttackInfo e)
|
public void Damaged(Actor self, AttackInfo e)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user