Merge pull request #6948 from pchote/revert-production-desync

Closes #6910
Closes #6925
Closes #6933
This commit is contained in:
Matthias Mailänder
2014-11-15 00:15:25 +01:00
8 changed files with 55 additions and 91 deletions

View File

@@ -155,19 +155,19 @@ namespace OpenRA
return new Order("Command", null, false) { IsImmediate = true, TargetString = text };
}
public static Order StartProduction(Actor subject, int queueID, string item, int count)
public static Order StartProduction(Actor subject, string item, int count)
{
return new Order("StartProduction", subject, false) { TargetString = item, ExtraLocation = new CPos(queueID, count) };
return new Order("StartProduction", subject, false) { ExtraData = (uint)count, TargetString = item };
}
public static Order PauseProduction(Actor subject, int queueID, string item, bool pause)
public static Order PauseProduction(Actor subject, string item, bool pause)
{
return new Order("PauseProduction", subject, false) { TargetString = item, ExtraLocation = new CPos(queueID, pause ? 1 : 0) };
return new Order("PauseProduction", subject, false) { ExtraData = pause ? 1u : 0u, TargetString = item };
}
public static Order CancelProduction(Actor subject, int queueID, string item, int count)
public static Order CancelProduction(Actor subject, string item, int count)
{
return new Order("CancelProduction", subject, false) { TargetString = item, ExtraLocation = new CPos(queueID, count) };
return new Order("CancelProduction", subject, false) { ExtraData = (uint)count, TargetString = item };
}
// For scripting special powers

View File

@@ -383,7 +383,7 @@ namespace OpenRA.Mods.D2k.Widgets
if (producing.Paused)
{
world.IssueOrder(Order.PauseProduction(CurrentQueue.Actor, CurrentQueue.QueueID, item, false));
world.IssueOrder(Order.PauseProduction(CurrentQueue.Actor, item, false));
return;
}
}
@@ -412,12 +412,12 @@ namespace OpenRA.Mods.D2k.Widgets
Sound.PlayNotification(world.Map.Rules, world.LocalPlayer, "Speech", CurrentQueue.Info.CancelledAudio, world.LocalPlayer.Country.Race);
var numberToCancel = Game.GetModifierKeys().HasModifier(Modifiers.Shift) ? 5 : 1;
world.IssueOrder(Order.CancelProduction(CurrentQueue.Actor, CurrentQueue.QueueID, item, numberToCancel));
world.IssueOrder(Order.CancelProduction(CurrentQueue.Actor, item, numberToCancel));
}
else
{
Sound.PlayNotification(world.Map.Rules, world.LocalPlayer, "Speech", CurrentQueue.Info.OnHoldAudio, world.LocalPlayer.Country.Race);
world.IssueOrder(Order.PauseProduction(CurrentQueue.Actor, CurrentQueue.QueueID, item, true));
world.IssueOrder(Order.PauseProduction(CurrentQueue.Actor, item, true));
}
}
}
@@ -425,7 +425,7 @@ namespace OpenRA.Mods.D2k.Widgets
void StartProduction(World world, string item)
{
world.IssueOrder(Order.StartProduction(CurrentQueue.Actor, CurrentQueue.QueueID, item,
world.IssueOrder(Order.StartProduction(CurrentQueue.Actor, item,
Game.GetModifierKeys().HasModifier(Modifiers.Shift) ? 5 : 1));
}

View File

@@ -71,7 +71,7 @@ namespace OpenRA.Mods.RA.AI
return false;
HackyAI.BotDebug("AI: {0} is starting production of {1}".F(player, item.Name));
world.IssueOrder(Order.StartProduction(queue.Actor, queue.QueueID, item.Name, 1));
world.IssueOrder(Order.StartProduction(queue.Actor, item.Name, 1));
}
// Production is complete
@@ -89,7 +89,7 @@ namespace OpenRA.Mods.RA.AI
if (location == null)
{
HackyAI.BotDebug("AI: {0} has nowhere to place {1}".F(player, currentBuilding.Item));
world.IssueOrder(Order.CancelProduction(queue.Actor, queue.QueueID, currentBuilding.Item, 1));
world.IssueOrder(Order.CancelProduction(queue.Actor, currentBuilding.Item, 1));
}
else
{

View File

@@ -886,7 +886,7 @@ namespace OpenRA.Mods.RA.AI
ChooseUnitToBuild(queue);
if (unit != null && Info.UnitsToBuild.Any(u => u.Key == unit.Name))
world.IssueOrder(Order.StartProduction(queue.Actor, queue.QueueID, unit.Name, 1));
world.IssueOrder(Order.StartProduction(queue.Actor, unit.Name, 1));
}
void BuildUnit(string category, string name)
@@ -896,7 +896,7 @@ namespace OpenRA.Mods.RA.AI
return;
if (Map.Rules.Actors[name] != null)
world.IssueOrder(Order.StartProduction(queue.Actor, queue.QueueID, name, 1));
world.IssueOrder(Order.StartProduction(queue.Actor, name, 1));
}
public void Damaged(Actor self, AttackInfo e)

