@@ -28,6 +28,7 @@ public class PlanetWarsMatchMaker : PlanetWarsMatchMakerState
2828 private DateTime ? defendersFullTime ; // set when every formed squad has enough defender volunteers
2929
3030 private Timer timer ;
31+ private DateTime lastChargeRechargeCheck = DateTime . MinValue ;
3132
3233 public PlanetWarsMatchMaker ( ZkLobbyServer . ZkLobbyServer server )
3334 {
@@ -108,6 +109,12 @@ private async void TimerOnElapsed(object sender, ElapsedEventArgs elapsedEventAr
108109 lastPlanetWarsMode = MiscVar . PlanetWarsMode ;
109110 }
110111
112+ if ( DateTime . UtcNow - lastChargeRechargeCheck >= TimeSpan . FromMinutes ( 1 ) )
113+ {
114+ lastChargeRechargeCheck = DateTime . UtcNow ;
115+ await ProcessChargeRecharge ( ) ;
116+ }
117+
111118 if ( MiscVar . PlanetWarsMode != PlanetWarsModes . Running ) return ;
112119
113120 // clean up stale running battles (e.g. if Spring process crashed)
@@ -119,7 +126,6 @@ private async void TimerOnElapsed(object sender, ElapsedEventArgs elapsedEventAr
119126 case PwPhase . AttackCollect :
120127 if ( DateTime . UtcNow > GetAttackDeadline ( ) )
121128 {
122- await ApplyTurnEndChargeBump ( ) ;
123129 RunSquadFormation ( ) ;
124130 if ( FormedSquads . Any ( ) )
125131 {
@@ -506,9 +512,8 @@ private async Task SpendAttackCharges(List<string> playerNames)
506512 List < Account > accounts ;
507513 using ( var db = new ZkDataContext ( ) )
508514 {
509- var turn = db . Galaxies . First ( g => g . IsDefault ) . Turn ;
510515 accounts = db . Accounts . Where ( a => playerNames . Contains ( a . Name ) ) . ToList ( ) ;
511- foreach ( var acc in accounts ) acc . SpendPwAttackCharge ( turn ) ;
516+ foreach ( var acc in accounts ) acc . SpendPwAttackCharge ( ) ;
512517 db . SaveChanges ( ) ;
513518 }
514519 await Task . WhenAll ( accounts . Select ( acc => SendPwAttackCharges ( server , acc . Name , acc ) ) ) ;
@@ -1179,13 +1184,13 @@ public void RemoveFromRunningBattles(int battleID)
11791184 public static PwAttackCharges BuildPwAttackCharges ( Account account )
11801185 {
11811186 var max = DynamicConfig . Instance . PwAttackChargesMax ;
1182- int ? nextRechargeTurn = null ;
1183- if ( max > 0 && account . PwAttackCharges < max && account . PwLastChargeChangeTurn != null )
1184- nextRechargeTurn = account . PwLastChargeChangeTurn . Value + DynamicConfig . Instance . PwAttackChargesCooldownTurns ;
1187+ DateTime ? nextRechargeTime = null ;
1188+ if ( max > 0 && account . PwAttackCharges < max && account . PwLastChargeChange != null )
1189+ nextRechargeTime = account . PwLastChargeChange . Value . AddMinutes ( DynamicConfig . Instance . PwAttackChargesCooldownMinutes ) . CeilingToMinute ( ) ;
11851190 return new PwAttackCharges
11861191 {
11871192 Current = account . PwAttackCharges ,
1188- NextRechargeTurn = nextRechargeTurn ,
1193+ NextRechargeTime = nextRechargeTime ,
11891194 } ;
11901195 }
11911196
@@ -1208,28 +1213,28 @@ private async Task SendPwAttackChargesForUser(string userName)
12081213 }
12091214 }
12101215
1211- private async Task ApplyTurnEndChargeBump ( )
1216+ private async Task ProcessChargeRecharge ( )
12121217 {
12131218 try
12141219 {
12151220 var max = DynamicConfig . Instance . PwAttackChargesMax ;
12161221 if ( max <= 0 ) return ;
1217- var cooldown = DynamicConfig . Instance . PwAttackChargesCooldownTurns ;
1222+ var cooldownMinutes = DynamicConfig . Instance . PwAttackChargesCooldownMinutes ;
1223+ // +35s offset: displayed nextRechargeTime is rounded up to a full minute. Bumping the
1224+ // eligibility window forward absorbs ≤1min jitter between the recharge check and the
1225+ // displayed minute boundary, so the user never sees the time pass without the grant.
1226+ var threshold = DateTime . UtcNow . AddSeconds ( 35 ) . AddMinutes ( - cooldownMinutes ) ;
12181227
12191228 List < Account > bumped ;
12201229 using ( var db = new ZkDataContext ( ) )
12211230 {
1222- var turn = db . Galaxies . First ( g => g . IsDefault ) . Turn ;
12231231 bumped = db . Accounts . Where ( a =>
12241232 a . FactionID != null &&
12251233 a . PwAttackCharges < max &&
1226- ( a . PwLastChargeChangeTurn == null || turn - a . PwLastChargeChangeTurn >= cooldown ) ) . ToList ( ) ;
1234+ a . PwLastChargeChange != null &&
1235+ a . PwLastChargeChange <= threshold ) . ToList ( ) ;
12271236
1228- foreach ( var acc in bumped )
1229- {
1230- acc . PwAttackCharges ++ ;
1231- acc . PwLastChargeChangeTurn = turn ;
1232- }
1237+ foreach ( var acc in bumped ) acc . GrantPwAttackCharge ( max ) ;
12331238
12341239 if ( bumped . Count > 0 ) db . SaveChanges ( ) ;
12351240 }
@@ -1238,7 +1243,7 @@ private async Task ApplyTurnEndChargeBump()
12381243 }
12391244 catch ( Exception ex )
12401245 {
1241- Trace . TraceError ( "PlanetWars turn-end charge bump error: {0}" , ex ) ;
1246+ Trace . TraceError ( "PlanetWars charge recharge tick error: {0}" , ex ) ;
12421247 }
12431248 }
12441249
0 commit comments