1
0
forked from 0ad/0ad

Fixed formations so switching formation in-place doesn't leave entities in FORMATIONMEMBER.WALKING and short walk orders bring units into proper formation.

This was SVN commit r12563.
This commit is contained in:
Deiz 2012-08-31 08:20:36 +00:00
parent d98c62f00a
commit 9fcb7cc738
5 changed files with 60 additions and 12 deletions

View File

@ -8,6 +8,7 @@ var g_ColumnDistanceThreshold = 128; // distance at which we'll switch between c
Formation.prototype.Init = function()
{
this.members = []; // entity IDs currently belonging to this formation
this.inPosition = []; // entities that have reached their final position
this.columnar = false; // whether we're travelling in column (vs box) formation
this.formationName = "Line Closed";
this.rearrange = true; // whether we should rearrange all formation members
@ -30,6 +31,29 @@ Formation.prototype.GetPrimaryMember = function()
return this.members[0];
};
/**
* Permits formation members to register that they've reached their
* destination, and automatically disbands the formation if all members
* are at their final positions and no controller orders remain.
*/
Formation.prototype.SetInPosition = function(ent)
{
if (this.inPosition.indexOf(ent) != -1)
return;
// Only consider automatically disbanding if there are no orders left.
var cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI);
if (cmpUnitAI.GetOrders().length)
{
this.inPosition = [];
return;
}
this.inPosition.push(ent);
if (this.inPosition.length >= this.members.length)
this.Disband();
};
/**
* Set whether we should rearrange formation members if
* units are removed from the formation.
@ -67,6 +91,7 @@ Formation.prototype.SetMembers = function(ents)
Formation.prototype.RemoveMembers = function(ents)
{
this.members = this.members.filter(function(e) { return ents.indexOf(e) == -1; });
this.inPosition = this.inPosition.filter(function(e) { return ents.indexOf(e) == -1; });
for each (var ent in ents)
{
@ -102,6 +127,7 @@ Formation.prototype.Disband = function()
}
this.members = [];
this.inPosition = [];
Engine.DestroyEntity(this.entity);
};

View File

@ -593,11 +593,7 @@ var UnitFsmSpec = {
},
"MoveCompleted": function(msg) {
if (this.FinishOrder())
return;
var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation);
cmpFormation.Disband();
this.FinishOrder();
},
},
@ -674,9 +670,13 @@ var UnitFsmSpec = {
this.SelectAnimation("move");
},
// (We stay in this state even if we're already in position
// and no longer moving, because the formation controller might
// move and we'll automatically start chasing after it again)
// Occurs when the unit has reached its destination and the controller
// is done moving. The controller is notified, and will disband the
// formation if all units are in formation and no orders remain.
"MoveCompleted": function(msg) {
var cmpFormation = Engine.QueryInterface(this.formationController, IID_Formation);
cmpFormation.SetInPosition(this.entity);
},
},
},

View File

@ -390,6 +390,11 @@ public:
}
}
virtual bool IsMoving()
{
return m_State != STATE_IDLE;
}
virtual fixed GetWalkSpeed()
{
return m_WalkSpeed;
@ -903,9 +908,15 @@ void CCmpUnitMotion::Move(fixed dt)
{
if (IsFormationMember())
{
// If we're in formation, we've reached our assigned position.
// so wait here.
// (We'll try to continue following the formation next turn.)
// We've reached our assigned position. If the controller
// is idle, send a notification in case it should disband,
// otherwise continue following the formation next turn.
CmpPtr<ICmpUnitMotion> cmpUnitMotion(GetSimContext(), m_TargetEntity);
if (cmpUnitMotion && !cmpUnitMotion->IsMoving())
{
CMessageMotionChanged msg(false, false);
GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg);
}
}
else
{
@ -1512,7 +1523,7 @@ bool CCmpUnitMotion::IsInTargetRange(entity_id_t target, entity_pos_t minRange,
void CCmpUnitMotion::MoveToFormationOffset(entity_id_t target, entity_pos_t x, entity_pos_t z)
{
CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), GetEntityId());
CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), target);
if (!cmpPosition || !cmpPosition->IsInWorld())
return;

View File

@ -30,6 +30,7 @@ DEFINE_INTERFACE_METHOD_3("MoveToFormationOffset", void, ICmpUnitMotion, MoveToF
DEFINE_INTERFACE_METHOD_2("FaceTowardsPoint", void, ICmpUnitMotion, FaceTowardsPoint, entity_pos_t, entity_pos_t)
DEFINE_INTERFACE_METHOD_0("StopMoving", void, ICmpUnitMotion, StopMoving)
DEFINE_INTERFACE_METHOD_1("SetSpeed", void, ICmpUnitMotion, SetSpeed, fixed)
DEFINE_INTERFACE_METHOD_0("IsMoving", bool, ICmpUnitMotion, IsMoving)
DEFINE_INTERFACE_METHOD_0("GetWalkSpeed", fixed, ICmpUnitMotion, GetWalkSpeed)
DEFINE_INTERFACE_METHOD_0("GetRunSpeed", fixed, ICmpUnitMotion, GetRunSpeed)
DEFINE_INTERFACE_METHOD_1("SetUnitRadius", void, ICmpUnitMotion, SetUnitRadius, fixed)
@ -76,6 +77,11 @@ public:
m_Script.CallVoid("SetSpeed", speed);
}
virtual bool IsMoving()
{
return m_Script.Call<bool>("IsMoving");
}
virtual fixed GetWalkSpeed()
{
return m_Script.Call<fixed>("GetWalkSpeed");

View File

@ -83,6 +83,11 @@ public:
*/
virtual void SetSpeed(fixed speed) = 0;
/**
* Get whether the unit is moving.
*/
virtual bool IsMoving() = 0;
/**
* Get the default speed that this unit will have when walking, in metres per second.
*/