Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

End of Round Cash Summary Revision #2276

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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].
Loading