Substantially rework how Gaia is handled by UnitAI, BuildingAI. Dangerous animals and combat units will be attacked like regular enemies.
This was SVN commit r12317.
This commit is contained in:
parent
84305155de
commit
1120701351
@ -32,6 +32,10 @@ BuildingAI.prototype.OnOwnershipChanged = function(msg)
|
||||
{
|
||||
if (msg.to != -1)
|
||||
this.SetupRangeQuery(msg.to);
|
||||
|
||||
// Non-Gaia buildings should attack certain Gaia units.
|
||||
if (msg.to != 0 || this.gaiaUnitsQuery)
|
||||
this.SetupGaiaRangeQuery(msg.to);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -50,6 +54,8 @@ BuildingAI.prototype.OnDestroy = function()
|
||||
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||
if (this.enemyUnitsQuery)
|
||||
cmpRangeManager.DestroyActiveQuery(this.enemyUnitsQuery);
|
||||
if (this.gaiaUnitsQuery)
|
||||
cmpRangeManager.DestroyActiveQuery(this.gaiaUnitsQuery);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -81,12 +87,58 @@ BuildingAI.prototype.SetupRangeQuery = function(owner)
|
||||
}
|
||||
};
|
||||
|
||||
// Set up a range query for Gaia units within LOS range which can be attacked.
|
||||
// This should be called whenever our ownership changes.
|
||||
BuildingAI.prototype.SetupGaiaRangeQuery = function()
|
||||
{
|
||||
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
||||
var owner = cmpOwnership.GetOwner();
|
||||
|
||||
var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||
var playerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
|
||||
|
||||
if (this.gaiaUnitsQuery)
|
||||
{
|
||||
rangeMan.DestroyActiveQuery(this.gaiaUnitsQuery);
|
||||
this.gaiaUnitsQuery = undefined;
|
||||
}
|
||||
|
||||
if (owner == -1)
|
||||
return;
|
||||
|
||||
var cmpPlayer = Engine.QueryInterface(playerMan.GetPlayerByID(owner), IID_Player);
|
||||
if (!cmpPlayer.IsEnemy(0))
|
||||
return;
|
||||
|
||||
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
||||
if (cmpAttack)
|
||||
{
|
||||
var range = cmpAttack.GetRange("Ranged");
|
||||
|
||||
// This query is only interested in Gaia entities that can attack.
|
||||
this.gaiaUnitsQuery = rangeMan.CreateActiveQuery(this.entity, range.min, range.max, [0], IID_Attack, rangeMan.GetEntityFlagMask("normal"));
|
||||
rangeMan.EnableActiveQuery(this.gaiaUnitsQuery);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when units enter or leave range
|
||||
*/
|
||||
BuildingAI.prototype.OnRangeUpdate = function(msg)
|
||||
{
|
||||
if (msg.tag != this.enemyUnitsQuery)
|
||||
if (msg.tag == this.gaiaUnitsQuery)
|
||||
{
|
||||
const filter = function(e) {
|
||||
var cmpUnitAI = Engine.QueryInterface(e, IID_UnitAI);
|
||||
return (cmpUnitAI && (!cmpUnitAI.IsAnimal() || cmpUnitAI.IsDangerousAnimal()));
|
||||
};
|
||||
|
||||
if (msg.added.length)
|
||||
msg.added = msg.added.filter(filter);
|
||||
if (msg.removed.length)
|
||||
msg.removed = msg.removed.filter(filter);
|
||||
}
|
||||
else if (msg.tag != this.enemyUnitsQuery)
|
||||
return;
|
||||
|
||||
if (msg.added.length > 0)
|
||||
|
@ -140,6 +140,10 @@ var UnitFsmSpec = {
|
||||
// ignore newly-seen units by default
|
||||
},
|
||||
|
||||
"LosGaiaRangeUpdate": function(msg) {
|
||||
// ignore newly-seen Gaia units by default
|
||||
},
|
||||
|
||||
"LosHealRangeUpdate": function(msg) {
|
||||
// ignore newly-seen injured units by default
|
||||
},
|
||||
@ -188,6 +192,26 @@ var UnitFsmSpec = {
|
||||
// Individual orders:
|
||||
// (these will switch the unit out of formation mode)
|
||||
|
||||
"Order.Stop": function(msg) {
|
||||
// We have no control over non-domestic animals.
|
||||
if (this.IsAnimal() && !this.IsDomestic())
|
||||
{
|
||||
this.FinishOrder();
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop moving immediately.
|
||||
this.StopMoving();
|
||||
this.FinishOrder();
|
||||
|
||||
// No orders left, we're an individual now
|
||||
if (this.IsAnimal())
|
||||
this.SetNextState("ANIMAL.IDLE");
|
||||
else
|
||||
this.SetNextState("INDIVIDUAL.IDLE");
|
||||
|
||||
},
|
||||
|
||||
"Order.Walk": function(msg) {
|
||||
// Let players move captured domestic animals around
|
||||
if (this.IsAnimal() && !this.IsDomestic())
|
||||
@ -458,6 +482,12 @@ var UnitFsmSpec = {
|
||||
this.FinishOrder();
|
||||
},
|
||||
|
||||
"Order.Stop": function(msg) {
|
||||
var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation);
|
||||
cmpFormation.CallMemberFunction("Stop", [false]);
|
||||
cmpFormation.Disband();
|
||||
},
|
||||
|
||||
"Order.Attack": function(msg) {
|
||||
// TODO: we should move in formation towards the target,
|
||||
// then break up into individuals when close enough to it
|
||||
@ -698,6 +728,14 @@ var UnitFsmSpec = {
|
||||
}
|
||||
},
|
||||
|
||||
"LosGaiaRangeUpdate": function(msg) {
|
||||
if (this.GetStance().targetVisibleEnemies)
|
||||
{
|
||||
// Start attacking one of the newly-seen enemy (if any)
|
||||
this.RespondToTargetedEntities(this.GetAttackableEntitiesByPreference(msg.data.added, true));
|
||||
}
|
||||
},
|
||||
|
||||
"LosHealRangeUpdate": function(msg) {
|
||||
this.RespondToHealableEntities(msg.data.added);
|
||||
},
|
||||
@ -1614,9 +1652,7 @@ var UnitFsmSpec = {
|
||||
{
|
||||
this.Flee(msg.data.attacker, false);
|
||||
}
|
||||
else if (this.template.NaturalBehaviour == "violent" ||
|
||||
this.template.NaturalBehaviour == "aggressive" ||
|
||||
this.template.NaturalBehaviour == "defensive")
|
||||
else if (this.IsDangerousAnimal() || this.template.NaturalBehaviour == "defensive")
|
||||
{
|
||||
if (this.CanAttack(msg.data.attacker))
|
||||
this.Attack(msg.data.attacker, false);
|
||||
@ -1691,8 +1727,7 @@ var UnitFsmSpec = {
|
||||
}
|
||||
}
|
||||
// Start attacking one of the newly-seen enemy (if any)
|
||||
else if (this.template.NaturalBehaviour == "violent" ||
|
||||
this.template.NaturalBehaviour == "aggressive")
|
||||
else if (this.IsDangerousAnimal())
|
||||
{
|
||||
this.AttackVisibleEntity(msg.data.added);
|
||||
}
|
||||
@ -1781,6 +1816,12 @@ UnitAI.prototype.IsAnimal = function()
|
||||
return (this.template.NaturalBehaviour ? true : false);
|
||||
};
|
||||
|
||||
UnitAI.prototype.IsDangerousAnimal = function()
|
||||
{
|
||||
return (this.IsAnimal() && (this.template.NaturalBehaviour == "violent" ||
|
||||
this.template.NaturalBehaviour == "aggressive"));
|
||||
};
|
||||
|
||||
UnitAI.prototype.IsDomestic = function()
|
||||
{
|
||||
var cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity);
|
||||
@ -1804,6 +1845,19 @@ UnitAI.prototype.IsGarrisoned = function()
|
||||
return this.isGarrisoned;
|
||||
};
|
||||
|
||||
UnitAI.prototype.CanAttackGaia = function()
|
||||
{
|
||||
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
||||
if (!cmpAttack)
|
||||
return false;
|
||||
|
||||
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
||||
if (!cmpOwnership || cmpOwnership.GetOwner() == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
UnitAI.prototype.OnCreate = function()
|
||||
{
|
||||
if (this.IsAnimal())
|
||||
@ -1816,9 +1870,14 @@ UnitAI.prototype.OnCreate = function()
|
||||
|
||||
UnitAI.prototype.OnOwnershipChanged = function(msg)
|
||||
{
|
||||
this.SetupRangeQuery();
|
||||
if (this.IsHealer())
|
||||
this.SetupHealRangeQuery();
|
||||
this.SetupRangeQueries();
|
||||
|
||||
// If the unit isn't being created or dying, clear orders and reset stance.
|
||||
if (msg.to != -1 && msg.from != -1)
|
||||
{
|
||||
this.SetStance(this.template.DefaultStance);
|
||||
this.Stop(false);
|
||||
}
|
||||
};
|
||||
|
||||
UnitAI.prototype.OnDestroy = function()
|
||||
@ -1832,8 +1891,22 @@ UnitAI.prototype.OnDestroy = function()
|
||||
rangeMan.DestroyActiveQuery(this.losRangeQuery);
|
||||
if (this.losHealRangeQuery)
|
||||
rangeMan.DestroyActiveQuery(this.losHealRangeQuery);
|
||||
if (this.losGaiaRangeQuery)
|
||||
rangeMan.DestroyActiveQuery(this.losGaiaRangeQuery);
|
||||
};
|
||||
|
||||
// Wrapper function that sets up the normal, healer, and Gaia range queries.
|
||||
UnitAI.prototype.SetupRangeQueries = function()
|
||||
{
|
||||
this.SetupRangeQuery();
|
||||
|
||||
if (this.IsHealer())
|
||||
this.SetupHealRangeQuery();
|
||||
|
||||
if (this.CanAttackGaia() || this.losGaiaRangeQuery)
|
||||
this.SetupGaiaRangeQuery();
|
||||
}
|
||||
|
||||
// Set up a range query for all enemy units within LOS range
|
||||
// which can be attacked.
|
||||
// This should be called whenever our ownership changes.
|
||||
@ -1846,7 +1919,10 @@ UnitAI.prototype.SetupRangeQuery = function()
|
||||
var playerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
|
||||
|
||||
if (this.losRangeQuery)
|
||||
{
|
||||
rangeMan.DestroyActiveQuery(this.losRangeQuery);
|
||||
this.losRangeQuery = undefined;
|
||||
}
|
||||
|
||||
var players = [];
|
||||
|
||||
@ -1905,6 +1981,40 @@ UnitAI.prototype.SetupHealRangeQuery = function()
|
||||
rangeMan.EnableActiveQuery(this.losHealRangeQuery);
|
||||
};
|
||||
|
||||
// Set up a range query for Gaia units within LOS range which can be attacked.
|
||||
// This should be called whenever our ownership changes.
|
||||
UnitAI.prototype.SetupGaiaRangeQuery = function()
|
||||
{
|
||||
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
||||
var owner = cmpOwnership.GetOwner();
|
||||
|
||||
var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||
var playerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
|
||||
|
||||
if (this.losGaiaRangeQuery)
|
||||
{
|
||||
rangeMan.DestroyActiveQuery(this.losGaiaRangeQuery);
|
||||
this.losGaiaRangeQuery = undefined;
|
||||
}
|
||||
|
||||
if (owner == -1)
|
||||
return;
|
||||
|
||||
var cmpPlayer = Engine.QueryInterface(playerMan.GetPlayerByID(owner), IID_Player);
|
||||
if (!cmpPlayer.IsEnemy(0))
|
||||
return;
|
||||
|
||||
// Only create the query if Gaia is our enemy and we can attack.
|
||||
if (this.CanAttackGaia())
|
||||
{
|
||||
var range = this.GetQueryRange(IID_Attack);
|
||||
|
||||
// This query is only interested in Gaia entities that can attack.
|
||||
this.losGaiaRangeQuery = rangeMan.CreateActiveQuery(this.entity, range.min, range.max, [0], IID_Attack, rangeMan.GetEntityFlagMask("normal"));
|
||||
rangeMan.EnableActiveQuery(this.losGaiaRangeQuery);
|
||||
}
|
||||
};
|
||||
|
||||
//// FSM linkage functions ////
|
||||
|
||||
UnitAI.prototype.SetNextState = function(state)
|
||||
@ -2157,6 +2267,8 @@ UnitAI.prototype.OnRangeUpdate = function(msg)
|
||||
{
|
||||
if (msg.tag == this.losRangeQuery)
|
||||
UnitFsm.ProcessMessage(this, {"type": "LosRangeUpdate", "data": msg});
|
||||
else if (msg.tag == this.losGaiaRangeQuery)
|
||||
UnitFsm.ProcessMessage(this, {"type": "LosGaiaRangeUpdate", "data": msg});
|
||||
else if (msg.tag == this.losHealRangeQuery)
|
||||
UnitFsm.ProcessMessage(this, {"type": "LosHealRangeUpdate", "data": msg});
|
||||
};
|
||||
@ -2743,6 +2855,9 @@ UnitAI.prototype.ComputeWalkingDistance = function()
|
||||
// Return the total distance to the target
|
||||
return distance;
|
||||
|
||||
case "Stop":
|
||||
return 0;
|
||||
|
||||
default:
|
||||
error("ComputeWalkingDistance: Unrecognised order type '"+order.type+"'");
|
||||
return distance;
|
||||
@ -2769,6 +2884,14 @@ UnitAI.prototype.Walk = function(x, z, queued)
|
||||
this.AddOrder("Walk", { "x": x, "z": z, "force": true }, queued);
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds stop order to queue, forced by the player.
|
||||
*/
|
||||
UnitAI.prototype.Stop = function(queued)
|
||||
{
|
||||
this.AddOrder("Stop", undefined, queued);
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds walk-to-target order to queue, this only occurs in response
|
||||
* to a player order, and so is forced.
|
||||
@ -3046,12 +3169,8 @@ UnitAI.prototype.SwitchToStance = function(stance)
|
||||
if (stance == "standground")
|
||||
this.StopMoving();
|
||||
|
||||
// Reset the range query, since the range depends on stance
|
||||
this.SetupRangeQuery();
|
||||
// Just if we are a healer
|
||||
// TODO maybe move those two to a SetupRangeQuerys()
|
||||
if (this.IsHealer())
|
||||
this.SetupHealRangeQuery();
|
||||
// Reset the range queries, since the range depends on stance.
|
||||
this.SetupRangeQueries();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -3060,7 +3179,7 @@ UnitAI.prototype.SwitchToStance = function(stance)
|
||||
*/
|
||||
UnitAI.prototype.FindNewTargets = function()
|
||||
{
|
||||
if (!this.losRangeQuery)
|
||||
if (!this.losRangeQuery && !this.losGaiaRangeQuery)
|
||||
return false;
|
||||
|
||||
var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||
@ -3069,6 +3188,13 @@ UnitAI.prototype.FindNewTargets = function()
|
||||
if (!this.GetStance().targetVisibleEnemies)
|
||||
return false;
|
||||
|
||||
// If no regular enemies were found, attempt to attack a hostile Gaia entity.
|
||||
if (this.losGaiaRangeQuery && (!ents || !ents.length))
|
||||
{
|
||||
ents = rangeMan.ResetActiveQuery(this.losGaiaRangeQuery);
|
||||
return this.RespondToTargetedEntities(this.GetAttackableEntitiesByPreference(ents, true));
|
||||
}
|
||||
|
||||
return this.RespondToTargetedEntities(this.GetAttackableEntitiesByPreference(ents));
|
||||
};
|
||||
|
||||
@ -3410,12 +3536,24 @@ UnitAI.prototype.MoveRandomly = function(distance)
|
||||
cmpMotion.MoveToPointRange(tx, tz, distance, distance);
|
||||
};
|
||||
|
||||
UnitAI.prototype.GetAttackableEntitiesByPreference = function(ents)
|
||||
UnitAI.prototype.GetAttackableEntitiesByPreference = function(ents, filterGaia)
|
||||
{
|
||||
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
||||
if (!cmpAttack)
|
||||
return [];
|
||||
|
||||
if (filterGaia)
|
||||
{
|
||||
const filter = function(e) {
|
||||
var cmpUnitAI = Engine.QueryInterface(e, IID_UnitAI);
|
||||
return (cmpUnitAI && (!cmpUnitAI.IsAnimal() || cmpUnitAI.IsDangerousAnimal()));
|
||||
};
|
||||
|
||||
return ents
|
||||
.filter(function (v, i, a) { return cmpAttack.CanAttack(v) && filter(v); })
|
||||
.sort(function (a, b) { return cmpAttack.CompareEntitiesByPreference(a, b); });
|
||||
}
|
||||
|
||||
return ents
|
||||
.filter(function (v, i, a) { return cmpAttack.CanAttack(v); })
|
||||
.sort(function (a, b) { return cmpAttack.CompareEntitiesByPreference(a, b); });
|
||||
|
@ -128,8 +128,11 @@ function LoadPlayerSettings(settings, newPlayers)
|
||||
cmpPlayer.SetCiv(pDefs.Civ);
|
||||
cmpPlayer.SetColour(pDefs.Colour.r, pDefs.Colour.g, pDefs.Colour.b);
|
||||
|
||||
// Gaia should be its own ally.
|
||||
cmpPlayer.SetAlly(0);
|
||||
|
||||
// Gaia is everyone's enemy
|
||||
for (var j = 0; j < numPlayers; ++j)
|
||||
for (var j = 1; j < numPlayers; ++j)
|
||||
cmpPlayer.SetEnemy(j);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user