Changeset View
Changeset View
Standalone View
Standalone View
binaries/data/mods/public/simulation/components/TechnologyManager.js
function TechnologyManager() {} | function TechnologyManager() {} | ||||
TechnologyManager.prototype.Schema = | TechnologyManager.prototype.Schema = | ||||
"<empty/>"; | "<empty/>"; | ||||
TechnologyManager.prototype.Serialize = function() | |||||
{ | |||||
// The modifications cache will be affected by property reads from the GUI and other places so we shouldn't | |||||
// serialize it. | |||||
var ret = {}; | |||||
for (var i in this) | |||||
{ | |||||
if (this.hasOwnProperty(i)) | |||||
ret[i] = this[i]; | |||||
} | |||||
ret.modificationCache = {}; | |||||
return ret; | |||||
}; | |||||
TechnologyManager.prototype.Init = function() | TechnologyManager.prototype.Init = function() | ||||
{ | { | ||||
// Holds names of technologies that have been researched. | // Holds names of technologies that have been researched. | ||||
this.researchedTechs = new Set(); | this.researchedTechs = new Set(); | ||||
// Maps from technolgy name to the entityID of the researcher. | // Maps from technolgy name to the entityID of the researcher. | ||||
this.researchQueued = new Map(); | this.researchQueued = new Map(); | ||||
// Holds technologies which are being researched currently (non-queued). | // Holds technologies which are being researched currently (non-queued). | ||||
this.researchStarted = new Set(); | this.researchStarted = new Set(); | ||||
// This stores the modifications to unit stats from researched technologies | |||||
// Example data: {"ResourceGatherer/Rates/food.grain": [ | |||||
// {"multiply": 1.15, "affects": ["FemaleCitizen", "Infantry Sword"]}, | |||||
// {"add": 2} | |||||
// ]} | |||||
this.modifications = {}; | |||||
this.modificationCache = {}; // Caches the values after technologies have been applied | |||||
// e.g. { "Attack/Melee/Damage/Hack" : {5: {"origValue": 8, "newValue": 10}, 7: {"origValue": 9, "newValue": 12}, ...}, ...} | |||||
// where 5 and 7 are entity id's | |||||
this.classCounts = {}; // stores the number of entities of each Class | this.classCounts = {}; // stores the number of entities of each Class | ||||
this.typeCountsByClass = {}; // stores the number of entities of each type for each class i.e. | this.typeCountsByClass = {}; // stores the number of entities of each type for each class i.e. | ||||
// {"someClass": {"unit/spearman": 2, "unit/cav": 5} "someOtherClass":...} | // {"someClass": {"unit/spearman": 2, "unit/cav": 5} "someOtherClass":...} | ||||
// Some technologies are automatically researched when their conditions are met. They have no cost and are | // Some technologies are automatically researched when their conditions are met. They have no cost and are | ||||
// researched instantly. This allows civ bonuses and more complicated technologies. | // researched instantly. This allows civ bonuses and more complicated technologies. | ||||
this.unresearchedAutoResearchTechs = new Set(); | this.unresearchedAutoResearchTechs = new Set(); | ||||
let allTechs = TechnologyTemplates.GetAll(); | let allTechs = TechnologyTemplates.GetAll(); | ||||
▲ Show 20 Lines • Show All 149 Lines • ▼ Show 20 Lines | if (!Engine.QueryInterface(msg.entity, IID_Foundation)) | ||||
this.classCounts[cls] = this.classCounts[cls] || 0; | this.classCounts[cls] = this.classCounts[cls] || 0; | ||||
this.classCounts[cls] += 1; | this.classCounts[cls] += 1; | ||||
this.typeCountsByClass[cls] = this.typeCountsByClass[cls] || {}; | this.typeCountsByClass[cls] = this.typeCountsByClass[cls] || {}; | ||||
this.typeCountsByClass[cls][template] = this.typeCountsByClass[cls][template] || 0; | this.typeCountsByClass[cls][template] = this.typeCountsByClass[cls][template] || 0; | ||||
this.typeCountsByClass[cls][template] += 1; | this.typeCountsByClass[cls][template] += 1; | ||||
} | } | ||||
} | } | ||||
// Newly created entity, check if any researched techs might apply | |||||
// (only do this for new entities because even if an entity is converted or captured, | |||||
// we want it to maintain whatever technologies previously applied) | |||||
wraitii: BTW is that still the behaviour we want? I believe it means units will get new technologies… | |||||
Not Done Inline ActionsGiven that we don't have conversion that doesn't apply to most things. It does apply to siege weapons though. Also I suspect this is at least partially inaccurate since quite a few OwnershipChanged handlers will run and things will be recalculated. That said changing behaviour is not something this diff should even attempt to do. leper: Given that we don't have conversion that doesn't apply to most things. It does apply to siege… | |||||
Done Inline ActionsI'm not sure this is correct in svn but regardless I believe converted units change their technologies with the new code, which may or may not be fixed. wraitii: I'm not sure this is correct in svn but regardless I believe converted units change their… | |||||
if (msg.from == INVALID_PLAYER) | |||||
{ | |||||
var modifiedComponents = {}; | |||||
for (var name in this.modifications) | |||||
{ | |||||
// We only need to find one one tech per component for a match | |||||
var modifications = this.modifications[name]; | |||||
var component = name.split("/")[0]; | |||||
for (let modif of modifications) | |||||
if (DoesModificationApply(modif, classes)) | |||||
{ | |||||
if (!modifiedComponents[component]) | |||||
modifiedComponents[component] = []; | |||||
modifiedComponents[component].push(name); | |||||
} | |||||
} | |||||
// Send mesage(s) to the entity so it knows about researched techs | |||||
for (var component in modifiedComponents) | |||||
Engine.PostMessage(msg.entity, MT_ValueModification, { "entities": [msg.entity], "component": component, "valueNames": modifiedComponents[component] }); | |||||
} | |||||
} | } | ||||
if (msg.from == playerID) | if (msg.from == playerID) | ||||
{ | { | ||||
var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); | var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); | ||||
var template = cmpTemplateManager.GetCurrentTemplateName(msg.entity); | var template = cmpTemplateManager.GetCurrentTemplateName(msg.entity); | ||||
// don't use foundations for the class counts | // don't use foundations for the class counts | ||||
if (!Engine.QueryInterface(msg.entity, IID_Foundation)) | if (!Engine.QueryInterface(msg.entity, IID_Foundation)) | ||||
Show All 9 Lines | if (!Engine.QueryInterface(msg.entity, IID_Foundation)) | ||||
delete this.classCounts[cls]; | delete this.classCounts[cls]; | ||||
this.typeCountsByClass[cls][template] -= 1; | this.typeCountsByClass[cls][template] -= 1; | ||||
if (this.typeCountsByClass[cls][template] <= 0) | if (this.typeCountsByClass[cls][template] <= 0) | ||||
delete this.typeCountsByClass[cls][template]; | delete this.typeCountsByClass[cls][template]; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
this.clearModificationCache(msg.entity); | |||||
} | } | ||||
}; | }; | ||||
// Marks a technology as researched. Note that this does not verify that the requirements are met. | // Marks a technology as researched. Note that this does not verify that the requirements are met. | ||||
TechnologyManager.prototype.ResearchTechnology = function(tech) | TechnologyManager.prototype.ResearchTechnology = function(tech) | ||||
{ | { | ||||
this.StoppedResearch(tech, false); | this.StoppedResearch(tech, false); | ||||
var modifiedComponents = {}; | var modifiedComponents = {}; | ||||
this.researchedTechs.add(tech); | this.researchedTechs.add(tech); | ||||
// store the modifications in an easy to access structure | // store the modifications in an easy to access structure | ||||
let template = TechnologyTemplates.Get(tech); | let template = TechnologyTemplates.Get(tech); | ||||
if (template.modifications) | if (template.modifications) | ||||
{ | { | ||||
let cmpModificationsManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ModificationsManager); | |||||
let derivedModifiers = DeriveModificationsFromTech(template); | let derivedModifiers = DeriveModificationsFromTech(template); | ||||
for (let modifierPath in derivedModifiers) | for (let modifierPath in derivedModifiers) | ||||
{ | for (let modifier of derivedModifiers[modifierPath]) | ||||
if (!this.modifications[modifierPath]) | cmpModificationsManager.AddModif(modifierPath, "tech/" + tech, modifier, this.entity); | ||||
Not Done Inline ActionsMissing spaces with the operator, can be fixed when committing. Stan: Missing spaces with the operator, can be fixed when committing. | |||||
this.modifications[modifierPath] = []; | |||||
this.modifications[modifierPath] = this.modifications[modifierPath].concat(derivedModifiers[modifierPath]); | |||||
let component = modifierPath.split("/")[0]; | |||||
if (!modifiedComponents[component]) | |||||
modifiedComponents[component] = []; | |||||
modifiedComponents[component].push(modifierPath); | |||||
this.modificationCache[modifierPath] = {}; | |||||
} | |||||
} | } | ||||
if (template.replaces && template.replaces.length > 0) | if (template.replaces && template.replaces.length > 0) | ||||
{ | { | ||||
for (var i of template.replaces) | for (var i of template.replaces) | ||||
{ | { | ||||
if (!i || this.IsTechnologyResearched(i)) | if (!i || this.IsTechnologyResearched(i)) | ||||
continue; | continue; | ||||
Show All 24 Lines | TechnologyManager.prototype.ResearchTechnology = function(tech) | ||||
// Change the EntityLimit if any | // Change the EntityLimit if any | ||||
var cmpPlayerEntityLimits = QueryPlayerIDInterface(playerID, IID_EntityLimits); | var cmpPlayerEntityLimits = QueryPlayerIDInterface(playerID, IID_EntityLimits); | ||||
if (cmpPlayerEntityLimits) | if (cmpPlayerEntityLimits) | ||||
cmpPlayerEntityLimits.UpdateLimitsFromTech(tech); | cmpPlayerEntityLimits.UpdateLimitsFromTech(tech); | ||||
// always send research finished message | // always send research finished message | ||||
Engine.PostMessage(this.entity, MT_ResearchFinished, {"player": playerID, "tech": tech}); | Engine.PostMessage(this.entity, MT_ResearchFinished, {"player": playerID, "tech": tech}); | ||||
for (var component in modifiedComponents) | |||||
{ | |||||
Engine.PostMessage(SYSTEM_ENTITY, MT_TemplateModification, { "player": playerID, "component": component, "valueNames": modifiedComponents[component]}); | |||||
Engine.BroadcastMessage(MT_ValueModification, { "entities": ents, "component": component, "valueNames": modifiedComponents[component]}); | |||||
} | |||||
if (tech.startsWith("phase") && !template.autoResearch) | |||||
{ | |||||
let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); | |||||
cmpGUIInterface.PushNotification({ | |||||
"type": "phase", | |||||
"players": [playerID], | |||||
"phaseName": tech, | |||||
"phaseState": "completed" | |||||
}); | |||||
} | |||||
}; | |||||
// Clears the cached data for an entity from the modifications cache | |||||
TechnologyManager.prototype.clearModificationCache = function(ent) | |||||
{ | |||||
for (var valueName in this.modificationCache) | |||||
delete this.modificationCache[valueName][ent]; | |||||
}; | |||||
// Caching layer in front of ApplyModificationsWorker | |||||
// Note: be careful with the type of curValue, if it should be a numerical | |||||
// value and is derived from template data, you must convert the string | |||||
// from the template to a number using the + operator, before calling | |||||
// this function! | |||||
TechnologyManager.prototype.ApplyModifications = function(valueName, curValue, ent) | |||||
{ | |||||
if (!this.modificationCache[valueName]) | |||||
this.modificationCache[valueName] = {}; | |||||
if (!this.modificationCache[valueName][ent] || this.modificationCache[valueName][ent].origValue != curValue) | |||||
{ | |||||
let cmpIdentity = Engine.QueryInterface(ent, IID_Identity); | |||||
if (!cmpIdentity) | |||||
return curValue; | |||||
this.modificationCache[valueName][ent] = { | |||||
"origValue": curValue, | |||||
"newValue": GetTechModifiedProperty(this.modifications, cmpIdentity.GetClassesList(), valueName, curValue) | |||||
}; | |||||
} | |||||
return this.modificationCache[valueName][ent].newValue; | |||||
}; | |||||
// Alternative version of ApplyModifications, applies to templates instead of entities | |||||
TechnologyManager.prototype.ApplyModificationsTemplate = function(valueName, curValue, template) | |||||
{ | |||||
if (!template || !template.Identity) | |||||
return curValue; | |||||
return GetTechModifiedProperty(this.modifications, GetIdentityClasses(template.Identity), valueName, curValue); | |||||
}; | }; | ||||
/** | /** | ||||
* Marks a technology as being queued for research at the given entityID. | * Marks a technology as being queued for research at the given entityID. | ||||
*/ | */ | ||||
TechnologyManager.prototype.QueuedResearch = function(tech, researcher) | TechnologyManager.prototype.QueuedResearch = function(tech, researcher) | ||||
{ | { | ||||
this.researchQueued.set(tech, researcher); | this.researchQueued.set(tech, researcher); | ||||
▲ Show 20 Lines • Show All 92 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator
BTW is that still the behaviour we want? I believe it means units will get new technologies once they've been captured, but will have their old one on top. So potentially by switching back and forth you could have OP units, but haven't actually tried.