mirror of
https://github.com/WWhiteDreamProject/wwdpublic.git
synced 2026-04-18 14:07:53 +03:00
<!-- This is a semi-strict format, you can add/remove sections as needed but the order/format should be kept the same Remove these comments before submitting --> # Description <!-- Explain this PR in as much detail as applicable Some example prompts to consider: How might this affect the game? The codebase? What might be some alternatives to this? How/Who does this benefit/hurt [the game/codebase]? --> This PR does not have any effects on the game from a player-perspective. It does, however, allow us to add CharacterRequirements to ExtendDescriptions, which allows us to add contextual information to items that only show up if characters know about them, for example. It has an optional field that can also show text if your character does _not_ meet requirements. --- # TODO <!-- A list of everything you have to do before this PR is "complete" You probably won't have to complete everything before merging but it's good to leave future references --> - [x] Add a bunch of CharacterRequirements to new and existing ExtendDescriptions for contraband or other neat info --- <!-- This is default collapsed, readers click to expand it and see all your media The PR media section can get very large at times, so this is a good way to keep it clean The title is written using HTML tags The title must be within the <summary> tags or you won't see it --> <details><summary><h1>Media</h1></summary> <p> Example of how to add a requirement:  https://github.com/user-attachments/assets/67ad6ecd-1886-4f71-85c0-fdd035a9f5c9  </p> </details> --- # Changelog <!-- You can add an author after the `🆑` to change the name that appears in the changelog (ex: `🆑 Death`) Leaving it blank will default to your GitHub display name This includes all available types for the changelog --> 🆑 - tweak: Tweaked Extended Descriptions to be able to require CharacterRequirements before being shown to the player. Currently not actually implemented anywhere except for the emag and some posters. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Summary by CodeRabbit - **New Features** - Enhanced character creation and role-validation systems now incorporate playtime tracking and additional criteria, providing a more tailored experience. - In-game items—such as hacking devices, weapons, and posters—feature extended, lore-rich descriptions that adjust based on character attributes. - New localized texts enrich the narrative by offering clear feedback when character requirements are or aren’t met. - New character requirements related to antagonists and mindshields have been introduced, enhancing gameplay dynamics. - A new method for validating character requirements has been added, improving the accuracy of checks during character creation. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: VMSolidus <evilexecutive@gmail.com> Co-authored-by: VMSolidus <evilexecutive@gmail.com> (cherry picked from commit 0640f1f54619a95a4360a79b870654b2c4a1e433)
140 lines
4.3 KiB
C#
140 lines
4.3 KiB
C#
using System.Diagnostics.CodeAnalysis;
|
|
using Content.Shared.CCVar;
|
|
using Content.Shared.Customization.Systems;
|
|
using Content.Shared.Players.JobWhitelist;
|
|
using Content.Shared.Players;
|
|
using Content.Shared.Players.PlayTimeTracking;
|
|
using Content.Shared.Roles;
|
|
using Robust.Client;
|
|
using Robust.Client.Player;
|
|
using Robust.Shared.Configuration;
|
|
using Robust.Shared.Network;
|
|
using Robust.Shared.Player;
|
|
using Robust.Shared.Prototypes;
|
|
using Robust.Shared.Utility;
|
|
|
|
namespace Content.Client.Players.PlayTimeTracking;
|
|
|
|
public sealed partial class JobRequirementsManager : ISharedPlaytimeManager
|
|
{
|
|
[Dependency] private readonly IBaseClient _client = default!;
|
|
[Dependency] private readonly IClientNetManager _net = default!;
|
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
|
[Dependency] private readonly IPrototypeManager _prototypes = default!;
|
|
|
|
private readonly Dictionary<string, TimeSpan> _roles = new();
|
|
private readonly List<string> _roleBans = new();
|
|
private ISawmill _sawmill = default!;
|
|
private readonly List<string> _jobWhitelists = new();
|
|
public event Action? Updated;
|
|
|
|
public void Initialize()
|
|
{
|
|
_sawmill = Logger.GetSawmill("job_requirements");
|
|
|
|
// Yeah the client manager handles role bans and playtime but the server ones are separate DEAL.
|
|
_net.RegisterNetMessage<MsgRoleBans>(RxRoleBans);
|
|
_net.RegisterNetMessage<MsgPlayTime>(RxPlayTime);
|
|
_net.RegisterNetMessage<MsgWhitelist>(RxWhitelist);
|
|
_net.RegisterNetMessage<MsgJobWhitelist>(RxJobWhitelist);
|
|
|
|
_client.RunLevelChanged += ClientOnRunLevelChanged;
|
|
}
|
|
|
|
public bool TryGetTrackerTimes(ICommonSession id, [NotNullWhen(true)] out Dictionary<string, TimeSpan>? time)
|
|
{
|
|
time = new(_roles);
|
|
return true;
|
|
}
|
|
|
|
private void ClientOnRunLevelChanged(object? sender, RunLevelChangedEventArgs e)
|
|
{
|
|
if (e.NewLevel == ClientRunLevel.Initialize)
|
|
{
|
|
// Reset on disconnect, just in case.
|
|
_roles.Clear();
|
|
_jobWhitelists.Clear();
|
|
_roleBans.Clear();
|
|
}
|
|
}
|
|
|
|
private void RxRoleBans(MsgRoleBans message)
|
|
{
|
|
_sawmill.Debug($"Received roleban info containing {message.Bans.Count} entries.");
|
|
|
|
_roleBans.Clear();
|
|
_roleBans.AddRange(message.Bans);
|
|
Updated?.Invoke();
|
|
}
|
|
|
|
private void RxPlayTime(MsgPlayTime message)
|
|
{
|
|
_roles.Clear();
|
|
|
|
// NOTE: do not assign _roles = message.Trackers due to implicit data sharing in integration tests.
|
|
foreach (var (tracker, time) in message.Trackers)
|
|
{
|
|
_roles[tracker] = time;
|
|
}
|
|
|
|
/*var sawmill = Logger.GetSawmill("play_time");
|
|
foreach (var (tracker, time) in _roles)
|
|
{
|
|
sawmill.Info($"{tracker}: {time}");
|
|
}*/
|
|
Updated?.Invoke();
|
|
}
|
|
|
|
private void RxJobWhitelist(MsgJobWhitelist message)
|
|
{
|
|
_jobWhitelists.Clear();
|
|
_jobWhitelists.AddRange(message.Whitelist);
|
|
Updated?.Invoke();
|
|
}
|
|
|
|
public bool CheckJobWhitelist(JobPrototype job, [NotNullWhen(false)] out FormattedMessage? reason)
|
|
{
|
|
reason = default;
|
|
if (!_cfg.GetCVar(CCVars.GameRoleWhitelist))
|
|
return true;
|
|
|
|
if (job.Whitelisted && !_jobWhitelists.Contains(job.ID))
|
|
{
|
|
reason = FormattedMessage.FromUnformatted(Loc.GetString("role-not-whitelisted"));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public TimeSpan FetchOverallPlaytime()
|
|
{
|
|
return _roles.TryGetValue("Overall", out var overallPlaytime) ? overallPlaytime : TimeSpan.Zero;
|
|
}
|
|
|
|
public Dictionary<string, TimeSpan> FetchPlaytimeByRoles()
|
|
{
|
|
var jobsToMap = _prototypes.EnumeratePrototypes<JobPrototype>();
|
|
var ret = new Dictionary<string, TimeSpan>();
|
|
|
|
foreach (var job in jobsToMap)
|
|
if (_roles.TryGetValue(job.PlayTimeTracker, out var locJobName))
|
|
ret.Add(job.Name, locJobName);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
public Dictionary<string, TimeSpan> GetPlayTimes()
|
|
{
|
|
var dict = FetchPlaytimeByRoles();
|
|
dict.Add(PlayTimeTrackingShared.TrackerOverall, FetchOverallPlaytime());
|
|
return dict;
|
|
}
|
|
|
|
public Dictionary<string, TimeSpan> GetRawPlayTimeTrackers()
|
|
{
|
|
return _roles;
|
|
}
|
|
}
|