1
0
forked from 0ad/0ad

Allow to push items to the front of the ProductionQueue.

Refs. #6104
Differential revision: https://code.wildfiregames.com/D4241
Comments by: @bb, @Langbart, @Stan
This was SVN commit r25958.
This commit is contained in:
Freagarach 2021-10-10 19:07:42 +00:00
parent b1a01005b8
commit 75aa2091b7
10 changed files with 74 additions and 21 deletions

View File

@ -55,6 +55,7 @@ class ResearchProgressButton
this.sprite = Engine.GetGUIObjectByName("researchStartedIcon[" + i + "]"); this.sprite = Engine.GetGUIObjectByName("researchStartedIcon[" + i + "]");
this.progress = Engine.GetGUIObjectByName("researchStartedProgressSlider[" + i + "]"); this.progress = Engine.GetGUIObjectByName("researchStartedProgressSlider[" + i + "]");
this.timeRemaining = Engine.GetGUIObjectByName("researchStartedTimeRemaining[" + i + "]"); this.timeRemaining = Engine.GetGUIObjectByName("researchStartedTimeRemaining[" + i + "]");
this.paused = Engine.GetGUIObjectByName("researchPausedIcon[" + i + "]");
this.buttonHeight = this.button.size.bottom - this.button.size.top; this.buttonHeight = this.button.size.bottom - this.button.size.top;
this.buttonTop = this.Margin + (this.Margin + this.buttonHeight) * i; this.buttonTop = this.Margin + (this.Margin + this.buttonHeight) * i;
@ -68,13 +69,18 @@ class ResearchProgressButton
this.researcher = researchStatus.researcher; this.researcher = researchStatus.researcher;
let template = GetTechnologyData(techName, g_Players[g_ViewedPlayer].civ); let template = GetTechnologyData(techName, g_Players[g_ViewedPlayer].civ);
this.sprite.sprite = "stretched:" + this.PortraitDirectory + template.icon; let modifier = "stretched:";
if (researchStatus.paused)
modifier += "color:0 0 0 127:grayscale:";
this.sprite.sprite = modifier + this.PortraitDirectory + template.icon;
let size = this.button.size; let size = this.button.size;
size.top = offset + this.buttonTop; size.top = offset + this.buttonTop;
size.bottom = size.top + this.buttonHeight; size.bottom = size.top + this.buttonHeight;
this.button.size = size; this.button.size = size;
this.button.tooltip = getEntityNames(template); this.button.tooltip = getEntityNames(template);
if (researchStatus.paused)
this.button.tooltip += "\n" + translate(this.PausedResearchString);
this.button.hidden = false; this.button.hidden = false;
size = this.progress.size; size = this.progress.size;
@ -85,6 +91,8 @@ class ResearchProgressButton
Engine.FormatMillisecondsIntoDateStringGMT( Engine.FormatMillisecondsIntoDateStringGMT(
researchStatus.timeRemaining, researchStatus.timeRemaining,
translateWithContext("countdown format", this.CountdownFormat)); translateWithContext("countdown format", this.CountdownFormat));
this.paused.hidden = !researchStatus.paused;
} }
onPress() onPress()
@ -107,3 +115,6 @@ ResearchProgressButton.prototype.PortraitDirectory = "session/portraits/";
* This format is used when displaying the remaining time of the currently viewed techs in research. * This format is used when displaying the remaining time of the currently viewed techs in research.
*/ */
ResearchProgressButton.prototype.CountdownFormat = markForTranslationWithContext("countdown format", "m:ss"); ResearchProgressButton.prototype.CountdownFormat = markForTranslationWithContext("countdown format", "m:ss");
// Translation: String displayed when the research is paused. E.g. by being garrisoned or when not the first item in the queue.
ResearchProgressButton.prototype.PausedResearchString = markForTranslation("(This item is paused.)");

View File

