Changeset View
Changeset View
Standalone View
Standalone View
binaries/data/mods/public/simulation/components/UnitAI.js
Show First 20 Lines • Show All 2,480 Lines • ▼ Show 20 Lines | "GATHER": { | ||||
initPos = { 'x': pos.X, 'z': pos.Z }; | initPos = { 'x': pos.X, 'z': pos.Z }; | ||||
} | } | ||||
} | } | ||||
if (initPos) | if (initPos) | ||||
{ | { | ||||
// Try to find a new resource of the same specific type near the initial resource position: | // Try to find a new resource of the same specific type near the initial resource position: | ||||
// Also don't switch to a different type of huntable animal | // Also don't switch to a different type of huntable animal | ||||
let nearbyResource = this.FindNearbyResource((ent, type, template) => { | let nearbyResource = this.FindNearbyResource(new Vector2D(initPos.x, initPos.z), | ||||
(ent, type, template) => { | |||||
if (previousTarget == ent) | if (previousTarget == ent) | ||||
return false; | return false; | ||||
if (type.generic == "treasure" && resourceType.generic == "treasure") | if (type.generic == "treasure" && resourceType.generic == "treasure") | ||||
return true; | return true; | ||||
return type.specific == resourceType.specific && | return type.specific == resourceType.specific && | ||||
(type.specific != "meat" || resourceTemplate == template); | (type.specific != "meat" || resourceTemplate == template); | ||||
}, new Vector2D(initPos.x, initPos.z)); | }); | ||||
if (nearbyResource) | if (nearbyResource) | ||||
{ | { | ||||
this.PerformGather(nearbyResource, false, false); | this.PerformGather(nearbyResource, false, false); | ||||
return true; | return true; | ||||
} | } | ||||
// Failing that, try to move there and se if we are more lucky: maybe there are resources in FOW. | // Failing that, try to move there and se if we are more lucky: maybe there are resources in FOW. | ||||
▲ Show 20 Lines • Show All 432 Lines • ▼ Show 20 Lines | "REPAIR": { | ||||
return; | return; | ||||
} | } | ||||
// If this building was e.g. a farmstead of ours, entities that received | // If this building was e.g. a farmstead of ours, entities that received | ||||
// the build command should look for nearby resources to gather | // the build command should look for nearby resources to gather | ||||
if ((oldData.force || oldData.autoharvest) && this.CanReturnResource(msg.data.newentity, false)) | if ((oldData.force || oldData.autoharvest) && this.CanReturnResource(msg.data.newentity, false)) | ||||
{ | { | ||||
let types = cmpResourceDropsite.GetTypes(); | let types = cmpResourceDropsite.GetTypes(); | ||||
let pos; | |||||
let cmpPosition = Engine.QueryInterface(msg.data.newentity, IID_Position); | |||||
if (cmpPosition && cmpPosition.IsInWorld()) | |||||
pos = cmpPosition.GetPosition2D(); | |||||
// TODO: Slightly undefined behavior here, we don't know what type of resource will be collected, | // TODO: Slightly undefined behavior here, we don't know what type of resource will be collected, | ||||
// may cause problems for AIs (especially hunting fast animals), but avoid ugly hacks to fix that! | // may cause problems for AIs (especially hunting fast animals), but avoid ugly hacks to fix that! | ||||
let nearby = this.FindNearbyResource(function(ent, type, template) { | let nearby = this.FindNearbyResource(this.TargetPosOrEntPos(msg.data.newentity), | ||||
return (types.indexOf(type.generic) != -1); | (ent, type, template) => types.indexOf(type.generic) != -1); | ||||
}, pos); | |||||
if (nearby) | if (nearby) | ||||
{ | { | ||||
this.PerformGather(nearby, true, false); | this.PerformGather(nearby, true, false); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
// Look for a nearby foundation to help with | // Look for a nearby foundation to help with. | ||||
let nearbyFoundation = this.FindNearbyFoundation(); | let nearbyFoundation = this.FindNearbyFoundation(this.TargetPosOrEntPos(msg.data.newentity)); | ||||
if (nearbyFoundation) | if (nearbyFoundation) | ||||
{ | { | ||||
this.AddOrder("Repair", { "target": nearbyFoundation, "autocontinue": oldData.autocontinue, "force": false }, true); | this.AddOrder("Repair", { "target": nearbyFoundation, "autocontinue": oldData.autocontinue, "force": false }, true); | ||||
return; | return; | ||||
} | } | ||||
// Unit was approaching and there's nothing to do now, so switch to walking | // Unit was approaching and there's nothing to do now, so switch to walking | ||||
wraitii: As noted by stan, this should be moved to the function itself, that's simpler. | |||||
if (oldState === "INDIVIDUAL.REPAIR.APPROACHING") | if (oldState === "INDIVIDUAL.REPAIR.APPROACHING") | ||||
// We're already walking to the given point, so add this as a order. | // We're already walking to the given point, so add this as a order. | ||||
this.WalkToTarget(msg.data.newentity, true); | this.WalkToTarget(msg.data.newentity, true); | ||||
}, | }, | ||||
}, | }, | ||||
"GARRISON": { | "GARRISON": { | ||||
"leave": function() { | "leave": function() { | ||||
▲ Show 20 Lines • Show All 1,256 Lines • ▼ Show 20 Lines | UnitAI.prototype.MustKillGatherTarget = function(ent) | ||||
if (!cmpResourceSupply.GetKillBeforeGather()) | if (!cmpResourceSupply.GetKillBeforeGather()) | ||||
return false; | return false; | ||||
return this.TargetIsAlive(ent); | return this.TargetIsAlive(ent); | ||||
}; | }; | ||||
/** | /** | ||||
* Returns the position of target or, if there is none, | |||||
* the entity's position, or undefined. | |||||
*/ | |||||
UnitAI.prototype.TargetPosOrEntPos = function(target) | |||||
{ | |||||
let cmpTargetPosition = Engine.QueryInterface(target, IID_Position); | |||||
if (cmpTargetPosition && cmpTargetPosition.IsInWorld()) | |||||
return cmpTargetPosition.GetPosition2D(); | |||||
let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); | |||||
if (cmpPosition && cmpPosition.IsInWorld()) | |||||
return cmpPosition.GetPosition2D(); | |||||
return undefined; | |||||
}; | |||||
/** | |||||
* Returns the entity ID of the nearest resource supply where the given | * Returns the entity ID of the nearest resource supply where the given | ||||
* filter returns true, or undefined if none can be found. | * filter returns true, or undefined if none can be found. | ||||
* if position (as a vector2D) is given, the nearest is computed versus this position. | * "Nearest" is nearest from @param position. | ||||
* TODO: extend this to exclude resources that already have lots of | * TODO: extend this to exclude resources that already have lots of gatherers. | ||||
* gatherers. | |||||
*/ | */ | ||||
UnitAI.prototype.FindNearbyResource = function(filter, position) | UnitAI.prototype.FindNearbyResource = function(position, filter) | ||||
{ | { | ||||
if (!position) | |||||
return undefined; | |||||
let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); | let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); | ||||
if (!cmpOwnership || cmpOwnership.GetOwner() == INVALID_PLAYER) | if (!cmpOwnership || cmpOwnership.GetOwner() == INVALID_PLAYER) | ||||
return undefined; | return undefined; | ||||
let owner = cmpOwnership.GetOwner(); | let owner = cmpOwnership.GetOwner(); | ||||
// We accept resources owned by Gaia or any player | // We accept resources owned by Gaia or any player | ||||
let players = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetAllPlayers(); | let players = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetAllPlayers(); | ||||
let range = 64; // TODO: what's a sensible number? | let range = 64; // TODO: what's a sensible number? | ||||
let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); | let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); | ||||
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); | let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); | ||||
let pos = position; | let nearby = cmpRangeManager.ExecuteQueryAroundPos(position, 0, range, players, IID_ResourceSupply); | ||||
if (!pos) | |||||
{ | |||||
let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); | |||||
if (cmpPosition && cmpPosition.IsInWorld()) | |||||
pos = cmpPosition.GetPosition2D(); | |||||
} | |||||
let nearby = cmpRangeManager.ExecuteQueryAroundPos(pos, 0, range, players, IID_ResourceSupply); | |||||
return nearby.find(ent => { | return nearby.find(ent => { | ||||
if (!this.CanGather(ent) || !this.CheckTargetVisible(ent)) | if (!this.CanGather(ent) || !this.CheckTargetVisible(ent)) | ||||
return false; | return false; | ||||
let cmpResourceSupply = Engine.QueryInterface(ent, IID_ResourceSupply); | let cmpResourceSupply = Engine.QueryInterface(ent, IID_ResourceSupply); | ||||
let type = cmpResourceSupply.GetType(); | let type = cmpResourceSupply.GetType(); | ||||
let amount = cmpResourceSupply.GetCurrentAmount(); | let amount = cmpResourceSupply.GetCurrentAmount(); | ||||
let template = cmpTemplateManager.GetCurrentTemplateName(ent); | let template = cmpTemplateManager.GetCurrentTemplateName(ent); | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | for (let dropsite of nearestDropsites) | ||||
} | } | ||||
else if (dist > bestDist + maxDifference) | else if (dist > bestDist + maxDifference) | ||||
break; | break; | ||||
} | } | ||||
return bestDropsite; | return bestDropsite; | ||||
}; | }; | ||||
/** | /** | ||||
* Returns the entity ID of the nearest building that needs to be constructed, | * Returns the entity ID of the nearest building that needs to be constructed. | ||||
* or undefined if none can be found close enough. | * "Nearest" is nearest from @param position. | ||||
*/ | */ | ||||
UnitAI.prototype.FindNearbyFoundation = function() | UnitAI.prototype.FindNearbyFoundation = function(position) | ||||
{ | { | ||||
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); | if (!position) | ||||
return undefined; | |||||
let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); | |||||
if (!cmpOwnership || cmpOwnership.GetOwner() == INVALID_PLAYER) | if (!cmpOwnership || cmpOwnership.GetOwner() == INVALID_PLAYER) | ||||
return undefined; | return undefined; | ||||
// Find buildings owned by this unit's player | // Find buildings owned by this unit's player | ||||
var players = [cmpOwnership.GetOwner()]; | let players = [cmpOwnership.GetOwner()]; | ||||
var range = 64; // TODO: what's a sensible number? | |||||
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); | let range = 64; // TODO: what's a sensible number? | ||||
var nearby = cmpRangeManager.ExecuteQuery(this.entity, 0, range, players, IID_Foundation); | let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); | ||||
let nearby = cmpRangeManager.ExecuteQueryAroundPos(position, 0, range, players, IID_Foundation); | |||||
// Skip foundations that are already complete. (This matters since | // Skip foundations that are already complete. (This matters since | ||||
// we process the ConstructionFinished message before the foundation | // we process the ConstructionFinished message before the foundation | ||||
// we're working on has been deleted.) | // we're working on has been deleted.) | ||||
return nearby.find(ent => !Engine.QueryInterface(ent, IID_Foundation).IsFinished()); | return nearby.find(ent => !Engine.QueryInterface(ent, IID_Foundation).IsFinished()); | ||||
}; | }; | ||||
/** | /** | ||||
▲ Show 20 Lines • Show All 1,989 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator
As noted by stan, this should be moved to the function itself, that's simpler.