Skip to content

Commit ccb1bd7

Browse files
PorenutakPunkPun
andcommitted
Enable paying upfront
Fix tab availability on low money Co-Authored-By: Gustas <[email protected]>
1 parent 2a3271b commit ccb1bd7

File tree

4 files changed

+90
-15
lines changed

4 files changed

+90
-15
lines changed

OpenRA.Mods.Common/Traits/Player/ProductionQueue.cs

Lines changed: 83 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ public class ProductionQueueInfo : TraitInfo, IRulesetLoaded
3838
[Desc("Should the prerequisite remain enabled if the owner changes?")]
3939
public readonly bool Sticky = true;
4040

41+
[Desc("Player must pay for item upfront")]
42+
public readonly bool PayUpFront = false;
43+
4144
[Desc("Should right clicking on the icon instantly cancel the production instead of putting it on hold?")]
4245
public readonly bool DisallowPaused = false;
4346

@@ -185,7 +188,16 @@ protected void ClearQueue()
185188
{
186189
// Refund the current item
187190
foreach (var item in Queue)
191+
{
192+
if (item.ResourcesPaid > 0)
193+
{
194+
playerResources.GiveResources(item.ResourcesPaid);
195+
item.RemainingCost += item.ResourcesPaid;
196+
}
197+
188198
playerResources.GiveCash(item.TotalCost - item.RemainingCost);
199+
}
200+
189201
Queue.Clear();
190202
}
191203

@@ -267,6 +279,11 @@ public virtual bool IsProducing(ProductionItem item)
267279
return Queue.Count > 0 && Queue[0] == item;
268280
}
269281

282+
public virtual bool IsInQueue(ActorInfo actor)
283+
{
284+
return Queue.Any(i => i.Item == actor.Name);
285+
}
286+
270287
public ProductionItem CurrentItem()
271288
{
272289
return Queue.ElementAtOrDefault(0);
@@ -293,12 +310,22 @@ public virtual IEnumerable<ActorInfo> BuildableItems()
293310
return Enumerable.Empty<ActorInfo>();
294311
if (!Enabled)
295312
return Enumerable.Empty<ActorInfo>();
296-
if (developerMode.AllTech)
313+
if (!Info.PayUpFront && developerMode.AllTech)
297314
return Producible.Keys;
298-
315+
if (Info.PayUpFront && developerMode.AllTech)
316+
return Producible.Keys.Where(a => GetProductionCost(a) <= playerResources.GetCashAndResources() || IsInQueue(a));
317+
if (Info.PayUpFront)
318+
return buildableProducibles.Where(a => GetProductionCost(a) <= playerResources.GetCashAndResources() || IsInQueue(a));
299319
return buildableProducibles;
300320
}
301321

