@@ -38,6 +38,9 @@ public class ProductionQueueInfo : TraitInfo, IRulesetLoaded
38
38
[ Desc ( "Should the prerequisite remain enabled if the owner changes?" ) ]
39
39
public readonly bool Sticky = true ;
40
40
41
+ [ Desc ( "Player must pay for item upfront" ) ]
42
+ public readonly bool PayUpFront = false ;
43
+
41
44
[ Desc ( "Should right clicking on the icon instantly cancel the production instead of putting it on hold?" ) ]
42
45
public readonly bool DisallowPaused = false ;
43
46
@@ -185,7 +188,16 @@ protected void ClearQueue()
185
188
{
186
189
// Refund the current item
187
190
foreach ( var item in Queue )
191
+ {
192
+ if ( item . ResourcesPaid > 0 )
193
+ {
194
+ playerResources . GiveResources ( item . ResourcesPaid ) ;
195
+ item . RemainingCost += item . ResourcesPaid ;
196
+ }
197
+
188
198
playerResources . GiveCash ( item . TotalCost - item . RemainingCost ) ;
199
+ }
200
+
189
201
Queue . Clear ( ) ;
190
202
}
191
203
@@ -267,6 +279,11 @@ public virtual bool IsProducing(ProductionItem item)
267
279
return Queue . Count > 0 && Queue [ 0 ] == item ;
268
280
}
269
281
282
+ public virtual bool IsInQueue ( ActorInfo actor )
283
+ {
284
+ return Queue . Any ( i => i . Item == actor . Name ) ;
285
+ }
286
+
270
287
public ProductionItem CurrentItem ( )
271
288
{
272
289
return Queue . ElementAtOrDefault ( 0 ) ;
@@ -293,12 +310,22 @@ public virtual IEnumerable<ActorInfo> BuildableItems()
293
310
return Enumerable . Empty < ActorInfo > ( ) ;
294
311
if ( ! Enabled )
295
312
return Enumerable . Empty < ActorInfo > ( ) ;
296
- if ( developerMode . AllTech )
313
+ if ( ! Info . PayUpFront && developerMode . AllTech )
297
314
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 ) ) ;
299
319
return buildableProducibles ;
300
320
}
301
321
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
+
302
329
public bool CanBuild ( ActorInfo actor )
303
330
{
304
331
if ( ! Producible . TryGetValue ( actor , out var ps ) )
@@ -352,6 +379,13 @@ protected void CancelUnbuildableItems()
352
379
if ( buildableNames . Contains ( Queue [ i ] . Item ) )
353
380
continue ;
354
381
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
+
355
389
// Refund what's been paid so far
356
390
playerResources . GiveCash ( Queue [ i ] . TotalCost - Queue [ i ] . RemainingCost ) ;
357
391
EndProduction ( Queue [ i ] ) ;
@@ -369,6 +403,9 @@ public bool CanQueue(ActorInfo actor, out string notificationAudio, out string n
369
403
370
404
if ( ! developerMode . AllTech )
371
405
{
406
+ if ( Info . PayUpFront && actor . TraitInfo < ValuedInfo > ( ) . Cost > playerResources . GetCashAndResources ( ) )
407
+ return false ;
408
+
372
409
if ( Info . QueueLimit > 0 && Queue . Count >= Info . QueueLimit )
373
410
{
374
411
notificationAudio = Info . LimitedAudio ;
@@ -444,6 +481,8 @@ public void ResolveOrder(Actor self, Order order)
444
481
var amountToBuild = Math . Min ( fromLimit , order . ExtraData ) ;
445
482
for ( var n = 0 ; n < amountToBuild ; n ++ )
446
483
{
484
+ if ( Info . PayUpFront && cost > playerResources . GetCashAndResources ( ) )
485
+ return ;
447
486
var hasPlayedSound = false ;
448
487
BeginProduction ( new ProductionItem ( this , order . TargetString , cost , playerPower , ( ) => self . World . AddFrameEndTask ( _ =>
449
488
{
@@ -540,6 +579,12 @@ protected bool CancelProductionInner(string itemName)
540
579
else
541
580
{
542
581
// Refund what has been paid
582
+ if ( item . ResourcesPaid > 0 )
583
+ {
584
+ playerResources . GiveResources ( item . ResourcesPaid ) ;
585
+ item . RemainingCost += item . ResourcesPaid ;
586
+ }
587
+
543
588
playerResources . GiveCash ( item . TotalCost - item . RemainingCost ) ;
544
589
EndProduction ( item ) ;
545
590
}
@@ -560,9 +605,19 @@ public void EndProduction(ProductionItem item)
560
605
561
606
protected virtual void BeginProduction ( ProductionItem item , bool hasPriority )
562
607
{
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
+
563
619
if ( Queue . Any ( i => i . Item == item . Item && i . Infinite ) )
564
620
return ;
565
-
566
621
if ( hasPriority && Queue . Count > 1 )
567
622
Queue . Insert ( 1 , item ) ;
568
623
else
@@ -581,6 +636,12 @@ protected virtual void BeginProduction(ProductionItem item, bool hasPriority)
581
636
for ( var i = 1 ; i < queued . Count ; i ++ )
582
637
{
583
638
// 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
+
584
645
playerResources . GiveCash ( queued [ i ] . TotalCost - queued [ i ] . RemainingCost ) ;
585
646
EndProduction ( queued [ i ] ) ;
586
647
}
@@ -645,10 +706,10 @@ public class ProductionItem
645
706
public readonly ProductionQueue Queue ;
646
707
public readonly int TotalCost ;
647
708
public readonly Action OnComplete ;
648
-
649
709
public int TotalTime { get ; private set ; }
650
710
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 ; }
652
713
public int RemainingTimeActual =>
653
714
( pm == null || pm . PowerState == PowerState . Normal ) ? RemainingTime :
654
715
RemainingTime * Queue . Info . LowPowerModifier / 100 ;
@@ -669,6 +730,7 @@ public ProductionItem(ProductionQueue queue, string item, int cost, PowerManager
669
730
Item = item ;
670
731
RemainingTime = TotalTime = 1 ;
671
732
RemainingCost = TotalCost = cost ;
733
+ ResourcesPaid = 0 ;
672
734
OnComplete = onComplete ;
673
735
Queue = queue ;
674
736
this . pm = pm ;
@@ -685,7 +747,6 @@ public void Tick(PlayerResources pr)
685
747
var time = Queue . GetBuildTime ( ai , bi ) ;
686
748
if ( time > 0 )
687
749
RemainingTime = TotalTime = time ;
688
-
689
750
Started = true ;
690
751
}
691
752
@@ -708,12 +769,23 @@ public void Tick(PlayerResources pr)
708
769
return ;
709
770
}
710
771
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
+ }
715
788
716
- RemainingCost -= costThisFrame ;
717
789
RemainingTime -- ;
718
790
if ( RemainingTime > 0 )
719
791
return ;
0 commit comments