Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion Content.Client/Humanoid/MarkingPicker.xaml.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
}

// 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
}
21 changes: 19 additions & 2 deletions Content.Client/Humanoid/SingleMarkingPicker.xaml.cs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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;

Expand Down Expand Up @@ -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)
Expand All @@ -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;
Expand Down Expand Up @@ -302,4 +319,4 @@ private string GetMarkingName(MarkingPrototype marking)
{
return Loc.GetString($"marking-{marking.ID}");
}
}
}
1 change: 1 addition & 0 deletions Content.Server/_Arcane/DiscordRoles/DiscordRoleIds.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public static class DiscordRoleIds
[DiscordRole.SponsorTier1] = 1510991486399942707,
[DiscordRole.SponsorTier2] = 1510991694785675397,
[DiscordRole.AdminBenefit] = 1545943229143195658,
[DiscordRole.ArtLead] = 1509175991241670696,
[DiscordRole.UnlockRoles] = 1533054913318223872,
};
}
6 changes: 5 additions & 1 deletion Content.Shared/Humanoid/HumanoidCharacterAppearance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
24 changes: 24 additions & 0 deletions Content.Shared/Humanoid/Markings/Effects/MarkingEffect.cs
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// Base class for effects that gate whether a marking may be used by a given session.
/// </summary>
[ImplicitDataDefinitionForInheritors]
public abstract partial class MarkingEffect
{
/// <summary>
/// Tries to validate whether the marking is available to the session.
/// </summary>
public abstract bool Validate(
MarkingPrototype marking,
ICommonSession? session,
ISharedDiscordRoleManager? discordRoles,
[NotNullWhen(false)] out FormattedMessage? reason);
}
2 changes: 1 addition & 1 deletion Content.Shared/Humanoid/Markings/MarkingManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public FrozenDictionary<string, MarkingPrototype> MarkingsByCategory(MarkingCate
}

/// <summary>
/// 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.
/// </summary>
/// <param name="category"></param>
/// <param name="species"></param>
Expand Down
30 changes: 30 additions & 0 deletions Content.Shared/Humanoid/Markings/MarkingPrototype.cs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -44,6 +47,33 @@ public sealed partial class MarkingPrototype : IPrototype
[DataField("sprites", required: true)]
public List<SpriteSpecifier> Sprites { get; private set; } = default!;

// Arcane-Start
/// <summary>
/// Effects that gate whether this marking may be used by a given session. Empty means no restriction.
/// </summary>
[DataField("effects")]
public List<MarkingEffect> 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;
Expand Down
38 changes: 38 additions & 0 deletions Content.Shared/Humanoid/Markings/MarkingsSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -234,6 +236,42 @@ public void EnsureSexes(Sex sex, MarkingManager? markingManager = null)
}
}

// Arcane-Start
/// <summary>
/// Removes markings whose effects reject the session.
/// </summary>
/// <param name="discordRoles">Discord role manager, used by sponsor effects.</param>
/// <param name="session">The session to check, or null to skip filtering.</param>
/// <param name="markingManager">Marking manager.</param>
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);
}
}

/// <summary>
/// Ensures that all markings in this set are valid.
/// </summary>
Expand Down
4 changes: 3 additions & 1 deletion Content.Shared/Preferences/HumanoidCharacterProfile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<ISharedDiscordRoleManager>(); // Arcane
var appearance = HumanoidCharacterAppearance.EnsureValid(Appearance, Species, Sex, discordRoles, session); // Arcane-Edit

var prefsUnavailableMode = PreferenceUnavailable switch
{
Expand Down
1 change: 1 addition & 0 deletions Content.Shared/_Arcane/DiscordRoles/DiscordRole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public enum DiscordRole : byte
SponsorTier1,
SponsorTier2,
AdminBenefit,
ArtLead,
UnlockRoles,
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// Verifies possession of a specific Discord role that unlocks the sponsor marking
/// </summary>
public sealed partial class SponsorRequirementMarkingEffect : MarkingEffect
{
[DataField(required: true)]
public HashSet<DiscordRole> 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));
}
}
2 changes: 2 additions & 0 deletions Content.Shared/_Arcane/Sponsor/SponsorRoleBenefits.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions Resources/Locale/ru-RU/_Arcane/markings/humanoid_xeno.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ marking-HumanoidXenoTailOpress = Хвост угнетателя
marking-HumanoidXenoTailValkyr = Хвост валькирии
marking-HumanoidXenoTailDefender = Хвост защитника
marking-HumanoidXenoTailWarrior = Хвост воина
marking-HumanoidXenoTailRen = Хвост Рэн
Comment thread
ReWAFFlution marked this conversation as resolved.
marking-HumanoidXenoHeadDrone = Голова дрона
marking-HumanoidXenoHeadSpitter = Голова плевателя
marking-HumanoidXenoHeadPretor = Голова претора
Expand All @@ -44,6 +45,7 @@ marking-HumanoidXenoHeadBurrower = Голова бурильщика
marking-HumanoidXenoHeadDefender = Голова защитника
marking-HumanoidXenoHeadValkyr = Голова валькирии
marking-HumanoidXenoHeadWarrior = Голова воина
marking-HumanoidXenoHeadRen = Голова Рэн
marking-HumanoidXenoChestPredalien = Грудь предалиена
marking-HumanoidXenoChestSpitter = Грудь плевателя
marking-HumanoidXenoChestMuscles = "Мышцы"
Expand All @@ -63,6 +65,7 @@ marking-HumanoidXenoTracheasCougar = Трахеи пумы
marking-HumanoidXenoTracheasCrocodile = Трахеи крокодила
marking-HumanoidXenoTracheasBers = Трахеи берсерка
marking-HumanoidXenoTracheasWarrior = Трахеи воина
marking-HumanoidXenoTracheasRen = Трахеи Рэн
marking-HumanoidXenoLegsPredalien = Ноги предалиена
marking-HumanoidXenoLegsMuscles = "Мышцы"
marking-HumanoidXenoLegsCougar = Ноги пумы
Expand Down
Loading
Loading