mirror of
https://github.com/WWhiteDreamProject/wwdpublic.git
synced 2026-04-16 21:17:39 +03:00
CharacterRequirements on ExtendDescriptions (#1862)
<!-- 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)
This commit is contained in:
@@ -41,6 +41,12 @@ public sealed partial class JobRequirementsManager : ISharedPlaytimeManager
|
||||
_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)
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Roles;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Customization.Systems;
|
||||
|
||||
/// <summary>
|
||||
/// Requires the player to be a specific antagonist
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class CharacterAntagonistRequirement : CharacterRequirement
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public List<ProtoId<AntagPrototype>> Antagonists;
|
||||
|
||||
public override bool IsValid(JobPrototype job,
|
||||
HumanoidCharacterProfile profile,
|
||||
Dictionary<string, TimeSpan> playTimes,
|
||||
bool whitelisted,
|
||||
IPrototype prototype,
|
||||
IEntityManager entityManager,
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0,
|
||||
MindComponent? mind = null)
|
||||
{
|
||||
// Considering this will not be used in the character creation menu, players will likely never see this text.
|
||||
reason = Loc.GetString("character-antagonist-requirement", ("inverted", Inverted));
|
||||
|
||||
if (mind == null)
|
||||
return false;
|
||||
|
||||
foreach (var mindRoleComponent in mind.MindRoles.Select(entityManager.GetComponent<MindRoleComponent>))
|
||||
{
|
||||
if (!mindRoleComponent.AntagPrototype.HasValue)
|
||||
continue;
|
||||
|
||||
if (Antagonists.Contains(mindRoleComponent.AntagPrototype.Value))
|
||||
return !Inverted;
|
||||
}
|
||||
|
||||
return Inverted;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Players.PlayTimeTracking;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Roles;
|
||||
@@ -32,7 +33,8 @@ public sealed partial class CharacterJobRequirement : CharacterRequirement
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0)
|
||||
int depth = 0,
|
||||
MindComponent? mind = null)
|
||||
{
|
||||
var jobs = new List<string>();
|
||||
var depts = prototypeManager.EnumeratePrototypes<DepartmentPrototype>();
|
||||
@@ -83,7 +85,8 @@ public sealed partial class CharacterDepartmentRequirement : CharacterRequiremen
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0)
|
||||
int depth = 0,
|
||||
MindComponent? mind = null)
|
||||
{
|
||||
var departments = new List<string>();
|
||||
|
||||
@@ -130,7 +133,8 @@ public sealed partial class CharacterDepartmentTimeRequirement : CharacterRequir
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0)
|
||||
int depth = 0,
|
||||
MindComponent? mind = null)
|
||||
{
|
||||
// Disable the requirement if the role timers are disabled
|
||||
if (!configManager.GetCVar(CCVars.GameRoleTimers))
|
||||
@@ -202,7 +206,8 @@ public sealed partial class CharacterOverallTimeRequirement : CharacterRequireme
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0)
|
||||
int depth = 0,
|
||||
MindComponent? mind = null)
|
||||
{
|
||||
// Disable the requirement if the role timers are disabled
|
||||
if (!configManager.GetCVar(CCVars.GameRoleTimers))
|
||||
@@ -264,7 +269,8 @@ public sealed partial class CharacterPlaytimeRequirement : CharacterRequirement
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0)
|
||||
int depth = 0,
|
||||
MindComponent? mind = null)
|
||||
{
|
||||
// Disable the requirement if the role timers are disabled
|
||||
if (!configManager.GetCVar(CCVars.GameRoleTimers))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Roles;
|
||||
using JetBrains.Annotations;
|
||||
@@ -30,7 +31,8 @@ public sealed partial class CharacterLogicAndRequirement : CharacterRequirement
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0)
|
||||
int depth = 0,
|
||||
MindComponent? mind = null)
|
||||
{
|
||||
var succeeded = entityManager.EntitySysManager.GetEntitySystem<CharacterRequirementsSystem>()
|
||||
.CheckRequirementsValid(Requirements, job, profile, playTimes, whitelisted, prototype, entityManager,
|
||||
@@ -72,7 +74,8 @@ public sealed partial class CharacterLogicOrRequirement : CharacterRequirement
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0)
|
||||
int depth = 0,
|
||||
MindComponent? mind = null)
|
||||
{
|
||||
var succeeded = false;
|
||||
var reasons = new List<string>();
|
||||
@@ -127,7 +130,8 @@ public sealed partial class CharacterLogicXorRequirement : CharacterRequirement
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0)
|
||||
int depth = 0,
|
||||
MindComponent? mind = null)
|
||||
{
|
||||
var reasons = new List<string>();
|
||||
var succeeded = false;
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.Implants.Components;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Mindshield.Components;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Roles;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Customization.Systems;
|
||||
|
||||
/// <summary>
|
||||
/// Requires the player to have a mindshield
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class CharacterMindshieldRequirement : CharacterRequirement
|
||||
{
|
||||
public override bool IsValid(JobPrototype job,
|
||||
HumanoidCharacterProfile profile,
|
||||
Dictionary<string, TimeSpan> playTimes,
|
||||
bool whitelisted,
|
||||
IPrototype prototype,
|
||||
IEntityManager entityManager,
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0,
|
||||
MindComponent? mind = null)
|
||||
{
|
||||
reason = Loc.GetString("character-mindshield-requirement", ("inverted", Inverted));
|
||||
|
||||
if (mind == null)
|
||||
return false;
|
||||
|
||||
return entityManager.HasComponent<MindShieldComponent>(mind.CurrentEntity) != Inverted;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.Customization.Systems;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Roles;
|
||||
using JetBrains.Annotations;
|
||||
@@ -9,7 +10,7 @@ using Robust.Shared.Serialization;
|
||||
namespace Content.Shared.Customization.Systems;
|
||||
|
||||
/// <summary>
|
||||
/// Requires the server to have a specific CVar value.
|
||||
/// Requires the server to have a specific CVar value.
|
||||
/// </summary>
|
||||
[UsedImplicitly, Serializable, NetSerializable,]
|
||||
public sealed partial class CVarRequirement : CharacterRequirement
|
||||
@@ -30,7 +31,8 @@ public sealed partial class CVarRequirement : CharacterRequirement
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0
|
||||
int depth = 0,
|
||||
MindComponent? mind = null
|
||||
)
|
||||
{
|
||||
if (!configManager.IsCVarRegistered(CVar))
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Linq;
|
||||
using Content.Shared.Clothing.Loadouts.Prototypes;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Humanoid.Prototypes;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Prototypes;
|
||||
using Content.Shared.Roles;
|
||||
@@ -38,7 +39,8 @@ public sealed partial class CharacterAgeRequirement : CharacterRequirement
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0
|
||||
int depth = 0,
|
||||
MindComponent? mind = null
|
||||
)
|
||||
{
|
||||
var localeString = "";
|
||||
@@ -76,7 +78,8 @@ public sealed partial class CharacterGenderRequirement : CharacterRequirement
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0
|
||||
int depth = 0,
|
||||
MindComponent? mind = null
|
||||
)
|
||||
{
|
||||
reason = Loc.GetString(
|
||||
@@ -106,7 +109,8 @@ public sealed partial class CharacterSexRequirement : CharacterRequirement
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0
|
||||
int depth = 0,
|
||||
MindComponent? mind = null
|
||||
)
|
||||
{
|
||||
reason = Loc.GetString(
|
||||
@@ -136,7 +140,8 @@ public sealed partial class CharacterSpeciesRequirement : CharacterRequirement
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0
|
||||
int depth = 0,
|
||||
MindComponent? mind = null
|
||||
)
|
||||
{
|
||||
const string color = "green";
|
||||
@@ -178,7 +183,8 @@ public sealed partial class CharacterHeightRequirement : CharacterRequirement
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0
|
||||
int depth = 0,
|
||||
MindComponent? mind = null
|
||||
)
|
||||
{
|
||||
const string color = "yellow";
|
||||
@@ -224,7 +230,8 @@ public sealed partial class CharacterWidthRequirement : CharacterRequirement
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0
|
||||
int depth = 0,
|
||||
MindComponent? mind = null
|
||||
)
|
||||
{
|
||||
const string color = "yellow";
|
||||
@@ -270,7 +277,8 @@ public sealed partial class CharacterWeightRequirement : CharacterRequirement
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0
|
||||
int depth = 0,
|
||||
MindComponent? mind = null
|
||||
)
|
||||
{
|
||||
const string color = "green";
|
||||
@@ -320,7 +328,8 @@ public sealed partial class CharacterTraitRequirement : CharacterRequirement
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0
|
||||
int depth = 0,
|
||||
MindComponent? mind = null
|
||||
)
|
||||
{
|
||||
const string color = "lightblue";
|
||||
@@ -353,7 +362,8 @@ public sealed partial class CharacterLoadoutRequirement : CharacterRequirement
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0
|
||||
int depth = 0,
|
||||
MindComponent? mind = null
|
||||
)
|
||||
{
|
||||
const string color = "lightblue";
|
||||
@@ -386,7 +396,8 @@ public sealed partial class CharacterItemGroupRequirement : CharacterRequirement
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0
|
||||
int depth = 0,
|
||||
MindComponent? mind = null
|
||||
)
|
||||
{
|
||||
var group = prototypeManager.Index(Group);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Roles;
|
||||
using JetBrains.Annotations;
|
||||
@@ -27,7 +28,8 @@ public sealed partial class CharacterWhitelistRequirement : CharacterRequirement
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0)
|
||||
int depth = 0,
|
||||
MindComponent? mind = null)
|
||||
{
|
||||
reason = null;
|
||||
if (!configManager.IsCVarRegistered("whitelist.enabled"))
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Roles;
|
||||
using JetBrains.Annotations;
|
||||
@@ -36,6 +37,7 @@ public abstract partial class CharacterRequirement
|
||||
IPrototypeManager prototypeManager,
|
||||
IConfigurationManager configManager,
|
||||
out string? reason,
|
||||
int depth = 0
|
||||
int depth = 0,
|
||||
MindComponent? mind = null
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
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;
|
||||
@@ -13,7 +17,14 @@ 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,
|
||||
@@ -30,10 +41,34 @@ public sealed class CharacterRequirementsSystem : EntitySystem
|
||||
: !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)
|
||||
out List<string> reasons, int depth = 0, MindComponent? mind = null)
|
||||
{
|
||||
reasons = new List<string>();
|
||||
var valid = true;
|
||||
@@ -44,7 +79,7 @@ public sealed class CharacterRequirementsSystem : EntitySystem
|
||||
// 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))
|
||||
out var reason, depth, mind))
|
||||
{
|
||||
if (valid)
|
||||
valid = requirement.Inverted;
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Shared.Players.PlayTimeTracking;
|
||||
|
||||
public interface ISharedPlaytimeManager;
|
||||
public interface ISharedPlaytimeManager
|
||||
{
|
||||
bool TryGetTrackerTimes(ICommonSession id, [NotNullWhen(true)] out Dictionary<string, TimeSpan>? time);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared.Customization.Systems;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Traits.Assorted.Components;
|
||||
@@ -5,9 +6,15 @@ namespace Content.Shared.Traits.Assorted.Components;
|
||||
[Serializable, NetSerializable, DataDefinition]
|
||||
public sealed partial class DescriptionExtension
|
||||
{
|
||||
[DataField]
|
||||
public List<CharacterRequirement>? Requirements;
|
||||
|
||||
[DataField]
|
||||
public string Description = "";
|
||||
|
||||
[DataField]
|
||||
public string RequirementsNotMetDescription = "";
|
||||
|
||||
[DataField]
|
||||
public int FontSize = 12;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared.Customization.Systems;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Traits.Assorted.Components;
|
||||
|
||||
@@ -5,6 +6,8 @@ namespace Content.Shared.Traits.Assorted.Systems;
|
||||
|
||||
public sealed class ExtendDescriptionSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly CharacterRequirementsSystem _characterRequirements = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -18,10 +21,15 @@ public sealed class ExtendDescriptionSystem : EntitySystem
|
||||
|
||||
foreach (var desc in component.DescriptionList)
|
||||
{
|
||||
if (!args.IsInDetailsRange && desc.RequireDetailRange)
|
||||
if (!args.IsInDetailsRange && desc.RequireDetailRange
|
||||
|| !TryComp(args.Examiner, out MetaDataComponent? comp) || comp.EntityPrototype == null)
|
||||
continue;
|
||||
|
||||
args.PushMarkup($"[font size ={desc.FontSize}][color={desc.Color}]{Loc.GetString(desc.Description, ("entity", uid))}[/color][/font]");
|
||||
var meetsRequirements = desc.Requirements == null || _characterRequirements.CheckRequirementsValid(desc.Requirements, args.Examiner, comp.EntityPrototype, out _);
|
||||
var description = meetsRequirements ? desc.Description : desc.RequirementsNotMetDescription;
|
||||
|
||||
if(description != string.Empty)
|
||||
args.PushMarkup($"[font size ={desc.FontSize}][color={desc.Color}]{Loc.GetString(description, ("entity", uid))}[/color][/font]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,16 @@ character-department-requirement = You must{$inverted ->
|
||||
*[other]{""}
|
||||
} be in one of these departments: {$departments}
|
||||
|
||||
character-antagonist-requirement = You must{$inverted ->
|
||||
[true]{" "}not
|
||||
*[other]{""}
|
||||
} be an antagonist
|
||||
|
||||
character-mindshield-requirement = You must{$inverted ->
|
||||
[true]{" "}not
|
||||
*[other]{""}
|
||||
} be mindshielded
|
||||
|
||||
character-timer-department-insufficient = You require [color=yellow]{TOSTRING($time, "0")}[/color] more minutes of [color={$departmentColor}]{$department}[/color] department playtime
|
||||
character-timer-department-too-high = You require [color=yellow]{TOSTRING($time, "0")}[/color] fewer minutes in [color={$departmentColor}]{$department}[/color] department
|
||||
|
||||
@@ -153,7 +163,7 @@ character-whitelist-requirement = You must{$inverted ->
|
||||
|
||||
## CVar
|
||||
|
||||
character-cvar-requirement =
|
||||
character-cvar-requirement =
|
||||
The server must{$inverted ->
|
||||
[true]{" "}not
|
||||
*[other]{""}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
emag-extenddescription-engineering = An illegal hacking tool used to subvert station electronics.
|
||||
emag-extenddescription-security = An advanced illegal hacking tool used by criminal operatives.
|
||||
emag-extenddescription-command = A dangerous illegal tool used by hostile operatives.
|
||||
emag-extenddescription-epistemics = An illegal hacking tool that can cause targeted damage to circuits, gaining access or modifying behaviour.
|
||||
emag-extenddescription-syndicate = The all-in-one hacking solution. The thinking man's lockpick. The iconic EMAG.
|
||||
28
Resources/Locale/en-US/extenddescriptions/mindshield.ftl
Normal file
28
Resources/Locale/en-US/extenddescriptions/mindshield.ftl
Normal file
@@ -0,0 +1,28 @@
|
||||
mindshield-extenddescription-emag = I feel an overwhelming urge to turn this item in to Security.
|
||||
mindshield-extenddescription-poster-atmosia = Doomed from the start. Nanotrasen cannot be defeated by rebels!
|
||||
mindshield-extenddescription-poster-funpolice = The security staff is here for our protection.
|
||||
mindshield-extenddescription-poster-syndicaterecruitment = This poster is treasonous! I feel an overwhelming urge to take it down.
|
||||
mindshield-extenddescription-poster-contrabandsmoke = Only a fool would take these over the smokes recommended by Nanotrasen!
|
||||
mindshield-extenddescription-poster-greytide = Those unwashed masses should be praising Nanotrasen for permitting them on the station.
|
||||
mindshield-extenddescription-poster-ripbadger = Anyone with a brain should realize that this story is complete falsehood...
|
||||
mindshield-extenddescription-poster-contrabandpower = Foolish. Nanotrasen knows what's best for us.
|
||||
mindshield-extenddescription-poster-KosmicheskayaStantsiya = If Nanotrasen says it doesn't exist, it doesn't exist.
|
||||
mindshield-extenddescription-poster-rebelsunite = Why would anyone rebel against such a wonderful organisation like Nanotrasen?
|
||||
mindshield-extenddescription-poster-freedrone = That drone was a danger to us all. We should be happy CentCom destroyed it.
|
||||
mindshield-extenddescription-poster-syndicateencryption = As if anyone could break Nanotrasen secure radio systems!
|
||||
mindshield-extenddescription-poster-cybersun600 = Six hundred years too many.
|
||||
mindshield-extenddescription-poster-foryoursafety = Heroes of the station.
|
||||
mindshield-extenddescription-poster-nanotrasen = I feel an intense urge to salute.
|
||||
mindshield-extenddescription-poster-helpothers = The camaraderie Nanotrasen personnel is known for!
|
||||
mindshield-extenddescription-poster-obey = Nanotrasen's wish is my command!
|
||||
mindshield-extenddescription-poster-donotquestion = Nanotrasen knows best!
|
||||
mindshield-extenddescription-poster-safetyreport = It's necessary for our own safety.
|
||||
mindshield-extenddescription-poster-reportcrimes = We cannot let criminals threaten the security of this station!
|
||||
mindshield-extenddescription-poster-vintagereprint50 = Fifty beautiful years of informative posters!
|
||||
mindshield-extenddescription-poster-pdaad = How can anyone else even compete against Nanotrasen standards?
|
||||
mindshield-extenddescription-poster-enlist = Their heroics bring a tear to my eye.
|
||||
mindshield-extenddescription-poster-theowl = Everyone should do their part!
|
||||
mindshield-extenddescription-poster-nogasgiant = It would be silly to believe otherwise.
|
||||
mindshield-extenddescription-poster-watchingyou = I feel safe under their protective gaze.
|
||||
mindshield-extenddescription-poster-vacation = Looking at it makes me proud to work for Nanotrasen.
|
||||
mindshield-extenddescription-poster-buycards = I feel the urge to purchase another pack...
|
||||
@@ -3,12 +3,65 @@
|
||||
id: EmagUnlimited
|
||||
suffix: Unlimited
|
||||
name: cryptographic sequencer
|
||||
description: The all-in-one hacking solution. The thinking man's lockpick. The iconic EMAG.
|
||||
description: A red circuit board with a charge indicator.
|
||||
components:
|
||||
- type: Emag
|
||||
blacklist: # DeltaV - Split Emag into 2 items, this one cannot emag doors
|
||||
components:
|
||||
- Airlock
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "emag-extenddescription-command"
|
||||
fontSize: 12
|
||||
color: "#1155ff"
|
||||
requireDetailRange: true
|
||||
requirements:
|
||||
- !type:CharacterDepartmentRequirement
|
||||
departments:
|
||||
- Command
|
||||
- description: "emag-extenddescription-engineering"
|
||||
fontSize: 12
|
||||
color: "#ffaf00"
|
||||
requireDetailRange: true
|
||||
requirements:
|
||||
- !type:CharacterDepartmentRequirement
|
||||
departments:
|
||||
- Engineering
|
||||
- description: "emag-extenddescription-security"
|
||||
fontSize: 12
|
||||
color: "#ff0000"
|
||||
requireDetailRange: true
|
||||
requirements:
|
||||
- !type:CharacterDepartmentRequirement
|
||||
departments:
|
||||
- Security
|
||||
- description: "emag-extenddescription-epistemics"
|
||||
fontSize: 12
|
||||
color: "#aa00aa"
|
||||
requireDetailRange: true
|
||||
requirements:
|
||||
- !type:CharacterDepartmentRequirement
|
||||
departments:
|
||||
- Epistemics
|
||||
- description: "emag-extenddescription-syndicate"
|
||||
fontSize: 12
|
||||
color: "#880000"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterAntagonistRequirement
|
||||
antagonists:
|
||||
- Traitor
|
||||
- TraitorSleeper
|
||||
- SpaceNinja
|
||||
- Nukeops
|
||||
- NukeopsMedic
|
||||
- NukeopsCommander
|
||||
- description: "mindshield-extenddescription-emag"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: true
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
- type: Sprite
|
||||
sprite: Objects/Tools/emag.rsi
|
||||
state: icon
|
||||
|
||||
@@ -149,6 +149,24 @@
|
||||
visible: false
|
||||
shader: unshaded
|
||||
- type: Flash
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "flash-extenddescription-headrevolutionary"
|
||||
fontSize: 12
|
||||
color: "#880000"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterAntagonistRequirement
|
||||
antagonists:
|
||||
- HeadRev
|
||||
- description: "flash-extenddescription-revolutionary"
|
||||
fontSize: 12
|
||||
color: "#880000"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterAntagonistRequirement
|
||||
antagonists:
|
||||
- Rev
|
||||
- type: LimitedCharges
|
||||
maxCharges: 5
|
||||
charges: 5
|
||||
|
||||
@@ -67,6 +67,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster2_contraband
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-atmosia"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -76,6 +84,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster3_contraband
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-funpolice"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -94,6 +110,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster5_contraband
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-syndicaterecruitment"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -112,6 +136,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster7_contraband
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-contrabandsmoke"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -121,6 +153,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster8_contraband
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-greytide"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -148,6 +188,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster11_contraband
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-ripbadger"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -193,6 +241,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster16_contraband
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-contrabandpower"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -247,6 +303,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster22_contraband
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-KosmicheskayaStantsiya"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -256,6 +320,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster23_contraband
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-rebelsunite"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -355,6 +427,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster35_contraband
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-freedrone"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -454,6 +534,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster46_contraband
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-syndicateencryption"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -554,6 +642,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster58_contraband
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-cybersun600"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -590,7 +686,7 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster62_contraband
|
||||
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
id: PosterContrabandMissingSpacepen
|
||||
@@ -609,6 +705,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster1_legit
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-foryoursafety"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -618,6 +722,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster2_legit
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-nanotrasen"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -636,6 +748,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster4_legit
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-helpothers"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -681,6 +801,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster9_legit
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-obey"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -744,6 +872,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster16_legit
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-donotquestion"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -789,6 +925,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster21_legit
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-safetyreport"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -798,6 +942,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster22_legit
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-reportcrimes"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -834,6 +986,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster26_legit
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-vintagereprint50"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -852,6 +1012,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster28_legit
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-pdaad"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -861,6 +1029,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster29_legit
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-enlist"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -897,6 +1073,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster33_legit
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-theowl"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -933,6 +1117,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster37_legit
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-nogasgiant"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -951,6 +1143,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster39_legit
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-watchingyou"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -1032,6 +1232,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster48_legit
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-vacation"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
@@ -1059,6 +1267,14 @@
|
||||
components:
|
||||
- type: Sprite
|
||||
state: poster51_legit
|
||||
- type: ExtendDescription
|
||||
descriptionList:
|
||||
- description: "mindshield-extenddescription-poster-buycards"
|
||||
fontSize: 12
|
||||
color: "#11aaff"
|
||||
requireDetailRange: false
|
||||
requirements:
|
||||
- !type:CharacterMindshieldRequirement
|
||||
|
||||
- type: entity
|
||||
parent: PosterBase
|
||||
|
||||
Reference in New Issue
Block a user