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 @@ -293,9 +293,17 @@ // persistent corpse retaining the ResourceSupply element of the parent. var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); var templateName = cmpTemplateManager.GetCurrentTemplateName(this.entity); - var corpse; + let corpse; if (leaveResources) - corpse = Engine.AddEntity("resource|" + templateName); + { + let cmpResourceSupply = Engine.QueryInterface(this.entity, IID_ResourceSupply); + if (cmpResourceSupply) + { + corpse = Engine.AddEntity("resource|" + templateName); + let corpseResourceSupply = Engine.QueryInterface(corpse, IID_ResourceSupply); + corpseResourceSupply.SetAmount(cmpResourceSupply.GetCurrentAmount()); + } + } else corpse = Engine.AddLocalEntity("corpse|" + templateName); 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,21 @@ "Provides a supply of one particular type of resource." + "" + "1000" + + "1500" + "food.meat" + "false" + "25" + "0.8" + + "" + + "" + + "1" + + "500" + + "" + + "" + + "" + + "1" + + "1000" + + "" + "" + "" + "" + @@ -15,6 +26,11 @@ "" + "Infinity" + "" + + "" + + "" + + "" + + "" + + "" + "" + Resources.BuildChoicesSchema(true, true) + "" + @@ -25,21 +41,70 @@ "" + "" + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + ""; 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.Growth) + { + this.growsWhenAliveOnly = "GrowsWhenAliveOnly" in this.template.Growth; + this.growthRate = ApplyValueModificationsToEntity("ResourceSupply/GrowthRate", +this.template.Growth.Rate, this.entity); + this.growthInterval = +this.template.Growth.Interval; + this.AddGrowthTimer(); + } + + if (this.template.Decay && !this.infinite) + { + this.decaysWhenDeadOnly = "DecaysWhenDeadOnly" in this.template.Decay; + this.decayRate = ApplyValueModificationsToEntity("ResourceSupply/DecayRate", +this.template.Decay.Rate, this.entity); + this.decayInterval = +this.template.Decay.Interval; + this.AddDecayTimer(); + } // 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 }; }; @@ -56,7 +121,7 @@ ResourceSupply.prototype.GetMaxAmount = function() { - return +this.template.Amount; + return this.maxAmount; }; ResourceSupply.prototype.GetCurrentAmount = function() @@ -74,6 +139,15 @@ return this.gatherers.reduce((a, b) => a + b.length, 0); }; +ResourceSupply.prototype.OnValueModification = function(msg) +{ + if (msg.component != "ResourceSupply") + return; + + this.decayRate = ApplyValueModificationsToEntity("ResourceSupply/DecayRate", +this.template.Decay.Rate, this.entity); + this.growthRate = ApplyValueModificationsToEntity("ResourceSupply/GrowthRate", +this.template.Growth.Rate, this.entity); +}; + /* The rate of each additionnal gatherer rate follow a geometric sequence, with diminishingReturns as common ratio. */ ResourceSupply.prototype.GetDiminishingReturns = function() { @@ -84,12 +158,19 @@ { 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.SetAmount = function(newAmount) +{ + var oldAmount = this.GetCurrentAmount(); + this.amount = Math.min(Math.max(newAmount, 0), this.GetMaxAmount()); + this.UpdateSupplyStatus(oldAmount); +}; + ResourceSupply.prototype.TakeResources = function(rate) { // Before changing the amount, activate Fogging if necessary to hide changes @@ -100,19 +181,10 @@ if (this.infinite) return { "amount": rate, "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); - - Engine.PostMessage(this.entity, MT_ResourceSupplyChanged, { "from": old, "to": this.amount }); + let oldAmount = this.GetCurrentAmount(); + this.SetAmount(oldAmount - rate); - return { "amount": change, "exhausted": (this.amount === 0) }; + return { "amount": oldAmount - this.GetCurrentAmount(), "exhausted": this.GetCurrentAmount() === 0 }; }; ResourceSupply.prototype.GetType = function() @@ -138,29 +210,99 @@ Engine.PostMessage(this.entity, MT_ResourceSupplyNumGatherersChanged, { "to": this.GetNumGatherers() }); } + if (this.growthTimer) + { + Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer).CancelTimer(this.growthTimer); + this.growthTimer = null; + } + + if (this.decayTimer) + { + Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer).CancelTimer(this.decayTimer); + this.decayTimer = null; + } + return true; }; // 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) - { - for (var i = 0; i < this.gatherers.length; ++i) - this.RemoveGatherer(gathererID, i); - } - else + if (player != undefined && player != INVALID_PLAYER) { var 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 (var i = 0; i < this.gatherers.length; ++i) + this.RemoveGatherer(gathererID, i); + + let hasGatherers = this.gatherers.some(p => !p.length); + if(hasGatherers) + return; + + if (this.template.Growth && !this.growthTimer) + this.AddGrowthTimer(); + + if (this.template.Decay && !this.decayTimer) + this.AddDecayTimer(); +}; + +ResourceSupply.prototype.AddGrowthTimer = function() +{ + let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); + this.growthTimer = cmpTimer.SetInterval(this.entity, IID_ResourceSupply, "GrowSupply", this.growthInterval, this.growthInterval, undefined); +}; + +ResourceSupply.prototype.AddDecayTimer = function() +{ + let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); + this.decayTimer = cmpTimer.SetInterval(this.entity, IID_ResourceSupply, "DecaySupply", this.decayInterval, this.decayInterval, undefined); }; +ResourceSupply.prototype.GrowSupply = function() +{ + if (this.growsWhenAliveOnly) + { + let cmpHealth = Engine.QueryInterface(this.entity, IID_Health); + if (!cmpHealth) + return; + } + + this.SetAmount(this.GetCurrentAmount() + this.growthRate); +}; + +ResourceSupply.prototype.DecaySupply = function() +{ + if (this.decaysWhenDeadOnly) + { + let cmpHealth = Engine.QueryInterface(this.entity, IID_Health); + if (cmpHealth) + return; + } + + this.SetAmount(this.GetCurrentAmount() - this.decayRate); +}; + +ResourceSupply.prototype.UpdateSupplyStatus = function(oldAmount) +{ + // Remove entities that have been exhausted. + if (this.GetCurrentAmount() === 0) + Engine.DestroyEntity(this.entity); + + // Do not send messages if the resource count didn't change. + if (oldAmount == this.GetCurrentAmount()) + return; + + Engine.PostMessage(this.entity, MT_ResourceSupplyChanged, { "from": oldAmount, "to": this.GetCurrentAmount() }); +}; + + Engine.RegisterComponentType(IID_ResourceSupply, "ResourceSupply", ResourceSupply); Index: binaries/data/mods/public/simulation/templates/gaia/fauna_sheep.xml =================================================================== --- binaries/data/mods/public/simulation/templates/gaia/fauna_sheep.xml +++ binaries/data/mods/public/simulation/templates/gaia/fauna_sheep.xml @@ -12,6 +12,19 @@ pitch + + 200 + + + 2 + 1000 + + + + 1 + 1000 + + Index: binaries/data/mods/public/simulation/templates/gaia/flora_tree_dead.xml =================================================================== --- binaries/data/mods/public/simulation/templates/gaia/flora_tree_dead.xml +++ binaries/data/mods/public/simulation/templates/gaia/flora_tree_dead.xml @@ -3,6 +3,13 @@ Dead Tree + + + + 0.1 + 1000 + + flora/trees/tree_dead.xml 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 @@ -9,6 +9,7 @@ Instead, create a static, unblocking (see #3530 for why) static obstruction. TODO: this should probably be generalized as a parameter on entity death or something. --> + true false Index: binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt.xml +++ binaries/data/mods/public/simulation/templates/template_unit_fauna_hunt.xml @@ -12,5 +12,10 @@ 100 food.meat 8 + + + 1 + 1000 +