1
0
forked from 0ad/0ad

Don't disband idle formations anymore, but give the formations a decent idle state. Formationmembers still need to leave the formation to anything other than walking, but this is a small step towards attacking formations.

This was SVN commit r14543.
This commit is contained in:
sanderd17 2014-01-08 09:47:27 +00:00
parent 4585f7322c
commit e8c4031bea
2 changed files with 100 additions and 27 deletions

View File

@ -209,26 +209,14 @@ Formation.prototype.GetFormationAnimation = function(entity, defaultAnimation)
};
/**
* 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.
* Permits formation members to register that they've reached their destination.
*/
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();
};
/**
@ -281,7 +269,6 @@ Formation.prototype.SetMembers = function(ents)
this.MoveToMembersCenter();
this.ComputeMotionParameters();
};
/**

View File

@ -794,7 +794,6 @@ var UnitFsmSpec = {
"Order.Stop": function(msg) {
var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation);
cmpFormation.CallMemberFunction("Stop", [false]);
cmpFormation.Disband();
},
"Order.Attack": function(msg) {
@ -1024,9 +1023,6 @@ var UnitFsmSpec = {
cmpFormation.CallMemberFunction("ResetFinishOrder", []);
return;
}
// No more orders left.
cmpFormation.Disband();
},
},
@ -1058,9 +1054,6 @@ var UnitFsmSpec = {
cmpFormation.CallMemberFunction("ResetFinishOrder", []);
return;
}
// No more orders left.
cmpFormation.Disband();
},
},
@ -1131,7 +1124,6 @@ var UnitFsmSpec = {
return;
}
// If this was the last order, attempt to disband the formation.
cmpFormation.FindInPosition();
}
},
@ -1159,9 +1151,6 @@ var UnitFsmSpec = {
this.FindWalkAndFightTargets();
return;
}
// No more order left.
cmpFormation.Disband();
},
"leave": function(msg) {
@ -1225,7 +1214,105 @@ var UnitFsmSpec = {
"IDLE": {
"enter": function() {
var cmpFormation = Engine.QueryInterface(this.formationController, IID_Formation);
if (!cmpFormation)
{
warn("UnitAI: " + this.entity + " got into FORMATIONMEMBER.IDLE mode without a valid formationController");
if (this.IsAnimal())
this.SetNextState("ANIMAL.IDLE");
else
this.SetNextState("INDIVIDUAL.IDLE");
return true;
}
var cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
if (cmpVisual)
cmpVisual.ReplaceMoveAnimation("idle", cmpFormation.GetFormationAnimation(this.entity, "idle"));
// Switch back to idle animation to guarantee we won't
// get stuck with an incorrect animation
this.SelectAnimation("idle");
// If the unit is guarding/escorting, go back to its duty
if (this.isGuardOf)
{
this.Guard(this.isGuardOf, false);
cmpFormation.RemoveMembers([this.entity]);
return true;
}
// The GUI and AI want to know when a unit is idle, but we don't
// want to send frequent spurious messages if the unit's only
// idle for an instant and will quickly go off and do something else.
// So we'll set a timer here and only report the idle event if we
// remain idle
this.StartTimer(1000);
// If a unit can heal and attack we first want to heal wounded units,
// so check if we are a healer and find whether there's anybody nearby to heal.
// (If anyone approaches later it'll be handled via LosHealRangeUpdate.)
// If anyone in sight gets hurt that will be handled via LosHealRangeUpdate.
if (this.IsHealer() && this.FindNewHealTargets())
{
cmpFormation.RemoveMembers([this.entity]);
return true; // (abort the FSM transition since we may have already switched state)
}
// If we entered the idle state we must have nothing better to do,
// so immediately check whether there's anybody nearby to attack.
// (If anyone approaches later, it'll be handled via LosRangeUpdate.)
if (this.FindNewTargets())
{
cmpFormation.RemoveMembers([this.entity]);
return true; // (abort the FSM transition since we may have already switched state)
}
// Nobody to attack - stay in idle
return false;
},
"leave": function() {
var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
if (this.losRangeQuery)
rangeMan.DisableActiveQuery(this.losRangeQuery);
if (this.losHealRangeQuery)
rangeMan.DisableActiveQuery(this.losHealRangeQuery);
var cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
if (cmpVisual)
cmpVisual.ResetMoveAnimation("idle");
this.StopTimer();
if (this.isIdle)
{
this.isIdle = false;
Engine.PostMessage(this.entity, MT_UnitIdleChanged, { "idle": this.isIdle });
}
},
"LosRangeUpdate": function(msg) {
if (this.GetStance().targetVisibleEnemies)
{
// Start attacking one of the newly-seen enemy (if any)
this.AttackEntitiesByPreference(msg.data.added);
}
},
"LosHealRangeUpdate": function(msg) {
if (this.RespondToHealableEntities(msg.data.added))
{
var cmpFormation = Engine.QueryInterface(this.formationController, IID_Formation);
if (cmpFormation)
cmpFormation.RemoveMembers([this.entity]);
}
},
"Timer": function(msg) {
if (!this.isIdle)
{
this.isIdle = true;
Engine.PostMessage(this.entity, MT_UnitIdleChanged, { "idle": this.isIdle });
}
},
},
@ -1242,8 +1329,7 @@ var UnitFsmSpec = {
},
// 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.
// is done moving. The controller is notified.
"MoveCompleted": function(msg) {
// We can only finish this order if the move was really completed.
if (!msg.data.error && this.FinishOrder())