@ -7,6 +7,7 @@
<object name="researchStartedIcon[n]" ghost="true" type="image" size="3 3 35 35"/> <object name="researchStartedIcon[n]" ghost="true" type="image" size="3 3 35 35"/>
<object name="researchStartedProgressSlider[n]" type="image" sprite="queueProgressSlider" ghost="true" size="3 3 37 37"/> <object name="researchStartedProgressSlider[n]" type="image" sprite="queueProgressSlider" ghost="true" size="3 3 37 37"/>
<object name="researchStartedTimeRemaining[n]" ghost="true" style="iconButtonProgress" type="text"/> <object name="researchStartedTimeRemaining[n]" ghost="true" style="iconButtonProgress" type="text"/>
<object name="researchPausedIcon[n]" ghost="true" type="image" sprite="stretched:session/icons/stop.png" size="3 3 35 35"/>
</object> </object>
</repeat> </repeat>
</object> </object>

View File

@ -1521,7 +1521,8 @@ function addTrainingToQueue(selection, trainEntType, playerState)
"type": "train", "type": "train",
"template": trainEntType, "template": trainEntType,
"count": 1, "count": 1,
"entities": buildingsForTraining "entities": buildingsForTraining,
"pushFront": Engine.HotkeyIsPressed("session.pushorderfront")
}); });
} }
} }
@ -1579,7 +1580,8 @@ function flushTrainingBatch()
"type": "train", "type": "train",
"entities": appropriateBuildings.slice(0, buildingsCountToTrainFullBatch), "entities": appropriateBuildings.slice(0, buildingsCountToTrainFullBatch),
"template": g_BatchTrainingType, "template": g_BatchTrainingType,
"count": batchedSize "count": batchedSize,
"pushFront": Engine.HotkeyIsPressed("session.pushorderfront")
}); });
// Train remainer in one more structure. // Train remainer in one more structure.
@ -1589,7 +1591,8 @@ function flushTrainingBatch()
"type": "train", "type": "train",
"entities": [appropriateBuildings[buildingsCountToTrainFullBatch]], "entities": [appropriateBuildings[buildingsCountToTrainFullBatch]],
"template": g_BatchTrainingType, "template": g_BatchTrainingType,
"count": remainer "count": remainer,
"pushFront": Engine.HotkeyIsPressed("session.pushorderfront")
}); });
} }
else else
@ -1597,7 +1600,8 @@ function flushTrainingBatch()
"type": "train", "type": "train",
"entities": appropriateBuildings, "entities": appropriateBuildings,
"template": g_BatchTrainingType, "template": g_BatchTrainingType,
"count": batchedSize "count": batchedSize,
"pushFront": Engine.HotkeyIsPressed("session.pushorderfront")
}); });
} }

View File

@ -590,10 +590,22 @@ g_SelectionPanels.Queue = {
guiObject.size = size; guiObject.size = size;
data.button.enabled = controlsPlayer(data.player); data.button.enabled = controlsPlayer(data.player);
Engine.GetGUIObjectByName("unitQueuePausedIcon[" + data.i + "]").hidden = !queuedItem.paused;
if (queuedItem.paused)
// Translation: String displayed when the research is paused. E.g. by being garrisoned or when not the first item in the queue.
data.button.tooltip += "\n" + translate("(This item is paused.)");
} }
if (template.icon) if (template.icon)
data.icon.sprite = (data.item.ghost ? "grayscale:" : "") + "stretched:session/portraits/" + template.icon; {
let modifier = "stretched:";
if (queuedItem.paused)
modifier += "color:0 0 0 127:grayscale:";
else if (data.item.ghost)
modifier += "grayscale:";
data.icon.sprite = modifier + "session/portraits/" + template.icon;
}
const showTemplateFunc = () => { showTemplateDetails(data.item.queuedItem.unitTemplate || data.item.queuedItem.technologyTemplate, data.playerState.civ); }; const showTemplateFunc = () => { showTemplateDetails(data.item.queuedItem.unitTemplate || data.item.queuedItem.technologyTemplate, data.playerState.civ); };

View File

@ -272,7 +272,8 @@ function addResearchToQueue(entity, researchType)
Engine.PostNetworkCommand({ Engine.PostNetworkCommand({
"type": "research", "type": "research",
"entity": entity, "entity": entity,
"template": researchType "template": researchType,
"pushFront": Engine.HotkeyIsPressed("session.pushorderfront")
}); });
} }

View File

