diff --git a/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs b/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs index 7bf1610de43..d17cc3952ea 100644 --- a/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs +++ b/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs @@ -782,6 +782,20 @@ public void RefreshTraits() tooltipParts.Add($"You must not be: {string.Join(", ", names)}"); } + // HardLight: Required traits + if (trait.RequiredTraits.Count > 0) + { + var names = new List(); + foreach (var reqId in trait.RequiredTraits) + { + if (_prototypeManager.TryIndex(reqId, out var reqProto)) + names.Add($"[color=#FFD700]{Loc.GetString(reqProto.Name)}[/color]"); + } + if (names.Count > 0) + tooltipParts.Add($"Requires: {string.Join(", ", names)}"); + } + // HardLight end + if (tooltipParts.Count > 0) selector.SetTooltip(string.Join("\n", tooltipParts)); } @@ -828,6 +842,30 @@ public void RefreshTraits() else { Profile = Profile?.WithoutTraitPreference(trait.ID, _prototypeManager); + + // HardLight - Cascade deselect: remove any traits that required this one + if (Profile != null) + { + var toRemove = new List>(); + foreach (var selectedTraitId in Profile.TraitPreferences) + { + if (!_prototypeManager.TryIndex(selectedTraitId, out var selectedProto)) + continue; + + if (selectedProto.RequiredTraits.Contains(trait.ID)) + toRemove.Add(selectedTraitId); + } + + foreach (var removeId in toRemove) + { + Profile = Profile.WithoutTraitPreference(removeId, _prototypeManager); + + // Also uncheck the UI selector + if (allSelectors.TryGetValue(removeId, out var depSelector)) + depSelector.Preference = false; + } + } + // HardLight end } SetDirty(); @@ -1024,6 +1062,20 @@ private void UpdateTraitIncompatibilityVisibility(Dictionary 0) + { + foreach (var requiredId in thisProto.RequiredTraits) + { + if (!selected.Contains(requiredId)) + { + hide = true; + break; + } + } + } + // HardLight end + if (!hide) { foreach (var sel in selected) @@ -1727,6 +1779,36 @@ private void EnforceSpeciesTraitRestrictions() toRemove.Add(traitId); } + // HardLight - Also remove traits whose required traits are not selected + // Iterate until stable since removing one trait may cascade + bool changed; + do + { + changed = false; + foreach (var traitId in Profile.TraitPreferences) + { + if (toRemove.Contains(traitId)) + continue; + + if (!_prototypeManager.TryIndex(traitId, out TraitPrototype? trait)) + continue; + + if (trait.RequiredTraits.Count == 0) + continue; + + foreach (var reqId in trait.RequiredTraits) + { + if (!Profile.TraitPreferences.Contains(reqId) || toRemove.Contains(reqId)) + { + toRemove.Add(traitId); + changed = true; + break; + } + } + } + } while (changed); + // HardLight end + foreach (var traitId in toRemove) { Profile = Profile.WithoutTraitPreference(traitId, _prototypeManager); @@ -2300,4 +2382,4 @@ private void UpdateCompanyControls() } } } -} +} \ No newline at end of file diff --git a/Content.Shared/Traits/TraitPrototype.cs b/Content.Shared/Traits/TraitPrototype.cs index 8221e5213bd..aa369a72d6a 100644 --- a/Content.Shared/Traits/TraitPrototype.cs +++ b/Content.Shared/Traits/TraitPrototype.cs @@ -64,11 +64,17 @@ public sealed partial class TraitPrototype : IPrototype, IComparable? Category; /// - /// List of traits that ca't be taken together with this one. + /// List of traits that can't be taken together with this one. /// [DataField] public HashSet> MutuallyExclusiveTraits { get; private set; } = new(); + /// + /// List of traits that must be selected before this trait becomes available, w/ deselect if its removed + /// + [DataField] + public HashSet> RequiredTraits { get; private set; } = new(); + /// /// List of species that can't have this trait. /// @@ -121,4 +127,4 @@ public int CompareTo(TraitPrototype? other) if (other == null) return 1; return Cost.CompareTo(other.Cost); } -} +} \ No newline at end of file diff --git a/Resources/Locale/en-US/_HL/traits/traits.ftl b/Resources/Locale/en-US/_HL/traits/traits.ftl index 09a1d4eb514..b20f1738012 100644 --- a/Resources/Locale/en-US/_HL/traits/traits.ftl +++ b/Resources/Locale/en-US/_HL/traits/traits.ftl @@ -37,3 +37,56 @@ hl-trait-egglayer-infertile-desc = You produce eggs very slowly and seldomly (50 pooltoy-name = Pool Toy! pooltoy-text = You're a living inflatable, whether by some weird mutation or by being a synthetic being. You are quite resillient to blunt and naturally insulated, but are extra susceptible to pierce and slash, and you are easily knocked about by sudden forces! + +hl-trait-category-supernatural = Supernatural + +hl-trait-vampire-name = Vampire +hl-trait-vampire-desc = You are an undead vampire who can only feed their hunger with blood. You are immune to airloss damage, but are weak to silver. + +hl-trait-werewolf-name = Werewolf +hl-trait-werewolf-desc = Exposure to the sun or UV light can transform you into a powerful but mindless creature that attacks everyone in sight. You are also weak to silver. + +hl-trait-changeling-name = Changeling +hl-trait-changeling-desc = You are a shapeless creature who can only feed their hunger by absorbing DNA from others. You are weak to silver, but can transform into your victims. + +hl-trait-vampire-bat-transformation-name = Bat Transformation +hl-trait-vampire-bat-transformation-desc = You can transform into a bat at the cost of hunger. + +hl-trait-vampire-uv-weakness-name = UV Weakness +hl-trait-vampire-uv-weakness-desc = Exposure to the sun or UV lights will burn you. + +hl-trait-vampire-light-weakness-name = Light Weakness +hl-trait-vampire-light-weakness-desc = Bright lights will weaken you. + +hl-trait-werewolf-transform-name = Transform at Will +hl-trait-werewolf-transform-desc = You can transform yourself at will if you are fully fed. + +hl-trait-changeling-armblade-name = Armblade +hl-trait-changeling-armblade-desc = Your arms can turn into blades to slice at others + +hl-trait-changeling-armclaw-name = Armclaw +hl-trait-changeling-armclaw-desc = Your arms can turn into claws to stab at others + +hl-trait-changeling-armhammer-name = Armhammer +hl-trait-changeling-armhammer-desc = Your arms can turn into a hammer to bludgeon others + +hl-trait-changeling-playdead-name = Playdead +hl-trait-changeling-playdead-desc = You can reduce your functions to appear dead, and later revive at will. + +hl-trait-changeling-screech-name = EMP Screech +hl-trait-changeling-screech-desc = You can screech out a shockwave that knocks others back and disables nearby electronics + +hl-trait-changeling-thermaleyes-name = Thermal Eyes +hl-trait-changeling-thermaleyes-desc = You can see in the dark with toggable thermal vision + +hl-trait-changeling-healing-name = Healing Factor +hl-trait-changeling-healing-desc = At the cost of hunger, you can increase your healing factor for brute and toxin damage + +hl-trait-changeling-chitin-name = Chitin Armor +hl-trait-changeling-chitin-desc = Your skin is tougher than normal, allowing you to resist brute damage but it takes longer to inject chems in you + +hl-trait-changeling-firevurn-name = Fire Vurnability +hl-trait-changeling-firevurn-desc = You take 50% more damage from heat sources + +hl-trait-changeling-acidvurn-name = Acid Vurnability +hl-trait-changeling-acidvurn-desc = You take 50% more damage from caustic sources diff --git a/Resources/Prototypes/Traits/categories.yml b/Resources/Prototypes/Traits/categories.yml index 15912495075..19c793f0bf9 100644 --- a/Resources/Prototypes/Traits/categories.yml +++ b/Resources/Prototypes/Traits/categories.yml @@ -18,3 +18,9 @@ id: Physical name: trait-category-physical maxTraitPoints: 10 + +# Hardlight +- type: traitCategory + id: Supernatural + name: hl-trait-category-supernatural + maxTraitPoints: 1 \ No newline at end of file diff --git a/Resources/Prototypes/_HL/Traits/supernatural.yml b/Resources/Prototypes/_HL/Traits/supernatural.yml new file mode 100644 index 00000000000..656a134be30 --- /dev/null +++ b/Resources/Prototypes/_HL/Traits/supernatural.yml @@ -0,0 +1,161 @@ +- type: trait + id: Vampire + name: hl-trait-vampire-name + description: hl-trait-vampire-desc + category: Supernatural + cost: 1 + mutuallyExclusiveTraits: + - Changeling + - Werewolf + +- type: trait + id: Changeling + name: hl-trait-changeling-name + description: hl-trait-changeling-desc + category: Supernatural + cost: 1 + mutuallyExclusiveTraits: + - Vampire + - Werewolf + +- type: trait + id: Werewolf + name: hl-trait-werewolf-name + description: hl-trait-werewolf-desc + category: Supernatural + cost: 1 + mutuallyExclusiveTraits: + - Vampire + - Changeling + +# Vampire Sub-Traits + +- type: trait + id: BatTransformation + name: hl-trait-vampire-bat-transformation-name + description: hl-vampire-trait-bat-transformation-desc + category: Supernatural + cost: 5 + requiredTraits: + - Vampire + +- type: trait + id: UVWeakness + name: hl-trait-vampire-uv-weakness-name + description: hl-trait-vampire-uv-weakness-desc + category: Supernatural + cost: -5 + requiredTraits: + - Vampire + +- type: trait + id: LightWeakness + name: hl-trait-vampire-light-weakness-name + description: hl-trait-vampire-light-weakness-desc + category: Supernatural + cost: -5 + requiredTraits: + - Vampire + +# Werewolf Sub-Traits + +- type: trait + id: WerewolfTransformAtWill + name: hl-trait-werewolf-transform-name + description: hl-trait-werewolf-transform-desc + category: Supernatural + cost: 5 + requiredTraits: + - Werewolf + +# Changeling Sub-Traits + +- type: trait + id: CLArmblade + name: hl-trait-changeling-armblade-name + description: hl-trait-changeling-armblade-desc + category: Supernatural + cost: 5 + requiredTraits: + - Changeling + +- type: trait + id: CLArmclaw + name: hl-trait-changeling-armclaw-name + description: hl-trait-changeling-armclaw-desc + category: Supernatural + cost: 5 + requiredTraits: + - Changeling + +- type: trait + id: CLArmhammer + name: hl-trait-changeling-armhammer-name + description: hl-trait-changeling-armhammer-desc + category: Supernatural + cost: 5 + requiredTraits: + - Changeling + +- type: trait + id: CLPlaydead + name: hl-trait-changeling-playdead-name + description: hl-trait-changeling-playdead-desc + category: Supernatural + cost: 5 + requiredTraits: + - Changeling + +- type: trait + id: CLScreech + name: hl-trait-changeling-screech-name + description: hl-trait-changeling-screech-desc + category: Supernatural + cost: 10 + requiredTraits: + - Changeling + +- type: trait + id: CLThermalEyes + name: hl-trait-changeling-thermaleyes-name + description: hl-trait-changeling-thermaleyes-desc + category: Supernatural + cost: 2 + requiredTraits: + - Changeling + +- type: trait + id: CLHealingFactor + name: hl-trait-changeling-healing-name + description: hl-trait-changeling-healing-desc + category: Supernatural + cost: 5 + requiredTraits: + - Changeling + +- type: trait + id: CLChitinArmor + name: hl-trait-changeling-chitin-name + description: hl-trait-changeling-chitin-desc + category: Supernatural + cost: -5 + requiredTraits: + - Changeling + +- type: trait + id: CLFireVurn + name: hl-trait-changeling-firevurn-name + description: hl-trait-changeling-firevurn-desc + category: Supernatural + cost: -5 + requiredTraits: + - Changeling + +- type: trait + id: CLAcidVurn + name: hl-trait-changeling-acidvurn-name + description: hl-trait-changeling-acidvurn-desc + category: Supernatural + cost: -5 + requiredTraits: + - Changeling