Improvement to autoqueue usability
The graphical interface will show autoqueued units as 'ghost' units so the player gets immediate feedback on what's happening. The autoqueue disengages if it runs out of resources or entity limits: this reflects that the autoqueue cannot resume on its own. By changing the spot where the autoqueue pushes items, the autoqueue no longer 'buffers' one unit in advance, but remains very slightly less efficient than manual queuing. This also prevents cheats from leading to a ton of units accidentally being created. Accepted By: Freagarach Refs #6213 Differential Revision: https://code.wildfiregames.com/D4144 This was SVN commit r25779.
This commit is contained in:
parent
42d6893eb8
commit
956b3f96db
@ -493,22 +493,37 @@ g_SelectionPanels.Queue = {
|
||||
*/
|
||||
"getItems": function(unitEntStates)
|
||||
{
|
||||
let queue = [];
|
||||
const queue = [];
|
||||
let foundNew = true;
|
||||
for (let i = 0; foundNew; ++i)
|
||||
{
|
||||
foundNew = false;
|
||||
for (let state of unitEntStates)
|
||||
for (const state of unitEntStates)
|
||||
{
|
||||
if (!state.production || !state.production.queue[i])
|
||||
continue;
|
||||
queue.push({
|
||||
"producingEnt": state.id,
|
||||
"queuedItem": state.production.queue[i]
|
||||
"queuedItem": state.production.queue[i],
|
||||
"autoqueue": state.production.autoqueue && state.production.queue[i].unitTemplate,
|
||||
});
|
||||
foundNew = true;
|
||||
}
|
||||
}
|
||||
if (!queue.length)
|
||||
return queue;
|
||||
// Add 'ghost' items to show autoqueues.
|
||||
const repeat = [];
|
||||
for (const item of queue)
|
||||
if (item.autoqueue)
|
||||
{
|
||||
const ghostItem = clone(item);
|
||||
ghostItem.ghost = true;
|
||||
repeat.push(ghostItem);
|
||||
}
|
||||
if (repeat.length)
|
||||
for (let i = 0; queue.length < g_SelectionPanels.Queue.getMaxNumberOfItems(); ++i)
|
||||
queue.push(repeat[i % repeat.length]);
|
||||
return queue;
|
||||
},
|
||||
"resizePanel": function(numberOfItems, rowLength)
|
||||
@ -536,10 +551,11 @@ g_SelectionPanels.Queue = {
|
||||
warning("Unknown production queue template " + uneval(queuedItem));
|
||||
return false;
|
||||
}
|
||||
|
||||
data.button.onPress = function() { removeFromProductionQueue(data.item.producingEnt, queuedItem.id); };
|
||||
|
||||
const tooltips = [getEntityNames(template)];
|
||||
if (data.item.ghost)
|
||||
tooltips.push(translate("The auto-queue will try to train this item later."));
|
||||
if (queuedItem.neededSlots)
|
||||
{
|
||||
tooltips.push(coloredText(translate("Insufficient population capacity:"), "red"));
|
||||
@ -553,22 +569,32 @@ g_SelectionPanels.Queue = {
|
||||
|
||||
data.countDisplay.caption = queuedItem.count > 1 ? queuedItem.count : "";
|
||||
|
||||
if (data.item.ghost)
|
||||
{
|
||||
data.button.enabled = false;
|
||||
Engine.GetGUIObjectByName("unitQueueProgressSlider[" + data.i + "]").sprite="color:0 150 250 50";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show the time remaining to finish the first item
|
||||
if (data.i == 0)
|
||||
Engine.GetGUIObjectByName("queueTimeRemaining").caption =
|
||||
Engine.FormatMillisecondsIntoDateStringGMT(queuedItem.timeRemaining, translateWithContext("countdown format", "m:ss"));
|
||||
|
||||
let guiObject = Engine.GetGUIObjectByName("unitQueueProgressSlider[" + data.i + "]");
|
||||
let size = guiObject.size;
|
||||
const guiObject = Engine.GetGUIObjectByName("unitQueueProgressSlider[" + data.i + "]");
|
||||
guiObject.sprite = "queueProgressSlider";
|
||||
const size = guiObject.size;
|
||||
|
||||
// Buttons are assumed to be square, so left/right offsets can be used for top/bottom.
|
||||
size.top = size.left + Math.round(queuedItem.progress * (size.right - size.left));
|
||||
guiObject.size = size;
|
||||
|
||||
if (template.icon)
|
||||
data.icon.sprite = "stretched:session/portraits/" + template.icon;
|
||||
|
||||
data.button.enabled = controlsPlayer(data.player);
|
||||
}
|
||||
|
||||
if (template.icon)
|
||||
data.icon.sprite = (data.item.ghost ? "grayscale:" : "") + "stretched:session/portraits/" + template.icon;
|
||||
|
||||
|
||||
const showTemplateFunc = () => { showTemplateDetails(data.item.queuedItem.unitTemplate || data.item.queuedItem.technologyTemplate, data.playerState.civ); };
|
||||
data.button.onPressRight = showTemplateFunc;
|
||||
|
@ -809,12 +809,6 @@ ProductionQueue.prototype.ProgressTimeout = function(data, lateness)
|
||||
|
||||
cmpPlayer.UnBlockTraining();
|
||||
|
||||
// AutoQueue: We add the second batch after starting the first.
|
||||
// (As opposed to when the first batch finishes.)
|
||||
// This is to make the feature not infinitely better than good micro.
|
||||
if (this.autoqueuing)
|
||||
this.AddItem(item.unitTemplate, "unit", item.count, item.metadata);
|
||||
|
||||
Engine.PostMessage(this.entity, MT_TrainingStarted, { "entity": this.entity });
|
||||
}
|
||||
if (item.technologyTemplate)
|
||||
@ -891,6 +885,26 @@ ProductionQueue.prototype.ProgressTimeout = function(data, lateness)
|
||||
time -= item.timeRemaining;
|
||||
this.queue.shift();
|
||||
Engine.PostMessage(this.entity, MT_ProductionQueueChanged, null);
|
||||
|
||||
// If autoqueuing, push a new unit on the queue immediately,
|
||||
// but don't start right away. This 'wastes' some time, making
|
||||
// autoqueue slightly worse than regular queuing, and also ensures
|
||||
// that autoqueue doesn't train more than one item per turn,
|
||||
// if the units would take fewer than ProgressInterval ms to train.
|
||||
if (this.autoqueuing && item.unitTemplate)
|
||||
{
|
||||
if (!this.AddItem(item.unitTemplate, "unit", item.count, item.metadata))
|
||||
{
|
||||
this.DisableAutoQueue();
|
||||
const cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
|
||||
cmpGUIInterface.PushNotification({
|
||||
"players": [cmpPlayer.GetPlayerID()],
|
||||
"message": markForTranslation("Could not auto-queue unit, de-activating."),
|
||||
"translateMessage": true
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.queue.length)
|
||||
|
@ -615,7 +615,7 @@ function test_auto_queue()
|
||||
cmpProdQueue.AddItem("some_template", "unit", 3);
|
||||
TS_ASSERT_EQUALS(cmpProdQueue.GetQueue().length, 1);
|
||||
cmpProdQueue.ProgressTimeout(null, 0);
|
||||
TS_ASSERT_EQUALS(cmpProdQueue.GetQueue().length, 2);
|
||||
TS_ASSERT_EQUALS(cmpProdQueue.GetQueue().length, 1);
|
||||
}
|
||||
|
||||
testEntitiesList();
|
||||
|
Loading…
Reference in New Issue
Block a user