From 8ac9f1d8ea2b19c189c0aad351bf56d1e720aff1 Mon Sep 17 00:00:00 2001 From: wraitii Date: Wed, 13 Mar 2013 20:10:46 +0000 Subject: [PATCH] Limit the number of gatherer per resource, as described in #1387. Based on work by crezax. Fixes #1387 This was SVN commit r13277. --- .../simulation/ai/common-api-v2/entity.js | 23 ++++- .../mods/public/simulation/ai/qbot/worker.js | 4 + .../public/simulation/components/AIProxy.js | 7 ++ .../simulation/components/GuiInterface.js | 4 +- .../simulation/components/ResourceSupply.js | 47 +++++++++ .../public/simulation/components/UnitAI.js | 99 ++++++++++++++++--- .../components/interfaces/ResourceSupply.js | 4 + .../templates/gaia/fauna_chicken.xml | 1 + .../simulation/templates/gaia/fauna_goat.xml | 1 + .../template_gaia_flora_bush_berry.xml | 1 + .../templates/template_gaia_flora_tree.xml | 1 + .../templates/template_gaia_geo_mineral.xml | 1 + .../template_gaia_geo_mineral_slabs.xml | 1 + .../templates/template_gaia_geo_rock.xml | 1 + .../template_gaia_geo_rock_slabs.xml | 1 + .../templates/template_gaia_ruins.xml | 1 + .../templates/template_gaia_treasure.xml | 1 + .../template_structure_resource_corral.xml | 1 + .../template_structure_resource_field.xml | 1 + .../templates/template_unit_fauna_fish.xml | 1 + .../templates/template_unit_fauna_herd.xml | 1 + .../templates/template_unit_fauna_hunt.xml | 1 + .../template_unit_fauna_hunt_whale.xml | 1 + 23 files changed, 189 insertions(+), 15 deletions(-) diff --git a/binaries/data/mods/public/simulation/ai/common-api-v2/entity.js b/binaries/data/mods/public/simulation/ai/common-api-v2/entity.js index 749c6ae4eb..b867b55ca7 100644 --- a/binaries/data/mods/public/simulation/ai/common-api-v2/entity.js +++ b/binaries/data/mods/public/simulation/ai/common-api-v2/entity.js @@ -161,7 +161,14 @@ var EntityTemplate = Class({ return undefined; return +this._template.ResourceSupply.Amount; }, - + + maxGatherers: function() + { + if (this._template.ResourceSupply !== undefined) + return this._template.ResourceSupply.MaxGatherers; + return 0; + }, + resourceGatherRates: function() { if (!this._template.ResourceGatherer) return undefined; @@ -339,6 +346,20 @@ var Entity = Class({ return this._entity.resourceSupplyAmount; }, + resourceSupplyGatherers: function() + { + if (this._entity.resourceSupplyGatherers !== undefined) + return this._entity.resourceSupplyGatherers; + return []; + }, + + isFull: function() + { + if (this._entity.resourceSupplyGatherers !== undefined) + return (this.maxGatherers === this._entity.resourceSupplyGatherers.length); + return undefined; + }, + resourceCarrying: function() { if(this._entity.resourceCarrying === undefined) return undefined; diff --git a/binaries/data/mods/public/simulation/ai/qbot/worker.js b/binaries/data/mods/public/simulation/ai/qbot/worker.js index f31bc6de3c..8fe10ec1af 100644 --- a/binaries/data/mods/public/simulation/ai/qbot/worker.js +++ b/binaries/data/mods/public/simulation/ai/qbot/worker.js @@ -168,6 +168,10 @@ Worker.prototype.startGathering = function(gameState){ if (!supply.position()){ return; } + + if (supply.isFull === true) { + return; + } // measure the distance to the resource var dist = VectorDistance(supply.position(), ent.position()); diff --git a/binaries/data/mods/public/simulation/components/AIProxy.js b/binaries/data/mods/public/simulation/components/AIProxy.js index aa73f4fb55..0b54bb9a5b 100644 --- a/binaries/data/mods/public/simulation/components/AIProxy.js +++ b/binaries/data/mods/public/simulation/components/AIProxy.js @@ -141,6 +141,12 @@ AIProxy.prototype.OnResourceSupplyChanged = function(msg) this.changes.resourceSupplyAmount = msg.to; }; +AIProxy.prototype.OnResourceSupplyGatherersChanged = function(msg) +{ + this.NotifyChange(); + this.changes.resourceSupplyGatherers = msg.to; +}; + AIProxy.prototype.OnResourceCarryingChanged = function(msg) { this.NotifyChange(); @@ -225,6 +231,7 @@ AIProxy.prototype.GetFullRepresentation = function() { // Updated by OnResourceSupplyChanged ret.resourceSupplyAmount = cmpResourceSupply.GetCurrentAmount(); + ret.resourceSupplyGatherers = cmpResourceSupply.GetGatherers(); } var cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); diff --git a/binaries/data/mods/public/simulation/components/GuiInterface.js b/binaries/data/mods/public/simulation/components/GuiInterface.js index bf385e1df9..453c1b6753 100644 --- a/binaries/data/mods/public/simulation/components/GuiInterface.js +++ b/binaries/data/mods/public/simulation/components/GuiInterface.js @@ -261,7 +261,9 @@ GuiInterface.prototype.GetEntityState = function(player, ent) "max": cmpResourceSupply.GetMaxAmount(), "amount": cmpResourceSupply.GetCurrentAmount(), "type": cmpResourceSupply.GetType(), - "killBeforeGather": cmpResourceSupply.GetKillBeforeGather() + "killBeforeGather": cmpResourceSupply.GetKillBeforeGather(), + "maxGatherers": cmpResourceSupply.GetMaxGatherers(), + "gatherers": cmpResourceSupply.GetGatherers() }; } diff --git a/binaries/data/mods/public/simulation/components/ResourceSupply.js b/binaries/data/mods/public/simulation/components/ResourceSupply.js index 2dbf4e44c2..8a4a1bb8c2 100644 --- a/binaries/data/mods/public/simulation/components/ResourceSupply.js +++ b/binaries/data/mods/public/simulation/components/ResourceSupply.js @@ -29,12 +29,16 @@ ResourceSupply.prototype.Schema = "treasure.metal" + "treasure.food" + "" + + "" + + "" + + "" + ""; ResourceSupply.prototype.Init = function() { // Current resource amount (non-negative) this.amount = this.GetMaxAmount(); + this.gatherers = []; // list of IDs }; ResourceSupply.prototype.GetKillBeforeGather = function() @@ -52,6 +56,16 @@ ResourceSupply.prototype.GetCurrentAmount = function() return this.amount; }; +ResourceSupply.prototype.GetMaxGatherers = function() +{ + return +this.template.MaxGatherers; +}; + +ResourceSupply.prototype.GetGatherers = function() +{ + return this.gatherers; +}; + ResourceSupply.prototype.TakeResources = function(rate) { // 'rate' should be a non-negative integer @@ -77,4 +91,37 @@ ResourceSupply.prototype.GetType = function() return { "generic": type, "specific": subtype }; }; +ResourceSupply.prototype.IsAvailable = function(gathererID) +{ + if (this.gatherers.length < this.GetMaxGatherers() || this.gatherers.indexOf(gathererID) !== -1) + return true; + return false; +}; + +ResourceSupply.prototype.AddGatherer = function(gathererID) +{ + if (!this.IsAvailable(gathererID)) + return false; + + if (this.gatherers.indexOf(gathererID) === -1) + { + this.gatherers.push(gathererID); + // broadcast message, mainly useful for the AIs. + Engine.PostMessage(this.entity, MT_ResourceSupplyGatherersChanged, { "to": this.gatherers }); + } + + return true; +}; + +// should this return false if the gatherer didn't gather from said resource? +ResourceSupply.prototype.RemoveGatherer = function(gathererID) +{ + if (this.gatherers.indexOf(gathererID) !== -1) + { + this.gatherers.splice(this.gatherers.indexOf(gathererID),1); + // broadcast message, mainly useful for the AIs. + Engine.PostMessage(this.entity, MT_ResourceSupplyGatherersChanged, { "to": this.gatherers }); + } +}; + Engine.RegisterComponentType(IID_ResourceSupply, "ResourceSupply", ResourceSupply); diff --git a/binaries/data/mods/public/simulation/components/UnitAI.js b/binaries/data/mods/public/simulation/components/UnitAI.js index 48f0ad935f..5487383e7f 100644 --- a/binaries/data/mods/public/simulation/components/UnitAI.js +++ b/binaries/data/mods/public/simulation/components/UnitAI.js @@ -1539,6 +1539,48 @@ var UnitFsmSpec = { "APPROACHING": { "enter": function() { this.SelectAnimation("move"); + + this.gatheringTarget = this.order.data.target; // temporary, deleted in "leave". + + // check that we can gather from the resource we're supposed to gather from. + var cmpSupply = Engine.QueryInterface(this.gatheringTarget, IID_ResourceSupply); + if (!cmpSupply || !cmpSupply.AddGatherer(this.entity)) + { + // Save the current order's data in case we need it later + var oldType = this.order.data.type; + var oldTarget = this.order.data.target; + var oldTemplate = this.order.data.template; + + // Try the next queued order if there is any + if (this.FinishOrder()) + return true; + + // Try to find another nearby target of the same specific type + // Also don't switch to a different type of huntable animal + var nearby = this.FindNearbyResource(function (ent, type, template) { + return ( + ent != oldTarget + && ((type.generic == "treasure" && oldType.generic == "treasure") + || (type.specific == oldType.specific + && (type.specific != "meat" || oldTemplate == template))) + ); + }); + if (nearby) + { + this.PerformGather(nearby, false, false); + return true; + } + + var nearby = this.FindNearestDropsite(oldType.generic); + if (nearby) + { + this.PushOrderFront("ReturnResource", { "target": nearby, "force": false }); + return true; + } + + return true; + } + return false; }, "MoveCompleted": function(msg) { @@ -1546,6 +1588,11 @@ var UnitFsmSpec = { { // We failed to reach the target + // remove us from the list of entities gathering from Resource. + var cmpSupply = Engine.QueryInterface(this.gatheringTarget, IID_ResourceSupply); + if (cmpSupply) + cmpSupply.RemoveGatherer(this.entity); + // Save the current order's data in case we need it later var oldType = this.order.data.type; var oldTarget = this.order.data.target; @@ -1580,6 +1627,13 @@ var UnitFsmSpec = { // We reached the target - start gathering from it now this.SetNextState("GATHERING"); }, + + "leave": function() { + var cmpSupply = Engine.QueryInterface(this.gatheringTarget, IID_ResourceSupply); + if (cmpSupply) + cmpSupply.RemoveGatherer(this.entity); + delete this.gatheringTarget; + }, }, // Walking to a good place to gather resources near, used by GatherNearPosition @@ -1616,8 +1670,18 @@ var UnitFsmSpec = { "GATHERING": { "enter": function() { - var target = this.order.data.target; + this.gatheringTarget = this.order.data.target; // deleted in "leave". + if (this.gatheringTarget) { + // Check that we can gather from the resource we're supposed to gather from. + // Will only be added if we're not already in. + var cmpSupply = Engine.QueryInterface(this.gatheringTarget, IID_ResourceSupply); + if (!cmpSupply || !cmpSupply.AddGatherer(this.entity)) + { + this.StartTimer(0); + return false; + } + } // If this order was forced, the player probably gave it, but now we've reached the target // switch to an unforced order (can be interrupted by attacks) this.order.data.force = false; @@ -1626,12 +1690,12 @@ var UnitFsmSpec = { // Calculate timing based on gather rates // This allows the gather rate to control how often we gather, instead of how much. var cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); - var rate = cmpResourceGatherer.GetTargetGatherRate(target); + var rate = cmpResourceGatherer.GetTargetGatherRate(this.gatheringTarget); if (!rate) { // Try to find another target if the current one stopped existing - if (!Engine.QueryInterface(target, IID_Identity)) + if (!Engine.QueryInterface(this.gatheringTarget, IID_Identity)) { // Let the Timer logic handle this this.StartTimer(0); @@ -1654,7 +1718,7 @@ var UnitFsmSpec = { // (else it'll look like we're chopping empty air). // (If it's not alive, the Timer handler will deal with sending us // off to a different target.) - if (this.CheckTargetRange(target, IID_ResourceGatherer)) + if (this.CheckTargetRange(this.gatheringTarget, IID_ResourceGatherer)) { var typename = "gather_" + this.order.data.type.specific; this.SelectAnimation(typename, false, 1.0, typename); @@ -1664,24 +1728,31 @@ var UnitFsmSpec = { "leave": function() { this.StopTimer(); - + + var cmpSupply = Engine.QueryInterface(this.gatheringTarget, IID_ResourceSupply); + if (cmpSupply) + cmpSupply.RemoveGatherer(this.entity); + delete this.gatheringTarget; + // Show the carried resource, if we've gathered anything. this.SetGathererAnimationOverride(); }, "Timer": function(msg) { - var target = this.order.data.target; var resourceTemplate = this.order.data.template; var resourceType = this.order.data.type; + + var cmpSupply = Engine.QueryInterface(this.gatheringTarget, IID_ResourceSupply); + // Check we can still reach and gather from the target - if (this.CheckTargetRange(target, IID_ResourceGatherer) && this.CanGather(target)) + if (this.CheckTargetRange(this.gatheringTarget, IID_ResourceGatherer) && this.CanGather(this.gatheringTarget) && cmpSupply && cmpSupply.IsAvailable(this.entity)) { // Gather the resources: var cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); // Try to gather treasure - if (cmpResourceGatherer.TryInstantGather(target)) + if (cmpResourceGatherer.TryInstantGather(this.gatheringTarget)) return; // If we've already got some resources but they're the wrong type, @@ -1690,7 +1761,7 @@ var UnitFsmSpec = { cmpResourceGatherer.DropResources(); // Collect from the target - var status = cmpResourceGatherer.PerformGather(target); + var status = cmpResourceGatherer.PerformGather(this.gatheringTarget); // If we've collected as many resources as possible, // return to the nearest dropsite @@ -1714,10 +1785,10 @@ var UnitFsmSpec = { if (!status.exhausted) return; } - else + else if (cmpSupply && cmpSupply.IsAvailable(this.entity)) { // Try to follow the target - if (this.MoveToTargetRange(target, IID_ResourceGatherer)) + if (this.MoveToTargetRange(this.gatheringTarget, IID_ResourceGatherer)) { this.SetNextState("APPROACHING"); return; @@ -2997,7 +3068,7 @@ UnitAI.prototype.FindNearbyResource = function(filter) if (template.indexOf("resource|") != -1) template = template.slice(9); - if (amount > 0 && filter(ent, type, template)) + if (amount > 0 && cmpResourceSupply.IsAvailable(this.entity) && filter(ent, type, template)) return ent; } @@ -4179,7 +4250,9 @@ UnitAI.prototype.CanGather = function(target) // No need to verify ownership as we should be able to gather from // a target regardless of ownership. - + // No need to call "cmpResourceSupply.IsAvailable()" either because that + // would cause units to walk to full entities instead of choosing another one + // nearby to gather from, which is undesirable. return true; }; diff --git a/binaries/data/mods/public/simulation/components/interfaces/ResourceSupply.js b/binaries/data/mods/public/simulation/components/interfaces/ResourceSupply.js index 017d762a1f..caf4caad88 100644 --- a/binaries/data/mods/public/simulation/components/interfaces/ResourceSupply.js +++ b/binaries/data/mods/public/simulation/components/interfaces/ResourceSupply.js @@ -3,3 +3,7 @@ Engine.RegisterInterface("ResourceSupply"); // Message of the form { "from": 100, "to", 90 }, // sent whenever supply level changes. Engine.RegisterMessageType("ResourceSupplyChanged"); + +// Message of the form { "to", [array of gatherers ID] }, +// sent whenever the number of gatherer changes +Engine.RegisterMessageType("ResourceSupplyGatherersChanged"); diff --git a/binaries/data/mods/public/simulation/templates/gaia/fauna_chicken.xml b/binaries/data/mods/public/simulation/templates/gaia/fauna_chicken.xml index 4ce90d2507..8ac2d267b3 100644 --- a/binaries/data/mods/public/simulation/templates/gaia/fauna_chicken.xml +++ b/binaries/data/mods/public/simulation/templates/gaia/fauna_chicken.xml @@ -15,6 +15,7 @@ 40 food.meat + 5 diff --git a/binaries/data/mods/public/simulation/templates/gaia/fauna_goat.xml b/binaries/data/mods/public/simulation/templates/gaia/fauna_goat.xml index 844e266c56..82ab8ddae6 100644 --- a/binaries/data/mods/public/simulation/templates/gaia/fauna_goat.xml +++ b/binaries/data/mods/public/simulation/templates/gaia/fauna_goat.xml @@ -14,6 +14,7 @@ 120 food.meat + 6 fauna/goat.xml diff --git a/binaries/data/mods/public/simulation/templates/template_gaia_flora_bush_berry.xml b/binaries/data/mods/public/simulation/templates/template_gaia_flora_bush_berry.xml index 8350b68175..b63d368a42 100644 --- a/binaries/data/mods/public/simulation/templates/template_gaia_flora_bush_berry.xml +++ b/binaries/data/mods/public/simulation/templates/template_gaia_flora_bush_berry.xml @@ -19,6 +19,7 @@ false 200 food.fruit + 8 diff --git a/binaries/data/mods/public/simulation/templates/template_gaia_flora_tree.xml b/binaries/data/mods/public/simulation/templates/template_gaia_flora_tree.xml index 5d28e90f28..e5684db562 100644 --- a/binaries/data/mods/public/simulation/templates/template_gaia_flora_tree.xml +++ b/binaries/data/mods/public/simulation/templates/template_gaia_flora_tree.xml @@ -14,6 +14,7 @@ false 200 wood.tree + 6 diff --git a/binaries/data/mods/public/simulation/templates/template_gaia_geo_mineral.xml b/binaries/data/mods/public/simulation/templates/template_gaia_geo_mineral.xml index 6cb0d7f977..eaadb6f568 100644 --- a/binaries/data/mods/public/simulation/templates/template_gaia_geo_mineral.xml +++ b/binaries/data/mods/public/simulation/templates/template_gaia_geo_mineral.xml @@ -14,6 +14,7 @@ false 1000 metal.ore + 8 diff --git a/binaries/data/mods/public/simulation/templates/template_gaia_geo_mineral_slabs.xml b/binaries/data/mods/public/simulation/templates/template_gaia_geo_mineral_slabs.xml index 19c80f0c63..7d371ef3b9 100644 --- a/binaries/data/mods/public/simulation/templates/template_gaia_geo_mineral_slabs.xml +++ b/binaries/data/mods/public/simulation/templates/template_gaia_geo_mineral_slabs.xml @@ -12,6 +12,7 @@ 5000 + 16 diff --git a/binaries/data/mods/public/simulation/templates/template_gaia_geo_rock.xml b/binaries/data/mods/public/simulation/templates/template_gaia_geo_rock.xml index e0a86d96b8..bc2bdde908 100644 --- a/binaries/data/mods/public/simulation/templates/template_gaia_geo_rock.xml +++ b/binaries/data/mods/public/simulation/templates/template_gaia_geo_rock.xml @@ -14,6 +14,7 @@ false 1000 stone.rock + 8 diff --git a/binaries/data/mods/public/simulation/templates/template_gaia_geo_rock_slabs.xml b/binaries/data/mods/public/simulation/templates/template_gaia_geo_rock_slabs.xml index ec339f20af..8a5adf7ecb 100644 --- a/binaries/data/mods/public/simulation/templates/template_gaia_geo_rock_slabs.xml +++ b/binaries/data/mods/public/simulation/templates/template_gaia_geo_rock_slabs.xml @@ -12,6 +12,7 @@ 5000 + 16 diff --git a/binaries/data/mods/public/simulation/templates/template_gaia_ruins.xml b/binaries/data/mods/public/simulation/templates/template_gaia_ruins.xml index 48bed40953..abf177c395 100644 --- a/binaries/data/mods/public/simulation/templates/template_gaia_ruins.xml +++ b/binaries/data/mods/public/simulation/templates/template_gaia_ruins.xml @@ -21,6 +21,7 @@ false 500 stone.ruins + 1 diff --git a/binaries/data/mods/public/simulation/templates/template_gaia_treasure.xml b/binaries/data/mods/public/simulation/templates/template_gaia_treasure.xml index eafd4755ef..7f19850db6 100644 --- a/binaries/data/mods/public/simulation/templates/template_gaia_treasure.xml +++ b/binaries/data/mods/public/simulation/templates/template_gaia_treasure.xml @@ -21,6 +21,7 @@ false 300 treasure.metal + 1 diff --git a/binaries/data/mods/public/simulation/templates/template_structure_resource_corral.xml b/binaries/data/mods/public/simulation/templates/template_structure_resource_corral.xml index a7120bc29d..764aae2a7e 100644 --- a/binaries/data/mods/public/simulation/templates/template_structure_resource_corral.xml +++ b/binaries/data/mods/public/simulation/templates/template_structure_resource_corral.xml @@ -60,6 +60,7 @@ false 200 food.milk + 6 diff --git a/binaries/data/mods/public/simulation/templates/template_structure_resource_field.xml b/binaries/data/mods/public/simulation/templates/template_structure_resource_field.xml index f2e183d65e..b48b83fe03 100644 --- a/binaries/data/mods/public/simulation/templates/template_structure_resource_field.xml +++ b/binaries/data/mods/public/simulation/templates/template_structure_resource_field.xml @@ -53,6 +53,7 @@ false 2000 food.grain + 20 diff --git a/binaries/data/mods/public/simulation/templates/template_unit_fauna_fish.xml b/binaries/data/mods/public/simulation/templates/template_unit_fauna_fish.xml index b491f04c2c..35ccc69140 100644 --- a/binaries/data/mods/public/simulation/templates/template_unit_fauna_fish.xml +++ b/binaries/data/mods/public/simulation/templates/template_unit_fauna_fish.xml @@ -22,6 +22,7 @@ false 1000 food.fish + 4 diff --git a/binaries/data/mods/public/simulation/templates/template_unit_fauna_herd.xml b/binaries/data/mods/public/simulation/templates/template_unit_fauna_herd.xml index 31de0e120a..daf7ae86a8 100644 --- a/binaries/data/mods/public/simulation/templates/template_unit_fauna_herd.xml +++ b/binaries/data/mods/public/simulation/templates/template_unit_fauna_herd.xml @@ -13,6 +13,7 @@ true 100 food.meat + 8 20 diff --git a/binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt.xml b/binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt.xml index 93929fac95..48c71024c2 100644 --- a/binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt.xml +++ b/binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt.xml @@ -8,5 +8,6 @@ true 100 food.meat + 8 diff --git a/binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt_whale.xml b/binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt_whale.xml index 100b8158d4..d681283bfe 100644 --- a/binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt_whale.xml +++ b/binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt_whale.xml @@ -14,5 +14,6 @@ true 500 food.meat + 4