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