mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-17 22:03:56 -07:00
Handle researching technologies in the TechnologyManager.
Moves the work done from cmpResearcher to cmpTechnologyManager. No functional changes. It allows fancy stuff in the future (#6364). Differential revision: https://code.wildfiregames.com/D4438 This was SVN commit r26252.
This commit is contained in:
parent
27f64b80ed
commit
73f741d266
11 changed files with 529 additions and 290 deletions
|
|
@ -212,11 +212,9 @@ m.GameState.prototype.isResearched = function(template)
|
|||
return this.playerData.researchedTechs.has(template);
|
||||
};
|
||||
|
||||
/** true if started or queued */
|
||||
m.GameState.prototype.isResearching = function(template)
|
||||
{
|
||||
return this.playerData.researchStarted.has(template) ||
|
||||
this.playerData.researchQueued.has(template);
|
||||
return this.playerData.researchQueued.has(template);
|
||||
};
|
||||
|
||||
/** this is an "in-absolute" check that doesn't check if we have a building to research from. */
|
||||
|
|
@ -229,9 +227,7 @@ m.GameState.prototype.canResearch = function(techTemplateName, noRequirementChec
|
|||
if (!template)
|
||||
return false;
|
||||
|
||||
// researching or already researched: NOO.
|
||||
if (this.playerData.researchQueued.has(techTemplateName) ||
|
||||
this.playerData.researchStarted.has(techTemplateName) ||
|
||||
this.playerData.researchedTechs.has(techTemplateName))
|
||||
return false;
|
||||
|
||||
|
|
@ -243,7 +239,6 @@ m.GameState.prototype.canResearch = function(techTemplateName, noRequirementChec
|
|||
{
|
||||
let other = template.pairedWith();
|
||||
if (this.playerData.researchQueued.has(other) ||
|
||||
this.playerData.researchStarted.has(other) ||
|
||||
this.playerData.researchedTechs.has(other))
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,7 +122,6 @@ GuiInterface.prototype.GetSimulationState = function()
|
|||
"matchEntityCounts": cmpPlayerEntityLimits ? cmpPlayerEntityLimits.GetMatchCounts() : null,
|
||||
"entityLimitChangers": cmpPlayerEntityLimits ? cmpPlayerEntityLimits.GetLimitChangers() : null,
|
||||
"researchQueued": cmpTechnologyManager ? cmpTechnologyManager.GetQueuedResearch() : null,
|
||||
"researchStarted": cmpTechnologyManager ? cmpTechnologyManager.GetStartedTechs() : null,
|
||||
"researchedTechs": cmpTechnologyManager ? cmpTechnologyManager.GetResearchedTechs() : null,
|
||||
"classCounts": cmpTechnologyManager ? cmpTechnologyManager.GetClassCounts() : null,
|
||||
"typeCountsByClass": cmpTechnologyManager ? cmpTechnologyManager.GetTypeCountsByClass() : null,
|
||||
|
|
@ -687,30 +686,7 @@ GuiInterface.prototype.CheckTechnologyRequirements = function(player, data)
|
|||
*/
|
||||
GuiInterface.prototype.GetStartedResearch = function(player)
|
||||
{
|
||||
let cmpTechnologyManager = QueryPlayerIDInterface(player, IID_TechnologyManager);
|
||||
if (!cmpTechnologyManager)
|
||||
return {};
|
||||
|
||||
let ret = {};
|
||||
for (let tech of cmpTechnologyManager.GetStartedTechs())
|
||||
{
|
||||
ret[tech] = { "researcher": cmpTechnologyManager.GetResearcher(tech) };
|
||||
const cmpResearcher = Engine.QueryInterface(ret[tech].researcher, IID_Researcher);
|
||||
if (cmpResearcher)
|
||||
{
|
||||
const research = cmpResearcher.GetResearchingTechnologyByName(tech);
|
||||
ret[tech].progress = research.progress;
|
||||
ret[tech].timeRemaining = research.timeRemaining;
|
||||
ret[tech].paused = research.paused;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret[tech].progress = 0;
|
||||
ret[tech].timeRemaining = 0;
|
||||
ret[tech].paused = true;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
return QueryPlayerIDInterface(player, IID_TechnologyManager)?.GetBasicInfoOfStartedTechs() || {};
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -120,6 +120,8 @@ ProductionQueue.prototype.Item.prototype.IsFinished = function()
|
|||
*/
|
||||
ProductionQueue.prototype.Item.prototype.Progress = function(allocatedTime)
|
||||
{
|
||||
if (this.paused)
|
||||
this.Unpause();
|
||||
if (this.entity)
|
||||
{
|
||||
const cmpTrainer = Engine.QueryInterface(this.producer, IID_Trainer);
|
||||
|
|
@ -152,10 +154,6 @@ ProductionQueue.prototype.Item.prototype.Pause = function()
|
|||
ProductionQueue.prototype.Item.prototype.Unpause = function()
|
||||
{
|
||||
delete this.paused;
|
||||
if (this.entity)
|
||||
Engine.QueryInterface(this.producer, IID_Trainer).UnpauseBatch(this.entity);
|
||||
if (this.technology)
|
||||
Engine.QueryInterface(this.producer, IID_Researcher).UnpauseTechnology(this.technology);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -413,8 +411,6 @@ ProductionQueue.prototype.ProgressTimeout = function(data, lateness)
|
|||
while (this.queue.length)
|
||||
{
|
||||
let item = this.queue[0];
|
||||
if (item.IsPaused())
|
||||
item.Unpause();
|
||||
if (!item.IsStarted())
|
||||
{
|
||||
if (item.entity)
|
||||
|
|
@ -472,7 +468,6 @@ ProductionQueue.prototype.PauseProduction = function()
|
|||
|
||||
ProductionQueue.prototype.UnpauseProduction = function()
|
||||
{
|
||||
this.queue[0]?.Unpause();
|
||||
delete this.paused;
|
||||
this.StartTimer();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -48,43 +48,18 @@ Researcher.prototype.Item = function(templateName, researcher, metadata)
|
|||
*/
|
||||
Researcher.prototype.Item.prototype.Queue = function(techCostMultiplier)
|
||||
{
|
||||
const template = TechnologyTemplates.Get(this.templateName);
|
||||
if (!template)
|
||||
return false;
|
||||
|
||||
this.resources = {};
|
||||
|
||||
if (template.cost)
|
||||
for (const res in template.cost)
|
||||
this.resources[res] = Math.floor(techCostMultiplier[res] * template.cost[res]);
|
||||
|
||||
const cmpPlayer = QueryOwnerInterface(this.researcher);
|
||||
|
||||
// TrySubtractResources should report error to player (they ran out of resources).
|
||||
if (!cmpPlayer?.TrySubtractResources(this.resources))
|
||||
return false;
|
||||
this.player = cmpPlayer.GetPlayerID();
|
||||
|
||||
const time = techCostMultiplier.time * (template.researchTime || 0) * 1000;
|
||||
this.timeRemaining = time;
|
||||
this.timeTotal = time;
|
||||
|
||||
// Tell the technology manager that we have queued researching this
|
||||
// such that players can't research the same thing twice.
|
||||
this.player = QueryOwnerInterface(this.researcher).GetPlayerID();
|
||||
const cmpTechnologyManager = QueryPlayerIDInterface(this.player, IID_TechnologyManager);
|
||||
cmpTechnologyManager.QueuedResearch(this.templateName, this.researcher);
|
||||
if (!cmpTechnologyManager.QueuedResearch(this.templateName, this.researcher, techCostMultiplier))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
Researcher.prototype.Item.prototype.Stop = function()
|
||||
{
|
||||
const cmpTechnologyManager = QueryPlayerIDInterface(this.player, IID_TechnologyManager);
|
||||
if (cmpTechnologyManager)
|
||||
cmpTechnologyManager.StoppedResearch(this.templateName, true);
|
||||
|
||||
QueryPlayerIDInterface(this.player)?.RefundResources(this.resources);
|
||||
delete this.resources;
|
||||
QueryPlayerIDInterface(this.player, IID_TechnologyManager).StoppedResearch(this.templateName);
|
||||
delete this.started;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -92,19 +67,11 @@ Researcher.prototype.Item.prototype.Stop = function()
|
|||
*/
|
||||
Researcher.prototype.Item.prototype.Start = function()
|
||||
{
|
||||
const cmpTechnologyManager = QueryPlayerIDInterface(this.player, IID_TechnologyManager);
|
||||
cmpTechnologyManager.StartedResearch(this.templateName, true);
|
||||
this.started = true;
|
||||
};
|
||||
|
||||
Researcher.prototype.Item.prototype.Finish = function()
|
||||
{
|
||||
const cmpTechnologyManager = QueryPlayerIDInterface(this.player, IID_TechnologyManager);
|
||||
cmpTechnologyManager.ResearchTechnology(this.templateName);
|
||||
|
||||
const template = TechnologyTemplates.Get(this.templateName);
|
||||
if (template?.soundComplete)
|
||||
Engine.QueryInterface(SYSTEM_ENTITY, IID_SoundManager)?.PlaySoundGroup(template.soundComplete, this.researcher);
|
||||
this.finished = true;
|
||||
};
|
||||
|
||||
|
|
@ -116,18 +83,18 @@ Researcher.prototype.Item.prototype.Progress = function(allocatedTime)
|
|||
{
|
||||
if (!this.started)
|
||||
this.Start();
|
||||
|
||||
if (this.timeRemaining > allocatedTime)
|
||||
{
|
||||
this.timeRemaining -= allocatedTime;
|
||||
return allocatedTime;
|
||||
}
|
||||
this.Finish();
|
||||
return this.timeRemaining;
|
||||
if (this.paused)
|
||||
this.Unpause();
|
||||
const cmpTechnologyManager = QueryPlayerIDInterface(this.player, IID_TechnologyManager);
|
||||
const usedTime = cmpTechnologyManager.Progress(this.templateName, allocatedTime);
|
||||
if (!cmpTechnologyManager.IsTechnologyQueued(this.templateName))
|
||||
this.Finish();
|
||||
return usedTime;
|
||||
};
|
||||
|
||||
Researcher.prototype.Item.prototype.Pause = function()
|
||||
{
|
||||
QueryPlayerIDInterface(this.player, IID_TechnologyManager).Pause(this.templateName);
|
||||
this.paused = true;
|
||||
};
|
||||
|
||||
|
|
@ -141,13 +108,10 @@ Researcher.prototype.Item.prototype.Unpause = function()
|
|||
*/
|
||||
Researcher.prototype.Item.prototype.GetBasicInfo = function()
|
||||
{
|
||||
return {
|
||||
"technologyTemplate": this.templateName,
|
||||
"progress": 1 - (this.timeRemaining / (this.timeTotal || 1)),
|
||||
"timeRemaining": this.timeRemaining,
|
||||
"paused": this.paused,
|
||||
"metadata": this.metadata
|
||||
};
|
||||
const result = QueryPlayerIDInterface(this.player, IID_TechnologyManager).GetBasicInfo(this.templateName);
|
||||
result.technologyTemplate = this.templateName;
|
||||
result.metadata = this.metadata;
|
||||
return result;
|
||||
};
|
||||
|
||||
Researcher.prototype.Item.prototype.SerializableAttributes = [
|
||||
|
|
@ -155,11 +119,8 @@ Researcher.prototype.Item.prototype.SerializableAttributes = [
|
|||
"paused",
|
||||
"player",
|
||||
"researcher",
|
||||
"resources",
|
||||
"started",
|
||||
"templateName",
|
||||
"timeRemaining",
|
||||
"timeTotal"
|
||||
"templateName"
|
||||
];
|
||||
|
||||
Researcher.prototype.Item.prototype.Serialize = function(id)
|
||||
|
|
@ -226,6 +187,7 @@ Researcher.prototype.GetTechnologiesList = function()
|
|||
const cmpPlayer = QueryOwnerInterface(this.entity);
|
||||
if (!cmpPlayer)
|
||||
return [];
|
||||
const civ = cmpPlayer.GetCiv();
|
||||
|
||||
let techs = string.split(/\s+/);
|
||||
|
||||
|
|
@ -235,14 +197,14 @@ Researcher.prototype.GetTechnologiesList = function()
|
|||
const tech = techs[i];
|
||||
if (tech.indexOf("{civ}") == -1)
|
||||
continue;
|
||||
const civTech = tech.replace("{civ}", cmpPlayer.GetCiv());
|
||||
const civTech = tech.replace("{civ}", civ);
|
||||
techs[i] = TechnologyTemplates.Has(civTech) ? civTech : tech.replace("{civ}", "generic");
|
||||
}
|
||||
|
||||
// Remove any technologies that can't be researched by this civ.
|
||||
techs = techs.filter(tech =>
|
||||
cmpTechnologyManager.CheckTechnologyRequirements(
|
||||
DeriveTechnologyRequirements(TechnologyTemplates.Get(tech), cmpPlayer.GetCiv()),
|
||||
DeriveTechnologyRequirements(TechnologyTemplates.Get(tech), civ),
|
||||
true));
|
||||
|
||||
const techList = [];
|
||||
|
|
@ -376,14 +338,6 @@ Researcher.prototype.PauseTechnology = function(id)
|
|||
this.queue.get(id).Pause();
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} id - The id of the technology.
|
||||
*/
|
||||
Researcher.prototype.UnpauseTechnology = function(id)
|
||||
{
|
||||
this.queue.get(id).Unpause();
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} id - The ID of the item to check.
|
||||
* @return {boolean} - Whether we are currently training the item.
|
||||
|
|
@ -402,25 +356,6 @@ Researcher.prototype.GetResearchingTechnology = function(id)
|
|||
return this.queue.get(id).GetBasicInfo();
|
||||
};
|
||||
|
||||
/**
|
||||
* @parameter {string} technologyName - The name of the research.
|
||||
* @return {Object} - Some basic information about the research.
|
||||
*/
|
||||
Researcher.prototype.GetResearchingTechnologyByName = function(technologyName)
|
||||
{
|
||||
let techID;
|
||||
for (const [id, value] of this.queue)
|
||||
if (value.templateName === technologyName)
|
||||
{
|
||||
techID = id;
|
||||
break;
|
||||
}
|
||||
if (!techID)
|
||||
return undefined;
|
||||
|
||||
return this.GetResearchingTechnology(techID);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} id - The ID of the item we spent time on.
|
||||
* @param {number} allocatedTime - The time we spent on the given item.
|
||||
|
|
|
|||
|
|
@ -3,17 +3,203 @@ function TechnologyManager() {}
|
|||
TechnologyManager.prototype.Schema =
|
||||
"<empty/>";
|
||||
|
||||
/**
|
||||
* This object represents a technology under research.
|
||||
* @param {string} templateName - The name of the template to research.
|
||||
* @param {number} player - The player ID researching.
|
||||
* @param {number} researcher - The entity ID researching.
|
||||
*/
|
||||
TechnologyManager.prototype.Technology = function(templateName, player, researcher)
|
||||
{
|
||||
this.player = player;
|
||||
this.researcher = researcher;
|
||||
this.templateName = templateName;
|
||||
};
|
||||
|
||||
/**
|
||||
* Prepare for the queue.
|
||||
* @param {Object} techCostMultiplier - The multipliers to use when calculating costs.
|
||||
* @return {boolean} - Whether the technology was successfully initiated.
|
||||
*/
|
||||
TechnologyManager.prototype.Technology.prototype.Queue = function(techCostMultiplier)
|
||||
{
|
||||
const template = TechnologyTemplates.Get(this.templateName);
|
||||
if (!template)
|
||||
return false;
|
||||
|
||||
this.resources = {};
|
||||
if (template.cost)
|
||||
for (const res in template.cost)
|
||||
this.resources[res] = Math.floor(techCostMultiplier[res] * template.cost[res]);
|
||||
|
||||
// ToDo: Subtract resources here or in cmpResearcher?
|
||||
const cmpPlayer = Engine.QueryInterface(this.player, IID_Player);
|
||||
// TrySubtractResources should report error to player (they ran out of resources).
|
||||
if (!cmpPlayer?.TrySubtractResources(this.resources))
|
||||
return false;
|
||||
|
||||
const time = techCostMultiplier.time * (template.researchTime || 0) * 1000;
|
||||
this.timeRemaining = time;
|
||||
this.timeTotal = time;
|
||||
|
||||
const playerID = cmpPlayer.GetPlayerID();
|
||||
Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger).CallEvent("OnResearchQueued", {
|
||||
"playerid": playerID,
|
||||
"technologyTemplate": this.templateName,
|
||||
"researcherEntity": this.researcher
|
||||
});
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
TechnologyManager.prototype.Technology.prototype.Stop = function()
|
||||
{
|
||||
const cmpPlayer = Engine.QueryInterface(this.player, IID_Player);
|
||||
cmpPlayer?.RefundResources(this.resources);
|
||||
delete this.resources;
|
||||
|
||||
if (this.started && this.templateName.startsWith("phase"))
|
||||
Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface).PushNotification({
|
||||
"type": "phase",
|
||||
"players": [cmpPlayer.GetPlayerID()],
|
||||
"phaseName": this.templateName,
|
||||
"phaseState": "aborted"
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when the first work is performed.
|
||||
*/
|
||||
TechnologyManager.prototype.Technology.prototype.Start = function()
|
||||
{
|
||||
this.started = true;
|
||||
if (!this.templateName.startsWith("phase"))
|
||||
return;
|
||||
|
||||
const cmpPlayer = Engine.QueryInterface(this.player, IID_Player);
|
||||
Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface).PushNotification({
|
||||
"type": "phase",
|
||||
"players": [cmpPlayer.GetPlayerID()],
|
||||
"phaseName": this.templateName,
|
||||
"phaseState": "started"
|
||||
});
|
||||
};
|
||||
|
||||
TechnologyManager.prototype.Technology.prototype.Finish = function()
|
||||
{
|
||||
this.finished = true;
|
||||
|
||||
const template = TechnologyTemplates.Get(this.templateName);
|
||||
if (template.soundComplete)
|
||||
Engine.QueryInterface(SYSTEM_ENTITY, IID_SoundManager)?.PlaySoundGroup(template.soundComplete, this.researcher);
|
||||
|
||||
if (template.modifications)
|
||||
{
|
||||
const cmpModifiersManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ModifiersManager);
|
||||
cmpModifiersManager.AddModifiers("tech/" + this.templateName, DeriveModificationsFromTech(template), this.player);
|
||||
}
|
||||
|
||||
const cmpEntityLimits = Engine.QueryInterface(this.player, IID_EntityLimits);
|
||||
const cmpTechnologyManager = Engine.QueryInterface(this.player, IID_TechnologyManager);
|
||||
if (template.replaces && template.replaces.length > 0)
|
||||
for (const i of template.replaces)
|
||||
{
|
||||
cmpTechnologyManager.MarkTechnologyAsResearched(i);
|
||||
cmpEntityLimits?.UpdateLimitsFromTech(i);
|
||||
}
|
||||
|
||||
cmpTechnologyManager.MarkTechnologyAsResearched(this.templateName);
|
||||
|
||||
// ToDo: Move to EntityLimits.js.
|
||||
cmpEntityLimits?.UpdateLimitsFromTech(this.templateName);
|
||||
|
||||
const playerID = Engine.QueryInterface(this.player, IID_Player).GetPlayerID();
|
||||
Engine.PostMessage(this.player, MT_ResearchFinished, { "player": playerID, "tech": this.templateName });
|
||||
|
||||
if (this.templateName.startsWith("phase") && !template.autoResearch)
|
||||
Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface).PushNotification({
|
||||
"type": "phase",
|
||||
"players": [playerID],
|
||||
"phaseName": this.templateName,
|
||||
"phaseState": "completed"
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} allocatedTime - The time allocated to this item.
|
||||
* @return {number} - The time used for this item.
|
||||
*/
|
||||
TechnologyManager.prototype.Technology.prototype.Progress = function(allocatedTime)
|
||||
{
|
||||
if (!this.started)
|
||||
this.Start();
|
||||
if (this.paused)
|
||||
this.Unpause();
|
||||
if (this.timeRemaining > allocatedTime)
|
||||
{
|
||||
this.timeRemaining -= allocatedTime;
|
||||
return allocatedTime;
|
||||
}
|
||||
this.Finish();
|
||||
return this.timeRemaining;
|
||||
};
|
||||
|
||||
TechnologyManager.prototype.Technology.prototype.Pause = function()
|
||||
{
|
||||
this.paused = true;
|
||||
};
|
||||
|
||||
TechnologyManager.prototype.Technology.prototype.Unpause = function()
|
||||
{
|
||||
delete this.paused;
|
||||
};
|
||||
|
||||
TechnologyManager.prototype.Technology.prototype.GetBasicInfo = function()
|
||||
{
|
||||
return {
|
||||
"paused": this.paused,
|
||||
"progress": 1 - (this.timeRemaining / (this.timeTotal || 1)),
|
||||
"researcher": this.researcher,
|
||||
"templateName": this.templateName,
|
||||
"timeRemaining": this.timeRemaining
|
||||
};
|
||||
};
|
||||
|
||||
TechnologyManager.prototype.Technology.prototype.SerializableAttributes = [
|
||||
"paused",
|
||||
"player",
|
||||
"researcher",
|
||||
"resources",
|
||||
"started",
|
||||
"templateName",
|
||||
"timeRemaining",
|
||||
"timeTotal"
|
||||
];
|
||||
|
||||
TechnologyManager.prototype.Technology.prototype.Serialize = function()
|
||||
{
|
||||
const result = {};
|
||||
for (const att of this.SerializableAttributes)
|
||||
if (this.hasOwnProperty(att))
|
||||
result[att] = this[att];
|
||||
return result;
|
||||
};
|
||||
|
||||
TechnologyManager.prototype.Technology.prototype.Deserialize = function(data)
|
||||
{
|
||||
for (const att of this.SerializableAttributes)
|
||||
if (att in data)
|
||||
this[att] = data[att];
|
||||
};
|
||||
|
||||
TechnologyManager.prototype.Init = function()
|
||||
{
|
||||
// Holds names of technologies that have been researched.
|
||||
this.researchedTechs = new Set();
|
||||
|
||||
// Maps from technolgy name to the entityID of the researcher.
|
||||
// Maps from technolgy name to the technology object.
|
||||
this.researchQueued = new Map();
|
||||
|
||||
// Holds technologies which are being researched currently (non-queued).
|
||||
this.researchStarted = new Set();
|
||||
|
||||
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.
|
||||
// {"someClass": {"unit/spearman": 2, "unit/cav": 5} "someOtherClass":...}
|
||||
|
|
@ -27,12 +213,47 @@ TechnologyManager.prototype.Init = function()
|
|||
this.unresearchedAutoResearchTechs.add(key);
|
||||
};
|
||||
|
||||
TechnologyManager.prototype.SerializableAttributes = [
|
||||
"researchedTechs",
|
||||
"classCounts",
|
||||
"typeCountsByClass",
|
||||
"unresearchedAutoResearchTechs"
|
||||
];
|
||||
|
||||
TechnologyManager.prototype.Serialize = function()
|
||||
{
|
||||
const result = {};
|
||||
for (const att of this.SerializableAttributes)
|
||||
if (this.hasOwnProperty(att))
|
||||
result[att] = this[att];
|
||||
|
||||
result.researchQueued = [];
|
||||
for (const [techName, techObject] of this.researchQueued)
|
||||
result.researchQueued.push(techObject.Serialize());
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
TechnologyManager.prototype.Deserialize = function(data)
|
||||
{
|
||||
for (const att of this.SerializableAttributes)
|
||||
if (att in data)
|
||||
this[att] = data[att];
|
||||
|
||||
this.researchQueued = new Map();
|
||||
for (const tech of data.researchQueued)
|
||||
{
|
||||
const newTech = new this.Technology();
|
||||
newTech.Deserialize(tech);
|
||||
this.researchQueued.set(tech.templateName, newTech);
|
||||
}
|
||||
};
|
||||
|
||||
TechnologyManager.prototype.OnUpdate = function()
|
||||
{
|
||||
this.UpdateAutoResearch();
|
||||
};
|
||||
|
||||
|
||||
// This function checks if the requirements of any autoresearch techs are met and if they are it researches them
|
||||
TechnologyManager.prototype.UpdateAutoResearch = function()
|
||||
{
|
||||
|
|
@ -71,11 +292,6 @@ TechnologyManager.prototype.IsTechnologyResearched = function(tech)
|
|||
return this.researchedTechs.has(tech);
|
||||
};
|
||||
|
||||
TechnologyManager.prototype.IsTechnologyStarted = function(tech)
|
||||
{
|
||||
return this.researchStarted.has(tech);
|
||||
};
|
||||
|
||||
// Checks the requirements for a technology to see if it can be researched at the current time
|
||||
TechnologyManager.prototype.CanResearch = function(tech)
|
||||
{
|
||||
|
|
@ -208,130 +424,86 @@ TechnologyManager.prototype.OnGlobalOwnershipChanged = function(msg)
|
|||
};
|
||||
|
||||
/**
|
||||
* Marks a technology as researched.
|
||||
* Note that this does not verify that the requirements are met.
|
||||
*
|
||||
* @param {string} tech - The technology to mark as researched.
|
||||
* This does neither apply effects nor verify requirements.
|
||||
* @param {string} tech - The name of the technology to mark as researched.
|
||||
*/
|
||||
TechnologyManager.prototype.ResearchTechnology = function(tech)
|
||||
TechnologyManager.prototype.MarkTechnologyAsResearched = function(tech)
|
||||
{
|
||||
this.StoppedResearch(tech, false);
|
||||
|
||||
let modifiedComponents = {};
|
||||
this.researchedTechs.add(tech);
|
||||
|
||||
// Store the modifications in an easy to access structure.
|
||||
let template = TechnologyTemplates.Get(tech);
|
||||
if (template.modifications)
|
||||
{
|
||||
let cmpModifiersManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ModifiersManager);
|
||||
cmpModifiersManager.AddModifiers("tech/" + tech, DeriveModificationsFromTech(template), this.entity);
|
||||
}
|
||||
|
||||
if (template.replaces && template.replaces.length > 0)
|
||||
{
|
||||
for (let i of template.replaces)
|
||||
{
|
||||
if (!i || this.IsTechnologyResearched(i))
|
||||
continue;
|
||||
|
||||
this.researchedTechs.add(i);
|
||||
|
||||
// Change the EntityLimit if any.
|
||||
let cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);
|
||||
if (cmpPlayer && cmpPlayer.GetPlayerID() !== undefined)
|
||||
{
|
||||
let playerID = cmpPlayer.GetPlayerID();
|
||||
let cmpPlayerEntityLimits = QueryPlayerIDInterface(playerID, IID_EntityLimits);
|
||||
if (cmpPlayerEntityLimits)
|
||||
cmpPlayerEntityLimits.UpdateLimitsFromTech(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.UpdateAutoResearch();
|
||||
};
|
||||
|
||||
let cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);
|
||||
if (!cmpPlayer || cmpPlayer.GetPlayerID() === undefined)
|
||||
/**
|
||||
* Note that this does not verify whether the requirements are met.
|
||||
* @param {string} tech - The technology to research.
|
||||
* @param {number} researcher - Optionally the entity to couple with the research.
|
||||
*/
|
||||
TechnologyManager.prototype.ResearchTechnology = function(tech, researcher = INVALID_ENTITY)
|
||||
{
|
||||
if (this.IsTechnologyQueued(tech) || this.IsTechnologyResearched(tech))
|
||||
return;
|
||||
let playerID = cmpPlayer.GetPlayerID();
|
||||
|
||||
// Change the EntityLimit if any.
|
||||
let cmpPlayerEntityLimits = QueryPlayerIDInterface(playerID, IID_EntityLimits);
|
||||
if (cmpPlayerEntityLimits)
|
||||
cmpPlayerEntityLimits.UpdateLimitsFromTech(tech);
|
||||
|
||||
// Always send research finished message.
|
||||
Engine.PostMessage(this.entity, MT_ResearchFinished, { "player": playerID, "tech": tech });
|
||||
|
||||
if (tech.startsWith("phase") && !template.autoResearch)
|
||||
{
|
||||
let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
|
||||
cmpGUIInterface.PushNotification({
|
||||
"type": "phase",
|
||||
"players": [playerID],
|
||||
"phaseName": tech,
|
||||
"phaseState": "completed"
|
||||
});
|
||||
}
|
||||
const technology = new this.Technology(tech, this.entity, researcher);
|
||||
technology.Finish();
|
||||
};
|
||||
|
||||
/**
|
||||
* Marks a technology as being queued for research at the given entityID.
|
||||
* @param {string} tech - The technology to queue.
|
||||
* @param {number} researcher - The entity ID of the entity researching this technology.
|
||||
* @param {Object} techCostMultiplier - The multipliers used when calculating the costs.
|
||||
*
|
||||
* @return {boolean} - Whether we successfully have queued the technology.
|
||||
*/
|
||||
TechnologyManager.prototype.QueuedResearch = function(tech, researcher)
|
||||
TechnologyManager.prototype.QueuedResearch = function(tech, researcher, techCostMultiplier)
|
||||
{
|
||||
this.researchQueued.set(tech, researcher);
|
||||
|
||||
const cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);
|
||||
if (!cmpPlayer)
|
||||
return;
|
||||
const playerID = cmpPlayer.GetPlayerID();
|
||||
|
||||
Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger).CallEvent("OnResearchQueued", {
|
||||
"playerid": playerID,
|
||||
"technologyTemplate": tech,
|
||||
"researcherEntity": researcher
|
||||
});
|
||||
};
|
||||
|
||||
// Marks a technology as actively being researched
|
||||
TechnologyManager.prototype.StartedResearch = function(tech, notification)
|
||||
{
|
||||
this.researchStarted.add(tech);
|
||||
|
||||
if (notification && tech.startsWith("phase"))
|
||||
{
|
||||
let cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);
|
||||
let cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
|
||||
cmpGuiInterface.PushNotification({
|
||||
"type": "phase",
|
||||
"players": [cmpPlayer.GetPlayerID()],
|
||||
"phaseName": tech,
|
||||
"phaseState": "started"
|
||||
});
|
||||
}
|
||||
// ToDo: Check whether the technology is researched already?
|
||||
const technology = new this.Technology(tech, this.entity, researcher);
|
||||
if (!technology.Queue(techCostMultiplier))
|
||||
return false;
|
||||
this.researchQueued.set(tech, technology);
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Marks a technology as not being currently researched and optionally sends a GUI notification.
|
||||
* Marks a technology as not being currently researched and optionally sends a GUI notification.
|
||||
* @param {string} tech - The name of the technology to stop.
|
||||
* @param {boolean} notification - Whether a GUI notification ought to be sent.
|
||||
*/
|
||||
TechnologyManager.prototype.StoppedResearch = function(tech, notification)
|
||||
TechnologyManager.prototype.StoppedResearch = function(tech)
|
||||
{
|
||||
if (notification && tech.startsWith("phase") && this.researchStarted.has(tech))
|
||||
{
|
||||
let cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);
|
||||
let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
|
||||
cmpGUIInterface.PushNotification({
|
||||
"type": "phase",
|
||||
"players": [cmpPlayer.GetPlayerID()],
|
||||
"phaseName": tech,
|
||||
"phaseState": "aborted"
|
||||
});
|
||||
}
|
||||
|
||||
this.researchQueued.get(tech).Stop();
|
||||
this.researchQueued.delete(tech);
|
||||
this.researchStarted.delete(tech);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} tech -
|
||||
*/
|
||||
TechnologyManager.prototype.Pause = function(tech)
|
||||
{
|
||||
this.researchQueued.get(tech).Pause();
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} tech - The technology to advance.
|
||||
* @param {number} allocatedTime - The time allocated to the technology.
|
||||
* @return {number} - The time we've actually used.
|
||||
*/
|
||||
TechnologyManager.prototype.Progress = function(techName, allocatedTime)
|
||||
{
|
||||
const technology = this.researchQueued.get(techName);
|
||||
const usedTime = technology.Progress(allocatedTime);
|
||||
if (technology.finished)
|
||||
this.researchQueued.delete(techName);
|
||||
return usedTime;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} tech - The technology name to retreive some basic information for.
|
||||
* @return {Object} - Some basic information about the technology under research.
|
||||
*/
|
||||
TechnologyManager.prototype.GetBasicInfo = function(tech)
|
||||
{
|
||||
return this.researchQueued.get(tech).GetBasicInfo();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -342,20 +514,13 @@ TechnologyManager.prototype.IsInProgress = function(tech)
|
|||
return this.researchQueued.has(tech);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the names of technologies that are currently being researched (non-queued).
|
||||
*/
|
||||
TechnologyManager.prototype.GetStartedTechs = function()
|
||||
TechnologyManager.prototype.GetBasicInfoOfStartedTechs = function()
|
||||
{
|
||||
return this.researchStarted;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the entity currently researching the technology.
|
||||
*/
|
||||
TechnologyManager.prototype.GetResearcher = function(tech)
|
||||
{
|
||||
return this.researchQueued.get(tech);
|
||||
const result = {};
|
||||
for (const [techName, tech] of this.researchQueued)
|
||||
if (tech.started)
|
||||
result[techName] = tech.GetBasicInfo();
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -333,6 +333,8 @@ Trainer.prototype.Item.prototype.Spawn = function()
|
|||
*/
|
||||
Trainer.prototype.Item.prototype.Progress = function(allocatedTime)
|
||||
{
|
||||
if (this.paused)
|
||||
this.Unpause();
|
||||
// We couldn't start this timeout, try again later.
|
||||
if (!this.started && !this.Start())
|
||||
return allocatedTime;
|
||||
|
|
@ -650,14 +652,6 @@ Trainer.prototype.PauseBatch = function(id)
|
|||
this.queue.get(id).Pause();
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} id - The ID of the training.
|
||||
*/
|
||||
Trainer.prototype.UnpauseBatch = function(id)
|
||||
{
|
||||
this.queue.get(id).Unpause();
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} id - The ID of the batch to check.
|
||||
* @return {boolean} - Whether we are currently training the batch.
|
||||
|
|
|
|||
|
|
@ -311,7 +311,6 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetSimulationState(), {
|
|||
"matchEntityCounts": { "Bar": 0 },
|
||||
"entityLimitChangers": { "Foo": {} },
|
||||
"researchQueued": new Map(),
|
||||
"researchStarted": new Set(),
|
||||
"researchedTechs": new Set(),
|
||||
"classCounts": {},
|
||||
"typeCountsByClass": {},
|
||||
|
|
@ -362,7 +361,6 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetSimulationState(), {
|
|||
"matchEntityCounts": { "Foo": 0 },
|
||||
"entityLimitChangers": { "Bar": {} },
|
||||
"researchQueued": new Map(),
|
||||
"researchStarted": new Set(),
|
||||
"researchedTechs": new Set(),
|
||||
"classCounts": {},
|
||||
"typeCountsByClass": {},
|
||||
|
|
@ -423,7 +421,6 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), {
|
|||
"matchEntityCounts": { "Bar": 0 },
|
||||
"entityLimitChangers": { "Foo": {} },
|
||||
"researchQueued": new Map(),
|
||||
"researchStarted": new Set(),
|
||||
"researchedTechs": new Set(),
|
||||
"classCounts": {},
|
||||
"typeCountsByClass": {},
|
||||
|
|
@ -497,7 +494,6 @@ TS_ASSERT_UNEVAL_EQUALS(cmp.GetExtendedSimulationState(), {
|
|||
"matchEntityCounts": { "Foo": 0 },
|
||||
"entityLimitChangers": { "Bar": {} },
|
||||
"researchQueued": new Map(),
|
||||
"researchStarted": new Set(),
|
||||
"researchedTechs": new Set(),
|
||||
"classCounts": {},
|
||||
"typeCountsByClass": {},
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ AddMock(SYSTEM_ENTITY, IID_PlayerManager, {
|
|||
|
||||
AddMock(playerEntityID, IID_Player, {
|
||||
"GetCiv": () => "iber",
|
||||
"GetDisabledTechnologies": () => ({})
|
||||
"GetDisabledTechnologies": () => ({}) // ToDo: Should be in the techmanager.
|
||||
});
|
||||
|
||||
AddMock(playerEntityID, IID_TechnologyManager, {
|
||||
|
|
@ -98,23 +98,15 @@ const cmpPlayer = AddMock(playerEntityID, IID_Player, {
|
|||
"GetCiv": () => "iber",
|
||||
"GetDisabledTechnologies": () => ({}),
|
||||
"GetPlayerID": () => playerID,
|
||||
"TrySubtractResources": (resources) => {
|
||||
TS_ASSERT_UNEVAL_EQUALS(resources, cost);
|
||||
// Just have enough resources.
|
||||
return true;
|
||||
},
|
||||
"RefundResources": (resources) => {
|
||||
TS_ASSERT_UNEVAL_EQUALS(resources, cost);
|
||||
},
|
||||
});
|
||||
let spyCmpPlayer = new Spy(cmpPlayer, "TrySubtractResources");
|
||||
const techManager = AddMock(playerEntityID, IID_TechnologyManager, {
|
||||
"CheckTechnologyRequirements": () => true,
|
||||
"IsInProgress": () => false,
|
||||
"IsTechnologyResearched": () => false,
|
||||
"QueuedResearch": (templateName, researcher) => {
|
||||
"QueuedResearch": (templateName, researcher, techCostMultiplier) => {
|
||||
TS_ASSERT_UNEVAL_EQUALS(templateName, queuedTech);
|
||||
TS_ASSERT_UNEVAL_EQUALS(researcher, entityID);
|
||||
return true;
|
||||
},
|
||||
"StoppedResearch": (templateName, _) => {
|
||||
TS_ASSERT_UNEVAL_EQUALS(templateName, queuedTech);
|
||||
|
|
@ -129,30 +121,26 @@ const techManager = AddMock(playerEntityID, IID_TechnologyManager, {
|
|||
let spyTechManager = new Spy(techManager, "QueuedResearch");
|
||||
let id = cmpResearcher.QueueTechnology(queuedTech);
|
||||
TS_ASSERT_EQUALS(spyTechManager._called, 1);
|
||||
TS_ASSERT_EQUALS(spyCmpPlayer._called, 1);
|
||||
TS_ASSERT_EQUALS(cmpResearcher.queue.size, 1);
|
||||
|
||||
|
||||
// Test removing a queued tech.
|
||||
spyCmpPlayer = new Spy(cmpPlayer, "RefundResources");
|
||||
spyTechManager = new Spy(techManager, "StoppedResearch");
|
||||
cmpResearcher.StopResearching(id);
|
||||
TS_ASSERT_EQUALS(spyTechManager._called, 1);
|
||||
TS_ASSERT_EQUALS(spyCmpPlayer._called, 1);
|
||||
TS_ASSERT_EQUALS(cmpResearcher.queue.size, 0);
|
||||
|
||||
|
||||
// Test finishing a queued tech.
|
||||
id = cmpResearcher.QueueTechnology(queuedTech);
|
||||
TS_ASSERT_EQUALS(cmpResearcher.GetResearchingTechnology(id).progress, 0);
|
||||
techManager.Progress = () => 500;
|
||||
techManager.IsTechnologyQueued = () => true;
|
||||
TS_ASSERT_EQUALS(cmpResearcher.Progress(id, 500), 500);
|
||||
TS_ASSERT_EQUALS(cmpResearcher.GetResearchingTechnology(id).progress, 0.5);
|
||||
|
||||
cmpResearcher = SerializationCycle(cmpResearcher);
|
||||
|
||||
spyTechManager = new Spy(techManager, "ResearchTechnology");
|
||||
techManager.IsTechnologyQueued = () => false;
|
||||
TS_ASSERT_EQUALS(cmpResearcher.Progress(id, 1000), 500);
|
||||
TS_ASSERT_EQUALS(spyTechManager._called, 1);
|
||||
TS_ASSERT_EQUALS(cmpResearcher.queue.size, 0);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
Resources = {
|
||||
"GetCodes": () => ["food", "metal", "stone", "wood"],
|
||||
"GetTradableCodes": () => ["food", "metal", "stone", "wood"],
|
||||
"GetBarterableCodes": () => ["food", "metal", "stone", "wood"],
|
||||
"BuildSchema": () => {
|
||||
let schema = "";
|
||||
for (let res of ["food", "metal"])
|
||||
{
|
||||
for (let subtype in ["meat", "grain"])
|
||||
schema += "<value>" + res + "." + subtype + "</value>";
|
||||
schema += "<value> treasure." + res + "</value>";
|
||||
}
|
||||
return "<choice>" + schema + "</choice>";
|
||||
},
|
||||
"BuildChoicesSchema": () => {
|
||||
let schema = "";
|
||||
for (let res of ["food", "metal"])
|
||||
{
|
||||
for (let subtype in ["meat", "grain"])
|
||||
schema += "<value>" + res + "." + subtype + "</value>";
|
||||
schema += "<value> treasure." + res + "</value>";
|
||||
}
|
||||
return "<choice>" + schema + "</choice>";
|
||||
},
|
||||
"GetResource": (type) => {
|
||||
return {
|
||||
"subtypes": {
|
||||
"meat": "meat",
|
||||
"grain": "grain"
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
Engine.LoadComponentScript("interfaces/EntityLimits.js");
|
||||
Engine.LoadComponentScript("interfaces/Player.js");
|
||||
Engine.LoadComponentScript("interfaces/Researcher.js");
|
||||
Engine.LoadComponentScript("interfaces/StatisticsTracker.js");
|
||||
Engine.LoadComponentScript("interfaces/TechnologyManager.js");
|
||||
Engine.LoadComponentScript("interfaces/Timer.js");
|
||||
Engine.LoadComponentScript("interfaces/Trigger.js");
|
||||
Engine.LoadComponentScript("Player.js");
|
||||
Engine.LoadComponentScript("Researcher.js");
|
||||
Engine.LoadComponentScript("TechnologyManager.js");
|
||||
Engine.LoadComponentScript("Timer.js");
|
||||
Engine.LoadComponentScript("Trigger.js");
|
||||
|
||||
Engine.LoadHelperScript("Player.js");
|
||||
|
||||
ConstructComponent(SYSTEM_ENTITY, "Trigger");
|
||||
const cmpTimer = ConstructComponent(SYSTEM_ENTITY, "Timer", null);
|
||||
|
||||
Engine.RegisterGlobal("ApplyValueModificationsToEntity", (_, value) => typeof value === "string" ? value + " some_test": value);
|
||||
|
||||
const template = {
|
||||
"name": "templateName"
|
||||
};
|
||||
Engine.RegisterGlobal("TechnologyTemplates", {
|
||||
"GetAll": () => [],
|
||||
"Get": (tech) => {
|
||||
return template;
|
||||
}
|
||||
});
|
||||
|
||||
const playerID = 1;
|
||||
const playerEntityID = 11;
|
||||
const researcherID = 21;
|
||||
|
||||
let cmpTechnologyManager = ConstructComponent(playerEntityID, "TechnologyManager", null);
|
||||
|
||||
AddMock(researcherID, IID_Ownership, {
|
||||
"GetOwner": () => playerID
|
||||
});
|
||||
AddMock(SYSTEM_ENTITY, IID_PlayerManager, {
|
||||
"GetPlayerByID": id => playerEntityID
|
||||
});
|
||||
|
||||
template.cost = {
|
||||
"food": 100
|
||||
};
|
||||
template.researchTime = 1.5;
|
||||
|
||||
const cmpPlayer = ConstructComponent(playerEntityID, "Player", {
|
||||
"SpyCostMultiplier": "1",
|
||||
"BarterMultiplier": {
|
||||
"Buy": {},
|
||||
"Sell": {}
|
||||
}
|
||||
});
|
||||
const spyPlayerResSub = new Spy(cmpPlayer, "TrySubtractResources");
|
||||
const spyPlayerResRefund = new Spy(cmpPlayer, "RefundResources");
|
||||
|
||||
let cmpResearcher = ConstructComponent(researcherID, "Researcher", {
|
||||
"Technologies": {
|
||||
"_string": template.name
|
||||
}
|
||||
});
|
||||
|
||||
let id = cmpResearcher.QueueTechnology(template.name);
|
||||
|
||||
TS_ASSERT_EQUALS(spyPlayerResSub._called, 1);
|
||||
TS_ASSERT(!cmpTechnologyManager.IsTechnologyResearched(template.name));
|
||||
TS_ASSERT(cmpTechnologyManager.IsInProgress(template.name));
|
||||
TS_ASSERT_EQUALS(cmpResearcher.Progress(id, 1000), 1000);
|
||||
cmpResearcher = SerializationCycle(cmpResearcher);
|
||||
cmpTechnologyManager = SerializationCycle(cmpTechnologyManager);
|
||||
|
||||
cmpResearcher.StopResearching(id);
|
||||
TS_ASSERT(!cmpTechnologyManager.IsInProgress(template.name));
|
||||
TS_ASSERT_EQUALS(spyPlayerResRefund._called, 1);
|
||||
|
||||
id = cmpResearcher.QueueTechnology(template.name);
|
||||
TS_ASSERT_EQUALS(spyPlayerResSub._called, 2);
|
||||
TS_ASSERT_EQUALS(cmpResearcher.Progress(id, 1000), 1000);
|
||||
cmpResearcher = SerializationCycle(cmpResearcher);
|
||||
cmpTechnologyManager = SerializationCycle(cmpTechnologyManager);
|
||||
TS_ASSERT_EQUALS(cmpResearcher.Progress(id, 1000), 500);
|
||||
TS_ASSERT(cmpTechnologyManager.IsTechnologyResearched(template.name));
|
||||
TS_ASSERT_EQUALS(spyPlayerResRefund._called, 1);
|
||||
|
|
@ -1,14 +1,28 @@
|
|||
Engine.LoadComponentScript("interfaces/EntityLimits.js");
|
||||
Engine.LoadComponentScript("interfaces/TechnologyManager.js");
|
||||
Engine.LoadComponentScript("interfaces/Trigger.js");
|
||||
Engine.LoadComponentScript("TechnologyManager.js");
|
||||
Engine.LoadComponentScript("Trigger.js");
|
||||
|
||||
global.TechnologyTemplates = {
|
||||
"GetAll": () => []
|
||||
};
|
||||
Engine.LoadHelperScript("Player.js");
|
||||
|
||||
let cmpTechnologyManager = ConstructComponent(SYSTEM_ENTITY, "TechnologyManager", {});
|
||||
ConstructComponent(SYSTEM_ENTITY, "Trigger");
|
||||
|
||||
const techTemplate = {};
|
||||
Engine.RegisterGlobal("TechnologyTemplates", {
|
||||
"GetAll": () => [],
|
||||
"Get": (tech) => {
|
||||
return techTemplate;
|
||||
}
|
||||
});
|
||||
|
||||
const playerID = 1;
|
||||
const playerEntityID = 11;
|
||||
|
||||
let cmpTechnologyManager = ConstructComponent(playerEntityID, "TechnologyManager", null);
|
||||
|
||||
// Test CheckTechnologyRequirements
|
||||
let template = { "requirements": { "all": [{ "entity": { "class": "Village", "number": 5 } }, { "civ": "athen" }] } };
|
||||
const template = { "requirements": { "all": [{ "entity": { "class": "Village", "number": 5 } }, { "civ": "athen" }] } };
|
||||
cmpTechnologyManager.classCounts.Village = 2;
|
||||
TS_ASSERT_EQUALS(cmpTechnologyManager.CheckTechnologyRequirements(DeriveTechnologyRequirements(template, "athen")), false);
|
||||
TS_ASSERT_EQUALS(cmpTechnologyManager.CheckTechnologyRequirements(DeriveTechnologyRequirements(template, "athen"), true), true);
|
||||
|
|
@ -16,3 +30,66 @@ TS_ASSERT_EQUALS(cmpTechnologyManager.CheckTechnologyRequirements(DeriveTechnolo
|
|||
cmpTechnologyManager.classCounts.Village = 6;
|
||||
TS_ASSERT_EQUALS(cmpTechnologyManager.CheckTechnologyRequirements(DeriveTechnologyRequirements(template, "athen")), true);
|
||||
TS_ASSERT_EQUALS(cmpTechnologyManager.CheckTechnologyRequirements(DeriveTechnologyRequirements(template, "maur")), false);
|
||||
|
||||
AddMock(SYSTEM_ENTITY, IID_PlayerManager, {
|
||||
"GetPlayerByID": id => playerEntityID
|
||||
});
|
||||
|
||||
const templateName = "template";
|
||||
techTemplate.cost = {
|
||||
"food": 100
|
||||
};
|
||||
const cmpPlayer = AddMock(playerEntityID, IID_Player, {
|
||||
"GetPlayerID": () => playerID,
|
||||
"TrySubtractResources": (resources) => {
|
||||
TS_ASSERT_UNEVAL_EQUALS(resources, techTemplate.cost);
|
||||
// Just have enough resources.
|
||||
return true;
|
||||
},
|
||||
"RefundResources": (resources) => {
|
||||
TS_ASSERT_UNEVAL_EQUALS(resources, techTemplate.cost);
|
||||
},
|
||||
});
|
||||
const spyCmpPlayerSubtract = new Spy(cmpPlayer, "TrySubtractResources");
|
||||
const spyCmpPlayerRefund = new Spy(cmpPlayer, "RefundResources");
|
||||
|
||||
TS_ASSERT(cmpTechnologyManager.QueuedResearch(templateName, INVALID_ENTITY, { "food": 1 }));
|
||||
TS_ASSERT(cmpTechnologyManager.IsInProgress(templateName));
|
||||
TS_ASSERT_EQUALS(spyCmpPlayerSubtract._called, 1);
|
||||
|
||||
// Test refunding before start.
|
||||
cmpTechnologyManager.StoppedResearch(templateName, true);
|
||||
TS_ASSERT(!cmpTechnologyManager.IsInProgress(templateName));
|
||||
TS_ASSERT_EQUALS(spyCmpPlayerRefund._called, 1);
|
||||
|
||||
techTemplate.researchTime = 2;
|
||||
TS_ASSERT(cmpTechnologyManager.QueuedResearch(templateName, INVALID_ENTITY, { "food": 1, "time": 1 }));
|
||||
TS_ASSERT_EQUALS(cmpTechnologyManager.Progress(templateName, 500), 500);
|
||||
|
||||
cmpTechnologyManager = SerializationCycle(cmpTechnologyManager);
|
||||
|
||||
cmpTechnologyManager.Pause(templateName);
|
||||
TS_ASSERT_UNEVAL_EQUALS(cmpTechnologyManager.GetBasicInfoOfStartedTechs(), {
|
||||
[templateName]: {
|
||||
"paused": true,
|
||||
"progress": 0.25,
|
||||
"researcher": INVALID_ENTITY,
|
||||
"templateName": templateName,
|
||||
"timeRemaining": 1500
|
||||
},
|
||||
});
|
||||
|
||||
TS_ASSERT(!cmpTechnologyManager.IsTechnologyResearched(templateName));
|
||||
TS_ASSERT_EQUALS(cmpTechnologyManager.Progress(templateName, 2000), 1500);
|
||||
TS_ASSERT(cmpTechnologyManager.IsTechnologyResearched(templateName));
|
||||
|
||||
TS_ASSERT(cmpTechnologyManager.QueuedResearch(templateName, INVALID_ENTITY, { "food": 1, "time": 1 }));
|
||||
TS_ASSERT_EQUALS(cmpTechnologyManager.Progress(templateName, 500), 500);
|
||||
TS_ASSERT(cmpTechnologyManager.IsInProgress(templateName));
|
||||
|
||||
cmpTechnologyManager = SerializationCycle(cmpTechnologyManager);
|
||||
|
||||
// Test refunding after start.
|
||||
cmpTechnologyManager.StoppedResearch(templateName, true);
|
||||
TS_ASSERT(!cmpTechnologyManager.IsInProgress(templateName));
|
||||
TS_ASSERT_EQUALS(spyCmpPlayerRefund._called, 2);
|
||||
|
|
|
|||
|
|
@ -164,8 +164,7 @@ function Cheat(input)
|
|||
}
|
||||
}
|
||||
|
||||
if (TechnologyTemplates.Has(techname) &&
|
||||
!cmpTechnologyManager.IsTechnologyResearched(techname))
|
||||
if (TechnologyTemplates.Has(techname))
|
||||
cmpTechnologyManager.ResearchTechnology(techname);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue