diff --git a/Content.Client/Humanoid/MarkingPicker.xaml.cs b/Content.Client/Humanoid/MarkingPicker.xaml.cs index 80b4270c3e7..6dd9d3d9e92 100644 --- a/Content.Client/Humanoid/MarkingPicker.xaml.cs +++ b/Content.Client/Humanoid/MarkingPicker.xaml.cs @@ -22,6 +22,10 @@ using Robust.Shared.Prototypes; using Robust.Shared.Utility; using static Robust.Client.UserInterface.Controls.BoxContainer; +// Arcane - Start +using Content.Shared._Arcane.SpecialWhitelist; +using Robust.Client.Player; +// Arcane - End namespace Content.Client.Humanoid; @@ -31,6 +35,7 @@ public sealed partial class MarkingPicker : Control [Dependency] private readonly MarkingManager _markingManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly IPlayerManager _playerManager = default!; // Arcane private readonly SpriteSystem _sprite; @@ -239,8 +244,13 @@ public void Populate(string filter) continue; } + // Arcane - Start + if (!MarkingWhitelistManager.IsMarkingAllowed(marking, _playerManager.LocalSession)) + continue; + // Arcane - End + var item = CMarkingsUnused.AddItem($"{GetMarkingName(marking)}", _sprite.Frame0(marking.Sprites[0])); - item.Metadata = marking; + item.Metadata = marking; } CMarkingPoints.Visible = _currentMarkings.PointsLeft(_selectedMarkingCategory) != -1; @@ -561,4 +571,4 @@ private void MarkingRemove() CMarkingColors.Visible = false; OnMarkingRemoved?.Invoke(_currentMarkings); } -} \ No newline at end of file +} diff --git a/Content.Client/Humanoid/SingleMarkingPicker.xaml.cs b/Content.Client/Humanoid/SingleMarkingPicker.xaml.cs index 6bad2c2c57c..2ed8fe8227f 100644 --- a/Content.Client/Humanoid/SingleMarkingPicker.xaml.cs +++ b/Content.Client/Humanoid/SingleMarkingPicker.xaml.cs @@ -13,6 +13,8 @@ using Robust.Client.GameObjects; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; +using Content.Shared._Arcane.SpecialWhitelist; +using Robust.Client.Player; namespace Content.Client.Humanoid; @@ -21,6 +23,7 @@ public sealed partial class SingleMarkingPicker : BoxContainer { [Dependency] private readonly MarkingManager _markingManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly IPlayerManager _playerManager = default!; // Arcane private readonly SpriteSystem _sprite; @@ -201,6 +204,12 @@ public void PopulateList(string filter) foreach (var (id, marking) in sortedMarkings) { + // Arcane - Start + if (!MarkingWhitelistManager.IsMarkingAllowed(marking, _playerManager.LocalSession)) + { + continue; + } + // Arcane - End var item = MarkingList.AddItem(Loc.GetString($"marking-{id}"), _sprite.Frame0(marking.Sprites[0])); item.Metadata = marking.ID; @@ -310,4 +319,4 @@ private string GetMarkingName(MarkingPrototype marking) { return Loc.GetString($"marking-{marking.ID}"); } -} \ No newline at end of file +} diff --git a/Content.Shared/Humanoid/Markings/MarkingPrototype.cs b/Content.Shared/Humanoid/Markings/MarkingPrototype.cs index 152610a216a..f92b1cb1086 100644 --- a/Content.Shared/Humanoid/Markings/MarkingPrototype.cs +++ b/Content.Shared/Humanoid/Markings/MarkingPrototype.cs @@ -17,6 +17,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Utility; +using Content.Shared._Arcane.SpecialWhitelist; namespace Content.Shared.Humanoid.Markings { @@ -69,5 +70,9 @@ public Marking AsMarking() { return new Marking(ID, Sprites.Count); } + // Arcane - Start + [DataField("whitelist")] + public MarkingWhitelistData? Whitelist { get; private set; } + // Arcane - End } } diff --git a/Content.Shared/Preferences/HumanoidCharacterProfile.cs b/Content.Shared/Preferences/HumanoidCharacterProfile.cs index 4d825e206da..4e05dedbd62 100644 --- a/Content.Shared/Preferences/HumanoidCharacterProfile.cs +++ b/Content.Shared/Preferences/HumanoidCharacterProfile.cs @@ -69,6 +69,10 @@ using Robust.Shared.Random; using Robust.Shared.Serialization; using Robust.Shared.Utility; +// Arcane - Start +using Content.Shared.Humanoid.Markings; +using Content.Shared._Arcane.SpecialWhitelist; +// Arcane - End namespace Content.Shared.Preferences { @@ -1106,6 +1110,16 @@ public void EnsureValid(ICommonSession session, IDependencyCollection collection { _loadouts.Remove(value); } + // Arcane - Start + foreach (var markingId in Appearance.Markings.ToList()) + { + if (!prototypeManager.TryIndex(markingId.MarkingId, out var proto)) + continue; + + if (!MarkingWhitelistManager.IsMarkingAllowed(proto, session)) + Appearance.Markings.Remove(markingId); + } + // Arcane - End } // Art-TTS Start diff --git a/Content.Shared/_Arcane/MarkingWhitelistData.cs b/Content.Shared/_Arcane/MarkingWhitelistData.cs new file mode 100644 index 00000000000..88789d1bc2a --- /dev/null +++ b/Content.Shared/_Arcane/MarkingWhitelistData.cs @@ -0,0 +1,10 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared._Arcane.SpecialWhitelist; + +[DataDefinition] +public sealed partial class MarkingWhitelistData +{ + [DataField("allowed")] + public List Allowed { get; private set; } = new(); +} diff --git a/Content.Shared/_Arcane/MarkingWhitelistManager.cs b/Content.Shared/_Arcane/MarkingWhitelistManager.cs new file mode 100644 index 00000000000..63af2b62ee0 --- /dev/null +++ b/Content.Shared/_Arcane/MarkingWhitelistManager.cs @@ -0,0 +1,29 @@ +using Content.Shared.Humanoid.Markings; +using Robust.Shared.Player; + +namespace Content.Shared._Arcane.SpecialWhitelist; + +public static class MarkingWhitelistManager +{ + public static bool IsMarkingAllowed(MarkingPrototype marking, ICommonSession? session) + { + // Если вайтлиста нет — разметка доступна всем + if (marking.Whitelist == null || marking.Whitelist.Allowed.Count == 0) + return true; + + // Если сессии нет (например, локальный просмотр без игрока), скрываем на всякий случай + if (session == null) + return false; + + // Для привязки к аккаунту используем login username, а не отображаемое имя персонажа. + var ckey = session.Data.UserName; + + foreach (var allowedCkey in marking.Whitelist.Allowed) + { + if (string.Equals(allowedCkey, ckey, StringComparison.OrdinalIgnoreCase)) + return true; + } + + return false; + } +} diff --git a/Resources/Locale/ru-RU/_Arcane/markings/humanoid_xeno.ftl b/Resources/Locale/ru-RU/_Arcane/markings/humanoid_xeno.ftl index 792bbf10659..86d7d5fca0a 100644 --- a/Resources/Locale/ru-RU/_Arcane/markings/humanoid_xeno.ftl +++ b/Resources/Locale/ru-RU/_Arcane/markings/humanoid_xeno.ftl @@ -8,6 +8,7 @@ marking-HumanoidXenoTailRunner = Хвост бегуна marking-HumanoidXenoTailBoiler = Хвост бойлера marking-HumanoidXenoTailCrusher = Хвост крушителя marking-HumanoidXenoTailNeomprph = Хвост неоморфа +marking-HumanoidXenoTailRen = Хвост Рэна marking-HumanoidXenoTailQueenLong = Длинный хвост королевы marking-HumanoidXenoHeadDrone = Голова дрона marking-HumanoidXenoHeadSpitter = Голова плевателя @@ -21,6 +22,7 @@ marking-HumanoidXenoHeadCrusher = Голова крушителя marking-HumanoidXenoHeadCarrier = Голова носителя marking-HumanoidXenoHeadNeomorph = Голова неоморфа marking-HumanoidXenoHeadWorker = Голова рабочего +marking-HumanoidXenoHeadRen = Голова Рэна marking-HumanoidXenoChestPredalien = Грудь предалиена marking-HumanoidXenoChestSpitter = Грудь плевателя marking-HumanoidXenoChestMuscles = "Мышцы" @@ -35,6 +37,7 @@ marking-HumanoidXenoTracheasBoiler = Трахеи бойлера marking-HumanoidXenoTracheasCrusher = Трахеи крушителя marking-HumanoidXenoTracheasNeomorph = Трахеи неоморфа marking-HumanoidXenoTracheasCarrier = Трахеи носителя +marking-HumanoidXenoTracheasRen = Трахеи Рэна marking-HumanoidXenoLegsPredalien = Ноги предалиена marking-HumanoidXenoLegsMuscles = "Мышцы" marking-HumanoidXenoArmsPredalien = Руки предалиена diff --git a/Resources/Prototypes/_Arcane/Entities/Mobs/Customization/Markings/humanoid_xeno.yml b/Resources/Prototypes/_Arcane/Entities/Mobs/Customization/Markings/humanoid_xeno.yml index e734ba9a304..f7c61271be0 100644 --- a/Resources/Prototypes/_Arcane/Entities/Mobs/Customization/Markings/humanoid_xeno.yml +++ b/Resources/Prototypes/_Arcane/Entities/Mobs/Customization/Markings/humanoid_xeno.yml @@ -117,6 +117,20 @@ - sprite: _Arcane/Mobs/Customization/HumanoidXeno/tail.rsi state: neomorph_tail +- type: marking + id: HumanoidXenoTailRen + bodyPart: Tail + markingCategory: Tail + speciesRestriction: [HumanoidXeno] + sprites: + - sprite: _Arcane/Mobs/Customization/HumanoidXeno/tail.rsi + state: ren_tail + - sprite: _Arcane/Mobs/Customization/HumanoidXeno/tail.rsi + state: ren_tail_grad + whitelist: + allowed: + - Bulbo44key + # Head - type: marking @@ -281,6 +295,18 @@ - sprite: _Arcane/Mobs/Customization/HumanoidXeno/head.rsi state: worker_shine +- type: marking + id: HumanoidXenoHeadRen + bodyPart: Head + markingCategory: Head + speciesRestriction: [HumanoidXeno] + sprites: + - sprite: _Arcane/Mobs/Customization/HumanoidXeno/head.rsi + state: ren_head + whitelist: + allowed: + - Bulbo44key + # Chest - type: marking @@ -411,6 +437,18 @@ - sprite: _Arcane/Mobs/Customization/HumanoidXeno/long_tracheas.rsi state: carrier_tubes +- type: marking + id: HumanoidXenoTracheasRen + bodyPart: Chest + markingCategory: Tracheas + speciesRestriction: [HumanoidXeno] + sprites: + - sprite: _Arcane/Mobs/Customization/HumanoidXeno/tracheas.rsi + state: ren_tubes + whitelist: + allowed: + - Bulbo44key + # Legs - type: marking diff --git a/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi/meta.json b/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi/meta.json index 23fcc137ada..ac84ce667de 100644 --- a/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi/meta.json +++ b/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi/meta.json @@ -138,6 +138,10 @@ { "name": "worker_teeth", "directions": 4 + }, + { + "name": "ren_head", + "directions": 4 } ] } diff --git a/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi/ren_head.png b/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi/ren_head.png new file mode 100644 index 00000000000..c7dd57d04e7 Binary files /dev/null and b/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi/ren_head.png differ diff --git a/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi/meta.json b/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi/meta.json index ab4cea8c9b9..04d97a7ccda 100644 --- a/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi/meta.json +++ b/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi/meta.json @@ -66,6 +66,14 @@ { "name": "neomorph_tail", "directions": 4 + }, + { + "name": "ren_tail", + "directions": 4 + }, + { + "name": "ren_tail_grad", + "directions": 4 } ] } diff --git a/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi/ren_tail.png b/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi/ren_tail.png new file mode 100644 index 00000000000..2a594fbf0b1 Binary files /dev/null and b/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi/ren_tail.png differ diff --git a/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi/ren_tail_grad.png b/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi/ren_tail_grad.png new file mode 100644 index 00000000000..2fa6c79eb32 Binary files /dev/null and b/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi/ren_tail_grad.png differ diff --git a/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tracheas.rsi/meta.json b/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tracheas.rsi/meta.json index 893d2bff650..d18b94f2a48 100644 --- a/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tracheas.rsi/meta.json +++ b/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tracheas.rsi/meta.json @@ -34,6 +34,10 @@ { "name": "neomorph_tubes", "directions": 4 + }, + { + "name": "ren_tubes", + "directions": 4 } ] } diff --git a/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tracheas.rsi/ren_tubes.png b/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tracheas.rsi/ren_tubes.png new file mode 100644 index 00000000000..d1996719480 Binary files /dev/null and b/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tracheas.rsi/ren_tubes.png differ