Skip to content

Commit 7e2b8af

Browse files
authored
add attack charges to planetwars
add per-player attack charges to planetwars
2 parents 729104b + 306fc33 commit 7e2b8af

10 files changed

Lines changed: 339 additions & 3 deletions

File tree

Shared/LobbyClient/Protocol/Messages.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,13 @@ public class PwStatus
749749
public int MinLevel { get; set; }
750750
}
751751

752+
[Message(Origin.Server)]
753+
public class PwAttackCharges
754+
{
755+
public int Current { get; set; }
756+
public int? NextRechargeTurn { get; set; }
757+
}
758+
752759

753760

754761

Zero-K.info/Controllers/PlanetwarsAdminController.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,13 @@ public ActionResult StartGalaxy(int galaxyID)
365365
gal.Ended = null;
366366
gal.EndMessage = null;
367367
db.SaveChanges();
368+
369+
var maxCharges = DynamicConfig.Instance.PwAttackChargesMax;
370+
db.Accounts.Where(x => x.FactionID != null).Update(x => new Account()
371+
{
372+
PwAttackCharges = maxCharges,
373+
PwLastChargeChangeTurn = null,
374+
});
368375
}
369376

370377
return RedirectToAction("Index");

ZkData/Ef/Account.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ public static double AdjustEloWeight(double currentWeight, double sumWeight, int
153153
public double PwWarpProduced { get; set; }
154154
public double PwWarpUsed { get; set; }
155155
public double PwAttackPoints { get; set; }
156+
public int PwAttackCharges { get; set; }
157+
public int? PwLastChargeChangeTurn { get; set; }
156158
public bool HasVpnException { get; set; }
157159
public bool HasKudos { get; set; }
158160
public int ForumTotalUpvotes { get; set; }
@@ -530,6 +532,21 @@ public void ResetQuotas()
530532

531533

532534

535+
public void SpendPwAttackCharge(int currentTurn)
536+
{
537+
if (PwAttackCharges > 0) PwAttackCharges--;
538+
PwLastChargeChangeTurn = currentTurn;
539+
}
540+
541+
public void GrantPwAttackCharge(int maxCharges, int currentTurn)
542+
{
543+
if (maxCharges <= 0) return;
544+
if (PwAttackCharges >= maxCharges) return;
545+
PwAttackCharges++;
546+
PwLastChargeChangeTurn = currentTurn;
547+
}
548+
549+
533550
public void SpendBombers(double count)
534551
{
535552
PwBombersUsed += count;

ZkData/Ef/DynamicConfig.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ public class DynamicConfig
4646
[Description("PlanetWars: maximum attack charges a player can hold. 0 disables the charge system.")]
4747
public int PwAttackChargesMax { get; set; } = 2;
4848

49-
[Description("PlanetWars: minutes a player must sit below max charges before gaining one passively.")]
50-
public int PwAttackChargesRechargeMinutes { get; set; } = 60;
49+
[Description("PlanetWars: turns a player must be idle (no spend/gain) before their next +1 passive charge, up to max. Every charge gain or loss resets this clock, so the average regen rate is at most 1 charge per this many turns.")]
50+
public int PwAttackChargesCooldownTurns { get; set; } = 4;
5151

5252
[Description("PlanetWars: fraction of enemy bomber IP damage also applied to the bomber's own faction. 0 disables self-damage.")]
5353
public double PwBomberSelfIpRate { get; set; } = 0.5;

ZkData/Migrations/202604241242120_AddPwAttackCharges.Designer.cs

Lines changed: 29 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
namespace ZkData.Migrations
2+
{
3+
using System;
4+
using System.Data.Entity.Migrations;
5+
6+
public partial class AddPwAttackCharges : DbMigration
7+
{
8+
public override void Up()
9+
{
10+
AddColumn("dbo.Accounts", "PwAttackCharges", c => c.Int(nullable: false, defaultValue: 2));
11+
AddColumn("dbo.Accounts", "PwLastChargeChangeTurn", c => c.Int());
12+
AddColumn("dbo.DynamicConfigs", "PwAttackChargesCooldownTurns", c => c.Int(nullable: false, defaultValue: 4));
13+
DropColumn("dbo.DynamicConfigs", "PwAttackChargesRechargeMinutes");
14+
}
15+
16+
public override void Down()
17+
{
18+
AddColumn("dbo.DynamicConfigs", "PwAttackChargesRechargeMinutes", c => c.Int(nullable: false, defaultValue: 60));
19+
DropColumn("dbo.DynamicConfigs", "PwAttackChargesCooldownTurns");
20+
DropColumn("dbo.Accounts", "PwLastChargeChangeTurn");
21+
DropColumn("dbo.Accounts", "PwAttackCharges");
22+
}
23+
}
24+
}

ZkData/Migrations/202604241242120_AddPwAttackCharges.resx

Lines changed: 126 additions & 0 deletions
Large diffs are not rendered by default.

ZkData/ZkData.csproj

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,10 @@
507507
<Compile Include="Migrations\202604231826040_AddPwBomberNerfConfigs.Designer.cs">
508508
<DependentUpon>202604231826040_AddPwBomberNerfConfigs.cs</DependentUpon>
509509
</Compile>
510+
<Compile Include="Migrations\202604241242120_AddPwAttackCharges.cs" />
511+
<Compile Include="Migrations\202604241242120_AddPwAttackCharges.Designer.cs">
512+
<DependentUpon>202604241242120_AddPwAttackCharges.cs</DependentUpon>
513+
</Compile>
510514
<Compile Include="SpringFilesUnitsyncAttempt.cs" />
511515
<Compile Include="SteamWebApi.cs" />
512516
<Compile Include="UserLanguageNoteAttribute.cs" />
@@ -967,6 +971,9 @@
967971
<EmbeddedResource Include="Migrations\202604231826040_AddPwBomberNerfConfigs.resx">
968972
<DependentUpon>202604231826040_AddPwBomberNerfConfigs.cs</DependentUpon>
969973
</EmbeddedResource>
974+
<EmbeddedResource Include="Migrations\202604241242120_AddPwAttackCharges.resx">
975+
<DependentUpon>202604241242120_AddPwAttackCharges.cs</DependentUpon>
976+
</EmbeddedResource>
970977
<EmbeddedResource Include="ZkDataResources.resx">
971978
<Generator>ResXFileCodeGenerator</Generator>
972979
<LastGenOutput>ZkDataResources.Designer.cs</LastGenOutput>

ZkLobbyServer/SpringieInterface/PlanetWarsMatchMaker.cs

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ private async void TimerOnElapsed(object sender, ElapsedEventArgs elapsedEventAr
154154
RunDefenderAssignment();
155155
await LaunchAllBattles();
156156
RunGalaxyTick();
157+
await ApplyTurnEndChargeBump();
157158
AttackerSideCounter++;
158159
ResetAttackOptions();
159160
}
@@ -420,6 +421,8 @@ private double GetPlayerWhr(string name)
420421

421422
private async Task LaunchAllBattles()
422423
{
424+
var attackerNamesToChargeSpend = new List<string>();
425+
423426
// merge squads on the same planet into one battle per planet
424427
foreach (var planetId in FormedSquads.Select(s => s.PlanetID).Distinct().ToList())
425428
{
@@ -434,6 +437,8 @@ private async Task LaunchAllBattles()
434437
merged.Defenders.AddRange(squad.Defenders.Where(x => server.ConnectedUsers.ContainsKey(x)));
435438
}
436439

440+
if (merged.Attackers.Count > 0) attackerNamesToChargeSpend.AddRange(merged.Attackers);
441+
437442
if (merged.Defenders.Count > 0 && merged.Attackers.Count > 0)
438443
{
439444
// battle (may be uneven)
@@ -473,6 +478,30 @@ private async Task LaunchAllBattles()
473478

474479
FormedSquads.Clear();
475480
DefenderVotes.Clear();
481+
482+
if (attackerNamesToChargeSpend.Count > 0) await SpendAttackCharges(attackerNamesToChargeSpend);
483+
}
484+
485+
private async Task SpendAttackCharges(List<string> playerNames)
486+
{
487+
var max = DynamicConfig.Instance.PwAttackChargesMax;
488+
if (max <= 0) return;
489+
try
490+
{
491+
List<Account> accounts;
492+
using (var db = new ZkDataContext())
493+
{
494+
var turn = db.Galaxies.First(g => g.IsDefault).Turn;
495+
accounts = db.Accounts.Where(a => playerNames.Contains(a.Name)).ToList();
496+
foreach (var acc in accounts) acc.SpendPwAttackCharge(turn);
497+
db.SaveChanges();
498+
}
499+
await Task.WhenAll(accounts.Select(acc => SendPwAttackCharges(server, acc.Name, acc)));
500+
}
501+
catch (Exception ex)
502+
{
503+
Trace.TraceError("PlanetWars SpendAttackCharges error: {0}", ex);
504+
}
476505
}
477506

478507

@@ -540,6 +569,13 @@ private async Task JoinPlanetAttack(int targetPlanetId, string userName)
540569
var account = db.Accounts.Find(user.AccountID);
541570
if (account == null || account.FactionID != AttackingFaction.FactionID || !account.CanPlayerPlanetWars()) return;
542571

572+
var maxCharges = DynamicConfig.Instance.PwAttackChargesMax;
573+
if (maxCharges > 0 && account.PwAttackCharges <= 0)
574+
{
575+
await server.GhostChanSay(user.Faction, $"{userName} cannot attack: out of attack charges");
576+
return;
577+
}
578+
543579
// remove from other options
544580
foreach (var aop in AttackOptions.Where(x => x.PlanetID != targetPlanetId))
545581
aop.Attackers.RemoveAll(x => x == userName);
@@ -604,7 +640,11 @@ public async Task OnLoginAccepted(ConnectedUser connectedUser)
604640
if (MiscVar.PlanetWarsMode == PlanetWarsModes.Running)
605641
{
606642
var u = connectedUser.User;
607-
if (u.CanUserPlanetWars()) await UpdateLobby(u.Name);
643+
if (u.CanUserPlanetWars())
644+
{
645+
await UpdateLobby(u.Name);
646+
await SendPwAttackChargesForUser(u.Name);
647+
}
608648
}
609649
}
610650

@@ -939,6 +979,75 @@ public void RemoveFromRunningBattles(int battleID)
939979
RunningBattles.Remove(battleID);
940980
}
941981

982+
983+
// ===================== ATTACK CHARGES =====================
984+
985+
public static PwAttackCharges BuildPwAttackCharges(Account account)
986+
{
987+
var max = DynamicConfig.Instance.PwAttackChargesMax;
988+
int? nextRechargeTurn = null;
989+
if (max > 0 && account.PwAttackCharges < max && account.PwLastChargeChangeTurn != null)
990+
nextRechargeTurn = account.PwLastChargeChangeTurn.Value + DynamicConfig.Instance.PwAttackChargesCooldownTurns;
991+
return new PwAttackCharges
992+
{
993+
Current = account.PwAttackCharges,
994+
NextRechargeTurn = nextRechargeTurn,
995+
};
996+
}
997+
998+
public static async Task SendPwAttackCharges(ZkLobbyServer.ZkLobbyServer server, string userName, Account account)
999+
{
1000+
var conus = server.ConnectedUsers.Get(userName);
1001+
if (conus == null) return;
1002+
await conus.SendCommand(BuildPwAttackCharges(account));
1003+
}
1004+
1005+
private async Task SendPwAttackChargesForUser(string userName)
1006+
{
1007+
var conus = server.ConnectedUsers.Get(userName);
1008+
if (conus?.User == null) return;
1009+
using (var db = new ZkDataContext())
1010+
{
1011+
var account = db.Accounts.Find(conus.User.AccountID);
1012+
if (account == null) return;
1013+
await conus.SendCommand(BuildPwAttackCharges(account));
1014+
}
1015+
}
1016+
1017+
private async Task ApplyTurnEndChargeBump()
1018+
{
1019+
try
1020+
{
1021+
var max = DynamicConfig.Instance.PwAttackChargesMax;
1022+
if (max <= 0) return;
1023+
var cooldown = DynamicConfig.Instance.PwAttackChargesCooldownTurns;
1024+
1025+
List<Account> bumped;
1026+
using (var db = new ZkDataContext())
1027+
{
1028+
var turn = db.Galaxies.First(g => g.IsDefault).Turn;
1029+
bumped = db.Accounts.Where(a =>
1030+
a.FactionID != null &&
1031+
a.PwAttackCharges < max &&
1032+
(a.PwLastChargeChangeTurn == null || turn - a.PwLastChargeChangeTurn >= cooldown)).ToList();
1033+
1034+
foreach (var acc in bumped)
1035+
{
1036+
acc.PwAttackCharges++;
1037+
acc.PwLastChargeChangeTurn = turn;
1038+
}
1039+
1040+
if (bumped.Count > 0) db.SaveChanges();
1041+
}
1042+
1043+
await Task.WhenAll(bumped.Select(a => SendPwAttackCharges(server, a.Name, a)));
1044+
}
1045+
catch (Exception ex)
1046+
{
1047+
Trace.TraceError("PlanetWars turn-end charge bump error: {0}", ex);
1048+
}
1049+
}
1050+
9421051
private async Task UpdateLobby()
9431052
{
9441053
// per-player: flags (CanSelectForBattle / PlayerIsAttacker) depend on the viewer

ZkLobbyServer/SpringieInterface/PlanetWarsTurnHandler.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,16 @@ public static void ProcessBattleResult(string mapName, List<string> extraData, Z
174174
db.Events.InsertOnSubmit(ev);
175175
text.AppendLine(ev.PlainText);
176176
}
177+
178+
var maxCharges = DynamicConfig.Instance.PwAttackChargesMax;
179+
if (maxCharges > 0)
180+
{
181+
foreach (Account w in defenders)
182+
{
183+
w.GrantPwAttackCharge(maxCharges, gal.Turn);
184+
_ = ZeroKWeb.PlanetWarsMatchMaker.SendPwAttackCharges(server, w.Name, w);
185+
}
186+
}
177187
}
178188
else
179189
{

0 commit comments

Comments
 (0)