10 | | "<data type='boolean'/>" + |
11 | | "</element>" + |
12 | | "<element name='Amount' a:help='Amount of resources available from this entity'>" + |
13 | | "<choice><data type='nonNegativeInteger'/><value>Infinity</value></choice>" + |
14 | | "</element>" + |
15 | | "<element name='Type' a:help='Type of resources'>" + |
16 | | "<choice>" + |
| 10 | "<data type='boolean'/>" + |
| 11 | "</element>" + |
| 12 | "<element name='Amount' a:help='Amount of resources available from this entity'>" + |
| 13 | "<choice><data type='nonNegativeInteger'/><value>Infinity</value></choice>" + |
| 14 | "</element>" + |
| 15 | "<element name='Type' a:help='Type of resources'>" + |
| 16 | "<choice>" + |
32 | | "</element>" + |
33 | | "<element name='MaxGatherers' a:help='Amount of gatherers who can gather resources from this entity at the same time'>" + |
34 | | "<data type='nonNegativeInteger'/>" + |
35 | | "</element>" + |
36 | | "<optional>" + |
37 | | "<element name='DiminishingReturns' a:help='The rate at which adding more gatherers decreases overall efficiency. Lower numbers = faster dropoff. Leave the element out for no diminishing returns.'>" + |
38 | | "<ref name='positiveDecimal'/>" + |
39 | | "</element>" + |
40 | | "</optional>"; |
41 | | |
42 | | ResourceSupply.prototype.Init = function() |
43 | | { |
44 | | // Current resource amount (non-negative) |
45 | | this.amount = this.GetMaxAmount(); |
46 | | this.gatherers = []; // list of IDs |
47 | | this.infinite = !isFinite(+this.template.Amount); |
48 | | }; |
49 | | |
50 | | ResourceSupply.prototype.IsInfinite = function() |
51 | | { |
52 | | return this.infinite; |
53 | | }; |
54 | | |
55 | | ResourceSupply.prototype.GetKillBeforeGather = function() |
56 | | { |
57 | | return (this.template.KillBeforeGather == "true"); |
| 32 | "</element>" + |
| 33 | "<optional>" + |
| 34 | "<element name='Regeneration' a:help='Controls whether this resource can regenerate its remaining amount.'>" + |
| 35 | "<interleave>" + |
| 36 | "<element name='Rate' a:help='Optional regeneration rate. Resources/second if the growth is linear or a constant controlling the rate of growth if the growth is sigmoid.'>" + |
| 37 | "<ref name='nonNegativeDecimal'/>" + |
| 38 | "</element>" + |
| 39 | "<optional>" + |
| 40 | "<element name='Acceleration' a:help='Controls the curve the regeneration rate will follow for sigmoid growth; does nothing for linear growth.'>" + |
| 41 | "<ref name='nonNegativeDecimal'/>" + |
| 42 | "</element>" + |
| 43 | "</optional>" + |
| 44 | "<element name='Delay' a:help='Seconds between when the number of gatherers hit 0 and the resource starts regenerating.'>" + |
| 45 | "<data type='nonNegativeInteger'/>" + |
| 46 | "</element>" + |
| 47 | "<element name='Growth' a:help='Growth formula for regeneration. Either linear or sigmoid. Linear continues at a steady rate, while sigmoid gets faster as more resources accumulate, then slows down as it approaches the maximum.'>" + |
| 48 | "<choice>" + |
| 49 | "<value>linear</value>" + |
| 50 | "<value>sigmoid</value>" + |
| 51 | "</choice>" + |
| 52 | "</element>" + |
| 53 | "</interleave>" + |
| 54 | "</element>" + |
| 55 | "</optional>" + |
| 56 | "<element name='MaxGatherers' a:help='Amount of gatherers who can gather resources from this entity at the same time'>" + |
| 57 | "<data type='nonNegativeInteger'/>" + |
| 58 | "</element>" + |
| 59 | "<optional>" + |
| 60 | "<element name='DiminishingReturns' a:help='The rate at which adding more gatherers decreases overall efficiency. Lower numbers = faster dropoff. Leave the element out for no diminishing returns.'>" + |
| 61 | "<ref name='positiveDecimal'/>" + |
| 62 | "</element>" + |
| 63 | "</optional>"; |
| 64 | |
| 65 | ResourceSupply.prototype.Init = function() |
| 66 | { |
| 67 | // Current resource amount (non-negative) |
| 68 | this.amount = this.GetMaxAmount(); |
| 69 | this.gatherers = []; // list of IDs |
| 70 | this.infinite = !isFinite(+this.template.Amount); |
| 71 | if (this.template.Regeneration) { |
| 72 | this.regenRate = +this.template.Regeneration.Rate; |
| 73 | if (this.template.Regeneration.Acceleration) |
| 74 | this.regenAccel = +this.template.Regeneration.Acceleration; |
| 75 | this.regenDelay = +this.template.Regeneration.Delay; |
| 76 | } |
| 77 | if (this.IsRegenerative()) |
| 78 | this.RegenerateResources(); |
77 | | return this.gatherers; |
78 | | }; |
79 | | |
80 | | ResourceSupply.prototype.GetDiminishingReturns = function() |
81 | | { |
82 | | if ("DiminishingReturns" in this.template) |
83 | | return ApplyTechModificationsToEntity("ResourceSupply/DiminishingReturns", +this.template.DiminishingReturns, this.entity); |
84 | | return null; |
85 | | }; |
86 | | |
87 | | ResourceSupply.prototype.TakeResources = function(rate) |
88 | | { |
89 | | if (this.infinite) |
90 | | return { "amount": rate, "exhausted": false }; |
91 | | |
92 | | // 'rate' should be a non-negative integer |
93 | | |
94 | | var old = this.amount; |
| 108 | return this.gatherers; |
| 109 | }; |
| 110 | |
| 111 | ResourceSupply.prototype.GetDiminishingReturns = function() |
| 112 | { |
| 113 | if ("DiminishingReturns" in this.template) |
| 114 | return ApplyTechModificationsToEntity("ResourceSupply/DiminishingReturns", +this.template.DiminishingReturns, this.entity); |
| 115 | return null; |
| 116 | }; |
| 117 | |
| 118 | ResourceSupply.prototype.TakeResources = function(rate) |
| 119 | { |
| 120 | if (this.infinite) |
| 121 | return { "amount": rate, "exhausted": false }; |
| 122 | |
| 123 | // 'rate' should be a non-negative integer |
| 124 | |
| 125 | var old = this.amount; |
| 138 | ResourceSupply.prototype.RegenerateResources = function(data, lateness) |
| 139 | { |
| 140 | var max = this.GetMaxAmount(); |
| 141 | if (this.gatherers.length == 0 && !this.regenDelayTimer && this.amount < max) |
| 142 | { |
| 143 | var old = this.amount; |
| 144 | if (this.regenGrowth == "linear") |
| 145 | this.amount = Math.min(max, this.amount + data.rate); |
| 146 | else |
| 147 | this.amount = Math.min(max, this.amount + Math.max(1, data.rate * max * (data.acceleration * this.amount / max -Math.pow(this.amount / max, 2)) / 100)); |
| 148 | Engine.PostMessage(this.entity, MT_ResourceSupplyChanged, { "from": old, "to": this.amount }); |
| 149 | } |
| 150 | var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); |
| 151 | var regenRate = this.GetRegenerationRate(); |
| 152 | var absRegen = Math.abs(regenRate); |
| 153 | if (Math.floor(regenRate) == regenRate || this.regenGrowth == "sigmoid") |
| 154 | cmpTimer.SetTimeout(this.entity, IID_ResourceSupply, "RegenerateResources", 1000, { "rate": regenRate, "acceleration": this.GetRegenerationAcceleration() }); |
| 155 | else |
| 156 | cmpTimer.SetTimeout(this.entity, IID_ResourceSupply, "RegenerateResources", 1000 / absRegen, |
| 157 | { "rate": absRegen == regenRate ? 1 : -1 }); |
| 158 | }; |
| 159 | |
| 160 | ResourceSupply.prototype.StartRegenerationDelayTimer = function() |
| 161 | { |
| 162 | if (!this.regenDelayTimer) { |
| 163 | var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); |
| 164 | this.regenDelayTimer = cmpTimer.SetTimeout(this.entity, IID_ResourceSupply, "CancelRegenerationDelayTimer", this.GetRegenerationDelay() * 1000, null); |
| 165 | } |
| 166 | }; |
| 167 | |
| 168 | ResourceSupply.prototype.CancelRegenerationDelayTimer = function() |
| 169 | { |
| 170 | var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); |
| 171 | cmpTimer.CancelTimer(this.regenDelayTimer); |
| 172 | this.regenDelayTimer = null; |
| 173 | }; |
| 174 | |
| 190 | ResourceSupply.prototype.IsRegenerative = function() |
| 191 | { |
| 192 | return this.GetRegenerationRate() != 0; |
| 193 | }; |
| 194 | |
| 195 | ResourceSupply.prototype.GetTerritoryOwner = function () |
| 196 | { |
| 197 | var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); |
| 198 | var cmpTerritoryManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryManager); |
| 199 | var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); |
| 200 | if (!(cmpPosition && cmpPosition.IsInWorld())) |
| 201 | return 0; // Something's wrong, just say we're in neutral territory. |
| 202 | var pos = cmpPosition.GetPosition2D(); |
| 203 | return cmpPlayerManager.GetPlayerByID(cmpTerritoryManager.GetOwner(pos.x, pos.y)); |
| 204 | }; |
| 205 | |
| 206 | ResourceSupply.prototype.GetRegenerationRate = function() |
| 207 | { |
| 208 | return ApplyTechModificationsToPlayer("ResourceSupply/Regeneration/Rate", this.regenRate, this.GetTerritoryOwner()); |
| 209 | }; |
| 210 | |
| 211 | ResourceSupply.prototype.GetRegenerationAcceleration = function() |
| 212 | { |
| 213 | return ApplyTechModificationsToPlayer("ResourceSupply/Regeneration/Acceleration", this.regenAccel, this.GetTerritoryOwner()); |
| 214 | }; |
| 215 | |
| 216 | ResourceSupply.prototype.GetRegenerationDelay = function() |
| 217 | { |
| 218 | return ApplyTechModificationsToPlayer("ResourcesSupply/Regeneration/Delay", this.regenDelay, this.GetTerritoryOwner()); |
| 219 | }; |
| 220 | |