mirror of
https://github.com/WWhiteDreamProject/wwdpublic.git
synced 2026-04-17 05:27:38 +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)
133 lines
5.8 KiB
C#
133 lines
5.8 KiB
C#
using System.Linq;
|
|
using System.Text;
|
|
using Content.Shared.Inventory;
|
|
using Content.Shared.Mind;
|
|
using Content.Shared.Players.PlayTimeTracking;
|
|
using Content.Shared.Preferences;
|
|
using Content.Shared.Roles;
|
|
using Content.Shared.Roles.Jobs;
|
|
using Content.Shared.Station;
|
|
using Robust.Shared.Configuration;
|
|
using Robust.Shared.Prototypes;
|
|
using Robust.Shared.Utility;
|
|
|
|
namespace Content.Shared.Customization.Systems;
|
|
|
|
|
|
public sealed class CharacterRequirementsSystem : EntitySystem
|
|
{
|
|
[Dependency] private readonly InventorySystem _inventory = default!;
|
|
[Dependency] private readonly SharedJobSystem _jobSystem = default!;
|
|
[Dependency] private readonly SharedMindSystem _mindSystem = default!;
|
|
[Dependency] private readonly SharedStationSpawningSystem _stationSpawningSystem = default!;
|
|
|
|
[Dependency] private readonly IEntityManager _entManager = default!;
|
|
[Dependency] private readonly IPrototypeManager _protomanager = default!;
|
|
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
|
[Dependency] private readonly ISharedPlaytimeManager _playtimeManager = default!;
|
|
|
|
public bool CheckRequirementValid(CharacterRequirement requirement, JobPrototype job,
|
|
HumanoidCharacterProfile profile, Dictionary<string, TimeSpan> playTimes, bool whitelisted, IPrototype prototype,
|
|
IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager,
|
|
out string? reason, int depth = 0)
|
|
{
|
|
// Return false if the requirement is invalid and not inverted
|
|
// If it's inverted return false when it's valid
|
|
return
|
|
!requirement.IsValid(job, profile, playTimes, whitelisted, prototype,
|
|
entityManager, prototypeManager, configManager,
|
|
out reason, depth)
|
|
? requirement.Inverted
|
|
: !requirement.Inverted;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if a character entity meets the specified requirements.
|
|
/// </summary>
|
|
/// <param name="requirements">The list of requirements to validate.</param>
|
|
/// <param name="characterUid">The entity ID of the character to check.</param>
|
|
/// <param name="prototype">The prototype associated with the requirements.</param>
|
|
/// <param name="reasons">Output list of reasons why requirements weren't met.</param>
|
|
/// <param name="depth">Current recursion depth for nested requirements.</param>
|
|
/// <param name="whitelisted">Whether the character is whitelisted.</param>
|
|
/// <returns>True if all requirements are met, false otherwise.</returns>
|
|
public bool CheckRequirementsValid(List<CharacterRequirement> requirements, EntityUid characterUid, IPrototype prototype, out List<string> reasons, int depth = 0, bool whitelisted = false)
|
|
{
|
|
reasons = new List<string>();
|
|
|
|
if (!_mindSystem.TryGetMind(characterUid, out var mindId, out var mind)
|
|
|| mind.Session == null
|
|
|| !_jobSystem.MindTryGetJob(mindId, out var jobPrototype)
|
|
|| !_stationSpawningSystem.GetProfile(characterUid, out var stationSpawningProfile)
|
|
|| !_playtimeManager.TryGetTrackerTimes(mind.Session, out var trackerTimes))
|
|
return false;
|
|
|
|
return CheckRequirementsValid(requirements, jobPrototype, stationSpawningProfile, trackerTimes, whitelisted, prototype, _entManager, _protomanager, _configurationManager, out reasons, depth, mind);
|
|
}
|
|
|
|
public bool CheckRequirementsValid(List<CharacterRequirement> requirements, JobPrototype job,
|
|
HumanoidCharacterProfile profile, Dictionary<string, TimeSpan> playTimes, bool whitelisted, IPrototype prototype,
|
|
IEntityManager entityManager, IPrototypeManager prototypeManager, IConfigurationManager configManager,
|
|
out List<string> reasons, int depth = 0, MindComponent? mind = null)
|
|
{
|
|
reasons = new List<string>();
|
|
var valid = true;
|
|
|
|
foreach (var requirement in requirements)
|
|
{
|
|
// Set valid to false if the requirement is invalid and not inverted
|
|
// If it's inverted set valid to false when it's valid
|
|
if (!requirement.IsValid(job, profile, playTimes, whitelisted, prototype,
|
|
entityManager, prototypeManager, configManager,
|
|
out var reason, depth, mind))
|
|
{
|
|
if (valid)
|
|
valid = requirement.Inverted;
|
|
}
|
|
else
|
|
{
|
|
if (valid)
|
|
valid = !requirement.Inverted;
|
|
}
|
|
|
|
if (reason != null)
|
|
reasons.Add(reason);
|
|
}
|
|
|
|
return valid;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Gets the reason text from <see cref="CheckRequirementsValid"/> as a <see cref="FormattedMessage"/>.
|
|
/// </summary>
|
|
public FormattedMessage GetRequirementsText(List<string> reasons)
|
|
{
|
|
return FormattedMessage.FromMarkup(GetRequirementsMarkup(reasons));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the reason text from <see cref="CheckRequirementsValid"/> as a markup string.
|
|
/// </summary>
|
|
public string GetRequirementsMarkup(List<string> reasons)
|
|
{
|
|
var text = new StringBuilder();
|
|
foreach (var reason in reasons)
|
|
text.Append($"\n{reason}");
|
|
|
|
return text.ToString().Trim();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Returns true if the given dummy can equip the given item.
|
|
/// Does not care if items are already in equippable slots, and ignores pockets.
|
|
/// </summary>
|
|
public bool CanEntityWearItem(EntityUid dummy, EntityUid clothing, bool bypassAccessCheck = false)
|
|
{
|
|
return _inventory.TryGetSlots(dummy, out var slots)
|
|
&& slots.Where(slot => !slot.SlotFlags.HasFlag(SlotFlags.POCKET))
|
|
.Any(slot => _inventory.CanEquip(dummy, clothing, slot.Name, out _, onSpawn: true, bypassAccessCheck: bypassAccessCheck));
|
|
}
|
|
}
|