View File

@@ -69,10 +69,7 @@ namespace OpenRA.Mods.RA
public class ProductionQueue : IResolveOrder, ITick, ITechTreeElement, INotifyOwnerChanged, INotifyKilled, INotifySold, ISync, INotifyTransform
{
static int nextQueueID = 1;
public readonly ProductionQueueInfo Info;
public readonly int QueueID;
readonly Actor self;
// Will change if the owner changes
@@ -83,7 +80,6 @@ namespace OpenRA.Mods.RA
// A list of things we could possibly build
Dictionary<ActorInfo, ProductionState> produceable;
List<ProductionItem> queue = new List<ProductionItem>();
bool allTech = false;
// A list of things we are currently building
public Actor Actor { get { return self; } }
@@ -97,8 +93,6 @@ namespace OpenRA.Mods.RA
[Sync] public bool Enabled { get; private set; }
public string Race { get; private set; }
public int Name = 0;
public string DisplayName = "";
public ProductionQueue(ActorInitializer init, Actor playerActor, ProductionQueueInfo info)
{
@@ -109,8 +103,7 @@ namespace OpenRA.Mods.RA
developerMode = playerActor.Trait<DeveloperMode>();
Race = init.Contains<RaceInit>() ? init.Get<RaceInit, string>() : self.Owner.Country.Race;
Enabled = (!Info.Race.Any() || Info.Race.Contains(Race)) || developerMode.AllTech;
QueueID = nextQueueID++;
Enabled = !info.Race.Any() || info.Race.Contains(Race);
CacheProduceables(playerActor);
}
@@ -136,7 +129,7 @@ namespace OpenRA.Mods.RA
if (!Info.Sticky)
{
Race = self.Owner.Country.Race;
Enabled = (!Info.Race.Any() || Info.Race.Contains(Race)) || developerMode.AllTech;
Enabled = !Info.Race.Any() || Info.Race.Contains(Race);
}
// Regenerate the produceables and tech tree state
@@ -244,27 +237,6 @@ namespace OpenRA.Mods.RA
public virtual void Tick(Actor self)
{
if (self.World.AllowDevCommands && developerMode.AllTech != allTech)
{
allTech = developerMode.AllTech;
Enabled = (!Info.Race.Any() || Info.Race.Contains(Race)) || developerMode.AllTech;
OnOwnerChanged(self, self.Owner, self.Owner);
self.World.AddFrameEndTask((World w) => {
var selected = w.Selection.Contains(self);
var controlgroup = w.Selection.GetControlGroupForActor(self);
w.Remove(self); // force production palettes to update
w.Add(self);
if (selected)
w.Selection.Add(w, self);
if (controlgroup.HasValue)
w.Selection.AddToControlGroup(self, controlgroup.Value);
});
}
while (queue.Count > 0 && BuildableItems().All(b => b.Name != queue[0].Item))
{
playerResources.GiveCash(queue[0].TotalCost - queue[0].RemainingCost); // refund what's been paid so far.
@@ -284,9 +256,6 @@ namespace OpenRA.Mods.RA
{
case "StartProduction":
{
if (order.ExtraLocation.X != QueueID)
return;
var unit = self.World.Map.Rules.Actors[order.TargetString];
var bi = unit.Traits.Get<BuildableInfo>();
if (!bi.Queue.Contains(Info.Type))
@@ -310,7 +279,7 @@ namespace OpenRA.Mods.RA
return;
}
var amountToBuild = Math.Min(fromLimit, order.ExtraLocation.Y);
var amountToBuild = Math.Min(fromLimit, order.ExtraData);
for (var n = 0; n < amountToBuild; n++)
{
var hasPlayedSound = false;
@@ -338,19 +307,15 @@ namespace OpenRA.Mods.RA
case "PauseProduction":
{
if (order.ExtraLocation.X != QueueID)
return;
if (queue.Count > 0 && queue[0].Item == order.TargetString)
queue[0].Pause(order.ExtraLocation.Y != 0);
queue[0].Pause(order.ExtraData != 0);
break;
}
case "CancelProduction":
{
if (order.ExtraLocation.X != QueueID)
return;
CancelProduction(order.TargetString, (uint)order.ExtraLocation.Y);
CancelProduction(order.TargetString, order.ExtraData);
break;
}
}

View File

@@ -140,7 +140,7 @@ namespace OpenRA.Mods.RA.Scripting
}
foreach (var actorType in actorTypes)
queue.ResolveOrder(self, Order.StartProduction(self, queue.QueueID, actorType, 1));
queue.ResolveOrder(self, Order.StartProduction(self, actorType, 1));
return true;
}
@@ -245,7 +245,7 @@ namespace OpenRA.Mods.RA.Scripting
foreach (var actorType in actorTypes)
{
var queue = queues[typeToQueueMap[actorType]];
queue.ResolveOrder(queue.Actor, Order.StartProduction(queue.Actor, queue.QueueID, actorType, 1));
queue.ResolveOrder(queue.Actor, Order.StartProduction(queue.Actor, actorType, 1));
}
return true;

View File

@@ -150,14 +150,14 @@ namespace OpenRA.Mods.RA.Widgets
{
// Resume a paused item
Sound.Play(TabClick);
World.IssueOrder(Order.PauseProduction(CurrentQueue.Actor, CurrentQueue.QueueID, icon.Name, false));
World.IssueOrder(Order.PauseProduction(CurrentQueue.Actor, icon.Name, false));
}
else if (CurrentQueue.BuildableItems().Any(a => a.Name == icon.Name))
{
// Queue a new item
Sound.Play(TabClick);
Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Speech", CurrentQueue.Info.QueuedAudio, World.LocalPlayer.Country.Race);
World.IssueOrder(Order.StartProduction(CurrentQueue.Actor, CurrentQueue.QueueID, icon.Name,
World.IssueOrder(Order.StartProduction(CurrentQueue.Actor, icon.Name,
handleMultiple ? 5 : 1));
}
else
@@ -174,13 +174,13 @@ namespace OpenRA.Mods.RA.Widgets
if (first.Paused || first.Done || first.TotalCost == first.RemainingCost)
{
Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Speech", CurrentQueue.Info.CancelledAudio, World.LocalPlayer.Country.Race);
World.IssueOrder(Order.CancelProduction(CurrentQueue.Actor, CurrentQueue.QueueID, icon.Name,
World.IssueOrder(Order.CancelProduction(CurrentQueue.Actor, icon.Name,
handleMultiple ? 5 : 1));
}
else
{
Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Speech", CurrentQueue.Info.OnHoldAudio, World.LocalPlayer.Country.Race);
World.IssueOrder(Order.PauseProduction(CurrentQueue.Actor, CurrentQueue.QueueID, icon.Name, true));
World.IssueOrder(Order.PauseProduction(CurrentQueue.Actor, icon.Name, true));
}
}
else

View File

@@ -18,43 +18,42 @@ using OpenRA.Widgets;
namespace OpenRA.Mods.RA.Widgets
{
public class ProductionTab
{
public string Name;
public ProductionQueue Queue;
}
public class ProductionTabGroup
{
public List<ProductionQueue> Tabs = new List<ProductionQueue>();
public List<ProductionTab> Tabs = new List<ProductionTab>();
public string Group;
public bool Alert { get { return Tabs.Any(t => t.CurrentDone); } }
public int NextQueueName = 1;
public bool Alert { get { return Tabs.Any(t => t.Queue.CurrentDone); } }
public void Update(IEnumerable<ProductionQueue> allQueues)
{
var queues = allQueues.Where(q => q.Info.Group == Group).ToList();
var names = new Queue<int>(Enumerable.Range(1, queues.Count).Except(queues.Select(q => q.Name)));
var tabs = new List<ProductionTab>();
// Assign names based on available numbers
foreach (var queue in queues.Where(q => q.Name == 0))
// Remove stale queues
foreach (var t in Tabs)
{
foreach (var q in queues.Where(q => q.Name > 0))
if (queue.Actor == q.Actor)
queue.Name = q.Name;
if (queue.Name == 0)
queue.Name = names.Dequeue();
if (!queues.Contains(t.Queue))
continue;
tabs.Add(t);
queues.Remove(t.Queue);
}
Tabs = queues.OrderBy(q => q.Name).ToList();
// distinction between tabs of the same actor
foreach (var group in queues.GroupBy(q => q.Actor))
{
if (group.Count() > 1)
// Add new queues
foreach (var queue in queues)
tabs.Add(new ProductionTab()
{
var n = 'a';
foreach (var queue in group)
queue.DisplayName = queue.Name + (n++).ToString();
}
else
group.First().DisplayName = group.First().Name.ToString();
}
Name = (NextQueueName++).ToString(),
Queue = queue
});
Tabs = tabs;
}
}
@@ -99,7 +98,7 @@ namespace OpenRA.Mods.RA.Widgets
return true;
// Prioritize alerted queues
var queues = Groups[queueGroup].Tabs.Select(t => t)
var queues = Groups[queueGroup].Tabs.Select(t => t.Queue)
.OrderByDescending(q => q.CurrentDone ? 1 : 0)
.ToList();
@@ -172,13 +171,13 @@ namespace OpenRA.Mods.RA.Widgets
{
var rect = new Rectangle(origin.X + contentWidth, origin.Y, TabWidth, rb.Height);
var hover = !leftHover && !rightHover && Ui.MouseOverWidget == this && rect.Contains(Viewport.LastMousePos);
var baseName = tab == CurrentQueue ? "button-highlighted" : "button";
var baseName = tab.Queue == CurrentQueue ? "button-highlighted" : "button";
ButtonWidget.DrawBackground(baseName, rect, false, false, hover, false);
contentWidth += TabWidth - 1;
var textSize = font.Measure(tab.DisplayName);
var textSize = font.Measure(tab.Name);
var position = new int2(rect.X + (rect.Width - textSize.X) / 2, rect.Y + (rect.Height - textSize.Y) / 2);
font.DrawTextWithContrast(tab.DisplayName, position, tab.CurrentDone ? Color.Gold : Color.White, Color.Black, 1);
font.DrawTextWithContrast(tab.Name, position, tab.Queue.CurrentDone ? Color.Gold : Color.White, Color.Black, 1);
}
Game.Renderer.DisableScissor();
@@ -211,7 +210,7 @@ namespace OpenRA.Mods.RA.Widgets
.Select(g => g.Key).FirstOrDefault();
// Queue destroyed, others of same type: switch to another tab
else if (!Groups[queueGroup].Tabs.Contains(CurrentQueue))
else if (!Groups[queueGroup].Tabs.Select(t => t.Queue).Contains(CurrentQueue))
SelectNextTab(false);
}
}
@@ -265,7 +264,7 @@ namespace OpenRA.Mods.RA.Widgets
var offsetloc = mi.Location - new int2(leftButtonRect.Right - 1 + (int)listOffset, leftButtonRect.Y);
if (offsetloc.X > 0 && offsetloc.X < contentWidth)
{
CurrentQueue = Groups[queueGroup].Tabs[offsetloc.X / (TabWidth - 1)];
CurrentQueue = Groups[queueGroup].Tabs[offsetloc.X / (TabWidth - 1)].Queue;
Sound.PlayNotification(world.Map.Rules, null, "Sounds", "ClickSound", null);
}