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:
parent
4585f7322c
commit
e8c4031bea
@ -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();
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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())
|
||||
|
Loading…
Reference in New Issue
Block a user