Differential D270 Diff 12733 ps/trunk/binaries/data/mods/public/simulation/components/ProductionQueue.js
Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/binaries/data/mods/public/simulation/components/ProductionQueue.js
Show First 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | ProductionQueue.prototype.Init = function() | ||||
this.spawnNotified = false; | this.spawnNotified = false; | ||||
}; | }; | ||||
/* | /* | ||||
* Returns list of entities that can be trained by this building. | * Returns list of entities that can be trained by this building. | ||||
*/ | */ | ||||
ProductionQueue.prototype.GetEntitiesList = function() | ProductionQueue.prototype.GetEntitiesList = function() | ||||
{ | { | ||||
return this.entitiesList; | return Array.from(this.entitiesMap.values()); | ||||
}; | }; | ||||
ProductionQueue.prototype.CalculateEntitiesList = function() | /** | ||||
* Calculate the new list of producible entities | |||||
* and update any entities currently being produced. | |||||
*/ | |||||
ProductionQueue.prototype.CalculateEntitiesMap = function() | |||||
{ | { | ||||
this.entitiesList = []; | // Don't reset the map, it's used below to update entities. | ||||
if (!this.entitiesMap) | |||||
this.entitiesMap = new Map(); | |||||
if (!this.template.Entities) | if (!this.template.Entities) | ||||
return; | return; | ||||
let string = this.template.Entities._string; | let string = this.template.Entities._string; | ||||
if (!string) | // Tokens can be added -> process an empty list to get them. | ||||
let addedTokens = ApplyValueModificationsToEntity("ProductionQueue/Entities/_string", "", this.entity); | |||||
if (!addedTokens && !string) | |||||
return; | return; | ||||
// Replace the "{civ}" and "{native}" codes with the owner's civ ID and entity's civ ID. | addedTokens = addedTokens == "" ? [] : addedTokens.split(/\s+/); | ||||
let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); | let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); | ||||
let cmpPlayer = QueryOwnerInterface(this.entity); | let cmpPlayer = QueryOwnerInterface(this.entity); | ||||
if (!cmpPlayer) | |||||
return; | |||||
let cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity); | let cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity); | ||||
if (cmpIdentity) | |||||
string = string.replace(/\{native\}/g, cmpIdentity.GetCiv()); | |||||
let entitiesList = string.replace(/\{civ\}/g, cmpPlayer.GetCiv()).split(/\s+/); | let disabledEntities = cmpPlayer ? cmpPlayer.GetDisabledTemplates() : {}; | ||||
/** | |||||
* Process tokens: | |||||
* - process token modifiers (this is a bit tricky). | |||||
* - replace the "{civ}" and "{native}" codes with the owner's civ ID and entity's civ ID | |||||
* - remove disabled entities | |||||
* - upgrade templates where necessary | |||||
* This also updates currently queued production (it's more convenient to do it here). | |||||
*/ | |||||
let removeAllQueuedTemplate = (token) => { | |||||
let queue = clone(this.queue); | |||||
let template = this.entitiesMap.get(token); | |||||
for (let item of queue) | |||||
if (item.unitTemplate && item.unitTemplate === template) | |||||
this.RemoveBatch(item.id); | |||||
}; | |||||
let updateAllQueuedTemplate = (token, updateTo) => { | |||||
let template = this.entitiesMap.get(token); | |||||
for (let item of this.queue) | |||||
if (item.unitTemplate && item.unitTemplate === template) | |||||
item.unitTemplate = updateTo; | |||||
}; | |||||
let toks = string.split(/\s+/); | |||||
for (let tok of addedTokens) | |||||
toks.push(tok); | |||||
let addedDict = addedTokens.reduce((out, token) => { out[token] = true; return out; }, {}); | |||||
this.entitiesMap = toks.reduce((entMap, token) => { | |||||
let rawToken = token; | |||||
if (!(token in addedDict)) | |||||
{ | |||||
// This is a bit wasteful but I can't think of a simpler/better way. | |||||
// The list of token is unlikely to be a performance bottleneck anyways. | |||||
token = ApplyValueModificationsToEntity("ProductionQueue/Entities/_string", token, this.entity); | |||||
token = token.split(/\s+/); | |||||
if (token.every(tok => addedTokens.indexOf(tok) !== -1)) | |||||
{ | |||||
removeAllQueuedTemplate(rawToken); | |||||
return entMap; | |||||
} | |||||
token = token[0]; | |||||
} | |||||
// Replace the "{civ}" and "{native}" codes with the owner's civ ID and entity's civ ID. | |||||
if (cmpIdentity) | |||||
token = token.replace(/\{native\}/g, cmpIdentity.GetCiv()); | |||||
if (cmpPlayer) | |||||
token = token.replace(/\{civ\}/g, cmpPlayer.GetCiv()); | |||||
// Filter out disabled and invalid entities. | // Filter out disabled and invalid entities. | ||||
let disabledEntities = cmpPlayer.GetDisabledTemplates(); | if (disabledEntities[token] || !cmpTemplateManager.TemplateExists(token)) | ||||
entitiesList = entitiesList.filter(ent => !disabledEntities[ent] && cmpTemplateManager.TemplateExists(ent)); | { | ||||
removeAllQueuedTemplate(rawToken); | |||||
return entMap; | |||||
} | |||||
// Check if some templates need to show their advanced or elite version. | token = this.GetUpgradedTemplate(token); | ||||
let upgradeTemplate = function(templateName) | entMap.set(rawToken, token); | ||||
updateAllQueuedTemplate(rawToken, token); | |||||
return entMap; | |||||
}, new Map()); | |||||
}; | |||||
/* | |||||
* Returns the upgraded template name if necessary. | |||||
*/ | |||||
ProductionQueue.prototype.GetUpgradedTemplate = function(templateName) | |||||
{ | { | ||||
let cmpPlayer = QueryOwnerInterface(this.entity); | |||||
if (!cmpPlayer) | |||||
return templateName; | |||||
let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); | |||||
let template = cmpTemplateManager.GetTemplate(templateName); | let template = cmpTemplateManager.GetTemplate(templateName); | ||||
while (template && template.Promotion !== undefined) | while (template && template.Promotion !== undefined) | ||||
{ | { | ||||
let requiredXp = ApplyValueModificationsToTemplate( | let requiredXp = ApplyValueModificationsToTemplate( | ||||
"Promotion/RequiredXp", | "Promotion/RequiredXp", | ||||
+template.Promotion.RequiredXp, | +template.Promotion.RequiredXp, | ||||
cmpPlayer.GetPlayerID(), | cmpPlayer.GetPlayerID(), | ||||
template); | template); | ||||
if (requiredXp > 0) | if (requiredXp > 0) | ||||
break; | break; | ||||
templateName = template.Promotion.Entity; | templateName = template.Promotion.Entity; | ||||
template = cmpTemplateManager.GetTemplate(templateName); | template = cmpTemplateManager.GetTemplate(templateName); | ||||
} | } | ||||
return templateName; | return templateName; | ||||
}; | }; | ||||
for (let templateName of entitiesList) | |||||
this.entitiesList.push(upgradeTemplate(templateName)); | |||||
for (let item of this.queue) | |||||
if (item.unitTemplate) | |||||
item.unitTemplate = upgradeTemplate(item.unitTemplate); | |||||
}; | |||||
/* | /* | ||||
* Returns list of technologies that can be researched by this building. | * Returns list of technologies that can be researched by this building. | ||||
*/ | */ | ||||
ProductionQueue.prototype.GetTechnologiesList = function() | ProductionQueue.prototype.GetTechnologiesList = function() | ||||
{ | { | ||||
if (!this.template.Technologies) | if (!this.template.Technologies) | ||||
return []; | return []; | ||||
let string = this.template.Technologies._string; | let string = this.template.Technologies._string; | ||||
string = ApplyValueModificationsToEntity("ProductionQueue/Technologies/_string", string, this.entity); | |||||
if (!string) | if (!string) | ||||
return []; | return []; | ||||
let cmpTechnologyManager = QueryOwnerInterface(this.entity, IID_TechnologyManager); | let cmpTechnologyManager = QueryOwnerInterface(this.entity, IID_TechnologyManager); | ||||
if (!cmpTechnologyManager) | if (!cmpTechnologyManager) | ||||
return []; | return []; | ||||
let cmpPlayer = QueryOwnerInterface(this.entity); | let cmpPlayer = QueryOwnerInterface(this.entity); | ||||
let cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity); | if (!cmpPlayer) | ||||
if (!cmpPlayer || !cmpIdentity) | |||||
return []; | return []; | ||||
let techs = string.split(/\s+/); | let techs = string.split(/\s+/); | ||||
// Replace the civ specific technologies. | // Replace the civ specific technologies. | ||||
for (let i = 0; i < techs.length; ++i) | for (let i = 0; i < techs.length; ++i) | ||||
{ | { | ||||
let tech = techs[i]; | let tech = techs[i]; | ||||
▲ Show 20 Lines • Show All 392 Lines • ▼ Show 20 Lines | ProductionQueue.prototype.OnOwnershipChanged = function(msg) | ||||
if (msg.from != INVALID_PLAYER) | if (msg.from != INVALID_PLAYER) | ||||
{ | { | ||||
// Unset flag that previous owner's training may be blocked. | // Unset flag that previous owner's training may be blocked. | ||||
let cmpPlayer = QueryPlayerIDInterface(msg.from); | let cmpPlayer = QueryPlayerIDInterface(msg.from); | ||||
if (cmpPlayer && this.queue.length) | if (cmpPlayer && this.queue.length) | ||||
cmpPlayer.UnBlockTraining(); | cmpPlayer.UnBlockTraining(); | ||||
} | } | ||||
if (msg.to != INVALID_PLAYER) | if (msg.to != INVALID_PLAYER) | ||||
this.CalculateEntitiesList(); | this.CalculateEntitiesMap(); | ||||
// Reset the production queue whenever the owner changes. | // Reset the production queue whenever the owner changes. | ||||
// (This should prevent players getting surprised when they capture | // (This should prevent players getting surprised when they capture | ||||
// an enemy building, and then loads of the enemy's civ's soldiers get | // an enemy building, and then loads of the enemy's civ's soldiers get | ||||
// created from it. Also it means we don't have to worry about | // created from it. Also it means we don't have to worry about | ||||
// updating the reserved pop slots.) | // updating the reserved pop slots.) | ||||
this.ResetQueue(); | this.ResetQueue(); | ||||
}; | }; | ||||
ProductionQueue.prototype.OnCivChanged = function() | ProductionQueue.prototype.OnCivChanged = function() | ||||
{ | { | ||||
this.CalculateEntitiesList(); | this.CalculateEntitiesMap(); | ||||
}; | }; | ||||
ProductionQueue.prototype.OnDestroy = function() | ProductionQueue.prototype.OnDestroy = function() | ||||
{ | { | ||||
// Reset the queue to refund any resources. | // Reset the queue to refund any resources. | ||||
this.ResetQueue(); | this.ResetQueue(); | ||||
if (this.timer) | if (this.timer) | ||||
▲ Show 20 Lines • Show All 279 Lines • ▼ Show 20 Lines | ProductionQueue.prototype.UnpauseProduction = function() | ||||
this.timer = cmpTimer.SetTimeout(this.entity, IID_ProductionQueue, "ProgressTimeout", this.ProgressInterval, {}); | this.timer = cmpTimer.SetTimeout(this.entity, IID_ProductionQueue, "ProgressTimeout", this.ProgressInterval, {}); | ||||
}; | }; | ||||
ProductionQueue.prototype.OnValueModification = function(msg) | ProductionQueue.prototype.OnValueModification = function(msg) | ||||
{ | { | ||||
// If the promotion requirements of units is changed, | // If the promotion requirements of units is changed, | ||||
// update the entities list so that automatically promoted units are shown | // update the entities list so that automatically promoted units are shown | ||||
// appropriately in the list. | // appropriately in the list. | ||||
if (msg.component == "Promotion") | if (msg.component != "Promotion" && (msg.component != "ProductionQueue" || | ||||
this.CalculateEntitiesList(); | !msg.valueNames.some(val => val.startsWith("ProductionQueue/Entities/")))) | ||||
return; | |||||
if (msg.entities.indexOf(this.entity) === -1) | |||||
return; | |||||
// This also updates the queued production if necessary. | |||||
this.CalculateEntitiesMap(); | |||||
// Inform the GUI that it'll need to recompute the selection panel. | |||||
// TODO: it would be better to only send the message if something actually changing | |||||
// for the current production queue. | |||||
let cmpPlayer = QueryOwnerInterface(this.entity); | |||||
if (cmpPlayer) | |||||
Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface).SetSelectionDirty(cmpPlayer.GetPlayerID()); | |||||
}; | }; | ||||
ProductionQueue.prototype.OnDisabledTemplatesChanged = function(msg) | ProductionQueue.prototype.OnDisabledTemplatesChanged = function(msg) | ||||
{ | { | ||||
// If the disabled templates of the player is changed, | // If the disabled templates of the player is changed, | ||||
// update the entities list so that this is reflected there. | // update the entities list so that this is reflected there. | ||||
this.CalculateEntitiesList(); | this.CalculateEntitiesMap(); | ||||
}; | }; | ||||
Engine.RegisterComponentType(IID_ProductionQueue, "ProductionQueue", ProductionQueue); | Engine.RegisterComponentType(IID_ProductionQueue, "ProductionQueue", ProductionQueue); |
Wildfire Games · Phabricator