Return Gathering to A23 behaviour - Make units try to gather near the target resource's position instead of their position.

Units were incorrectly looking at resources near their position
following 7d53fb19a2.

Fixes #5477.

Differential Revision: https://code.wildfiregames.com/D2034
This was SVN commit r22428.
This commit is contained in:
wraitii
2019-07-03 17:57:16 +00:00
parent 5fef05d780
commit 8a38cfb7cf
@@ -529,6 +529,7 @@ UnitAI.prototype.UnitFsmSpec = {
} }
this.RememberTargetPosition(); this.RememberTargetPosition();
this.order.data.initPos = this.order.data.lastPos;
if (this.CheckTargetRange(this.order.data.target, IID_ResourceGatherer)) if (this.CheckTargetRange(this.order.data.target, IID_ResourceGatherer))
this.SetNextState("INDIVIDUAL.GATHER.GATHERING"); this.SetNextState("INDIVIDUAL.GATHER.GATHERING");
@@ -2059,12 +2060,13 @@ UnitAI.prototype.UnitFsmSpec = {
this.SetNextState("GATHERING"); this.SetNextState("GATHERING");
return true; return true;
} }
this.SelectAnimation("move"); this.SelectAnimation("move");
return false; return false;
}, },
"MovementUpdate": function(msg) { "MovementUpdate": function(msg) {
// If we failed, the GATHERING timer will handle finding a valid resource. // The GATHERING timer will handle finding a valid resource.
this.SetNextState("GATHERING"); this.SetNextState("GATHERING");
}, },
@@ -2100,7 +2102,8 @@ UnitAI.prototype.UnitFsmSpec = {
"MovementUpdate": function(msg) { "MovementUpdate": function(msg) {
// If we failed, the GATHERING timer will handle finding a valid resource. // If we failed, the GATHERING timer will handle finding a valid resource.
this.SetNextState("GATHERING"); if (msg.error || this.CheckRange(this.order.data))
this.SetNextState("GATHERING");
}, },
}, },
@@ -2181,22 +2184,21 @@ UnitAI.prototype.UnitFsmSpec = {
}, },
"Timer": function(msg) { "Timer": function(msg) {
var resourceTemplate = this.order.data.template; let resourceTemplate = this.order.data.template;
var resourceType = this.order.data.type; let resourceType = this.order.data.type;
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
if (!cmpOwnership) if (!cmpOwnership)
return; return;
var cmpSupply = Engine.QueryInterface(this.gatheringTarget, IID_ResourceSupply); let cmpSupply = Engine.QueryInterface(this.gatheringTarget, IID_ResourceSupply);
if (cmpSupply && cmpSupply.IsAvailable(cmpOwnership.GetOwner(), this.entity)) if (cmpSupply && cmpSupply.IsAvailable(cmpOwnership.GetOwner(), this.entity))
{
// Check we can still reach and gather from the target // Check we can still reach and gather from the target
if (this.CheckTargetRange(this.gatheringTarget, IID_ResourceGatherer) && this.CanGather(this.gatheringTarget)) if (this.CheckTargetRange(this.gatheringTarget, IID_ResourceGatherer) && this.CanGather(this.gatheringTarget))
{ {
// Gather the resources: // Gather the resources:
var cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); let cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer);
// Try to gather treasure // Try to gather treasure
if (cmpResourceGatherer.TryInstantGather(this.gatheringTarget)) if (cmpResourceGatherer.TryInstantGather(this.gatheringTarget))
@@ -2208,13 +2210,13 @@ UnitAI.prototype.UnitFsmSpec = {
cmpResourceGatherer.DropResources(); cmpResourceGatherer.DropResources();
// Collect from the target // Collect from the target
var status = cmpResourceGatherer.PerformGather(this.gatheringTarget); let status = cmpResourceGatherer.PerformGather(this.gatheringTarget);
// If we've collected as many resources as possible, // If we've collected as many resources as possible,
// return to the nearest dropsite // return to the nearest dropsite
if (status.filled) if (status.filled)
{ {
var nearby = this.FindNearestDropsite(resourceType.generic); let nearby = this.FindNearestDropsite(resourceType.generic);
if (nearby) if (nearby)
{ {
// (Keep this Gather order on the stack so we'll // (Keep this Gather order on the stack so we'll
@@ -2253,15 +2255,14 @@ UnitAI.prototype.UnitFsmSpec = {
return; return;
} }
} }
}
// We're already in range, can't get anywhere near it or the target is exhausted. // We're already in range, can't get anywhere near it or the target is exhausted.
var herdPos = this.order.data.initPos; let herdPos = this.order.data.initPos;
// Give up on this order and try our next queued order // Give up on this order and try our next queued order
// but first check what is our next order and, if needed, insert a returnResource order // but first check what is our next order and, if needed, insert a returnResource order
var cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); let cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer);
if (cmpResourceGatherer.IsCarrying(resourceType.generic) && if (cmpResourceGatherer.IsCarrying(resourceType.generic) &&
this.orderQueue.length > 1 && this.orderQueue[1] !== "ReturnResource" && this.orderQueue.length > 1 && this.orderQueue[1] !== "ReturnResource" &&
(this.orderQueue[1].type !== "Gather" || this.orderQueue[1].data.type.generic !== resourceType.generic)) (this.orderQueue[1].type !== "Gather" || this.orderQueue[1].data.type.generic !== resourceType.generic))
@@ -2277,13 +2278,14 @@ UnitAI.prototype.UnitFsmSpec = {
// Try to find a new resource of the same specific type near our current position: // Try to find a new resource of the same specific type near our current position:
// Also don't switch to a different type of huntable animal // Also don't switch to a different type of huntable animal
var nearby = this.FindNearbyResource(function(ent, type, template) { let nearby = this.FindNearbyResource(function(ent, type, template) {
return ( return (
(type.generic == "treasure" && resourceType.generic == "treasure") (type.generic == "treasure" && resourceType.generic == "treasure") ||
|| (type.specific == resourceType.specific (type.specific == resourceType.specific &&
&& (type.specific != "meat" || resourceTemplate == template)) (type.specific != "meat" || resourceTemplate == template))
); );
}); }, new Vector2D(herdPos.x, herdPos.z));
if (nearby) if (nearby)
{ {
this.PerformGather(nearby, false, false); this.PerformGather(nearby, false, false);
@@ -2301,7 +2303,7 @@ UnitAI.prototype.UnitFsmSpec = {
// drop it off, and if not then we might as well head to the dropsite // drop it off, and if not then we might as well head to the dropsite
// anyway because that's a nice enough place to congregate and idle // anyway because that's a nice enough place to congregate and idle
var nearby = this.FindNearestDropsite(resourceType.generic); nearby = this.FindNearestDropsite(resourceType.generic);
if (nearby) if (nearby)
{ {
this.PushOrderFront("ReturnResource", { "target": nearby, "force": false }); this.PushOrderFront("ReturnResource", { "target": nearby, "force": false });
@@ -2640,16 +2642,16 @@ UnitAI.prototype.UnitFsmSpec = {
return; // ignore other buildings return; // ignore other buildings
// Save the current order's data in case we need it later // Save the current order's data in case we need it later
var oldData = this.order.data; let oldData = this.order.data;
// Save the current state so we can continue walking if necessary // Save the current state so we can continue walking if necessary
// FinishOrder() below will switch to IDLE if there's no order, which sets the idle animation. // FinishOrder() below will switch to IDLE if there's no order, which sets the idle animation.
// Idle animation while moving towards finished construction looks weird (ghosty). // Idle animation while moving towards finished construction looks weird (ghosty).
var oldState = this.GetCurrentState(); let oldState = this.GetCurrentState();
// Drop any resource we can if we are in range when the construction finishes // Drop any resource we can if we are in range when the construction finishes
var cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); let cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer);
var cmpResourceDropsite = Engine.QueryInterface(msg.data.newentity, IID_ResourceDropsite); let cmpResourceDropsite = Engine.QueryInterface(msg.data.newentity, IID_ResourceDropsite);
if (cmpResourceGatherer && cmpResourceDropsite && this.CheckTargetRange(msg.data.newentity, IID_Builder) && if (cmpResourceGatherer && cmpResourceDropsite && this.CheckTargetRange(msg.data.newentity, IID_Builder) &&
this.CanReturnResource(msg.data.newentity, true)) this.CanReturnResource(msg.data.newentity, true))
{ {
@@ -2694,13 +2696,18 @@ UnitAI.prototype.UnitFsmSpec = {
// 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))
{ {
var cmpResourceDropsite = Engine.QueryInterface(msg.data.newentity, IID_ResourceDropsite); let types = cmpResourceDropsite.GetTypes();
var 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!
var nearby = this.FindNearbyResource(function(ent, type, template) { let nearby = this.FindNearbyResource(function(ent, type, template) {
return (types.indexOf(type.generic) != -1); return (types.indexOf(type.generic) != -1);
}, msg.data.newentity); }, pos);
if (nearby) if (nearby)
{ {
this.PerformGather(nearby, true, false); this.PerformGather(nearby, true, false);
@@ -2709,7 +2716,7 @@ UnitAI.prototype.UnitFsmSpec = {
} }
// Look for a nearby foundation to help with // Look for a nearby foundation to help with
var nearbyFoundation = this.FindNearbyFoundation(); let nearbyFoundation = this.FindNearbyFoundation();
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);
@@ -2718,10 +2725,8 @@ UnitAI.prototype.UnitFsmSpec = {
// 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
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);
}
}, },
}, },
@@ -3903,40 +3908,40 @@ UnitAI.prototype.MustKillGatherTarget = function(ent)
/** /**
* 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 target if given, the nearest is computed versus this target position. * if position (as a vector2D) is given, the nearest is computed versus this 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, target) UnitAI.prototype.FindNearbyResource = function(filter, position)
{ {
var 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;
var 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
var players = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetAllPlayers(); let players = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetAllPlayers();
var range = 64; // TODO: what's a sensible number? let range = 64; // TODO: what's a sensible number?
var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
let entity = this.entity; let pos = position;
if (target) if (!pos)
{ {
let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
if (cmpPosition && cmpPosition.IsInWorld()) if (cmpPosition && cmpPosition.IsInWorld())
entity = target; pos = cmpPosition.GetPosition2D();
} }
var nearby = cmpRangeManager.ExecuteQuery(entity, 0, range, players, IID_ResourceSupply); 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;
var cmpResourceSupply = Engine.QueryInterface(ent, IID_ResourceSupply); let cmpResourceSupply = Engine.QueryInterface(ent, IID_ResourceSupply);
var type = cmpResourceSupply.GetType(); let type = cmpResourceSupply.GetType();
var amount = cmpResourceSupply.GetCurrentAmount(); let amount = cmpResourceSupply.GetCurrentAmount();
var template = cmpTemplateManager.GetCurrentTemplateName(ent); let template = cmpTemplateManager.GetCurrentTemplateName(ent);
// Remove "resource|" prefix from template names, if present. // Remove "resource|" prefix from template names, if present.
if (template.indexOf("resource|") != -1) if (template.indexOf("resource|") != -1)
template = template.slice(9); template = template.slice(9);
@@ -5031,6 +5036,7 @@ UnitAI.prototype.PerformGather = function(target, queued, force)
}; };
this.RememberTargetPosition(order); this.RememberTargetPosition(order);
order.initPos = order.lastPos;
this.AddOrder("Gather", order, queued); this.AddOrder("Gather", order, queued);
}; };