@ -12,8 +12,9 @@
<repeat count="16"> <repeat count="16">
<object name="unitQueueButton[n]" hidden="true" style="iconButton" type="button" size="2 2 40 40" tooltip_style="sessionToolTipBottom"> <object name="unitQueueButton[n]" hidden="true" style="iconButton" type="button" size="2 2 40 40" tooltip_style="sessionToolTipBottom">
<object name="unitQueueIcon[n]" ghost="true" type="image" size="3 3 35 35"/> <object name="unitQueueIcon[n]" ghost="true" type="image" size="3 3 35 35"/>
<object name="unitQueueProgressSlider[n]" type="image" sprite="queueProgressSlider" ghost="true" size="3 3 35 35" z="20"/> <object name="unitQueueProgressSlider[n]" type="image" sprite="queueProgressSlider" ghost="true" size="3 3 35 35"/>
<object name="unitQueueCount[n]" ghost="true" style="groupIconsText" type="text" z="20"/> <object name="unitQueueCount[n]" ghost="true" style="groupIconsText" type="text" z="20"/>
<object name="unitQueuePausedIcon[n]" ghost="true" type="image" sprite="stretched:session/icons/stop.png" size="3 3 35 35"/>
</object> </object>
</repeat> </repeat>
</object> </object>

View File

@ -940,7 +940,7 @@ m.Entity = m.Class({
return this; return this;
}, },
"train": function(civ, type, count, metadata, promotedTypes) "train": function(civ, type, count, metadata, promotedTypes, pushFront = false)
{ {
let trainable = this.trainableEntities(civ); let trainable = this.trainableEntities(civ);
if (!trainable) if (!trainable)
@ -960,7 +960,8 @@ m.Entity = m.Class({
"template": type, "template": type,
"count": count, "count": count,
"metadata": metadata, "metadata": metadata,
"promoted": promotedTypes "promoted": promotedTypes,
"pushFront": pushFront
}); });
return this; return this;
}, },
@ -985,8 +986,13 @@ m.Entity = m.Class({
return this; return this;
}, },
"research": function(template) { "research": function(template, pushFront = false) {
Engine.PostCommand(PlayerID, { "type": "research", "entity": this.id(), "template": template }); Engine.PostCommand(PlayerID, {
"type": "research",
"entity": this.id(),
"template": template,
"pushFront": pushFront
});
return this; return this;
}, },

View File

@ -692,13 +692,16 @@ GuiInterface.prototype.GetStartedResearch = function(player)
let cmpProductionQueue = Engine.QueryInterface(ret[tech].researcher, IID_ProductionQueue); let cmpProductionQueue = Engine.QueryInterface(ret[tech].researcher, IID_ProductionQueue);
if (cmpProductionQueue) if (cmpProductionQueue)
{ {
ret[tech].progress = cmpProductionQueue.GetQueue()[0].progress; const research = cmpProductionQueue.GetQueue().find(item => item.technologyTemplate === tech);
ret[tech].timeRemaining = cmpProductionQueue.GetQueue()[0].timeRemaining; ret[tech].progress = research.progress;
ret[tech].timeRemaining = research.timeRemaining;
ret[tech].paused = research.paused;
} }
else else
{ {
ret[tech].progress = 0; ret[tech].progress = 0;
ret[tech].timeRemaining = 0; ret[tech].timeRemaining = 0;
ret[tech].paused = true;
} }
} }
return ret; return ret;

View File

