diff --git a/Content.Client/Humanoid/MarkingPicker.xaml.cs b/Content.Client/Humanoid/MarkingPicker.xaml.cs
index 847f8d2d5a2..44b4f757c9f 100644
--- a/Content.Client/Humanoid/MarkingPicker.xaml.cs
+++ b/Content.Client/Humanoid/MarkingPicker.xaml.cs
@@ -1,11 +1,13 @@
// SPDX-License-Identifier: MIT
using System.Linq;
+using Content.Shared._Arcane.DiscordRoles;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Markings;
using Content.Shared.Humanoid.Prototypes;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
+using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
@@ -21,6 +23,10 @@ public sealed partial class MarkingPicker : Control
[Dependency] private readonly MarkingManager _markingManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
+ // Arcane-Start
+ [Dependency] private readonly ISharedDiscordRoleManager _discordRoles = default!;
+ [Dependency] private readonly IPlayerManager _player = default!;
+ // Arcane-End
private readonly SpriteSystem _sprite;
@@ -231,6 +237,10 @@ public void Populate(string filter)
var item = CMarkingsUnused.AddItem($"{GetMarkingName(marking)}", _sprite.Frame0(marking.Sprites[0]));
item.Metadata = marking;
+
+ // Arcane-Start
+ SetMarkingUnavailableIfNeeded(item, marking);
+ // Arcane-End
}
CMarkingPoints.Visible = _currentMarkings.PointsLeft(_selectedMarkingCategory) != -1;
@@ -499,6 +509,15 @@ private void MarkingAdd()
}
var marking = (MarkingPrototype) _selectedUnusedMarking.Metadata!;
+
+ // Arcane-Start
+ if (!marking.CanUse(_discordRoles, _player.LocalSession, out _))
+ {
+ _selectedUnusedMarking = null;
+ return;
+ }
+ // Arcane-End
+
var markingObject = marking.AsMarking();
// We need add hair markings in cloned set manually because _currentMarkings doesn't have it
@@ -571,9 +590,24 @@ private void MarkingRemove()
{
var item = CMarkingsUnused.AddItem($"{GetMarkingName(marking)}", _sprite.Frame0(marking.Sprites[0]));
item.Metadata = marking;
+
+ // Arcane-Start
+ SetMarkingUnavailableIfNeeded(item, marking);
+ // Arcane-End
}
_selectedMarking = null;
CMarkingColors.Visible = false;
OnMarkingRemoved?.Invoke(_currentMarkings);
}
-}
\ No newline at end of file
+
+ // Arcane-Start
+ private void SetMarkingUnavailableIfNeeded(ItemList.Item item, MarkingPrototype marking)
+ {
+ if (!marking.CanUse(_discordRoles, _player.LocalSession, out var reason))
+ {
+ item.Disabled = true;
+ item.TooltipText = reason?.ToString();
+ }
+ }
+ // Arcane-End
+}
diff --git a/Content.Client/Humanoid/SingleMarkingPicker.xaml.cs b/Content.Client/Humanoid/SingleMarkingPicker.xaml.cs
index b1511c1af4f..024d5ff2e49 100644
--- a/Content.Client/Humanoid/SingleMarkingPicker.xaml.cs
+++ b/Content.Client/Humanoid/SingleMarkingPicker.xaml.cs
@@ -1,9 +1,11 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
using System.Linq;
+using Content.Shared._Arcane.DiscordRoles;
using Content.Shared.Humanoid.Markings;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
+using Robust.Client.Player;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
@@ -14,6 +16,10 @@ public sealed partial class SingleMarkingPicker : BoxContainer
{
[Dependency] private readonly MarkingManager _markingManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
+ // Arcane-Start
+ [Dependency] private readonly ISharedDiscordRoleManager _discordRoles = default!;
+ [Dependency] private readonly IPlayerManager _player = default!;
+ // Arcane-End
private readonly SpriteSystem _sprite;
@@ -177,7 +183,9 @@ public void PopulateList(string filter)
throw new ArgumentException("Tried to populate marking list without a set species!");
}
+ // Arcane-Start
_markingPrototypeCache ??= _markingManager.MarkingsByCategoryAndSpecies(Category, _species);
+ // Arcane-End
MarkingSelectorContainer.Visible = _markings != null && _markings.Count != 0;
if (_markings == null || _markings.Count == 0)
@@ -197,7 +205,16 @@ public void PopulateList(string filter)
var item = MarkingList.AddItem(Loc.GetString($"marking-{id}"), _sprite.Frame0(marking.Sprites[0]));
item.Metadata = marking.ID;
- if (_markings[Slot].MarkingId == id)
+ // Arcane-Start
+ var isCurrent = _markings![Slot].MarkingId == id;
+ if (!isCurrent && !marking.CanUse(_discordRoles, _player.LocalSession, out var reason))
+ {
+ item.Disabled = true;
+ item.TooltipText = reason?.ToString();
+ }
+ // Arcane-End
+
+ if (isCurrent)
{
_ignoreItemSelected = true;
item.Selected = true;
@@ -302,4 +319,4 @@ private string GetMarkingName(MarkingPrototype marking)
{
return Loc.GetString($"marking-{marking.ID}");
}
-}
\ No newline at end of file
+}
diff --git a/Content.Server/_Arcane/DiscordRoles/DiscordRoleIds.cs b/Content.Server/_Arcane/DiscordRoles/DiscordRoleIds.cs
index df7208bc56e..2a8a0388162 100644
--- a/Content.Server/_Arcane/DiscordRoles/DiscordRoleIds.cs
+++ b/Content.Server/_Arcane/DiscordRoles/DiscordRoleIds.cs
@@ -13,6 +13,7 @@ public static class DiscordRoleIds
[DiscordRole.SponsorTier1] = 1510991486399942707,
[DiscordRole.SponsorTier2] = 1510991694785675397,
[DiscordRole.AdminBenefit] = 1545943229143195658,
+ [DiscordRole.ArtLead] = 1509175991241670696,
[DiscordRole.UnlockRoles] = 1533054913318223872,
};
}
diff --git a/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs b/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs
index b0f8eeebd4a..8bf9e7d70b7 100644
--- a/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs
+++ b/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs
@@ -2,8 +2,10 @@
using System.Linq;
using System.Numerics;
+using Content.Shared._Arcane.DiscordRoles;
using Content.Shared.Humanoid.Markings;
using Content.Shared.Humanoid.Prototypes;
+using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Serialization;
@@ -236,7 +238,8 @@ public static Color ClampColor(Color color)
return new(color.RByte, color.GByte, color.BByte);
}
- public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearance appearance, string species, Sex sex)
+ public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearance appearance, string species, Sex sex,
+ ISharedDiscordRoleManager? discordRoles = null, ICommonSession? session = null) // Arcane
{
var hairStyleId = appearance.HairStyleId;
var facialHairStyleId = appearance.FacialHairStyleId;
@@ -264,6 +267,7 @@ public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearanc
{
markingSet = new MarkingSet(appearance.Markings, speciesProto.MarkingPoints, markingManager, proto);
markingSet.EnsureValid(markingManager);
+ markingSet.EnsureEffects(discordRoles, session, markingManager); // Arcane
var strategy = proto.Index(speciesProto.SkinColoration).Strategy;
skinColor = strategy.EnsureVerified(skinColor);
diff --git a/Content.Shared/Humanoid/Markings/Effects/MarkingEffect.cs b/Content.Shared/Humanoid/Markings/Effects/MarkingEffect.cs
new file mode 100644
index 00000000000..8fe6b7fce9b
--- /dev/null
+++ b/Content.Shared/Humanoid/Markings/Effects/MarkingEffect.cs
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+using System.Diagnostics.CodeAnalysis;
+using Content.Shared._Arcane.DiscordRoles;
+using Robust.Shared.Player;
+using Robust.Shared.Utility;
+
+namespace Content.Shared.Humanoid.Markings.Effects;
+
+///
+/// Base class for effects that gate whether a marking may be used by a given session.
+///
+[ImplicitDataDefinitionForInheritors]
+public abstract partial class MarkingEffect
+{
+ ///
+ /// Tries to validate whether the marking is available to the session.
+ ///
+ public abstract bool Validate(
+ MarkingPrototype marking,
+ ICommonSession? session,
+ ISharedDiscordRoleManager? discordRoles,
+ [NotNullWhen(false)] out FormattedMessage? reason);
+}
diff --git a/Content.Shared/Humanoid/Markings/MarkingManager.cs b/Content.Shared/Humanoid/Markings/MarkingManager.cs
index 95b2846fe3e..0a501e35d42 100644
--- a/Content.Shared/Humanoid/Markings/MarkingManager.cs
+++ b/Content.Shared/Humanoid/Markings/MarkingManager.cs
@@ -50,7 +50,7 @@ public FrozenDictionary MarkingsByCategory(MarkingCate
}
///
- /// Markings by category and species.
+ /// Filters and colors markings based on species and it's restrictions in the marking's prototype from this marking set.
///
///
///
diff --git a/Content.Shared/Humanoid/Markings/MarkingPrototype.cs b/Content.Shared/Humanoid/Markings/MarkingPrototype.cs
index 4f031d25478..26ef208d814 100644
--- a/Content.Shared/Humanoid/Markings/MarkingPrototype.cs
+++ b/Content.Shared/Humanoid/Markings/MarkingPrototype.cs
@@ -1,5 +1,8 @@
// SPDX-License-Identifier: MIT
+using Content.Shared._Arcane.DiscordRoles;
+using Content.Shared.Humanoid.Markings.Effects;
+using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
@@ -44,6 +47,33 @@ public sealed partial class MarkingPrototype : IPrototype
[DataField("sprites", required: true)]
public List Sprites { get; private set; } = default!;
+ // Arcane-Start
+ ///
+ /// Effects that gate whether this marking may be used by a given session. Empty means no restriction.
+ ///
+ [DataField("effects")]
+ public List Effects { get; private set; } = new();
+
+ public bool CanUse(ISharedDiscordRoleManager? discordRoles, ICommonSession? session)
+ => CanUse(discordRoles, session, out _);
+
+ public bool CanUse(ISharedDiscordRoleManager? discordRoles, ICommonSession? session, out FormattedMessage? reason)
+ {
+ reason = null;
+
+ if (discordRoles == null || session == null)
+ return true;
+
+ foreach (var effect in Effects)
+ {
+ if (!effect.Validate(this, session, discordRoles, out reason))
+ return false;
+ }
+
+ return true;
+ }
+ // Arcane-End
+
/// Impstation start
[DataField]
public string? Shader { get; private set; } = null;
diff --git a/Content.Shared/Humanoid/Markings/MarkingsSet.cs b/Content.Shared/Humanoid/Markings/MarkingsSet.cs
index 440a28c2be9..31d329e11f7 100644
--- a/Content.Shared/Humanoid/Markings/MarkingsSet.cs
+++ b/Content.Shared/Humanoid/Markings/MarkingsSet.cs
@@ -3,7 +3,9 @@
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
+using Content.Shared._Arcane.DiscordRoles;
using Content.Shared.Humanoid.Prototypes;
+using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
@@ -234,6 +236,42 @@ public void EnsureSexes(Sex sex, MarkingManager? markingManager = null)
}
}
+ // Arcane-Start
+ ///
+ /// Removes markings whose effects reject the session.
+ ///
+ /// Discord role manager, used by sponsor effects.
+ /// The session to check, or null to skip filtering.
+ /// Marking manager.
+ public void EnsureEffects(ISharedDiscordRoleManager? discordRoles, ICommonSession? session,
+ MarkingManager? markingManager = null)
+ {
+ IoCManager.Resolve(ref markingManager);
+
+ var toRemove = new List<(MarkingCategories category, string id)>();
+
+ foreach (var (category, list) in Markings)
+ {
+ foreach (var marking in list)
+ {
+ if (!markingManager.TryGetMarking(marking, out var prototype))
+ {
+ continue;
+ }
+
+ if (!prototype.CanUse(discordRoles, session))
+ {
+ toRemove.Add((category, marking.MarkingId));
+ }
+ }
+ }
+
+ foreach (var remove in toRemove)
+ {
+ Remove(remove.category, remove.id);
+ }
+ }
+
///
/// Ensures that all markings in this set are valid.
///
diff --git a/Content.Shared/Preferences/HumanoidCharacterProfile.cs b/Content.Shared/Preferences/HumanoidCharacterProfile.cs
index 55a87ff56fd..27b370be5b6 100644
--- a/Content.Shared/Preferences/HumanoidCharacterProfile.cs
+++ b/Content.Shared/Preferences/HumanoidCharacterProfile.cs
@@ -61,6 +61,7 @@
using System.Linq;
using System.Text.RegularExpressions;
using Content.Shared._Arcane.CCVars;
+using Content.Shared._Arcane.DiscordRoles;
using Content.Shared._Arcane.TTS;
using Content.Shared.CCVar;
using Content.Shared.GameTicking;
@@ -1107,7 +1108,8 @@ public void EnsureValid(ICommonSession session, IDependencyCollection collection
width = Math.Clamp(Width, speciesPrototype.MinWidth, speciesPrototype.MaxWidth);
// end Goobstation: port EE height/width sliders
- var appearance = HumanoidCharacterAppearance.EnsureValid(Appearance, Species, Sex);
+ var discordRoles = collection.Resolve(); // Arcane
+ var appearance = HumanoidCharacterAppearance.EnsureValid(Appearance, Species, Sex, discordRoles, session); // Arcane-Edit
var prefsUnavailableMode = PreferenceUnavailable switch
{
diff --git a/Content.Shared/_Arcane/DiscordRoles/DiscordRole.cs b/Content.Shared/_Arcane/DiscordRoles/DiscordRole.cs
index cb203ee1cac..704d900a974 100644
--- a/Content.Shared/_Arcane/DiscordRoles/DiscordRole.cs
+++ b/Content.Shared/_Arcane/DiscordRoles/DiscordRole.cs
@@ -8,6 +8,7 @@ public enum DiscordRole : byte
SponsorTier1,
SponsorTier2,
AdminBenefit,
+ ArtLead,
UnlockRoles,
}
diff --git a/Content.Shared/_Arcane/Humanoid/Markings/Effects/SponsorRequirementMarkingEffect.cs b/Content.Shared/_Arcane/Humanoid/Markings/Effects/SponsorRequirementMarkingEffect.cs
new file mode 100644
index 00000000000..17233222bb4
--- /dev/null
+++ b/Content.Shared/_Arcane/Humanoid/Markings/Effects/SponsorRequirementMarkingEffect.cs
@@ -0,0 +1,32 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using Content.Shared._Arcane.DiscordRoles;
+using Content.Shared.Humanoid.Markings;
+using Content.Shared.Humanoid.Markings.Effects;
+using Robust.Shared.Player;
+using Robust.Shared.Utility;
+
+namespace Content.Shared._Arcane.Humanoid.Markings.Effects;
+
+///
+/// Verifies possession of a specific Discord role that unlocks the sponsor marking
+///
+public sealed partial class SponsorRequirementMarkingEffect : MarkingEffect
+{
+ [DataField(required: true)]
+ public HashSet Roles;
+
+ public override bool Validate(
+ MarkingPrototype marking,
+ ICommonSession? session,
+ ISharedDiscordRoleManager? discordRoles,
+ [NotNullWhen(false)] out FormattedMessage? reason)
+ {
+ reason = FormattedMessage.FromUnformatted(Loc.GetString("marking-sponsor-requirement"));
+
+ if (session == null || discordRoles == null)
+ return true;
+
+ return Roles.Any(role => discordRoles.HasRole(session, role));
+ }
+}
diff --git a/Content.Shared/_Arcane/Sponsor/SponsorRoleBenefits.cs b/Content.Shared/_Arcane/Sponsor/SponsorRoleBenefits.cs
index 778e0d3f816..17070a45b63 100644
--- a/Content.Shared/_Arcane/Sponsor/SponsorRoleBenefits.cs
+++ b/Content.Shared/_Arcane/Sponsor/SponsorRoleBenefits.cs
@@ -17,10 +17,12 @@ public static class SponsorRoleBenefits
[DiscordRole.SponsorTier1] = new("Tier1", "#7d25a8", 2, -1),
[DiscordRole.SponsorTier2] = new("Tier2", "#d8aa2d", 3, -2),
[DiscordRole.AdminBenefit] = new("AdminBenefit", "#78ecf5", 5, -3),
+ [DiscordRole.ArtLead] = new("ArtLead", "#ffdaf9", 6, -4)
};
private static readonly DiscordRole[] Priority =
[
+ DiscordRole.ArtLead,
DiscordRole.AdminBenefit,
DiscordRole.SponsorTier2,
DiscordRole.SponsorTier1,
diff --git a/Resources/Locale/ru-RU/_Arcane/markings/humanoid_xeno.ftl b/Resources/Locale/ru-RU/_Arcane/markings/humanoid_xeno.ftl
index 844113d2609..8282dc2cbf7 100644
--- a/Resources/Locale/ru-RU/_Arcane/markings/humanoid_xeno.ftl
+++ b/Resources/Locale/ru-RU/_Arcane/markings/humanoid_xeno.ftl
@@ -21,6 +21,7 @@ marking-HumanoidXenoTailOpress = Хвост угнетателя
marking-HumanoidXenoTailValkyr = Хвост валькирии
marking-HumanoidXenoTailDefender = Хвост защитника
marking-HumanoidXenoTailWarrior = Хвост воина
+marking-HumanoidXenoTailRen = Хвост Рэн
marking-HumanoidXenoHeadDrone = Голова дрона
marking-HumanoidXenoHeadSpitter = Голова плевателя
marking-HumanoidXenoHeadPretor = Голова претора
@@ -44,6 +45,7 @@ marking-HumanoidXenoHeadBurrower = Голова бурильщика
marking-HumanoidXenoHeadDefender = Голова защитника
marking-HumanoidXenoHeadValkyr = Голова валькирии
marking-HumanoidXenoHeadWarrior = Голова воина
+marking-HumanoidXenoHeadRen = Голова Рэн
marking-HumanoidXenoChestPredalien = Грудь предалиена
marking-HumanoidXenoChestSpitter = Грудь плевателя
marking-HumanoidXenoChestMuscles = "Мышцы"
@@ -63,6 +65,7 @@ marking-HumanoidXenoTracheasCougar = Трахеи пумы
marking-HumanoidXenoTracheasCrocodile = Трахеи крокодила
marking-HumanoidXenoTracheasBers = Трахеи берсерка
marking-HumanoidXenoTracheasWarrior = Трахеи воина
+marking-HumanoidXenoTracheasRen = Трахеи Рэн
marking-HumanoidXenoLegsPredalien = Ноги предалиена
marking-HumanoidXenoLegsMuscles = "Мышцы"
marking-HumanoidXenoLegsCougar = Ноги пумы
diff --git a/Resources/Locale/ru-RU/_Arcane/sponsor/sponsor.ftl b/Resources/Locale/ru-RU/_Arcane/sponsor/sponsor.ftl
index 39543c56ad7..80d94103692 100644
--- a/Resources/Locale/ru-RU/_Arcane/sponsor/sponsor.ftl
+++ b/Resources/Locale/ru-RU/_Arcane/sponsor/sponsor.ftl
@@ -5,6 +5,8 @@ not-patron-name = Отсутствует
Tier1-patron-name = [color=#8b00d1]Тир 1[/color]
Tier2-patron-name = [color=#ecad00]Тир 2[/color]
AdminBenefit-patron-name = [color=#ecad00]Хорошая Вахта[/color]
+ArtLead-patron-name = [color=#ffdaf9]Арт-Лид[/color]
loadout-sponsor-requirement = Этот предмет доступен только для спонсоров!
+marking-sponsor-requirement = Этот маркинг доступен только для спонсоров!
loadout-group-patron = Спонсор
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 d143f71019f..60a52e24032 100644
--- a/Resources/Prototypes/_Arcane/Entities/Mobs/Customization/Markings/humanoid_xeno.yml
+++ b/Resources/Prototypes/_Arcane/Entities/Mobs/Customization/Markings/humanoid_xeno.yml
@@ -263,6 +263,20 @@
- sprite: _Arcane/Mobs/Customization/HumanoidXeno/tail.rsi
state: warrior_tail_thin_grad
+- type: marking
+ id: HumanoidXenoTailRen
+ bodyPart: Tail
+ markingCategory: Tail
+ speciesRestriction: [HumanoidXeno]
+ effects:
+ - !type:SponsorRequirementMarkingEffect
+ roles: [ArtLead]
+ sprites:
+ - sprite: _Arcane/Mobs/Customization/HumanoidXeno/tail.rsi
+ state: ren_tail
+ - sprite: _Arcane/Mobs/Customization/HumanoidXeno/tail.rsi
+ state: ren_tail_grad
+
# Head
@@ -566,6 +580,18 @@
- sprite: _Arcane/Mobs/Customization/HumanoidXeno/head.rsi
state: warrior_head_shine
+- type: marking
+ id: HumanoidXenoHeadRen
+ bodyPart: Head
+ markingCategory: Head
+ speciesRestriction: [HumanoidXeno]
+ effects:
+ - !type:SponsorRequirementMarkingEffect
+ roles: [ArtLead]
+ sprites:
+ - sprite: _Arcane/Mobs/Customization/HumanoidXeno/head.rsi
+ state: ren_head
+
# Chest
- type: marking
@@ -743,6 +769,18 @@
- sprite: _Arcane/Mobs/Customization/HumanoidXeno/tracheas.rsi
state: warrior_tubes
+- type: marking
+ id: HumanoidXenoTracheasRen
+ bodyPart: Chest
+ markingCategory: Tracheas
+ speciesRestriction: [HumanoidXeno]
+ effects:
+ - !type:SponsorRequirementMarkingEffect
+ roles: [ArtLead]
+ sprites:
+ - sprite: _Arcane/Mobs/Customization/HumanoidXeno/tracheas.rsi
+ state: ren_tubes
+
# 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 6662091b1f5..3122047c50e 100644
--- a/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi/meta.json
+++ b/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi/meta.json
@@ -286,6 +286,10 @@
{
"name": "warrior_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 310ef8936f5..fea88158a15 100644
--- a/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi/meta.json
+++ b/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi/meta.json
@@ -98,6 +98,14 @@
{
"name": "warrior_tail_thin",
"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 96be503100e..72642618c6f 100644
--- a/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tracheas.rsi/meta.json
+++ b/Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tracheas.rsi/meta.json
@@ -58,6 +58,10 @@
{
"name": "warrior_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