322+
public virtual bool AnyItemsToBuild()
323+
{
324+
return Enabled
325+
&& (productionTraits.Length <= 0 || productionTraits.Any(p => p.IsTraitDisabled))
326+
&& ((developerMode.AllTech && Producible.Keys.Count != 0) || buildableProducibles.Any());
327+
}
328+
302329
public bool CanBuild(ActorInfo actor)
303330
{
304331
if (!Producible.TryGetValue(actor, out var ps))
@@ -352,6 +379,13 @@ protected void CancelUnbuildableItems()
352379
if (buildableNames.Contains(Queue[i].Item))
353380
continue;
354381

382+
// Refund spended resources
383+
if (Queue[i].ResourcesPaid > 0)
384+
{
385+
playerResources.GiveResources(Queue[i].ResourcesPaid);
386+
Queue[i].RemainingCost += Queue[i].ResourcesPaid;
387+
}
388+
355389
// Refund what's been paid so far
356390
playerResources.GiveCash(Queue[i].TotalCost - Queue[i].RemainingCost);
357391
EndProduction(Queue[i]);
@@ -369,6 +403,9 @@ public bool CanQueue(ActorInfo actor, out string notificationAudio, out string n
369403

370404
if (!developerMode.AllTech)
371405
{
406+
if (Info.PayUpFront && actor.TraitInfo<ValuedInfo>().Cost > playerResources.GetCashAndResources())
407+
return false;
408+
372409
if (Info.QueueLimit > 0 && Queue.Count >= Info.QueueLimit)
373410
{
374411
notificationAudio = Info.LimitedAudio;
@@ -444,6 +481,8 @@ public void ResolveOrder(Actor self, Order order)
444481
var amountToBuild = Math.Min(fromLimit, order.ExtraData);
445482
for (var n = 0; n < amountToBuild; n++)
446483
{
484+
if (Info.PayUpFront && cost > playerResources.GetCashAndResources())
485+
return;
447486
var hasPlayedSound = false;
448487
BeginProduction(new ProductionItem(this, order.TargetString, cost, playerPower, () => self.World.AddFrameEndTask(_ =>
449488
{
@@ -540,6 +579,12 @@ protected bool CancelProductionInner(string itemName)
540579
else
541580
{
542581
// Refund what has been paid
582+
if (item.ResourcesPaid > 0)
583+
{
584+
playerResources.GiveResources(item.ResourcesPaid);
585+
item.RemainingCost += item.ResourcesPaid;
586+
}
587+
543588
playerResources.GiveCash(item.TotalCost - item.RemainingCost);
544589
EndProduction(item);
545590
}
@@ -560,9 +605,19 @@ public void EndProduction(ProductionItem item)
560605

561606
protected virtual void BeginProduction(ProductionItem item, bool hasPriority)
562607
{
608+
if (Info.PayUpFront)
609+
{
610+
if (playerResources.Resources > 0 && playerResources.Resources <= item.TotalCost)
611+
item.ResourcesPaid = playerResources.Resources;
612+
else if (playerResources.Resources > item.TotalCost)
613+
item.ResourcesPaid = item.TotalCost;
614+
615+
playerResources.TakeCash(item.TotalCost);
616+
item.RemainingCost = 0;
617+
}
618+
563619
if (Queue.Any(i => i.Item == item.Item && i.Infinite))
564620
return;
565-
566621
if (hasPriority && Queue.Count > 1)
567622
Queue.Insert(1, item);
568623
else
@@ -581,6 +636,12 @@ protected virtual void BeginProduction(ProductionItem item, bool hasPriority)
581636
for (var i = 1; i < queued.Count; i++)
582637
{
583638
// Refund what has been paid
639+
if (queued[i].ResourcesPaid > 0)
640+
{
641+
playerResources.GiveResources(queued[i].ResourcesPaid);
642+
queued[i].RemainingCost += queued[i].ResourcesPaid;
643+
}
644+
584645
playerResources.GiveCash(queued[i].TotalCost - queued[i].RemainingCost);
585646
EndProduction(queued[i]);
586647
}
@@ -645,10 +706,10 @@ public class ProductionItem
645706
public readonly ProductionQueue Queue;
646707
public readonly int TotalCost;
647708
public readonly Action OnComplete;
648-
649709
public int TotalTime { get; private set; }
650710
public int RemainingTime { get; private set; }
651-
public int RemainingCost { get; private set; }
711+
public int RemainingCost { get; set; }
712+
public int ResourcesPaid { get; set; }
652713
public int RemainingTimeActual =>
653714
(pm == null || pm.PowerState == PowerState.Normal) ? RemainingTime :
654715
RemainingTime * Queue.Info.LowPowerModifier / 100;
@@ -669,6 +730,7 @@ public ProductionItem(ProductionQueue queue, string item, int cost, PowerManager
669730
Item = item;
670731
RemainingTime = TotalTime = 1;
671732
RemainingCost = TotalCost = cost;
733+
ResourcesPaid = 0;
672734
OnComplete = onComplete;
673735
Queue = queue;
674736
this.pm = pm;
@@ -685,7 +747,6 @@ public void Tick(PlayerResources pr)
685747
var time = Queue.GetBuildTime(ai, bi);
686748
if (time > 0)
687749
RemainingTime = TotalTime = time;
688-
689750
Started = true;
690751
}
691752

@@ -708,12 +769,23 @@ public void Tick(PlayerResources pr)
708769
return;
709770
}
710771

711-
var expectedRemainingCost = RemainingTime == 1 ? 0 : TotalCost * RemainingTime / Math.Max(1, TotalTime);
712-
var costThisFrame = RemainingCost - expectedRemainingCost;
713-
if (costThisFrame != 0 && !pr.TakeCash(costThisFrame, true))
714-
return;
772+
if (!Queue.Info.PayUpFront)
773+
{
774+
var expectedRemainingCost = RemainingTime == 1 ? 0 : TotalCost * RemainingTime / Math.Max(1, TotalTime);
775+
var costThisFrame = RemainingCost - expectedRemainingCost;
776+
if (pr.Resources > 0 && pr.Resources <= costThisFrame)
777+
ResourcesPaid += pr.Resources;
778+
else if (pr.Resources > costThisFrame)
779+
ResourcesPaid += costThisFrame;
780+
if (costThisFrame != 0 && !pr.TakeCash(costThisFrame, true))
781+
{
782+
ResourcesPaid -= pr.Resources;
783+
return;
784+
}
785+
786+
RemainingCost -= costThisFrame;
787+
}
715788

716-
RemainingCost -= costThisFrame;
717789
RemainingTime--;
718790
if (RemainingTime > 0)
719791
return;

OpenRA.Mods.Common/Traits/ProductionQueueFromSelection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ void INotifySelection.SelectionChanged()
6363
.FirstOrDefault(q => q.Enabled && types.Contains(q.Info.Type));
6464
}
6565

66-
if (queue == null || !queue.BuildableItems().Any())
66+
if (queue == null || !queue.AnyItemsToBuild())
6767
return;
6868

6969
if (tabsWidget.Value != null)

OpenRA.Mods.Common/Widgets/Logic/Ingame/ClassicProductionLogic.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ void SelectTab(bool reverse)
4242
palette.PickUpCompletedBuilding();
4343
}
4444

45-
button.IsDisabled = () => !queues.Any(q => q.BuildableItems().Any());
45+
button.IsDisabled = () => !queues.Any(q => q.AnyItemsToBuild());
4646
button.OnMouseUp = mi => SelectTab(mi.Modifiers.HasModifier(Modifiers.Shift));
4747
button.OnKeyPress = e => SelectTab(e.Modifiers.HasModifier(Modifiers.Shift));
4848
button.OnClick = () => SelectTab(false);

OpenRA.Mods.Common/Widgets/ProductionPaletteWidget.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,8 +338,11 @@ bool HandleLeftClick(ProductionItem item, ProductionIcon icon, int handleCount,
338338

339339
if (buildable != null)
340340
{
341-
// Queue a new item
341+
if (CurrentQueue.Info.PayUpFront && currentQueue.GetProductionCost(buildable) > CurrentQueue.Actor.Owner.PlayerActor.Trait<PlayerResources>().GetCashAndResources())
342+
return false;
342343
Game.Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Sounds", ClickSound, null);
344+
345+
// Queue a new item
343346
var canQueue = CurrentQueue.CanQueue(buildable, out var notification, out var textNotification);
344347

345348
if (!CurrentQueue.AllQueued().Any())
@@ -366,7 +369,7 @@ bool HandleRightClick(ProductionItem item, ProductionIcon icon, int handleCount)
366369

367370
Game.Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Sounds", ClickSound, null);
368371

369-
if (CurrentQueue.Info.DisallowPaused || item.Paused || item.Done || item.TotalCost == item.RemainingCost)
372+
if (CurrentQueue.Info.DisallowPaused || item.Paused || item.Done || item.TotalCost == item.RemainingCost || !item.Started)
370373
{
371374
// Instantly cancel items that haven't started, have finished, or if the queue doesn't support pausing
372375
Game.Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Speech", CurrentQueue.Info.CancelledAudio, World.LocalPlayer.Faction.InternalName);

0 commit comments

Comments
 (0)