Enable paying upfront
Fix tab availability on low money Co-Authored-By: Gustas <37534529+PunkPun@users.noreply.github.com>
This commit is contained in:
@@ -38,6 +38,9 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
[Desc("Should the prerequisite remain enabled if the owner changes?")]
|
[Desc("Should the prerequisite remain enabled if the owner changes?")]
|
||||||
public readonly bool Sticky = true;
|
public readonly bool Sticky = true;
|
||||||
|
|
||||||
|
[Desc("Player must pay for item upfront")]
|
||||||
|
public readonly bool PayUpFront = false;
|
||||||
|
|
||||||
[Desc("Should right clicking on the icon instantly cancel the production instead of putting it on hold?")]
|
[Desc("Should right clicking on the icon instantly cancel the production instead of putting it on hold?")]
|
||||||
public readonly bool DisallowPaused = false;
|
public readonly bool DisallowPaused = false;
|
||||||
|
|
||||||
@@ -185,7 +188,16 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
{
|
{
|
||||||
// Refund the current item
|
// Refund the current item
|
||||||
foreach (var item in Queue)
|
foreach (var item in Queue)
|
||||||
|
{
|
||||||
|
if (item.ResourcesPaid > 0)
|
||||||
|
{
|
||||||
|
playerResources.GiveResources(item.ResourcesPaid);
|
||||||
|
item.RemainingCost += item.ResourcesPaid;
|
||||||
|
}
|
||||||
|
|
||||||
playerResources.GiveCash(item.TotalCost - item.RemainingCost);
|
playerResources.GiveCash(item.TotalCost - item.RemainingCost);
|
||||||
|
}
|
||||||
|
|
||||||
Queue.Clear();
|
Queue.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,6 +279,11 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
return Queue.Count > 0 && Queue[0] == item;
|
return Queue.Count > 0 && Queue[0] == item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual bool IsInQueue(ActorInfo actor)
|
||||||
|
{
|
||||||
|
return Queue.Any(i => i.Item == actor.Name);
|
||||||
|
}
|
||||||
|
|
||||||
public ProductionItem CurrentItem()
|
public ProductionItem CurrentItem()
|
||||||
{
|
{
|
||||||
return Queue.ElementAtOrDefault(0);
|
return Queue.ElementAtOrDefault(0);
|
||||||
@@ -293,12 +310,22 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
return Enumerable.Empty<ActorInfo>();
|
return Enumerable.Empty<ActorInfo>();
|
||||||
if (!Enabled)
|
if (!Enabled)
|
||||||
return Enumerable.Empty<ActorInfo>();
|
return Enumerable.Empty<ActorInfo>();
|
||||||
if (developerMode.AllTech)
|
if (!Info.PayUpFront && developerMode.AllTech)
|
||||||
return Producible.Keys;
|
return Producible.Keys;
|
||||||
|
if (Info.PayUpFront && developerMode.AllTech)
|
||||||
|
return Producible.Keys.Where(a => GetProductionCost(a) <= playerResources.GetCashAndResources() || IsInQueue(a));
|
||||||
|
if (Info.PayUpFront)
|
||||||
|
return buildableProducibles.Where(a => GetProductionCost(a) <= playerResources.GetCashAndResources() || IsInQueue(a));
|
||||||
return buildableProducibles;
|
return buildableProducibles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual bool AnyItemsToBuild()
|
||||||
|
{
|
||||||
|
return Enabled
|
||||||
|
&& (productionTraits.Length <= 0 || productionTraits.Any(p => p.IsTraitDisabled))
|
||||||
|
&& ((developerMode.AllTech && Producible.Keys.Count != 0) || buildableProducibles.Any());
|
||||||
|
}
|
||||||
|
|
||||||
public bool CanBuild(ActorInfo actor)
|
public bool CanBuild(ActorInfo actor)
|
||||||
{
|
{
|
||||||
if (!Producible.TryGetValue(actor, out var ps))
|
if (!Producible.TryGetValue(actor, out var ps))
|
||||||
@@ -352,6 +379,13 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (buildableNames.Contains(Queue[i].Item))
|
if (buildableNames.Contains(Queue[i].Item))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Refund spended resources
|
||||||
|
if (Queue[i].ResourcesPaid > 0)
|
||||||
|
{
|
||||||
|
playerResources.GiveResources(Queue[i].ResourcesPaid);
|
||||||
|
Queue[i].RemainingCost += Queue[i].ResourcesPaid;
|
||||||
|
}
|
||||||
|
|
||||||
// Refund what's been paid so far
|
// Refund what's been paid so far
|
||||||
playerResources.GiveCash(Queue[i].TotalCost - Queue[i].RemainingCost);
|
playerResources.GiveCash(Queue[i].TotalCost - Queue[i].RemainingCost);
|
||||||
EndProduction(Queue[i]);
|
EndProduction(Queue[i]);
|
||||||
@@ -369,6 +403,9 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
if (!developerMode.AllTech)
|
if (!developerMode.AllTech)
|
||||||
{
|
{
|
||||||
|
if (Info.PayUpFront && actor.TraitInfo<ValuedInfo>().Cost > playerResources.GetCashAndResources())
|
||||||
|
return false;
|
||||||
|
|
||||||
if (Info.QueueLimit > 0 && Queue.Count >= Info.QueueLimit)
|
if (Info.QueueLimit > 0 && Queue.Count >= Info.QueueLimit)
|
||||||
{
|
{
|
||||||
notificationAudio = Info.LimitedAudio;
|
notificationAudio = Info.LimitedAudio;
|
||||||
@@ -444,6 +481,8 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
var amountToBuild = Math.Min(fromLimit, order.ExtraData);
|
var amountToBuild = Math.Min(fromLimit, order.ExtraData);
|
||||||
for (var n = 0; n < amountToBuild; n++)
|
for (var n = 0; n < amountToBuild; n++)
|
||||||
{
|
{
|
||||||
|
if (Info.PayUpFront && cost > playerResources.GetCashAndResources())
|
||||||
|
return;
|
||||||
var hasPlayedSound = false;
|
var hasPlayedSound = false;
|
||||||
BeginProduction(new ProductionItem(this, order.TargetString, cost, playerPower, () => self.World.AddFrameEndTask(_ =>
|
BeginProduction(new ProductionItem(this, order.TargetString, cost, playerPower, () => self.World.AddFrameEndTask(_ =>
|
||||||
{
|
{
|
||||||
@@ -540,6 +579,12 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Refund what has been paid
|
// Refund what has been paid
|
||||||
|
if (item.ResourcesPaid > 0)
|
||||||
|
{
|
||||||
|
playerResources.GiveResources(item.ResourcesPaid);
|
||||||
|
item.RemainingCost += item.ResourcesPaid;
|
||||||
|
}
|
||||||
|
|
||||||
playerResources.GiveCash(item.TotalCost - item.RemainingCost);
|
playerResources.GiveCash(item.TotalCost - item.RemainingCost);
|
||||||
EndProduction(item);
|
EndProduction(item);
|
||||||
}
|
}
|
||||||
@@ -560,9 +605,19 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
protected virtual void BeginProduction(ProductionItem item, bool hasPriority)
|
protected virtual void BeginProduction(ProductionItem item, bool hasPriority)
|
||||||
{
|
{
|
||||||
|
if (Info.PayUpFront)
|
||||||
|
{
|
||||||
|
if (playerResources.Resources > 0 && playerResources.Resources <= item.TotalCost)
|
||||||
|
item.ResourcesPaid = playerResources.Resources;
|
||||||
|
else if (playerResources.Resources > item.TotalCost)
|
||||||
|
item.ResourcesPaid = item.TotalCost;
|
||||||
|
|
||||||
|
playerResources.TakeCash(item.TotalCost);
|
||||||
|
item.RemainingCost = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (Queue.Any(i => i.Item == item.Item && i.Infinite))
|
if (Queue.Any(i => i.Item == item.Item && i.Infinite))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (hasPriority && Queue.Count > 1)
|
if (hasPriority && Queue.Count > 1)
|
||||||
Queue.Insert(1, item);
|
Queue.Insert(1, item);
|
||||||
else
|
else
|
||||||
@@ -581,6 +636,12 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
for (var i = 1; i < queued.Count; i++)
|
for (var i = 1; i < queued.Count; i++)
|
||||||
{
|
{
|
||||||
// Refund what has been paid
|
// Refund what has been paid
|
||||||
|
if (queued[i].ResourcesPaid > 0)
|
||||||
|
{
|
||||||
|
playerResources.GiveResources(queued[i].ResourcesPaid);
|
||||||
|
queued[i].RemainingCost += queued[i].ResourcesPaid;
|
||||||
|
}
|
||||||
|
|
||||||
playerResources.GiveCash(queued[i].TotalCost - queued[i].RemainingCost);
|
playerResources.GiveCash(queued[i].TotalCost - queued[i].RemainingCost);
|
||||||
EndProduction(queued[i]);
|
EndProduction(queued[i]);
|
||||||
}
|
}
|
||||||
@@ -645,10 +706,10 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
public readonly ProductionQueue Queue;
|
public readonly ProductionQueue Queue;
|
||||||
public readonly int TotalCost;
|
public readonly int TotalCost;
|
||||||
public readonly Action OnComplete;
|
public readonly Action OnComplete;
|
||||||
|
|
||||||
public int TotalTime { get; private set; }
|
public int TotalTime { get; private set; }
|
||||||
public int RemainingTime { get; private set; }
|
public int RemainingTime { get; private set; }
|
||||||
public int RemainingCost { get; private set; }
|
public int RemainingCost { get; set; }
|
||||||
|
public int ResourcesPaid { get; set; }
|
||||||
public int RemainingTimeActual =>
|
public int RemainingTimeActual =>
|
||||||
(pm == null || pm.PowerState == PowerState.Normal) ? RemainingTime :
|
(pm == null || pm.PowerState == PowerState.Normal) ? RemainingTime :
|
||||||
RemainingTime * Queue.Info.LowPowerModifier / 100;
|
RemainingTime * Queue.Info.LowPowerModifier / 100;
|
||||||
@@ -669,6 +730,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
Item = item;
|
Item = item;
|
||||||
RemainingTime = TotalTime = 1;
|
RemainingTime = TotalTime = 1;
|
||||||
RemainingCost = TotalCost = cost;
|
RemainingCost = TotalCost = cost;
|
||||||
|
ResourcesPaid = 0;
|
||||||
OnComplete = onComplete;
|
OnComplete = onComplete;
|
||||||
Queue = queue;
|
Queue = queue;
|
||||||
this.pm = pm;
|
this.pm = pm;
|
||||||
@@ -685,7 +747,6 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
var time = Queue.GetBuildTime(ai, bi);
|
var time = Queue.GetBuildTime(ai, bi);
|
||||||
if (time > 0)
|
if (time > 0)
|
||||||
RemainingTime = TotalTime = time;
|
RemainingTime = TotalTime = time;
|
||||||
|
|
||||||
Started = true;
|
Started = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -708,12 +769,23 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Queue.Info.PayUpFront)
|
||||||
|
{
|
||||||
var expectedRemainingCost = RemainingTime == 1 ? 0 : TotalCost * RemainingTime / Math.Max(1, TotalTime);
|
var expectedRemainingCost = RemainingTime == 1 ? 0 : TotalCost * RemainingTime / Math.Max(1, TotalTime);
|
||||||
var costThisFrame = RemainingCost - expectedRemainingCost;
|
var costThisFrame = RemainingCost - expectedRemainingCost;
|
||||||
|
if (pr.Resources > 0 && pr.Resources <= costThisFrame)
|
||||||
|
ResourcesPaid += pr.Resources;
|
||||||
|
else if (pr.Resources > costThisFrame)
|
||||||
|
ResourcesPaid += costThisFrame;
|
||||||
if (costThisFrame != 0 && !pr.TakeCash(costThisFrame, true))
|
if (costThisFrame != 0 && !pr.TakeCash(costThisFrame, true))
|
||||||
|
{
|
||||||
|
ResourcesPaid -= pr.Resources;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
RemainingCost -= costThisFrame;
|
RemainingCost -= costThisFrame;
|
||||||
|
}
|
||||||
|
|
||||||
RemainingTime--;
|
RemainingTime--;
|
||||||
if (RemainingTime > 0)
|
if (RemainingTime > 0)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
.FirstOrDefault(q => q.Enabled && types.Contains(q.Info.Type));
|
.FirstOrDefault(q => q.Enabled && types.Contains(q.Info.Type));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (queue == null || !queue.BuildableItems().Any())
|
if (queue == null || !queue.AnyItemsToBuild())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (tabsWidget.Value != null)
|
if (tabsWidget.Value != null)
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
palette.PickUpCompletedBuilding();
|
palette.PickUpCompletedBuilding();
|
||||||
}
|
}
|
||||||
|
|
||||||
button.IsDisabled = () => !queues.Any(q => q.BuildableItems().Any());
|
button.IsDisabled = () => !queues.Any(q => q.AnyItemsToBuild());
|
||||||
button.OnMouseUp = mi => SelectTab(mi.Modifiers.HasModifier(Modifiers.Shift));
|
button.OnMouseUp = mi => SelectTab(mi.Modifiers.HasModifier(Modifiers.Shift));
|
||||||
button.OnKeyPress = e => SelectTab(e.Modifiers.HasModifier(Modifiers.Shift));
|
button.OnKeyPress = e => SelectTab(e.Modifiers.HasModifier(Modifiers.Shift));
|
||||||
button.OnClick = () => SelectTab(false);
|
button.OnClick = () => SelectTab(false);
|
||||||
|
|||||||
@@ -338,8 +338,11 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
|
|
||||||
if (buildable != null)
|
if (buildable != null)
|
||||||
{
|
{
|
||||||
// Queue a new item
|
if (CurrentQueue.Info.PayUpFront && currentQueue.GetProductionCost(buildable) > CurrentQueue.Actor.Owner.PlayerActor.Trait<PlayerResources>().GetCashAndResources())
|
||||||
|
return false;
|
||||||
Game.Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Sounds", ClickSound, null);
|
Game.Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Sounds", ClickSound, null);
|
||||||
|
|
||||||
|
// Queue a new item
|
||||||
var canQueue = CurrentQueue.CanQueue(buildable, out var notification, out var textNotification);
|
var canQueue = CurrentQueue.CanQueue(buildable, out var notification, out var textNotification);
|
||||||
|
|
||||||
if (!CurrentQueue.AllQueued().Any())
|
if (!CurrentQueue.AllQueued().Any())
|
||||||
@@ -366,7 +369,7 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
|
|
||||||
Game.Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Sounds", ClickSound, null);
|
Game.Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Sounds", ClickSound, null);
|
||||||
|
|
||||||
if (CurrentQueue.Info.DisallowPaused || item.Paused || item.Done || item.TotalCost == item.RemainingCost)
|
if (CurrentQueue.Info.DisallowPaused || item.Paused || item.Done || item.TotalCost == item.RemainingCost || !item.Started)
|
||||||
{
|
{
|
||||||
// Instantly cancel items that haven't started, have finished, or if the queue doesn't support pausing
|
// Instantly cancel items that haven't started, have finished, or if the queue doesn't support pausing
|
||||||
Game.Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Speech", CurrentQueue.Info.CancelledAudio, World.LocalPlayer.Faction.InternalName);
|
Game.Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Speech", CurrentQueue.Info.CancelledAudio, World.LocalPlayer.Faction.InternalName);
|
||||||
|
|||||||
Reference in New Issue
Block a user