diff --git a/Content.Client/White/Overlays/SaturationScaleOverlay.cs b/Content.Client/White/Overlays/SaturationScaleOverlay.cs new file mode 100644 index 0000000000..272b34fc46 --- /dev/null +++ b/Content.Client/White/Overlays/SaturationScaleOverlay.cs @@ -0,0 +1,37 @@ +using Robust.Client.Graphics; +using Robust.Shared.Enums; +using Robust.Shared.Prototypes; + +namespace Content.Client.White.Overlays; + +public sealed class SaturationScaleOverlay : Overlay +{ + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + + public override bool RequestScreenTexture => true; + public override OverlaySpace Space => OverlaySpace.WorldSpace; + private readonly ShaderInstance _shader; + private const float Saturation = 0.5f; + + public SaturationScaleOverlay() + { + IoCManager.InjectDependencies(this); + _shader = _prototypeManager.Index("SaturationScale").InstanceUnique(); + } + + + protected override void Draw(in OverlayDrawArgs args) + { + if (ScreenTexture == null) + return; + + _shader.SetParameter("SCREEN_TEXTURE", ScreenTexture); + _shader.SetParameter("saturation", Saturation); + + var handle = args.WorldHandle; + + handle.UseShader(_shader); + handle.DrawRect(args.WorldBounds, Color.White); + handle.UseShader(null); + } +} diff --git a/Content.Client/White/Overlays/SaturationScaleSystem.cs b/Content.Client/White/Overlays/SaturationScaleSystem.cs new file mode 100644 index 0000000000..543ba53ff5 --- /dev/null +++ b/Content.Client/White/Overlays/SaturationScaleSystem.cs @@ -0,0 +1,61 @@ +using Content.Shared.GameTicking; +using Content.Shared.White.Overlays; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Client.Player; +using Robust.Shared.Player; + +namespace Content.Client.White.Overlays; + +public sealed class SaturationScaleSystem : EntitySystem +{ + [Dependency] private readonly IPlayerManager _player = default!; + [Dependency] private readonly IOverlayManager _overlayMan = default!; + [Dependency] private readonly ILightManager _lightManager = default!; + + private SaturationScaleOverlay _overlay = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnShutdown); + + SubscribeLocalEvent(OnPlayerAttached); + SubscribeLocalEvent(OnPlayerDetached); + + SubscribeNetworkEvent(RoundRestartCleanup); + + _overlay = new(); + } + + private void RoundRestartCleanup(RoundRestartCleanupEvent ev) + { + _overlayMan.RemoveOverlay(_overlay); + } + + private void OnPlayerDetached(EntityUid uid, SaturationScaleComponent component, PlayerDetachedEvent args) + { + _overlayMan.RemoveOverlay(_overlay); + } + + private void OnPlayerAttached(EntityUid uid, SaturationScaleComponent component, PlayerAttachedEvent args) + { + _overlayMan.AddOverlay(_overlay); + } + + private void OnShutdown(EntityUid uid, SaturationScaleComponent component, ComponentShutdown args) + { + if (_player.LocalPlayer?.ControlledEntity == uid) + { + _overlayMan.RemoveOverlay(_overlay); + } + } + + private void OnInit(EntityUid uid, SaturationScaleComponent component, ComponentInit args) + { + if (_player.LocalPlayer?.ControlledEntity == uid) + _overlayMan.AddOverlay(_overlay); + } +} diff --git a/Content.Server/Arcade/BlockGame/BlockGame.cs b/Content.Server/Arcade/BlockGame/BlockGame.cs index 3af1828d56..4c8f0e6eed 100644 --- a/Content.Server/Arcade/BlockGame/BlockGame.cs +++ b/Content.Server/Arcade/BlockGame/BlockGame.cs @@ -2,6 +2,7 @@ using Content.Shared.Arcade; using Robust.Server.GameObjects; using Robust.Shared.Random; using System.Linq; +using Content.Shared.White.Mood; namespace Content.Server.Arcade.BlockGame; @@ -82,6 +83,10 @@ public sealed partial class BlockGame { _highScorePlacement = _arcadeSystem.RegisterHighScore(meta.EntityName, Points); SendHighscoreUpdate(); + //WD start + var ev = new MoodEffectEvent("ArcadePlay"); + _entityManager.EventBus.RaiseLocalEvent(meta.Owner, ev); + //WD end } SendMessage(new BlockGameMessages.BlockGameGameOverScreenMessage(Points, _highScorePlacement?.LocalPlacement, _highScorePlacement?.GlobalPlacement)); } diff --git a/Content.Server/Arcade/SpaceVillainGame/SpaceVillainArcadeSystem.cs b/Content.Server/Arcade/SpaceVillainGame/SpaceVillainArcadeSystem.cs index eae9b94964..3114a5479f 100644 --- a/Content.Server/Arcade/SpaceVillainGame/SpaceVillainArcadeSystem.cs +++ b/Content.Server/Arcade/SpaceVillainGame/SpaceVillainArcadeSystem.cs @@ -1,5 +1,6 @@ using Content.Server.Power.Components; using Content.Server.UserInterface; +using Content.Shared.White.Mood; using static Content.Shared.Arcade.SharedSpaceVillainArcadeComponent; using Robust.Server.GameObjects; using Robust.Shared.Audio; @@ -73,6 +74,9 @@ public sealed partial class SpaceVillainArcadeSystem : EntitySystem if (!TryComp(uid, out var power) || !power.Powered) return; + if (msg.Session.AttachedEntity != null) + RaiseLocalEvent(msg.Session.AttachedEntity.Value, new MoodEffectEvent("ArcadePlay")); //WD edit + switch (msg.PlayerAction) { case PlayerAction.Attack: diff --git a/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs b/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs index 1b3e1b07a6..a82ea14767 100644 --- a/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs +++ b/Content.Server/Atmos/EntitySystems/BarotraumaSystem.cs @@ -7,6 +7,7 @@ using Content.Shared.Database; using Content.Shared.FixedPoint; using Content.Shared.Inventory; using Content.Shared.Inventory.Events; +using Content.Shared.White.Mood; using Robust.Shared.Containers; namespace Content.Server.Atmos.EntitySystems @@ -203,6 +204,8 @@ namespace Content.Server.Atmos.EntitySystems _adminLogger.Add(LogType.Barotrauma, $"{ToPrettyString(uid):entity} started taking low pressure damage"); } + RaiseLocalEvent(uid, new MoodEffectEvent("MobLowPressure")); // WD edit + if (pressure <= Atmospherics.HazardLowPressure) { _alertsSystem.ShowAlert(uid, AlertType.LowPressure, 2); @@ -230,6 +233,8 @@ namespace Content.Server.Atmos.EntitySystems _adminLogger.Add(LogType.Barotrauma, $"{ToPrettyString(uid):entity} started taking high pressure damage"); } + RaiseLocalEvent(uid, new MoodEffectEvent("MobHighPressure")); // WD edit + if (pressure >= Atmospherics.HazardHighPressure) { _alertsSystem.ShowAlert(uid, AlertType.HighPressure, 2); @@ -247,6 +252,8 @@ namespace Content.Server.Atmos.EntitySystems _adminLogger.Add(LogType.Barotrauma, $"{ToPrettyString(uid):entity} stopped taking pressure damage"); } _alertsSystem.ClearAlertCategory(uid, AlertCategory.Pressure); + RaiseLocalEvent(uid, new MoodRemoveEffectEvent("MobLowPressure")); // WD edit + RaiseLocalEvent(uid, new MoodRemoveEffectEvent("MobHighPressure")); // WD edit break; } } diff --git a/Content.Server/Atmos/EntitySystems/FlammableSystem.cs b/Content.Server/Atmos/EntitySystems/FlammableSystem.cs index 95273f6e7f..3c697217ea 100644 --- a/Content.Server/Atmos/EntitySystems/FlammableSystem.cs +++ b/Content.Server/Atmos/EntitySystems/FlammableSystem.cs @@ -20,6 +20,9 @@ using Content.Shared.Timing; using Content.Shared.Toggleable; using Content.Shared.Weapons.Melee.Events; using Robust.Server.Audio; +using Content.Shared.White.Mood; +using Robust.Server.GameObjects; +using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Systems; @@ -371,10 +374,12 @@ namespace Content.Server.Atmos.EntitySystems if (!flammable.OnFire) { _alertsSystem.ClearAlert(uid, AlertType.Fire); + RaiseLocalEvent(uid, new MoodRemoveEffectEvent("OnFire")); // WD edit continue; } _alertsSystem.ShowAlert(uid, AlertType.Fire); + RaiseLocalEvent(uid, new MoodEffectEvent("OnFire")); // WD edit if (flammable.FireStacks > 0) { diff --git a/Content.Server/Bible/BibleSystem.cs b/Content.Server/Bible/BibleSystem.cs index ae990ff80d..6f7686f4e4 100644 --- a/Content.Server/Bible/BibleSystem.cs +++ b/Content.Server/Bible/BibleSystem.cs @@ -15,6 +15,7 @@ using Content.Shared.Mobs.Systems; using Content.Shared.Popups; using Content.Shared.Timing; using Content.Shared.Verbs; +using Content.Shared.White.Mood; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Player; @@ -154,6 +155,8 @@ namespace Content.Server.Bible _audio.PlayPvs(component.HealSoundPath, args.User); _delay.TryResetDelay((uid, useDelay)); } + + RaiseLocalEvent(args.Target.Value, new MoodEffectEvent("GotBlessed")); // WD edit } private void AddSummonVerb(EntityUid uid, SummonableComponent component, GetVerbsEvent args) diff --git a/Content.Server/Body/Systems/RespiratorSystem.cs b/Content.Server/Body/Systems/RespiratorSystem.cs index 8155a3598e..cbaa93ba86 100644 --- a/Content.Server/Body/Systems/RespiratorSystem.cs +++ b/Content.Server/Body/Systems/RespiratorSystem.cs @@ -21,7 +21,8 @@ using Content.Shared.Mobs; // WD using Content.Shared.Mobs.Components; // WD using Content.Shared.Mobs.Systems; using Content.Shared.Popups; // WD -using Content.Shared.White.CPR.Events; // WD +using Content.Shared.White.CPR.Events; +using Content.Shared.White.Mood; // WD using JetBrains.Annotations; using Robust.Server.Audio; // WD using Robust.Shared.Audio; // WD @@ -188,6 +189,7 @@ namespace Content.Server.Body.Systems if (respirator.SuffocationCycles >= respirator.SuffocationCycleThreshold) { _alertsSystem.ShowAlert(uid, AlertType.LowOxygen); + RaiseLocalEvent(uid, new MoodEffectEvent("Suffocating")); // WD edit } _damageableSys.TryChangeDamage(uid, respirator.Damage, false, false); @@ -343,6 +345,8 @@ namespace Content.Server.Body.Systems args.Repeat = true; else component.CPRPerformedBy = null; + + RaiseLocalEvent(args.User, new MoodEffectEvent("SavedLife")); } //WD end } diff --git a/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs b/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs index a6094e3606..34da3ed1d3 100644 --- a/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs @@ -27,6 +27,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; using Content.Server.Objectives; +using Content.Shared.White.Mood; namespace Content.Server.GameTicking.Rules; @@ -242,6 +243,8 @@ public sealed class TraitorRuleSystem : GameRuleSystem _npcFaction.RemoveFaction(entity, "NanoTrasen", false); _npcFaction.AddFaction(entity, "Syndicate"); + RaiseLocalEvent(mind.OwnedEntity.Value, new MoodEffectEvent("TraitorFocused")); // WD edit + // Give traitors their objectives if (giveObjectives) { diff --git a/Content.Server/Interaction/InteractionPopupSystem.cs b/Content.Server/Interaction/InteractionPopupSystem.cs index 474284cf80..406cac0bc8 100644 --- a/Content.Server/Interaction/InteractionPopupSystem.cs +++ b/Content.Server/Interaction/InteractionPopupSystem.cs @@ -5,6 +5,7 @@ using Content.Shared.IdentityManagement; using Content.Shared.Interaction; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; +using Content.Shared.White.Mood; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Player; @@ -58,7 +59,21 @@ public sealed class InteractionPopupSystem : EntitySystem if (_random.Prob(component.SuccessChance)) { if (component.InteractSuccessString != null) + { msg = Loc.GetString(component.InteractSuccessString, ("target", Identity.Entity(uid, EntityManager))); // Success message (localized). + //WD start + if (component.InteractSuccessString == "hugging-success-generic") + { + var ev = new MoodEffectEvent("BeingHugged"); + RaiseLocalEvent(uid, ev); + } + else if (component.InteractSuccessString.Contains("petting-success-")) + { + var ev = new MoodEffectEvent("PetAnimal"); + RaiseLocalEvent(args.User, ev); + } + //WD end + } if (component.InteractSuccessSound != null) sfx = component.InteractSuccessSound; diff --git a/Content.Server/Medical/VomitSystem.cs b/Content.Server/Medical/VomitSystem.cs index 8c3b15aed3..d5bef6997e 100644 --- a/Content.Server/Medical/VomitSystem.cs +++ b/Content.Server/Medical/VomitSystem.cs @@ -11,6 +11,8 @@ using Content.Shared.Nutrition.Components; using Content.Shared.Nutrition.EntitySystems; using Content.Shared.StatusEffect; using Robust.Server.Audio; +using Content.Shared.White.Mood; +using Robust.Server.GameObjects; using Robust.Shared.Audio; using Robust.Shared.Prototypes; @@ -94,6 +96,8 @@ namespace Content.Server.Medical // Force sound to play as spill doesn't work if solution is empty. _audio.PlayPvs("/Audio/Effects/Fluids/splat.ogg", uid, AudioParams.Default.WithVariation(0.2f).WithVolume(-4f)); _popup.PopupEntity(Loc.GetString("disease-vomit", ("person", Identity.Entity(uid, EntityManager))), uid); + + RaiseLocalEvent(uid, new MoodEffectEvent("MobVomit")); } } } diff --git a/Content.Server/White/Mood/MoodComponent.cs b/Content.Server/White/Mood/MoodComponent.cs new file mode 100644 index 0000000000..84f7e67ac2 --- /dev/null +++ b/Content.Server/White/Mood/MoodComponent.cs @@ -0,0 +1,107 @@ +using Content.Shared.Alert; +using Content.Shared.FixedPoint; +using Content.Shared.White.Mood; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Generic; + +namespace Content.Server.White.Mood; + +[RegisterComponent] +public sealed partial class MoodComponent : Component +{ + [DataField("currentMoodLevel"), ViewVariables(VVAccess.ReadOnly)] + public float CurrentMoodLevel; + + [DataField("currentMoodThreshold"), ViewVariables(VVAccess.ReadOnly)] + public MoodThreshold CurrentMoodThreshold; + + [DataField("lastThreshold"), ViewVariables(VVAccess.ReadOnly)] + public MoodThreshold LastThreshold; + + [ViewVariables(VVAccess.ReadOnly)] + public readonly Dictionary CategorisedEffects = new(); + + [ViewVariables(VVAccess.ReadOnly)] + public readonly Dictionary UncategorisedEffects = new(); + + [DataField("slowdownSpeedModifier"), ViewVariables(VVAccess.ReadWrite)] + public float SlowdownSpeedModifier = 0.75f; + + [DataField("increaseSpeedModifier"), ViewVariables(VVAccess.ReadWrite)] + public float IncreaseSpeedModifier = 1.15f; + + [DataField("increaseCritThreshold"), ViewVariables(VVAccess.ReadWrite)] + public float IncreaseCritThreshold = 1.2f; + + [DataField("decreaseCritThreshold"), ViewVariables(VVAccess.ReadWrite)] + public float DecreaseCritThreshold = 0.9f; + + [ViewVariables(VVAccess.ReadOnly)] + public FixedPoint2 CritThresholdBeforeModify; + + [DataField("moodThresholds", customTypeSerializer: typeof(DictionarySerializer))] + public Dictionary MoodThresholds = new() + { + { MoodThreshold.VeryVeryGood, 10.0f }, + { MoodThreshold.VeryGood, 8.0f }, + { MoodThreshold.Good, 7.0f }, + { MoodThreshold.Great, 6.0f }, + { MoodThreshold.Neutral, 5.0f }, + { MoodThreshold.NotGreat, 4.0f }, + { MoodThreshold.Bad, 3.0f }, + { MoodThreshold.VeryBad, 2.0f }, + { MoodThreshold.VeryVeryBad, 1.0f }, + { MoodThreshold.Dead, 0.0f } + }; + + [DataField("moodThresholdsAlerts", customTypeSerializer: typeof(DictionarySerializer))] + public Dictionary MoodThresholdsAlerts = new() + { + { MoodThreshold.Dead, AlertType.MoodDead }, + { MoodThreshold.VeryVeryBad, AlertType.VeryVeryBad }, + { MoodThreshold.VeryBad, AlertType.VeryBad }, + { MoodThreshold.Bad, AlertType.Bad }, + { MoodThreshold.NotGreat, AlertType.NotGreat }, + { MoodThreshold.Neutral, AlertType.Neutral }, + { MoodThreshold.Great, AlertType.Great }, + { MoodThreshold.Good, AlertType.Good }, + { MoodThreshold.VeryGood, AlertType.VeryGood }, + { MoodThreshold.VeryVeryGood, AlertType.VeryVeryGood }, + { MoodThreshold.Insane, AlertType.Insane } + }; + + [DataField("moodChangeValues", customTypeSerializer: typeof(DictionarySerializer))] + public Dictionary MoodChangeValues = new() + { + { MoodChangeLevel.None , 0.0f }, + { MoodChangeLevel.Small , 0.3f }, + { MoodChangeLevel.Medium , 0.7f }, + { MoodChangeLevel.Big , 1.0f }, + { MoodChangeLevel.Huge , 1.3f }, + { MoodChangeLevel.Large , 2f } + }; + + [DataField("healthMoodEffectsThresholds", customTypeSerializer: typeof(DictionarySerializer))] + public Dictionary HealthMoodEffectsThresholds = new() + { + { "HealthHeavyDamage", 80f }, + { "HealthSevereDamage", 50f }, + { "HealthLightDamage", 10f }, + { "HealthNoDamage", 5f } + }; +} + +[Serializable] +public enum MoodThreshold : ushort +{ + Insane = 1, + VeryVeryBad = 2, + VeryBad = 3, + Bad = 4, + NotGreat = 5, + Neutral = 6, + Great = 7, + Good = 8, + VeryGood = 9, + VeryVeryGood = 10, + Dead = 0 +} diff --git a/Content.Server/White/Mood/MoodSystem.cs b/Content.Server/White/Mood/MoodSystem.cs new file mode 100644 index 0000000000..b9c43d1e80 --- /dev/null +++ b/Content.Server/White/Mood/MoodSystem.cs @@ -0,0 +1,415 @@ +using Content.Server.Chat.Managers; +using Content.Shared.Alert; +using Content.Shared.Chat; +using Content.Shared.Damage; +using Content.Shared.FixedPoint; +using Content.Shared.Mobs; +using Content.Shared.Mobs.Components; +using Content.Shared.Mobs.Systems; +using Content.Shared.Movement.Systems; +using Content.Shared.White.Mood; +using Content.Shared.White.Overlays; +using JetBrains.Annotations; +using Robust.Server.GameObjects; +using Robust.Shared.Player; +using Robust.Shared.Prototypes; +using Timer = Robust.Shared.Timing.Timer; + +namespace Content.Server.White.Mood; + +public sealed class MoodSystem : EntitySystem +{ + [Dependency] private readonly AlertsSystem _alerts = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!; + [Dependency] private readonly SharedJetpackSystem _jetpack = default!; + [Dependency] private readonly MobThresholdSystem _mobThreshold = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnMobStateChanged); + SubscribeLocalEvent(OnMoodEffect); + SubscribeLocalEvent(OnDamageChange); + SubscribeLocalEvent(OnRefreshMoveSpeed); + SubscribeLocalEvent(OnRemoveEffect); + } + + private void OnRemoveEffect(EntityUid uid, MoodComponent component, MoodRemoveEffectEvent args) + { + if (component.UncategorisedEffects.TryGetValue(args.EffectId, out _)) + RemoveTimedOutEffect(uid, component, args.EffectId); + else + { + foreach (var (category, id) in component.CategorisedEffects) + { + if (id == args.EffectId) + { + RemoveTimedOutEffect(uid, component, args.EffectId, category); + return; + } + } + } + } + + private void OnRefreshMoveSpeed(EntityUid uid, MoodComponent component, RefreshMovementSpeedModifiersEvent args) + { + if (component.CurrentMoodThreshold is > MoodThreshold.VeryBad and < MoodThreshold.VeryGood or MoodThreshold.Dead) + return; + + if (_jetpack.IsUserFlying(uid)) + return; + + var modifier = GetMovementThreshold(component.CurrentMoodThreshold) switch + { + -1 => component.SlowdownSpeedModifier, + 1 => component.IncreaseSpeedModifier, + _ => 1 + }; + + args.ModifySpeed(modifier, modifier); + } + + private void OnMoodEffect(EntityUid uid, MoodComponent component, MoodEffectEvent args) + { + if (!_prototypeManager.TryIndex(args.EffectId, out var prototype)) + return; + + ApplyEffect(uid, component, prototype); + } + + private void ApplyEffect(EntityUid uid, MoodComponent component, MoodEffectPrototype prototype) + { + var amount = component.CurrentMoodLevel; + + if (!component.MoodChangeValues.TryGetValue(prototype.MoodChange, out var value)) + return; + + //Apply categorised effect + if (prototype.Category != null) + { + if (component.CategorisedEffects.TryGetValue(prototype.Category, out var oldPrototypeId)) + { + if (!_prototypeManager.TryIndex(oldPrototypeId, out var oldPrototype)) + return; + + if (prototype.ID != oldPrototype.ID) + { + if (!component.MoodChangeValues.TryGetValue(oldPrototype.MoodChange, out var oldValue)) + return; + + amount += (oldPrototype.PositiveEffect ? -oldValue : oldValue) + (prototype.PositiveEffect ? value : -value); + component.CategorisedEffects[prototype.Category] = prototype.ID; + } + } + else + { + component.CategorisedEffects.Add(prototype.Category, prototype.ID); + amount += prototype.PositiveEffect ? value : -value; + } + + if (prototype.Timeout != 0) + Timer.Spawn(TimeSpan.FromMinutes(prototype.Timeout), () => RemoveTimedOutEffect(uid, component, prototype.ID, prototype.Category)); + } + //Apply uncategorised effect + else + { + if (component.UncategorisedEffects.TryGetValue(prototype.ID, out _)) + return; + + var effectValue = prototype.PositiveEffect ? value : -value; + + component.UncategorisedEffects.Add(prototype.ID, effectValue); + amount += effectValue; + + if (prototype.Timeout != 0) + Timer.Spawn(TimeSpan.FromMinutes(prototype.Timeout), () => RemoveTimedOutEffect(uid, component, prototype.ID)); + } + + SetMood(uid, amount, component); + } + + private void RemoveTimedOutEffect(EntityUid uid, MoodComponent comp, string prototypeId, string? category = null) + { + var amount = comp.CurrentMoodLevel; + + if (category == null) + { + if (!comp.UncategorisedEffects.TryGetValue(prototypeId, out var value)) + return; + + amount += -value; + comp.UncategorisedEffects.Remove(prototypeId); + } + else + { + if (!comp.CategorisedEffects.TryGetValue(category, out var currentProtoId)) + return; + if (currentProtoId != prototypeId) + return; + if (!_prototypeManager.TryIndex(currentProtoId, out var currentProto)) + return; + if (!comp.MoodChangeValues.TryGetValue(currentProto.MoodChange, out var value)) + return; + + amount += currentProto.PositiveEffect ? -value : value; + comp.CategorisedEffects.Remove(category); + } + + SetMood(uid, amount, comp); + } + + private void OnMobStateChanged(EntityUid uid, MoodComponent component, MobStateChangedEvent args) + { + if (args.NewMobState == MobState.Dead && args.OldMobState != MobState.Dead) + { + SetMood(uid, component.MoodThresholds[MoodThreshold.Dead], component, true); + } + + else if (args.OldMobState == MobState.Dead && args.NewMobState != MobState.Dead) + { + ReapplyAllEffects(uid, component); + } + } + + private void ReapplyAllEffects(EntityUid uid, MoodComponent component) + { + var amount = component.MoodThresholds[MoodThreshold.Neutral]; + + foreach (var (_, protoId) in component.CategorisedEffects) + { + if (!_prototypeManager.TryIndex(protoId, out var prototype)) + return; + + if (!component.MoodChangeValues.TryGetValue(prototype.MoodChange, out var value)) + return; + + amount += prototype.PositiveEffect ? value : -value; + } + + foreach (var (_, value) in component.UncategorisedEffects) + { + amount += value; + } + + SetMood(uid, amount, component, refresh: true); + } + + private void OnInit(EntityUid uid, MoodComponent component, ComponentInit args) + { + _mobThreshold.TryGetThresholdForState(uid, MobState.Critical, out var critThreshold); + if (critThreshold != null) + component.CritThresholdBeforeModify = critThreshold.Value; + + var amount = component.MoodThresholds[MoodThreshold.Neutral]; + SetMood(uid, amount, component, refresh: true); + } + + public void SetMood(EntityUid uid, float amount, MoodComponent? component = null, bool force = false, bool refresh = false) + { + if (!Resolve(uid, ref component)) + return; + + if (component.CurrentMoodThreshold == MoodThreshold.Dead && !refresh) + return; + + if (!force) + { + component.CurrentMoodLevel = Math.Clamp(amount, + component.MoodThresholds[MoodThreshold.Dead] + 0.1f, + component.MoodThresholds[MoodThreshold.VeryVeryGood]); + } + else + { + component.CurrentMoodLevel = amount; + } + + UpdateCurrentThreshold(uid, component); + } + + private void UpdateCurrentThreshold(EntityUid uid, MoodComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + var calculatedThreshold = GetMoodThreshold(component); + if (calculatedThreshold == component.CurrentMoodThreshold) + return; + + component.CurrentMoodThreshold = calculatedThreshold; + + DoMoodThresholdsEffects(uid, component); + } + + private void DoMoodThresholdsEffects(EntityUid uid, MoodComponent? component = null, bool force = false) + { + if (!Resolve(uid, ref component)) + return; + + if (component.CurrentMoodThreshold == component.LastThreshold && !force) + return; + + var modifier = GetMovementThreshold(component.CurrentMoodThreshold); + // Modify mob stats + if (modifier != GetMovementThreshold(component.LastThreshold)) + { + _movementSpeedModifier.RefreshMovementSpeedModifiers(uid); + SetCritThreshold(uid, component, modifier); + RefreshShaders(uid, modifier); + } + + // Modify interface + if (component.MoodThresholdsAlerts.TryGetValue(component.CurrentMoodThreshold, out var alertId)) + { + _alerts.ShowAlert(uid, alertId); + } + else + { + _alerts.ClearAlertCategory(uid, AlertCategory.Mood); + } + + component.LastThreshold = component.CurrentMoodThreshold; + } + + private void RefreshShaders(EntityUid uid, int modifier) + { + if (modifier == -1) + { + EnsureComp(uid); + } + else + { + RemComp(uid); + } + } + + private void SetCritThreshold(EntityUid uid, MoodComponent component, int modifier) + { + if (!TryComp(uid, out var mobThresholds)) + return; + + if (!_mobThreshold.TryGetThresholdForState(uid, MobState.Critical, out var key)) + return; + + var newKey = modifier switch + { + 1 => FixedPoint2.New(key.Value.Float() * component.IncreaseCritThreshold), + -1 => FixedPoint2.New(key.Value.Float() * component.DecreaseCritThreshold), + _ => component.CritThresholdBeforeModify + }; + + component.CritThresholdBeforeModify = key.Value; + _mobThreshold.SetMobStateThreshold(uid, newKey, MobState.Critical, mobThresholds); + } + + private MoodThreshold GetMoodThreshold(MoodComponent component, float? moodLevel = null) + { + moodLevel ??= component.CurrentMoodLevel; + var result = MoodThreshold.Dead; + var value = component.MoodThresholds[MoodThreshold.VeryVeryGood]; + + foreach (var threshold in component.MoodThresholds) + { + if (threshold.Value <= value && threshold.Value >= moodLevel) + { + result = threshold.Key; + value = threshold.Value; + } + } + + return result; + } + + private int GetMovementThreshold(MoodThreshold threshold) + { + return threshold switch + { + >= MoodThreshold.VeryGood => 1, + <= MoodThreshold.VeryBad => -1, + _ => 0 + }; + } + + #region HealthStatusCheck + + private void OnDamageChange(EntityUid uid, MoodComponent component, DamageChangedEvent args) + { + var damage = args.Damageable.TotalDamage.Float(); + var protoId = "HealthNoDamage"; + var value = component.HealthMoodEffectsThresholds["HealthNoDamage"]; + + foreach (var threshold in component.HealthMoodEffectsThresholds) + { + if (threshold.Value <= damage && threshold.Value >= value) + { + protoId = threshold.Key; + value = threshold.Value; + } + } + + var ev = new MoodEffectEvent(protoId); + RaiseLocalEvent(uid, ev); + } + + #endregion +} + +[UsedImplicitly] +[DataDefinition] +public sealed partial class ShowMoodEffects : IAlertClick +{ + public void AlertClicked(EntityUid uid) + { + var entityManager = IoCManager.Resolve(); + var prototypeManager = IoCManager.Resolve(); + var chatManager = IoCManager.Resolve(); + + if (!entityManager.TryGetComponent(uid, out var comp)) + return; + + if (comp.CurrentMoodThreshold == MoodThreshold.Dead) + return; + + if (!entityManager.TryGetComponent(uid, out var actorComp)) + return; + + var msgStart = Loc.GetString("mood-show-effects-start"); + chatManager.ChatMessageToOne(ChatChannel.Emotes, msgStart, msgStart, EntityUid.Invalid, false, + actorComp.PlayerSession.ConnectedClient); + + foreach (var (_, protoId) in comp.CategorisedEffects) + { + if (!prototypeManager.TryIndex(protoId, out var proto)) + continue; + + if (proto.Hidden) + continue; + + SendDescToChat(proto, actorComp); + } + + foreach (var (protoId, _) in comp.UncategorisedEffects) + { + if (!prototypeManager.TryIndex(protoId, out var proto)) + continue; + + if (proto.Hidden) + continue; + + SendDescToChat(proto, actorComp); + } + } + + private void SendDescToChat(MoodEffectPrototype proto, ActorComponent comp) + { + var chatManager = IoCManager.Resolve(); + + var color = proto.PositiveEffect ? "#008000" : "#BA0000"; + var msg = $"[font size=10][color={color}]{proto.Description}[/color][/font]"; + + chatManager.ChatMessageToOne(ChatChannel.Emotes, msg, msg, EntityUid.Invalid, false, + comp.PlayerSession.ConnectedClient); + } +} diff --git a/Content.Shared/Alert/AlertCategory.cs b/Content.Shared/Alert/AlertCategory.cs index 7450f585a4..a769e88355 100644 --- a/Content.Shared/Alert/AlertCategory.cs +++ b/Content.Shared/Alert/AlertCategory.cs @@ -10,6 +10,7 @@ public enum AlertCategory Breathing, Buckled, Health, + Mood, //WD-edit Internals, Stamina, Piloting, diff --git a/Content.Shared/Alert/AlertType.cs b/Content.Shared/Alert/AlertType.cs index f236e6fb09..7b40876df2 100644 --- a/Content.Shared/Alert/AlertType.cs +++ b/Content.Shared/Alert/AlertType.cs @@ -25,6 +25,20 @@ namespace Content.Shared.Alert Bleeding, BorgBattery, BorgBatteryNone, + //WD start + Insane, + VeryVeryBad, + VeryBad, + Bad, + NotGreat, + Neutral, + Great, + Good, + VeryGood, + VeryVeryGood, + MoodDead, + //WD end + CultBuffed, PilotingShuttle, Peckish, Starving, diff --git a/Content.Shared/Cuffs/SharedCuffableSystem.cs b/Content.Shared/Cuffs/SharedCuffableSystem.cs index c51a2fb185..cd16b0bc33 100644 --- a/Content.Shared/Cuffs/SharedCuffableSystem.cs +++ b/Content.Shared/Cuffs/SharedCuffableSystem.cs @@ -30,6 +30,7 @@ using Content.Shared.Verbs; using Content.Shared.Weapons.Melee.Events; using Robust.Shared.Audio.Systems; using Content.Shared.White.EndOfRoundStats.CuffedTime; +using Content.Shared.White.Mood; using Robust.Shared.Containers; using Robust.Shared.Network; using Robust.Shared.Player; @@ -172,9 +173,15 @@ namespace Content.Shared.Cuffs _actionBlocker.UpdateCanMove(uid); if (component.CanStillInteract) + { _alerts.ClearAlert(uid, AlertType.Handcuffed); + RaiseLocalEvent(uid, new MoodRemoveEffectEvent("Handcuffed")); //WD edit + } else + { _alerts.ShowAlert(uid, AlertType.Handcuffed); + RaiseLocalEvent(uid, new MoodEffectEvent("Handcuffed")); // WD edit + } var ev = new CuffedStateChangeEvent(); RaiseLocalEvent(uid, ref ev); diff --git a/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs b/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs index 9c09603510..ad09db1824 100644 --- a/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs @@ -4,6 +4,9 @@ using Content.Shared.Mobs.Systems; using Content.Shared.Movement.Systems; using Content.Shared.Nutrition.Components; using Content.Shared.Rejuvenate; +using Content.Shared.White.Mood; +using Robust.Shared.GameStates; +using Robust.Shared.Network; using Robust.Shared.Random; using Robust.Shared.Timing; @@ -18,6 +21,7 @@ public sealed class HungerSystem : EntitySystem [Dependency] private readonly MobStateSystem _mobState = default!; [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!; [Dependency] private readonly SharedJetpackSystem _jetpack = default!; + [Dependency] private readonly INetManager _net = default!; // WD edit public override void Initialize() { @@ -26,7 +30,7 @@ public sealed class HungerSystem : EntitySystem SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnShutdown); - SubscribeLocalEvent(OnRefreshMovespeed); + //SubscribeLocalEvent(OnRefreshMovespeed); WD-edit SubscribeLocalEvent(OnRejuvenate); } @@ -115,10 +119,18 @@ public sealed class HungerSystem : EntitySystem if (component.CurrentThreshold == component.LastThreshold && !force) return; - if (GetMovementThreshold(component.CurrentThreshold) != GetMovementThreshold(component.LastThreshold)) + //WD start + if (_net.IsServer) + { + var ev = new MoodEffectEvent("Hunger" + component.CurrentThreshold); + RaiseLocalEvent(uid, ev); + } + + /*if (GetMovementThreshold(component.CurrentThreshold) != GetMovementThreshold(component.LastThreshold)) { _movementSpeedModifier.RefreshMovementSpeedModifiers(uid); - } + }*/ + //WD end if (component.HungerThresholdAlerts.TryGetValue(component.CurrentThreshold, out var alertId)) { diff --git a/Content.Shared/Nutrition/EntitySystems/SharedCreamPieSystem.cs b/Content.Shared/Nutrition/EntitySystems/SharedCreamPieSystem.cs index bd7251b943..c278b88b48 100644 --- a/Content.Shared/Nutrition/EntitySystems/SharedCreamPieSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/SharedCreamPieSystem.cs @@ -1,6 +1,7 @@ using Content.Shared.Nutrition.Components; using Content.Shared.Stunnable; using Content.Shared.Throwing; +using Content.Shared.White.Mood; using JetBrains.Annotations; namespace Content.Shared.Nutrition.EntitySystems @@ -44,6 +45,8 @@ namespace Content.Shared.Nutrition.EntitySystems { _appearance.SetData(uid, CreamPiedVisuals.Creamed, value, appearance); } + + RaiseLocalEvent(uid, new MoodEffectEvent("Creampied")); // WD edit } private void OnCreamPieLand(EntityUid uid, CreamPieComponent component, ref LandEvent args) diff --git a/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs b/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs index 05a2338768..7b869a3bfb 100644 --- a/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs @@ -6,6 +6,11 @@ using Content.Shared.Rejuvenate; using JetBrains.Annotations; using Robust.Shared.Random; using Robust.Shared.Timing; +using Content.Shared.Movement.Components; +using Content.Shared.Alert; +using Content.Shared.Movement.Systems; +using Content.Shared.Rejuvenate; +using Content.Shared.White.Mood; namespace Content.Shared.Nutrition.EntitySystems; @@ -26,7 +31,7 @@ public sealed class ThirstSystem : EntitySystem _sawmill = Logger.GetSawmill("thirst"); - SubscribeLocalEvent(OnRefreshMovespeed); + //SubscribeLocalEvent(OnRefreshMovespeed); WD-edit SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnRejuvenate); SubscribeLocalEvent(OnUnpaused); @@ -114,11 +119,13 @@ public sealed class ThirstSystem : EntitySystem private void UpdateEffects(EntityUid uid, ThirstComponent component) { - if (IsMovementThreshold(component.LastThirstThreshold) != IsMovementThreshold(component.CurrentThirstThreshold) && + //WD start + /*if (IsMovementThreshold(component.LastThirstThreshold) != IsMovementThreshold(component.CurrentThirstThreshold) && TryComp(uid, out MovementSpeedModifierComponent? movementSlowdownComponent)) { _movement.RefreshMovementSpeedModifiers(uid, movementSlowdownComponent); - } + }*/ + //WD end // Update UI if (ThirstComponent.ThirstThresholdAlertTypes.TryGetValue(component.CurrentThirstThreshold, out var alertId)) @@ -130,6 +137,11 @@ public sealed class ThirstSystem : EntitySystem _alerts.ClearAlertCategory(uid, AlertCategory.Thirst); } + //WD start + var ev = new MoodEffectEvent("Thirst" + component.CurrentThirstThreshold); + RaiseLocalEvent(uid, ev); + //WD end + switch (component.CurrentThirstThreshold) { case ThirstThreshold.OverHydrated: diff --git a/Content.Shared/Revolutionary/SharedRevolutionarySystem.cs b/Content.Shared/Revolutionary/SharedRevolutionarySystem.cs index 1399b116e0..61c11be0d2 100644 --- a/Content.Shared/Revolutionary/SharedRevolutionarySystem.cs +++ b/Content.Shared/Revolutionary/SharedRevolutionarySystem.cs @@ -3,6 +3,7 @@ using Content.Shared.Mindshield.Components; using Content.Shared.Popups; using Content.Shared.Revolutionary.Components; using Content.Shared.Stunnable; +using Content.Shared.White.Mood; namespace Content.Shared.Revolutionary; @@ -15,8 +16,22 @@ public sealed class SharedRevolutionarySystem : EntitySystem { base.Initialize(); SubscribeLocalEvent(MindShieldImplanted); + SubscribeLocalEvent(OnInit); // WD EDIT + SubscribeLocalEvent(OnShutdown); // WD EDIT } + // WD START + private void OnShutdown(Entity ent, ref ComponentShutdown args) + { + RaiseLocalEvent(ent, new MoodRemoveEffectEvent("RevolutionFocused")); + } + + private void OnInit(Entity ent, ref ComponentInit args) + { + RaiseLocalEvent(ent, new MoodEffectEvent("RevolutionFocused")); + } + // WD END + /// /// When the mindshield is implanted in the rev it will popup saying they were deconverted. In Head Revs it will remove the mindshield component. /// diff --git a/Content.Shared/Slippery/SlipperySystem.cs b/Content.Shared/Slippery/SlipperySystem.cs index 60d53eb16f..b841ef1c0b 100644 --- a/Content.Shared/Slippery/SlipperySystem.cs +++ b/Content.Shared/Slippery/SlipperySystem.cs @@ -4,6 +4,7 @@ using Content.Shared.Inventory; using Content.Shared.StatusEffect; using Content.Shared.StepTrigger.Systems; using Content.Shared.Stunnable; +using Content.Shared.White.Mood; using JetBrains.Annotations; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; @@ -78,6 +79,8 @@ public sealed class SlipperySystem : EntitySystem _stun.TryParalyze(other, TimeSpan.FromSeconds(component.ParalyzeTime), true); + RaiseLocalEvent(other, new MoodEffectEvent("MobSlipped")); // WD edit + // Preventing from playing the slip sound when you are already knocked down. if (playSound) { diff --git a/Content.Shared/White/Mood/MoodEffectPrototype.cs b/Content.Shared/White/Mood/MoodEffectPrototype.cs new file mode 100644 index 0000000000..5cad886171 --- /dev/null +++ b/Content.Shared/White/Mood/MoodEffectPrototype.cs @@ -0,0 +1,31 @@ +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations; + +namespace Content.Shared.White.Mood; + +[Prototype("moodEffect")] +public sealed class MoodEffectPrototype : IPrototype +{ + [ViewVariables] + [IdDataField] + public string ID { get; } = default!; + + [DataField("desc", required: true)] + public string Description = string.Empty; + + [DataField("moodChange", customTypeSerializer: typeof(EnumSerializer), required: true)] + public Enum MoodChange = default!; + + [DataField("positiveEffect", required: true)] + public bool PositiveEffect; + + [DataField("timeout")] + public int Timeout; + + [DataField("hidden")] + public bool Hidden; + + //If mob already has effect of the same category, the new one will replace the old one. + [DataField("category")] + public string? Category; +} diff --git a/Content.Shared/White/Mood/MoodSerializables.cs b/Content.Shared/White/Mood/MoodSerializables.cs new file mode 100644 index 0000000000..bd1b707cd6 --- /dev/null +++ b/Content.Shared/White/Mood/MoodSerializables.cs @@ -0,0 +1,36 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.White.Mood; + +[Serializable, NetSerializable] +public enum MoodChangeLevel : byte +{ + None, + Small, + Medium, + Big, + Huge, + Large +} + +[Serializable, NetSerializable] +public sealed partial class MoodEffectEvent : EntityEventArgs +{ + public string EffectId; + + public MoodEffectEvent(string effectId) + { + EffectId = effectId; + } +} + +[Serializable, NetSerializable] +public sealed partial class MoodRemoveEffectEvent : EntityEventArgs +{ + public string EffectId; + + public MoodRemoveEffectEvent(string effectId) + { + EffectId = effectId; + } +} diff --git a/Content.Shared/White/Overlays/SaturationScaleComponent.cs b/Content.Shared/White/Overlays/SaturationScaleComponent.cs new file mode 100644 index 0000000000..489b79eab3 --- /dev/null +++ b/Content.Shared/White/Overlays/SaturationScaleComponent.cs @@ -0,0 +1,8 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.White.Overlays; + +[RegisterComponent, NetworkedComponent] +public sealed partial class SaturationScaleComponent : Component +{ +} diff --git a/Resources/Locale/ru-RU/white/mood/mood-alerts.ftl b/Resources/Locale/ru-RU/white/mood/mood-alerts.ftl new file mode 100644 index 0000000000..043494dc67 --- /dev/null +++ b/Resources/Locale/ru-RU/white/mood/mood-alerts.ftl @@ -0,0 +1,22 @@ +alerts-mood-insane-name = Безумие +alerts-mood-insane-desc = В моей душе тлеют мрак и безнадежность, мир обречен на абсолютное зло. +alerts-mood-very-very-bad-name = Печально +alerts-mood-very-very-bad-desc = Я борюсь с болями и страхами, моя судьба - череда мучений и страданий. +alerts-mood-very-bad-name = Очень плохо +alerts-mood-very-bad-desc = Моя жизнь иссякла, как кровь из раны, и вокруг лишь мрак и отчаяние. +alerts-mood-bad-name = Плохо +alerts-mood-bad-desc = Силы покидают меня, и каждый день становится тяжелым испытанием. +alerts-mood-not-great-name = Нехорошо +alerts-mood-not-great-desc = Мир полон угроз и боли, и мои надежды медленно умирают. +alerts-mood-neutral-name = Нормально +alerts-mood-neutral-desc = Я продолжаю свой путь, несмотря на угрозы и лишения, ища хоть малейший свет во мраке. +alerts-mood-great-name = Неплохо +alerts-mood-great-desc = В этом мире полном страданий, я обретаю небольшое облегчение и надежду. +alerts-mood-good-name = Хорошо +alerts-mood-good-desc = Моя сила восстанавливается, и мир кажется меньшим злом и болью. +alerts-mood-very-good-name = Очень хорошо +alerts-mood-very-good-desc = Я ощущаю в себе силы и надежду на лучшие дни, несмотря на угрозы, что таятся вокруг. +alerts-mood-very-very-good-name = Великолепно +alerts-mood-very-very-good-desc = Моя душа полна света и силы, и я готов сразиться с тьмой в этом жестоком мире. +alerts-mood-dead-name = Мёртв +alerts-mood-dead-desc = Вечная пустота окутала меня, и мир больше не имеет власти над моей душой. diff --git a/Resources/Locale/ru-RU/white/mood/mood.ftl b/Resources/Locale/ru-RU/white/mood/mood.ftl new file mode 100644 index 0000000000..b9619035ea --- /dev/null +++ b/Resources/Locale/ru-RU/white/mood/mood.ftl @@ -0,0 +1 @@ +mood-show-effects-start = [font size=12]Настроение:[/font] diff --git a/Resources/Prototypes/Alerts/alerts.yml b/Resources/Prototypes/Alerts/alerts.yml index 1e72376048..a97479ef81 100644 --- a/Resources/Prototypes/Alerts/alerts.yml +++ b/Resources/Prototypes/Alerts/alerts.yml @@ -6,6 +6,7 @@ order: - category: Health - alertType: Bleeding + - category: Mood # WD edit - category: Stamina - alertType: SuitPower - category: Internals diff --git a/Resources/Prototypes/Entities/Mobs/Species/base.yml b/Resources/Prototypes/Entities/Mobs/Species/base.yml index 9652da27d4..4752e6a94c 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/base.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/base.yml @@ -234,6 +234,7 @@ - type: ExaminableClothes - type: CharacterInformation - type: Penetrated + - type: Mood - type: entity save: false diff --git a/Resources/Prototypes/Shaders/shaders.yml b/Resources/Prototypes/Shaders/shaders.yml index e286dcb7a4..f6f30fdd4e 100644 --- a/Resources/Prototypes/Shaders/shaders.yml +++ b/Resources/Prototypes/Shaders/shaders.yml @@ -99,3 +99,8 @@ id: Cataracts kind: source path: "/Textures/Shaders/cataracts.swsl" + +- type: shader + id: SaturationScale + kind: source + path: "/Textures/Shaders/White/saturationscale.swsl" diff --git a/Resources/Prototypes/White/Alerts/alerts.yml b/Resources/Prototypes/White/Alerts/alerts.yml new file mode 100644 index 0000000000..b04ec45e4f --- /dev/null +++ b/Resources/Prototypes/White/Alerts/alerts.yml @@ -0,0 +1,110 @@ +# Moods +- type: alert + id: Insane + category: Mood + onClick: !type:ShowMoodEffects { } + icons: + - sprite: /Textures/White/Interface/Alerts/mood.rsi + state: mood_insane + name: alerts-mood-insane-name + description: alerts-mood-insane-desc + +- type: alert + id: VeryVeryBad + category: Mood + onClick: !type:ShowMoodEffects { } + icons: + - sprite: /Textures/White/Interface/Alerts/mood.rsi + state: mood1 + name: alerts-mood-very-very-bad-name + description: alerts-mood-very-very-bad-desc + +- type: alert + id: VeryBad + category: Mood + onClick: !type:ShowMoodEffects { } + icons: + - sprite: /Textures/White/Interface/Alerts/mood.rsi + state: mood2 + name: alerts-mood-very-bad-name + description: alerts-mood-very-bad-desc + +- type: alert + id: Bad + category: Mood + onClick: !type:ShowMoodEffects { } + icons: + - sprite: /Textures/White/Interface/Alerts/mood.rsi + state: mood3 + name: alerts-mood-bad-name + description: alerts-mood-bad-desc + +- type: alert + id: NotGreat + category: Mood + onClick: !type:ShowMoodEffects { } + icons: + - sprite: /Textures/White/Interface/Alerts/mood.rsi + state: mood4 + name: alerts-mood-not-great-name + description: alerts-mood-not-great-desc + +- type: alert + id: Neutral + category: Mood + onClick: !type:ShowMoodEffects { } + icons: + - sprite: /Textures/White/Interface/Alerts/mood.rsi + state: mood5 + name: alerts-mood-neutral-name + description: alerts-mood-neutral-desc + +- type: alert + id: Great + category: Mood + onClick: !type:ShowMoodEffects { } + icons: + - sprite: /Textures/White/Interface/Alerts/mood.rsi + state: mood6 + name: alerts-mood-great-name + description: alerts-mood-great-desc + +- type: alert + id: Good + category: Mood + onClick: !type:ShowMoodEffects { } + icons: + - sprite: /Textures/White/Interface/Alerts/mood.rsi + state: mood7 + name: alerts-mood-good-name + description: alerts-mood-good-desc + +- type: alert + id: VeryGood + category: Mood + onClick: !type:ShowMoodEffects { } + icons: + - sprite: /Textures/White/Interface/Alerts/mood.rsi + state: mood8 + name: alerts-mood-very-good-name + description: alerts-mood-very-good-desc + +- type: alert + id: VeryVeryGood + category: Mood + onClick: !type:ShowMoodEffects { } + icons: + - sprite: /Textures/White/Interface/Alerts/mood.rsi + state: mood9 + name: alerts-mood-very-very-good-name + description: alerts-mood-very-very-good-desc + +- type: alert + id: MoodDead + category: Mood + onClick: !type:ShowMoodEffects { } + icons: + - sprite: /Textures/White/Interface/Alerts/mood.rsi + state: mood_happiness_bad + name: alerts-mood-dead-name + description: alerts-mood-dead-desc diff --git a/Resources/Prototypes/White/Mood/generic_negativeEffects.yml b/Resources/Prototypes/White/Mood/generic_negativeEffects.yml new file mode 100644 index 0000000000..7deab7f4f6 --- /dev/null +++ b/Resources/Prototypes/White/Mood/generic_negativeEffects.yml @@ -0,0 +1,51 @@ +- type: moodEffect + id: Handcuffed + desc: "Кажется мои выходки кто-то заметил." + moodChange: enum.MoodChangeLevel.Small + positiveEffect: false + +- type: moodEffect + id: Suffocating + desc: "НЕ.. МОГУ... ДЫШАТЬ..." + moodChange: enum.MoodChangeLevel.Medium + positiveEffect: false + timeout: 1 + +- type: moodEffect + id: OnFire + desc: "ГОРЮ!!!" + moodChange: enum.MoodChangeLevel.Big + positiveEffect: false + +- type: moodEffect + id: Creampied + desc: "Меня окремили. На вкус как пирог." + moodChange: enum.MoodChangeLevel.Small + positiveEffect: false + timeout: 3 + +- type: moodEffect + id: MobSlipped + desc: "Опять поскальзываюсь. Надо быть аккуратней." + moodChange: enum.MoodChangeLevel.Small + positiveEffect: false + timeout: 3 + +- type: moodEffect + id: MobVomit + desc: "Меня только что вырвало. Мерзость." + moodChange: enum.MoodChangeLevel.Small + positiveEffect: false + timeout: 8 + +- type: moodEffect + id: MobLowPressure + desc: "Меня сейчас разорвёт наружу!" + moodChange: enum.MoodChangeLevel.Medium + positiveEffect: false + +- type: moodEffect + id: MobHighPressure + desc: "На меня оказывается огромное давление!" + moodChange: enum.MoodChangeLevel.Medium + positiveEffect: false diff --git a/Resources/Prototypes/White/Mood/generic_positveEffects.yml b/Resources/Prototypes/White/Mood/generic_positveEffects.yml new file mode 100644 index 0000000000..71fd30dc0b --- /dev/null +++ b/Resources/Prototypes/White/Mood/generic_positveEffects.yml @@ -0,0 +1,52 @@ +- type: moodEffect + id: BeingHugged + desc: "Обнимашки - круто." + moodChange: enum.MoodChangeLevel.Small + positiveEffect: true + timeout: 2 + +- type: moodEffect + id: ArcadePlay + desc: "Я весело поиграл в интересную аркаду." + moodChange: enum.MoodChangeLevel.Small + positiveEffect: true + timeout: 8 + +- type: moodEffect + id: GotBlessed + desc: "Меня благословили." + moodChange: enum.MoodChangeLevel.Small + positiveEffect: true + timeout: 8 + +- type: moodEffect + id: PetAnimal + desc: "Животные такие милые! Не могу перестать их гладить!" + moodChange: enum.MoodChangeLevel.Small + positiveEffect: true + timeout: 5 + +- type: moodEffect + id: SavedLife + desc: "Так приятно спасать чью-то жизнь." + moodChange: enum.MoodChangeLevel.Medium + positiveEffect: true + timeout: 8 + +- type: moodEffect + id: TraitorFocused #Used for traitors to boost their goals completion. + desc: "У меня есть цель, и я добьюсь её, во что бы то ни стало!" + moodChange: enum.MoodChangeLevel.Medium + positiveEffect: true + +- type: moodEffect + id: RevolutionFocused #Used for revolution + desc: "СЛАВА РЕВОЛЮЦИИ!!!" + moodChange: enum.MoodChangeLevel.Medium + positiveEffect: true + +- type: moodEffect + id: CultFocused + desc: "Знаю правду, славим великого!" + moodChange: enum.MoodChangeLevel.Big + positiveEffect: true diff --git a/Resources/Prototypes/White/Mood/moodEffects_needs.yml b/Resources/Prototypes/White/Mood/moodEffects_needs.yml new file mode 100644 index 0000000000..03f52858c8 --- /dev/null +++ b/Resources/Prototypes/White/Mood/moodEffects_needs.yml @@ -0,0 +1,87 @@ +#Hunger +- type: moodEffect + id: HungerOverfed + desc: "Во мне столько жира..." + moodChange: enum.MoodChangeLevel.Small + positiveEffect: false + category: "Hunger" + +- type: moodEffect + id: HungerOkay + desc: "Мой желудок полон!" + moodChange: enum.MoodChangeLevel.Medium + positiveEffect: true + category: "Hunger" + +- type: moodEffect + id: HungerPeckish + desc: "Хочу есть." + moodChange: enum.MoodChangeLevel.Medium + positiveEffect: true + category: "Hunger" + +- type: moodEffect + id: HungerStarving + desc: "Голодаю!" + moodChange: enum.MoodChangeLevel.Big + positiveEffect: false + category: "Hunger" + +#Thirst +- type: moodEffect + id: ThirstOverHydrated + desc: "СЛИШКОМ МНОГО ВОДЫ..." + moodChange: enum.MoodChangeLevel.Small + positiveEffect: false + category: "Thirst" + +- type: moodEffect + id: ThirstOkay + desc: "Не хочу пить." + moodChange: enum.MoodChangeLevel.Medium + positiveEffect: true + category: "Thirst" + +- type: moodEffect + id: ThirstThirsty + desc: "Хочу пить." + moodChange: enum.MoodChangeLevel.Medium + positiveEffect: false + category: "Thirst" + +- type: moodEffect + id: ThirstParched + desc: "ВОДЫ!" + moodChange: enum.MoodChangeLevel.Big + positiveEffect: false + category: "Thirst" + +#Health +- type: moodEffect + id: HealthNoDamage + desc: "Чувствую себя лишённым боли." + moodChange: enum.MoodChangeLevel.None + positiveEffect: true + hidden: true + category: "Health" + +- type: moodEffect + id: HealthLightDamage + desc: "Мои ссадины жгутся." + moodChange: enum.MoodChangeLevel.Small + positiveEffect: false + category: "Health" + +- type: moodEffect + id: HealthSevereDamage + desc: "Сильная боль пронзает меня." + moodChange: enum.MoodChangeLevel.Medium + positiveEffect: false + category: "Health" + +- type: moodEffect + id: HealthHeavyDamage + desc: "Агония гложет мою душу!" + moodChange: enum.MoodChangeLevel.Large + positiveEffect: false + category: "Health" diff --git a/Resources/Textures/Shaders/White/saturationscale.swsl b/Resources/Textures/Shaders/White/saturationscale.swsl new file mode 100644 index 0000000000..9829e20762 --- /dev/null +++ b/Resources/Textures/Shaders/White/saturationscale.swsl @@ -0,0 +1,12 @@ +uniform highp float saturation; // Between 0 and 2; +uniform sampler2D SCREEN_TEXTURE; + +void fragment() { + highp vec4 color = texture(SCREEN_TEXTURE, UV); + + highp float brightness = (color.r + color.g + color.b) / 3.0; + + color.rgb = mix(vec3(brightness), color.rgb, saturation); + + COLOR = color; +} diff --git a/Resources/Textures/White/Interface/Alerts/mood.rsi/meta.json b/Resources/Textures/White/Interface/Alerts/mood.rsi/meta.json new file mode 100644 index 0000000000..c40ea9334e --- /dev/null +++ b/Resources/Textures/White/Interface/Alerts/mood.rsi/meta.json @@ -0,0 +1,60 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from NSV13 at b6b1e2bf2cc60455851317d8e82cca8716d9dac1", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "mood1" + }, + { + "name": "mood2" + }, + { + "name": "mood3" + }, + { + "name": "mood4" + }, + { + "name": "mood5" + }, + { + "name": "mood6" + }, + { + "name": "mood7" + }, + { + "name": "mood8" + }, + { + "name": "mood9" + }, + { + "name": "mood_insane", + "delays": [ + [ + 0.07, + 0.07, + 0.07, + 0.07, + 0.07, + 0.07, + 0.07, + 0.07, + 0.07 + ] + ] + }, + { + "name": "mood_happiness_good" + }, + { + "name": "mood_happiness_bad" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/White/Interface/Alerts/mood.rsi/mood1.png b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood1.png new file mode 100644 index 0000000000..ae1e1386db Binary files /dev/null and b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood1.png differ diff --git a/Resources/Textures/White/Interface/Alerts/mood.rsi/mood2.png b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood2.png new file mode 100644 index 0000000000..41be928f02 Binary files /dev/null and b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood2.png differ diff --git a/Resources/Textures/White/Interface/Alerts/mood.rsi/mood3.png b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood3.png new file mode 100644 index 0000000000..179991e198 Binary files /dev/null and b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood3.png differ diff --git a/Resources/Textures/White/Interface/Alerts/mood.rsi/mood4.png b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood4.png new file mode 100644 index 0000000000..4ea7d70117 Binary files /dev/null and b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood4.png differ diff --git a/Resources/Textures/White/Interface/Alerts/mood.rsi/mood5.png b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood5.png new file mode 100644 index 0000000000..c4c3370f62 Binary files /dev/null and b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood5.png differ diff --git a/Resources/Textures/White/Interface/Alerts/mood.rsi/mood6.png b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood6.png new file mode 100644 index 0000000000..388483e143 Binary files /dev/null and b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood6.png differ diff --git a/Resources/Textures/White/Interface/Alerts/mood.rsi/mood7.png b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood7.png new file mode 100644 index 0000000000..b4f944d045 Binary files /dev/null and b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood7.png differ diff --git a/Resources/Textures/White/Interface/Alerts/mood.rsi/mood8.png b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood8.png new file mode 100644 index 0000000000..f12f71b7ff Binary files /dev/null and b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood8.png differ diff --git a/Resources/Textures/White/Interface/Alerts/mood.rsi/mood9.png b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood9.png new file mode 100644 index 0000000000..e65c650149 Binary files /dev/null and b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood9.png differ diff --git a/Resources/Textures/White/Interface/Alerts/mood.rsi/mood_happiness_bad.png b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood_happiness_bad.png new file mode 100644 index 0000000000..4ed8f4d68f Binary files /dev/null and b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood_happiness_bad.png differ diff --git a/Resources/Textures/White/Interface/Alerts/mood.rsi/mood_happiness_good.png b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood_happiness_good.png new file mode 100644 index 0000000000..eb9943a301 Binary files /dev/null and b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood_happiness_good.png differ diff --git a/Resources/Textures/White/Interface/Alerts/mood.rsi/mood_insane.png b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood_insane.png new file mode 100644 index 0000000000..b2407bbdad Binary files /dev/null and b/Resources/Textures/White/Interface/Alerts/mood.rsi/mood_insane.png differ