From e9c72005739e9079d23efa06e3da1c2ff7abc681 Mon Sep 17 00:00:00 2001 From: Rouden <149893554+Roudenn@users.noreply.github.com> Date: Mon, 9 Dec 2024 01:01:15 +0300 Subject: [PATCH] [Fix] Mood cool fixes (#916) * Fix Overlays (#756) Overlays have a funny bug where the calls to update them are global. Meaning if any single person gets a bad enough mood to greyscale themselves, everyone globally gets greyscaled. This bug was also present on Dogvision and Ultravision, and had the same cause. Frontier luckily had a fix for those two, and the fix works here as well for the Mood Overlay. :cl: - fix: Fixed an issue where Overlays(Dogvision, Ultravision, Mood) would apply globally to all entities when updating. * MoodSystem Crit Threshold CVar (#1010) This PR adds a CVar that allows server hosts (such as N14 who need it) to optionally disable the Crit Threshold modification part of the MoodSystem. This is useful if a server has some other system that frequently messes with Thresholds, and that a server host wishes their system to not have to fight with Mood for it. No changelog because this isn't playerfacing. * Update SaturationScaleOverlay.cs --------- Co-authored-by: VMSolidus --- Content.Server/Backmen/Mood/MoodComponent.cs | 105 +------------- Content.Server/Backmen/Mood/MoodSystem.cs | 46 +++--- .../Assorted/ModifyMoodTraitComponent.cs | 8 +- .../Backmen/Mood/SharedMoodComponent.cs | 135 +++++++++++++++++- .../Systems/MovementSpeedModifierSystem.cs | 36 ++++- Resources/Locale/ru-RU/backmen/mood/mood.ftl | 2 + Resources/Locale/ru-RU/backmen/trait/Mood.ftl | 10 ++ .../_Backmen/Mood/genericNegativeEffects.yml | 8 +- .../Prototypes/_Backmen/Traits/categories.yml | 4 + .../Prototypes/_Backmen/Traits/neutral.yml | 33 +++++ 10 files changed, 250 insertions(+), 137 deletions(-) create mode 100644 Resources/Locale/ru-RU/backmen/trait/Mood.ftl create mode 100644 Resources/Prototypes/_Backmen/Traits/categories.yml create mode 100644 Resources/Prototypes/_Backmen/Traits/neutral.yml diff --git a/Content.Server/Backmen/Mood/MoodComponent.cs b/Content.Server/Backmen/Mood/MoodComponent.cs index a06c1f978e7..c35ffad1206 100644 --- a/Content.Server/Backmen/Mood/MoodComponent.cs +++ b/Content.Server/Backmen/Mood/MoodComponent.cs @@ -3,110 +3,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Generic; -namespace Content.Server._CorvaxNext.Mood; - -[RegisterComponent] -public sealed partial class MoodComponent : Component +namespace Content.Server._CorvaxNext.Mood { - [DataField] - public float CurrentMoodLevel; - - [DataField] - public MoodThreshold CurrentMoodThreshold; - - [DataField] - public MoodThreshold LastThreshold; - - [ViewVariables(VVAccess.ReadOnly)] - public readonly Dictionary CategorisedEffects = new(); - - [ViewVariables(VVAccess.ReadOnly)] - public readonly Dictionary UncategorisedEffects = new(); - - /// - /// The formula for the movement speed modifier is SpeedBonusGrowth ^ (MoodLevel - MoodThreshold.Neutral). - /// Change this ONLY BY 0.001 AT A TIME. - /// - [DataField] - public float SpeedBonusGrowth = 1.003f; - - /// - /// The lowest point that low morale can multiply our movement speed by. Lowering speed follows a linear curve, rather than geometric. - /// - [DataField] - public float MinimumSpeedModifier = 0.75f; - - /// - /// The maximum amount that high morale can multiply our movement speed by. This follows a significantly slower geometric sequence. - /// - [DataField] - public float MaximumSpeedModifier = 1.15f; - [DataField] - public float IncreaseCritThreshold = 1.2f; - - [DataField] - public float DecreaseCritThreshold = 0.9f; - - [ViewVariables(VVAccess.ReadOnly)] - public FixedPoint2 CritThresholdBeforeModify; - - [DataField(customTypeSerializer: typeof(DictionarySerializer))] - public Dictionary MoodThresholds = new() - { - { MoodThreshold.Perfect, 100f }, - { MoodThreshold.Exceptional, 80f }, - { MoodThreshold.Great, 70f }, - { MoodThreshold.Good, 60f }, - { MoodThreshold.Neutral, 50f }, - { MoodThreshold.Meh, 40f }, - { MoodThreshold.Bad, 30f }, - { MoodThreshold.Terrible, 20f }, - { MoodThreshold.Horrible, 10f }, - { MoodThreshold.Dead, 0f } - }; - - [DataField(customTypeSerializer: typeof(DictionarySerializer>))] - public Dictionary> MoodThresholdsAlerts = new() - { - { MoodThreshold.Dead, "MoodDead" }, - { MoodThreshold.Horrible, "MoodHorrible" }, - { MoodThreshold.Terrible, "MoodTerrible" }, - { MoodThreshold.Bad, "MoodBad" }, - { MoodThreshold.Meh, "MoodMeh" }, - { MoodThreshold.Neutral, "MoodNeutral" }, - { MoodThreshold.Good, "MoodGood" }, - { MoodThreshold.Great, "MoodGreat" }, - { MoodThreshold.Exceptional, "MoodExceptional" }, - { MoodThreshold.Perfect, "MoodPerfect" }, - { MoodThreshold.Insane, "MoodInsane" } - }; - - /// - /// These thresholds represent a percentage of Crit-Threshold, 0.8 corresponding with 80%. - /// - [DataField(customTypeSerializer: typeof(DictionarySerializer))] - public Dictionary HealthMoodEffectsThresholds = new() - { - { "HealthHeavyDamage", 0.8f }, - { "HealthSevereDamage", 0.5f }, - { "HealthLightDamage", 0.1f }, - { "HealthNoDamage", 0.05f } - }; -} - -[Serializable] -public enum MoodThreshold : ushort -{ - Insane = 1, - Horrible = 2, - Terrible = 3, - Bad = 4, - Meh = 5, - Neutral = 6, - Good = 7, - Great = 8, - Exceptional = 9, - Perfect = 10, - Dead = 0 } diff --git a/Content.Server/Backmen/Mood/MoodSystem.cs b/Content.Server/Backmen/Mood/MoodSystem.cs index 8233c5d6564..41a9d60996f 100644 --- a/Content.Server/Backmen/Mood/MoodSystem.cs +++ b/Content.Server/Backmen/Mood/MoodSystem.cs @@ -155,8 +155,12 @@ private void OnRefreshMoveSpeed(EntityUid uid, MoodComponent component, RefreshM private void OnTraitStartup(EntityUid uid, MoodModifyTraitComponent component, ComponentStartup args) { - if (component.MoodId != null) - RaiseLocalEvent(uid, new MoodEffectEvent($"{component.MoodId}")); + if (!TryComp(uid, out var mood)) + return; + + mood.GoodMoodMultiplier = component.GoodMoodMultiplier; + mood.BadMoodMultiplier = component.BadMoodMultiplier; + RaiseLocalEvent(uid, new MoodEffectEvent($"{component.MoodId}")); } private void OnMoodEffect(EntityUid uid, MoodComponent component, MoodEffectEvent args) @@ -289,12 +293,18 @@ private void RefreshMood(EntityUid uid, MoodComponent component) if (!_prototypeManager.TryIndex(protoId, out var prototype)) continue; - amount += prototype.MoodChange; + if (prototype.MoodChange > 0) + amount += prototype.MoodChange * component.GoodMoodMultiplier; + else + amount += prototype.MoodChange * component.BadMoodMultiplier; } foreach (var (_, value) in component.UncategorisedEffects) { - amount += value; + if (value > 0) + amount += value * component.GoodMoodMultiplier; + else + amount += value * component.BadMoodMultiplier; } SetMood(uid, amount, component, refresh: true); @@ -307,7 +317,6 @@ private void OnInit(EntityUid uid, MoodComponent component, ComponentStartup arg && _mobThreshold.TryGetThresholdForState(uid, MobState.Critical, out var critThreshold, mobThresholdsComponent)) component.CritThresholdBeforeModify = critThreshold.Value; - EnsureComp(uid); RefreshMood(uid, component); } @@ -340,12 +349,8 @@ private void SetMood(EntityUid uid, float amount, MoodComponent? component = nul component.CurrentMoodLevel = newMoodLevel; - if (TryComp(uid, out var mood)) - { - mood.CurrentMoodLevel = component.CurrentMoodLevel; - mood.NeutralMoodThreshold = component.MoodThresholds.GetValueOrDefault(MoodThreshold.Neutral); - } - + component.NeutralMoodThreshold = component.MoodThresholds.GetValueOrDefault(MoodThreshold.Neutral); + Dirty(uid, component); UpdateCurrentThreshold(uid, component); } @@ -369,10 +374,10 @@ private void DoMoodThresholdsEffects(EntityUid uid, MoodComponent? component = n || component.CurrentMoodThreshold == component.LastThreshold && !force) return; - var modifier = GetMovementThreshold(component.CurrentMoodThreshold); + var modifier = GetMovementThreshold(component.CurrentMoodThreshold, component); // Modify mob stats - if (modifier != GetMovementThreshold(component.LastThreshold)) + if (modifier != GetMovementThreshold(component.LastThreshold, component)) { _movementSpeedModifier.RefreshMovementSpeedModifiers(uid); SetCritThreshold(uid, component, modifier); @@ -432,14 +437,15 @@ private MoodThreshold GetMoodThreshold(MoodComponent component, float? moodLevel return result; } - private int GetMovementThreshold(MoodThreshold threshold) + private int GetMovementThreshold(MoodThreshold threshold, MoodComponent component) { - return threshold switch - { - >= MoodThreshold.Good => 1, - <= MoodThreshold.Meh => -1, - _ => 0 - }; + if (threshold >= component.BuffsMoodThreshold) + return 1; + + if (threshold <= component.ConsMoodThreshold) + return -1; + + return 0; } private string GetMoodName(MoodThreshold threshold) diff --git a/Content.Server/Backmen/Traits/Assorted/ModifyMoodTraitComponent.cs b/Content.Server/Backmen/Traits/Assorted/ModifyMoodTraitComponent.cs index eccf2c35588..14b3f4a45ab 100644 --- a/Content.Server/Backmen/Traits/Assorted/ModifyMoodTraitComponent.cs +++ b/Content.Server/Backmen/Traits/Assorted/ModifyMoodTraitComponent.cs @@ -7,5 +7,11 @@ namespace Content.Server._CorvaxNext.Traits.Assorted; public sealed partial class MoodModifyTraitComponent : Component { [DataField] - public string? MoodId = null; + public string? MoodId; + + [DataField] + public float GoodMoodMultiplier = 1.0f; + + [DataField] + public float BadMoodMultiplier = 1.0f; } diff --git a/Content.Shared/Backmen/Mood/SharedMoodComponent.cs b/Content.Shared/Backmen/Mood/SharedMoodComponent.cs index 65bab6011bf..68ef0d4ee60 100644 --- a/Content.Shared/Backmen/Mood/SharedMoodComponent.cs +++ b/Content.Shared/Backmen/Mood/SharedMoodComponent.cs @@ -1,15 +1,138 @@ + +using Content.Shared.Alert; +using Content.Shared.FixedPoint; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Generic; + namespace Content.Shared._CorvaxNext.Mood; -/// -/// This component exists solely to network CurrentMoodLevel, so that clients can make use of its value for math Prediction. -/// All mood logic is otherwise handled by the Server, and the client is not allowed to know the identity of its mood events. -/// -[RegisterComponent, AutoGenerateComponentState] -public sealed partial class NetMoodComponent : Component +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class MoodComponent : Component { + public override bool SendOnlyToOwner => true; + [DataField, AutoNetworkedField] public float CurrentMoodLevel; [DataField, AutoNetworkedField] public float NeutralMoodThreshold; + + [DataField] + public MoodThreshold CurrentMoodThreshold; + + [DataField] + public MoodThreshold LastThreshold; + + [ViewVariables(VVAccess.ReadOnly)] + public readonly Dictionary CategorisedEffects = new(); + + [ViewVariables(VVAccess.ReadOnly)] + public readonly Dictionary UncategorisedEffects = new(); + + /// + /// The formula for the movement speed modifier is SpeedBonusGrowth ^ (MoodLevel - MoodThreshold.Neutral). + /// Change this ONLY BY 0.001 AT A TIME. + /// + [DataField] + public float SpeedBonusGrowth = 1.003f; + + /// + /// The lowest point that low morale can multiply our movement speed by. Lowering speed follows a linear curve, rather than geometric. + /// + [DataField] + public float MinimumSpeedModifier = 0.90f; + + /// + /// The maximum amount that high morale can multiply our movement speed by. This follows a significantly slower geometric sequence. + /// + [DataField] + public float MaximumSpeedModifier = 1.15f; + + [DataField] + public float IncreaseCritThreshold = 1.2f; + + [DataField] + public float DecreaseCritThreshold = 0.9f; + + /// + /// Multiplier for positive mood effects. + /// + [DataField] + public float GoodMoodMultiplier = 1.0f; + + /// + /// Multiplier for negative mood effects. + /// + [DataField] + public float BadMoodMultiplier = 1.0f; + + [DataField] + public MoodThreshold BuffsMoodThreshold = MoodThreshold.Good; + + [DataField] + public MoodThreshold ConsMoodThreshold = MoodThreshold.Bad; + + [ViewVariables(VVAccess.ReadOnly)] + public FixedPoint2 CritThresholdBeforeModify; + + [DataField(customTypeSerializer: typeof(DictionarySerializer))] + public Dictionary MoodThresholds = new() + { + { MoodThreshold.Perfect, 100f }, + { MoodThreshold.Exceptional, 80f }, + { MoodThreshold.Great, 70f }, + { MoodThreshold.Good, 60f }, + { MoodThreshold.Neutral, 50f }, + { MoodThreshold.Meh, 40f }, + { MoodThreshold.Bad, 30f }, + { MoodThreshold.Terrible, 20f }, + { MoodThreshold.Horrible, 10f }, + { MoodThreshold.Dead, 0f } + }; + + [DataField(customTypeSerializer: typeof(DictionarySerializer>))] + public Dictionary> MoodThresholdsAlerts = new() + { + { MoodThreshold.Dead, "MoodDead" }, + { MoodThreshold.Horrible, "MoodHorrible" }, + { MoodThreshold.Terrible, "MoodTerrible" }, + { MoodThreshold.Bad, "MoodBad" }, + { MoodThreshold.Meh, "MoodMeh" }, + { MoodThreshold.Neutral, "MoodNeutral" }, + { MoodThreshold.Good, "MoodGood" }, + { MoodThreshold.Great, "MoodGreat" }, + { MoodThreshold.Exceptional, "MoodExceptional" }, + { MoodThreshold.Perfect, "MoodPerfect" }, + { MoodThreshold.Insane, "MoodInsane" } + }; + + /// + /// These thresholds represent a percentage of Crit-Threshold, 0.8 corresponding with 80%. + /// + [DataField(customTypeSerializer: typeof(DictionarySerializer))] + public Dictionary HealthMoodEffectsThresholds = new() + { + { "HealthHeavyDamage", 0.8f }, + { "HealthSevereDamage", 0.5f }, + { "HealthOkayDamage", 0.35f }, + { "HealthLightDamage", 0.1f }, + { "HealthNoDamage", 0.05f } + }; +} + +[Serializable] +public enum MoodThreshold : ushort +{ + Insane = 1, + Horrible = 2, + Terrible = 3, + Bad = 4, + Meh = 5, + Neutral = 6, + Good = 7, + Great = 8, + Exceptional = 9, + Perfect = 10, + Dead = 0 } diff --git a/Content.Shared/Movement/Systems/MovementSpeedModifierSystem.cs b/Content.Shared/Movement/Systems/MovementSpeedModifierSystem.cs index 8e89e4b62b3..c668a6bf7a1 100644 --- a/Content.Shared/Movement/Systems/MovementSpeedModifierSystem.cs +++ b/Content.Shared/Movement/Systems/MovementSpeedModifierSystem.cs @@ -1,5 +1,7 @@ +using Content.Shared.Backmen.Standing; using Content.Shared.Inventory; using Content.Shared.Movement.Components; +using Content.Shared.Standing; using Robust.Shared.Timing; namespace Content.Shared.Movement.Systems @@ -8,6 +10,19 @@ public sealed class MovementSpeedModifierSystem : EntitySystem { [Dependency] private readonly IGameTiming _timing = default!; + // start-backmen: layingdown + private EntityQuery _layerQuery; + private EntityQuery _standingStateQuery; + + public override void Initialize() + { + base.Initialize(); + + _layerQuery = GetEntityQuery(); + _standingStateQuery = GetEntityQuery(); + } + // end-backmen: layingdows + public void RefreshMovementSpeedModifiers(EntityUid uid, MovementSpeedModifierComponent? move = null) { if (!Resolve(uid, ref move, false)) @@ -19,12 +34,25 @@ public void RefreshMovementSpeedModifiers(EntityUid uid, MovementSpeedModifierCo var ev = new RefreshMovementSpeedModifiersEvent(); RaiseLocalEvent(uid, ev); - if (MathHelper.CloseTo(ev.WalkSpeedModifier, move.WalkSpeedModifier) && - MathHelper.CloseTo(ev.SprintSpeedModifier, move.SprintSpeedModifier)) + // start-backmen: layingdown + var walkSpeedModifier = ev.WalkSpeedModifier; + var sprintSpeedModifier = ev.SprintSpeedModifier; + // cap moving speed while laying + if (_standingStateQuery.TryComp(uid, out var standing) && + !standing.Standing && + _layerQuery.TryComp(uid, out var layingDown)) + { + walkSpeedModifier = Math.Min(walkSpeedModifier, layingDown.SpeedModify); + sprintSpeedModifier = Math.Min(sprintSpeedModifier, layingDown.SpeedModify); + } + // end-backmen: layingdows + + if (MathHelper.CloseTo(walkSpeedModifier, move.WalkSpeedModifier) && + MathHelper.CloseTo(sprintSpeedModifier, move.SprintSpeedModifier)) return; - move.WalkSpeedModifier = ev.WalkSpeedModifier; - move.SprintSpeedModifier = ev.SprintSpeedModifier; + move.WalkSpeedModifier = walkSpeedModifier; + move.SprintSpeedModifier = sprintSpeedModifier; Dirty(uid, move); } diff --git a/Resources/Locale/ru-RU/backmen/mood/mood.ftl b/Resources/Locale/ru-RU/backmen/mood/mood.ftl index 5bca034dab9..f1bef5700c8 100644 --- a/Resources/Locale/ru-RU/backmen/mood/mood.ftl +++ b/Resources/Locale/ru-RU/backmen/mood/mood.ftl @@ -33,6 +33,8 @@ mood-effect-MobHighPressure = Я чувствую будто воздух сжи mood-effect-TraitSaturnine = Тут всё очень скучное. Ненавижу эту работу. +mood-effect-TraitFortitude = Мне уже на всё плевать. + mood-effect-Dead = Вы мертвы. mood-effect-BeingHugged = Люблю когда меня обнимают. diff --git a/Resources/Locale/ru-RU/backmen/trait/Mood.ftl b/Resources/Locale/ru-RU/backmen/trait/Mood.ftl new file mode 100644 index 00000000000..29e29f14871 --- /dev/null +++ b/Resources/Locale/ru-RU/backmen/trait/Mood.ftl @@ -0,0 +1,10 @@ +trait-category-mood = Настроение + +trait-fortitude-name = Моральная стойкость +trait-fortitude-desc = Вы не такой эмоциональный человек как остальные, вам плевать на все трудности и радости жизни. + +trait-hypomania-name = Гипомания +trait-hypomania-desc = Обычно вам чертвоски весело, но любой негатив вас сильно расстраивает! + +trait-depression-name = Депрессия +trait-depression-desc = Чувак, эта вечеринка отстой. Я, блин, ненавижу этих людей. diff --git a/Resources/Prototypes/_Backmen/Mood/genericNegativeEffects.yml b/Resources/Prototypes/_Backmen/Mood/genericNegativeEffects.yml index 808bb88ee36..92faea75d10 100644 --- a/Resources/Prototypes/_Backmen/Mood/genericNegativeEffects.yml +++ b/Resources/Prototypes/_Backmen/Mood/genericNegativeEffects.yml @@ -40,6 +40,10 @@ id: TraitSaturnine moodChange: -20 +- type: moodEffect + id: TraitFortitude + moodChange: -10 + - type: moodEffect id: Dead moodChange: -1000 @@ -58,5 +62,5 @@ - type: moodEffect id: SurgeryPain - moodChange: -15 - timeout: 180 + moodChange: -30 + timeout: 90 diff --git a/Resources/Prototypes/_Backmen/Traits/categories.yml b/Resources/Prototypes/_Backmen/Traits/categories.yml new file mode 100644 index 00000000000..fd2f9aa6796 --- /dev/null +++ b/Resources/Prototypes/_Backmen/Traits/categories.yml @@ -0,0 +1,4 @@ +- type: traitCategory + id: MoodTraits + name: trait-category-mood + maxTraitPoints: 1 diff --git a/Resources/Prototypes/_Backmen/Traits/neutral.yml b/Resources/Prototypes/_Backmen/Traits/neutral.yml new file mode 100644 index 00000000000..bbc953e8336 --- /dev/null +++ b/Resources/Prototypes/_Backmen/Traits/neutral.yml @@ -0,0 +1,33 @@ +# for mood haters +- type: trait + id: Fortitude + name: trait-fortitude-name + description: trait-fortitude-desc + category: MoodTraits + cost: 1 + components: + - type: MoodModifyTrait + moodId: TraitFortitude + goodMoodMultiplier: 0.5 + badMoodMultiplier: 0.5 + +- type: trait + id: Hypomania + name: trait-hypomania-name + description: trait-hypomania-desc + category: MoodTraits + cost: 1 + components: + - type: MoodModifyTrait + moodId: TraitSanguine + badMoodMultiplier: 1.5 # Everything comes with a price. + +- type: trait + id: Depression + name: trait-depression-name + description: trait-depression-desc + category: MoodTraits + cost: 1 + components: + - type: MoodModifyTrait + moodId: TraitSaturnine