Skip to content

Commit

Permalink
End of Round Cash Summary Revision (#2276)
Browse files Browse the repository at this point in the history
  • Loading branch information
whatston3 authored Oct 18, 2024
1 parent 4ee1a0c commit 25c6538
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 26 deletions.
32 changes: 29 additions & 3 deletions Content.Server/_NF/Bank/BankSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,11 @@ public bool TryBankDeposit(ICommonSession session, PlayerPreferences prefs, Huma
}

/// <summary>
/// Attempts to add money to a character's bank account. This should always be used instead of attempting to modify the bankaccountcomponent directly
/// Retrieves a character's balance via its in-game entity, if it has one.
/// </summary>
/// <param name="ent">The UID that the bank account is connected to, typically the player controlled mob</param>
/// <param name="balance">The amount of spesos to add into the bank account</param>
/// <returns>true if the transaction was successful, false if it was not</returns>
/// <param name="balance">When successful, contains the account balance in spesos. Otherwise, set to 0.</param>
/// <returns>true if the account was successfully queried.</returns>
public bool TryGetBalance(EntityUid ent, out int balance)
{
if (!_playerManager.TryGetSessionByEntity(ent, out var session) ||
Expand All @@ -234,6 +234,32 @@ public bool TryGetBalance(EntityUid ent, out int balance)
return true;
}

/// <summary>
/// Retrieves a character's balance via a player's session.
/// </summary>
/// <param name="session">The session of the player character to query.</param>
/// <param name="balance">When successful, contains the account balance in spesos. Otherwise, set to 0.</param>
/// <returns>true if the account was successfully queried.</returns>
public bool TryGetBalance(ICommonSession session, out int balance)
{
if (!_prefsManager.TryGetCachedPreferences(session.UserId, out var prefs))
{
_log.Info($"{session.UserId} has no cached prefs");
balance = 0;
return false;
}

if (prefs.SelectedCharacter is not HumanoidCharacterProfile profile)
{
_log.Info($"{session.UserId} has the wrong prefs type");
balance = 0;
return false;
}

balance = profile.BankBalance;
return true;
}

/// <summary>
/// Update the bank balance to the character's current account balance.
/// </summary>
Expand Down
129 changes: 112 additions & 17 deletions Content.Server/_NF/GameRule/NfAdventureRuleSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using System.Threading.Tasks;
using Content.Shared._NF.GameRule;
using Content.Server.Procedural;
using Content.Shared.Bank.Components;
using Content.Server._NF.GameTicking.Events;
using Content.Shared.Procedural;
using Robust.Server.GameObjects;
Expand All @@ -30,9 +29,16 @@
using Robust.Shared.Configuration;
using Robust.Shared.Physics.Components;
using Content.Server.Shuttles.Components;
using Content.Shared._NF.Bank;
using Content.Shared.Tiles;
using Content.Server._NF.PublicTransit.Components;
using Content.Server._NF.GameRule.Components;
using Content.Server.Bank;
using Robust.Shared.Player;
using Robust.Shared.Network;
using Content.Shared.GameTicking;
using Robust.Shared.Enums;
using Robust.Server.Player;

namespace Content.Server._NF.GameRule;

Expand All @@ -44,18 +50,42 @@ public sealed class NfAdventureRuleSystem : GameRuleSystem<AdventureRuleComponen
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly MapLoaderSystem _map = default!;
[Dependency] private readonly MetaDataSystem _meta = default!;
[Dependency] private readonly DungeonSystem _dunGen = default!;
[Dependency] private readonly IConsoleHost _console = default!;
[Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly ShuttleSystem _shuttle = default!;
[Dependency] private readonly PhysicsSystem _physics = default!;
[Dependency] private readonly BankSystem _bank = default!;

private readonly HttpClient _httpClient = new();

public sealed class PlayerRoundBankInformation
{
// Initial balance, obtained on spawn
public int StartBalance;
// Ending balance, obtained on game end or detach (NOTE: multiple detaches possible), whichever happens first.
public int EndBalance;
// Entity name: used for display purposes ("The Feel of Fresh Bills earned 100,000 spesos")
public string Name;
// User ID: used to validate incoming information.
// If, for whatever reason, another player takes over this character, their initial balance is inaccurate.
public NetUserId UserId;

public PlayerRoundBankInformation(int startBalance, string name, NetUserId userId)
{
StartBalance = startBalance;
EndBalance = -1;
Name = name;
UserId = userId;
}
}

// A list of player bank account information stored by the controlled character's entity.
[ViewVariables]
private List<(EntityUid, int)> _players = new();
private Dictionary<EntityUid, PlayerRoundBankInformation> _players = new();

private float _distanceOffset = 1f;
private List<Vector2> _stationCoords = new();
Expand All @@ -67,23 +97,40 @@ public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(OnPlayerSpawningEvent);
SubscribeLocalEvent<PlayerDetachedEvent>(OnPlayerDetachedEvent);
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundRestart);
_playerManager.PlayerStatusChanged += PlayerManagerOnPlayerStatusChanged;
}

protected override void AppendRoundEndText(EntityUid uid, AdventureRuleComponent component, GameRuleComponent gameRule, ref RoundEndTextAppendEvent ev)
{
var profitText = Loc.GetString($"adventure-mode-profit-text");
var lossText = Loc.GetString($"adventure-mode-loss-text");
ev.AddLine(Loc.GetString("adventure-list-start"));
var allScore = new List<Tuple<string, int>>();

foreach (var player in _players)
foreach (var (player, playerInfo) in _players)
{
if (!TryComp<BankAccountComponent>(player.Item1, out var bank) || !TryComp<MetaDataComponent>(player.Item1, out var meta))
var endBalance = playerInfo.EndBalance;
if (_bank.TryGetBalance(player, out var bankBalance))
{
endBalance = bankBalance;
}

// Check if endBalance is valid (non-negative)
if (endBalance < 0)
continue;

var profit = bank.Balance - player.Item2;
ev.AddLine($"- {meta.EntityName} {profitText} {profit} Spesos");
allScore.Add(new Tuple<string, int>(meta.EntityName, profit));
var profit = endBalance - playerInfo.StartBalance;
string summaryText;
if (profit < 0)
{
summaryText = Loc.GetString("adventure-mode-list-loss", ("amount", BankSystemExtensions.ToSpesoString(-profit)));
}
else
{
summaryText = Loc.GetString("adventure-mode-list-profit", ("amount", BankSystemExtensions.ToSpesoString(profit)));
}
ev.AddLine($"- {playerInfo.Name} {summaryText}");
allScore.Add(new Tuple<string, int>(playerInfo.Name, profit));
}

if (!(allScore.Count >= 1))
Expand All @@ -93,20 +140,27 @@ protected override void AppendRoundEndText(EntityUid uid, AdventureRuleComponent
relayText += '\n';
var highScore = allScore.OrderByDescending(h => h.Item2).ToList();

for (var i = 0; i < 10 && i < highScore.Count; i++)
for (var i = 0; i < 10 && highScore.Count > 0; i++)
{
relayText += $"{highScore.First().Item1} {profitText} {highScore.First().Item2} Spesos";
if (highScore.First().Item2 < 0)
break;
var profitText = Loc.GetString("adventure-mode-top-profit", ("amount", BankSystemExtensions.ToSpesoString(highScore.First().Item2)));
relayText += $"{highScore.First().Item1} {profitText}";
relayText += '\n';
highScore.Remove(highScore.First());
highScore.RemoveAt(0);
}
relayText += '\n'; // Extra line separating the
relayText += Loc.GetString("adventure-list-low");
relayText += '\n';
highScore.Reverse();
for (var i = 0; i < 10 && i < highScore.Count; i++)
for (var i = 0; i < 10 && highScore.Count > 0; i++)
{
relayText += $"{highScore.First().Item1} {lossText} {highScore.First().Item2} Spesos";
if (highScore.First().Item2 > 0)
break;
var lossText = Loc.GetString("adventure-mode-top-loss", ("amount", BankSystemExtensions.ToSpesoString(-highScore.First().Item2)));
relayText += $"{highScore.First().Item1} {lossText}";
relayText += '\n';
highScore.Remove(highScore.First());
highScore.RemoveAt(0);
}
ReportRound(relayText);
}
Expand All @@ -115,11 +169,52 @@ private void OnPlayerSpawningEvent(PlayerSpawnCompleteEvent ev)
{
if (ev.Player.AttachedEntity is { Valid: true } mobUid)
{
_players.Add((mobUid, ev.Profile.BankBalance));
EnsureComp<CargoSellBlacklistComponent>(mobUid);

// Store player info with the bank balance - we have it directly, and BankSystem won't have a cache yet.
if (!_players.ContainsKey(mobUid))
_players[mobUid] = new PlayerRoundBankInformation(ev.Profile.BankBalance, MetaData(mobUid).EntityName, ev.Player.UserId);
}
}

private void OnPlayerDetachedEvent(PlayerDetachedEvent ev)
{
if (ev.Entity is not { Valid: true } mobUid)
return;

if (_players.ContainsKey(mobUid))
{
if (_players[mobUid].UserId == ev.Player.UserId &&
_bank.TryGetBalance(ev.Player, out var bankBalance))
{
_players[mobUid].EndBalance = bankBalance;
}
}
}

private void PlayerManagerOnPlayerStatusChanged(object? _, SessionStatusEventArgs e)
{
// Treat all disconnections as being possibly final.
if (e.NewStatus != SessionStatus.Disconnected ||
e.Session.AttachedEntity == null)
return;

var mobUid = e.Session.AttachedEntity.Value;
if (_players.ContainsKey(mobUid))
{
if (_players[mobUid].UserId == e.Session.UserId &&
_bank.TryGetBalance(e.Session, out var bankBalance))
{
_players[mobUid].EndBalance = bankBalance;
}
}
}

private void OnRoundRestart(RoundRestartCleanupEvent ev)
{
_players.Clear();
}

protected override void Started(EntityUid uid, AdventureRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
_mapId = GameTicker.DefaultMap;
Expand Down Expand Up @@ -439,7 +534,7 @@ private void AddStationCoordsToSet(Vector2 coords)
_stationCoords.Add(coords);
}

private async Task ReportRound(String message, int color = 0x77DDE7)
private async Task ReportRound(String message, int color = 0x77DDE7)
{
Logger.InfoS("discord", message);
String webhookUrl = _configurationManager.GetCVar(CCVars.DiscordLeaderboardWebhook);
Expand Down
12 changes: 7 additions & 5 deletions Resources/Locale/en-US/_NF/adventure/adventure.ftl
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
## UI
adventure-list-start = NT Galactic Bank
adventure-mode-profit-text = made a total profit of: {" "}
adventure-mode-loss-text = lost a total of: {" "}
adventure-list-high = Today's Top Earners:
adventure-list-low = Today's Biggest Spenders:
adventure-list-start = [color=gold]NT Galactic Bank[/color]
adventure-mode-list-profit = made a total profit of [color=#d19e5e]{$amount}[/color].
adventure-mode-list-loss = lost a total of [color=#659cc9]{$amount}[/color].
adventure-mode-top-profit = made a total profit of {$amount}.
adventure-mode-top-loss = lost a total of {$amount}.
adventure-list-high = This Shift's Top Earners:
adventure-list-low = This Shift's Biggest Spenders:
adventure-title = New Frontier Adventure Mode
adventure-description = Join a ship crew or buy your own and explore, research, salvage, or haul your way to riches!
currency = Spesos
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ round-end-summary-window-title = Round End Summary
round-end-summary-window-round-end-summary-tab-title = Round Information
round-end-summary-window-player-manifest-tab-title = Player Manifest
round-end-summary-window-round-id-label = Round [color=white]#{$roundId}[/color] has ended.
round-end-summary-window-gamemode-name-label = The game mode was [color=white]{$gamemode}[/color].
# Frontier
round-end-summary-window-gamemode-name-label = {""}
# round-end-summary-window-gamemode-name-label = The game mode was [color=white]{$gamemode}[/color].
# End Frontier
round-end-summary-window-duration-label = It lasted for [color=yellow]{$hours} hours, {$minutes} minutes, and {$seconds} seconds.
round-end-summary-window-player-info-if-observer-text = [color=gray]{$playerOOCName}[/color] was [color=lightblue]{$playerICName}[/color], an observer.
round-end-summary-window-player-info-if-not-observer-text = [color=gray]{$playerOOCName}[/color] was [color={$icNameColor}]{$playerICName}[/color] playing role of [color=orange]{$playerRole}[/color].

0 comments on commit 25c6538

Please sign in to comment.