Changeset View
Changeset View
Standalone View
Standalone View
binaries/data/mods/public/simulation/components/ResourceGatherer.js
Show All 24 Lines | "<element name='BaseSpeed' a:help='Base resource-gathering rate (in resource units per second)'>" + | ||||||||
"<ref name='positiveDecimal'/>" + | "<ref name='positiveDecimal'/>" + | ||||||||
"</element>" + | "</element>" + | ||||||||
"<element name='Rates' a:help='Per-resource-type gather rate multipliers. If a resource type is not specified then it cannot be gathered by this unit'>" + | "<element name='Rates' a:help='Per-resource-type gather rate multipliers. If a resource type is not specified then it cannot be gathered by this unit'>" + | ||||||||
Resources.BuildSchema("positiveDecimal", ["treasure"], true) + | Resources.BuildSchema("positiveDecimal", ["treasure"], true) + | ||||||||
"</element>" + | "</element>" + | ||||||||
"<element name='Capacities' a:help='Per-resource-type maximum carrying capacity'>" + | "<element name='Capacities' a:help='Per-resource-type maximum carrying capacity'>" + | ||||||||
Resources.BuildSchema("positiveDecimal") + | Resources.BuildSchema("positiveDecimal") + | ||||||||
"</element>"; | "</element>"; | ||||||||
FreagarachAuthorUnsubmitted Done Inline Actions
Freagarach: | |||||||||
ResourceGatherer.prototype.Init = function() | ResourceGatherer.prototype.Init = function() | ||||||||
{ | { | ||||||||
this.carrying = {}; // { generic type: integer amount currently carried } | this.carrying = {}; // { generic type: integer amount currently carried } | ||||||||
// (Note that this component supports carrying multiple types of resources, | // (Note that this component supports carrying multiple types of resources, | ||||||||
// each with an independent capacity, but the rest of the game currently | // each with an independent capacity, but the rest of the game currently | ||||||||
// ensures and assumes we'll only be carrying one type at once) | // ensures and assumes we'll only be carrying one type at once) | ||||||||
// The last exact type gathered, so we can render appropriate props | // The last exact type gathered, so we can render appropriate props | ||||||||
this.lastCarriedType = undefined; // { generic, specific } | this.lastCarriedType = undefined; // { generic, specific } | ||||||||
this.target = INVALID_ENTITY; | |||||||||
}; | }; | ||||||||
/** | /** | ||||||||
* Returns data about what resources the unit is currently carrying, | * Returns data about what resources the unit is currently carrying, | ||||||||
* in the form [ {"type":"wood", "amount":7, "max":10} ] | * in the form [ {"type":"wood", "amount":7, "max":10} ] | ||||||||
*/ | */ | ||||||||
ResourceGatherer.prototype.GetCarryingStatus = function() | ResourceGatherer.prototype.GetCarryingStatus = function() | ||||||||
{ | { | ||||||||
▲ Show 20 Lines • Show All 116 Lines • ▼ Show 20 Lines | if (type.generic != "treasure") | ||||||||
return false; | return false; | ||||||||
let status = cmpResourceSupply.TakeResources(cmpResourceSupply.GetCurrentAmount()); | let status = cmpResourceSupply.TakeResources(cmpResourceSupply.GetCurrentAmount()); | ||||||||
let cmpPlayer = QueryOwnerInterface(this.entity, IID_Player); | let cmpPlayer = QueryOwnerInterface(this.entity, IID_Player); | ||||||||
if (cmpPlayer) | if (cmpPlayer) | ||||||||
cmpPlayer.AddResource(type.specific, status.amount); | cmpPlayer.AddResource(type.specific, status.amount); | ||||||||
let cmpStatisticsTracker = QueryOwnerInterface(this.entity, IID_StatisticsTracker); | let cmpStatisticsTracker = QueryOwnerInterface(this.entity, IID_StatisticsTracker); | ||||||||
Done Inline ActionsYou don't need this I think, since it's already checked in the only place it's called from. Stan: You don't need this I think, since it's already checked in the only place it's called from. | |||||||||
Done Inline ActionsI added this here as a safeguard to modders. Freagarach: I added this here as a safeguard to modders. | |||||||||
if (cmpStatisticsTracker) | if (cmpStatisticsTracker) | ||||||||
cmpStatisticsTracker.IncreaseTreasuresCollectedCounter(); | cmpStatisticsTracker.IncreaseTreasuresCollectedCounter(); | ||||||||
let cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); | let cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); | ||||||||
if (cmpTrigger && cmpPlayer) | if (cmpTrigger && cmpPlayer) | ||||||||
cmpTrigger.CallEvent("TreasureCollected", { "player": cmpPlayer.GetPlayerID(), "type": type.specific, "amount": status.amount }); | cmpTrigger.CallEvent("TreasureCollected", { "player": cmpPlayer.GetPlayerID(), "type": type.specific, "amount": status.amount }); | ||||||||
return true; | return true; | ||||||||
}; | }; | ||||||||
/** | /** | ||||||||
* Starts gathering on the specified target. | |||||||||
* @param {number} target - The target to gather from. | |||||||||
* @return {number} - The gathering rate. | |||||||||
*/ | |||||||||
ResourceGatherer.prototype.StartGathering = function(target) | |||||||||
{ | |||||||||
// We were already gathering! | |||||||||
if (this.target != INVALID_ENTITY) | |||||||||
this.StopGathering(); | |||||||||
let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); | |||||||||
if (!cmpOwnership) | |||||||||
return 0; | |||||||||
// Check if the resource is full. | |||||||||
// We'll only be added if we're not already in. | |||||||||
let cmpResourceSupply = Engine.QueryInterface(target, IID_ResourceSupply); | |||||||||
if (!cmpResourceSupply || !cmpResourceSupply.AddGatherer(cmpOwnership.GetOwner(), this.entity)) | |||||||||
return 0; | |||||||||
let rate = this.GetTargetGatherRate(target); | |||||||||
if (!rate) | |||||||||
return 0; | |||||||||
// Try to gather a treasure. | |||||||||
if (this.TryInstantGather(target)) | |||||||||
return 0; | |||||||||
// Calculate timing based on gather rates. | |||||||||
// This allows the gather rate to control how often we gather, instead of how much. | |||||||||
let timing = 1000 / rate; | |||||||||
this.target = target; | |||||||||
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); | |||||||||
this.gatherTimer = cmpTimer.SetInterval(this.entity, IID_ResourceGatherer, "PerformGather", timing, timing, null); | |||||||||
return rate; | |||||||||
}; | |||||||||
/** | |||||||||
* Stop gathering. | |||||||||
* @param {boolean} exhausted - Whether the target was exhausted when we stopped. | |||||||||
* @param {boolean} filled - Whether we were filled when we stopped. | |||||||||
*/ | |||||||||
ResourceGatherer.prototype.StopGathering = function(exhausted, filled) | |||||||||
{ | |||||||||
if (this.gatherTimer) | |||||||||
{ | |||||||||
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); | |||||||||
cmpTimer.CancelTimer(this.gatherTimer); | |||||||||
delete this.gatherTimer; | |||||||||
} | |||||||||
if (this.target != INVALID_ENTITY) | |||||||||
{ | |||||||||
let cmpResourceSupply = Engine.QueryInterface(this.target, IID_ResourceSupply); | |||||||||
if (cmpResourceSupply) | |||||||||
cmpResourceSupply.RemoveGatherer(this.entity); | |||||||||
this.target = INVALID_ENTITY; | |||||||||
} | |||||||||
Engine.PostMessage(this.entity, MT_GatheringStateChanged, { | |||||||||
"exhausted": exhausted, | |||||||||
"filled": filled | |||||||||
}); | |||||||||
}; | |||||||||
/** | |||||||||
* Gather from the target entity. This should only be called after a successful range check, | * Gather from the target entity. This should only be called after a successful range check, | ||||||||
* and if the target has a compatible ResourceSupply. | * and if the target has a compatible ResourceSupply. | ||||||||
* Call interval will be determined by gather rate, so always gather 1 amount when called. | * Call interval will be determined by gather rate, so always gather 1 amount when called. | ||||||||
*/ | */ | ||||||||
ResourceGatherer.prototype.PerformGather = function(target) | ResourceGatherer.prototype.PerformGather = function() | ||||||||
{ | |||||||||
if (this.target == INVALID_ENTITY || !this.GetTargetGatherRate(this.target)) | |||||||||
{ | { | ||||||||
if (!this.GetTargetGatherRate(target)) | this.StopGathering(true); | ||||||||
return { "exhausted": true }; | return; | ||||||||
} | |||||||||
let gatherAmount = 1; | let cmpResourceSupply = Engine.QueryInterface(this.target, IID_ResourceSupply); | ||||||||
if (!cmpResourceSupply) | |||||||||
{ | |||||||||
this.StopGathering(true); | |||||||||
return; | |||||||||
} | |||||||||
let cmpResourceSupply = Engine.QueryInterface(target, IID_ResourceSupply); | let gatherAmount = 1; | ||||||||
let type = cmpResourceSupply.GetType(); | let type = cmpResourceSupply.GetType(); | ||||||||
// Initialise the carried count if necessary | // If we've already got some resources but they're the wrong type, | ||||||||
// drop them first to ensure we're only ever carrying one type. | |||||||||
if (this.IsCarryingAnythingExcept(type.generic)) | |||||||||
this.DropResources(); | |||||||||
// Initialise the carried count if necessary. | |||||||||
if (!this.carrying[type.generic]) | if (!this.carrying[type.generic]) | ||||||||
this.carrying[type.generic] = 0; | this.carrying[type.generic] = 0; | ||||||||
// Find the maximum so we won't exceed our capacity | // Find the maximum so we won't exceed our capacity. | ||||||||
Done Inline ActionsAdd the (not used) data and lateness parameters? Freagarach: Add the (not used) `data` and `lateness` parameters? | |||||||||
let maxGathered = this.GetCapacity(type.generic) - this.carrying[type.generic]; | let maxGathered = this.GetCapacity(type.generic) - this.carrying[type.generic]; | ||||||||
let status = cmpResourceSupply.TakeResources(Math.min(gatherAmount, maxGathered)); | let status = cmpResourceSupply.TakeResources(Math.min(gatherAmount, maxGathered)); | ||||||||
this.carrying[type.generic] += status.amount; | this.carrying[type.generic] += status.amount; | ||||||||
this.lastCarriedType = type; | this.lastCarriedType = type; | ||||||||
Done Inline ActionsOnly a subset of this function is needed. Freagarach: Only a subset of this function is needed. | |||||||||
// Update stats of how much the player collected. | // Update stats of how much the player collected. | ||||||||
// (We have to do it here rather than at the dropsite, because we | // (We have to do it here rather than at the dropsite, because we | ||||||||
// need to know what subtype it was) | // need to know what subtype it was.) | ||||||||
let cmpStatisticsTracker = QueryOwnerInterface(this.entity, IID_StatisticsTracker); | let cmpStatisticsTracker = QueryOwnerInterface(this.entity, IID_StatisticsTracker); | ||||||||
if (cmpStatisticsTracker) | if (cmpStatisticsTracker) | ||||||||
cmpStatisticsTracker.IncreaseResourceGatheredCounter(type.generic, status.amount, type.specific); | cmpStatisticsTracker.IncreaseResourceGatheredCounter(type.generic, status.amount, type.specific); | ||||||||
Engine.PostMessage(this.entity, MT_ResourceCarryingChanged, { "to": this.GetCarryingStatus() }); | Engine.PostMessage(this.entity, MT_ResourceCarryingChanged, { "to": this.GetCarryingStatus() }); | ||||||||
let filled = !this.CanCarryMore(type.generic); | |||||||||
return { | if (status.exhausted || filled) | ||||||||
Done Inline ActionsYou check it twice. Stan: You check it twice. | |||||||||
"amount": status.amount, | this.StopGathering(status.exhausted, filled); | ||||||||
"exhausted": status.exhausted, | |||||||||
"filled": this.carrying[type.generic] >= this.GetCapacity(type.generic) | |||||||||
}; | |||||||||
}; | }; | ||||||||
/** | /** | ||||||||
* Compute the amount of resources collected per second from the target. | * Compute the amount of resources collected per second from the target. | ||||||||
* Returns 0 if resources cannot be collected (e.g. the target doesn't | * Returns 0 if resources cannot be collected (e.g. the target doesn't | ||||||||
* exist, or is the wrong type). | * exist, or is the wrong type). | ||||||||
*/ | */ | ||||||||
ResourceGatherer.prototype.GetTargetGatherRate = function(target) | ResourceGatherer.prototype.GetTargetGatherRate = function(target) | ||||||||
{ | { | ||||||||
let cmpResourceSupply = QueryMiragedInterface(target, IID_ResourceSupply); | let cmpResourceSupply = QueryMiragedInterface(target, IID_ResourceSupply); | ||||||||
if (!cmpResourceSupply) | if (!cmpResourceSupply || cmpResourceSupply.GetCurrentAmount() <= 0) | ||||||||
return 0; | return 0; | ||||||||
let type = cmpResourceSupply.GetType(); | let type = cmpResourceSupply.GetType(); | ||||||||
let rate = 0; | let rate = 0; | ||||||||
if (type.specific) | if (type.specific) | ||||||||
rate = this.GetGatherRate(type.generic+"."+type.specific); | rate = this.GetGatherRate(type.generic + "." + type.specific); | ||||||||
if (rate == 0 && type.generic) | if (rate == 0 && type.generic) | ||||||||
rate = this.GetGatherRate(type.generic); | rate = this.GetGatherRate(type.generic); | ||||||||
if ("Mirages" in cmpResourceSupply) | if ("Mirages" in cmpResourceSupply) | ||||||||
return rate; | return rate; | ||||||||
// Apply diminishing returns with more gatherers, for e.g. infinite farms. For most resources this has no effect | // Apply diminishing returns with more gatherers, for e.g. infinite farms. For most resources this has no effect | ||||||||
// (GetDiminishingReturns will return null). We can assume that for resources that are miraged this is the case | // (GetDiminishingReturns will return null). We can assume that for resources that are miraged this is the case | ||||||||
// (else just add the diminishing returns data to the mirage data and remove the early return above) | // (else just add the diminishing returns data to the mirage data and remove the early return above). | ||||||||
let diminishingReturns = cmpResourceSupply.GetDiminishingReturns(); | let diminishingReturns = cmpResourceSupply.GetDiminishingReturns(); | ||||||||
if (diminishingReturns) | if (diminishingReturns) | ||||||||
rate *= diminishingReturns; | rate *= diminishingReturns; | ||||||||
return rate; | return rate; | ||||||||
}; | }; | ||||||||
/** | /** | ||||||||
▲ Show 20 Lines • Show All 92 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator