Index: binaries/data/mods/public/simulation/components/Health.js
===================================================================
--- binaries/data/mods/public/simulation/components/Health.js
+++ binaries/data/mods/public/simulation/components/Health.js
@@ -285,15 +285,23 @@
// persistent corpse retaining the ResourceSupply element of the parent.
let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
let templateName = cmpTemplateManager.GetCurrentTemplateName(this.entity);
- let corpse;
+ let entCorpse;
if (leaveResources)
- corpse = Engine.AddEntity("resource|" + templateName);
+ {
+ let cmpResourceSupply = Engine.QueryInterface(this.entity, IID_ResourceSupply);
+ if (cmpResourceSupply)
+ {
+ entCorpse = Engine.AddEntity("resource|" + templateName);
+ let cmpResourceSupplyCorpse = Engine.QueryInterface(entCorpse, IID_ResourceSupply);
+ cmpResourceSupplyCorpse.SetAmount(cmpResourceSupply.GetCurrentAmount());
+ }
+ }
else
- corpse = Engine.AddLocalEntity("corpse|" + templateName);
+ entCorpse = Engine.AddLocalEntity("corpse|" + templateName);
// Copy various parameters so it looks just like us
- let cmpCorpsePosition = Engine.QueryInterface(corpse, IID_Position);
+ let cmpCorpsePosition = Engine.QueryInterface(entCorpse, IID_Position);
let pos = cmpPosition.GetPosition();
cmpCorpsePosition.JumpTo(pos.x, pos.z);
let rot = cmpPosition.GetRotation();
@@ -301,17 +309,17 @@
cmpCorpsePosition.SetXZRotation(rot.x, rot.z);
let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
- let cmpCorpseOwnership = Engine.QueryInterface(corpse, IID_Ownership);
+ let cmpCorpseOwnership = Engine.QueryInterface(entCorpse, IID_Ownership);
cmpCorpseOwnership.SetOwner(cmpOwnership.GetOwner());
let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
- let cmpCorpseVisual = Engine.QueryInterface(corpse, IID_Visual);
+ let cmpCorpseVisual = Engine.QueryInterface(entCorpse, IID_Visual);
cmpCorpseVisual.SetActorSeed(cmpVisual.GetActorSeed());
// Make it fall over
cmpCorpseVisual.SelectAnimation("death", true, 1.0);
- return corpse;
+ return entCorpse;
};
Health.prototype.CreateDeathSpawnedEntity = function()
Index: binaries/data/mods/public/simulation/components/ResourceSupply.js
===================================================================
--- binaries/data/mods/public/simulation/components/ResourceSupply.js
+++ binaries/data/mods/public/simulation/components/ResourceSupply.js
@@ -4,10 +4,24 @@
"Provides a supply of one particular type of resource." +
"" +
"1000" +
+ "1500" +
"food.meat" +
"false" +
"25" +
"0.8" +
+ "" +
+ "" +
+ "Alive" +
+ "2" +
+ "1000" +
+ "" +
+ "" +
+ "Dead" +
+ "-1" +
+ "1000" +
+ "2000" +
+ "" +
+ "" +
"" +
"" +
"" +
@@ -15,6 +29,11 @@
"" +
"Infinity" +
"" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
"" +
Resources.BuildChoicesSchema(true, true) +
"" +
@@ -25,21 +44,61 @@
"" +
"" +
"" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "Alive" +
+ "Dead" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "" +
"";
ResourceSupply.prototype.Init = function()
{
// Current resource amount (non-negative)
- this.amount = this.GetMaxAmount();
+ this.amount = +this.template.Amount;
+ this.maxAmount = this.amount;
+ if (this.template.MaxAmount && +this.template.MaxAmount > this.amount)
+ this.maxAmount = +this.template.MaxAmount;
+
+ this.infinite = !isFinite(+this.template.Amount);
+
+ if (this.template.Change && !this.infinite)
+ for (let changeKey in this.template.Change)
+ this.AddTimer(changeKey);
// List of IDs for each player
this.gatherers = [];
- let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers()
+ let numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers();
for (let i = 0; i < numPlayers; ++i)
this.gatherers.push([]);
- this.infinite = !isFinite(+this.template.Amount);
-
let [type, subtype] = this.template.Type.split('.');
this.cachedType = { "generic": type, "specific": subtype };
};
@@ -51,12 +110,12 @@
ResourceSupply.prototype.GetKillBeforeGather = function()
{
- return (this.template.KillBeforeGather == "true");
+ return this.template.KillBeforeGather == "true";
};
ResourceSupply.prototype.GetMaxAmount = function()
{
- return +this.template.Amount;
+ return this.maxAmount;
};
ResourceSupply.prototype.GetCurrentAmount = function()
@@ -84,13 +143,20 @@
{
let numGatherers = this.GetNumGatherers();
if (numGatherers > 1)
- return diminishingReturns == 1 ? 1 : (1. - Math.pow(diminishingReturns, numGatherers)) / (1. - diminishingReturns) / numGatherers;
+ return diminishingReturns == 1 ? 1 : (1 - Math.pow(diminishingReturns, numGatherers)) / (1 - diminishingReturns) / numGatherers;
}
}
return null;
};
-ResourceSupply.prototype.TakeResources = function(rate)
+ResourceSupply.prototype.SetAmount = function(newAmount)
+{
+ let oldAmount = this.amount;
+ this.amount = Math.min(Math.max(newAmount, 0), this.GetMaxAmount());
+ this.UpdateSupplyStatus(oldAmount);
+};
+
+ResourceSupply.prototype.TakeResources = function(amount)
{
// Before changing the amount, activate Fogging if necessary to hide changes
let cmpFogging = Engine.QueryInterface(this.entity, IID_Fogging);
@@ -98,21 +164,12 @@
cmpFogging.Activate();
if (this.infinite)
- return { "amount": rate, "exhausted": false };
+ return { "amount": amount, "exhausted": false };
- // 'rate' should be a non-negative integer
-
- var old = this.amount;
- this.amount = Math.max(0, old - rate);
- var change = old - this.amount;
-
- // Remove entities that have been exhausted
- if (this.amount === 0)
- Engine.DestroyEntity(this.entity);
+ let oldAmount = this.amount;
+ this.SetAmount(oldAmount - amount);
- Engine.PostMessage(this.entity, MT_ResourceSupplyChanged, { "from": old, "to": this.amount });
-
- return { "amount": change, "exhausted": (this.amount === 0) };
+ return { "amount": oldAmount - this.amount, "exhausted": this.amount == 0 };
};
ResourceSupply.prototype.GetType = function()
@@ -144,23 +201,109 @@
// should this return false if the gatherer didn't gather from said resource?
ResourceSupply.prototype.RemoveGatherer = function(gathererID, player)
{
- // this can happen if the unit is dead
- if (player == undefined || player == INVALID_PLAYER)
+ if (player != undefined && player != INVALID_PLAYER)
{
- for (var i = 0; i < this.gatherers.length; ++i)
- this.RemoveGatherer(gathererID, i);
- }
- else
- {
- var index = this.gatherers[player].indexOf(gathererID);
+ let index = this.gatherers[player].indexOf(gathererID);
if (index !== -1)
{
- this.gatherers[player].splice(index,1);
+ this.gatherers[player].splice(index, 1);
// broadcast message, mainly useful for the AIs.
Engine.PostMessage(this.entity, MT_ResourceSupplyNumGatherersChanged, { "to": this.GetNumGatherers() });
- return;
}
}
+ // This can happen if the unit is dead
+ else
+ for (let i = 0; i < this.gatherers.length; ++i)
+ this.RemoveGatherer(gathererID, i);
+};
+
+/**
+ * @param {string} changeKey the name of the change to apply to the entity
+ */
+ResourceSupply.prototype.AddTimer = function(changeKey)
+{
+ let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
+ if (!this.timers)
+ this.timers = {};
+
+ if (!this.timers[changeKey])
+ {
+ let change = this.template.Change[changeKey];
+ let interval = ApplyValueModificationsToEntity("ResourceSupply/Change/" + changeKey + "/Interval", +change.Interval, this.entity);
+ this.timers[changeKey] = cmpTimer.SetInterval(this.entity, IID_ResourceSupply, "RegenSupply", +change.Delay, interval, changeKey);
+ }
+};
+
+/**
+ * @param {string} changeKey the name of the change to apply to the entity
+ */
+ResourceSupply.prototype.RegenSupply = function(changeKey)
+{
+ let change = this.template.Change[changeKey];
+ let cmpHealth = Engine.QueryInterface(this.entity, IID_Health);
+ if (change.Constraint &&
+ (change.Constraint == "Alive" && !cmpHealth ||
+ change.Constraint == "Dead" && cmpHealth))
+ return;
+
+ let newAmount = ApplyValueModificationsToEntity("ResourceSupply/Change/" + changeKey + "/Value", +change.Value, this.entity);
+
+ if (this.change.Limit)
+ {
+ if (newAmount > 0 && this.amount + newAmount > limit)
+ return;
+
+ if (newAmount < 0 && this.amount - newAmount < limit)
+ return;
+ }
+
+ this.SetAmount(this.amount + newAmount);
+};
+
+ResourceSupply.prototype.UpdateSupplyStatus = function(oldAmount)
+{
+ // Remove entities that have been exhausted.
+ if (this.amount == 0)
+ Engine.DestroyEntity(this.entity);
+
+ // Do not send messages if the resource count didn't change.
+ if (oldAmount != this.amount)
+ Engine.PostMessage(this.entity, MT_ResourceSupplyChanged, {
+ "from": oldAmount,
+ "to": this.amount
+ });
+};
+
+ResourceSupply.prototype.OnDestroy = function()
+{
+ if (!this.timers)
+ return;
+
+ let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
+ for (let changeKey in this.timers)
+ cmpTimer.CancelTimer(this.timers[changeKey]);
+};
+
+ResourceSupply.prototype.OnValueModification = function(msg)
+{
+ if (msg.component != "ResourceSupply" || !this.template.Change && this.infinite)
+ return;
+
+ let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
+ for (let value of msg.valueNames)
+ {
+ if (!value)
+ continue;
+
+ let elements = value.split("/");
+ if (elements.length != 4 || elements[3] != "Interval")
+ continue;
+
+ // Get the third element of the message as it contains the change key.
+ let changeKey = elements[2];
+ cmpTimer.CancelTimer(this.timers[changeKey]);
+ this.AddTimer(changeKey);
+ }
};
Engine.RegisterComponentType(IID_ResourceSupply, "ResourceSupply", ResourceSupply);
Index: binaries/data/mods/public/simulation/templates/special/filter/resource.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/special/filter/resource.xml
+++ binaries/data/mods/public/simulation/templates/special/filter/resource.xml
@@ -2,6 +2,7 @@
+