Skip to content

Commit

Permalink
[Fix] Mood cool fixes (space-syndicate#916)
Browse files Browse the repository at this point in the history
* Fix Overlays (space-syndicate#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 (space-syndicate#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 <[email protected]>
  • Loading branch information
2 people authored and AwareFoxy committed Dec 17, 2024
1 parent 7883b5d commit e9c7200
Show file tree
Hide file tree
Showing 10 changed files with 250 additions and 137 deletions.
105 changes: 1 addition & 104 deletions Content.Server/Backmen/Mood/MoodComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, string> CategorisedEffects = new();

[ViewVariables(VVAccess.ReadOnly)]
public readonly Dictionary<string, float> UncategorisedEffects = new();

/// <summary>
/// The formula for the movement speed modifier is SpeedBonusGrowth ^ (MoodLevel - MoodThreshold.Neutral).
/// Change this ONLY BY 0.001 AT A TIME.
/// </summary>
[DataField]
public float SpeedBonusGrowth = 1.003f;

/// <summary>
/// The lowest point that low morale can multiply our movement speed by. Lowering speed follows a linear curve, rather than geometric.
/// </summary>
[DataField]
public float MinimumSpeedModifier = 0.75f;

/// <summary>
/// The maximum amount that high morale can multiply our movement speed by. This follows a significantly slower geometric sequence.
/// </summary>
[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<MoodThreshold, float>))]
public Dictionary<MoodThreshold, float> 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<MoodThreshold, ProtoId<AlertPrototype>>))]
public Dictionary<MoodThreshold, ProtoId<AlertPrototype>> 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" }
};

/// <summary>
/// These thresholds represent a percentage of Crit-Threshold, 0.8 corresponding with 80%.
/// </summary>
[DataField(customTypeSerializer: typeof(DictionarySerializer<string, float>))]
public Dictionary<string, float> 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
}
46 changes: 26 additions & 20 deletions Content.Server/Backmen/Mood/MoodSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<MoodComponent>(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)
Expand Down Expand Up @@ -289,12 +293,18 @@ private void RefreshMood(EntityUid uid, MoodComponent component)
if (!_prototypeManager.TryIndex<MoodEffectPrototype>(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);
Expand All @@ -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<NetMoodComponent>(uid);
RefreshMood(uid, component);
}

Expand Down Expand Up @@ -340,12 +349,8 @@ private void SetMood(EntityUid uid, float amount, MoodComponent? component = nul

component.CurrentMoodLevel = newMoodLevel;

if (TryComp<NetMoodComponent>(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);
}

Expand All @@ -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);
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
135 changes: 129 additions & 6 deletions Content.Shared/Backmen/Mood/SharedMoodComponent.cs
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// 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.
/// </summary>
[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<string, string> CategorisedEffects = new();

[ViewVariables(VVAccess.ReadOnly)]
public readonly Dictionary<string, float> UncategorisedEffects = new();

/// <summary>
/// The formula for the movement speed modifier is SpeedBonusGrowth ^ (MoodLevel - MoodThreshold.Neutral).
/// Change this ONLY BY 0.001 AT A TIME.
/// </summary>
[DataField]
public float SpeedBonusGrowth = 1.003f;

/// <summary>
/// The lowest point that low morale can multiply our movement speed by. Lowering speed follows a linear curve, rather than geometric.
/// </summary>
[DataField]
public float MinimumSpeedModifier = 0.90f;

/// <summary>
/// The maximum amount that high morale can multiply our movement speed by. This follows a significantly slower geometric sequence.
/// </summary>
[DataField]
public float MaximumSpeedModifier = 1.15f;

[DataField]
public float IncreaseCritThreshold = 1.2f;

[DataField]
public float DecreaseCritThreshold = 0.9f;

/// <summary>
/// Multiplier for positive mood effects.
/// </summary>
[DataField]
public float GoodMoodMultiplier = 1.0f;

/// <summary>
/// Multiplier for negative mood effects.
/// </summary>
[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<MoodThreshold, float>))]
public Dictionary<MoodThreshold, float> 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<MoodThreshold, ProtoId<AlertPrototype>>))]
public Dictionary<MoodThreshold, ProtoId<AlertPrototype>> 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" }
};

/// <summary>
/// These thresholds represent a percentage of Crit-Threshold, 0.8 corresponding with 80%.
/// </summary>
[DataField(customTypeSerializer: typeof(DictionarySerializer<string, float>))]
public Dictionary<string, float> 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
}
Loading

0 comments on commit e9c7200

Please sign in to comment.