@ -47,6 +47,7 @@ ProductionQueue.prototype.Init = function()
"productionStarted": false, // true iff production has started (we have reserved population). "productionStarted": false, // true iff production has started (we have reserved population).
"timeTotal": 15000, // msecs "timeTotal": 15000, // msecs
"timeRemaining": 10000, // msecs "timeRemaining": 10000, // msecs
"paused": false, // Whether the item is currently paused (e.g. not the first item or parent is garrisoned).
"resources": { "wood": 100, ... }, // Total resources of the item when queued. "resources": { "wood": 100, ... }, // Total resources of the item when queued.
"entity": { "entity": {
"template": "units/example", "template": "units/example",
@ -340,10 +341,11 @@ ProductionQueue.prototype.IsTechnologyResearchedOrInProgress = function(tech)
* @param {string} type - The type of production (i.e. "unit" or "technology"). * @param {string} type - The type of production (i.e. "unit" or "technology").
* @param {number} count - The amount of units to be produced. Ignored for a tech. * @param {number} count - The amount of units to be produced. Ignored for a tech.
* @param {any} metadata - Optionally any metadata to be attached to the item. * @param {any} metadata - Optionally any metadata to be attached to the item.
* @param {boolean} pushFront - Whether to push the item to the front of the queue and pause any item(s) currently in progress.
* *
* @return {boolean} - Whether the addition of the item has succeeded. * @return {boolean} - Whether the addition of the item has succeeded.
*/ */
ProductionQueue.prototype.AddItem = function(templateName, type, count, metadata) ProductionQueue.prototype.AddItem = function(templateName, type, count, metadata, pushFront = false)
{ {
// TODO: there should be a way for the GUI to determine whether it's going // TODO: there should be a way for the GUI to determine whether it's going
// to be possible to add a batch (based on resource costs and length limits). // to be possible to add a batch (based on resource costs and length limits).
@ -382,6 +384,7 @@ ProductionQueue.prototype.AddItem = function(templateName, type, count, metadata
"metadata": metadata, "metadata": metadata,
"productionStarted": false, "productionStarted": false,
"resources": {}, // The total resource costs. "resources": {}, // The total resource costs.
"paused": false
}; };
// ToDo: Still some duplication here, some can might be combined, // ToDo: Still some duplication here, some can might be combined,
@ -490,6 +493,13 @@ ProductionQueue.prototype.AddItem = function(templateName, type, count, metadata
return false; return false;
item.id = this.nextID++; item.id = this.nextID++;
if (pushFront)
{
if (this.queue[0])
this.queue[0].paused = true;
this.queue.unshift(item);
}
else
this.queue.push(item); this.queue.push(item);
const cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); const cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
@ -618,6 +628,7 @@ ProductionQueue.prototype.GetQueue = function()
"neededSlots": item.entity?.neededSlots, "neededSlots": item.entity?.neededSlots,
"progress": 1 - (item.timeRemaining / (item.timeTotal || 1)), "progress": 1 - (item.timeRemaining / (item.timeTotal || 1)),
"timeRemaining": item.timeRemaining, "timeRemaining": item.timeRemaining,
"paused": item.paused,
"metadata": item.metadata "metadata": item.metadata
})); }));
}; };
@ -797,6 +808,8 @@ ProductionQueue.prototype.ProgressTimeout = function(data, lateness)
while (this.queue.length) while (this.queue.length)
{ {
let item = this.queue[0]; let item = this.queue[0];
if (item.paused)
item.paused = false;
if (!item.productionStarted) if (!item.productionStarted)
{ {
if (item.entity) if (item.entity)
@ -924,10 +937,14 @@ ProductionQueue.prototype.PauseProduction = function()
{ {
this.StopTimer(); this.StopTimer();
this.paused = true; this.paused = true;
if (this.queue[0])
this.queue[0].paused = true;
}; };
ProductionQueue.prototype.UnpauseProduction = function() ProductionQueue.prototype.UnpauseProduction = function()
{ {
if (this.queue[0])
this.queue[0].paused = false;
delete this.paused; delete this.paused;
this.StartTimer(); this.StartTimer();
}; };

View File

@ -372,10 +372,7 @@ var g_Commands = {
} }
} }
if (queue && queue.GetEntitiesList().indexOf(cmd.template) != -1) if (queue && queue.GetEntitiesList().indexOf(cmd.template) != -1)
if ("metadata" in cmd) queue.AddItem(cmd.template, "unit", +cmd.count, cmd.metadata, cmd.pushFront);
queue.AddItem(cmd.template, "unit", +cmd.count, cmd.metadata);
else
queue.AddItem(cmd.template, "unit", +cmd.count);
} }
}, },
@ -391,7 +388,7 @@ var g_Commands = {
var queue = Engine.QueryInterface(cmd.entity, IID_ProductionQueue); var queue = Engine.QueryInterface(cmd.entity, IID_ProductionQueue);
if (queue) if (queue)
queue.AddItem(cmd.template, "technology"); queue.AddItem(cmd.template, "technology", undefined, cmd.metadata, cmd.pushFront);
}, },
"stop-production": function(player, cmd, data) "stop-production": function(player, cmd, data)