Index: binaries/data/mods/public/simulation/components/UnitAI.js =================================================================== --- binaries/data/mods/public/simulation/components/UnitAI.js +++ binaries/data/mods/public/simulation/components/UnitAI.js @@ -490,31 +490,6 @@ }, "Order.Gather": function(msg) { - if (!this.CanGather(this.order.data.target)) - { - this.SetNextState("INDIVIDUAL.GATHER.FINDINGNEWTARGET"); - return; - } - - // If the unit is full go to the nearest dropsite instead of trying to gather. - // Unless our target is a treasure which we cannot be full enough with (we can't carry treasures). - let cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); - if (msg.data.type.generic !== "treasure" && cmpResourceGatherer && !cmpResourceGatherer.CanCarryMore(msg.data.type.generic)) - { - let nearestDropsite = this.FindNearestDropsite(msg.data.type.generic); - if (nearestDropsite) - this.PushOrderFront("ReturnResource", { - "target": nearestDropsite, - "force": false, - "type": msg.data.type - }); - // Players expect the unit to move, so walk to the target instead of trying to gather. - else if (!this.FinishOrder()) - this.WalkToTarget(msg.data.target, false); - - return; - } - if (this.MustKillGatherTarget(this.order.data.target)) { // Make sure we can attack the target, else we'll get very stuck @@ -552,15 +527,7 @@ this.PushOrderFront("Attack", { "target": this.order.data.target, "force": !!this.order.data.force, "hunting": true, "allowCapture": false }); return; } - - this.RememberTargetPosition(); - if (!this.order.data.initPos) - this.order.data.initPos = this.order.data.lastPos; - - if (this.CheckTargetRange(this.order.data.target, IID_ResourceGatherer)) - this.SetNextState("INDIVIDUAL.GATHER.GATHERING"); - else - this.SetNextState("INDIVIDUAL.GATHER.APPROACHING"); + this.SetNextState("INDIVIDUAL.GATHER"); }, "Order.GatherNearPosition": function(msg) { @@ -2263,9 +2230,44 @@ }, "GATHER": { + "enter": function() { + let cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); + if (cmpResourceGatherer) + cmpResourceGatherer.AddToPlayerCounter(this.order.data.type.generic); + + if (!this.CanGather(this.order.data.target)) + { + this.SetNextState("FINDINGNEWTARGET"); + return true; + } + + // If the unit is full go to the nearest dropsite instead of trying to gather. + // Unless our target is a treasure which we cannot be full enough with (we can't carry treasures). + if (this.order.data.type.generic !== "treasure" && cmpResourceGatherer && !cmpResourceGatherer.CanCarryMore(this.order.data.type.generic)) + { + this.SetNextState("RETURNINGRESOURCE"); + return true; + } + + this.RememberTargetPosition(); + if (!this.order.data.initPos) + this.order.data.initPos = this.order.data.lastPos; + + if (this.CheckTargetRange(this.order.data.target, IID_ResourceGatherer)) + this.SetNextState("GATHERING"); + else + this.SetNextState("APPROACHING"); + + return false; + }, + "leave": function() { // Show the carried resource, if we've gathered anything. this.SetDefaultAnimationVariant(); + + let cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); + if (cmpResourceGatherer) + cmpResourceGatherer.RemoveFromPlayerCounter(); }, "APPROACHING": { @@ -2294,9 +2296,6 @@ return true; } this.SetAnimationVariant("approach_" + this.order.data.type.specific); - let cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); - if (cmpResourceGatherer) - cmpResourceGatherer.AddToPlayerCounter(this.order.data.type.generic); return false; }, @@ -2313,16 +2312,11 @@ if (!this.gatheringTarget) return; - // don't use ownership because this is called after a conversion/resignation - // and the ownership would be invalid then. + let cmpSupply = Engine.QueryInterface(this.gatheringTarget, IID_ResourceSupply); if (cmpSupply) cmpSupply.RemoveGatherer(this.entity); - let cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); - if (cmpResourceGatherer) - cmpResourceGatherer.RemoveFromPlayerCounter(); - delete this.gatheringTarget; }, }, @@ -2404,7 +2398,6 @@ this.SetDefaultAnimationVariant(); this.FaceTowardsTarget(this.order.data.target); this.SelectAnimation("gather_" + this.order.data.type.specific); - cmpResourceGatherer.AddToPlayerCounter(this.order.data.type.generic); } return false; }, @@ -2418,12 +2411,7 @@ if (cmpSupply) cmpSupply.RemoveGatherer(this.entity); - let cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); - if (cmpResourceGatherer) - cmpResourceGatherer.RemoveFromPlayerCounter(); - delete this.gatheringTarget; - this.ResetAnimation(); }, @@ -2485,22 +2473,9 @@ // return to the nearest dropsite if (status.filled) { - let nearestDropsite = this.FindNearestDropsite(resourceType.generic); - if (nearestDropsite) - { - // (Keep this Gather order on the stack so we'll - // continue gathering after returning) - // However mark our target as invalid if it's exhausted, so we don't waste time - // trying to gather from it. - if (status.exhausted) - this.order.data.target = INVALID_ENTITY; - this.PushOrderFront("ReturnResource", { "target": nearestDropsite, "force": false }); - return; - } - - // Oh no, couldn't find any drop sites. Give up on gathering. - this.FinishOrder(); - return; + if (status.exhausted) + this.order.data.target = INVALID_ENTITY; + this.SetNextState("RETURNINGRESOURCE"); } if (status.exhausted) @@ -2589,6 +2564,47 @@ return true; }, }, + + "RETURNINGRESOURCE": { + "enter": function() { + let nearestDropsite = this.FindNearestDropsite(this.order.data.type.generic); + if (!nearestDropsite || + !this.MoveTo({ "target": nearestDropsite }, IID_ResourceGatherer)) + { + let formerTarget = this.order.data.target; + // Players expect the unit to move, so walk to the target instead of trying to gather. + if (!this.FinishOrder()) + this.WalkToTarget(formerTarget, false); + return true; + } + this.order.data.nearestDropsite = nearestDropsite; + return false; + }, + + "leave": function() { + this.StopMoving(); + }, + + "MovementUpdate": function(msg) { + let cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); + if (this.CheckTargetRange(this.order.data.nearestDropsite, IID_ResourceGatherer) && + this.CanReturnResource(this.order.data.nearestDropsite, true, cmpResourceGatherer)) + { + cmpResourceGatherer.CommitResources(this.order.data.nearestDropsite); + + // Stop showing the carried resource animation. + this.SetDefaultAnimationVariant(); + + this.SetNextState("APPROACHING"); + return; + } + + if (msg.obstructed) + return; + + this.SetNextState("RETURNINGRESOURCE"); + }, + }, }, "HEAL": { @@ -5511,8 +5527,8 @@ // Save the resource type now, so if the resource gets destroyed // before we process the order then we still know what resource // type to look for more of - var type; - var cmpResourceSupply = QueryMiragedInterface(target, IID_ResourceSupply); + let type; + let cmpResourceSupply = QueryMiragedInterface(target, IID_ResourceSupply); if (cmpResourceSupply) type = cmpResourceSupply.GetType(); else @@ -5520,8 +5536,8 @@ // Also save the target entity's template, so that if it's an animal, // we won't go from hunting slow safe animals to dangerous fast ones - var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); - var template = cmpTemplateManager.GetCurrentTemplateName(target); + let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); + let template = cmpTemplateManager.GetCurrentTemplateName(target); if (template.indexOf("resource|") != -1) template = template.slice(9);