From 6099c110c971b02a0612aed766f264aea170acb5 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Fri, 3 May 2024 13:16:25 -0400 Subject: [PATCH 01/82] guh --- .../Abilities/Dispel/DispelPowerComponent.cs | 5 ++- .../MassSleep/MassSleepPowerComponent.cs | 3 ++ .../Metapsionics/MetapsionicPowerComponent.cs | 30 ++++++++++++---- .../MindSwap/MindSwapPowerComponent.cs | 3 ++ .../NoosphericZapPowerComponent.cs | 3 ++ .../PsionicInvisibilityPowerComponent.cs | 6 ++++ .../PsionicRegenerationPowerComponent.cs | 6 ++++ .../Pyrokinesis/PyrokinesisPowerComponent.cs | 3 ++ .../Telegnosis/TelegnosisPowerComponent.cs | 5 ++- .../Abilities/Psionics/PsionicComponent.cs | 12 +++++-- .../Events/MetapsionicPowerActionEvent.cs | 3 +- Content.Shared/Nyanotrasen/Psionics/Events.cs | 36 +++++++++++++++++++ 12 files changed, 104 insertions(+), 11 deletions(-) diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DispelPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DispelPowerComponent.cs index cd887866364..837bdd96a87 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DispelPowerComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DispelPowerComponent.cs @@ -9,12 +9,15 @@ public sealed partial class DispelPowerComponent : Component { [DataField("range")] public float Range = 10f; - + [DataField("dispelActionId", customTypeSerializer: typeof(PrototypeIdSerializer))] public string? DispelActionId = "ActionDispel"; [DataField("dispelActionEntity")] public EntityUid? DispelActionEntity; + + [DataField("dispelFeedback")] + public string DispelFeedback = "dispel-feedback"; } } diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs index 7d611c63dac..c092cacd8b8 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs @@ -14,5 +14,8 @@ public sealed partial class MassSleepPowerComponent : Component [DataField("massSleepActionEntity")] public EntityUid? MassSleepActionEntity; + + [DataField("massSleepFeedback")] + public string MassSleepFeedback = "mass-sleep-feedback"; } } diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs index c9d0130221a..0e12d05dead 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs @@ -1,4 +1,6 @@ using Content.Shared.Actions; +using Content.Shared.DoAfter; +using Robust.Shared.Audio; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; @@ -7,15 +9,31 @@ namespace Content.Shared.Abilities.Psionics [RegisterComponent] public sealed partial class MetapsionicPowerComponent : Component { + [DataField("doAfter")] + public DoAfterId? DoAfter; + + [DataField("useDelay")] + public float UseDelay = 8f; + [DataField("soundUse")] + + public SoundSpecifier SoundUse = new SoundPathSpecifier("/Audio/Nyanotrasen/heartbeat_fast.ogg"); + [DataField("range")] public float Range = 5f; - public InstantActionComponent? MetapsionicPowerAction = null; - [DataField("metapsionicActionId", - customTypeSerializer: typeof(PrototypeIdSerializer))] - public string? MetapsionicActionId = "ActionMetapsionic"; + [DataField("actionWideMetapsionic", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string ActionWideMetapsionic = "ActionWideMetapsionic"; + + [DataField("actionWideMetapsionicEntity")] + public EntityUid? ActionWideMetapsionicEntity; + + [DataField("actionFocusedMetapsionic", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string ActionFocusedMetapsionic = "ActionFocusedMetapsionic"; + + [DataField("actionFocusedMetapsionicEntity")] + public EntityUid? ActionFocusedMetapsionicEntity; - [DataField("metapsionicActionEntity")] - public EntityUid? MetapsionicActionEntity; + [DataField("metapsionicFeedback")] + public string MetapsionicFeedback = "metapsionic-feedback"; } } diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs index 6a3fc811c89..e617c48cf2d 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs @@ -12,5 +12,8 @@ public sealed partial class MindSwapPowerComponent : Component [DataField("mindSwapActionEntity")] public EntityUid? MindSwapActionEntity; + + [DataField("mindSwapFeedback")] + public string MindSwapFeedback = "mind-swap-feedback"; } } diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs index 0e91894b1dc..24c144079e4 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs @@ -13,5 +13,8 @@ public sealed partial class NoosphericZapPowerComponent : Component [DataField("noosphericZapActionEntity")] public EntityUid? NoosphericZapActionEntity; + + [DataField("noosphericZapFeedback")] + public string NoosphericZapFeedback = "noospheric-zap-feedback"; } } diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs index 3e198aa9303..3b29a1e4367 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs @@ -12,5 +12,11 @@ public sealed partial class PsionicInvisibilityPowerComponent : Component [DataField("psionicInvisibilityActionEntity")] public EntityUid? PsionicInvisibilityActionEntity; + + [DataField("InvisibilityFeedback")] + public string InvisibilityFeedback = "invisibility-feedback"; + + [DataField("UseTimer")] + public float UseTimer = 30f; } } diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs index 4a62e84d191..2f86615b836 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs @@ -26,6 +26,12 @@ public sealed partial class PsionicRegenerationPowerComponent : Component [DataField("psionicRegenerationActionEntity")] public EntityUid? PsionicRegenerationActionEntity; + + [DataField("regenerationFeedback")] + public string RegenerationFeedback = "regeneration-feedback"; + + [DataField("selfRevive")] + public bool SelfRevive { get; set; } = false; } } diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs index 28425afdb4c..d2af000e269 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs @@ -14,5 +14,8 @@ public sealed partial class PyrokinesisPowerComponent : Component [DataField("pyrokinesisActionEntity")] public EntityUid? PyrokinesisActionEntity; + + [DataField("pyrokinesisFeedback")] + public string PyrokinesisFeedback = "pyrokinesis-feedback"; } } diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs index 51958822a41..cd298c3ec0f 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs @@ -19,5 +19,8 @@ public sealed partial class TelegnosisPowerComponent : Component [DataField("telegnosisActionEntity")] public EntityUid? TelegnosisActionEntity; + + [DataField("telegnosisFeedback")] + public string TelegnosisFeedback = "telegnosis-feedback"; } -} \ No newline at end of file +} diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicComponent.cs index 9091e03cfc3..7c7befa33c3 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicComponent.cs @@ -1,4 +1,3 @@ -using Content.Shared.Actions; using Robust.Shared.GameStates; namespace Content.Shared.Abilities.Psionics @@ -15,6 +14,15 @@ public sealed partial class PsionicComponent : Component public bool Removable = true; [DataField("activePowers")] - public HashSet ActivePowers = new(); + public List ActivePowers = new(); + + [DataField("psychicFeedback")] + public List PsychicFeedback= new(); + + [DataField("amplification")] + public float Amplification = 1f; + + [DataField("dampening")] + public float Dampening = 1f; } } diff --git a/Content.Shared/Nyanotrasen/Actions/Events/MetapsionicPowerActionEvent.cs b/Content.Shared/Nyanotrasen/Actions/Events/MetapsionicPowerActionEvent.cs index b28801efe74..b7c3c8ad2d6 100644 --- a/Content.Shared/Nyanotrasen/Actions/Events/MetapsionicPowerActionEvent.cs +++ b/Content.Shared/Nyanotrasen/Actions/Events/MetapsionicPowerActionEvent.cs @@ -1,2 +1,3 @@ namespace Content.Shared.Actions.Events; -public sealed partial class MetapsionicPowerActionEvent : InstantActionEvent {} +public sealed partial class WideMetapsionicPowerActionEvent : InstantActionEvent { } +public sealed partial class FocusedMetapsionicPowerActionEvent : EntityTargetActionEvent { } diff --git a/Content.Shared/Nyanotrasen/Psionics/Events.cs b/Content.Shared/Nyanotrasen/Psionics/Events.cs index cf9a50c6e18..45a00b5f048 100644 --- a/Content.Shared/Nyanotrasen/Psionics/Events.cs +++ b/Content.Shared/Nyanotrasen/Psionics/Events.cs @@ -21,6 +21,42 @@ public PsionicRegenerationDoAfterEvent(TimeSpan startedAt) public override DoAfterEvent Clone() => this; } + [Serializable, NetSerializable] + public sealed partial class PsionicInvisibilityTimerEvent : DoAfterEvent + { + [DataField("startedAt", required: true)] + public TimeSpan StartedAt; + + private PsionicInvisibilityTimerEvent() + { + } + + public PsionicInvisibilityTimerEvent(TimeSpan startedAt) + { + StartedAt = startedAt; + } + + public override DoAfterEvent Clone() => this; + } + + [Serializable, NetSerializable] + public sealed partial class FocusedMetapsionicDoAfterEvent : DoAfterEvent + { + [DataField("startedAt", required: true)] + public TimeSpan StartedAt; + + private FocusedMetapsionicDoAfterEvent() + { + } + + public FocusedMetapsionicDoAfterEvent(TimeSpan startedAt) + { + StartedAt = startedAt; + } + + public override DoAfterEvent Clone() => this; + } + [Serializable, NetSerializable] public sealed partial class GlimmerWispDrainDoAfterEvent : SimpleDoAfterEvent { From 89d58eda58cc7395d7cf8b838758e57165d57dd8 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Fri, 3 May 2024 13:59:49 -0400 Subject: [PATCH 02/82] Psionic Refactor pt 1 --- .../Psionics/Abilities/DispelPowerSystem.cs | 41 ++++---- .../Abilities/MetapsionicPowerSystem.cs | 33 +++---- .../Psionics/Abilities/MindSwapPowerSystem.cs | 93 +++++++++---------- .../Abilities/MindSwappedComponent.cs | 11 +-- .../Abilities/NoosphericZapPowerSystem.cs | 30 +++--- .../PsionicInvisibilityPowerSystem.cs | 56 ++++++----- .../PsionicRegenerationPowerSystem.cs | 36 +++---- .../Abilities/PyrokinesisPowerSystem.cs | 33 ++++--- .../Abilities/TelegnosisPowerSystem.cs | 32 +++---- .../Psionics/PsionicAbilitiesSystem.cs | 18 +--- .../Invisibility/PsionicInvisibilitySystem.cs | 20 ++-- .../Nyanotrasen/Psionics/PsionicsSystem.cs | 8 +- .../Prototypes/Nyanotrasen/Actions/types.yml | 22 ++++- 13 files changed, 195 insertions(+), 238 deletions(-) diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/DispelPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/DispelPowerSystem.cs index d338a5a5bcb..f7d88f4cb83 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/DispelPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/DispelPowerSystem.cs @@ -1,4 +1,5 @@ using Content.Shared.Actions; +using Content.Shared.Actions.ActionTypes; using Content.Shared.StatusEffect; using Content.Shared.Abilities.Psionics; using Content.Shared.Damage; @@ -10,9 +11,6 @@ using Robust.Shared.Player; using Robust.Shared.Random; using Robust.Shared.Timing; -using Content.Shared.Mind; -using Content.Shared.Actions.Events; -using Robust.Shared.Audio.Systems; namespace Content.Server.Abilities.Psionics { @@ -28,7 +26,6 @@ public sealed class DispelPowerSystem : EntitySystem [Dependency] private readonly SharedAudioSystem _audioSystem = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly SharedMindSystem _mindSystem = default!; public override void Initialize() @@ -48,25 +45,22 @@ public override void Initialize() private void OnInit(EntityUid uid, DispelPowerComponent component, ComponentInit args) { - _actions.AddAction(uid, ref component.DispelActionEntity, component.DispelActionId ); - _actions.TryGetActionData( component.DispelActionEntity, out var actionData ); - if (actionData is { UseDelay: not null }) - _actions.StartUseDelay(component.DispelActionEntity); + if (!_prototypeManager.TryIndex("Dispel", out var action)) + return; + + component.DispelPowerAction = new EntityTargetAction(action); + if (action.UseDelay != null) + component.DispelPowerAction.Cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + (TimeSpan) action.UseDelay); + _actions.AddAction(uid, component.DispelPowerAction, null); + if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - { - psionic.PsionicAbility = component.DispelActionEntity; - psionic.ActivePowers.Add(component); - } + psionic.PsionicAbility = component.DispelPowerAction; } private void OnShutdown(EntityUid uid, DispelPowerComponent component, ComponentShutdown args) { - _actions.RemoveAction(uid, component.DispelActionEntity); - - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Remove(component); - } + if (_prototypeManager.TryIndex("Dispel", out var action)) + _actions.RemoveAction(uid, new EntityTargetAction(action), null); } private void OnPowerUsed(DispelPowerActionEvent args) @@ -89,7 +83,7 @@ private void OnDispelled(EntityUid uid, DispellableComponent component, Dispelle QueueDel(uid); Spawn("Ash", Transform(uid).Coordinates); _popupSystem.PopupCoordinates(Loc.GetString("psionic-burns-up", ("item", uid)), Transform(uid).Coordinates, Filter.Pvs(uid), true, Shared.Popups.PopupType.MediumCaution); - _audioSystem.PlayEntity("/Audio/Effects/lightburn.ogg", Filter.Pvs(uid), uid, true); + _audioSystem.Play("/Audio/Effects/lightburn.ogg", Filter.Pvs(uid), uid, true); args.Handled = true; } @@ -106,7 +100,7 @@ private void OnDmgDispelled(EntityUid uid, DamageOnDispelComponent component, Di private void OnGuardianDispelled(EntityUid uid, GuardianComponent guardian, DispelledEvent args) { if (TryComp(guardian.Host, out var host)) - _guardianSystem.ToggleGuardian(guardian.Host.Value, host); + _guardianSystem.ToggleGuardian(guardian.Host, host); DealDispelDamage(uid); args.Handled = true; @@ -133,7 +127,7 @@ public void DealDispelDamage(EntityUid uid, DamageSpecifier? damage = null) return; _popupSystem.PopupCoordinates(Loc.GetString("psionic-burn-resist", ("item", uid)), Transform(uid).Coordinates, Filter.Pvs(uid), true, Shared.Popups.PopupType.SmallCaution); - _audioSystem.PlayEntity("/Audio/Effects/lightburn.ogg", Filter.Pvs(uid), uid, true); + _audioSystem.Play("/Audio/Effects/lightburn.ogg", Filter.Pvs(uid), uid, true); if (damage == null) { @@ -143,7 +137,8 @@ public void DealDispelDamage(EntityUid uid, DamageSpecifier? damage = null) _damageableSystem.TryChangeDamage(uid, damage, true, true); } } - public sealed class DispelledEvent : HandledEntityEventArgs {} -} + public sealed class DispelPowerActionEvent : EntityTargetActionEvent {} + public sealed class DispelledEvent : HandledEntityEventArgs {} +} diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs index b775117b716..ee3c9a58d9c 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs @@ -1,11 +1,11 @@ using Content.Shared.Actions; +using Content.Shared.Actions.ActionTypes; using Content.Shared.Abilities.Psionics; using Content.Shared.StatusEffect; using Content.Shared.Popups; using Robust.Shared.Prototypes; +using Robust.Shared.Player; using Robust.Shared.Timing; -using Content.Shared.Mind; -using Content.Shared.Actions.Events; namespace Content.Server.Abilities.Psionics { @@ -18,7 +18,6 @@ public sealed class MetapsionicPowerSystem : EntitySystem [Dependency] private readonly SharedPopupSystem _popups = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly SharedMindSystem _mindSystem = default!; public override void Initialize() @@ -31,26 +30,22 @@ public override void Initialize() private void OnInit(EntityUid uid, MetapsionicPowerComponent component, ComponentInit args) { - _actions.AddAction(uid, ref component.MetapsionicActionEntity, component.MetapsionicActionId ); - _actions.TryGetActionData( component.MetapsionicActionEntity, out var actionData ); - if (actionData is { UseDelay: not null }) - _actions.StartUseDelay(component.MetapsionicActionEntity); - if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - { - psionic.PsionicAbility = component.MetapsionicActionEntity; - psionic.ActivePowers.Add(component); - } + if (!_prototypeManager.TryIndex("MetapsionicPulse", out var metapsionicPulse)) + return; + component.MetapsionicPowerAction = new InstantAction(metapsionicPulse); + if (metapsionicPulse.UseDelay != null) + component.MetapsionicPowerAction.Cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + (TimeSpan) metapsionicPulse.UseDelay); + _actions.AddAction(uid, component.MetapsionicPowerAction, null); + + if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) + psionic.PsionicAbility = component.MetapsionicPowerAction; } private void OnShutdown(EntityUid uid, MetapsionicPowerComponent component, ComponentShutdown args) { - _actions.RemoveAction(uid, component.MetapsionicActionEntity); - - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Remove(component); - } + if (_prototypeManager.TryIndex("MetapsionicPulse", out var metapsionicPulse)) + _actions.RemoveAction(uid, new InstantAction(metapsionicPulse), null); } private void OnPowerUsed(EntityUid uid, MetapsionicPowerComponent component, MetapsionicPowerActionEvent args) @@ -71,4 +66,6 @@ private void OnPowerUsed(EntityUid uid, MetapsionicPowerComponent component, Met args.Handled = true; } } + + public sealed class MetapsionicPowerActionEvent : InstantActionEvent {} } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwapPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwapPowerSystem.cs index b23224cab48..5c83de2b526 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwapPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwapPowerSystem.cs @@ -1,4 +1,5 @@ using Content.Shared.Actions; +using Content.Shared.Actions.ActionTypes; using Content.Shared.Abilities.Psionics; using Content.Shared.Speech; using Content.Shared.Stealth.Components; @@ -6,14 +7,13 @@ using Content.Shared.Mobs; using Content.Shared.Damage; using Content.Server.Mind; +using Content.Server.Mind.Components; using Content.Shared.Mobs.Systems; using Content.Server.Popups; using Content.Server.Psionics; using Content.Server.GameTicking; using Robust.Shared.Prototypes; using Robust.Shared.Timing; -using Content.Shared.Mind; -using Content.Shared.Actions.Events; namespace Content.Server.Abilities.Psionics { @@ -26,7 +26,6 @@ public sealed class MindSwapPowerSystem : EntitySystem [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly MindSystem _mindSystem = default!; - [Dependency] private readonly MetaDataSystem _metaDataSystem = default!; public override void Initialize() { @@ -44,24 +43,22 @@ public override void Initialize() private void OnInit(EntityUid uid, MindSwapPowerComponent component, ComponentInit args) { - _actions.AddAction(uid, ref component.MindSwapActionEntity, component.MindSwapActionId ); - _actions.TryGetActionData( component.MindSwapActionEntity, out var actionData ); - if (actionData is { UseDelay: not null }) - _actions.StartUseDelay(component.MindSwapActionEntity); + if (!_prototypeManager.TryIndex("MindSwap", out var mindSwap)) + return; + + component.MindSwapPowerAction = new EntityTargetAction(mindSwap); + if (mindSwap.UseDelay != null) + component.MindSwapPowerAction.Cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + (TimeSpan) mindSwap.UseDelay); + _actions.AddAction(uid, component.MindSwapPowerAction, null); + if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - { - psionic.PsionicAbility = component.MindSwapActionEntity; - psionic.ActivePowers.Add(component); - } + psionic.PsionicAbility = component.MindSwapPowerAction; } private void OnShutdown(EntityUid uid, MindSwapPowerComponent component, ComponentShutdown args) { - _actions.RemoveAction(uid, component.MindSwapActionEntity); - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Remove(component); - } + if (_prototypeManager.TryIndex("MindSwap", out var action)) + _actions.RemoveAction(uid, new EntityTargetAction(action), null); } private void OnPowerUsed(MindSwapPowerActionEvent args) @@ -137,9 +134,8 @@ private void OnGhostAttempt(GhostAttemptHandleEvent args) if (!HasComp(args.Mind.CurrentEntity)) return; - //No idea where the viaCommand went. It's on the internal OnGhostAttempt, but not this layer. Maybe unnecessary. - /*if (!args.viaCommand) - return;*/ + if (!args.ViaCommand) + return; args.Result = false; args.Handled = true; @@ -147,12 +143,12 @@ private void OnGhostAttempt(GhostAttemptHandleEvent args) private void OnSwapInit(EntityUid uid, MindSwappedComponent component, ComponentInit args) { - _actions.AddAction(uid, ref component.MindSwapReturnActionEntity, component.MindSwapReturnActionId ); - _actions.TryGetActionData( component.MindSwapReturnActionEntity, out var actionData ); - if (actionData is { UseDelay: not null }) - _actions.StartUseDelay(component.MindSwapReturnActionEntity); - if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - psionic.PsionicAbility = component.MindSwapReturnActionEntity; + if (_prototypeManager.TryIndex("MindSwapReturn", out var mindSwap)) + { + var action = new InstantAction(mindSwap); + action.Cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + TimeSpan.FromSeconds(15)); + _actions.AddAction(uid, action, null); + } } public void Swap(EntityUid performer, EntityUid target, bool end = false) @@ -161,35 +157,30 @@ public void Swap(EntityUid performer, EntityUid target, bool end = false) return; // Get the minds first. On transfer, they'll be gone. - MindComponent? performerMind = null; - MindComponent? targetMind = null; + Mind.Mind? performerMind = null; + Mind.Mind? targetMind = null; // This is here to prevent missing MindContainerComponent Resolve errors. - if(!_mindSystem.TryGetMind(performer, out var performerMindId, out performerMind)){ - performerMind = null; - }; - - if(!_mindSystem.TryGetMind(target, out var targetMindId, out targetMind)){ - targetMind = null; - }; - //This is a terrible way to 'unattach' minds. I wanted to use UnVisit but in TransferTo's code they say - //To unnatch the minds, do it like this. - //Have to unnattach the minds before we reattach them via transfer. Still feels weird, but seems to work well. - _mindSystem.TransferTo(performerMindId, null); - _mindSystem.TransferTo(targetMindId, null); + if (TryComp(performer, out var performerMindContainer)) + performerMind = _mindSystem.GetMind(performer, performerMindContainer); + + if (TryComp(target, out var targetMindContainer)) + targetMind = _mindSystem.GetMind(target, targetMindContainer); + // Do the transfer. if (performerMind != null) - _mindSystem.TransferTo(performerMindId, target, ghostCheckOverride: true, false, performerMind); + _mindSystem.TransferTo(performerMind, target, ghostCheckOverride: true); if (targetMind != null) - _mindSystem.TransferTo(targetMindId, performer, ghostCheckOverride: true, false, targetMind); + _mindSystem.TransferTo(targetMind, performer, ghostCheckOverride: true); if (end) { - var performerMindPowerComp = EntityManager.GetComponent(performer); - var targetMindPowerComp = EntityManager.GetComponent(target); - _actions.RemoveAction(performer, performerMindPowerComp.MindSwapReturnActionEntity); - _actions.RemoveAction(target, targetMindPowerComp.MindSwapReturnActionEntity); + if (_prototypeManager.TryIndex("MindSwapReturn", out var mindSwap)) + { + _actions.RemoveAction(performer, new InstantAction(mindSwap), null); + _actions.RemoveAction(target, new InstantAction(mindSwap), null); + } RemComp(performer); RemComp(target); @@ -205,10 +196,11 @@ public void Swap(EntityUid performer, EntityUid target, bool end = false) public void GetTrapped(EntityUid uid) { + if (!_prototypeManager.TryIndex("MindSwapReturn", out var action)) + return; _popupSystem.PopupEntity(Loc.GetString("mindswap-trapped"), uid, uid, Shared.Popups.PopupType.LargeCaution); - var perfComp = EnsureComp(uid); - _actions.RemoveAction(uid, perfComp.MindSwapReturnActionEntity, null); + _actions.RemoveAction(uid, action); if (HasComp(uid)) { @@ -216,9 +208,12 @@ public void GetTrapped(EntityUid uid) RemComp(uid); EnsureComp(uid); EnsureComp(uid); - _metaDataSystem.SetEntityName(uid, Loc.GetString("telegnostic-trapped-entity-name")); - _metaDataSystem.SetEntityDescription(uid, Loc.GetString("telegnostic-trapped-entity-desc")); + MetaData(uid).EntityName = Loc.GetString("telegnostic-trapped-entity-name"); + MetaData(uid).EntityDescription = Loc.GetString("telegnostic-trapped-entity-desc"); } } } + + public sealed class MindSwapPowerActionEvent : EntityTargetActionEvent {} + public sealed class MindSwapPowerReturnActionEvent : InstantActionEvent {} } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwappedComponent.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwappedComponent.cs index 72cd6a66ef9..84d2909c1f2 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwappedComponent.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwappedComponent.cs @@ -1,18 +1,9 @@ -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - namespace Content.Server.Abilities.Psionics { [RegisterComponent] - public sealed partial class MindSwappedComponent : Component + public sealed class MindSwappedComponent : Component { [ViewVariables] public EntityUid OriginalEntity = default!; - [DataField("mindSwapReturnActionId", - customTypeSerializer: typeof(PrototypeIdSerializer))] - public string? MindSwapReturnActionId = "ActionMindSwapReturn"; - - [DataField("mindSwapReturnActionEntity")] - public EntityUid? MindSwapReturnActionEntity; } } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs index 0fd261ef12f..c844030f1e1 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs @@ -1,4 +1,5 @@ using Content.Shared.Actions; +using Content.Shared.Actions.ActionTypes; using Content.Shared.Abilities.Psionics; using Content.Server.Psionics; using Content.Shared.StatusEffect; @@ -6,8 +7,6 @@ using Content.Server.Beam; using Robust.Shared.Prototypes; using Robust.Shared.Timing; -using Content.Server.Mind; -using Content.Shared.Actions.Events; namespace Content.Server.Abilities.Psionics { @@ -20,7 +19,6 @@ public sealed class NoosphericZapPowerSystem : EntitySystem [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly BeamSystem _beam = default!; - [Dependency] private readonly MindSystem _mindSystem = default!; public override void Initialize() @@ -33,24 +31,22 @@ public override void Initialize() private void OnInit(EntityUid uid, NoosphericZapPowerComponent component, ComponentInit args) { - _actions.AddAction(uid, ref component.NoosphericZapActionEntity, component.NoosphericZapActionId ); - _actions.TryGetActionData( component.NoosphericZapActionEntity, out var actionData ); - if (actionData is { UseDelay: not null }) - _actions.StartUseDelay(component.NoosphericZapActionEntity); + if (!_prototypeManager.TryIndex("NoosphericZap", out var noosphericZap)) + return; + + component.NoosphericZapPowerAction = new EntityTargetAction(noosphericZap); + if (noosphericZap.UseDelay != null) + component.NoosphericZapPowerAction.Cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + (TimeSpan) noosphericZap.UseDelay); + _actions.AddAction(uid, component.NoosphericZapPowerAction, null); + if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - { - psionic.PsionicAbility = component.NoosphericZapActionEntity; - psionic.ActivePowers.Add(component); - } + psionic.PsionicAbility = component.NoosphericZapPowerAction; } private void OnShutdown(EntityUid uid, NoosphericZapPowerComponent component, ComponentShutdown args) { - _actions.RemoveAction(uid, component.NoosphericZapActionEntity); - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Remove(component); - } + if (_prototypeManager.TryIndex("NoosphericZap", out var noosphericZap)) + _actions.RemoveAction(uid, new EntityTargetAction(noosphericZap), null); } private void OnPowerUsed(NoosphericZapPowerActionEvent args) @@ -70,4 +66,6 @@ private void OnPowerUsed(NoosphericZapPowerActionEvent args) args.Handled = true; } } + + public sealed class NoosphericZapPowerActionEvent : EntityTargetActionEvent {} } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs index 5ca1dc7a6dc..3bbaf9d8136 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs @@ -1,4 +1,5 @@ using Content.Shared.Actions; +using Content.Shared.Actions.ActionTypes; using Content.Shared.CombatMode.Pacification; using Content.Shared.Abilities.Psionics; using Content.Shared.Damage; @@ -10,9 +11,6 @@ using Robust.Shared.Player; using Robust.Shared.Audio; using Robust.Shared.Timing; -using Content.Server.Mind; -using Content.Shared.Actions.Events; -using Robust.Shared.Audio.Systems; namespace Content.Server.Abilities.Psionics { @@ -24,8 +22,6 @@ public sealed class PsionicInvisibilityPowerSystem : EntitySystem [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly SharedStealthSystem _stealth = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly MindSystem _mindSystem = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; public override void Initialize() { @@ -33,7 +29,7 @@ public override void Initialize() SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent(OnPowerUsed); - SubscribeLocalEvent(OnPowerOff); + SubscribeLocalEvent(OnPowerOff); SubscribeLocalEvent(OnStart); SubscribeLocalEvent(OnEnd); SubscribeLocalEvent(OnDamageChanged); @@ -41,24 +37,22 @@ public override void Initialize() private void OnInit(EntityUid uid, PsionicInvisibilityPowerComponent component, ComponentInit args) { - _actions.AddAction(uid, ref component.PsionicInvisibilityActionEntity, component.PsionicInvisibilityActionId ); - _actions.TryGetActionData( component.PsionicInvisibilityActionEntity, out var actionData ); - if (actionData is { UseDelay: not null }) - _actions.StartUseDelay(component.PsionicInvisibilityActionEntity); + if (!_prototypeManager.TryIndex("PsionicInvisibility", out var invis)) + return; + + component.PsionicInvisibilityPowerAction = new InstantAction(invis); + if (invis.UseDelay != null) + component.PsionicInvisibilityPowerAction.Cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + (TimeSpan) invis.UseDelay); + _actions.AddAction(uid, component.PsionicInvisibilityPowerAction, null); + if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - { - psionic.PsionicAbility = component.PsionicInvisibilityActionEntity; - psionic.ActivePowers.Add(component); - } + psionic.PsionicAbility = component.PsionicInvisibilityPowerAction; } private void OnShutdown(EntityUid uid, PsionicInvisibilityPowerComponent component, ComponentShutdown args) { - _actions.RemoveAction(uid, component.PsionicInvisibilityActionEntity); - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Remove(component); - } + if (_prototypeManager.TryIndex("PsionicInvisibility", out var invis)) + _actions.RemoveAction(uid, new InstantAction(invis), null); } private void OnPowerUsed(EntityUid uid, PsionicInvisibilityPowerComponent component, PsionicInvisibilityPowerActionEvent args) @@ -67,17 +61,15 @@ private void OnPowerUsed(EntityUid uid, PsionicInvisibilityPowerComponent compon return; ToggleInvisibility(args.Performer); - var action = Spawn(PsionicInvisibilityUsedComponent.PsionicInvisibilityUsedActionPrototype); - _actions.AddAction(uid, action, action); - _actions.TryGetActionData( action, out var actionData ); - if (actionData is { UseDelay: not null }) - _actions.StartUseDelay(action); + + if (_prototypeManager.TryIndex("PsionicInvisibilityOff", out var invis)) + _actions.AddAction(args.Performer, new InstantAction(invis), null); _psionics.LogPowerUsed(uid, "psionic invisibility"); args.Handled = true; } - private void OnPowerOff(RemovePsionicInvisibilityOffPowerActionEvent args) + private void OnPowerOff(PsionicInvisibilityPowerOffActionEvent args) { if (!HasComp(args.Performer)) return; @@ -92,7 +84,7 @@ private void OnStart(EntityUid uid, PsionicInvisibilityUsedComponent component, EnsureComp(uid); var stealth = EnsureComp(uid); _stealth.SetVisibility(uid, 0.66f, stealth); - _audio.PlayPvs("/Audio/Effects/toss.ogg", uid); + SoundSystem.Play("/Audio/Effects/toss.ogg", Filter.Pvs(uid), uid); } @@ -104,12 +96,13 @@ private void OnEnd(EntityUid uid, PsionicInvisibilityUsedComponent component, Co RemComp(uid); RemComp(uid); RemComp(uid); - _audio.PlayPvs("/Audio/Effects/toss.ogg", uid); - //Pretty sure this DOESN'T work as intended. - _actions.RemoveAction(uid, component.PsionicInvisibilityUsedActionEntity); + SoundSystem.Play("/Audio/Effects/toss.ogg", Filter.Pvs(uid), uid); + + if (_prototypeManager.TryIndex("PsionicInvisibilityOff", out var invis)) + _actions.RemoveAction(uid, new InstantAction(invis), null); _stunSystem.TryParalyze(uid, TimeSpan.FromSeconds(8), false); - DirtyEntity(uid); + Dirty(uid); } private void OnDamageChanged(EntityUid uid, PsionicInvisibilityUsedComponent component, DamageChangedEvent args) @@ -131,4 +124,7 @@ public void ToggleInvisibility(EntityUid uid) } } } + + public sealed class PsionicInvisibilityPowerActionEvent : InstantActionEvent {} + public sealed class PsionicInvisibilityPowerOffActionEvent : InstantActionEvent {} } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs index 2eca3173b6d..985f45b1f6c 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs @@ -4,10 +4,10 @@ using Robust.Shared.Prototypes; using Content.Server.Body.Components; using Content.Server.Body.Systems; -using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Chemistry.EntitySystems; using Content.Server.DoAfter; using Content.Shared.Abilities.Psionics; +using Content.Shared.Actions.ActionTypes; using Content.Shared.Actions; using Content.Shared.Chemistry.Components; using Content.Shared.DoAfter; @@ -18,10 +18,6 @@ using Content.Shared.Examine; using static Content.Shared.Examine.ExamineSystemShared; using Robust.Shared.Timing; -using Content.Server.Mind; -using Content.Shared.Actions.Events; -using Content.Shared.Chemistry.EntitySystems; -using Robust.Server.Audio; namespace Content.Server.Abilities.Psionics { @@ -37,7 +33,6 @@ public sealed class PsionicRegenerationPowerSystem : EntitySystem [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly MindSystem _mindSystem = default!; public override void Initialize() @@ -53,21 +48,22 @@ public override void Initialize() private void OnInit(EntityUid uid, PsionicRegenerationPowerComponent component, ComponentInit args) { - _actions.AddAction(uid, ref component.PsionicRegenerationActionEntity, component.PsionicRegenerationActionId ); - _actions.TryGetActionData( component.PsionicRegenerationActionEntity, out var actionData ); - if (actionData is { UseDelay: not null }) - _actions.StartUseDelay(component.PsionicRegenerationActionEntity); + if (!_prototypeManager.TryIndex("PsionicRegeneration", out var metapsionic)) + return; + + component.PsionicRegenerationPowerAction = new InstantAction(metapsionic); + if (metapsionic.UseDelay != null) + component.PsionicRegenerationPowerAction.Cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + (TimeSpan) metapsionic.UseDelay); + _actions.AddAction(uid, component.PsionicRegenerationPowerAction, null); + if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - { - psionic.PsionicAbility = component.PsionicRegenerationActionEntity; - psionic.ActivePowers.Add(component); - } + psionic.PsionicAbility = component.PsionicRegenerationPowerAction; } private void OnPowerUsed(EntityUid uid, PsionicRegenerationPowerComponent component, PsionicRegenerationPowerActionEvent args) { var ev = new PsionicRegenerationDoAfterEvent(_gameTiming.CurTime); - var doAfterArgs = new DoAfterArgs(EntityManager, uid, component.UseDelay, ev, uid); + var doAfterArgs = new DoAfterArgs(uid, component.UseDelay, ev, uid); _doAfterSystem.TryStartDoAfter(doAfterArgs, out var doAfterId); @@ -87,12 +83,8 @@ private void OnPowerUsed(EntityUid uid, PsionicRegenerationPowerComponent compon private void OnShutdown(EntityUid uid, PsionicRegenerationPowerComponent component, ComponentShutdown args) { - _actions.RemoveAction(uid, component.PsionicRegenerationActionEntity); - - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Remove(component); - } + if (_prototypeManager.TryIndex("PsionicRegeneration", out var metapsionic)) + _actions.RemoveAction(uid, new InstantAction(metapsionic), null); } private void OnDispelled(EntityUid uid, PsionicRegenerationPowerComponent component, DispelledEvent args) @@ -124,5 +116,7 @@ private void OnDoAfter(EntityUid uid, PsionicRegenerationPowerComponent componen _bloodstreamSystem.TryAddToChemicals(uid, solution, stream); } } + + public sealed class PsionicRegenerationPowerActionEvent : InstantActionEvent {} } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs index 407b72c6b58..d86c3a346f0 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs @@ -1,12 +1,12 @@ using Content.Shared.Actions; +using Content.Shared.Actions.ActionTypes; using Content.Shared.Abilities.Psionics; using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; using Content.Server.Popups; using Robust.Shared.Prototypes; +using Robust.Shared.Player; using Robust.Shared.Timing; -using Content.Server.Mind; -using Content.Shared.Actions.Events; namespace Content.Server.Abilities.Psionics { @@ -18,7 +18,6 @@ public sealed class PyrokinesisPowerSystem : EntitySystem [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly MindSystem _mindSystem = default!; public override void Initialize() { @@ -30,24 +29,22 @@ public override void Initialize() private void OnInit(EntityUid uid, PyrokinesisPowerComponent component, ComponentInit args) { - _actions.AddAction(uid, ref component.PyrokinesisActionEntity, component.PyrokinesisActionId ); - _actions.TryGetActionData( component.PyrokinesisActionEntity, out var actionData ); - if (actionData is { UseDelay: not null }) - _actions.StartUseDelay(component.PyrokinesisActionEntity); + if (!_prototypeManager.TryIndex("Pyrokinesis", out var pyrokinesis)) + return; + + component.PyrokinesisPowerAction = new EntityTargetAction(pyrokinesis); + if (pyrokinesis.UseDelay != null) + component.PyrokinesisPowerAction.Cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + (TimeSpan) pyrokinesis.UseDelay); + _actions.AddAction(uid, component.PyrokinesisPowerAction, null); + if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - { - psionic.PsionicAbility = component.PyrokinesisActionEntity; - psionic.ActivePowers.Add(component); - } + psionic.PsionicAbility = component.PyrokinesisPowerAction; } private void OnShutdown(EntityUid uid, PyrokinesisPowerComponent component, ComponentShutdown args) { - _actions.RemoveAction(uid, component.PyrokinesisActionEntity); - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Remove(component); - } + if (_prototypeManager.TryIndex("Pyrokinesis", out var pyrokinesis)) + _actions.RemoveAction(uid, new EntityTargetAction(pyrokinesis), null); } private void OnPowerUsed(PyrokinesisPowerActionEvent args) @@ -56,11 +53,13 @@ private void OnPowerUsed(PyrokinesisPowerActionEvent args) return; flammableComponent.FireStacks += 5; - _flammableSystem.Ignite(args.Target, args.Target); + _flammableSystem.Ignite(args.Target, flammableComponent); _popupSystem.PopupEntity(Loc.GetString("pyrokinesis-power-used", ("target", args.Target)), args.Target, Shared.Popups.PopupType.LargeCaution); _psionics.LogPowerUsed(args.Performer, "pyrokinesis"); args.Handled = true; } } + + public sealed class PyrokinesisPowerActionEvent : EntityTargetActionEvent {} } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs index f7ae04b61ea..0d6adb7f9a9 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs @@ -1,11 +1,10 @@ using Content.Shared.Actions; +using Content.Shared.Actions.ActionTypes; using Content.Shared.StatusEffect; using Content.Shared.Abilities.Psionics; -using Content.Shared.Mind.Components; +using Content.Server.Mind.Components; using Robust.Shared.Prototypes; using Robust.Shared.Timing; -using Content.Server.Mind; -using Content.Shared.Actions.Events; namespace Content.Server.Abilities.Psionics { @@ -17,7 +16,6 @@ public sealed class TelegnosisPowerSystem : EntitySystem [Dependency] private readonly MindSwapPowerSystem _mindSwap = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly MindSystem _mindSystem = default!; public override void Initialize() { @@ -30,24 +28,22 @@ public override void Initialize() private void OnInit(EntityUid uid, TelegnosisPowerComponent component, ComponentInit args) { - _actions.AddAction(uid, ref component.TelegnosisActionEntity, component.TelegnosisActionId ); - _actions.TryGetActionData( component.TelegnosisActionEntity, out var actionData ); - if (actionData is { UseDelay: not null }) - _actions.StartUseDelay(component.TelegnosisActionEntity); + if (!_prototypeManager.TryIndex("Telegnosis", out var telegnosis)) + return; + + component.TelegnosisPowerAction = new InstantAction(telegnosis); + if (telegnosis.UseDelay != null) + component.TelegnosisPowerAction.Cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + (TimeSpan) telegnosis.UseDelay); + _actions.AddAction(uid, component.TelegnosisPowerAction, null); + if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - { - psionic.PsionicAbility = component.TelegnosisActionEntity; - psionic.ActivePowers.Add(component); - } + psionic.PsionicAbility = component.TelegnosisPowerAction; } private void OnShutdown(EntityUid uid, TelegnosisPowerComponent component, ComponentShutdown args) { - _actions.RemoveAction(uid, component.TelegnosisActionEntity); - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Remove(component); - } + if (_prototypeManager.TryIndex("Telegnosis", out var metapsionic)) + _actions.RemoveAction(uid, new InstantAction(metapsionic), null); } private void OnPowerUsed(EntityUid uid, TelegnosisPowerComponent component, TelegnosisPowerActionEvent args) @@ -64,4 +60,6 @@ private void OnMindRemoved(EntityUid uid, TelegnosticProjectionComponent compone QueueDel(uid); } } + + public sealed class TelegnosisPowerActionEvent : InstantActionEvent {} } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/PsionicAbilitiesSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/PsionicAbilitiesSystem.cs index ee16aaccfb6..326be3e0583 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/PsionicAbilitiesSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/PsionicAbilitiesSystem.cs @@ -6,14 +6,12 @@ using Content.Server.EUI; using Content.Server.Psionics; using Content.Server.Mind; -using Content.Shared.Mind; -using Content.Shared.Mind.Components; +using Content.Server.Mind.Components; using Content.Shared.StatusEffect; using Robust.Shared.Random; using Robust.Shared.Prototypes; using Robust.Server.GameObjects; using Robust.Server.Player; -using Robust.Shared.Player; namespace Content.Server.Abilities.Psionics { @@ -52,11 +50,8 @@ public void AddPsionics(EntityUid uid, bool warn = true) if (HasComp(uid)) return; - //Don't know if this will work. New mind state vs old. if (!TryComp(uid, out var mindContainer) || - !_mindSystem.TryGetMind(uid, out _, out var mind )) - //|| - //!_mindSystem.TryGetMind(uid, out var mind, mindContainer)) + !_mindSystem.TryGetMind(uid, out var mind, mindContainer)) { EnsureComp(uid); return; @@ -127,13 +122,8 @@ public void RemovePsionics(EntityUid uid) if (EntityManager.TryGetComponent(uid, comp.GetType(), out var psionicPower)) RemComp(uid, psionicPower); } - if (psionic.PsionicAbility != null){ - _actionsSystem.TryGetActionData( psionic.PsionicAbility, out var psiAbility ); - if (psiAbility != null){ - var owner = psiAbility.Owner; - _actionsSystem.RemoveAction(uid, psiAbility.Owner); - } - } + if (psionic.PsionicAbility != null) + _actionsSystem.RemoveAction(uid, psionic.PsionicAbility); _statusEffectsSystem.TryAddStatusEffect(uid, "Stutter", TimeSpan.FromMinutes(5), false, "StutteringAccent"); diff --git a/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibilitySystem.cs b/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibilitySystem.cs index 31e6b89f13d..1c9cb55f2dd 100644 --- a/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibilitySystem.cs +++ b/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibilitySystem.cs @@ -20,7 +20,6 @@ public override void Initialize() SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnInsulInit); SubscribeLocalEvent(OnInsulShutdown); - SubscribeLocalEvent(OnEyeInit); /// Layer SubscribeLocalEvent(OnInvisInit); @@ -36,11 +35,15 @@ private void OnInit(EntityUid uid, PotentialPsionicComponent component, Componen SetCanSeePsionicInvisiblity(uid, false); } + /// + /// Being able to see invisible by default is no longer tracked by "Not having Potential Psionic". + /// Anything intended to be immune to invisibility(and mind magic in general) should instead have PsionicInsulation as a built-in component + /// + /// + /// + /// private void OnInsulInit(EntityUid uid, PsionicInsulationComponent component, ComponentInit args) { - if (!HasComp(uid)) - return; - if (HasComp(uid)) _invisSystem.ToggleInvisibility(uid); @@ -61,9 +64,6 @@ private void OnInsulInit(EntityUid uid, PsionicInsulationComponent component, Co private void OnInsulShutdown(EntityUid uid, PsionicInsulationComponent component, ComponentShutdown args) { - if (!HasComp(uid)) - return; - SetCanSeePsionicInvisiblity(uid, false); if (!HasComp(uid)) @@ -99,10 +99,6 @@ private void OnInvisShutdown(EntityUid uid, PsionicallyInvisibleComponent compon } } - private void OnEyeInit(EntityUid uid, EyeComponent component, ComponentInit args) - { - //SetCanSeePsionicInvisiblity(uid, true); //JJ Comment - Not allowed to modifies .yml on spawn any longer. See UninitializedSaveTest. - } private void OnEntInserted(EntityUid uid, PsionicallyInvisibleComponent component, EntInsertedIntoContainerMessage args) { DirtyEntity(args.Entity); @@ -125,7 +121,7 @@ public void SetCanSeePsionicInvisiblity(EntityUid uid, bool set) { if (EntityManager.TryGetComponent(uid, out EyeComponent? eye)) { - _eye.SetVisibilityMask(uid, eye.VisibilityMask & ~ (int) VisibilityFlags.PsionicInvisibility, eye); + _eye.SetVisibilityMask(uid, eye.VisibilityMask & ~(int) VisibilityFlags.PsionicInvisibility, eye); } } } diff --git a/Content.Server/Nyanotrasen/Psionics/PsionicsSystem.cs b/Content.Server/Nyanotrasen/Psionics/PsionicsSystem.cs index 5a96af2e96b..9da293df0b5 100644 --- a/Content.Server/Nyanotrasen/Psionics/PsionicsSystem.cs +++ b/Content.Server/Nyanotrasen/Psionics/PsionicsSystem.cs @@ -1,19 +1,14 @@ using Content.Shared.Abilities.Psionics; using Content.Shared.StatusEffect; -using Content.Shared.Mobs; using Content.Shared.Psionics.Glimmer; using Content.Shared.Weapons.Melee.Events; using Content.Shared.Damage.Events; -using Content.Shared.IdentityManagement; using Content.Shared.CCVar; using Content.Server.Abilities.Psionics; -using Content.Server.Chat.Systems; using Content.Server.Electrocution; using Content.Server.NPC.Components; using Content.Server.NPC.Systems; -using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; -using Robust.Shared.Player; using Robust.Shared.Configuration; using Robust.Shared.Random; @@ -27,7 +22,6 @@ public sealed class PsionicsSystem : EntitySystem [Dependency] private readonly ElectrocutionSystem _electrocutionSystem = default!; [Dependency] private readonly MindSwapPowerSystem _mindSwapPowerSystem = default!; [Dependency] private readonly GlimmerSystem _glimmerSystem = default!; - [Dependency] private readonly ChatSystem _chat = default!; [Dependency] private readonly NpcFactionSystem _npcFactonSystem = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; @@ -151,7 +145,7 @@ public void RollPsionics(EntityUid uid, PotentialPsionicComponent component, boo chance = Math.Clamp(chance, 0, 1); if (_random.Prob(chance)) - _psionicAbilitiesSystem.AddPsionics(uid, warn); + _psionicAbilitiesSystem.AddPsionics(uid); } public void RerollPsionics(EntityUid uid, PotentialPsionicComponent? psionic = null, float bonusMuliplier = 1f) diff --git a/Resources/Prototypes/Nyanotrasen/Actions/types.yml b/Resources/Prototypes/Nyanotrasen/Actions/types.yml index e6e4bdc5a75..376d92e3efb 100644 --- a/Resources/Prototypes/Nyanotrasen/Actions/types.yml +++ b/Resources/Prototypes/Nyanotrasen/Actions/types.yml @@ -103,15 +103,29 @@ event: !type:PyrokinesisPowerActionEvent - type: entity - id: ActionMetapsionic - name: action-name-metapsionic - description: action-description-metapsionic + id: ActionWideMetapsionic + name: action-name-widemetapsionic + description: action-description-widemetapsionic noSpawn: true components: - type: InstantAction icon: Nyanotrasen/Interface/VerbIcons/metapsionic.png useDelay: 45 - event: !type:MetapsionicPowerActionEvent + event: !type:WideMetapsionicPowerActionEvent + +- type: entity + id: ActionFocusedMetapsionic + name: action-name-focusedmetapsionic + description: action-description-focusedmetapsionic + noSpawn: true + components: + - type: EntityTargetAction + icon: Nyanotrasen/Interface/VerbIcons/metapsionic.png + useDelay: 45 + range: 3 + checkCanAccess: false + itemIconStyle: BigAction + event: !type:FocusedMetapsionicPowerActionEvent - type: entity id: ActionPsionicRegeneration From afaedd2e747720e726d2a1bdb7d7147053273906 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Fri, 3 May 2024 14:08:58 -0400 Subject: [PATCH 03/82] Last bit --- .../Nyanotrasen/Chat/NyanoChatSystem.cs | 5 ++- .../BecomePsionicConditionComponent.cs | 11 ------ .../Systems/BecomePsionicConditionSystem.cs | 32 ------------------ .../Audio/Nyanotrasen/heartbeat_fast.ogg | Bin 0 -> 39983 bytes .../nyanotrasen/psionics/psychic-feedback.ftl | 6 ++++ .../DeltaV/Entities/Mobs/Player/harpy.yml | 1 - .../DeltaV/Entities/Mobs/Player/vulpkanin.yml | 1 - .../Entities/Mobs/Player/arachnid.yml | 1 - .../Prototypes/Entities/Mobs/Player/diona.yml | 1 - .../Prototypes/Entities/Mobs/Player/dwarf.yml | 2 -- .../Prototypes/Entities/Mobs/Player/human.yml | 2 -- .../Prototypes/Entities/Mobs/Player/moth.yml | 2 -- .../Entities/Mobs/Player/reptilian.yml | 2 -- .../Prototypes/Entities/Mobs/Player/slime.yml | 2 -- .../Nyanotrasen/Entities/Mobs/Player/Oni.yml | 1 - .../Entities/Mobs/Player/felinid.yml | 2 -- .../Nyanotrasen/Objectives/traitor.yml | 23 ------------- .../Nyanotrasen/Traits/psionics.yml | 6 ++++ .../Prototypes/Objectives/objectiveGroups.yml | 1 - 19 files changed, 16 insertions(+), 85 deletions(-) delete mode 100644 Content.Server/Nyanotrasen/Objectives/Components/BecomePsionicConditionComponent.cs delete mode 100644 Content.Server/Nyanotrasen/Objectives/Systems/BecomePsionicConditionSystem.cs create mode 100644 Resources/Audio/Nyanotrasen/heartbeat_fast.ogg create mode 100644 Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl create mode 100644 Resources/Prototypes/Nyanotrasen/Traits/psionics.yml diff --git a/Content.Server/Nyanotrasen/Chat/NyanoChatSystem.cs b/Content.Server/Nyanotrasen/Chat/NyanoChatSystem.cs index 58ed1782741..e0fb18fcae4 100644 --- a/Content.Server/Nyanotrasen/Chat/NyanoChatSystem.cs +++ b/Content.Server/Nyanotrasen/Chat/NyanoChatSystem.cs @@ -2,6 +2,7 @@ using Content.Server.Administration.Managers; using Content.Server.Chat.Managers; using Content.Server.Chat.Systems; +using Content.Server.Psionics; using Content.Shared.Abilities.Psionics; using Content.Shared.Bed.Sleep; using Content.Shared.Chat; @@ -47,7 +48,9 @@ private IEnumerable GetAdminClients() private List GetDreamers(IEnumerable removeList) { var filtered = Filter.Empty() - .AddWhereAttachedEntity(entity => HasComp(entity) || HasComp(entity) && !HasComp(entity) && !HasComp(entity)) + .AddWhereAttachedEntity(entity => HasComp(entity) + || HasComp(entity) && !HasComp(entity) && !HasComp(entity) + || HasComp(entity) && !HasComp(entity) && !HasComp(entity)) .Recipients .Select(p => p.ConnectedClient); diff --git a/Content.Server/Nyanotrasen/Objectives/Components/BecomePsionicConditionComponent.cs b/Content.Server/Nyanotrasen/Objectives/Components/BecomePsionicConditionComponent.cs deleted file mode 100644 index 3b677bab2d4..00000000000 --- a/Content.Server/Nyanotrasen/Objectives/Components/BecomePsionicConditionComponent.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Content.Server.Objectives.Systems; - -namespace Content.Server.Objectives.Components; - -/// -/// Requires that the player dies to be complete. -/// -[RegisterComponent, Access(typeof(BecomePsionicConditionSystem))] -public sealed partial class BecomePsionicConditionComponent : Component -{ -} \ No newline at end of file diff --git a/Content.Server/Nyanotrasen/Objectives/Systems/BecomePsionicConditionSystem.cs b/Content.Server/Nyanotrasen/Objectives/Systems/BecomePsionicConditionSystem.cs deleted file mode 100644 index d090c320a41..00000000000 --- a/Content.Server/Nyanotrasen/Objectives/Systems/BecomePsionicConditionSystem.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Content.Shared.Abilities.Psionics; -using Content.Server.Objectives.Components; -using Content.Shared.Mind; -using Content.Shared.Objectives.Components; - -namespace Content.Server.Objectives.Systems -{ - public sealed class BecomePsionicConditionSystem : EntitySystem - { - private EntityQuery _metaQuery; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnGetProgress); - } - - private void OnGetProgress(EntityUid uid, BecomePsionicConditionComponent comp, ref ObjectiveGetProgressEvent args) - { - args.Progress = GetProgress(args.Mind); - } - - private float GetProgress(MindComponent mind) - { - var entMan = IoCManager.Resolve(); - if (HasComp(mind.CurrentEntity)) - return 1; - return 0; - } - } -} diff --git a/Resources/Audio/Nyanotrasen/heartbeat_fast.ogg b/Resources/Audio/Nyanotrasen/heartbeat_fast.ogg new file mode 100644 index 0000000000000000000000000000000000000000..85a034d9bd0017dafea7df4128235c815babac0c GIT binary patch literal 39983 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 literal 0 HcmV?d00001 diff --git a/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl b/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl new file mode 100644 index 00000000000..5e6626eb9ca --- /dev/null +++ b/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl @@ -0,0 +1,6 @@ +dispel-feedback = {CAPITALIZE($entity)} projects an aura of normality +no-powers = {CAPITALIZE($entity)} will never awaken from the dream in this life +psychic-potential = {CAPITALIZE($entity)} has a slim chance of awakening from the dream +focused-metapsionic-pulse-begin = The air around {CAPITALIZE($entity)} begins to shimmer faintly, like a heat haze crawling across the endless desert +psionic-regeneration-self-revive = As {CAPITALIZE($entity)} falls to the floor greviously wounded, + they begin visibly regenerating! diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/Player/harpy.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/Player/harpy.yml index 1f4eb696c65..e2541def035 100644 --- a/Resources/Prototypes/DeltaV/Entities/Mobs/Player/harpy.yml +++ b/Resources/Prototypes/DeltaV/Entities/Mobs/Player/harpy.yml @@ -26,4 +26,3 @@ - type: NpcFactionMember factions: - NanoTrasen - - type: PotentialPsionic diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/Player/vulpkanin.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/Player/vulpkanin.yml index 06abe8c45fa..ea2357a5c06 100644 --- a/Resources/Prototypes/DeltaV/Entities/Mobs/Player/vulpkanin.yml +++ b/Resources/Prototypes/DeltaV/Entities/Mobs/Player/vulpkanin.yml @@ -24,7 +24,6 @@ - type: NpcFactionMember factions: - NanoTrasen - - type: PotentialPsionic - type: Respirator damage: types: diff --git a/Resources/Prototypes/Entities/Mobs/Player/arachnid.yml b/Resources/Prototypes/Entities/Mobs/Player/arachnid.yml index 5ebd43ddf48..d9dea3c18d9 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/arachnid.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/arachnid.yml @@ -11,4 +11,3 @@ damageRecovery: types: Asphyxiation: -0.5 - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. diff --git a/Resources/Prototypes/Entities/Mobs/Player/diona.yml b/Resources/Prototypes/Entities/Mobs/Player/diona.yml index 28687c68bfc..dfd5e9a1be7 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/diona.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/diona.yml @@ -11,7 +11,6 @@ damageRecovery: types: Asphyxiation: -1.0 - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. # Reformed Diona - type: entity diff --git a/Resources/Prototypes/Entities/Mobs/Player/dwarf.yml b/Resources/Prototypes/Entities/Mobs/Player/dwarf.yml index fb84ad3650f..d1de65df012 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/dwarf.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/dwarf.yml @@ -3,5 +3,3 @@ name: Urist McHands The Dwarf parent: BaseMobDwarf id: MobDwarf - components: - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Mobs/Player/human.yml b/Resources/Prototypes/Entities/Mobs/Player/human.yml index b864984a7f3..a96b53b9532 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/human.yml @@ -3,8 +3,6 @@ name: Urist McHands parent: BaseMobHuman id: MobHuman - components: - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. #Syndie - type: entity diff --git a/Resources/Prototypes/Entities/Mobs/Player/moth.yml b/Resources/Prototypes/Entities/Mobs/Player/moth.yml index ffdb36d86bd..72feba958ab 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/moth.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/moth.yml @@ -3,5 +3,3 @@ name: Urist McFluff parent: BaseMobMoth id: MobMoth - components: - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml b/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml index 71d74222979..b9f265e0bcf 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml @@ -3,7 +3,5 @@ name: Urisst' Mzhand parent: BaseMobReptilian id: MobReptilian - components: - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. #Weh diff --git a/Resources/Prototypes/Entities/Mobs/Player/slime.yml b/Resources/Prototypes/Entities/Mobs/Player/slime.yml index 79669a8fe2a..4e5974b3084 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/slime.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/slime.yml @@ -2,5 +2,3 @@ save: false parent: BaseMobSlimePerson id: MobSlimePerson - components: - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. \ No newline at end of file diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/Oni.yml b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/Oni.yml index 562b9c564ec..1166d8a29f5 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/Oni.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/Oni.yml @@ -32,4 +32,3 @@ - type: NpcFactionMember factions: - NanoTrasen - - type: PotentialPsionic diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/felinid.yml b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/felinid.yml index db7936cc5b4..94ac8403adc 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/felinid.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/felinid.yml @@ -49,5 +49,3 @@ - type: NpcFactionMember factions: - NanoTrasen - - type: PotentialPsionic - diff --git a/Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml b/Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml index 53910a54a92..e6e497003d5 100644 --- a/Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml +++ b/Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml @@ -9,29 +9,6 @@ stealGroup: AntiPsychicKnife owner: job-name-mantis -- type: entity - id: BecomePsionicObjective - parent: BaseTraitorObjective - name: Become psionic - description: We need you to acquire psionics and keep them until your mission is complete. - noSpawn: true - components: - - type: NotJobsRequirement - jobs: - - Mime - - ForensicMantis - - type: Objective - difficulty: 2.5 - #unique: false - icon: - sprite: Nyanotrasen/Icons/psi.rsi - state: psi - - type: ObjectiveBlacklistRequirement - blacklist: - components: - - BecomeGolemCondition - - type: BecomePsionicCondition - #- type: entity # id: BecomeGolemObjective # parent: BaseTraitorObjective diff --git a/Resources/Prototypes/Nyanotrasen/Traits/psionics.yml b/Resources/Prototypes/Nyanotrasen/Traits/psionics.yml new file mode 100644 index 00000000000..5fef3427703 --- /dev/null +++ b/Resources/Prototypes/Nyanotrasen/Traits/psionics.yml @@ -0,0 +1,6 @@ +- type: trait + id: LatentPsychic + name: Latent Psychic + description: trait-latent-psychic-desc + components: + - type: PotentialPsionic diff --git a/Resources/Prototypes/Objectives/objectiveGroups.yml b/Resources/Prototypes/Objectives/objectiveGroups.yml index 2fe5f7c833f..5ddf7af8efe 100644 --- a/Resources/Prototypes/Objectives/objectiveGroups.yml +++ b/Resources/Prototypes/Objectives/objectiveGroups.yml @@ -39,7 +39,6 @@ EscapeShuttleObjective: 1 # DieObjective: 0.05 # DeltaV - Disable the lrp objective aka murderbone justification #HijackShuttleObjective: 0.02 - BecomePsionicObjective: 1 # Nyanotrasen - Become Psionic objective, see Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml #BecomeGolemObjective: 0.5 # Nyanotrasen - Become a golem objective, see Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml - type: weightedRandom From 1566ee557d9d442eb2d8af7e83f845ed563d6436 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Fri, 3 May 2024 14:11:28 -0400 Subject: [PATCH 04/82] Last one missed --- Resources/Prototypes/Entities/Mobs/Species/human.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Mobs/Species/human.yml b/Resources/Prototypes/Entities/Mobs/Species/human.yml index 7bf96efe2cc..900de77712e 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/human.yml @@ -16,7 +16,6 @@ spawned: - id: FoodMeatHuman amount: 5 - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. - type: entity parent: BaseSpeciesDummy From c832f5f240ae87b83f2aca4487093929d9a67a3d Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Fri, 3 May 2024 17:57:09 -0400 Subject: [PATCH 05/82] I accidentally sent the DeltaV legacy version of these --- .../Psionics/Abilities/DispelPowerSystem.cs | 54 ++++--- .../Abilities/MetapsionicPowerSystem.cs | 144 +++++++++++++++--- .../Psionics/Abilities/MindSwapPowerSystem.cs | 117 ++++++++------ .../Abilities/MindSwappedComponent.cs | 14 +- .../Abilities/NoosphericZapPowerSystem.cs | 34 ++--- .../PsionicInvisibilityPowerSystem.cs | 102 ++++++++----- .../PsionicRegenerationPowerSystem.cs | 108 +++++++++---- .../Abilities/PyrokinesisPowerSystem.cs | 35 +++-- .../Abilities/TelegnosisPowerSystem.cs | 34 +++-- .../Psionics/PsionicAbilitiesSystem.cs | 83 ++++------ 10 files changed, 469 insertions(+), 256 deletions(-) diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/DispelPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/DispelPowerSystem.cs index f7d88f4cb83..8cde75f461d 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/DispelPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/DispelPowerSystem.cs @@ -1,5 +1,4 @@ using Content.Shared.Actions; -using Content.Shared.Actions.ActionTypes; using Content.Shared.StatusEffect; using Content.Shared.Abilities.Psionics; using Content.Shared.Damage; @@ -7,16 +6,15 @@ using Content.Server.Guardian; using Content.Server.Bible.Components; using Content.Server.Popups; -using Robust.Shared.Prototypes; using Robust.Shared.Player; using Robust.Shared.Random; -using Robust.Shared.Timing; +using Content.Shared.Actions.Events; +using Robust.Shared.Audio.Systems; namespace Content.Server.Abilities.Psionics { public sealed class DispelPowerSystem : EntitySystem { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly StatusEffectsSystem _statusEffects = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly DamageableSystem _damageableSystem = default!; @@ -25,7 +23,6 @@ public sealed class DispelPowerSystem : EntitySystem [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; public override void Initialize() @@ -45,28 +42,38 @@ public override void Initialize() private void OnInit(EntityUid uid, DispelPowerComponent component, ComponentInit args) { - if (!_prototypeManager.TryIndex("Dispel", out var action)) - return; - - component.DispelPowerAction = new EntityTargetAction(action); - if (action.UseDelay != null) - component.DispelPowerAction.Cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + (TimeSpan) action.UseDelay); - _actions.AddAction(uid, component.DispelPowerAction, null); - - if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - psionic.PsionicAbility = component.DispelPowerAction; + _actions.AddAction(uid, ref component.DispelActionEntity, component.DispelActionId ); + _actions.TryGetActionData( component.DispelActionEntity, out var actionData ); + if (actionData is { UseDelay: not null }) + _actions.StartUseDelay(component.DispelActionEntity); + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Add(component); + psionic.PsychicFeedback.Add(component.DispelFeedback); + //It's fully intended that Dispel doesn't increase Amplification, and instead heavily spikes Dampening + //Antimage archetype. + psionic.Dampening += 1f; + } } private void OnShutdown(EntityUid uid, DispelPowerComponent component, ComponentShutdown args) { - if (_prototypeManager.TryIndex("Dispel", out var action)) - _actions.RemoveAction(uid, new EntityTargetAction(action), null); + _actions.RemoveAction(uid, component.DispelActionEntity); + + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Remove(component); + psionic.PsychicFeedback.Remove(component.DispelFeedback); + psionic.Dampening -= 1f; + } } private void OnPowerUsed(DispelPowerActionEvent args) { if (HasComp(args.Target)) return; + if (!TryComp(args.Performer, out var psionic) || !HasComp(args.Target)) + return; var ev = new DispelledEvent(); RaiseLocalEvent(args.Target, ev, false); @@ -74,7 +81,7 @@ private void OnPowerUsed(DispelPowerActionEvent args) if (ev.Handled) { args.Handled = true; - _psionics.LogPowerUsed(args.Performer, "dispel"); + _psionics.LogPowerUsed(args.Performer, "dispel", (int) MathF.Round(psionic.Dampening * -2), (int) MathF.Round(psionic.Dampening * -4)); } } @@ -83,14 +90,14 @@ private void OnDispelled(EntityUid uid, DispellableComponent component, Dispelle QueueDel(uid); Spawn("Ash", Transform(uid).Coordinates); _popupSystem.PopupCoordinates(Loc.GetString("psionic-burns-up", ("item", uid)), Transform(uid).Coordinates, Filter.Pvs(uid), true, Shared.Popups.PopupType.MediumCaution); - _audioSystem.Play("/Audio/Effects/lightburn.ogg", Filter.Pvs(uid), uid, true); + _audioSystem.PlayEntity("/Audio/Effects/lightburn.ogg", Filter.Pvs(uid), uid, true); args.Handled = true; } private void OnDmgDispelled(EntityUid uid, DamageOnDispelComponent component, DispelledEvent args) { var damage = component.Damage; - var modifier = (1 + component.Variance) - (_random.NextFloat(0, component.Variance * 2)); + var modifier = 1 + component.Variance - _random.NextFloat(0, component.Variance * 2); damage *= modifier; DealDispelDamage(uid, damage); @@ -100,7 +107,7 @@ private void OnDmgDispelled(EntityUid uid, DamageOnDispelComponent component, Di private void OnGuardianDispelled(EntityUid uid, GuardianComponent guardian, DispelledEvent args) { if (TryComp(guardian.Host, out var host)) - _guardianSystem.ToggleGuardian(guardian.Host, host); + _guardianSystem.ToggleGuardian(guardian.Host.Value, host); DealDispelDamage(uid); args.Handled = true; @@ -127,7 +134,7 @@ public void DealDispelDamage(EntityUid uid, DamageSpecifier? damage = null) return; _popupSystem.PopupCoordinates(Loc.GetString("psionic-burn-resist", ("item", uid)), Transform(uid).Coordinates, Filter.Pvs(uid), true, Shared.Popups.PopupType.SmallCaution); - _audioSystem.Play("/Audio/Effects/lightburn.ogg", Filter.Pvs(uid), uid, true); + _audioSystem.PlayEntity("/Audio/Effects/lightburn.ogg", Filter.Pvs(uid), uid, true); if (damage == null) { @@ -137,8 +144,5 @@ public void DealDispelDamage(EntityUid uid, DamageSpecifier? damage = null) _damageableSystem.TryChangeDamage(uid, damage, true, true); } } - - public sealed class DispelPowerActionEvent : EntityTargetActionEvent {} - public sealed class DispelledEvent : HandledEntityEventArgs {} } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs index ee3c9a58d9c..44953767f19 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs @@ -1,23 +1,29 @@ using Content.Shared.Actions; -using Content.Shared.Actions.ActionTypes; +using Content.Shared.Actions.Events; using Content.Shared.Abilities.Psionics; -using Content.Shared.StatusEffect; +using Content.Shared.DoAfter; +using Content.Shared.Examine; +using static Content.Shared.Examine.ExamineSystemShared; using Content.Shared.Popups; -using Robust.Shared.Prototypes; -using Robust.Shared.Player; +using Robust.Server.Audio; +using Robust.Shared.Audio; using Robust.Shared.Timing; +using Robust.Shared.Player; +using Content.Server.DoAfter; +using Content.Shared.Psionics.Events; +using Content.Server.Psionics; namespace Content.Server.Abilities.Psionics { public sealed class MetapsionicPowerSystem : EntitySystem { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly StatusEffectsSystem _statusEffects = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly SharedPopupSystem _popups = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly AudioSystem _audioSystem = default!; public override void Initialize() @@ -25,31 +31,60 @@ public override void Initialize() base.Initialize(); SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnShutdown); - SubscribeLocalEvent(OnPowerUsed); + SubscribeLocalEvent(OnWidePowerUsed); + SubscribeLocalEvent(OnFocusedPowerUsed); + SubscribeLocalEvent(OnDoAfter); } private void OnInit(EntityUid uid, MetapsionicPowerComponent component, ComponentInit args) { - if (!_prototypeManager.TryIndex("MetapsionicPulse", out var metapsionicPulse)) + if (!TryComp(uid, out ActionsComponent? comp)) return; + _actions.AddAction(uid, ref component.ActionWideMetapsionicEntity, component.ActionWideMetapsionic, component: comp); + _actions.AddAction(uid, ref component.ActionFocusedMetapsionicEntity, component.ActionFocusedMetapsionic, component: comp); + _actions.TryGetActionData(component.ActionWideMetapsionicEntity, out var actionData); + if (actionData is { UseDelay: not null }) + { + _actions.StartUseDelay(component.ActionWideMetapsionicEntity); + _actions.StartUseDelay(component.ActionFocusedMetapsionicEntity); + } + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Add(component); + psionic.PsychicFeedback.Add(component.MetapsionicFeedback); + psionic.Amplification += 0.1f; + psionic.Dampening += 0.5f; + } - component.MetapsionicPowerAction = new InstantAction(metapsionicPulse); - if (metapsionicPulse.UseDelay != null) - component.MetapsionicPowerAction.Cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + (TimeSpan) metapsionicPulse.UseDelay); - _actions.AddAction(uid, component.MetapsionicPowerAction, null); + } - if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - psionic.PsionicAbility = component.MetapsionicPowerAction; + private void UpdateActions(EntityUid uid, MetapsionicPowerComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + _actions.StartUseDelay(component.ActionWideMetapsionicEntity); + _actions.StartUseDelay(component.ActionFocusedMetapsionicEntity); } private void OnShutdown(EntityUid uid, MetapsionicPowerComponent component, ComponentShutdown args) { - if (_prototypeManager.TryIndex("MetapsionicPulse", out var metapsionicPulse)) - _actions.RemoveAction(uid, new InstantAction(metapsionicPulse), null); + _actions.RemoveAction(uid, component.ActionWideMetapsionicEntity); + _actions.RemoveAction(uid, component.ActionFocusedMetapsionicEntity); + + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Remove(component); + psionic.PsychicFeedback.Remove(component.MetapsionicFeedback); + psionic.Amplification -= 0.1f; + psionic.Dampening -= 0.5f; + } } - private void OnPowerUsed(EntityUid uid, MetapsionicPowerComponent component, MetapsionicPowerActionEvent args) + private void OnWidePowerUsed(EntityUid uid, MetapsionicPowerComponent component, WideMetapsionicPowerActionEvent args) { + if (!TryComp(uid, out var psionic)) + return; + foreach (var entity in _lookup.GetEntitiesInRange(uid, component.Range)) { if (HasComp(entity) && entity != uid && !HasComp(entity) && @@ -61,11 +96,80 @@ private void OnPowerUsed(EntityUid uid, MetapsionicPowerComponent component, Met } } _popups.PopupEntity(Loc.GetString("metapsionic-pulse-failure"), uid, uid, PopupType.Large); - _psionics.LogPowerUsed(uid, "metapsionic pulse", 2, 4); + _psionics.LogPowerUsed(uid, "metapsionic pulse", (int) MathF.Round(psionic.Amplification / psionic.Dampening * 2), (int) MathF.Round(psionic.Amplification / psionic.Dampening * 4)); + UpdateActions(uid, component); + args.Handled = true; + } + + private void OnFocusedPowerUsed(FocusedMetapsionicPowerActionEvent args) + { + if (!TryComp(args.Performer, out var psionic)) + return; + + if (HasComp(args.Target)) + return; + + if (!TryComp(args.Performer, out var component)) + return; + + var ev = new FocusedMetapsionicDoAfterEvent(_gameTiming.CurTime); + + _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.Performer, component.UseDelay, ev, args.Performer, args.Target, args.Performer) + { + BlockDuplicate = true, + BreakOnUserMove = true, + BreakOnTargetMove = true, + BreakOnDamage = true, + }, out var doAfterId); + component.DoAfter = doAfterId; + + _popups.PopupEntity(Loc.GetString("focused-metapsionic-pulse-begin", ("entity", args.Performer)), + args.Performer, + // TODO: Use LoS-based Filter when one is available. + Filter.Pvs(args.Performer).RemoveWhereAttachedEntity(entity => !ExamineSystemShared.InRangeUnOccluded(args.Performer, entity, ExamineRange, null)), + true, + PopupType.Medium); + + _audioSystem.PlayPvs(component.SoundUse, component.Owner, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); + _psionics.LogPowerUsed(args.Performer, "focused metapsionic pulse", (int) MathF.Round(psionic.Amplification / psionic.Dampening * 3), (int) MathF.Round(psionic.Amplification / psionic.Dampening * 6)); args.Handled = true; + + UpdateActions(args.Performer, component); } - } - public sealed class MetapsionicPowerActionEvent : InstantActionEvent {} + private void OnDoAfter(EntityUid uid, MetapsionicPowerComponent component, FocusedMetapsionicDoAfterEvent args) + { + if (!TryComp(args.Target, out var psychic)) + return; + + component.DoAfter = null; + + if (args.Target == null) return; + + if (args.Target == uid) + { + _popups.PopupEntity(Loc.GetString("metapulse-self", ("entity", args.Target)), uid, uid, PopupType.LargeCaution); + return; + } + + if (!HasComp(args.Target)) + { + _popups.PopupEntity(Loc.GetString("no-powers", ("entity", args.Target)), uid, uid, PopupType.LargeCaution); + return; + } + + if (HasComp(args.Target) & !HasComp(args.Target)) + { + _popups.PopupEntity(Loc.GetString("psychic-potential", ("entity", args.Target)), uid, uid, PopupType.LargeCaution); + return; + } + + foreach (var psychicFeedback in psychic.PsychicFeedback) + { + _popups.PopupEntity(Loc.GetString(psychicFeedback, ("entity", args.Target)), uid, uid, PopupType.LargeCaution); + } + + } + } } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwapPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwapPowerSystem.cs index 5c83de2b526..04b90fe4d44 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwapPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwapPowerSystem.cs @@ -1,5 +1,4 @@ using Content.Shared.Actions; -using Content.Shared.Actions.ActionTypes; using Content.Shared.Abilities.Psionics; using Content.Shared.Speech; using Content.Shared.Stealth.Components; @@ -7,25 +6,25 @@ using Content.Shared.Mobs; using Content.Shared.Damage; using Content.Server.Mind; -using Content.Server.Mind.Components; using Content.Shared.Mobs.Systems; using Content.Server.Popups; using Content.Server.Psionics; using Content.Server.GameTicking; using Robust.Shared.Prototypes; using Robust.Shared.Timing; +using Content.Shared.Mind; +using Content.Shared.Actions.Events; namespace Content.Server.Abilities.Psionics { public sealed class MindSwapPowerSystem : EntitySystem { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly MobStateSystem _mobStateSystem = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly MindSystem _mindSystem = default!; + [Dependency] private readonly MetaDataSystem _metaDataSystem = default!; public override void Initialize() { @@ -39,39 +38,50 @@ public override void Initialize() SubscribeLocalEvent(OnGhostAttempt); // SubscribeLocalEvent(OnSwapInit); + SubscribeLocalEvent(OnSwapShutdown); } private void OnInit(EntityUid uid, MindSwapPowerComponent component, ComponentInit args) { - if (!_prototypeManager.TryIndex("MindSwap", out var mindSwap)) - return; - - component.MindSwapPowerAction = new EntityTargetAction(mindSwap); - if (mindSwap.UseDelay != null) - component.MindSwapPowerAction.Cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + (TimeSpan) mindSwap.UseDelay); - _actions.AddAction(uid, component.MindSwapPowerAction, null); - - if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - psionic.PsionicAbility = component.MindSwapPowerAction; + _actions.AddAction(uid, ref component.MindSwapActionEntity, component.MindSwapActionId); + _actions.TryGetActionData( component.MindSwapActionEntity, out var actionData); + if (actionData is { UseDelay: not null }) + _actions.StartUseDelay(component.MindSwapActionEntity); + if (TryComp(uid, out var psionic)) + { + psionic.PsionicAbility = component.MindSwapActionEntity; + psionic.ActivePowers.Add(component); + psionic.PsychicFeedback.Add(component.MindSwapFeedback); + psionic.Amplification += 1f; + } } private void OnShutdown(EntityUid uid, MindSwapPowerComponent component, ComponentShutdown args) { - if (_prototypeManager.TryIndex("MindSwap", out var action)) - _actions.RemoveAction(uid, new EntityTargetAction(action), null); + _actions.RemoveAction(uid, component.MindSwapActionEntity); + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Remove(component); + psionic.PsychicFeedback.Remove(component.MindSwapFeedback); + psionic.Amplification -= 1f; + } } private void OnPowerUsed(MindSwapPowerActionEvent args) { + if (!(TryComp(args.Target, out var damageable) && damageable.DamageContainerID == "Biological")) return; if (HasComp(args.Target)) return; + if (!TryComp(args.Performer, out var psionic)) + return; + Swap(args.Performer, args.Target); - _psionics.LogPowerUsed(args.Performer, "mind swap"); + _psionics.LogPowerUsed(args.Performer, "mind swap", (int) MathF.Round(psionic.Amplification / psionic.Dampening * 8), (int) MathF.Round(psionic.Amplification / psionic.Dampening * 12)); args.Handled = true; } @@ -134,8 +144,9 @@ private void OnGhostAttempt(GhostAttemptHandleEvent args) if (!HasComp(args.Mind.CurrentEntity)) return; - if (!args.ViaCommand) - return; + //No idea where the viaCommand went. It's on the internal OnGhostAttempt, but not this layer. Maybe unnecessary. + /*if (!args.viaCommand) + return;*/ args.Result = false; args.Handled = true; @@ -143,11 +154,24 @@ private void OnGhostAttempt(GhostAttemptHandleEvent args) private void OnSwapInit(EntityUid uid, MindSwappedComponent component, ComponentInit args) { - if (_prototypeManager.TryIndex("MindSwapReturn", out var mindSwap)) + _actions.AddAction(uid, ref component.MindSwapReturnActionEntity, component.MindSwapReturnActionId ); + _actions.TryGetActionData( component.MindSwapReturnActionEntity, out var actionData ); + if (actionData is { UseDelay: not null }) + _actions.StartUseDelay(component.MindSwapReturnActionEntity); + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Add(component); + psionic.PsychicFeedback.Add(component.MindSwappedFeedback); + } + } + + private void OnSwapShutdown(EntityUid uid, MindSwappedComponent component, ComponentShutdown args) + { + _actions.RemoveAction(uid, component.MindSwapReturnActionEntity); + if (TryComp(uid, out var psionic)) { - var action = new InstantAction(mindSwap); - action.Cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + TimeSpan.FromSeconds(15)); - _actions.AddAction(uid, action, null); + psionic.ActivePowers.Remove(component); + psionic.PsychicFeedback.Remove(component.MindSwappedFeedback); } } @@ -157,30 +181,35 @@ public void Swap(EntityUid performer, EntityUid target, bool end = false) return; // Get the minds first. On transfer, they'll be gone. - Mind.Mind? performerMind = null; - Mind.Mind? targetMind = null; + MindComponent? performerMind = null; + MindComponent? targetMind = null; // This is here to prevent missing MindContainerComponent Resolve errors. - if (TryComp(performer, out var performerMindContainer)) - performerMind = _mindSystem.GetMind(performer, performerMindContainer); - - if (TryComp(target, out var targetMindContainer)) - targetMind = _mindSystem.GetMind(target, targetMindContainer); - + if(!_mindSystem.TryGetMind(performer, out var performerMindId, out performerMind)){ + performerMind = null; + }; + + if(!_mindSystem.TryGetMind(target, out var targetMindId, out targetMind)){ + targetMind = null; + }; + //This is a terrible way to 'unattach' minds. I wanted to use UnVisit but in TransferTo's code they say + //To unnatch the minds, do it like this. + //Have to unnattach the minds before we reattach them via transfer. Still feels weird, but seems to work well. + _mindSystem.TransferTo(performerMindId, null); + _mindSystem.TransferTo(targetMindId, null); // Do the transfer. if (performerMind != null) - _mindSystem.TransferTo(performerMind, target, ghostCheckOverride: true); + _mindSystem.TransferTo(performerMindId, target, ghostCheckOverride: true, false, performerMind); if (targetMind != null) - _mindSystem.TransferTo(targetMind, performer, ghostCheckOverride: true); + _mindSystem.TransferTo(targetMindId, performer, ghostCheckOverride: true, false, targetMind); if (end) { - if (_prototypeManager.TryIndex("MindSwapReturn", out var mindSwap)) - { - _actions.RemoveAction(performer, new InstantAction(mindSwap), null); - _actions.RemoveAction(target, new InstantAction(mindSwap), null); - } + var performerMindPowerComp = EntityManager.GetComponent(performer); + var targetMindPowerComp = EntityManager.GetComponent(target); + _actions.RemoveAction(performer, performerMindPowerComp.MindSwapReturnActionEntity); + _actions.RemoveAction(target, targetMindPowerComp.MindSwapReturnActionEntity); RemComp(performer); RemComp(target); @@ -196,11 +225,10 @@ public void Swap(EntityUid performer, EntityUid target, bool end = false) public void GetTrapped(EntityUid uid) { - if (!_prototypeManager.TryIndex("MindSwapReturn", out var action)) - return; _popupSystem.PopupEntity(Loc.GetString("mindswap-trapped"), uid, uid, Shared.Popups.PopupType.LargeCaution); - _actions.RemoveAction(uid, action); + var perfComp = EnsureComp(uid); + _actions.RemoveAction(uid, perfComp.MindSwapReturnActionEntity, null); if (HasComp(uid)) { @@ -208,12 +236,9 @@ public void GetTrapped(EntityUid uid) RemComp(uid); EnsureComp(uid); EnsureComp(uid); - MetaData(uid).EntityName = Loc.GetString("telegnostic-trapped-entity-name"); - MetaData(uid).EntityDescription = Loc.GetString("telegnostic-trapped-entity-desc"); + _metaDataSystem.SetEntityName(uid, Loc.GetString("telegnostic-trapped-entity-name")); + _metaDataSystem.SetEntityDescription(uid, Loc.GetString("telegnostic-trapped-entity-desc")); } } } - - public sealed class MindSwapPowerActionEvent : EntityTargetActionEvent {} - public sealed class MindSwapPowerReturnActionEvent : InstantActionEvent {} } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwappedComponent.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwappedComponent.cs index 84d2909c1f2..92fc94773db 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwappedComponent.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwappedComponent.cs @@ -1,9 +1,21 @@ +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + namespace Content.Server.Abilities.Psionics { [RegisterComponent] - public sealed class MindSwappedComponent : Component + public sealed partial class MindSwappedComponent : Component { [ViewVariables] public EntityUid OriginalEntity = default!; + [DataField("mindSwapReturnActionId", + customTypeSerializer: typeof(PrototypeIdSerializer))] + public string? MindSwapReturnActionId = "ActionMindSwapReturn"; + + [DataField("mindSwapReturnActionEntity")] + public EntityUid? MindSwapReturnActionEntity; + + [DataField("mindSwappedFeedback")] + public string MindSwappedFeedback = "mindswapped-feedback"; } } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs index c844030f1e1..61917df3c7a 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs @@ -1,23 +1,19 @@ using Content.Shared.Actions; -using Content.Shared.Actions.ActionTypes; using Content.Shared.Abilities.Psionics; using Content.Server.Psionics; using Content.Shared.StatusEffect; using Content.Server.Stunnable; using Content.Server.Beam; -using Robust.Shared.Prototypes; -using Robust.Shared.Timing; +using Content.Shared.Actions.Events; namespace Content.Server.Abilities.Psionics { public sealed class NoosphericZapPowerSystem : EntitySystem { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly StunSystem _stunSystem = default!; [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly BeamSystem _beam = default!; @@ -31,22 +27,26 @@ public override void Initialize() private void OnInit(EntityUid uid, NoosphericZapPowerComponent component, ComponentInit args) { - if (!_prototypeManager.TryIndex("NoosphericZap", out var noosphericZap)) - return; - - component.NoosphericZapPowerAction = new EntityTargetAction(noosphericZap); - if (noosphericZap.UseDelay != null) - component.NoosphericZapPowerAction.Cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + (TimeSpan) noosphericZap.UseDelay); - _actions.AddAction(uid, component.NoosphericZapPowerAction, null); - + _actions.AddAction(uid, ref component.NoosphericZapActionEntity, component.NoosphericZapActionId ); + _actions.TryGetActionData( component.NoosphericZapActionEntity, out var actionData ); + if (actionData is { UseDelay: not null }) + _actions.StartUseDelay(component.NoosphericZapActionEntity); if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - psionic.PsionicAbility = component.NoosphericZapPowerAction; + { + psionic.PsionicAbility = component.NoosphericZapActionEntity; + psionic.ActivePowers.Add(component); + psionic.PsychicFeedback.Add(component.NoosphericZapFeedback); + } } private void OnShutdown(EntityUid uid, NoosphericZapPowerComponent component, ComponentShutdown args) { - if (_prototypeManager.TryIndex("NoosphericZap", out var noosphericZap)) - _actions.RemoveAction(uid, new EntityTargetAction(noosphericZap), null); + _actions.RemoveAction(uid, component.NoosphericZapActionEntity); + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Remove(component); + psionic.PsychicFeedback.Remove(component.NoosphericZapFeedback); + } } private void OnPowerUsed(NoosphericZapPowerActionEvent args) @@ -66,6 +66,4 @@ private void OnPowerUsed(NoosphericZapPowerActionEvent args) args.Handled = true; } } - - public sealed class NoosphericZapPowerActionEvent : EntityTargetActionEvent {} } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs index 3bbaf9d8136..cf3da800ed7 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs @@ -1,27 +1,31 @@ +using Content.Server.DoAfter; using Content.Shared.Actions; -using Content.Shared.Actions.ActionTypes; -using Content.Shared.CombatMode.Pacification; using Content.Shared.Abilities.Psionics; using Content.Shared.Damage; +using Content.Shared.DoAfter; using Content.Shared.Stunnable; using Content.Shared.Stealth; using Content.Shared.Stealth.Components; using Content.Server.Psionics; -using Robust.Shared.Prototypes; -using Robust.Shared.Player; -using Robust.Shared.Audio; +using Content.Shared.Psionics.Events; +using Content.Shared.Actions.Events; +using Robust.Shared.Audio.Systems; +using Content.Shared.Interaction.Events; +using Content.Shared.Weapons.Ranged.Events; +using Content.Shared.Throwing; using Robust.Shared.Timing; namespace Content.Server.Abilities.Psionics { public sealed class PsionicInvisibilityPowerSystem : EntitySystem { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly SharedStunSystem _stunSystem = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly SharedStealthSystem _stealth = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; public override void Initialize() { @@ -29,47 +33,61 @@ public override void Initialize() SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent(OnPowerUsed); - SubscribeLocalEvent(OnPowerOff); + SubscribeLocalEvent(OnPowerOff); SubscribeLocalEvent(OnStart); SubscribeLocalEvent(OnEnd); SubscribeLocalEvent(OnDamageChanged); + SubscribeLocalEvent(OnAttackAttempt); + SubscribeLocalEvent(OnShootAttempt); + SubscribeLocalEvent(OnThrowAttempt); } private void OnInit(EntityUid uid, PsionicInvisibilityPowerComponent component, ComponentInit args) { - if (!_prototypeManager.TryIndex("PsionicInvisibility", out var invis)) - return; - - component.PsionicInvisibilityPowerAction = new InstantAction(invis); - if (invis.UseDelay != null) - component.PsionicInvisibilityPowerAction.Cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + (TimeSpan) invis.UseDelay); - _actions.AddAction(uid, component.PsionicInvisibilityPowerAction, null); - - if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - psionic.PsionicAbility = component.PsionicInvisibilityPowerAction; + _actions.AddAction(uid, ref component.PsionicInvisibilityActionEntity, component.PsionicInvisibilityActionId); + _actions.TryGetActionData( component.PsionicInvisibilityActionEntity, out var actionData); + if (actionData is { UseDelay: not null }) + _actions.StartUseDelay(component.PsionicInvisibilityActionEntity); + if (TryComp(uid, out var psionic)) + { + psionic.PsionicAbility = component.PsionicInvisibilityActionEntity; + psionic.ActivePowers.Add(component); + psionic.PsychicFeedback.Add(component.InvisibilityFeedback); + psionic.Amplification += 0.5f; + } } private void OnShutdown(EntityUid uid, PsionicInvisibilityPowerComponent component, ComponentShutdown args) { - if (_prototypeManager.TryIndex("PsionicInvisibility", out var invis)) - _actions.RemoveAction(uid, new InstantAction(invis), null); + RemComp(uid); + RemComp(uid); + _actions.RemoveAction(uid, component.PsionicInvisibilityActionEntity); + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Remove(component); + psionic.PsychicFeedback.Remove(component.InvisibilityFeedback); + psionic.Amplification -= 0.5f; + } } private void OnPowerUsed(EntityUid uid, PsionicInvisibilityPowerComponent component, PsionicInvisibilityPowerActionEvent args) { - if (HasComp(uid)) - return; + var ev = new PsionicInvisibilityTimerEvent(_gameTiming.CurTime); + var doAfterArgs = new DoAfterArgs(EntityManager, uid, component.UseTimer, ev, uid) { Hidden = true }; + _doAfterSystem.TryStartDoAfter(doAfterArgs); ToggleInvisibility(args.Performer); - - if (_prototypeManager.TryIndex("PsionicInvisibilityOff", out var invis)) - _actions.AddAction(args.Performer, new InstantAction(invis), null); + var action = Spawn(PsionicInvisibilityUsedComponent.PsionicInvisibilityUsedActionPrototype); + _actions.AddAction(uid, action, action); + _actions.TryGetActionData( action, out var actionData ); + if (actionData is { UseDelay: not null }) + _actions.StartUseDelay(action); _psionics.LogPowerUsed(uid, "psionic invisibility"); args.Handled = true; } - private void OnPowerOff(PsionicInvisibilityPowerOffActionEvent args) + private void OnPowerOff(RemovePsionicInvisibilityOffPowerActionEvent args) { if (!HasComp(args.Performer)) return; @@ -81,10 +99,9 @@ private void OnPowerOff(PsionicInvisibilityPowerOffActionEvent args) private void OnStart(EntityUid uid, PsionicInvisibilityUsedComponent component, ComponentInit args) { EnsureComp(uid); - EnsureComp(uid); var stealth = EnsureComp(uid); _stealth.SetVisibility(uid, 0.66f, stealth); - SoundSystem.Play("/Audio/Effects/toss.ogg", Filter.Pvs(uid), uid); + _audio.PlayPvs("/Audio/Effects/toss.ogg", uid); } @@ -94,25 +111,34 @@ private void OnEnd(EntityUid uid, PsionicInvisibilityUsedComponent component, Co return; RemComp(uid); - RemComp(uid); RemComp(uid); - SoundSystem.Play("/Audio/Effects/toss.ogg", Filter.Pvs(uid), uid); + _audio.PlayPvs("/Audio/Effects/toss.ogg", uid); + _actions.RemoveAction(uid, component.PsionicInvisibilityUsedActionEntity); + DirtyEntity(uid); + } - if (_prototypeManager.TryIndex("PsionicInvisibilityOff", out var invis)) - _actions.RemoveAction(uid, new InstantAction(invis), null); + private void OnAttackAttempt(EntityUid uid, PsionicInvisibilityUsedComponent component, AttackAttemptEvent args) + { + RemComp(uid); + } - _stunSystem.TryParalyze(uid, TimeSpan.FromSeconds(8), false); - Dirty(uid); + private void OnShootAttempt(EntityUid uid, PsionicInvisibilityUsedComponent component, ShotAttemptedEvent args) + { + RemComp(uid); } + private void OnThrowAttempt(EntityUid uid, PsionicInvisibilityUsedComponent component, ThrowAttemptEvent args) + { + RemComp(uid); + } private void OnDamageChanged(EntityUid uid, PsionicInvisibilityUsedComponent component, DamageChangedEvent args) { if (!args.DamageIncreased) return; ToggleInvisibility(uid); + _stunSystem.TryParalyze(uid, TimeSpan.FromSeconds(4), false); } - public void ToggleInvisibility(EntityUid uid) { if (!HasComp(uid)) @@ -123,8 +149,10 @@ public void ToggleInvisibility(EntityUid uid) RemComp(uid); } } - } - public sealed class PsionicInvisibilityPowerActionEvent : InstantActionEvent {} - public sealed class PsionicInvisibilityPowerOffActionEvent : InstantActionEvent {} + public void OnDoAfter(EntityUid uid, PsionicInvisibilityPowerComponent component, PsionicInvisibilityTimerEvent args) + { + RemComp(uid); + } + } } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs index 985f45b1f6c..707e8d61298 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs @@ -1,39 +1,34 @@ using Robust.Shared.Audio; -using Robust.Server.GameObjects; using Robust.Shared.Player; -using Robust.Shared.Prototypes; using Content.Server.Body.Components; using Content.Server.Body.Systems; -using Content.Server.Chemistry.EntitySystems; using Content.Server.DoAfter; using Content.Shared.Abilities.Psionics; -using Content.Shared.Actions.ActionTypes; using Content.Shared.Actions; using Content.Shared.Chemistry.Components; using Content.Shared.DoAfter; using Content.Shared.FixedPoint; +using Content.Shared.Mobs; using Content.Shared.Popups; using Content.Shared.Psionics.Events; -using Content.Shared.Tag; using Content.Shared.Examine; using static Content.Shared.Examine.ExamineSystemShared; using Robust.Shared.Timing; +using Content.Shared.Actions.Events; +using Robust.Server.Audio; namespace Content.Server.Abilities.Psionics { public sealed class PsionicRegenerationPowerSystem : EntitySystem { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; - [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!; [Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!; [Dependency] private readonly AudioSystem _audioSystem = default!; - [Dependency] private readonly TagSystem _tagSystem = default!; [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; - + [Dependency] private readonly ExamineSystemShared _examine = default!; public override void Initialize() { @@ -41,29 +36,34 @@ public override void Initialize() SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent(OnPowerUsed); - + SubscribeLocalEvent(OnMobStateChangedEvent); SubscribeLocalEvent(OnDispelled); SubscribeLocalEvent(OnDoAfter); } private void OnInit(EntityUid uid, PsionicRegenerationPowerComponent component, ComponentInit args) { - if (!_prototypeManager.TryIndex("PsionicRegeneration", out var metapsionic)) - return; - - component.PsionicRegenerationPowerAction = new InstantAction(metapsionic); - if (metapsionic.UseDelay != null) - component.PsionicRegenerationPowerAction.Cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + (TimeSpan) metapsionic.UseDelay); - _actions.AddAction(uid, component.PsionicRegenerationPowerAction, null); - - if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - psionic.PsionicAbility = component.PsionicRegenerationPowerAction; + _actions.AddAction(uid, ref component.PsionicRegenerationActionEntity, component.PsionicRegenerationActionId ); + _actions.TryGetActionData( component.PsionicRegenerationActionEntity, out var actionData ); + if (actionData is { UseDelay: not null }) + _actions.StartUseDelay(component.PsionicRegenerationActionEntity); + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Add(component); + psionic.PsychicFeedback.Add(component.RegenerationFeedback); + } } private void OnPowerUsed(EntityUid uid, PsionicRegenerationPowerComponent component, PsionicRegenerationPowerActionEvent args) { var ev = new PsionicRegenerationDoAfterEvent(_gameTiming.CurTime); - var doAfterArgs = new DoAfterArgs(uid, component.UseDelay, ev, uid); + var doAfterArgs = new DoAfterArgs(EntityManager, uid, component.UseDelay, ev, uid); + + //Prevent the power from ignoring its own cooldown + _actions.TryGetActionData(component.PsionicRegenerationActionEntity, out var actionData); + var curTime = _gameTiming.CurTime; + if (actionData != null && actionData.Cooldown.HasValue && actionData.Cooldown.Value.End > curTime) + return; _doAfterSystem.TryStartDoAfter(doAfterArgs, out var doAfterId); @@ -72,19 +72,67 @@ private void OnPowerUsed(EntityUid uid, PsionicRegenerationPowerComponent compon _popupSystem.PopupEntity(Loc.GetString("psionic-regeneration-begin", ("entity", uid)), uid, // TODO: Use LoS-based Filter when one is available. - Filter.Pvs(uid).RemoveWhereAttachedEntity(entity => !ExamineSystemShared.InRangeUnOccluded(uid, entity, ExamineRange, null)), + Filter.Pvs(uid).RemoveWhereAttachedEntity(entity => !_examine.InRangeUnOccluded(uid, entity, ExamineRange, null)), true, PopupType.Medium); - _audioSystem.PlayPvs(component.SoundUse, component.Owner, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); + _audioSystem.PlayPvs(component.SoundUse, uid, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); _psionics.LogPowerUsed(uid, "psionic regeneration"); args.Handled = true; } + /// + /// Regenerators automatically activate upon crit, provided the power was off cooldown at that exact point in time. + /// Self-rescusitation is also far more costly, and extremely obvious + /// + /// + /// + /// + private void OnMobStateChangedEvent(EntityUid uid, PsionicRegenerationPowerComponent component, MobStateChangedEvent args) + { + if (HasComp(uid)) + return; + + if (args.NewMobState is MobState.Critical) + { + _actions.TryGetActionData(component.PsionicRegenerationActionEntity, out var actionData); + var curTime = _gameTiming.CurTime; + if (actionData != null && actionData.Cooldown.HasValue && actionData.Cooldown.Value.End > curTime) + return; + + if (actionData is { UseDelay: not null }) + { + component.SelfRevive = true; + _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, uid, component.UseDelay, new PsionicRegenerationDoAfterEvent(_gameTiming.CurTime), uid, args.Target, uid) + { + BreakOnUserMove = false, + BreakOnTargetMove = false, + BreakOnWeightlessMove = false, + BreakOnDamage = false, + RequireCanInteract = false, + }); + _popupSystem.PopupEntity(Loc.GetString("psionic-regeneration-self-revive", ("entity", uid)), + uid, + // TODO: Use LoS-based Filter when one is available. + Filter.Pvs(uid).RemoveWhereAttachedEntity(entity => !_examine.InRangeUnOccluded(uid, entity, ExamineRange, null)), + true, + PopupType.MediumCaution); + _audioSystem.PlayPvs(component.SoundUse, uid, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); + _psionics.LogPowerUsed(uid, "psionic regeneration", 20, 40); + _actions.StartUseDelay(component.PsionicRegenerationActionEntity); + } + } + } + private void OnShutdown(EntityUid uid, PsionicRegenerationPowerComponent component, ComponentShutdown args) { - if (_prototypeManager.TryIndex("PsionicRegeneration", out var metapsionic)) - _actions.RemoveAction(uid, new InstantAction(metapsionic), null); + _actions.RemoveAction(uid, component.PsionicRegenerationActionEntity); + + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Remove(component); + psionic.PsychicFeedback.Remove(component.RegenerationFeedback); + } } private void OnDispelled(EntityUid uid, PsionicRegenerationPowerComponent component, DispelledEvent args) @@ -114,9 +162,13 @@ private void OnDoAfter(EntityUid uid, PsionicRegenerationPowerComponent componen var solution = new Solution(); solution.AddReagent("PsionicRegenerationEssence", FixedPoint2.New(component.EssenceAmount * percentageComplete)); _bloodstreamSystem.TryAddToChemicals(uid, solution, stream); + if (component.SelfRevive == true) + { + var critSolution = new Solution(); + critSolution.AddReagent("Epinephrine", 10); + _bloodstreamSystem.TryAddToChemicals(uid, critSolution, stream); + component.SelfRevive = false; + } } } - - public sealed class PsionicRegenerationPowerActionEvent : InstantActionEvent {} } - diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs index d86c3a346f0..28b4d1b597b 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs @@ -1,12 +1,12 @@ using Content.Shared.Actions; -using Content.Shared.Actions.ActionTypes; using Content.Shared.Abilities.Psionics; using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; using Content.Server.Popups; using Robust.Shared.Prototypes; -using Robust.Shared.Player; using Robust.Shared.Timing; +using Content.Server.Mind; +using Content.Shared.Actions.Events; namespace Content.Server.Abilities.Psionics { @@ -18,6 +18,7 @@ public sealed class PyrokinesisPowerSystem : EntitySystem [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly MindSystem _mindSystem = default!; public override void Initialize() { @@ -29,22 +30,26 @@ public override void Initialize() private void OnInit(EntityUid uid, PyrokinesisPowerComponent component, ComponentInit args) { - if (!_prototypeManager.TryIndex("Pyrokinesis", out var pyrokinesis)) - return; - - component.PyrokinesisPowerAction = new EntityTargetAction(pyrokinesis); - if (pyrokinesis.UseDelay != null) - component.PyrokinesisPowerAction.Cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + (TimeSpan) pyrokinesis.UseDelay); - _actions.AddAction(uid, component.PyrokinesisPowerAction, null); - + _actions.AddAction(uid, ref component.PyrokinesisActionEntity, component.PyrokinesisActionId ); + _actions.TryGetActionData( component.PyrokinesisActionEntity, out var actionData ); + if (actionData is { UseDelay: not null }) + _actions.StartUseDelay(component.PyrokinesisActionEntity); if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - psionic.PsionicAbility = component.PyrokinesisPowerAction; + { + psionic.PsionicAbility = component.PyrokinesisActionEntity; + psionic.ActivePowers.Add(component); + psionic.PsychicFeedback.Add(component.PyrokinesisFeedback); + } } private void OnShutdown(EntityUid uid, PyrokinesisPowerComponent component, ComponentShutdown args) { - if (_prototypeManager.TryIndex("Pyrokinesis", out var pyrokinesis)) - _actions.RemoveAction(uid, new EntityTargetAction(pyrokinesis), null); + _actions.RemoveAction(uid, component.PyrokinesisActionEntity); + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Remove(component); + psionic.PsychicFeedback.Remove(component.PyrokinesisFeedback); + } } private void OnPowerUsed(PyrokinesisPowerActionEvent args) @@ -53,13 +58,11 @@ private void OnPowerUsed(PyrokinesisPowerActionEvent args) return; flammableComponent.FireStacks += 5; - _flammableSystem.Ignite(args.Target, flammableComponent); + _flammableSystem.Ignite(args.Target, args.Target); _popupSystem.PopupEntity(Loc.GetString("pyrokinesis-power-used", ("target", args.Target)), args.Target, Shared.Popups.PopupType.LargeCaution); _psionics.LogPowerUsed(args.Performer, "pyrokinesis"); args.Handled = true; } } - - public sealed class PyrokinesisPowerActionEvent : EntityTargetActionEvent {} } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs index 0d6adb7f9a9..1000ff453f5 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs @@ -1,10 +1,11 @@ using Content.Shared.Actions; -using Content.Shared.Actions.ActionTypes; using Content.Shared.StatusEffect; using Content.Shared.Abilities.Psionics; -using Content.Server.Mind.Components; +using Content.Shared.Mind.Components; using Robust.Shared.Prototypes; using Robust.Shared.Timing; +using Content.Server.Mind; +using Content.Shared.Actions.Events; namespace Content.Server.Abilities.Psionics { @@ -16,6 +17,7 @@ public sealed class TelegnosisPowerSystem : EntitySystem [Dependency] private readonly MindSwapPowerSystem _mindSwap = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly MindSystem _mindSystem = default!; public override void Initialize() { @@ -28,22 +30,26 @@ public override void Initialize() private void OnInit(EntityUid uid, TelegnosisPowerComponent component, ComponentInit args) { - if (!_prototypeManager.TryIndex("Telegnosis", out var telegnosis)) - return; - - component.TelegnosisPowerAction = new InstantAction(telegnosis); - if (telegnosis.UseDelay != null) - component.TelegnosisPowerAction.Cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + (TimeSpan) telegnosis.UseDelay); - _actions.AddAction(uid, component.TelegnosisPowerAction, null); - + _actions.AddAction(uid, ref component.TelegnosisActionEntity, component.TelegnosisActionId ); + _actions.TryGetActionData( component.TelegnosisActionEntity, out var actionData ); + if (actionData is { UseDelay: not null }) + _actions.StartUseDelay(component.TelegnosisActionEntity); if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - psionic.PsionicAbility = component.TelegnosisPowerAction; + { + psionic.PsionicAbility = component.TelegnosisActionEntity; + psionic.ActivePowers.Add(component); + psionic.PsychicFeedback.Add(component.TelegnosisFeedback); + } } private void OnShutdown(EntityUid uid, TelegnosisPowerComponent component, ComponentShutdown args) { - if (_prototypeManager.TryIndex("Telegnosis", out var metapsionic)) - _actions.RemoveAction(uid, new InstantAction(metapsionic), null); + _actions.RemoveAction(uid, component.TelegnosisActionEntity); + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Remove(component); + psionic.PsychicFeedback.Remove(component.TelegnosisFeedback); + } } private void OnPowerUsed(EntityUid uid, TelegnosisPowerComponent component, TelegnosisPowerActionEvent args) @@ -60,6 +66,4 @@ private void OnMindRemoved(EntityUid uid, TelegnosticProjectionComponent compone QueueDel(uid); } } - - public sealed class TelegnosisPowerActionEvent : InstantActionEvent {} } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/PsionicAbilitiesSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/PsionicAbilitiesSystem.cs index 326be3e0583..860b7baab21 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/PsionicAbilitiesSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/PsionicAbilitiesSystem.cs @@ -6,12 +6,15 @@ using Content.Server.EUI; using Content.Server.Psionics; using Content.Server.Mind; -using Content.Server.Mind.Components; +using Content.Shared.Mind.Components; using Content.Shared.StatusEffect; using Robust.Shared.Random; using Robust.Shared.Prototypes; -using Robust.Server.GameObjects; -using Robust.Server.Player; +using Robust.Shared.Player; +using Content.Shared.Examine; +using Content.Shared.Popups; +using Content.Shared.Examine; +using static Content.Shared.Examine.ExamineSystemShared; namespace Content.Server.Abilities.Psionics { @@ -20,29 +23,26 @@ public sealed class PsionicAbilitiesSystem : EntitySystem [Dependency] private readonly IComponentFactory _componentFactory = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; - [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly EuiManager _euiManager = default!; [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; [Dependency] private readonly GlimmerSystem _glimmerSystem = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly MindSystem _mindSystem = default!; + [Dependency] private readonly SharedPopupSystem _popups = default!; public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnPlayerAttached); } - private void OnPlayerAttached(EntityUid uid, PsionicAwaitingPlayerComponent component, PlayerAttachedEvent args) - { - if (TryComp(uid, out var bonus) && bonus.Warn == true) - _euiManager.OpenEui(new AcceptPsionicsEui(uid, this), args.Player); - else - AddRandomPsionicPower(uid); - RemCompDeferred(uid); - } - - public void AddPsionics(EntityUid uid, bool warn = true) + /// + /// Adds a psychic power once a character rolls one. This used to be a system you have to select for. However the opt-in is no longer the text window, but is now done at character creation. + /// This is going to get removed when I reach Part 3 of my reworks, when I touch upon the GlimmerSystem itself and overhaul how players get powers. + /// + /// + /// + /// + public void AddPsionics(EntityUid uid) { if (Deleted(uid)) return; @@ -50,41 +50,11 @@ public void AddPsionics(EntityUid uid, bool warn = true) if (HasComp(uid)) return; - if (!TryComp(uid, out var mindContainer) || - !_mindSystem.TryGetMind(uid, out var mind, mindContainer)) - { - EnsureComp(uid); - return; - } - - if (!_mindSystem.TryGetSession(mind, out var client)) - return; - - if (warn && TryComp(uid, out var actor)) - _euiManager.OpenEui(new AcceptPsionicsEui(uid, this), client); - else - AddRandomPsionicPower(uid); + AddRandomPsionicPower(uid); } - - public void AddPsionics(EntityUid uid, string powerComp) - { - if (Deleted(uid)) - return; - - if (HasComp(uid)) - return; - - AddComp(uid); - - var newComponent = (Component) _componentFactory.GetComponent(powerComp); - newComponent.Owner = uid; - - EntityManager.AddComponent(uid, newComponent); - } - public void AddRandomPsionicPower(EntityUid uid) { - AddComp(uid); + EnsureComp(uid, out var psionic); if (!_prototypeManager.TryIndex("RandomPsionicPowerPool", out var pool)) { @@ -98,7 +68,7 @@ public void AddRandomPsionicPower(EntityUid uid) EntityManager.AddComponent(uid, newComponent); - _glimmerSystem.Glimmer += _random.Next(1, 5); + _glimmerSystem.Glimmer += _random.Next((int) MathF.Round(psionic.Amplification * psionic.Dampening * 1), (int) MathF.Round(psionic.Amplification * psionic.Dampening * 5)); } public void RemovePsionics(EntityUid uid) @@ -122,12 +92,25 @@ public void RemovePsionics(EntityUid uid) if (EntityManager.TryGetComponent(uid, comp.GetType(), out var psionicPower)) RemComp(uid, psionicPower); } - if (psionic.PsionicAbility != null) - _actionsSystem.RemoveAction(uid, psionic.PsionicAbility); + if (psionic.PsionicAbility != null){ + _actionsSystem.TryGetActionData( psionic.PsionicAbility, out var psiAbility ); + if (psiAbility != null){ + _actionsSystem.RemoveAction(uid, psiAbility.Owner); + } + } + + _popups.PopupEntity(Loc.GetString("mindbreaking-feedback", ("entity", uid)), + uid, + // TODO: Use LoS-based Filter when one is available. + Filter.Pvs(uid).RemoveWhereAttachedEntity(entity => !ExamineSystemShared.InRangeUnOccluded(uid, entity, ExamineRange, null)), + true, + PopupType.Medium); _statusEffectsSystem.TryAddStatusEffect(uid, "Stutter", TimeSpan.FromMinutes(5), false, "StutteringAccent"); + _glimmerSystem.Glimmer += _random.Next((int) MathF.Round(psionic.Amplification * psionic.Dampening * -5), (int) MathF.Round(psionic.Amplification * psionic.Dampening * -10)); RemComp(uid); + RemComp(uid); } } } From 827bdb2084de621f9a5db427b7a92d2be7ad3d13 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 14 May 2024 16:02:58 -0400 Subject: [PATCH 06/82] Finishing Mind Swap rework --- .../Abilities/MetapsionicPowerSystem.cs | 2 +- .../Psionics/Abilities/MindSwapPowerSystem.cs | 20 +++++++++++-------- .../Abilities/NoosphericZapPowerSystem.cs | 3 +-- .../PsionicInvisibilityPowerSystem.cs | 1 - .../Abilities/PyrokinesisPowerSystem.cs | 3 +-- .../Abilities/TelegnosisPowerSystem.cs | 3 +-- .../Psionics/SharedPsionicSystem.Insulated.cs | 19 ++++++++++++++++++ 7 files changed, 35 insertions(+), 16 deletions(-) create mode 100644 Content.Shared/Nyanotrasen/Psionics/SharedPsionicSystem.Insulated.cs diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs index 44953767f19..fd9b8107568 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs @@ -131,7 +131,7 @@ private void OnFocusedPowerUsed(FocusedMetapsionicPowerActionEvent args) true, PopupType.Medium); - _audioSystem.PlayPvs(component.SoundUse, component.Owner, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); + _audioSystem.PlayPvs(component.SoundUse, args.Performer, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); _psionics.LogPowerUsed(args.Performer, "focused metapsionic pulse", (int) MathF.Round(psionic.Amplification / psionic.Dampening * 3), (int) MathF.Round(psionic.Amplification / psionic.Dampening * 6)); args.Handled = true; diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwapPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwapPowerSystem.cs index 04b90fe4d44..8f191949472 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwapPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwapPowerSystem.cs @@ -1,5 +1,6 @@ using Content.Shared.Actions; using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics; using Content.Shared.Speech; using Content.Shared.Stealth.Components; using Content.Shared.Mobs.Components; @@ -10,8 +11,6 @@ using Content.Server.Popups; using Content.Server.Psionics; using Content.Server.GameTicking; -using Robust.Shared.Prototypes; -using Robust.Shared.Timing; using Content.Shared.Mind; using Content.Shared.Actions.Events; @@ -36,9 +35,9 @@ public override void Initialize() SubscribeLocalEvent(OnDispelled); SubscribeLocalEvent(OnMobStateChanged); SubscribeLocalEvent(OnGhostAttempt); - // SubscribeLocalEvent(OnSwapInit); SubscribeLocalEvent(OnSwapShutdown); + SubscribeLocalEvent(OnInsulated); } private void OnInit(EntityUid uid, MindSwapPowerComponent component, ComponentInit args) @@ -49,7 +48,6 @@ private void OnInit(EntityUid uid, MindSwapPowerComponent component, ComponentIn _actions.StartUseDelay(component.MindSwapActionEntity); if (TryComp(uid, out var psionic)) { - psionic.PsionicAbility = component.MindSwapActionEntity; psionic.ActivePowers.Add(component); psionic.PsychicFeedback.Add(component.MindSwapFeedback); psionic.Amplification += 1f; @@ -132,8 +130,8 @@ private void OnDispelled(EntityUid uid, MindSwappedComponent component, Dispelle private void OnMobStateChanged(EntityUid uid, MindSwappedComponent component, MobStateChangedEvent args) { - if (args.NewMobState == MobState.Dead) - RemComp(uid); + if (args.NewMobState == MobState.Dead || args.NewMobState == MobState.Critical) + Swap(uid, component.OriginalEntity, true); } private void OnGhostAttempt(GhostAttemptHandleEvent args) @@ -185,11 +183,13 @@ public void Swap(EntityUid performer, EntityUid target, bool end = false) MindComponent? targetMind = null; // This is here to prevent missing MindContainerComponent Resolve errors. - if(!_mindSystem.TryGetMind(performer, out var performerMindId, out performerMind)){ + if (!_mindSystem.TryGetMind(performer, out var performerMindId, out performerMind)) + { performerMind = null; }; - if(!_mindSystem.TryGetMind(target, out var targetMindId, out targetMind)){ + if (!_mindSystem.TryGetMind(target, out var targetMindId, out targetMind)) + { targetMind = null; }; //This is a terrible way to 'unattach' minds. I wanted to use UnVisit but in TransferTo's code they say @@ -240,5 +240,9 @@ public void GetTrapped(EntityUid uid) _metaDataSystem.SetEntityDescription(uid, Loc.GetString("telegnostic-trapped-entity-desc")); } } + public void OnInsulated(EntityUid uid, MindSwappedComponent component, PsionicInsulationEvent args) + { + Swap(uid, component.OriginalEntity, true); + } } } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs index 61917df3c7a..cceb3ef2075 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs @@ -31,9 +31,8 @@ private void OnInit(EntityUid uid, NoosphericZapPowerComponent component, Compon _actions.TryGetActionData( component.NoosphericZapActionEntity, out var actionData ); if (actionData is { UseDelay: not null }) _actions.StartUseDelay(component.NoosphericZapActionEntity); - if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) + if (TryComp(uid, out var psionic)) { - psionic.PsionicAbility = component.NoosphericZapActionEntity; psionic.ActivePowers.Add(component); psionic.PsychicFeedback.Add(component.NoosphericZapFeedback); } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs index cf3da800ed7..af2ae0c7f05 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs @@ -50,7 +50,6 @@ private void OnInit(EntityUid uid, PsionicInvisibilityPowerComponent component, _actions.StartUseDelay(component.PsionicInvisibilityActionEntity); if (TryComp(uid, out var psionic)) { - psionic.PsionicAbility = component.PsionicInvisibilityActionEntity; psionic.ActivePowers.Add(component); psionic.PsychicFeedback.Add(component.InvisibilityFeedback); psionic.Amplification += 0.5f; diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs index 28b4d1b597b..8300b204dca 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs @@ -34,9 +34,8 @@ private void OnInit(EntityUid uid, PyrokinesisPowerComponent component, Componen _actions.TryGetActionData( component.PyrokinesisActionEntity, out var actionData ); if (actionData is { UseDelay: not null }) _actions.StartUseDelay(component.PyrokinesisActionEntity); - if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) + if (TryComp(uid, out var psionic)) { - psionic.PsionicAbility = component.PyrokinesisActionEntity; psionic.ActivePowers.Add(component); psionic.PsychicFeedback.Add(component.PyrokinesisFeedback); } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs index 1000ff453f5..00d06e6dd28 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs @@ -34,9 +34,8 @@ private void OnInit(EntityUid uid, TelegnosisPowerComponent component, Component _actions.TryGetActionData( component.TelegnosisActionEntity, out var actionData ); if (actionData is { UseDelay: not null }) _actions.StartUseDelay(component.TelegnosisActionEntity); - if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) + if (TryComp(uid, out var psionic)) { - psionic.PsionicAbility = component.TelegnosisActionEntity; psionic.ActivePowers.Add(component); psionic.PsychicFeedback.Add(component.TelegnosisFeedback); } diff --git a/Content.Shared/Nyanotrasen/Psionics/SharedPsionicSystem.Insulated.cs b/Content.Shared/Nyanotrasen/Psionics/SharedPsionicSystem.Insulated.cs new file mode 100644 index 00000000000..c59f98db7f0 --- /dev/null +++ b/Content.Shared/Nyanotrasen/Psionics/SharedPsionicSystem.Insulated.cs @@ -0,0 +1,19 @@ +using Content.Shared.Abilities.Psionics; + +namespace Content.Shared.Psionics +{ + public sealed class PsionicInsulationSystem : EntitySystem + { + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnInsulated); + } + + public void OnInsulated(EntityUid uid, PsionicInsulationComponent component, ComponentInit args) + { + RaiseLocalEvent(uid, new PsionicInsulationEvent()); + } + } + public readonly record struct PsionicInsulationEvent; +} From 22f405be7b2fa47a8d91f156f43354cdd50b441b Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 14 May 2024 16:58:05 -0400 Subject: [PATCH 07/82] Noospheric Zap updating --- .../Abilities/NoosphericZapPowerSystem.cs | 26 ++++++++++++------- .../Prototypes/Nyanotrasen/psionicPowers.yml | 3 ++- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs index cceb3ef2075..d849d383033 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs @@ -1,7 +1,8 @@ using Content.Shared.Actions; using Content.Shared.Abilities.Psionics; -using Content.Server.Psionics; +using Content.Shared.Damage; using Content.Shared.StatusEffect; +using Content.Server.Electrocution; using Content.Server.Stunnable; using Content.Server.Beam; using Content.Shared.Actions.Events; @@ -15,6 +16,8 @@ public sealed class NoosphericZapPowerSystem : EntitySystem [Dependency] private readonly StunSystem _stunSystem = default!; [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; [Dependency] private readonly BeamSystem _beam = default!; + [Dependency] private readonly DamageableSystem _damageableSystem = default!; + [Dependency] private readonly ElectrocutionSystem _electrocution = default!; public override void Initialize() @@ -35,6 +38,7 @@ private void OnInit(EntityUid uid, NoosphericZapPowerComponent component, Compon { psionic.ActivePowers.Add(component); psionic.PsychicFeedback.Add(component.NoosphericZapFeedback); + psionic.Amplification += 1f; } } @@ -45,24 +49,26 @@ private void OnShutdown(EntityUid uid, NoosphericZapPowerComponent component, Co { psionic.ActivePowers.Remove(component); psionic.PsychicFeedback.Remove(component.NoosphericZapFeedback); + psionic.Amplification += 1f; } } private void OnPowerUsed(NoosphericZapPowerActionEvent args) { - if (!HasComp(args.Target)) + if (!TryComp(args.Performer, out var psionic)) return; - if (HasComp(args.Target)) - return; - - _beam.TryCreateBeam(args.Performer, args.Target, "LightningNoospheric"); + if (!HasComp(args.Target) && !HasComp(args.Performer)) + { + _beam.TryCreateBeam(args.Performer, args.Target, "LightningNoospheric"); + _stunSystem.TryParalyze(args.Target, TimeSpan.FromSeconds(1 * psionic.Amplification), false); - _stunSystem.TryParalyze(args.Target, TimeSpan.FromSeconds(5), false); - _statusEffectsSystem.TryAddStatusEffect(args.Target, "Stutter", TimeSpan.FromSeconds(10), false, "StutteringAccent"); + _electrocution.TryDoElectrocution(args.Target, null, (int) MathF.Round(5f * psionic.Amplification), new TimeSpan((long) MathF.Round(1f * psionic.Amplification)), true, ignoreInsulation: true); + _statusEffectsSystem.TryAddStatusEffect(args.Target, "Stutter", TimeSpan.FromSeconds(2 * psionic.Amplification), false, "StutteringAccent"); - _psionics.LogPowerUsed(args.Performer, "noospheric zap"); - args.Handled = true; + _psionics.LogPowerUsed(args.Performer, "noopsheric zap", (int) MathF.Round(psionic.Dampening * -4), (int) MathF.Round(psionic.Dampening * -6)); + args.Handled = true; + } } } } diff --git a/Resources/Prototypes/Nyanotrasen/psionicPowers.yml b/Resources/Prototypes/Nyanotrasen/psionicPowers.yml index f40b688fd18..cb3f88d6a4a 100644 --- a/Resources/Prototypes/Nyanotrasen/psionicPowers.yml +++ b/Resources/Prototypes/Nyanotrasen/psionicPowers.yml @@ -6,5 +6,6 @@ TelegnosisPower: 1 PsionicRegenerationPower: 1 MassSleepPower: 0.3 -# PsionicInvisibilityPower: 0.15 + PsionicInvisibilityPower: 0.15 MindSwapPower: 0.15 + NoosphericZapPower: 0.15 From f50f9df784d98d5b3e4e35468c4be3c1519d27d4 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 14 May 2024 20:18:02 -0400 Subject: [PATCH 08/82] Almost done --- .../Components/IgniteOnCollideComponent.cs | 4 +- .../Nyanotrasen/Chat/NyanoChatSystem.cs | 8 +-- .../Psionics/Abilities/DispelPowerSystem.cs | 8 ++- .../Abilities/MetapsionicPowerSystem.cs | 13 ++++- .../Psionics/Abilities/MindSwapPowerSystem.cs | 4 +- .../Abilities/MindSwappedComponent.cs | 2 +- .../Abilities/NoosphericZapPowerSystem.cs | 15 +++-- .../Abilities}/PsionicAbilitiesSystem.cs | 2 +- .../PsionicInvisibilityPowerSystem.cs | 30 ++++++++-- .../PsionicRegenerationPowerSystem.cs | 36 +++++++++--- .../Abilities/PyrokinesisPowerSystem.cs | 54 +++++++++++------ .../Abilities/TelegnosisPowerSystem.cs | 58 +++++++++++++++---- .../Psionics/AcceptPsionicsEui.cs | 2 +- .../Psionics/AntiPsychicWeaponComponent.cs | 0 .../Audio/GlimmerSoundComponent.cs | 6 +- .../Psionics/Dreams/DreamSystem.cs | 1 - .../Psionics/Glimmer/GlimmerCommands.cs | 0 .../Psionics/Glimmer/GlimmerReactiveSystem.cs | 0 .../Glimmer/PassiveGlimmerReductionSystem.cs | 2 - .../Structures/GlimmerSourceComponent.cs | 0 .../Structures/GlimmerStructuresSystem.cs | 0 .../Invisibility/PsionicInvisibilitySystem.cs | 3 + .../PsionicInvisibleContactsComponent.cs | 0 .../PsionicInvisibleContactsSystem.cs | 0 .../PsionicallyInvisibleComponent.cs | 0 .../Psionics/PotentialPsionicComponent.cs | 0 .../PsionicAwaitingPlayerComponent.cs | 0 .../Psionics/PsionicBonusChanceComponent.cs | 0 .../Psionics/PsionicsCommands.cs | 0 .../Psionics/PsionicsSystem.cs | 39 ++++++++++++- .../PsionicRegenerationPowerComponent.cs | 2 +- .../Telegnosis/TelegnosisPowerComponent.cs | 3 + .../TelegnosticProjectionComponent.cs | 6 +- .../Abilities/Psionics/PsionicComponent.cs | 6 +- .../Events/PyrokinesisPowerActionEvent.cs | 4 +- .../Psionics/SharedPsionicSystem.Insulated.cs | 15 ----- .../Prototypes/Nyanotrasen/Actions/types.yml | 2 +- .../Prototypes/Nyanotrasen/psionicPowers.yml | 1 + 38 files changed, 229 insertions(+), 97 deletions(-) rename Content.Server/{Nyanotrasen/Abilities => }/Psionics/Abilities/DispelPowerSystem.cs (95%) rename Content.Server/{Nyanotrasen/Abilities => }/Psionics/Abilities/MetapsionicPowerSystem.cs (93%) rename Content.Server/{Nyanotrasen/Abilities => }/Psionics/Abilities/MindSwapPowerSystem.cs (98%) rename Content.Server/{Nyanotrasen/Abilities => }/Psionics/Abilities/MindSwappedComponent.cs (94%) rename Content.Server/{Nyanotrasen/Abilities => }/Psionics/Abilities/NoosphericZapPowerSystem.cs (87%) rename Content.Server/{Nyanotrasen/Abilities/Psionics => Psionics/Abilities}/PsionicAbilitiesSystem.cs (99%) rename Content.Server/{Nyanotrasen/Abilities => }/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs (84%) rename Content.Server/{Nyanotrasen/Abilities => }/Psionics/Abilities/PsionicRegenerationPowerSystem.cs (86%) rename Content.Server/{Nyanotrasen/Abilities => }/Psionics/Abilities/PyrokinesisPowerSystem.cs (50%) rename Content.Server/{Nyanotrasen/Abilities => }/Psionics/Abilities/TelegnosisPowerSystem.cs (52%) rename Content.Server/{Nyanotrasen => }/Psionics/AcceptPsionicsEui.cs (95%) rename Content.Server/{Nyanotrasen => }/Psionics/AntiPsychicWeaponComponent.cs (100%) rename Content.Server/{Nyanotrasen => Psionics}/Audio/GlimmerSoundComponent.cs (80%) rename Content.Server/{Nyanotrasen => }/Psionics/Dreams/DreamSystem.cs (98%) rename Content.Server/{Nyanotrasen => }/Psionics/Glimmer/GlimmerCommands.cs (100%) rename Content.Server/{Nyanotrasen => }/Psionics/Glimmer/GlimmerReactiveSystem.cs (100%) rename Content.Server/{Nyanotrasen => }/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs (94%) rename Content.Server/{Nyanotrasen => }/Psionics/Glimmer/Structures/GlimmerSourceComponent.cs (100%) rename Content.Server/{Nyanotrasen => }/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs (100%) rename Content.Server/{Nyanotrasen => }/Psionics/Invisibility/PsionicInvisibilitySystem.cs (98%) rename Content.Server/{Nyanotrasen => }/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs (100%) rename Content.Server/{Nyanotrasen => }/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs (100%) rename Content.Server/{Nyanotrasen => }/Psionics/Invisibility/PsionicallyInvisibleComponent.cs (100%) rename Content.Server/{Nyanotrasen => }/Psionics/PotentialPsionicComponent.cs (100%) rename Content.Server/{Nyanotrasen => }/Psionics/PsionicAwaitingPlayerComponent.cs (100%) rename Content.Server/{Nyanotrasen => }/Psionics/PsionicBonusChanceComponent.cs (100%) rename Content.Server/{Nyanotrasen => }/Psionics/PsionicsCommands.cs (100%) rename Content.Server/{Nyanotrasen => }/Psionics/PsionicsSystem.cs (79%) diff --git a/Content.Server/Atmos/Components/IgniteOnCollideComponent.cs b/Content.Server/Atmos/Components/IgniteOnCollideComponent.cs index a58d3a3c122..710c37b62fe 100644 --- a/Content.Server/Atmos/Components/IgniteOnCollideComponent.cs +++ b/Content.Server/Atmos/Components/IgniteOnCollideComponent.cs @@ -1,8 +1,6 @@ -using Content.Server.Atmos.EntitySystems; - namespace Content.Server.Atmos.Components; -[RegisterComponent, Access(typeof(FlammableSystem))] +[RegisterComponent] public sealed partial class IgniteOnCollideComponent : Component { /// diff --git a/Content.Server/Nyanotrasen/Chat/NyanoChatSystem.cs b/Content.Server/Nyanotrasen/Chat/NyanoChatSystem.cs index e0fb18fcae4..62d8032df1d 100644 --- a/Content.Server/Nyanotrasen/Chat/NyanoChatSystem.cs +++ b/Content.Server/Nyanotrasen/Chat/NyanoChatSystem.cs @@ -64,7 +64,7 @@ private List GetDreamers(IEnumerable removeList) private bool IsEligibleForTelepathy(EntityUid entity) { - return HasComp(entity) + return TryComp(entity, out var psionic) && psionic.Telepath && !HasComp(entity) && !HasComp(entity) && (!TryComp(entity, out var mobstate) || mobstate.CurrentState == MobState.Alive); @@ -95,9 +95,9 @@ public void SendTelepathicChat(EntityUid source, string message, bool hideChat) if (_random.Prob(0.1f)) _glimmerSystem.Glimmer++; - if (_random.Prob(Math.Min(0.33f + ((float) _glimmerSystem.Glimmer / 1500), 1))) + if (_random.Prob(Math.Min(0.33f + (float) _glimmerSystem.Glimmer / 1500, 1))) { - float obfuscation = (0.25f + (float) _glimmerSystem.Glimmer / 2000); + float obfuscation = 0.25f + (float) _glimmerSystem.Glimmer / 2000; var obfuscated = ObfuscateMessageReadability(message, obfuscation); _chatManager.ChatMessageToMany(ChatChannel.Telepathic, obfuscated, messageWrap, source, hideChat, false, GetDreamers(clients), Color.PaleVioletRed); } @@ -114,7 +114,7 @@ private string ObfuscateMessageReadability(string message, float chance) for (var i = 0; i < message.Length; i++) { - if (char.IsWhiteSpace((modifiedMessage[i]))) + if (char.IsWhiteSpace(modifiedMessage[i])) { continue; } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/DispelPowerSystem.cs b/Content.Server/Psionics/Abilities/DispelPowerSystem.cs similarity index 95% rename from Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/DispelPowerSystem.cs rename to Content.Server/Psionics/Abilities/DispelPowerSystem.cs index 8cde75f461d..14e3ea14aeb 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/DispelPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/DispelPowerSystem.cs @@ -11,7 +11,7 @@ using Content.Shared.Actions.Events; using Robust.Shared.Audio.Systems; -namespace Content.Server.Abilities.Psionics +namespace Content.Server.Psionics.Abilities { public sealed class DispelPowerSystem : EntitySystem { @@ -70,7 +70,7 @@ private void OnShutdown(EntityUid uid, DispelPowerComponent component, Component private void OnPowerUsed(DispelPowerActionEvent args) { - if (HasComp(args.Target)) + if (HasComp(args.Target) || HasComp(args.Performer)) return; if (!TryComp(args.Performer, out var psionic) || !HasComp(args.Target)) return; @@ -81,7 +81,9 @@ private void OnPowerUsed(DispelPowerActionEvent args) if (ev.Handled) { args.Handled = true; - _psionics.LogPowerUsed(args.Performer, "dispel", (int) MathF.Round(psionic.Dampening * -2), (int) MathF.Round(psionic.Dampening * -4)); + _psionics.LogPowerUsed(args.Performer, "dispel", + (int) MathF.Round(-2 * psionic.Dampening + psionic.Amplification), + (int) MathF.Round(-4 * psionic.Dampening + psionic.Amplification)); } } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs b/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs similarity index 93% rename from Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs rename to Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs index fd9b8107568..6279aa88622 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs @@ -13,7 +13,7 @@ using Content.Shared.Psionics.Events; using Content.Server.Psionics; -namespace Content.Server.Abilities.Psionics +namespace Content.Server.Psionics.Abilities { public sealed class MetapsionicPowerSystem : EntitySystem { @@ -82,6 +82,9 @@ private void OnShutdown(EntityUid uid, MetapsionicPowerComponent component, Comp private void OnWidePowerUsed(EntityUid uid, MetapsionicPowerComponent component, WideMetapsionicPowerActionEvent args) { + if (HasComp(uid)) + return; + if (!TryComp(uid, out var psionic)) return; @@ -96,7 +99,9 @@ private void OnWidePowerUsed(EntityUid uid, MetapsionicPowerComponent component, } } _popups.PopupEntity(Loc.GetString("metapsionic-pulse-failure"), uid, uid, PopupType.Large); - _psionics.LogPowerUsed(uid, "metapsionic pulse", (int) MathF.Round(psionic.Amplification / psionic.Dampening * 2), (int) MathF.Round(psionic.Amplification / psionic.Dampening * 4)); + _psionics.LogPowerUsed(uid, "metapsionic pulse", + (int) MathF.Round(2 * psionic.Amplification - psionic.Dampening), + (int) MathF.Round(4 * psionic.Amplification - psionic.Dampening)); UpdateActions(uid, component); args.Handled = true; } @@ -132,7 +137,9 @@ private void OnFocusedPowerUsed(FocusedMetapsionicPowerActionEvent args) PopupType.Medium); _audioSystem.PlayPvs(component.SoundUse, args.Performer, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); - _psionics.LogPowerUsed(args.Performer, "focused metapsionic pulse", (int) MathF.Round(psionic.Amplification / psionic.Dampening * 3), (int) MathF.Round(psionic.Amplification / psionic.Dampening * 6)); + _psionics.LogPowerUsed(args.Performer, "focused metapsionic pulse", + (int) MathF.Round(3 * psionic.Amplification - psionic.Dampening), + (int) MathF.Round(6 * psionic.Amplification - psionic.Dampening)); args.Handled = true; UpdateActions(args.Performer, component); diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwapPowerSystem.cs b/Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs similarity index 98% rename from Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwapPowerSystem.cs rename to Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs index 8f191949472..0beea77aa53 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwapPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs @@ -14,7 +14,7 @@ using Content.Shared.Mind; using Content.Shared.Actions.Events; -namespace Content.Server.Abilities.Psionics +namespace Content.Server.Psionics.Abilities { public sealed class MindSwapPowerSystem : EntitySystem { @@ -222,7 +222,7 @@ public void Swap(EntityUid performer, EntityUid target, bool end = false) perfComp.OriginalEntity = target; targetComp.OriginalEntity = performer; } - + //It shouldn't actually be possible anymore to get trapped under most circumstances, but for niche edge cases, I am leaving this here public void GetTrapped(EntityUid uid) { diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwappedComponent.cs b/Content.Server/Psionics/Abilities/MindSwappedComponent.cs similarity index 94% rename from Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwappedComponent.cs rename to Content.Server/Psionics/Abilities/MindSwappedComponent.cs index 92fc94773db..82c0313bca6 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwappedComponent.cs +++ b/Content.Server/Psionics/Abilities/MindSwappedComponent.cs @@ -1,7 +1,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Server.Abilities.Psionics +namespace Content.Server.Psionics.Abilities { [RegisterComponent] public sealed partial class MindSwappedComponent : Component diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs b/Content.Server/Psionics/Abilities/NoosphericZapPowerSystem.cs similarity index 87% rename from Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs rename to Content.Server/Psionics/Abilities/NoosphericZapPowerSystem.cs index d849d383033..7e4ba64afde 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/NoosphericZapPowerSystem.cs @@ -1,13 +1,12 @@ using Content.Shared.Actions; using Content.Shared.Abilities.Psionics; -using Content.Shared.Damage; using Content.Shared.StatusEffect; using Content.Server.Electrocution; using Content.Server.Stunnable; using Content.Server.Beam; using Content.Shared.Actions.Events; -namespace Content.Server.Abilities.Psionics +namespace Content.Server.Psionics.Abilities { public sealed class NoosphericZapPowerSystem : EntitySystem { @@ -16,7 +15,6 @@ public sealed class NoosphericZapPowerSystem : EntitySystem [Dependency] private readonly StunSystem _stunSystem = default!; [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; [Dependency] private readonly BeamSystem _beam = default!; - [Dependency] private readonly DamageableSystem _damageableSystem = default!; [Dependency] private readonly ElectrocutionSystem _electrocution = default!; @@ -63,10 +61,17 @@ private void OnPowerUsed(NoosphericZapPowerActionEvent args) _beam.TryCreateBeam(args.Performer, args.Target, "LightningNoospheric"); _stunSystem.TryParalyze(args.Target, TimeSpan.FromSeconds(1 * psionic.Amplification), false); - _electrocution.TryDoElectrocution(args.Target, null, (int) MathF.Round(5f * psionic.Amplification), new TimeSpan((long) MathF.Round(1f * psionic.Amplification)), true, ignoreInsulation: true); + _electrocution.TryDoElectrocution(args.Target, null, + (int) MathF.Round(5f * psionic.Amplification), + new TimeSpan((long) MathF.Round(1f * psionic.Amplification)), + true, + ignoreInsulation: true); + _statusEffectsSystem.TryAddStatusEffect(args.Target, "Stutter", TimeSpan.FromSeconds(2 * psionic.Amplification), false, "StutteringAccent"); - _psionics.LogPowerUsed(args.Performer, "noopsheric zap", (int) MathF.Round(psionic.Dampening * -4), (int) MathF.Round(psionic.Dampening * -6)); + _psionics.LogPowerUsed(args.Performer, "noopsheric zap", + (int) MathF.Round(6 * psionic.Amplification - psionic.Dampening), + (int) MathF.Round(8 * psionic.Amplification - psionic.Dampening)); args.Handled = true; } } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/PsionicAbilitiesSystem.cs b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs similarity index 99% rename from Content.Server/Nyanotrasen/Abilities/Psionics/PsionicAbilitiesSystem.cs rename to Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs index 860b7baab21..1bfacb0f119 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/PsionicAbilitiesSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs @@ -16,7 +16,7 @@ using Content.Shared.Examine; using static Content.Shared.Examine.ExamineSystemShared; -namespace Content.Server.Abilities.Psionics +namespace Content.Server.Psionics.Abilities { public sealed class PsionicAbilitiesSystem : EntitySystem { diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs b/Content.Server/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs similarity index 84% rename from Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs rename to Content.Server/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs index af2ae0c7f05..77690c49f48 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs @@ -14,8 +14,9 @@ using Content.Shared.Weapons.Ranged.Events; using Content.Shared.Throwing; using Robust.Shared.Timing; +using Content.Shared.Psionics; -namespace Content.Server.Abilities.Psionics +namespace Content.Server.Psionics.Abilities { public sealed class PsionicInvisibilityPowerSystem : EntitySystem { @@ -40,6 +41,7 @@ public override void Initialize() SubscribeLocalEvent(OnAttackAttempt); SubscribeLocalEvent(OnShootAttempt); SubscribeLocalEvent(OnThrowAttempt); + SubscribeLocalEvent(OnInsulated); } private void OnInit(EntityUid uid, PsionicInvisibilityPowerComponent component, ComponentInit args) @@ -71,6 +73,12 @@ private void OnShutdown(EntityUid uid, PsionicInvisibilityPowerComponent compone private void OnPowerUsed(EntityUid uid, PsionicInvisibilityPowerComponent component, PsionicInvisibilityPowerActionEvent args) { + if (!TryComp(uid, out var psionic)) + return; + + if (HasComp(uid)) + return; + var ev = new PsionicInvisibilityTimerEvent(_gameTiming.CurTime); var doAfterArgs = new DoAfterArgs(EntityManager, uid, component.UseTimer, ev, uid) { Hidden = true }; _doAfterSystem.TryStartDoAfter(doAfterArgs); @@ -78,11 +86,13 @@ private void OnPowerUsed(EntityUid uid, PsionicInvisibilityPowerComponent compon ToggleInvisibility(args.Performer); var action = Spawn(PsionicInvisibilityUsedComponent.PsionicInvisibilityUsedActionPrototype); _actions.AddAction(uid, action, action); - _actions.TryGetActionData( action, out var actionData ); + _actions.TryGetActionData(action, out var actionData); if (actionData is { UseDelay: not null }) _actions.StartUseDelay(action); - _psionics.LogPowerUsed(uid, "psionic invisibility"); + _psionics.LogPowerUsed(uid, "psionic invisibility", + (int) MathF.Round(8 * psionic.Amplification - 2 * psionic.Dampening), + (int) MathF.Round(12 * psionic.Amplification - 2 * psionic.Dampening)); args.Handled = true; } @@ -132,11 +142,14 @@ private void OnThrowAttempt(EntityUid uid, PsionicInvisibilityUsedComponent comp } private void OnDamageChanged(EntityUid uid, PsionicInvisibilityUsedComponent component, DamageChangedEvent args) { + if (!TryComp(uid, out var psionic)) + return; + if (!args.DamageIncreased) return; ToggleInvisibility(uid); - _stunSystem.TryParalyze(uid, TimeSpan.FromSeconds(4), false); + _stunSystem.TryParalyze(uid, TimeSpan.FromSeconds(4f / psionic.Dampening + psionic.Amplification), false); } public void ToggleInvisibility(EntityUid uid) { @@ -153,5 +166,14 @@ public void OnDoAfter(EntityUid uid, PsionicInvisibilityPowerComponent component { RemComp(uid); } + + private void OnInsulated(EntityUid uid, PsionicInvisibilityUsedComponent component, PsionicInsulationEvent args) + { + if (!TryComp(uid, out var psionic)) + return; + + RemComp(uid); + _stunSystem.TryParalyze(uid, TimeSpan.FromSeconds(4f / psionic.Dampening + psionic.Amplification), false); + } } } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs b/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs similarity index 86% rename from Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs rename to Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs index 707e8d61298..995bebb0fbe 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs @@ -17,7 +17,7 @@ using Content.Shared.Actions.Events; using Robust.Server.Audio; -namespace Content.Server.Abilities.Psionics +namespace Content.Server.Psionics.Abilities { public sealed class PsionicRegenerationPowerSystem : EntitySystem { @@ -28,7 +28,6 @@ public sealed class PsionicRegenerationPowerSystem : EntitySystem [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly ExamineSystemShared _examine = default!; public override void Initialize() { @@ -51,11 +50,16 @@ private void OnInit(EntityUid uid, PsionicRegenerationPowerComponent component, { psionic.ActivePowers.Add(component); psionic.PsychicFeedback.Add(component.RegenerationFeedback); + psionic.Amplification += 0.5f; + psionic.Dampening += 0.5f; } } private void OnPowerUsed(EntityUid uid, PsionicRegenerationPowerComponent component, PsionicRegenerationPowerActionEvent args) { + if (!TryComp(uid, out var psionic)) + return; + var ev = new PsionicRegenerationDoAfterEvent(_gameTiming.CurTime); var doAfterArgs = new DoAfterArgs(EntityManager, uid, component.UseDelay, ev, uid); @@ -72,12 +76,16 @@ private void OnPowerUsed(EntityUid uid, PsionicRegenerationPowerComponent compon _popupSystem.PopupEntity(Loc.GetString("psionic-regeneration-begin", ("entity", uid)), uid, // TODO: Use LoS-based Filter when one is available. - Filter.Pvs(uid).RemoveWhereAttachedEntity(entity => !_examine.InRangeUnOccluded(uid, entity, ExamineRange, null)), + Filter.Pvs(uid).RemoveWhereAttachedEntity(entity => !ExamineSystemShared.InRangeUnOccluded(uid, entity, ExamineRange, null)), true, PopupType.Medium); _audioSystem.PlayPvs(component.SoundUse, uid, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); - _psionics.LogPowerUsed(uid, "psionic regeneration"); + + _psionics.LogPowerUsed(uid, "psionic regeneration", + (int) Math.Round(6 * psionic.Amplification - psionic.Dampening), + (int) Math.Round(8 * psionic.Amplification - psionic.Dampening)); + args.Handled = true; } @@ -90,6 +98,9 @@ private void OnPowerUsed(EntityUid uid, PsionicRegenerationPowerComponent compon /// private void OnMobStateChangedEvent(EntityUid uid, PsionicRegenerationPowerComponent component, MobStateChangedEvent args) { + if (!TryComp(uid, out var psionic)) + return; + if (HasComp(uid)) return; @@ -114,11 +125,15 @@ private void OnMobStateChangedEvent(EntityUid uid, PsionicRegenerationPowerCompo _popupSystem.PopupEntity(Loc.GetString("psionic-regeneration-self-revive", ("entity", uid)), uid, // TODO: Use LoS-based Filter when one is available. - Filter.Pvs(uid).RemoveWhereAttachedEntity(entity => !_examine.InRangeUnOccluded(uid, entity, ExamineRange, null)), + Filter.Pvs(uid).RemoveWhereAttachedEntity(entity => !ExamineSystemShared.InRangeUnOccluded(uid, entity, ExamineRange, null)), true, PopupType.MediumCaution); _audioSystem.PlayPvs(component.SoundUse, uid, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); - _psionics.LogPowerUsed(uid, "psionic regeneration", 20, 40); + + _psionics.LogPowerUsed(uid, "psionic regeneration", + (int) Math.Round(10 * psionic.Amplification - 2 * psionic.Dampening), + (int) Math.Round(20 * psionic.Amplification - 2 * psionic.Dampening)); + _actions.StartUseDelay(component.PsionicRegenerationActionEntity); } } @@ -132,6 +147,8 @@ private void OnShutdown(EntityUid uid, PsionicRegenerationPowerComponent compone { psionic.ActivePowers.Remove(component); psionic.PsychicFeedback.Remove(component.RegenerationFeedback); + psionic.Amplification += 0.5f; + psionic.Dampening -= 0.5f; } } @@ -150,6 +167,9 @@ private void OnDoAfter(EntityUid uid, PsionicRegenerationPowerComponent componen { component.DoAfter = null; + if (!TryComp(uid, out var psionic)) + return; + if (!TryComp(uid, out var stream)) return; @@ -160,12 +180,12 @@ private void OnDoAfter(EntityUid uid, PsionicRegenerationPowerComponent componen var percentageComplete = Math.Min(1f, (_gameTiming.CurTime - args.StartedAt).TotalSeconds / component.UseDelay); var solution = new Solution(); - solution.AddReagent("PsionicRegenerationEssence", FixedPoint2.New(component.EssenceAmount * percentageComplete)); + solution.AddReagent("PsionicRegenerationEssence", FixedPoint2.New(component.EssenceAmount * percentageComplete + 10f * psionic.Dampening)); _bloodstreamSystem.TryAddToChemicals(uid, solution, stream); if (component.SelfRevive == true) { var critSolution = new Solution(); - critSolution.AddReagent("Epinephrine", 10); + critSolution.AddReagent("Epinephrine", MathF.MinMagnitude(5 + 5 * psionic.Dampening, 15)); _bloodstreamSystem.TryAddToChemicals(uid, critSolution, stream); component.SelfRevive = false; } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs similarity index 50% rename from Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs rename to Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs index 8300b204dca..d93b17f55cc 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs @@ -1,24 +1,20 @@ using Content.Shared.Actions; using Content.Shared.Abilities.Psionics; using Content.Server.Atmos.Components; -using Content.Server.Atmos.EntitySystems; -using Content.Server.Popups; -using Robust.Shared.Prototypes; -using Robust.Shared.Timing; -using Content.Server.Mind; +using Content.Server.Weapons.Ranged.Systems; +using Robust.Server.GameObjects; using Content.Shared.Actions.Events; +using Content.Server.Explosion.Components; -namespace Content.Server.Abilities.Psionics +namespace Content.Server.Psionics.Abilities { public sealed class PyrokinesisPowerSystem : EntitySystem { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; - [Dependency] private readonly FlammableSystem _flammableSystem = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; - [Dependency] private readonly PopupSystem _popupSystem = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly MindSystem _mindSystem = default!; + [Dependency] private readonly GunSystem _gunSystem = default!; + [Dependency] private readonly SharedTransformSystem _transformSystem = default!; + [Dependency] private readonly PhysicsSystem _physics = default!; public override void Initialize() { @@ -30,14 +26,15 @@ public override void Initialize() private void OnInit(EntityUid uid, PyrokinesisPowerComponent component, ComponentInit args) { - _actions.AddAction(uid, ref component.PyrokinesisActionEntity, component.PyrokinesisActionId ); - _actions.TryGetActionData( component.PyrokinesisActionEntity, out var actionData ); + _actions.AddAction(uid, ref component.PyrokinesisActionEntity, component.PyrokinesisActionId); + _actions.TryGetActionData( component.PyrokinesisActionEntity, out var actionData); if (actionData is { UseDelay: not null }) _actions.StartUseDelay(component.PyrokinesisActionEntity); if (TryComp(uid, out var psionic)) { psionic.ActivePowers.Add(component); psionic.PsychicFeedback.Add(component.PyrokinesisFeedback); + psionic.Amplification += 1f; } } @@ -48,20 +45,39 @@ private void OnShutdown(EntityUid uid, PyrokinesisPowerComponent component, Comp { psionic.ActivePowers.Remove(component); psionic.PsychicFeedback.Remove(component.PyrokinesisFeedback); + psionic.Amplification += 1f; } } private void OnPowerUsed(PyrokinesisPowerActionEvent args) { - if (!TryComp(args.Target, out var flammableComponent)) + if (!TryComp(args.Performer, out var psionic)) return; - flammableComponent.FireStacks += 5; - _flammableSystem.Ignite(args.Target, args.Target); - _popupSystem.PopupEntity(Loc.GetString("pyrokinesis-power-used", ("target", args.Target)), args.Target, Shared.Popups.PopupType.LargeCaution); + if (!HasComp(args.Performer)) + { + var ent = Spawn("ProjectileAnomalyFireball"); + + if (TryComp(ent, out var fireball)) + { + fireball.MaxIntensity = (int) MathF.Round(20 * psionic.Amplification - 10 * psionic.Dampening); + + if (psionic.Amplification > 5 && EnsureComp(ent, out var ignite)) + { + ignite.FireStacks = 0.1f * psionic.Amplification - 0.1f * psionic.Dampening; + } + } - _psionics.LogPowerUsed(args.Performer, "pyrokinesis"); - args.Handled = true; + var userVelocity = _physics.GetMapLinearVelocity(args.Performer); + var direction = args.Target.ToMapPos(EntityManager, _transformSystem); + + _gunSystem.ShootProjectile(ent, direction, userVelocity, args.Performer, args.Performer, 20f); + + _psionics.LogPowerUsed(args.Performer, "pyrokinesis", + (int) MathF.Round(6f * psionic.Amplification - psionic.Dampening), + (int) MathF.Round(8f * psionic.Amplification - psionic.Dampening)); + args.Handled = true; + } } } } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs b/Content.Server/Psionics/Abilities/TelegnosisPowerSystem.cs similarity index 52% rename from Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs rename to Content.Server/Psionics/Abilities/TelegnosisPowerSystem.cs index 00d06e6dd28..aa0f5487c08 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/TelegnosisPowerSystem.cs @@ -1,23 +1,17 @@ using Content.Shared.Actions; -using Content.Shared.StatusEffect; using Content.Shared.Abilities.Psionics; using Content.Shared.Mind.Components; -using Robust.Shared.Prototypes; -using Robust.Shared.Timing; -using Content.Server.Mind; using Content.Shared.Actions.Events; +using Content.Shared.Mobs; +using Content.Shared.Storage.Components; -namespace Content.Server.Abilities.Psionics +namespace Content.Server.Psionics.Abilities { public sealed class TelegnosisPowerSystem : EntitySystem { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly StatusEffectsSystem _statusEffects = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly MindSwapPowerSystem _mindSwap = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly MindSystem _mindSystem = default!; public override void Initialize() { @@ -26,6 +20,9 @@ public override void Initialize() SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent(OnPowerUsed); SubscribeLocalEvent(OnMindRemoved); + SubscribeLocalEvent(OnDispelled); + SubscribeLocalEvent(OnMobstateChanged); + SubscribeLocalEvent(OnStorageInsertAttempt); } private void OnInit(EntityUid uid, TelegnosisPowerComponent component, ComponentInit args) @@ -38,6 +35,8 @@ private void OnInit(EntityUid uid, TelegnosisPowerComponent component, Component { psionic.ActivePowers.Add(component); psionic.PsychicFeedback.Add(component.TelegnosisFeedback); + psionic.Amplification += 0.3f; + psionic.Dampening += 0.3f; } } @@ -48,21 +47,60 @@ private void OnShutdown(EntityUid uid, TelegnosisPowerComponent component, Compo { psionic.ActivePowers.Remove(component); psionic.PsychicFeedback.Remove(component.TelegnosisFeedback); + psionic.Amplification -= 0.3f; + psionic.Dampening -= 0.3f; } } private void OnPowerUsed(EntityUid uid, TelegnosisPowerComponent component, TelegnosisPowerActionEvent args) { + if (!TryComp(uid, out var psionic)) + return; + + if (HasComp(uid)) + return; + var projection = Spawn(component.Prototype, Transform(uid).Coordinates); Transform(projection).AttachToGridOrMap(); + component.OriginalEntity = uid; + component.IsProjecting = true; + component.ProjectionUid = projection; _mindSwap.Swap(uid, projection); - _psionics.LogPowerUsed(uid, "telegnosis"); + if (EnsureComp(projection, out var projectionComponent)) + projectionComponent.OriginalEntity = uid; + + _psionics.LogPowerUsed(uid, "telegnosis", + (int) Math.Round(8f * psionic.Amplification - psionic.Dampening), + (int) Math.Round(12f * psionic.Amplification - psionic.Dampening)); + args.Handled = true; } private void OnMindRemoved(EntityUid uid, TelegnosticProjectionComponent component, MindRemovedMessage args) { + if (TryComp(component.OriginalEntity, out var originalEntity)) + originalEntity.IsProjecting = false; + QueueDel(uid); } + + private void OnDispelled(EntityUid uid, TelegnosisPowerComponent component, DispelledEvent args) + { + if (component.IsProjecting) + _mindSwap.Swap(uid, component.ProjectionUid); + } + + private void OnMobstateChanged(EntityUid uid, TelegnosisPowerComponent component, MobStateChangedEvent args) + { + if (component.IsProjecting && args.NewMobState is MobState.Critical + || component.IsProjecting && args.NewMobState is MobState.Dead) + _mindSwap.Swap(uid, component.ProjectionUid); + } + + private void OnStorageInsertAttempt(EntityUid uid, TelegnosisPowerComponent component, InsertIntoEntityStorageAttemptEvent args) + { + if (component.IsProjecting) + _mindSwap.Swap(uid, component.ProjectionUid); + } } } diff --git a/Content.Server/Nyanotrasen/Psionics/AcceptPsionicsEui.cs b/Content.Server/Psionics/AcceptPsionicsEui.cs similarity index 95% rename from Content.Server/Nyanotrasen/Psionics/AcceptPsionicsEui.cs rename to Content.Server/Psionics/AcceptPsionicsEui.cs index 80fd8946f28..7c652664c64 100644 --- a/Content.Server/Nyanotrasen/Psionics/AcceptPsionicsEui.cs +++ b/Content.Server/Psionics/AcceptPsionicsEui.cs @@ -1,7 +1,7 @@ using Content.Shared.Psionics; using Content.Shared.Eui; using Content.Server.EUI; -using Content.Server.Abilities.Psionics; +using Content.Server.Psionics.Abilities; namespace Content.Server.Psionics { diff --git a/Content.Server/Nyanotrasen/Psionics/AntiPsychicWeaponComponent.cs b/Content.Server/Psionics/AntiPsychicWeaponComponent.cs similarity index 100% rename from Content.Server/Nyanotrasen/Psionics/AntiPsychicWeaponComponent.cs rename to Content.Server/Psionics/AntiPsychicWeaponComponent.cs diff --git a/Content.Server/Nyanotrasen/Audio/GlimmerSoundComponent.cs b/Content.Server/Psionics/Audio/GlimmerSoundComponent.cs similarity index 80% rename from Content.Server/Nyanotrasen/Audio/GlimmerSoundComponent.cs rename to Content.Server/Psionics/Audio/GlimmerSoundComponent.cs index 850be3e831c..9a6c62381be 100644 --- a/Content.Server/Nyanotrasen/Audio/GlimmerSoundComponent.cs +++ b/Content.Server/Psionics/Audio/GlimmerSoundComponent.cs @@ -2,12 +2,8 @@ using Content.Shared.Audio; using Content.Shared.Psionics.Glimmer; using Robust.Shared.Audio; -using Robust.Shared.ComponentTrees; -using Robust.Shared.GameStates; -using Robust.Shared.Physics; -using Robust.Shared.Serialization; -namespace Content.Server.Audio +namespace Content.Server.Psionics.Audio { [RegisterComponent] [Access(typeof(SharedAmbientSoundSystem), typeof(GlimmerReactiveSystem))] diff --git a/Content.Server/Nyanotrasen/Psionics/Dreams/DreamSystem.cs b/Content.Server/Psionics/Dreams/DreamSystem.cs similarity index 98% rename from Content.Server/Nyanotrasen/Psionics/Dreams/DreamSystem.cs rename to Content.Server/Psionics/Dreams/DreamSystem.cs index d6067717c94..15e1593a859 100644 --- a/Content.Server/Nyanotrasen/Psionics/Dreams/DreamSystem.cs +++ b/Content.Server/Psionics/Dreams/DreamSystem.cs @@ -4,7 +4,6 @@ using Content.Server.Chat.Managers; using Robust.Shared.Random; using Robust.Shared.Prototypes; -using Robust.Server.GameObjects; using Robust.Shared.Player; namespace Content.Server.Psionics.Dreams diff --git a/Content.Server/Nyanotrasen/Psionics/Glimmer/GlimmerCommands.cs b/Content.Server/Psionics/Glimmer/GlimmerCommands.cs similarity index 100% rename from Content.Server/Nyanotrasen/Psionics/Glimmer/GlimmerCommands.cs rename to Content.Server/Psionics/Glimmer/GlimmerCommands.cs diff --git a/Content.Server/Nyanotrasen/Psionics/Glimmer/GlimmerReactiveSystem.cs b/Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs similarity index 100% rename from Content.Server/Nyanotrasen/Psionics/Glimmer/GlimmerReactiveSystem.cs rename to Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs diff --git a/Content.Server/Nyanotrasen/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs b/Content.Server/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs similarity index 94% rename from Content.Server/Nyanotrasen/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs rename to Content.Server/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs index f0da85ce453..57c74398b08 100644 --- a/Content.Server/Nyanotrasen/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs +++ b/Content.Server/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs @@ -4,7 +4,6 @@ using Content.Shared.CCVar; using Content.Shared.Psionics.Glimmer; using Content.Shared.GameTicking; -using Content.Server.CartridgeLoader.Cartridges; namespace Content.Server.Psionics.Glimmer { @@ -17,7 +16,6 @@ public sealed class PassiveGlimmerReductionSystem : EntitySystem [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; - [Dependency] private readonly GlimmerMonitorCartridgeSystem _cartridgeSys = default!; /// List of glimmer values spaced by minute. public List GlimmerValues = new(); diff --git a/Content.Server/Nyanotrasen/Psionics/Glimmer/Structures/GlimmerSourceComponent.cs b/Content.Server/Psionics/Glimmer/Structures/GlimmerSourceComponent.cs similarity index 100% rename from Content.Server/Nyanotrasen/Psionics/Glimmer/Structures/GlimmerSourceComponent.cs rename to Content.Server/Psionics/Glimmer/Structures/GlimmerSourceComponent.cs diff --git a/Content.Server/Nyanotrasen/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs b/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs similarity index 100% rename from Content.Server/Nyanotrasen/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs rename to Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs diff --git a/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibilitySystem.cs b/Content.Server/Psionics/Invisibility/PsionicInvisibilitySystem.cs similarity index 98% rename from Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibilitySystem.cs rename to Content.Server/Psionics/Invisibility/PsionicInvisibilitySystem.cs index 1c9cb55f2dd..f85460a69f5 100644 --- a/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibilitySystem.cs +++ b/Content.Server/Psionics/Invisibility/PsionicInvisibilitySystem.cs @@ -1,4 +1,5 @@ using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics; using Content.Server.Abilities.Psionics; using Content.Shared.Eye; using Content.Server.NPC.Systems; @@ -44,6 +45,8 @@ private void OnInit(EntityUid uid, PotentialPsionicComponent component, Componen /// private void OnInsulInit(EntityUid uid, PsionicInsulationComponent component, ComponentInit args) { + RaiseLocalEvent(uid, new PsionicInsulationEvent()); + if (HasComp(uid)) _invisSystem.ToggleInvisibility(uid); diff --git a/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs b/Content.Server/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs similarity index 100% rename from Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs rename to Content.Server/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs diff --git a/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs b/Content.Server/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs similarity index 100% rename from Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs rename to Content.Server/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs diff --git a/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicallyInvisibleComponent.cs b/Content.Server/Psionics/Invisibility/PsionicallyInvisibleComponent.cs similarity index 100% rename from Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicallyInvisibleComponent.cs rename to Content.Server/Psionics/Invisibility/PsionicallyInvisibleComponent.cs diff --git a/Content.Server/Nyanotrasen/Psionics/PotentialPsionicComponent.cs b/Content.Server/Psionics/PotentialPsionicComponent.cs similarity index 100% rename from Content.Server/Nyanotrasen/Psionics/PotentialPsionicComponent.cs rename to Content.Server/Psionics/PotentialPsionicComponent.cs diff --git a/Content.Server/Nyanotrasen/Psionics/PsionicAwaitingPlayerComponent.cs b/Content.Server/Psionics/PsionicAwaitingPlayerComponent.cs similarity index 100% rename from Content.Server/Nyanotrasen/Psionics/PsionicAwaitingPlayerComponent.cs rename to Content.Server/Psionics/PsionicAwaitingPlayerComponent.cs diff --git a/Content.Server/Nyanotrasen/Psionics/PsionicBonusChanceComponent.cs b/Content.Server/Psionics/PsionicBonusChanceComponent.cs similarity index 100% rename from Content.Server/Nyanotrasen/Psionics/PsionicBonusChanceComponent.cs rename to Content.Server/Psionics/PsionicBonusChanceComponent.cs diff --git a/Content.Server/Nyanotrasen/Psionics/PsionicsCommands.cs b/Content.Server/Psionics/PsionicsCommands.cs similarity index 100% rename from Content.Server/Nyanotrasen/Psionics/PsionicsCommands.cs rename to Content.Server/Psionics/PsionicsCommands.cs diff --git a/Content.Server/Nyanotrasen/Psionics/PsionicsSystem.cs b/Content.Server/Psionics/PsionicsSystem.cs similarity index 79% rename from Content.Server/Nyanotrasen/Psionics/PsionicsSystem.cs rename to Content.Server/Psionics/PsionicsSystem.cs index 9da293df0b5..7920a09844a 100644 --- a/Content.Server/Nyanotrasen/Psionics/PsionicsSystem.cs +++ b/Content.Server/Psionics/PsionicsSystem.cs @@ -4,13 +4,14 @@ using Content.Shared.Weapons.Melee.Events; using Content.Shared.Damage.Events; using Content.Shared.CCVar; -using Content.Server.Abilities.Psionics; +using Content.Server.Psionics.Abilities; using Content.Server.Electrocution; using Content.Server.NPC.Components; using Content.Server.NPC.Systems; using Robust.Shared.Audio.Systems; using Robust.Shared.Configuration; using Robust.Shared.Random; +using Content.Shared.Psionics; namespace Content.Server.Psionics { @@ -49,6 +50,9 @@ public override void Initialize() SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnRemove); + + SubscribeLocalEvent(OnInnatePsiInit); + SubscribeLocalEvent(OnInnatePsiShutdown); } private void OnStartup(EntityUid uid, PotentialPsionicComponent component, MapInitEvent args) @@ -84,6 +88,16 @@ private void OnMeleeHit(EntityUid uid, AntiPsionicWeaponComponent component, Mel private void OnInit(EntityUid uid, PsionicComponent component, ComponentInit args) { + component.Amplification = _random.NextFloat(0.3f, 1.2f); + component.Dampening = _random.NextFloat(0.3f, 1.2f); + + if (TryComp(uid, out var innatePsicaster)) + { + component.Amplification += innatePsicaster.Amplification; + component.Dampening += innatePsicaster.Dampening; + component.InnatePsiChecked = true; + } + if (!component.Removable) return; @@ -98,7 +112,7 @@ private void OnInit(EntityUid uid, PsionicComponent component, ComponentInit arg private void OnRemove(EntityUid uid, PsionicComponent component, ComponentRemove args) { - if (!TryComp(uid, out var factions)) + if (!HasComp(uid)) return; _npcFactonSystem.RemoveFaction(uid, "PsionicInterloper"); @@ -138,7 +152,7 @@ public void RollPsionics(EntityUid uid, PotentialPsionicComponent component, boo } if (applyGlimmer) - chance += ((float) _glimmerSystem.Glimmer / 1000); + chance += (float) _glimmerSystem.Glimmer / 1000; chance *= multiplier; @@ -159,5 +173,24 @@ public void RerollPsionics(EntityUid uid, PotentialPsionicComponent? psionic = n RollPsionics(uid, psionic, multiplier: bonusMuliplier); psionic.Rerolled = true; } + + private void OnInnatePsiInit(EntityUid uid, InnatePsicasterComponent component, ComponentInit args) + { + if (EnsureComp(uid, out var psionic) && !psionic.InnatePsiChecked) + { + psionic.Amplification += component.Amplification; + psionic.Dampening += component.Dampening; + psionic.InnatePsiChecked = true; + } + } + + private void OnInnatePsiShutdown(EntityUid uid, InnatePsicasterComponent component, ComponentShutdown args) + { + if (TryComp(uid, out var psionic)) + { + psionic.Amplification -= component.Amplification; + psionic.Dampening -= component.Amplification; + } + } } } diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs index 2f86615b836..a4fc8b632ca 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs @@ -12,7 +12,7 @@ public sealed partial class PsionicRegenerationPowerComponent : Component public DoAfterId? DoAfter; [DataField("essence")] - public float EssenceAmount = 20; + public float EssenceAmount = 10; [DataField("useDelay")] public float UseDelay = 8f; diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs index cd298c3ec0f..e1a523c50d3 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs @@ -22,5 +22,8 @@ public sealed partial class TelegnosisPowerComponent : Component [DataField("telegnosisFeedback")] public string TelegnosisFeedback = "telegnosis-feedback"; + public EntityUid OriginalEntity = default!; + public EntityUid ProjectionUid = default!; + public bool IsProjecting = false; } } diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs index 9d627cb42d8..93359f2758c 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs @@ -2,5 +2,7 @@ namespace Content.Shared.Abilities.Psionics { [RegisterComponent] public sealed partial class TelegnosticProjectionComponent : Component - {} -} \ No newline at end of file + { + public EntityUid OriginalEntity = default!; + } +} diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicComponent.cs index 7c7befa33c3..cdccee393c4 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicComponent.cs @@ -20,9 +20,11 @@ public sealed partial class PsionicComponent : Component public List PsychicFeedback= new(); [DataField("amplification")] - public float Amplification = 1f; + public float Amplification = default!; [DataField("dampening")] - public float Dampening = 1f; + public float Dampening = default!; + public bool Telepath = false; + public bool InnatePsiChecked = false; } } diff --git a/Content.Shared/Nyanotrasen/Actions/Events/PyrokinesisPowerActionEvent.cs b/Content.Shared/Nyanotrasen/Actions/Events/PyrokinesisPowerActionEvent.cs index 896ec0bb63d..4639aadd55b 100644 --- a/Content.Shared/Nyanotrasen/Actions/Events/PyrokinesisPowerActionEvent.cs +++ b/Content.Shared/Nyanotrasen/Actions/Events/PyrokinesisPowerActionEvent.cs @@ -1,2 +1,4 @@ namespace Content.Shared.Actions.Events; -public sealed partial class PyrokinesisPowerActionEvent : EntityTargetActionEvent {} +public sealed partial class PyrokinesisPowerActionEvent : WorldTargetActionEvent {} + + diff --git a/Content.Shared/Nyanotrasen/Psionics/SharedPsionicSystem.Insulated.cs b/Content.Shared/Nyanotrasen/Psionics/SharedPsionicSystem.Insulated.cs index c59f98db7f0..5c89f39354c 100644 --- a/Content.Shared/Nyanotrasen/Psionics/SharedPsionicSystem.Insulated.cs +++ b/Content.Shared/Nyanotrasen/Psionics/SharedPsionicSystem.Insulated.cs @@ -1,19 +1,4 @@ -using Content.Shared.Abilities.Psionics; - namespace Content.Shared.Psionics { - public sealed class PsionicInsulationSystem : EntitySystem - { - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnInsulated); - } - - public void OnInsulated(EntityUid uid, PsionicInsulationComponent component, ComponentInit args) - { - RaiseLocalEvent(uid, new PsionicInsulationEvent()); - } - } public readonly record struct PsionicInsulationEvent; } diff --git a/Resources/Prototypes/Nyanotrasen/Actions/types.yml b/Resources/Prototypes/Nyanotrasen/Actions/types.yml index 376d92e3efb..71a92ec4516 100644 --- a/Resources/Prototypes/Nyanotrasen/Actions/types.yml +++ b/Resources/Prototypes/Nyanotrasen/Actions/types.yml @@ -94,7 +94,7 @@ description: action-description-pyrokinesis noSpawn: true components: - - type: EntityTargetAction + - type: WorldTargetAction icon: Nyanotrasen/Interface/VerbIcons/pyrokinesis.png useDelay: 50 range: 6 diff --git a/Resources/Prototypes/Nyanotrasen/psionicPowers.yml b/Resources/Prototypes/Nyanotrasen/psionicPowers.yml index cb3f88d6a4a..b577d419e38 100644 --- a/Resources/Prototypes/Nyanotrasen/psionicPowers.yml +++ b/Resources/Prototypes/Nyanotrasen/psionicPowers.yml @@ -9,3 +9,4 @@ PsionicInvisibilityPower: 0.15 MindSwapPower: 0.15 NoosphericZapPower: 0.15 + PyrokinesisPower: 0.15 From 834e0ebb7fb5d26502bf457746755d8c208f3a2c Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 14 May 2024 20:23:41 -0400 Subject: [PATCH 09/82] guh --- Content.Server/Psionics/PsionicsSystem.cs | 33 ++----------------- .../Abilities/Psionics/PsionicComponent.cs | 4 +-- 2 files changed, 4 insertions(+), 33 deletions(-) diff --git a/Content.Server/Psionics/PsionicsSystem.cs b/Content.Server/Psionics/PsionicsSystem.cs index 7920a09844a..06d0a51c84d 100644 --- a/Content.Server/Psionics/PsionicsSystem.cs +++ b/Content.Server/Psionics/PsionicsSystem.cs @@ -50,9 +50,6 @@ public override void Initialize() SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnRemove); - - SubscribeLocalEvent(OnInnatePsiInit); - SubscribeLocalEvent(OnInnatePsiShutdown); } private void OnStartup(EntityUid uid, PotentialPsionicComponent component, MapInitEvent args) @@ -88,15 +85,8 @@ private void OnMeleeHit(EntityUid uid, AntiPsionicWeaponComponent component, Mel private void OnInit(EntityUid uid, PsionicComponent component, ComponentInit args) { - component.Amplification = _random.NextFloat(0.3f, 1.2f); - component.Dampening = _random.NextFloat(0.3f, 1.2f); - - if (TryComp(uid, out var innatePsicaster)) - { - component.Amplification += innatePsicaster.Amplification; - component.Dampening += innatePsicaster.Dampening; - component.InnatePsiChecked = true; - } + component.Amplification = _random.NextFloat(0.3f, 1.1f); + component.Dampening = _random.NextFloat(0.3f, 1.1f); if (!component.Removable) return; @@ -173,24 +163,5 @@ public void RerollPsionics(EntityUid uid, PotentialPsionicComponent? psionic = n RollPsionics(uid, psionic, multiplier: bonusMuliplier); psionic.Rerolled = true; } - - private void OnInnatePsiInit(EntityUid uid, InnatePsicasterComponent component, ComponentInit args) - { - if (EnsureComp(uid, out var psionic) && !psionic.InnatePsiChecked) - { - psionic.Amplification += component.Amplification; - psionic.Dampening += component.Dampening; - psionic.InnatePsiChecked = true; - } - } - - private void OnInnatePsiShutdown(EntityUid uid, InnatePsicasterComponent component, ComponentShutdown args) - { - if (TryComp(uid, out var psionic)) - { - psionic.Amplification -= component.Amplification; - psionic.Dampening -= component.Amplification; - } - } } } diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicComponent.cs index cdccee393c4..e1574485074 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicComponent.cs @@ -20,10 +20,10 @@ public sealed partial class PsionicComponent : Component public List PsychicFeedback= new(); [DataField("amplification")] - public float Amplification = default!; + public float Amplification = 0.1f; [DataField("dampening")] - public float Dampening = default!; + public float Dampening = 0.1f; public bool Telepath = false; public bool InnatePsiChecked = false; } From 372671eb2a970e3cfb4756d1b6767943b6f75007 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 14 May 2024 20:36:35 -0400 Subject: [PATCH 10/82] More migrations --- Content.Server/Psionics/Abilities/DispelPowerSystem.cs | 2 +- Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs | 2 +- Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs | 2 +- Content.Server/Psionics/Abilities/NoosphericZapPowerSystem.cs | 2 +- Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs | 2 +- .../Psionics/Abilities/PsionicInvisibilityPowerSystem.cs | 2 +- .../Psionics/Abilities/PsionicRegenerationPowerSystem.cs | 2 +- Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs | 2 +- Content.Server/Psionics/Abilities/TelegnosisPowerSystem.cs | 2 +- Content.Server/Psionics/PsionicsSystem.cs | 2 +- .../Psionics/Abilities/AcceptPsionicsEuiMessage.cs | 0 .../Psionics/Abilities/Dispel/DamageOnDispelComponent.cs | 2 +- .../Psionics/Abilities/Dispel/DispelPowerComponent.cs | 2 +- .../Psionics/Abilities/Dispel/DispellableComponent.cs | 2 +- .../Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs | 2 +- .../Psionics/Abilities/MassSleep/MassSleepPowerSystem.cs | 2 +- .../Abilities/Metapsionics/MetapsionicPowerComponent.cs | 2 +- .../Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs | 2 +- .../Abilities/NoosphericZap/NoosphericZapPowerComponent.cs | 2 +- .../PsionicInvisibility/PsionicInvisibilityPowerComponent.cs | 2 +- .../PsionicInvisibility/PsionicInvisibilityUsedComponent.cs | 3 ++- .../PsionicRegeneration/PsionicRegenerationPowerComponent.cs | 2 +- .../Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs | 2 +- .../Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs | 2 +- .../Abilities/Telegnosis/TelegnosticProjectionComponent.cs | 2 +- Content.Shared/{Nyanotrasen => }/Psionics/Events.cs | 0 .../{Nyanotrasen => }/Psionics/Glimmer/GlimmerSystem.cs | 0 .../Psionics/Glimmer/SharedGlimmerReactiveComponent.cs | 0 .../Psionics/Glimmer/SharedGlimmerReactiveVisuals.cs | 0 .../Psionics/Items/ClothingGrantPsionicPowerComponent.cs | 2 +- .../Abilities => }/Psionics/Items/HeadCageComponent.cs | 2 +- .../Abilities => }/Psionics/Items/HeadCagedComponent.cs | 2 +- .../Abilities => }/Psionics/Items/PsionicItemsSystem.cs | 2 +- .../Abilities => }/Psionics/Items/TinfoilHatComponent.cs | 2 +- .../{Nyanotrasen/Abilities => }/Psionics/PsionicComponent.cs | 2 +- .../Abilities => }/Psionics/PsionicInsulationComponent.cs | 2 +- .../Abilities => }/Psionics/PsionicsDisabledComponent.cs | 2 +- .../Abilities => }/Psionics/SharedPsionicAbilitiesSystem.cs | 3 ++- .../Psionics/SharedPsionicSystem.Insulated.cs | 0 39 files changed, 35 insertions(+), 33 deletions(-) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/AcceptPsionicsEuiMessage.cs (100%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs (89%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/Dispel/DispelPowerComponent.cs (93%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/Dispel/DispellableComponent.cs (69%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs (93%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/MassSleep/MassSleepPowerSystem.cs (98%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs (96%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs (93%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs (93%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs (94%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs (94%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs (96%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs (94%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs (96%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs (79%) rename Content.Shared/{Nyanotrasen => }/Psionics/Events.cs (100%) rename Content.Shared/{Nyanotrasen => }/Psionics/Glimmer/GlimmerSystem.cs (100%) rename Content.Shared/{Nyanotrasen => }/Psionics/Glimmer/SharedGlimmerReactiveComponent.cs (100%) rename Content.Shared/{Nyanotrasen => }/Psionics/Glimmer/SharedGlimmerReactiveVisuals.cs (100%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Items/ClothingGrantPsionicPowerComponent.cs (84%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Items/HeadCageComponent.cs (96%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Items/HeadCagedComponent.cs (81%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Items/PsionicItemsSystem.cs (98%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Items/TinfoilHatComponent.cs (90%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/PsionicComponent.cs (95%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/PsionicInsulationComponent.cs (82%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/PsionicsDisabledComponent.cs (84%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/SharedPsionicAbilitiesSystem.cs (98%) rename Content.Shared/{Nyanotrasen => }/Psionics/SharedPsionicSystem.Insulated.cs (100%) diff --git a/Content.Server/Psionics/Abilities/DispelPowerSystem.cs b/Content.Server/Psionics/Abilities/DispelPowerSystem.cs index 14e3ea14aeb..cb7ef8313cd 100644 --- a/Content.Server/Psionics/Abilities/DispelPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/DispelPowerSystem.cs @@ -1,6 +1,6 @@ using Content.Shared.Actions; using Content.Shared.StatusEffect; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Damage; using Content.Shared.Revenant.Components; using Content.Server.Guardian; diff --git a/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs b/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs index 6279aa88622..c30abd84f57 100644 --- a/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs @@ -1,6 +1,6 @@ using Content.Shared.Actions; using Content.Shared.Actions.Events; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.DoAfter; using Content.Shared.Examine; using static Content.Shared.Examine.ExamineSystemShared; diff --git a/Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs b/Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs index 0beea77aa53..1e50a586b4f 100644 --- a/Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs @@ -1,5 +1,5 @@ using Content.Shared.Actions; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Psionics; using Content.Shared.Speech; using Content.Shared.Stealth.Components; diff --git a/Content.Server/Psionics/Abilities/NoosphericZapPowerSystem.cs b/Content.Server/Psionics/Abilities/NoosphericZapPowerSystem.cs index 7e4ba64afde..ce55cb3bb7d 100644 --- a/Content.Server/Psionics/Abilities/NoosphericZapPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/NoosphericZapPowerSystem.cs @@ -1,5 +1,5 @@ using Content.Shared.Actions; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.StatusEffect; using Content.Server.Electrocution; using Content.Server.Stunnable; diff --git a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs index 1bfacb0f119..74e6ed3b091 100644 --- a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs @@ -1,4 +1,4 @@ -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Actions; using Content.Shared.Psionics.Glimmer; using Content.Shared.Random; diff --git a/Content.Server/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs b/Content.Server/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs index 77690c49f48..9422dfb9acf 100644 --- a/Content.Server/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs @@ -1,6 +1,6 @@ using Content.Server.DoAfter; using Content.Shared.Actions; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Damage; using Content.Shared.DoAfter; using Content.Shared.Stunnable; diff --git a/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs b/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs index 995bebb0fbe..e6ef1ac6d73 100644 --- a/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs @@ -3,7 +3,7 @@ using Content.Server.Body.Components; using Content.Server.Body.Systems; using Content.Server.DoAfter; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Actions; using Content.Shared.Chemistry.Components; using Content.Shared.DoAfter; diff --git a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs index d93b17f55cc..444675d9b3f 100644 --- a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs @@ -1,5 +1,5 @@ using Content.Shared.Actions; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Server.Atmos.Components; using Content.Server.Weapons.Ranged.Systems; using Robust.Server.GameObjects; diff --git a/Content.Server/Psionics/Abilities/TelegnosisPowerSystem.cs b/Content.Server/Psionics/Abilities/TelegnosisPowerSystem.cs index aa0f5487c08..f03b001fc70 100644 --- a/Content.Server/Psionics/Abilities/TelegnosisPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/TelegnosisPowerSystem.cs @@ -1,5 +1,5 @@ using Content.Shared.Actions; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Mind.Components; using Content.Shared.Actions.Events; using Content.Shared.Mobs; diff --git a/Content.Server/Psionics/PsionicsSystem.cs b/Content.Server/Psionics/PsionicsSystem.cs index 06d0a51c84d..f2cb8754326 100644 --- a/Content.Server/Psionics/PsionicsSystem.cs +++ b/Content.Server/Psionics/PsionicsSystem.cs @@ -1,4 +1,4 @@ -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.StatusEffect; using Content.Shared.Psionics.Glimmer; using Content.Shared.Weapons.Melee.Events; diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/AcceptPsionicsEuiMessage.cs b/Content.Shared/Psionics/Abilities/AcceptPsionicsEuiMessage.cs similarity index 100% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/AcceptPsionicsEuiMessage.cs rename to Content.Shared/Psionics/Abilities/AcceptPsionicsEuiMessage.cs diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs b/Content.Shared/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs similarity index 89% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs rename to Content.Shared/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs index ce86111fc4b..89168d2b259 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs +++ b/Content.Shared/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs @@ -1,6 +1,6 @@ using Content.Shared.Damage; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { /// /// Takes damage when dispelled. diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DispelPowerComponent.cs b/Content.Shared/Psionics/Abilities/Dispel/DispelPowerComponent.cs similarity index 93% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DispelPowerComponent.cs rename to Content.Shared/Psionics/Abilities/Dispel/DispelPowerComponent.cs index 837bdd96a87..1426712cf94 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DispelPowerComponent.cs +++ b/Content.Shared/Psionics/Abilities/Dispel/DispelPowerComponent.cs @@ -2,7 +2,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class DispelPowerComponent : Component diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DispellableComponent.cs b/Content.Shared/Psionics/Abilities/Dispel/DispellableComponent.cs similarity index 69% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DispellableComponent.cs rename to Content.Shared/Psionics/Abilities/Dispel/DispellableComponent.cs index 40352004187..4bb5ee653d2 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DispellableComponent.cs +++ b/Content.Shared/Psionics/Abilities/Dispel/DispellableComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class DispellableComponent : Component diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs b/Content.Shared/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs similarity index 93% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs rename to Content.Shared/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs index c092cacd8b8..dcd1d2c1c42 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs +++ b/Content.Shared/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs @@ -2,7 +2,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class MassSleepPowerComponent : Component diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerSystem.cs b/Content.Shared/Psionics/Abilities/MassSleep/MassSleepPowerSystem.cs similarity index 98% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerSystem.cs rename to Content.Shared/Psionics/Abilities/MassSleep/MassSleepPowerSystem.cs index e36a3c70e8a..1f2f6954e77 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerSystem.cs +++ b/Content.Shared/Psionics/Abilities/MassSleep/MassSleepPowerSystem.cs @@ -8,7 +8,7 @@ using Content.Shared.Mind; using Content.Shared.Actions.Events; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { public sealed class MassSleepPowerSystem : EntitySystem { diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs b/Content.Shared/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs similarity index 96% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs rename to Content.Shared/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs index 0e12d05dead..8570668f744 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs +++ b/Content.Shared/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs @@ -4,7 +4,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class MetapsionicPowerComponent : Component diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs b/Content.Shared/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs similarity index 93% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs rename to Content.Shared/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs index e617c48cf2d..94b73c41e38 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs +++ b/Content.Shared/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs @@ -1,7 +1,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class MindSwapPowerComponent : Component diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs b/Content.Shared/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs similarity index 93% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs rename to Content.Shared/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs index 24c144079e4..997db65e1b1 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs +++ b/Content.Shared/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs @@ -2,7 +2,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class NoosphericZapPowerComponent : Component diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs b/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs similarity index 94% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs rename to Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs index 3b29a1e4367..d9c36f5b22a 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs +++ b/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs @@ -1,7 +1,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class PsionicInvisibilityPowerComponent : Component diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs b/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs similarity index 94% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs rename to Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs index 9037b8bcdfe..2a9dd7642ba 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs +++ b/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs @@ -1,6 +1,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Abilities.Psionics + +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class PsionicInvisibilityUsedComponent : Component diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs b/Content.Shared/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs similarity index 96% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs rename to Content.Shared/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs index a4fc8b632ca..3184bf7de5b 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs +++ b/Content.Shared/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs @@ -3,7 +3,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class PsionicRegenerationPowerComponent : Component diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs b/Content.Shared/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs similarity index 94% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs rename to Content.Shared/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs index d2af000e269..1f88741b9a9 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs +++ b/Content.Shared/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs @@ -2,7 +2,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class PyrokinesisPowerComponent : Component diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs b/Content.Shared/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs similarity index 96% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs rename to Content.Shared/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs index e1a523c50d3..f1a71332b18 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs +++ b/Content.Shared/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs @@ -3,7 +3,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class TelegnosisPowerComponent : Component diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs b/Content.Shared/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs similarity index 79% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs rename to Content.Shared/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs index 93359f2758c..bc18ff9f3c2 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs +++ b/Content.Shared/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class TelegnosticProjectionComponent : Component diff --git a/Content.Shared/Nyanotrasen/Psionics/Events.cs b/Content.Shared/Psionics/Events.cs similarity index 100% rename from Content.Shared/Nyanotrasen/Psionics/Events.cs rename to Content.Shared/Psionics/Events.cs diff --git a/Content.Shared/Nyanotrasen/Psionics/Glimmer/GlimmerSystem.cs b/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs similarity index 100% rename from Content.Shared/Nyanotrasen/Psionics/Glimmer/GlimmerSystem.cs rename to Content.Shared/Psionics/Glimmer/GlimmerSystem.cs diff --git a/Content.Shared/Nyanotrasen/Psionics/Glimmer/SharedGlimmerReactiveComponent.cs b/Content.Shared/Psionics/Glimmer/SharedGlimmerReactiveComponent.cs similarity index 100% rename from Content.Shared/Nyanotrasen/Psionics/Glimmer/SharedGlimmerReactiveComponent.cs rename to Content.Shared/Psionics/Glimmer/SharedGlimmerReactiveComponent.cs diff --git a/Content.Shared/Nyanotrasen/Psionics/Glimmer/SharedGlimmerReactiveVisuals.cs b/Content.Shared/Psionics/Glimmer/SharedGlimmerReactiveVisuals.cs similarity index 100% rename from Content.Shared/Nyanotrasen/Psionics/Glimmer/SharedGlimmerReactiveVisuals.cs rename to Content.Shared/Psionics/Glimmer/SharedGlimmerReactiveVisuals.cs diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/ClothingGrantPsionicPowerComponent.cs b/Content.Shared/Psionics/Items/ClothingGrantPsionicPowerComponent.cs similarity index 84% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Items/ClothingGrantPsionicPowerComponent.cs rename to Content.Shared/Psionics/Items/ClothingGrantPsionicPowerComponent.cs index 4cbb05c8395..f09efc3064c 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/ClothingGrantPsionicPowerComponent.cs +++ b/Content.Shared/Psionics/Items/ClothingGrantPsionicPowerComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class ClothingGrantPsionicPowerComponent : Component diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/HeadCageComponent.cs b/Content.Shared/Psionics/Items/HeadCageComponent.cs similarity index 96% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Items/HeadCageComponent.cs rename to Content.Shared/Psionics/Items/HeadCageComponent.cs index acaa832860f..c03241e47c7 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/HeadCageComponent.cs +++ b/Content.Shared/Psionics/Items/HeadCageComponent.cs @@ -1,7 +1,7 @@ using System.Threading; using Robust.Shared.Audio; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class HeadCageComponent : Component diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/HeadCagedComponent.cs b/Content.Shared/Psionics/Items/HeadCagedComponent.cs similarity index 81% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Items/HeadCagedComponent.cs rename to Content.Shared/Psionics/Items/HeadCagedComponent.cs index f8af46b8878..0f826f7a05e 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/HeadCagedComponent.cs +++ b/Content.Shared/Psionics/Items/HeadCagedComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] /// diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/PsionicItemsSystem.cs b/Content.Shared/Psionics/Items/PsionicItemsSystem.cs similarity index 98% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Items/PsionicItemsSystem.cs rename to Content.Shared/Psionics/Items/PsionicItemsSystem.cs index f88acf61f3c..950353c5dfb 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/PsionicItemsSystem.cs +++ b/Content.Shared/Psionics/Items/PsionicItemsSystem.cs @@ -2,7 +2,7 @@ using Content.Shared.Clothing.Components; using Content.Shared.StatusEffect; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { public sealed class PsionicItemsSystem : EntitySystem { diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/TinfoilHatComponent.cs b/Content.Shared/Psionics/Items/TinfoilHatComponent.cs similarity index 90% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Items/TinfoilHatComponent.cs rename to Content.Shared/Psionics/Items/TinfoilHatComponent.cs index 5086b9f4977..6ef7bdc823b 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/TinfoilHatComponent.cs +++ b/Content.Shared/Psionics/Items/TinfoilHatComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class TinfoilHatComponent : Component diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicComponent.cs b/Content.Shared/Psionics/PsionicComponent.cs similarity index 95% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicComponent.cs rename to Content.Shared/Psionics/PsionicComponent.cs index e1574485074..76e629f0839 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicComponent.cs +++ b/Content.Shared/Psionics/PsionicComponent.cs @@ -1,6 +1,6 @@ using Robust.Shared.GameStates; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent, NetworkedComponent] public sealed partial class PsionicComponent : Component diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicInsulationComponent.cs b/Content.Shared/Psionics/PsionicInsulationComponent.cs similarity index 82% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicInsulationComponent.cs rename to Content.Shared/Psionics/PsionicInsulationComponent.cs index 12370da5ae4..2ab054b1f8f 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicInsulationComponent.cs +++ b/Content.Shared/Psionics/PsionicInsulationComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class PsionicInsulationComponent : Component diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicsDisabledComponent.cs b/Content.Shared/Psionics/PsionicsDisabledComponent.cs similarity index 84% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicsDisabledComponent.cs rename to Content.Shared/Psionics/PsionicsDisabledComponent.cs index 28e7157a9d2..00cf5506523 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicsDisabledComponent.cs +++ b/Content.Shared/Psionics/PsionicsDisabledComponent.cs @@ -1,6 +1,6 @@ using Robust.Shared.GameStates; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { /// /// Only use this for the status effect, please. diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/SharedPsionicAbilitiesSystem.cs b/Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs similarity index 98% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/SharedPsionicAbilitiesSystem.cs rename to Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs index 2739d5ba31a..a4b283f59ce 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/SharedPsionicAbilitiesSystem.cs +++ b/Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs @@ -4,10 +4,11 @@ using Content.Shared.Mobs.Components; using Content.Shared.Popups; using Content.Shared.Psionics.Glimmer; +using Content.Shared.Psionics.Abilities; using Robust.Shared.Random; using Robust.Shared.Serialization; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { public sealed class SharedPsionicAbilitiesSystem : EntitySystem { diff --git a/Content.Shared/Nyanotrasen/Psionics/SharedPsionicSystem.Insulated.cs b/Content.Shared/Psionics/SharedPsionicSystem.Insulated.cs similarity index 100% rename from Content.Shared/Nyanotrasen/Psionics/SharedPsionicSystem.Insulated.cs rename to Content.Shared/Psionics/SharedPsionicSystem.Insulated.cs From f3bc3d81cd17fffdc58302e566f34cab8be69595 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 14 May 2024 20:45:39 -0400 Subject: [PATCH 11/82] Final migrations --- .../Psionics/Glimmer/GlimmerReactiveVisuals.cs | 0 .../Chat => Psionics/Telepathy}/PsionicChatUpdateSystem.cs | 4 ++-- .../UI => Psionics/UserInterface}/AcceptPsionicsEUI.cs | 0 .../UI => Psionics/UserInterface}/AcceptPsionicsWindow.cs | 0 .../{Nyanotrasen => Psionics}/UserInterface/GlimmerGraph.cs | 2 +- Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs | 3 --- Content.Server/Psionics/PsionicsCommands.cs | 3 +-- Content.Server/Psionics/PsionicsSystem.cs | 1 - .../{Nyanotrasen/Chat => Psionics/Telepathy}/TSayCommand.cs | 2 +- .../Telepathy}/TelepathicRepeaterComponent.cs | 2 +- .../Telepathy/TelepathyChatSystem.cs} | 6 +++--- 11 files changed, 9 insertions(+), 14 deletions(-) rename Content.Client/{Nyanotrasen => }/Psionics/Glimmer/GlimmerReactiveVisuals.cs (100%) rename Content.Client/{Nyanotrasen/Chat => Psionics/Telepathy}/PsionicChatUpdateSystem.cs (92%) rename Content.Client/{Nyanotrasen/Psionics/UI => Psionics/UserInterface}/AcceptPsionicsEUI.cs (100%) rename Content.Client/{Nyanotrasen/Psionics/UI => Psionics/UserInterface}/AcceptPsionicsWindow.cs (100%) rename Content.Client/{Nyanotrasen => Psionics}/UserInterface/GlimmerGraph.cs (97%) rename Content.Server/{Nyanotrasen/Chat => Psionics/Telepathy}/TSayCommand.cs (96%) rename Content.Server/{Nyanotrasen/Chat => Psionics/Telepathy}/TelepathicRepeaterComponent.cs (82%) rename Content.Server/{Nyanotrasen/Chat/NyanoChatSystem.cs => Psionics/Telepathy/TelepathyChatSystem.cs} (97%) diff --git a/Content.Client/Nyanotrasen/Psionics/Glimmer/GlimmerReactiveVisuals.cs b/Content.Client/Psionics/Glimmer/GlimmerReactiveVisuals.cs similarity index 100% rename from Content.Client/Nyanotrasen/Psionics/Glimmer/GlimmerReactiveVisuals.cs rename to Content.Client/Psionics/Glimmer/GlimmerReactiveVisuals.cs diff --git a/Content.Client/Nyanotrasen/Chat/PsionicChatUpdateSystem.cs b/Content.Client/Psionics/Telepathy/PsionicChatUpdateSystem.cs similarity index 92% rename from Content.Client/Nyanotrasen/Chat/PsionicChatUpdateSystem.cs rename to Content.Client/Psionics/Telepathy/PsionicChatUpdateSystem.cs index 84602052fe7..7bb88764a1f 100644 --- a/Content.Client/Nyanotrasen/Chat/PsionicChatUpdateSystem.cs +++ b/Content.Client/Psionics/Telepathy/PsionicChatUpdateSystem.cs @@ -1,8 +1,8 @@ -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Client.Chat.Managers; using Robust.Client.Player; -namespace Content.Client.Nyanotrasen.Chat +namespace Content.Client.Psionics.Chat { public sealed class PsionicChatUpdateSystem : EntitySystem { diff --git a/Content.Client/Nyanotrasen/Psionics/UI/AcceptPsionicsEUI.cs b/Content.Client/Psionics/UserInterface/AcceptPsionicsEUI.cs similarity index 100% rename from Content.Client/Nyanotrasen/Psionics/UI/AcceptPsionicsEUI.cs rename to Content.Client/Psionics/UserInterface/AcceptPsionicsEUI.cs diff --git a/Content.Client/Nyanotrasen/Psionics/UI/AcceptPsionicsWindow.cs b/Content.Client/Psionics/UserInterface/AcceptPsionicsWindow.cs similarity index 100% rename from Content.Client/Nyanotrasen/Psionics/UI/AcceptPsionicsWindow.cs rename to Content.Client/Psionics/UserInterface/AcceptPsionicsWindow.cs diff --git a/Content.Client/Nyanotrasen/UserInterface/GlimmerGraph.cs b/Content.Client/Psionics/UserInterface/GlimmerGraph.cs similarity index 97% rename from Content.Client/Nyanotrasen/UserInterface/GlimmerGraph.cs rename to Content.Client/Psionics/UserInterface/GlimmerGraph.cs index c4a9109dcd8..111c810acb1 100644 --- a/Content.Client/Nyanotrasen/UserInterface/GlimmerGraph.cs +++ b/Content.Client/Psionics/UserInterface/GlimmerGraph.cs @@ -4,7 +4,7 @@ using Robust.Client.ResourceManagement; using Robust.Client.UserInterface; -namespace Content.Client.Nyanotrasen.UserInterface; +namespace Content.Client.Psionics.UI; public sealed class GlimmerGraph : Control { diff --git a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs index 74e6ed3b091..b6ab74627d3 100644 --- a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs @@ -4,16 +4,13 @@ using Content.Shared.Random; using Content.Shared.Random.Helpers; using Content.Server.EUI; -using Content.Server.Psionics; using Content.Server.Mind; -using Content.Shared.Mind.Components; using Content.Shared.StatusEffect; using Robust.Shared.Random; using Robust.Shared.Prototypes; using Robust.Shared.Player; using Content.Shared.Examine; using Content.Shared.Popups; -using Content.Shared.Examine; using static Content.Shared.Examine.ExamineSystemShared; namespace Content.Server.Psionics.Abilities diff --git a/Content.Server/Psionics/PsionicsCommands.cs b/Content.Server/Psionics/PsionicsCommands.cs index 959251d1fb7..2eda2cd2bc8 100644 --- a/Content.Server/Psionics/PsionicsCommands.cs +++ b/Content.Server/Psionics/PsionicsCommands.cs @@ -1,9 +1,8 @@ using Content.Server.Administration; using Content.Shared.Administration; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Mobs.Components; using Robust.Shared.Console; -using Robust.Server.GameObjects; using Content.Shared.Actions; using Robust.Shared.Player; diff --git a/Content.Server/Psionics/PsionicsSystem.cs b/Content.Server/Psionics/PsionicsSystem.cs index f2cb8754326..5c10e4160ca 100644 --- a/Content.Server/Psionics/PsionicsSystem.cs +++ b/Content.Server/Psionics/PsionicsSystem.cs @@ -11,7 +11,6 @@ using Robust.Shared.Audio.Systems; using Robust.Shared.Configuration; using Robust.Shared.Random; -using Content.Shared.Psionics; namespace Content.Server.Psionics { diff --git a/Content.Server/Nyanotrasen/Chat/TSayCommand.cs b/Content.Server/Psionics/Telepathy/TSayCommand.cs similarity index 96% rename from Content.Server/Nyanotrasen/Chat/TSayCommand.cs rename to Content.Server/Psionics/Telepathy/TSayCommand.cs index 9ba27b65d71..378789ccbf9 100644 --- a/Content.Server/Nyanotrasen/Chat/TSayCommand.cs +++ b/Content.Server/Psionics/Telepathy/TSayCommand.cs @@ -5,7 +5,7 @@ using Robust.Shared.Enums; using Robust.Shared.Player; -namespace Content.Server.Chat.Commands +namespace Content.Server.Psionics.Telepathy { [AnyCommand] internal sealed class TSayCommand : IConsoleCommand diff --git a/Content.Server/Nyanotrasen/Chat/TelepathicRepeaterComponent.cs b/Content.Server/Psionics/Telepathy/TelepathicRepeaterComponent.cs similarity index 82% rename from Content.Server/Nyanotrasen/Chat/TelepathicRepeaterComponent.cs rename to Content.Server/Psionics/Telepathy/TelepathicRepeaterComponent.cs index fc199f4332a..6e194f76c8f 100644 --- a/Content.Server/Nyanotrasen/Chat/TelepathicRepeaterComponent.cs +++ b/Content.Server/Psionics/Telepathy/TelepathicRepeaterComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Server.Nyanotrasen.Chat +namespace Content.Server.Psionics.Telepathy { /// /// Repeats whatever is happening in telepathic chat. diff --git a/Content.Server/Nyanotrasen/Chat/NyanoChatSystem.cs b/Content.Server/Psionics/Telepathy/TelepathyChatSystem.cs similarity index 97% rename from Content.Server/Nyanotrasen/Chat/NyanoChatSystem.cs rename to Content.Server/Psionics/Telepathy/TelepathyChatSystem.cs index 62d8032df1d..565e7c7f0e6 100644 --- a/Content.Server/Nyanotrasen/Chat/NyanoChatSystem.cs +++ b/Content.Server/Psionics/Telepathy/TelepathyChatSystem.cs @@ -3,7 +3,7 @@ using Content.Server.Chat.Managers; using Content.Server.Chat.Systems; using Content.Server.Psionics; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Bed.Sleep; using Content.Shared.Chat; using Content.Shared.Database; @@ -17,10 +17,10 @@ using System.Linq; using System.Text; -namespace Content.Server.Nyanotrasen.Chat +namespace Content.Server.Psionics.Telepathy { /// - /// Extensions for nyano's chat stuff + /// Extensions for Telepathic Chat /// public sealed class NyanoChatSystem : EntitySystem From 303d1b307efa8f951bae9f3729f92e8f175d0d8d Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 14 May 2024 21:05:43 -0400 Subject: [PATCH 12/82] Last set of migrations --- .../GlimmerMonitor}/GlimmerMonitorUi.cs | 3 ++- .../GlimmerMonitor}/GlimmerMonitorUiFragment.xaml | 2 +- .../GlimmerMonitor}/GlimmerMonitorUiFragment.xaml.cs | 4 ++-- .../UserInterface/Systems/Chat/ChatUIController.cs | 9 ++++----- Content.Server/Abilities/Mime/MimePowersSystem.cs | 2 +- Content.Server/Anomaly/AnomalySystem.Psionics.cs | 4 ++-- Content.Server/Chat/Systems/ChatSystem.cs | 2 +- .../DeltaV/StationEvents/Events/GlimmerMobSpawnRule.cs | 2 +- .../Nyanotrasen/Chemistry/Effects/ChemRemovePsionic.cs | 2 +- .../Nyanotrasen/Research/Oracle/OracleSystem.cs | 2 +- .../Research/SophicScribe/SophicScribeSystem.cs | 2 +- .../StationEvents/Events/GlimmerWispSpawnRule.cs | 2 +- .../Nyanotrasen/StationEvents/Events/MassMindSwapRule.cs | 5 ++--- .../StationEvents/Events/NoosphericFryRule.cs | 2 +- .../StationEvents/Events/NoosphericStormRule.cs | 4 ++-- .../StationEvents/Events/NoosphericZapRule.cs | 2 +- .../StationEvents/Events/PsionicCatGotYourTongueRule.cs | 2 +- Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs | 2 +- .../Psionics/Invisibility/PsionicInvisibilitySystem.cs | 4 ++-- .../Singularity/EntitySystems/EventHorizonSystem.cs | 4 ++-- Content.Server/Zombies/ZombieSystem.Transform.cs | 2 +- 21 files changed, 31 insertions(+), 32 deletions(-) rename Content.Client/{Nyanotrasen/CartridgeLoader/Cartridges => Psionics/GlimmerMonitor}/GlimmerMonitorUi.cs (92%) rename Content.Client/{Nyanotrasen/CartridgeLoader/Cartridges => Psionics/GlimmerMonitor}/GlimmerMonitorUiFragment.xaml (93%) rename Content.Client/{Nyanotrasen/CartridgeLoader/Cartridges => Psionics/GlimmerMonitor}/GlimmerMonitorUiFragment.xaml.cs (96%) diff --git a/Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUi.cs b/Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUi.cs similarity index 92% rename from Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUi.cs rename to Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUi.cs index 0b5fc7ad38c..0d8accb9f86 100644 --- a/Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUi.cs +++ b/Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUi.cs @@ -1,10 +1,11 @@ using Robust.Client.GameObjects; using Robust.Client.UserInterface; +using Content.Client.Psionics.UI; using Content.Client.UserInterface.Fragments; using Content.Shared.CartridgeLoader.Cartridges; using Content.Shared.CartridgeLoader; -namespace Content.Client.Nyanotrasen.CartridgeLoader.Cartridges; +namespace Content.Client.Psionics.GlimmerMonitor; public sealed partial class GlimmerMonitorUi : UIFragment { diff --git a/Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUiFragment.xaml b/Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUiFragment.xaml similarity index 93% rename from Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUiFragment.xaml rename to Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUiFragment.xaml index 119a1831e6e..3044680e27b 100644 --- a/Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUiFragment.xaml +++ b/Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUiFragment.xaml @@ -1,4 +1,4 @@ - diff --git a/Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUiFragment.xaml.cs b/Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUiFragment.xaml.cs similarity index 96% rename from Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUiFragment.xaml.cs rename to Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUiFragment.xaml.cs index 43d9202aa45..58bbee38a2f 100644 --- a/Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUiFragment.xaml.cs +++ b/Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUiFragment.xaml.cs @@ -1,12 +1,12 @@ using System.Linq; using System.Numerics; -using Content.Client.Nyanotrasen.UserInterface; +using Content.Client.Psionics.UI; using Robust.Client.AutoGenerated; using Robust.Client.ResourceManagement; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; -namespace Content.Client.Nyanotrasen.CartridgeLoader.Cartridges; +namespace Content.Client.Psionics.GlimmerMonitor; [GenerateTypedNameReferences] public sealed partial class GlimmerMonitorUiFragment : BoxContainer diff --git a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs index ff4972d9d08..79c1909ebaf 100644 --- a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs +++ b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs @@ -20,7 +20,6 @@ using Content.Shared.Examine; using Content.Shared.Input; using Content.Shared.Radio; -using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.Input; using Robust.Client.Player; @@ -37,7 +36,7 @@ using Robust.Shared.Replays; using Robust.Shared.Timing; using Robust.Shared.Utility; -using Content.Client.Nyanotrasen.Chat; //Nyano - Summary: chat namespace. +using Content.Client.Psionics.Chat; namespace Content.Client.UserInterface.Systems.Chat; @@ -61,7 +60,7 @@ public sealed class ChatUIController : UIController [UISystemDependency] private readonly GhostSystem? _ghost = default; [UISystemDependency] private readonly TypingIndicatorSystem? _typingIndicator = default; [UISystemDependency] private readonly ChatSystem? _chatSys = default; - [UISystemDependency] private readonly PsionicChatUpdateSystem? _psionic = default!; //Nyano - Summary: makes the psionic chat available. + [UISystemDependency] private readonly PsionicChatUpdateSystem? _psionic = default!; //EE - Summary: makes the psionic chat available. [ValidatePrototypeId] private const string ChatNamePalette = "ChatNames"; @@ -82,7 +81,7 @@ public sealed class ChatUIController : UIController {SharedChatSystem.AdminPrefix, ChatSelectChannel.Admin}, {SharedChatSystem.RadioCommonPrefix, ChatSelectChannel.Radio}, {SharedChatSystem.DeadPrefix, ChatSelectChannel.Dead}, - {SharedChatSystem.TelepathicPrefix, ChatSelectChannel.Telepathic} //Nyano - Summary: adds the telepathic prefix =. + {SharedChatSystem.TelepathicPrefix, ChatSelectChannel.Telepathic} //EE - Summary: adds the telepathic prefix =. }; public static readonly Dictionary ChannelPrefixes = new() @@ -96,7 +95,7 @@ public sealed class ChatUIController : UIController {ChatSelectChannel.Admin, SharedChatSystem.AdminPrefix}, {ChatSelectChannel.Radio, SharedChatSystem.RadioCommonPrefix}, {ChatSelectChannel.Dead, SharedChatSystem.DeadPrefix}, - {ChatSelectChannel.Telepathic, SharedChatSystem.TelepathicPrefix } //Nyano - Summary: associates telepathic with =. + {ChatSelectChannel.Telepathic, SharedChatSystem.TelepathicPrefix } //EE - Summary: associates telepathic with =. }; /// diff --git a/Content.Server/Abilities/Mime/MimePowersSystem.cs b/Content.Server/Abilities/Mime/MimePowersSystem.cs index c1d2643d6fa..3e7605a07d3 100644 --- a/Content.Server/Abilities/Mime/MimePowersSystem.cs +++ b/Content.Server/Abilities/Mime/MimePowersSystem.cs @@ -10,7 +10,7 @@ using Robust.Shared.Containers; using Robust.Shared.Map; using Robust.Shared.Timing; -using Content.Shared.Abilities.Psionics; //Nyano - Summary: Makes Mime psionic. +using Content.Shared.Psionics.Abilities; //EE - Summary: Makes Mime psionic. using Content.Shared.Speech.Muting; namespace Content.Server.Abilities.Mime diff --git a/Content.Server/Anomaly/AnomalySystem.Psionics.cs b/Content.Server/Anomaly/AnomalySystem.Psionics.cs index 95fda1d5035..3a5a55c0bdc 100644 --- a/Content.Server/Anomaly/AnomalySystem.Psionics.cs +++ b/Content.Server/Anomaly/AnomalySystem.Psionics.cs @@ -1,4 +1,4 @@ -using Content.Server.Abilities.Psionics; //Nyano - Summary: the psniocs bin where dispel is located. +using Content.Server.Psionics.Abilities; //EE - Summary: the psionics bin where dispel is located. using Content.Shared.Anomaly; using Content.Shared.Anomaly.Components; using Robust.Shared.Random; @@ -15,7 +15,7 @@ private void InitializePsionics() SubscribeLocalEvent(OnDispelled); } - //Nyano - Summary: gives dispellable behavior to Anomalies. + //Nyano - Summary: gives dispellable behavior to Anomalies. private void OnDispelled(EntityUid uid, AnomalyComponent component, DispelledEvent args) { _dispel.DealDispelDamage(uid); diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs index be6e8b78fef..6cdb088dbb0 100644 --- a/Content.Server/Chat/Systems/ChatSystem.cs +++ b/Content.Server/Chat/Systems/ChatSystem.cs @@ -7,7 +7,7 @@ using Content.Server.GameTicking; using Content.Server.Speech.Components; using Content.Server.Speech.EntitySystems; -using Content.Server.Nyanotrasen.Chat; +using Content.Server.Psionics.Telepathy; using Content.Server.Speech.Components; using Content.Server.Speech.EntitySystems; using Content.Server.Station.Components; diff --git a/Content.Server/DeltaV/StationEvents/Events/GlimmerMobSpawnRule.cs b/Content.Server/DeltaV/StationEvents/Events/GlimmerMobSpawnRule.cs index ec9ec770313..22d96a54146 100644 --- a/Content.Server/DeltaV/StationEvents/Events/GlimmerMobSpawnRule.cs +++ b/Content.Server/DeltaV/StationEvents/Events/GlimmerMobSpawnRule.cs @@ -5,7 +5,7 @@ using Content.Server.Psionics.Glimmer; using Content.Server.StationEvents.Components; using Content.Shared.Psionics.Glimmer; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; namespace Content.Server.StationEvents.Events; diff --git a/Content.Server/Nyanotrasen/Chemistry/Effects/ChemRemovePsionic.cs b/Content.Server/Nyanotrasen/Chemistry/Effects/ChemRemovePsionic.cs index a23a5b3d77d..0ce3f9d7c64 100644 --- a/Content.Server/Nyanotrasen/Chemistry/Effects/ChemRemovePsionic.cs +++ b/Content.Server/Nyanotrasen/Chemistry/Effects/ChemRemovePsionic.cs @@ -1,5 +1,5 @@ using Content.Shared.Chemistry.Reagent; -using Content.Server.Abilities.Psionics; +using Content.Server.Psionics.Abilities; using JetBrains.Annotations; using Robust.Shared.Prototypes; diff --git a/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs b/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs index 148598fe2c3..24459d29e22 100644 --- a/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs +++ b/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs @@ -5,7 +5,7 @@ using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Fluids.EntitySystems; using Content.Server.Psionics; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Chat; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.EntitySystems; diff --git a/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs b/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs index bc3c22cc350..b8cdcb56d47 100644 --- a/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs +++ b/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs @@ -1,4 +1,4 @@ -using Content.Server.Abilities.Psionics; +using Content.Server.Psionics.Abilities; using Content.Server.Chat.Systems; using Content.Server.Radio.Components; using Content.Server.Radio.EntitySystems; diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/GlimmerWispSpawnRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/GlimmerWispSpawnRule.cs index 66eea988aeb..89b5a176f24 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/GlimmerWispSpawnRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/GlimmerWispSpawnRule.cs @@ -5,7 +5,7 @@ using Content.Server.Psionics.Glimmer; using Content.Server.StationEvents.Components; using Content.Shared.Psionics.Glimmer; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; namespace Content.Server.StationEvents.Events; diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/MassMindSwapRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/MassMindSwapRule.cs index 63944563269..89f3bc97501 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/MassMindSwapRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/MassMindSwapRule.cs @@ -1,10 +1,9 @@ -using Robust.Server.GameObjects; using Robust.Shared.Random; -using Content.Server.Abilities.Psionics; +using Content.Server.Psionics.Abilities; using Content.Server.GameTicking.Rules.Components; using Content.Server.Psionics; using Content.Server.StationEvents.Components; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Robust.Shared.Player; diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericFryRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericFryRule.cs index c04543d2195..6a2c1c3ba7d 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericFryRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericFryRule.cs @@ -10,7 +10,7 @@ using Content.Server.Power.EntitySystems; using Content.Server.Psionics.Glimmer; using Content.Server.StationEvents.Components; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Damage; using Content.Shared.Inventory; using Content.Shared.Mobs.Components; diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericStormRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericStormRule.cs index 175318e15bd..8812ed1fe37 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericStormRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericStormRule.cs @@ -1,9 +1,9 @@ using Robust.Shared.Random; -using Content.Server.Abilities.Psionics; +using Content.Server.Psionics.Abilities; using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; using Content.Server.Psionics; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Mobs.Systems; using Content.Shared.Psionics.Glimmer; using Content.Shared.Zombies; diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericZapRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericZapRule.cs index 82c3d72b139..3672d317d9e 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericZapRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericZapRule.cs @@ -3,7 +3,7 @@ using Content.Server.Psionics; using Content.Server.StationEvents.Components; using Content.Server.Stunnable; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Content.Shared.StatusEffect; diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/PsionicCatGotYourTongueRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/PsionicCatGotYourTongueRule.cs index 63e0a435cb0..753b2e25729 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/PsionicCatGotYourTongueRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/PsionicCatGotYourTongueRule.cs @@ -4,7 +4,7 @@ using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; using Content.Shared.Mobs.Components; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.StatusEffect; using Content.Shared.Mobs.Systems; using Robust.Shared.Audio.Systems; diff --git a/Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs b/Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs index da3b07d6dab..db61a3753a3 100644 --- a/Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs +++ b/Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs @@ -1,4 +1,4 @@ -using Content.Server.Audio; +using Content.Server.Psionics.Audio; using Content.Server.Power.Components; using Content.Server.Electrocution; using Content.Server.Lightning; diff --git a/Content.Server/Psionics/Invisibility/PsionicInvisibilitySystem.cs b/Content.Server/Psionics/Invisibility/PsionicInvisibilitySystem.cs index f85460a69f5..9583f45fdc9 100644 --- a/Content.Server/Psionics/Invisibility/PsionicInvisibilitySystem.cs +++ b/Content.Server/Psionics/Invisibility/PsionicInvisibilitySystem.cs @@ -1,6 +1,6 @@ -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Psionics; -using Content.Server.Abilities.Psionics; +using Content.Server.Psionics.Abilities; using Content.Shared.Eye; using Content.Server.NPC.Systems; using Robust.Shared.Containers; diff --git a/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs b/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs index 7784db015d3..ba07375699b 100644 --- a/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs +++ b/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs @@ -13,7 +13,7 @@ using Robust.Shared.Map.Components; using Robust.Shared.Physics.Events; using Robust.Shared.Timing; -using Content.Shared.Abilities.Psionics; //Nyano - Summary: for the telegnostic projection. +using Content.Shared.Psionics.Abilities; //EE - Summary: for the telegnostic projection. namespace Content.Server.Singularity.EntitySystems; @@ -39,7 +39,7 @@ public override void Initialize() SubscribeLocalEvent(PreventConsume); SubscribeLocalEvent(PreventConsume); - SubscribeLocalEvent(PreventConsume); ///Nyano - Summary: the telegnositic projection has the same trait as ghosts. + SubscribeLocalEvent(PreventConsume); ///EE - Summary: the telegnositic projection has the same trait as ghosts. SubscribeLocalEvent(PreventConsume); SubscribeLocalEvent(OnHorizonMapInit); SubscribeLocalEvent(OnStartCollide); diff --git a/Content.Server/Zombies/ZombieSystem.Transform.cs b/Content.Server/Zombies/ZombieSystem.Transform.cs index daadd4b518b..09a4489cf4c 100644 --- a/Content.Server/Zombies/ZombieSystem.Transform.cs +++ b/Content.Server/Zombies/ZombieSystem.Transform.cs @@ -16,7 +16,7 @@ using Content.Server.Roles; using Content.Server.Speech.Components; using Content.Server.Temperature.Components; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.CombatMode; using Content.Shared.CombatMode.Pacification; using Content.Shared.Damage; From 62163f025aeba8d687bb8fcd486b9d7518b2298c Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 14 May 2024 21:25:46 -0400 Subject: [PATCH 13/82] Update PsionicsSystem.cs --- Content.Server/Psionics/PsionicsSystem.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Content.Server/Psionics/PsionicsSystem.cs b/Content.Server/Psionics/PsionicsSystem.cs index 5c10e4160ca..f51d89200fa 100644 --- a/Content.Server/Psionics/PsionicsSystem.cs +++ b/Content.Server/Psionics/PsionicsSystem.cs @@ -48,6 +48,7 @@ public override void Initialize() SubscribeLocalEvent(OnStamHit); SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnRemove); } @@ -81,12 +82,13 @@ private void OnMeleeHit(EntityUid uid, AntiPsionicWeaponComponent component, Mel _electrocutionSystem.TryDoElectrocution(args.User, null, 20, TimeSpan.FromSeconds(5), false); } } - - private void OnInit(EntityUid uid, PsionicComponent component, ComponentInit args) + private void OnStartup(EntityUid uid, PsionicComponent component, ComponentStartup args) { component.Amplification = _random.NextFloat(0.3f, 1.1f); component.Dampening = _random.NextFloat(0.3f, 1.1f); - + } + private void OnInit(EntityUid uid, PsionicComponent component, ComponentInit args) + { if (!component.Removable) return; From 83ea6ace23a52093d296076c624ef4641523fa11 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 14 May 2024 22:05:31 -0400 Subject: [PATCH 14/82] Almost got it, one last bug to squash --- .../Abilities/PyrokinesisPowerSystem.cs | 17 ++++++++++++++--- Content.Server/Psionics/PsionicsSystem.cs | 4 ++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs index 444675d9b3f..64621313db8 100644 --- a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs @@ -5,17 +5,20 @@ using Robust.Server.GameObjects; using Content.Shared.Actions.Events; using Content.Server.Explosion.Components; +using Content.Shared.Mobs.Components; +using Robust.Shared.Map; namespace Content.Server.Psionics.Abilities { public sealed class PyrokinesisPowerSystem : EntitySystem { + [Dependency] private readonly TransformSystem _xform = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly GunSystem _gunSystem = default!; [Dependency] private readonly SharedTransformSystem _transformSystem = default!; [Dependency] private readonly PhysicsSystem _physics = default!; - + [Dependency] private readonly IMapManager _mapManager = default!; public override void Initialize() { base.Initialize(); @@ -56,7 +59,15 @@ private void OnPowerUsed(PyrokinesisPowerActionEvent args) if (!HasComp(args.Performer)) { - var ent = Spawn("ProjectileAnomalyFireball"); + var xformQuery = GetEntityQuery(); + var xform = xformQuery.GetComponent(args.Performer); + + var mapPos = xform.Coordinates.ToMap(EntityManager, _xform); + var spawnCoords = _mapManager.TryFindGridAt(mapPos, out var gridUid, out _) + ? xform.Coordinates.WithEntityId(gridUid, EntityManager) + : new(_mapManager.GetMapEntityId(mapPos.MapId), mapPos.Position); + + var ent = Spawn("ProjectileAnomalyFireball", spawnCoords); if (TryComp(ent, out var fireball)) { @@ -69,7 +80,7 @@ private void OnPowerUsed(PyrokinesisPowerActionEvent args) } var userVelocity = _physics.GetMapLinearVelocity(args.Performer); - var direction = args.Target.ToMapPos(EntityManager, _transformSystem); + var direction = args.Target.Position; _gunSystem.ShootProjectile(ent, direction, userVelocity, args.Performer, args.Performer, 20f); diff --git a/Content.Server/Psionics/PsionicsSystem.cs b/Content.Server/Psionics/PsionicsSystem.cs index f51d89200fa..bf829477609 100644 --- a/Content.Server/Psionics/PsionicsSystem.cs +++ b/Content.Server/Psionics/PsionicsSystem.cs @@ -48,7 +48,7 @@ public override void Initialize() SubscribeLocalEvent(OnStamHit); SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnStartup); + SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnRemove); } @@ -82,7 +82,7 @@ private void OnMeleeHit(EntityUid uid, AntiPsionicWeaponComponent component, Mel _electrocutionSystem.TryDoElectrocution(args.User, null, 20, TimeSpan.FromSeconds(5), false); } } - private void OnStartup(EntityUid uid, PsionicComponent component, ComponentStartup args) + private void OnStartup(EntityUid uid, PsionicComponent component, MapInitEvent args) { component.Amplification = _random.NextFloat(0.3f, 1.1f); component.Dampening = _random.NextFloat(0.3f, 1.1f); From c569e2e92c2d5e39c98ddded0307b093536beed2 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 14 May 2024 22:22:29 -0400 Subject: [PATCH 15/82] slightly more acccurate but still not quite right --- Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs index 64621313db8..4659ca0f463 100644 --- a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs @@ -79,10 +79,9 @@ private void OnPowerUsed(PyrokinesisPowerActionEvent args) } } - var userVelocity = _physics.GetMapLinearVelocity(args.Performer); var direction = args.Target.Position; - _gunSystem.ShootProjectile(ent, direction, userVelocity, args.Performer, args.Performer, 20f); + _gunSystem.ShootProjectile(ent, direction, new System.Numerics.Vector2(0, 0), args.Performer, args.Performer, 20f); _psionics.LogPowerUsed(args.Performer, "pyrokinesis", (int) MathF.Round(6f * psionic.Amplification - psionic.Dampening), From 851bebaa43a1153aa12284b70476fc3c812bc663 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 14 May 2024 22:28:42 -0400 Subject: [PATCH 16/82] Update PyrokinesisPowerSystem.cs --- Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs index 4659ca0f463..c0b35ae6169 100644 --- a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs @@ -75,7 +75,7 @@ private void OnPowerUsed(PyrokinesisPowerActionEvent args) if (psionic.Amplification > 5 && EnsureComp(ent, out var ignite)) { - ignite.FireStacks = 0.1f * psionic.Amplification - 0.1f * psionic.Dampening; + ignite.FireStacks = 0.2f * psionic.Amplification - 0.1f * psionic.Dampening; } } From 0597405a48a588c9127e1bdbdca1b3d8aae81732 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 14 May 2024 22:35:26 -0400 Subject: [PATCH 17/82] removing some errant instances of potentialpsionic --- Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml | 1 - Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml | 4 ---- Resources/Prototypes/Entities/Mobs/Player/skeleton.yml | 1 - Resources/Prototypes/Entities/Mobs/Player/vox.yml | 2 -- 4 files changed, 8 deletions(-) diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml b/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml index 89a6f16e525..b5d8dbb53f7 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml @@ -118,7 +118,6 @@ - type: Grammar attributes: gender: male - - type: PotentialPsionic # Nyano - type: entity id: MobRatKingBuff diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml index d0ac6fc0265..d70cf3277a0 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml @@ -121,10 +121,6 @@ molsPerSecondPerUnitMass: 0.0005 - type: Speech speechVerb: LargeMob - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. - chance: -2 - - type: Psionic #Nyano - Summary: makes psionic by default. - removable: false - type: entity name: Praetorian diff --git a/Resources/Prototypes/Entities/Mobs/Player/skeleton.yml b/Resources/Prototypes/Entities/Mobs/Player/skeleton.yml index bf41f2dda6e..f9132ce0ea0 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/skeleton.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/skeleton.yml @@ -8,7 +8,6 @@ interactSuccessString: hugging-success-generic interactSuccessSound: /Audio/Effects/thudswoosh.ogg messagePerceivedByOthers: hugging-success-generic-others - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. - type: entity name: skeleton pirate diff --git a/Resources/Prototypes/Entities/Mobs/Player/vox.yml b/Resources/Prototypes/Entities/Mobs/Player/vox.yml index 0a6f4f43644..de1e3da2be7 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/vox.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/vox.yml @@ -3,5 +3,3 @@ name: Vox parent: BaseMobVox id: MobVox - components: - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. From f96847f90b8fb49a44ca4b5f829f9a67989df2de Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 14 May 2024 22:37:03 -0400 Subject: [PATCH 18/82] Revert "removing some errant instances of potentialpsionic" This reverts commit 0597405a48a588c9127e1bdbdca1b3d8aae81732. --- Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml | 1 + Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml | 4 ++++ Resources/Prototypes/Entities/Mobs/Player/skeleton.yml | 1 + Resources/Prototypes/Entities/Mobs/Player/vox.yml | 2 ++ 4 files changed, 8 insertions(+) diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml b/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml index b5d8dbb53f7..89a6f16e525 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml @@ -118,6 +118,7 @@ - type: Grammar attributes: gender: male + - type: PotentialPsionic # Nyano - type: entity id: MobRatKingBuff diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml index d70cf3277a0..d0ac6fc0265 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml @@ -121,6 +121,10 @@ molsPerSecondPerUnitMass: 0.0005 - type: Speech speechVerb: LargeMob + - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. + chance: -2 + - type: Psionic #Nyano - Summary: makes psionic by default. + removable: false - type: entity name: Praetorian diff --git a/Resources/Prototypes/Entities/Mobs/Player/skeleton.yml b/Resources/Prototypes/Entities/Mobs/Player/skeleton.yml index f9132ce0ea0..bf41f2dda6e 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/skeleton.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/skeleton.yml @@ -8,6 +8,7 @@ interactSuccessString: hugging-success-generic interactSuccessSound: /Audio/Effects/thudswoosh.ogg messagePerceivedByOthers: hugging-success-generic-others + - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. - type: entity name: skeleton pirate diff --git a/Resources/Prototypes/Entities/Mobs/Player/vox.yml b/Resources/Prototypes/Entities/Mobs/Player/vox.yml index de1e3da2be7..0a6f4f43644 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/vox.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/vox.yml @@ -3,3 +3,5 @@ name: Vox parent: BaseMobVox id: MobVox + components: + - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. From 0e11da63167c8cb08abebde6e24bd041fb883ffc Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Wed, 15 May 2024 17:31:32 -0400 Subject: [PATCH 19/82] Final power update --- .../Abilities/MetapsionicPowerSystem.cs | 6 ++ .../Abilities/NoosphericZapPowerSystem.cs | 2 +- .../Abilities/PsionicAbilitiesSystem.cs | 4 - .../PsionicInvisibilityPowerSystem.cs | 1 - .../PsionicRegenerationPowerSystem.cs | 10 +-- .../Abilities/PyrokinesisPowerSystem.cs | 2 +- .../RegenerativeStasisPowerSystem.cs | 76 +++++++++++++++++++ Content.Server/Psionics/Dreams/DreamSystem.cs | 2 - .../Psionics/Glimmer/GlimmerReactiveSystem.cs | 3 - .../PsionicInvisibleContactsComponent.cs | 1 - .../PsionicInvisibleContactsSystem.cs | 2 - Content.Server/Psionics/PsionicsCommands.cs | 3 +- .../Psionics/Telepathy/TSayCommand.cs | 1 - .../Psionics/Telepathy/TelepathyChatSystem.cs | 1 - .../Zombies/ZombieSystem.Transform.cs | 2 - .../Events/MassSleepPowerActionEvent.cs | 2 - .../RegenerativeStasisPowerActionEvent.cs | 2 + .../Dispel/DamageOnDispelComponent.cs | 2 +- .../Abilities/Dispel/DispelPowerComponent.cs | 1 - .../MassSleep/MassSleepPowerComponent.cs | 21 ----- .../MassSleep/MassSleepPowerSystem.cs | 59 -------------- .../Metapsionics/MetapsionicPowerComponent.cs | 1 - .../RegenerativeStasisPowerComponent.cs | 20 +++++ .../Psionics/Glimmer/GlimmerSystem.cs | 2 +- Content.Shared/Psionics/PsionicComponent.cs | 2 +- .../Psionics/SharedPsionicAbilitiesSystem.cs | 3 +- .../nyanotrasen/psionics/psychic-feedback.ftl | 21 ++++- .../Prototypes/Nyanotrasen/Actions/types.yml | 10 +-- .../Machines/metempsychoticMachine.yml | 2 + .../Entities/Structures/Research/oracle.yml | 2 + .../Structures/Research/sophicscribe.yml | 2 + 31 files changed, 143 insertions(+), 125 deletions(-) create mode 100644 Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs delete mode 100644 Content.Shared/Nyanotrasen/Actions/Events/MassSleepPowerActionEvent.cs create mode 100644 Content.Shared/Nyanotrasen/Actions/Events/RegenerativeStasisPowerActionEvent.cs delete mode 100644 Content.Shared/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs delete mode 100644 Content.Shared/Psionics/Abilities/MassSleep/MassSleepPowerSystem.cs create mode 100644 Content.Shared/Psionics/Abilities/RegenerativeStasis/RegenerativeStasisPowerComponent.cs diff --git a/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs b/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs index c30abd84f57..ffe8ab00c2f 100644 --- a/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs @@ -154,6 +154,12 @@ private void OnDoAfter(EntityUid uid, MetapsionicPowerComponent component, Focus if (args.Target == null) return; + if (TryComp(args.Target, out var swapped)) + { + _popups.PopupEntity(Loc.GetString(swapped.MindSwappedFeedback, ("entity", args.Target)), uid, uid, PopupType.LargeCaution); + return; + } + if (args.Target == uid) { _popups.PopupEntity(Loc.GetString("metapulse-self", ("entity", args.Target)), uid, uid, PopupType.LargeCaution); diff --git a/Content.Server/Psionics/Abilities/NoosphericZapPowerSystem.cs b/Content.Server/Psionics/Abilities/NoosphericZapPowerSystem.cs index ce55cb3bb7d..c935bc0123d 100644 --- a/Content.Server/Psionics/Abilities/NoosphericZapPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/NoosphericZapPowerSystem.cs @@ -47,7 +47,7 @@ private void OnShutdown(EntityUid uid, NoosphericZapPowerComponent component, Co { psionic.ActivePowers.Remove(component); psionic.PsychicFeedback.Remove(component.NoosphericZapFeedback); - psionic.Amplification += 1f; + psionic.Amplification -= 1f; } } diff --git a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs index b6ab74627d3..5124aff0688 100644 --- a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs @@ -3,8 +3,6 @@ using Content.Shared.Psionics.Glimmer; using Content.Shared.Random; using Content.Shared.Random.Helpers; -using Content.Server.EUI; -using Content.Server.Mind; using Content.Shared.StatusEffect; using Robust.Shared.Random; using Robust.Shared.Prototypes; @@ -20,11 +18,9 @@ public sealed class PsionicAbilitiesSystem : EntitySystem [Dependency] private readonly IComponentFactory _componentFactory = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; - [Dependency] private readonly EuiManager _euiManager = default!; [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; [Dependency] private readonly GlimmerSystem _glimmerSystem = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly MindSystem _mindSystem = default!; [Dependency] private readonly SharedPopupSystem _popups = default!; public override void Initialize() diff --git a/Content.Server/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs b/Content.Server/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs index 9422dfb9acf..0c50efb5cf3 100644 --- a/Content.Server/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs @@ -6,7 +6,6 @@ using Content.Shared.Stunnable; using Content.Shared.Stealth; using Content.Shared.Stealth.Components; -using Content.Server.Psionics; using Content.Shared.Psionics.Events; using Content.Shared.Actions.Events; using Robust.Shared.Audio.Systems; diff --git a/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs b/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs index e6ef1ac6d73..882eb9e0b14 100644 --- a/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs @@ -147,7 +147,7 @@ private void OnShutdown(EntityUid uid, PsionicRegenerationPowerComponent compone { psionic.ActivePowers.Remove(component); psionic.PsychicFeedback.Remove(component.RegenerationFeedback); - psionic.Amplification += 0.5f; + psionic.Amplification -= 0.5f; psionic.Dampening -= 0.5f; } } @@ -173,19 +173,15 @@ private void OnDoAfter(EntityUid uid, PsionicRegenerationPowerComponent componen if (!TryComp(uid, out var stream)) return; - // DoAfter has no way to run a callback during the process to give - // small doses of the reagent, so we wait until either the action - // is cancelled (by being dispelled) or complete to give the - // appropriate dose. A timestamp delta is used to accomplish this. var percentageComplete = Math.Min(1f, (_gameTiming.CurTime - args.StartedAt).TotalSeconds / component.UseDelay); var solution = new Solution(); - solution.AddReagent("PsionicRegenerationEssence", FixedPoint2.New(component.EssenceAmount * percentageComplete + 10f * psionic.Dampening)); + solution.AddReagent("PsionicRegenerationEssence", FixedPoint2.New(Math.Min(component.EssenceAmount * percentageComplete + 10f * psionic.Dampening, 15f))); _bloodstreamSystem.TryAddToChemicals(uid, solution, stream); if (component.SelfRevive == true) { var critSolution = new Solution(); - critSolution.AddReagent("Epinephrine", MathF.MinMagnitude(5 + 5 * psionic.Dampening, 15)); + critSolution.AddReagent("Epinephrine", MathF.Min(5 + 5 * psionic.Dampening, 15)); _bloodstreamSystem.TryAddToChemicals(uid, critSolution, stream); component.SelfRevive = false; } diff --git a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs index c0b35ae6169..77075dab206 100644 --- a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs @@ -48,7 +48,7 @@ private void OnShutdown(EntityUid uid, PyrokinesisPowerComponent component, Comp { psionic.ActivePowers.Remove(component); psionic.PsychicFeedback.Remove(component.PyrokinesisFeedback); - psionic.Amplification += 1f; + psionic.Amplification -= 1f; } } diff --git a/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs b/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs new file mode 100644 index 00000000000..e184b19396b --- /dev/null +++ b/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs @@ -0,0 +1,76 @@ +using Content.Server.Body.Systems; +using Content.Server.Body.Components; +using Content.Shared.Actions; +using Content.Shared.Chemistry.Components; +using Content.Shared.Bed.Sleep; +using Content.Shared.Psionics.Abilities; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; +using Content.Shared.Mind; +using Content.Shared.Actions.Events; +using Content.Shared.FixedPoint; + +namespace Content.Server.Psionics.Abilities +{ + public sealed class MassSleepPowerSystem : EntitySystem + { + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; + [Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnPowerUsed); + } + + private void OnInit(EntityUid uid, RegenerativeStasisPowerComponent component, ComponentInit args) + { + _actions.AddAction(uid, ref component.RegenerativeStasisActionEntity, component.RegenerativeStasisActionId); + _actions.TryGetActionData(component.RegenerativeStasisActionEntity, out var actionData); + if (actionData is { UseDelay: not null }) + _actions.StartUseDelay(component.RegenerativeStasisActionEntity); + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Add(component); + psionic.PsychicFeedback.Add(component.RegenerativeStasisFeedback); + psionic.Amplification += 0.5f; + psionic.Dampening += 0.5f; + } + } + + private void OnShutdown(EntityUid uid, RegenerativeStasisPowerComponent component, ComponentShutdown args) + { + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Remove(component); + psionic.PsychicFeedback.Remove(component.RegenerativeStasisFeedback); + psionic.Amplification -= 0.5f; + psionic.Dampening -= 0.5f; + } + _actions.RemoveAction(uid, component.RegenerativeStasisActionEntity); + } + + private void OnPowerUsed(EntityUid uid, RegenerativeStasisPowerComponent component, RegenerativeStasisPowerActionEvent args) + { + if (TryComp(uid, out var psionic) + && !HasComp(uid) + && !HasComp(args.Target) + && TryComp(args.Target, out var stream)) + { + var solution = new Solution(); + solution.AddReagent("PsionicRegenerationEssence", FixedPoint2.New(MathF.Min(2.5f * psionic.Amplification + psionic.Dampening, 15f))); + solution.AddReagent("Epinephrine", FixedPoint2.New(MathF.Min(2.5f * psionic.Dampening + psionic.Amplification, 15f))); + _bloodstreamSystem.TryAddToChemicals(args.Target, solution, stream); + EnsureComp(args.Target); + + _psionics.LogPowerUsed(uid, "regenerative stasis", + (int) Math.Round(4 * psionic.Amplification - psionic.Dampening), + (int) Math.Round(6 * psionic.Amplification - psionic.Dampening)); + args.Handled = true; + } + } + } +} diff --git a/Content.Server/Psionics/Dreams/DreamSystem.cs b/Content.Server/Psionics/Dreams/DreamSystem.cs index 15e1593a859..1731c7a9bf5 100644 --- a/Content.Server/Psionics/Dreams/DreamSystem.cs +++ b/Content.Server/Psionics/Dreams/DreamSystem.cs @@ -1,6 +1,5 @@ using Content.Shared.Dataset; using Content.Shared.Bed.Sleep; -using Content.Server.Chat.Systems; using Content.Server.Chat.Managers; using Robust.Shared.Random; using Robust.Shared.Prototypes; @@ -10,7 +9,6 @@ namespace Content.Server.Psionics.Dreams { public sealed class DreamsSystem : EntitySystem { - [Dependency] private readonly ChatSystem _chat = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IChatManager _chatManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; diff --git a/Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs b/Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs index db61a3753a3..c0802c8b670 100644 --- a/Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs +++ b/Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs @@ -3,12 +3,10 @@ using Content.Server.Electrocution; using Content.Server.Lightning; using Content.Server.Explosion.EntitySystems; -using Content.Server.Construction; using Content.Server.Ghost; using Content.Server.Revenant.EntitySystems; using Content.Shared.Audio; using Content.Shared.Construction.EntitySystems; -using Content.Shared.Coordinates.Helpers; using Content.Shared.GameTicking; using Content.Shared.Psionics.Glimmer; using Content.Shared.Verbs; @@ -16,7 +14,6 @@ using Content.Shared.Damage; using Content.Shared.Destructible; using Content.Shared.Construction.Components; -using Content.Shared.Mind; using Content.Shared.Mind.Components; using Content.Shared.Weapons.Melee.Components; using Robust.Shared.Audio; diff --git a/Content.Server/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs b/Content.Server/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs index 859ceb7b83a..268deddf6d9 100644 --- a/Content.Server/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs +++ b/Content.Server/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs @@ -1,5 +1,4 @@ using Content.Shared.Whitelist; -using Robust.Shared.Timing; namespace Content.Server.Psionics { diff --git a/Content.Server/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs b/Content.Server/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs index cec755e3260..403e0592617 100644 --- a/Content.Server/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs +++ b/Content.Server/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs @@ -2,7 +2,6 @@ using Content.Shared.Stealth.Components; using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Systems; -using Robust.Shared.Timing; namespace Content.Server.Psionics { @@ -12,7 +11,6 @@ namespace Content.Server.Psionics public sealed class PsionicInvisibleContactsSystem : EntitySystem { [Dependency] private readonly SharedStealthSystem _stealth = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; public override void Initialize() { diff --git a/Content.Server/Psionics/PsionicsCommands.cs b/Content.Server/Psionics/PsionicsCommands.cs index 2eda2cd2bc8..3f9ee794b38 100644 --- a/Content.Server/Psionics/PsionicsCommands.cs +++ b/Content.Server/Psionics/PsionicsCommands.cs @@ -18,7 +18,8 @@ public async void Execute(IConsoleShell shell, string argStr, string[] args) { SharedActionsSystem actions = default!; var entMan = IoCManager.Resolve(); - foreach (var (actor, mob, psionic, meta) in entMan.EntityQuery()){ + foreach (var (actor, psionic, meta) in entMan.EntityQuery()) + { // filter out xenos, etc, with innate telepathy actions.TryGetActionData( psionic.PsionicAbility, out var actionData ); if (actionData == null || actionData.ToString() == null) diff --git a/Content.Server/Psionics/Telepathy/TSayCommand.cs b/Content.Server/Psionics/Telepathy/TSayCommand.cs index 378789ccbf9..8fbaa5e17b2 100644 --- a/Content.Server/Psionics/Telepathy/TSayCommand.cs +++ b/Content.Server/Psionics/Telepathy/TSayCommand.cs @@ -1,6 +1,5 @@ using Content.Server.Chat.Systems; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Enums; using Robust.Shared.Player; diff --git a/Content.Server/Psionics/Telepathy/TelepathyChatSystem.cs b/Content.Server/Psionics/Telepathy/TelepathyChatSystem.cs index 565e7c7f0e6..ad49075e65a 100644 --- a/Content.Server/Psionics/Telepathy/TelepathyChatSystem.cs +++ b/Content.Server/Psionics/Telepathy/TelepathyChatSystem.cs @@ -2,7 +2,6 @@ using Content.Server.Administration.Managers; using Content.Server.Chat.Managers; using Content.Server.Chat.Systems; -using Content.Server.Psionics; using Content.Shared.Psionics.Abilities; using Content.Shared.Bed.Sleep; using Content.Shared.Chat; diff --git a/Content.Server/Zombies/ZombieSystem.Transform.cs b/Content.Server/Zombies/ZombieSystem.Transform.cs index 09a4489cf4c..53128aade31 100644 --- a/Content.Server/Zombies/ZombieSystem.Transform.cs +++ b/Content.Server/Zombies/ZombieSystem.Transform.cs @@ -59,9 +59,7 @@ public sealed partial class ZombieSystem [Dependency] private readonly IChatManager _chatMan = default!; [Dependency] private readonly MindSystem _mind = default!; [Dependency] private readonly SharedRoleSystem _roles = default!; - [Dependency] private readonly MobThresholdSystem _mobThreshold = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly ActionsSystem _actions = default!; // DeltaV - No psionic zombies /// /// Handles an entity turning into a zombie when they die or go into crit diff --git a/Content.Shared/Nyanotrasen/Actions/Events/MassSleepPowerActionEvent.cs b/Content.Shared/Nyanotrasen/Actions/Events/MassSleepPowerActionEvent.cs deleted file mode 100644 index 6666ee48d6c..00000000000 --- a/Content.Shared/Nyanotrasen/Actions/Events/MassSleepPowerActionEvent.cs +++ /dev/null @@ -1,2 +0,0 @@ -namespace Content.Shared.Actions.Events; -public sealed partial class MassSleepPowerActionEvent : WorldTargetActionEvent {} diff --git a/Content.Shared/Nyanotrasen/Actions/Events/RegenerativeStasisPowerActionEvent.cs b/Content.Shared/Nyanotrasen/Actions/Events/RegenerativeStasisPowerActionEvent.cs new file mode 100644 index 00000000000..4435f475a44 --- /dev/null +++ b/Content.Shared/Nyanotrasen/Actions/Events/RegenerativeStasisPowerActionEvent.cs @@ -0,0 +1,2 @@ +namespace Content.Shared.Actions.Events; +public sealed partial class RegenerativeStasisPowerActionEvent : EntityTargetActionEvent {} diff --git a/Content.Shared/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs b/Content.Shared/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs index 89168d2b259..c3702880375 100644 --- a/Content.Shared/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs +++ b/Content.Shared/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs @@ -9,7 +9,7 @@ namespace Content.Shared.Psionics.Abilities public sealed partial class DamageOnDispelComponent : Component { [DataField("damage", required: true)] - public DamageSpecifier Damage = default!; + public DamageSpecifier Damage = default!; [DataField("variance")] public float Variance = 0.5f; diff --git a/Content.Shared/Psionics/Abilities/Dispel/DispelPowerComponent.cs b/Content.Shared/Psionics/Abilities/Dispel/DispelPowerComponent.cs index 1426712cf94..518a28b0967 100644 --- a/Content.Shared/Psionics/Abilities/Dispel/DispelPowerComponent.cs +++ b/Content.Shared/Psionics/Abilities/Dispel/DispelPowerComponent.cs @@ -1,4 +1,3 @@ -using Content.Shared.Actions; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; diff --git a/Content.Shared/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs b/Content.Shared/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs deleted file mode 100644 index dcd1d2c1c42..00000000000 --- a/Content.Shared/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Content.Shared.Actions; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Shared.Psionics.Abilities -{ - [RegisterComponent] - public sealed partial class MassSleepPowerComponent : Component - { - public float Radius = 1.25f; - [DataField("massSleepActionId", - customTypeSerializer: typeof(PrototypeIdSerializer))] - public string? MassSleepActionId = "ActionMassSleep"; - - [DataField("massSleepActionEntity")] - public EntityUid? MassSleepActionEntity; - - [DataField("massSleepFeedback")] - public string MassSleepFeedback = "mass-sleep-feedback"; - } -} diff --git a/Content.Shared/Psionics/Abilities/MassSleep/MassSleepPowerSystem.cs b/Content.Shared/Psionics/Abilities/MassSleep/MassSleepPowerSystem.cs deleted file mode 100644 index 1f2f6954e77..00000000000 --- a/Content.Shared/Psionics/Abilities/MassSleep/MassSleepPowerSystem.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Content.Shared.Actions; -using Content.Shared.Bed.Sleep; -using Content.Shared.Magic.Events; -using Content.Shared.Damage; -using Content.Shared.Mobs.Components; -using Robust.Shared.Prototypes; -using Robust.Shared.Timing; -using Content.Shared.Mind; -using Content.Shared.Actions.Events; - -namespace Content.Shared.Psionics.Abilities -{ - public sealed class MassSleepPowerSystem : EntitySystem - { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly SharedActionsSystem _actions = default!; - [Dependency] private readonly EntityLookupSystem _lookup = default!; - [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly SharedMindSystem _mindSystem = default!; - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnShutdown); - SubscribeLocalEvent(OnPowerUsed); - } - - private void OnInit(EntityUid uid, MassSleepPowerComponent component, ComponentInit args) - { - _actions.AddAction(uid, ref component.MassSleepActionEntity, component.MassSleepActionId ); - _actions.TryGetActionData( component.MassSleepActionEntity, out var actionData ); - if (actionData is { UseDelay: not null }) - _actions.StartUseDelay(component.MassSleepActionEntity); - if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - psionic.PsionicAbility = component.MassSleepActionEntity; - } - - private void OnShutdown(EntityUid uid, MassSleepPowerComponent component, ComponentShutdown args) - { - _actions.RemoveAction(uid, component.MassSleepActionEntity); - } - - private void OnPowerUsed(EntityUid uid, MassSleepPowerComponent component, MassSleepPowerActionEvent args) - { - foreach (var entity in _lookup.GetEntitiesInRange(args.Target, component.Radius)) - { - if (HasComp(entity) && entity != uid && !HasComp(entity)) - { - if (TryComp(entity, out var damageable) && damageable.DamageContainerID == "Biological") - EnsureComp(entity); - } - } - _psionics.LogPowerUsed(uid, "mass sleep"); - args.Handled = true; - } - } -} diff --git a/Content.Shared/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs b/Content.Shared/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs index 8570668f744..2fbfe18327e 100644 --- a/Content.Shared/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs +++ b/Content.Shared/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs @@ -1,4 +1,3 @@ -using Content.Shared.Actions; using Content.Shared.DoAfter; using Robust.Shared.Audio; using Robust.Shared.Prototypes; diff --git a/Content.Shared/Psionics/Abilities/RegenerativeStasis/RegenerativeStasisPowerComponent.cs b/Content.Shared/Psionics/Abilities/RegenerativeStasis/RegenerativeStasisPowerComponent.cs new file mode 100644 index 00000000000..27a0903e224 --- /dev/null +++ b/Content.Shared/Psionics/Abilities/RegenerativeStasis/RegenerativeStasisPowerComponent.cs @@ -0,0 +1,20 @@ +using Content.Shared.Actions; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Psionics.Abilities +{ + [RegisterComponent] + public sealed partial class RegenerativeStasisPowerComponent : Component + { + [DataField("regenerativeStasisActionId", + customTypeSerializer: typeof(PrototypeIdSerializer))] + public string? RegenerativeStasisActionId = "ActionRegenerativeStasis"; + + [DataField("regenerativeStasisActionEntity")] + public EntityUid? RegenerativeStasisActionEntity; + + [DataField("regenerativeStasisFeedback")] + public string RegenerativeStasisFeedback = "regenerative-stasis-feedback"; + } +} diff --git a/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs b/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs index 31af85bbb51..8be02f936a9 100644 --- a/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs +++ b/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs @@ -40,7 +40,7 @@ public GlimmerTier GetGlimmerTier(int? glimmer = null) if (glimmer == null) glimmer = Glimmer; - return (glimmer) switch + return glimmer switch { <= 49 => GlimmerTier.Minimal, >= 50 and <= 99 => GlimmerTier.Low, diff --git a/Content.Shared/Psionics/PsionicComponent.cs b/Content.Shared/Psionics/PsionicComponent.cs index 76e629f0839..9a06e54cb31 100644 --- a/Content.Shared/Psionics/PsionicComponent.cs +++ b/Content.Shared/Psionics/PsionicComponent.cs @@ -17,7 +17,7 @@ public sealed partial class PsionicComponent : Component public List ActivePowers = new(); [DataField("psychicFeedback")] - public List PsychicFeedback= new(); + public List PsychicFeedback = new(); [DataField("amplification")] public float Amplification = 0.1f; diff --git a/Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs b/Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs index a4b283f59ce..603c5188a52 100644 --- a/Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs +++ b/Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs @@ -4,7 +4,6 @@ using Content.Shared.Mobs.Components; using Content.Shared.Popups; using Content.Shared.Psionics.Glimmer; -using Content.Shared.Psionics.Abilities; using Robust.Shared.Random; using Robust.Shared.Serialization; @@ -74,7 +73,7 @@ public void SetPsionicsThroughEligibility(EntityUid uid) if (actionData == null) return; - _actions.SetEnabled(actionData.Owner, IsEligibleForPsionics(uid)); + _actions.SetEnabled(uid, IsEligibleForPsionics(uid)); } private bool IsEligibleForPsionics(EntityUid uid) diff --git a/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl b/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl index 5e6626eb9ca..6bdc84dc3ea 100644 --- a/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl +++ b/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl @@ -1,6 +1,19 @@ -dispel-feedback = {CAPITALIZE($entity)} projects an aura of normality +# Feedback messages for Focused Metapsionic Pulse +metapulse-self = I AM. no-powers = {CAPITALIZE($entity)} will never awaken from the dream in this life psychic-potential = {CAPITALIZE($entity)} has a slim chance of awakening from the dream -focused-metapsionic-pulse-begin = The air around {CAPITALIZE($entity)} begins to shimmer faintly, like a heat haze crawling across the endless desert -psionic-regeneration-self-revive = As {CAPITALIZE($entity)} falls to the floor greviously wounded, - they begin visibly regenerating! +dispel-feedback = {CAPITALIZE($entity)} is a mighty stone, standing against the currents of fate +metasionic-feedback = {CAPITALIZE($entity)} gazes back upon thee +mind-swap-feedback = {CAPITALIZE($entity)}'s vessel seems fit for other souls +mindswapped-feedback = Cursed flesh! {CAPITALIZE($entity)} dwells within the wrong vessel! +noospheric-zap-feedback = {CAPITALIZE($entity)}'s soul writhes with thunder from beyond the veil +pyrokinesis-feedback = The Secret of Fire dwells within {CAPITALIZE($entity)} +invisibility-feedback = {CAPITALIZE($entity)}'s wyrd seeks to hide from thine gaze +telegnosis-feedback = {CAPITALIZE($entity)}'s soul travels across bridges composed of dreamlight. +sophic-grammateus-feedback = SEEKER, YOU NEED ONLY ASK FOR MY WISDOM. +oracle-feedback = WHY DO YOU BOTHER ME SEEKER? HAVE I NOT MADE MY DESIRES CLEAR? +metempsychotic-machine-feedback = The sea of fate flows through this machine + +# Power PVS Messages +focused-metapsionic-pulse-begin = The air around {CAPITALIZE($entity)} begins to shimmer faintly +psionic-regeneration-self-revive = {CAPITALIZE($entity)} begins to visibly regenerate diff --git a/Resources/Prototypes/Nyanotrasen/Actions/types.yml b/Resources/Prototypes/Nyanotrasen/Actions/types.yml index 71a92ec4516..55dd48e5470 100644 --- a/Resources/Prototypes/Nyanotrasen/Actions/types.yml +++ b/Resources/Prototypes/Nyanotrasen/Actions/types.yml @@ -36,18 +36,18 @@ event: !type:DispelPowerActionEvent - type: entity - id: ActionMassSleep - name: action-name-mass-sleep - description: action-description-mass-sleep + id: ActionRegenerativeStasis + name: action-name-regenerative-stasis + description: action-description-regenerative-stasis noSpawn: true components: - - type: WorldTargetAction + - type: EntityTargetAction icon: Nyanotrasen/Interface/VerbIcons/mass_sleep.png useDelay: 60 checkCanAccess: false range: 8 itemIconStyle: BigAction - event: !type:MassSleepPowerActionEvent + event: !type:RegenerativeStasisPowerActionEvent - type: entity id: ActionMindSwap diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/metempsychoticMachine.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/metempsychoticMachine.yml index d8e791af1ed..5018a1da8f9 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/metempsychoticMachine.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/metempsychoticMachine.yml @@ -23,3 +23,5 @@ Gore: { state: pod_1 } Idle: { state: pod_0 } - type: Psionic + psychicFeedback: + - "metempsychotic-machine-feedback" diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/oracle.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/oracle.yml index f7481abf1ed..4e2183ef0b9 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/oracle.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/oracle.yml @@ -17,6 +17,8 @@ - type: Speech speechSounds: Tenor - type: Psionic + psychicFeedback: + - "oracle-feedback" - type: SolutionContainerManager solutions: fountain: diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml index ae85cd25e03..8e34a07ea5e 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml @@ -29,6 +29,8 @@ - Science - type: PotentialPsionic #this makes her easier to access for glimmer events, dw about it - type: Psionic + psychicFeedback: + - "sophic-grammateus-feedback" - type: Grammar attributes: gender: female From d177e55d29e800a407606126e39631b18a66ce1a Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Wed, 15 May 2024 17:34:34 -0400 Subject: [PATCH 20/82] Update psionicPowers.yml --- Resources/Prototypes/Nyanotrasen/psionicPowers.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Nyanotrasen/psionicPowers.yml b/Resources/Prototypes/Nyanotrasen/psionicPowers.yml index b577d419e38..ca1764e204c 100644 --- a/Resources/Prototypes/Nyanotrasen/psionicPowers.yml +++ b/Resources/Prototypes/Nyanotrasen/psionicPowers.yml @@ -5,7 +5,7 @@ DispelPower: 1 TelegnosisPower: 1 PsionicRegenerationPower: 1 - MassSleepPower: 0.3 + RegenerativeStasisPower: 0.3 PsionicInvisibilityPower: 0.15 MindSwapPower: 0.15 NoosphericZapPower: 0.15 From 685fc5fb160fb2ecd219d8720e3c60b4a23a2049 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Wed, 15 May 2024 17:40:52 -0400 Subject: [PATCH 21/82] Update psionic.ftl --- .../Locale/en-US/nyanotrasen/abilities/psionic.ftl | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl b/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl index 91ae21233a3..a27803aa6f7 100644 --- a/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl +++ b/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl @@ -3,8 +3,11 @@ cage-resist-third-person = {CAPITALIZE(THE($user))} starts removing {POSS-ADJ($u cage-uncage-verb = Uncage -action-name-metapsionic = Metapsionic Pulse -action-description-metapsionic = Send a mental pulse through the area to see if there are any psychics nearby. +action-name-widemetapsionic = Wide Metapsionic Pulse +action-description-widemetapsionic = Send a mental pulse through the area to see if there are any psychics nearby. + +action-name-focusedmetapsionic = Focused Metapsionic Pulse +action-description-focusedmetapsionic = Probe an entity at close range to glean metaphorical information about any powers they may have metapsionic-pulse-success = You detect psychic presence nearby. metapsionic-pulse-failure = You don't detect any psychic presence nearby. @@ -13,8 +16,8 @@ metapsionic-pulse-power = You detect that {$power} was used nearby. action-name-dispel = Dispel action-description-dispel = Dispel summoned entities such as familiars or forcewalls. -action-name-mass-sleep = Mass Sleep -action-description-mass-sleep = Put targets in a small area to sleep. +action-name-regenerative-stasis = Regenerative Stasis +action-description-regenerative-stasis = Puts the target into a brief stasis, during which time their wounds rapidly heal. accept-psionics-window-title = Psionic! accept-psionics-window-prompt-text-part = You rolled a psionic power! @@ -63,8 +66,7 @@ action-name-noospheric-zap = Noospheric Zap action-description-noospheric-zap = Shocks the conciousness of the target and leaves them stunned and stuttering. action-name-pyrokinesis = Pyrokinesis -action-description-pyrokinesis = Light a flammable target on fire. -pyrokinesis-power-used = A wisp of flame engulfs {THE($target)}, igniting {OBJECT($target)}! +action-description-pyrokinesis = Hurl a small gateway to the plane of Gehenna at your target. action-name-psychokinesis = Psychokinesis action-description-psychokinesis = Bend the fabric of space to instantly move across it. From 0d37ceb6d48c3ea5007dca7bfe935cfe4a5a03a0 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Wed, 15 May 2024 18:00:14 -0400 Subject: [PATCH 22/82] some more small tweaks --- Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs | 4 ++-- Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl | 4 ++++ .../Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl | 3 ++- .../Entities/Structures/Machines/metempsychoticMachine.yml | 1 + .../Nyanotrasen/Entities/Structures/Research/oracle.yml | 1 + 5 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs b/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs index ffe8ab00c2f..7b3a417c53f 100644 --- a/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs @@ -119,7 +119,7 @@ private void OnFocusedPowerUsed(FocusedMetapsionicPowerActionEvent args) var ev = new FocusedMetapsionicDoAfterEvent(_gameTiming.CurTime); - _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.Performer, component.UseDelay, ev, args.Performer, args.Target, args.Performer) + _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.Performer, component.UseDelay - psionic.Amplification, ev, args.Performer, args.Target, args.Performer) { BlockDuplicate = true, BreakOnUserMove = true, @@ -129,7 +129,7 @@ private void OnFocusedPowerUsed(FocusedMetapsionicPowerActionEvent args) component.DoAfter = doAfterId; - _popups.PopupEntity(Loc.GetString("focused-metapsionic-pulse-begin", ("entity", args.Performer)), + _popups.PopupEntity(Loc.GetString("focused-metapsionic-pulse-begin", ("entity", args.Target)), args.Performer, // TODO: Use LoS-based Filter when one is available. Filter.Pvs(args.Performer).RemoveWhereAttachedEntity(entity => !ExamineSystemShared.InRangeUnOccluded(args.Performer, entity, ExamineRange, null)), diff --git a/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl b/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl index a27803aa6f7..5b368e822f1 100644 --- a/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl +++ b/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl @@ -73,3 +73,7 @@ action-description-psychokinesis = Bend the fabric of space to instantly move ac action-name-rf-sensitivity = Toggle RF Sensitivity action-desc-rf-sensitivity = Toggle your ability to interpret radio waves on and off. + +trait-latent-psychic-desc = Your mind and soul are open to the noosphere, allowing for a limited use of Telepathy. + Thus, you are eligible for potentially receiving psychic powers. + It is possible that you may be hunted by otherworldly forces, so consider keeping your powers a secret. diff --git a/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl b/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl index 6bdc84dc3ea..d398c717c07 100644 --- a/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl +++ b/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl @@ -3,7 +3,7 @@ metapulse-self = I AM. no-powers = {CAPITALIZE($entity)} will never awaken from the dream in this life psychic-potential = {CAPITALIZE($entity)} has a slim chance of awakening from the dream dispel-feedback = {CAPITALIZE($entity)} is a mighty stone, standing against the currents of fate -metasionic-feedback = {CAPITALIZE($entity)} gazes back upon thee +metapsionic-feedback = {CAPITALIZE($entity)} gazes back upon thee mind-swap-feedback = {CAPITALIZE($entity)}'s vessel seems fit for other souls mindswapped-feedback = Cursed flesh! {CAPITALIZE($entity)} dwells within the wrong vessel! noospheric-zap-feedback = {CAPITALIZE($entity)}'s soul writhes with thunder from beyond the veil @@ -17,3 +17,4 @@ metempsychotic-machine-feedback = The sea of fate flows through this machine # Power PVS Messages focused-metapsionic-pulse-begin = The air around {CAPITALIZE($entity)} begins to shimmer faintly psionic-regeneration-self-revive = {CAPITALIZE($entity)} begins to visibly regenerate +mindbreaking-feedback = The light of life vanishes from {CAPITALIZE($entity)}'s eyes, leaving behind a husk pretending at sapience diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/metempsychoticMachine.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/metempsychoticMachine.yml index 5018a1da8f9..d773cf87c76 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/metempsychoticMachine.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/metempsychoticMachine.yml @@ -22,6 +22,7 @@ NoMind: { state: pod_1 } Gore: { state: pod_1 } Idle: { state: pod_0 } + - type: PotentialPsionic - type: Psionic psychicFeedback: - "metempsychotic-machine-feedback" diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/oracle.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/oracle.yml index 4e2183ef0b9..58189e49cec 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/oracle.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/oracle.yml @@ -16,6 +16,7 @@ - type: Oracle - type: Speech speechSounds: Tenor + - type: PotentialPsionic - type: Psionic psychicFeedback: - "oracle-feedback" From 324082a7a677683036e472ff378edea0ca422a12 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Wed, 15 May 2024 18:04:27 -0400 Subject: [PATCH 23/82] Update PotentialPsionicComponent.cs --- Content.Server/Psionics/PotentialPsionicComponent.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Content.Server/Psionics/PotentialPsionicComponent.cs b/Content.Server/Psionics/PotentialPsionicComponent.cs index 9499497cd1d..e874296a4c3 100644 --- a/Content.Server/Psionics/PotentialPsionicComponent.cs +++ b/Content.Server/Psionics/PotentialPsionicComponent.cs @@ -3,8 +3,15 @@ namespace Content.Server.Psionics [RegisterComponent] public sealed partial class PotentialPsionicComponent : Component { + /// + /// The base chance of an entity rolling psychic powers, which is increased by other modifiers such as glimmer. + /// + /// + /// I have increased this to 10% up from its original value of 2%, because I estimate that most people won't take the Latent Psychic trait + /// Simply because they might not even know it exists + /// [DataField("chance")] - public float Chance = 0.04f; + public float Chance = 0.10f; /// /// YORO (you only reroll once) From 952b7e232728449bda79ceb92a1e9d67dd801931 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Wed, 15 May 2024 18:41:37 -0400 Subject: [PATCH 24/82] Update Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs Co-authored-by: Danger Revolution! <142105406+DangerRevolution@users.noreply.github.com> --- Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs index 5124aff0688..e912a36ba25 100644 --- a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs @@ -30,7 +30,7 @@ public override void Initialize() /// /// Adds a psychic power once a character rolls one. This used to be a system you have to select for. However the opt-in is no longer the text window, but is now done at character creation. - /// This is going to get removed when I reach Part 3 of my reworks, when I touch upon the GlimmerSystem itself and overhaul how players get powers. + /// TODO: This is going to get removed when I reach Part 3 of my reworks, when I touch upon the GlimmerSystem itself and overhaul how players get powers. /// /// /// From 1a1c62a01166ca5fbece08a9d14591d645d4066e Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Wed, 15 May 2024 18:42:15 -0400 Subject: [PATCH 25/82] Update PsionicAbilitiesSystem.cs --- .../Abilities/PsionicAbilitiesSystem.cs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs index 5124aff0688..3f55e23794e 100644 --- a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs @@ -66,6 +66,16 @@ public void AddRandomPsionicPower(EntityUid uid) public void RemovePsionics(EntityUid uid) { + if (RemComp(uid)) + { + _popups.PopupEntity(Loc.GetString("mindbreaking-feedback", ("entity", uid)), + uid, + // TODO: Use LoS-based Filter when one is available. + Filter.Pvs(uid).RemoveWhereAttachedEntity(entity => !ExamineSystemShared.InRangeUnOccluded(uid, entity, ExamineRange, null)), + true, + PopupType.Medium); + } + if (!TryComp(uid, out var psionic)) return; @@ -92,16 +102,9 @@ public void RemovePsionics(EntityUid uid) } } - _popups.PopupEntity(Loc.GetString("mindbreaking-feedback", ("entity", uid)), - uid, - // TODO: Use LoS-based Filter when one is available. - Filter.Pvs(uid).RemoveWhereAttachedEntity(entity => !ExamineSystemShared.InRangeUnOccluded(uid, entity, ExamineRange, null)), - true, - PopupType.Medium); - _statusEffectsSystem.TryAddStatusEffect(uid, "Stutter", TimeSpan.FromMinutes(5), false, "StutteringAccent"); - _glimmerSystem.Glimmer += _random.Next((int) MathF.Round(psionic.Amplification * psionic.Dampening * -5), (int) MathF.Round(psionic.Amplification * psionic.Dampening * -10)); + _glimmerSystem.Glimmer += _random.Next((int) MathF.Round(psionic.Amplification * psionic.Dampening * -10), (int) MathF.Round(psionic.Amplification * psionic.Dampening * -5)); RemComp(uid); RemComp(uid); } From e4f387d83249484c2f6e216ce159264fdfd80dbe Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Wed, 15 May 2024 18:44:54 -0400 Subject: [PATCH 26/82] remove downstream comments --- Content.Server/Abilities/Mime/MimePowersSystem.cs | 2 +- Content.Server/Anomaly/AnomalySystem.Psionics.cs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Content.Server/Abilities/Mime/MimePowersSystem.cs b/Content.Server/Abilities/Mime/MimePowersSystem.cs index 3e7605a07d3..b3bd3392434 100644 --- a/Content.Server/Abilities/Mime/MimePowersSystem.cs +++ b/Content.Server/Abilities/Mime/MimePowersSystem.cs @@ -10,7 +10,7 @@ using Robust.Shared.Containers; using Robust.Shared.Map; using Robust.Shared.Timing; -using Content.Shared.Psionics.Abilities; //EE - Summary: Makes Mime psionic. +using Content.Shared.Psionics.Abilities; using Content.Shared.Speech.Muting; namespace Content.Server.Abilities.Mime diff --git a/Content.Server/Anomaly/AnomalySystem.Psionics.cs b/Content.Server/Anomaly/AnomalySystem.Psionics.cs index 3a5a55c0bdc..84f200f47ba 100644 --- a/Content.Server/Anomaly/AnomalySystem.Psionics.cs +++ b/Content.Server/Anomaly/AnomalySystem.Psionics.cs @@ -1,4 +1,4 @@ -using Content.Server.Psionics.Abilities; //EE - Summary: the psionics bin where dispel is located. +using Content.Server.Psionics.Abilities; using Content.Shared.Anomaly; using Content.Shared.Anomaly.Components; using Robust.Shared.Random; @@ -14,8 +14,6 @@ private void InitializePsionics() { SubscribeLocalEvent(OnDispelled); } - - //Nyano - Summary: gives dispellable behavior to Anomalies. private void OnDispelled(EntityUid uid, AnomalyComponent component, DispelledEvent args) { _dispel.DealDispelDamage(uid); From f5bf4d5bab436ad13f67294a6ada41a8a086f563 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Wed, 15 May 2024 19:32:40 -0400 Subject: [PATCH 27/82] Giving pyrokinesis back to ifrit, and setting up base caster stat bonuses to roundstart casters --- .../nyanotrasen/psionics/psychic-feedback.ftl | 3 +- .../DeltaV/Entities/Mobs/NPCs/familiars.yml | 7 +++-- .../Roles/Jobs/Epistemics/forensicmantis.yml | 15 +++++----- .../Roles/Jobs/Science/research_director.yml | 28 +++++++++---------- 4 files changed, 29 insertions(+), 24 deletions(-) diff --git a/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl b/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl index d398c717c07..26d2acb87cd 100644 --- a/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl +++ b/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl @@ -9,10 +9,11 @@ mindswapped-feedback = Cursed flesh! {CAPITALIZE($entity)} dwells within the wro noospheric-zap-feedback = {CAPITALIZE($entity)}'s soul writhes with thunder from beyond the veil pyrokinesis-feedback = The Secret of Fire dwells within {CAPITALIZE($entity)} invisibility-feedback = {CAPITALIZE($entity)}'s wyrd seeks to hide from thine gaze -telegnosis-feedback = {CAPITALIZE($entity)}'s soul travels across bridges composed of dreamlight. +telegnosis-feedback = {CAPITALIZE($entity)}'s soul travels across bridges composed of dreamlight sophic-grammateus-feedback = SEEKER, YOU NEED ONLY ASK FOR MY WISDOM. oracle-feedback = WHY DO YOU BOTHER ME SEEKER? HAVE I NOT MADE MY DESIRES CLEAR? metempsychotic-machine-feedback = The sea of fate flows through this machine +ifrit-feedback = A spirit of Gehenna, bound by the will of a powerful psychic # Power PVS Messages focused-metapsionic-pulse-begin = The air around {CAPITALIZE($entity)} begins to shimmer faintly diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml index 771da36719f..74a1eeee71b 100644 --- a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml +++ b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml @@ -84,7 +84,10 @@ - type: PotentialPsionic - type: Psionic removable: false - # - type: PyrokinesisPower # Pending psionic rework + amplification: 5 + psychicFeedback: + - "ifrit-feedback" + - type: PyrokinesisPower - type: Grammar attributes: proper: true @@ -103,7 +106,7 @@ requirements: - !type:DepartmentTimeRequirement department: Epistemics - time: 14400 # DeltaV - 4 hours + time: 14400 - type: entity parent: WelderExperimental diff --git a/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml b/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml index c3e682e02a9..15b2cdd4fa7 100644 --- a/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml +++ b/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml @@ -7,22 +7,24 @@ - !type:OverallPlaytimeRequirement time: 18000 - !type:DepartmentTimeRequirement - department: Epistemics # DeltaV - Epistemics Department replacing Science + department: Epistemics time: 3600 startingGear: ForensicMantisGear icon: "JobIconForensicMantis" supervisors: job-supervisors-rd - antagAdvantage: 5 # DeltaV - From 4 to 5 - canBeAntag: true # DeltaV - Mantis is no longer a Detective - # whitelistRequired: true + antagAdvantage: 5 + canBeAntag: true access: - Research - Maintenance - - Mantis # DeltaV - Psionic Mantis, see Resources/Prototypes/DeltaV/Access/epistemics.yml + - Mantis special: - !type:AddComponentSpecial components: + - type: PotentialPsionic - type: Psionic + amplification: 0.3 + dampening: 0.3 - type: MetapsionicPower - type: startingGear @@ -34,11 +36,10 @@ head: ClothingHeadHatFezMantis id: ForensicMantisPDA eyes: ClothingEyesGlassesSunglasses - ears: ClothingHeadsetScience # DeltaV - Mantis is part of Epistemics + ears: ClothingHeadsetScience gloves: ClothingHandsGlovesColorWhite outerClothing: ClothingOuterCoatMantis belt: ClothingBeltMantis - # pocket2: ForensicScanner # DeltaV - Mantis is no longer a Detective innerClothingSkirt: ClothingUniformSkirtMantis satchel: ClothingBackpackSatchelMantisFilled duffelbag: ClothingBackpackDuffelMantisFilled diff --git a/Resources/Prototypes/Roles/Jobs/Science/research_director.yml b/Resources/Prototypes/Roles/Jobs/Science/research_director.yml index 19cf1419111..ddb779669eb 100644 --- a/Resources/Prototypes/Roles/Jobs/Science/research_director.yml +++ b/Resources/Prototypes/Roles/Jobs/Science/research_director.yml @@ -3,13 +3,13 @@ name: job-name-rd description: job-description-rd playTimeTracker: JobResearchDirector - antagAdvantage: 6 # DeltaV - Reduced TC: Head of Staff + antagAdvantage: 6 requirements: - !type:DepartmentTimeRequirement - department: Epistemics # DeltaV - Epistemics Department replacing Science - time: 54000 # DeltaV - 15 hours + department: Epistemics + time: 54000 - !type:OverallPlaytimeRequirement - time: 72000 # DeltaV - 20 hours + time: 72000 weight: 10 startingGear: ResearchDirectorGear icon: "JobIconResearchDirector" @@ -21,20 +21,20 @@ - Command - Maintenance - ResearchDirector - - Mantis # DeltaV - Psionic Mantis, see Resources/Prototypes/DeltaV/Access/epistemics.yml - - Chapel # DeltaV - Chaplain is in Epistemics + - Mantis + - Chapel - Cryogenics - special: # Nyanotrasen - Mystagogue can use the Bible + special: - !type:AddComponentSpecial components: - - type: BibleUser # Nyano - Lets them heal with bibles - - type: Psionic # Nyano - They start with telepathic chat - - type: DispelPower # Nyano - They get the Dispel psionic power on spawn + - type: BibleUser + - type: PotentialPsionic + - type: Psionic + dampening: 1 #Mystagogue gets a significant buff to his antimage abilities, making him better at dispelling than other people + - type: DispelPower + - type: CommandStaff - !type:AddImplantSpecial implants: [ MindShieldImplant ] - - !type:AddComponentSpecial - components: - - type: CommandStaff - type: startingGear id: ResearchDirectorGear @@ -44,7 +44,7 @@ shoes: ClothingShoesColorBrown id: RnDPDA ears: ClothingHeadsetRD - belt: BibleMystagogue # Nyanotrasen - Mystagogue book for their Ifrit + belt: BibleMystagogue innerClothingSkirt: ClothingUniformJumpskirtResearchDirector satchel: ClothingBackpackSatchelResearchDirectorFilled duffelbag: ClothingBackpackDuffelResearchDirectorFilled From 626f2a5c62942ab237df245552ce0d10a9dfbf6d Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Wed, 15 May 2024 19:42:58 -0400 Subject: [PATCH 28/82] Update familiars.yml --- Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml index 74a1eeee71b..4f255cad211 100644 --- a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml +++ b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml @@ -84,7 +84,7 @@ - type: PotentialPsionic - type: Psionic removable: false - amplification: 5 + amplification: 4 psychicFeedback: - "ifrit-feedback" - type: PyrokinesisPower From 3584a4e23499e2b1643ea3e409b01c7265d6ca84 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 28 May 2024 21:40:16 -0400 Subject: [PATCH 29/82] Update PsionicRegenerationPowerSystem.cs --- .../Abilities/PsionicRegenerationPowerSystem.cs | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs b/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs index 882eb9e0b14..6958170a5c2 100644 --- a/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs @@ -12,7 +12,6 @@ using Content.Shared.Popups; using Content.Shared.Psionics.Events; using Content.Shared.Examine; -using static Content.Shared.Examine.ExamineSystemShared; using Robust.Shared.Timing; using Content.Shared.Actions.Events; using Robust.Server.Audio; @@ -28,6 +27,7 @@ public sealed class PsionicRegenerationPowerSystem : EntitySystem [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly ExamineSystemShared _examine = default!; public override void Initialize() { @@ -73,13 +73,7 @@ private void OnPowerUsed(EntityUid uid, PsionicRegenerationPowerComponent compon component.DoAfter = doAfterId; - _popupSystem.PopupEntity(Loc.GetString("psionic-regeneration-begin", ("entity", uid)), - uid, - // TODO: Use LoS-based Filter when one is available. - Filter.Pvs(uid).RemoveWhereAttachedEntity(entity => !ExamineSystemShared.InRangeUnOccluded(uid, entity, ExamineRange, null)), - true, - PopupType.Medium); - + _popupSystem.PopupEntity(Loc.GetString("psionic-regeneration-begin", ("entity", uid)), uid, PopupType.Medium); _audioSystem.PlayPvs(component.SoundUse, uid, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); _psionics.LogPowerUsed(uid, "psionic regeneration", @@ -122,12 +116,7 @@ private void OnMobStateChangedEvent(EntityUid uid, PsionicRegenerationPowerCompo BreakOnDamage = false, RequireCanInteract = false, }); - _popupSystem.PopupEntity(Loc.GetString("psionic-regeneration-self-revive", ("entity", uid)), - uid, - // TODO: Use LoS-based Filter when one is available. - Filter.Pvs(uid).RemoveWhereAttachedEntity(entity => !ExamineSystemShared.InRangeUnOccluded(uid, entity, ExamineRange, null)), - true, - PopupType.MediumCaution); + _popupSystem.PopupEntity(Loc.GetString("psionic-regeneration-self-revive", ("entity", uid)), uid, PopupType.MediumCaution); _audioSystem.PlayPvs(component.SoundUse, uid, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); _psionics.LogPowerUsed(uid, "psionic regeneration", From d439c5a9620844ae2e0e495822eea1cc0b43e7ce Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 28 May 2024 22:04:53 -0400 Subject: [PATCH 30/82] Revert "Merge branch 'VMSolidus-Psionic-Power-Refactor'" This reverts commit 15fc457e8f1ffa3a05966566dff93dbe6994310a, reversing changes made to c62f777aee0c5e28df70953f77de950009e42c13. --- .github/workflows/build-docfx.yml | 2 +- .../Atmos/Overlays/GasTileOverlay.cs | 70 ++-- Content.Client/Mapping/MappingSystem.cs | 2 +- .../Cartridges}/GlimmerMonitorUi.cs | 3 +- .../Cartridges}/GlimmerMonitorUiFragment.xaml | 2 +- .../GlimmerMonitorUiFragment.xaml.cs | 4 +- .../Chat}/PsionicChatUpdateSystem.cs | 4 +- .../Glimmer/GlimmerReactiveVisuals.cs | 0 .../Psionics/UI}/AcceptPsionicsEUI.cs | 0 .../Psionics/UI}/AcceptPsionicsWindow.cs | 0 .../UserInterface/GlimmerGraph.cs | 2 +- .../Options/UI/Tabs/KeyRebindTab.xaml.cs | 2 +- .../Systems/Chat/ChatUIController.cs | 9 +- .../Tests/Body/LungTest.cs | 2 +- .../Interaction/InteractionTest.Helpers.cs | 7 +- .../Abilities/Mime/MimePowersSystem.cs | 2 +- .../Managers/AdminManager.Metrics.cs | 98 ------ .../Administration/Managers/AdminManager.cs | 9 +- .../Systems/AdminVerbSystem.Smites.cs | 12 +- .../Anomaly/AnomalySystem.Psionics.cs | 4 +- .../Atmos/Commands/SetMapAtmosCommand.cs | 94 ----- .../Atmos/Components/AirtightComponent.cs | 4 +- .../Components/GridAtmosphereComponent.cs | 8 +- .../Components/IgniteOnCollideComponent.cs | 4 +- .../Components/MapAtmosphereComponent.cs | 8 +- .../Atmos/EntitySystems/AirtightSystem.cs | 18 +- .../EntitySystems/AtmosDebugOverlaySystem.cs | 11 +- .../AtmosObstructionEnumerator.cs | 37 ++ .../EntitySystems/AtmosphereSystem.API.cs | 45 ++- .../AtmosphereSystem.ExcitedGroup.cs | 28 +- .../AtmosphereSystem.GridAtmosphere.cs | 247 +++++++++----- .../AtmosphereSystem.HighPressureDelta.cs | 10 +- .../EntitySystems/AtmosphereSystem.LINDA.cs | 18 +- .../EntitySystems/AtmosphereSystem.Map.cs | 108 +----- .../AtmosphereSystem.Monstermos.cs | 110 +++--- .../AtmosphereSystem.Processing.cs | 323 ++++++------------ .../AtmosphereSystem.Superconductivity.cs | 8 +- .../EntitySystems/AtmosphereSystem.Utils.cs | 62 ++-- .../Atmos/EntitySystems/AtmosphereSystem.cs | 7 - .../EntitySystems/AutomaticAtmosSystem.cs | 8 +- .../Atmos/EntitySystems/GasAnalyzerSystem.cs | 4 +- .../EntitySystems/GasTileOverlaySystem.cs | 6 +- Content.Server/Atmos/GasMixture.cs | 57 +--- .../Unary/EntitySystems/GasCanisterSystem.cs | 2 +- .../Unary/EntitySystems/GasCondenserSystem.cs | 2 +- .../TileAtmosCollectionSerializer.cs | 8 +- Content.Server/Atmos/TileAtmosphere.cs | 53 +-- Content.Server/Body/Systems/LungSystem.cs | 2 +- Content.Server/Chat/Systems/ChatSystem.cs | 2 +- .../Chemistry/EntitySystems/VaporSystem.cs | 4 +- .../Chemistry/ReagentEffects/ModifyLungGas.cs | 13 +- .../Conditions/ComponentInTile.cs | 11 +- .../Events/GlimmerMobSpawnRule.cs | 2 +- .../ExplosionSystem.Processing.cs | 4 +- .../ImmovableRod/ImmovableRodSystem.cs | 6 +- .../Psionics/Abilities/DispelPowerSystem.cs | 31 +- .../Abilities/MetapsionicPowerSystem.cs | 74 ++++ .../Psionics/Abilities/MindSwapPowerSystem.cs | 62 ++-- .../Abilities/MindSwappedComponent.cs | 5 +- .../Abilities/NoosphericZapPowerSystem.cs | 44 ++- .../PsionicInvisibilityPowerSystem.cs | 94 ++--- .../PsionicRegenerationPowerSystem.cs | 128 +++++++ .../Abilities/PyrokinesisPowerSystem.cs | 66 ++++ .../Abilities/TelegnosisPowerSystem.cs | 67 ++++ .../Psionics}/PsionicAbilitiesSystem.cs | 89 +++-- .../Audio/GlimmerSoundComponent.cs | 6 +- .../Chat/NyanoChatSystem.cs} | 18 +- .../Chat}/TSayCommand.cs | 3 +- .../Chat}/TelepathicRepeaterComponent.cs | 2 +- .../Chemistry/Effects/ChemRemovePsionic.cs | 2 +- .../BecomePsionicConditionComponent.cs | 11 + .../Systems/BecomePsionicConditionSystem.cs | 32 ++ .../Psionics/AcceptPsionicsEui.cs | 2 +- .../Psionics/AntiPsychicWeaponComponent.cs | 0 .../Psionics/Dreams/DreamSystem.cs | 3 + .../Psionics/Glimmer/GlimmerCommands.cs | 0 .../Psionics/Glimmer/GlimmerReactiveSystem.cs | 5 +- .../Glimmer/PassiveGlimmerReductionSystem.cs | 2 + .../Structures/GlimmerSourceComponent.cs | 0 .../Structures/GlimmerStructuresSystem.cs | 0 .../Invisibility/PsionicInvisibilitySystem.cs | 25 +- .../PsionicInvisibleContactsComponent.cs | 1 + .../PsionicInvisibleContactsSystem.cs | 2 + .../PsionicallyInvisibleComponent.cs | 0 .../Psionics/PotentialPsionicComponent.cs | 14 + .../PsionicAwaitingPlayerComponent.cs | 0 .../Psionics/PsionicBonusChanceComponent.cs | 0 .../Psionics/PsionicsCommands.cs | 6 +- .../Psionics/PsionicsSystem.cs | 23 +- .../Research/Oracle/OracleSystem.cs | 2 +- .../SophicScribe/SophicScribeSystem.cs | 2 +- .../Events/GlimmerWispSpawnRule.cs | 2 +- .../StationEvents/Events/MassMindSwapRule.cs | 5 +- .../StationEvents/Events/NoosphericFryRule.cs | 2 +- .../Events/NoosphericStormRule.cs | 4 +- .../StationEvents/Events/NoosphericZapRule.cs | 2 +- .../Events/PsionicCatGotYourTongueRule.cs | 2 +- Content.Server/Parallax/BiomeSystem.cs | 11 +- .../ParticleAcceleratorSystem.Emitter.cs | 2 +- .../Physics/Controllers/ChasingWalkSystem.cs | 2 +- .../Power/Generator/GasPowerReceiverSystem.cs | 2 +- .../Abilities/MetapsionicPowerSystem.cs | 188 ---------- .../PsionicRegenerationPowerSystem.cs | 179 ---------- .../Abilities/PyrokinesisPowerSystem.cs | 93 ----- .../RegenerativeStasisPowerSystem.cs | 76 ----- .../Abilities/TelegnosisPowerSystem.cs | 106 ------ .../Psionics/PotentialPsionicComponent.cs | 21 -- .../Salvage/SpawnSalvageMissionJob.cs | 6 +- .../Systems/ShuttleSystem.FasterThanLight.cs | 8 +- .../Shuttles/Systems/ShuttleSystem.cs | 8 +- .../EntitySystems/EventHorizonSystem.cs | 4 +- Content.Server/Spreader/SpreaderSystem.cs | 69 ++-- .../StationEvents/Events/MeteorSwarmRule.cs | 6 +- .../Zombies/ZombieSystem.Transform.cs | 4 +- Content.Shared/Atmos/Atmospherics.cs | 7 +- .../SharedGasTileOverlaySystem.cs | 3 - .../Buckle/SharedBuckleSystem.Buckle.cs | 2 +- Content.Shared/Maps/ContentTileDefinition.cs | 6 +- Content.Shared/Maps/TurfHelpers.cs | 27 +- .../Movement/Systems/SharedJetpackSystem.cs | 4 +- .../Abilities/AcceptPsionicsEuiMessage.cs | 0 .../Dispel/DamageOnDispelComponent.cs | 4 +- .../Abilities/Dispel/DispelPowerComponent.cs | 8 +- .../Abilities/Dispel/DispellableComponent.cs | 2 +- .../MassSleep/MassSleepPowerComponent.cs | 18 + .../MassSleep/MassSleepPowerSystem.cs | 59 ++++ .../Metapsionics/MetapsionicPowerComponent.cs | 21 ++ .../MindSwap/MindSwapPowerComponent.cs | 5 +- .../NoosphericZapPowerComponent.cs | 5 +- .../PsionicInvisibilityPowerComponent.cs | 8 +- .../PsionicInvisibilityUsedComponent.cs | 3 +- .../PsionicRegenerationPowerComponent.cs | 10 +- .../Pyrokinesis/PyrokinesisPowerComponent.cs | 5 +- .../Telegnosis/TelegnosisPowerComponent.cs | 10 +- .../TelegnosticProjectionComponent.cs | 6 + .../ClothingGrantPsionicPowerComponent.cs | 2 +- .../Psionics/Items/HeadCageComponent.cs | 2 +- .../Psionics/Items/HeadCagedComponent.cs | 2 +- .../Psionics/Items/PsionicItemsSystem.cs | 2 +- .../Psionics/Items/TinfoilHatComponent.cs | 2 +- .../Abilities}/Psionics/PsionicComponent.cs | 16 +- .../Psionics/PsionicInsulationComponent.cs | 2 +- .../Psionics/PsionicsDisabledComponent.cs | 2 +- .../Psionics/SharedPsionicAbilitiesSystem.cs | 4 +- .../Events/MassSleepPowerActionEvent.cs | 2 + .../Events/MetapsionicPowerActionEvent.cs | 3 +- .../Events/PyrokinesisPowerActionEvent.cs | 4 +- .../RegenerativeStasisPowerActionEvent.cs | 2 - Content.Shared/Nyanotrasen/Psionics/Events.cs | 28 ++ .../Psionics/Glimmer/GlimmerSystem.cs | 2 +- .../Glimmer/SharedGlimmerReactiveComponent.cs | 0 .../Glimmer/SharedGlimmerReactiveVisuals.cs | 0 .../Metapsionics/MetapsionicPowerComponent.cs | 38 --- .../RegenerativeStasisPowerComponent.cs | 20 -- .../TelegnosticProjectionComponent.cs | 8 - Content.Shared/Psionics/Events.cs | 64 ---- .../Psionics/SharedPsionicSystem.Insulated.cs | 4 - Content.Shared/Throwing/ThrowingSystem.cs | 6 +- Content.Shared/Throwing/ThrownItemSystem.cs | 2 +- .../Weapons/Melee/MeleeThrowOnHitSystem.cs | 4 +- .../Weapons/Misc/SharedTetherGunSystem.cs | 10 +- .../Weapons/Ranged/Systems/SharedGunSystem.cs | 2 +- .../Audio/Nyanotrasen/heartbeat_fast.ogg | Bin 39983 -> 0 bytes Resources/Changelog/Changelog.yml | 14 - Resources/Credits/GitHub.txt | 2 +- Resources/Locale/en-US/atmos/commands.ftl | 8 - .../en-US/nyanotrasen/abilities/psionic.ftl | 18 +- .../nyanotrasen/psionics/psychic-feedback.ftl | 21 -- .../Catalog/Cargo/cargo_vending.yml | 2 +- .../Inventories/clothesmate.yml | 5 - .../DeltaV/Entities/Mobs/NPCs/familiars.yml | 7 +- .../DeltaV/Entities/Mobs/Player/harpy.yml | 1 + .../DeltaV/Entities/Mobs/Player/vulpkanin.yml | 1 + .../Prototypes/DeltaV/GameRules/events.yml | 5 +- .../Clothing/OuterClothing/wintercoats.yml | 55 --- .../Entities/Mobs/Player/arachnid.yml | 1 + .../Prototypes/Entities/Mobs/Player/diona.yml | 1 + .../Prototypes/Entities/Mobs/Player/dwarf.yml | 2 + .../Prototypes/Entities/Mobs/Player/human.yml | 2 + .../Prototypes/Entities/Mobs/Player/moth.yml | 2 + .../Entities/Mobs/Player/reptilian.yml | 2 + .../Prototypes/Entities/Mobs/Player/slime.yml | 2 + .../Entities/Mobs/Species/human.yml | 1 + .../Objects/Specific/Hydroponics/leaves.yml | 8 +- .../Specific/Robotics/borg_modules.yml | 2 +- .../Prototypes/Nyanotrasen/Actions/types.yml | 34 +- .../Nyanotrasen/Entities/Mobs/Player/Oni.yml | 1 + .../Entities/Mobs/Player/felinid.yml | 2 + .../Machines/metempsychoticMachine.yml | 3 - .../Entities/Structures/Research/oracle.yml | 3 - .../Structures/Research/sophicscribe.yml | 2 - .../Nyanotrasen/Objectives/traitor.yml | 23 ++ .../Roles/Jobs/Epistemics/forensicmantis.yml | 15 +- .../Nyanotrasen/Traits/psionics.yml | 6 - .../Prototypes/Nyanotrasen/psionicPowers.yml | 6 +- .../Prototypes/Objectives/objectiveGroups.yml | 1 + .../Objectives/stealTargetGroups.yml | 7 +- Resources/Prototypes/Objectives/thief.yml | 15 +- .../Roles/Jobs/Science/research_director.yml | 28 +- .../equipped-OUTERCLOTHING.png | Bin 8610 -> 0 bytes .../WinterCoats/cs_corpo_jacket.rsi/icon.png | Bin 5930 -> 0 bytes .../WinterCoats/cs_corpo_jacket.rsi/meta.json | 18 - .../equipped-OUTERCLOTHING.png | Bin 8514 -> 0 bytes .../WinterCoats/ee_corpo_jacket.rsi/icon.png | Bin 6063 -> 0 bytes .../WinterCoats/ee_corpo_jacket.rsi/meta.json | 18 - .../equipped-OUTERCLOTHING.png | Bin 8310 -> 0 bytes .../WinterCoats/hi_corpo_jacket.rsi/icon.png | Bin 5980 -> 0 bytes .../WinterCoats/hi_corpo_jacket.rsi/meta.json | 18 - .../equipped-OUTERCLOTHING.png | Bin 9341 -> 0 bytes .../WinterCoats/hm_corpo_jacket.rsi/icon.png | Bin 6169 -> 0 bytes .../WinterCoats/hm_corpo_jacket.rsi/meta.json | 18 - .../equipped-OUTERCLOTHING.png | Bin 9025 -> 0 bytes .../WinterCoats/id_corpo_jacket.rsi/icon.png | Bin 5955 -> 0 bytes .../WinterCoats/id_corpo_jacket.rsi/meta.json | 18 - Resources/keybinds.yml | 1 - global.json | 2 +- 216 files changed, 1588 insertions(+), 2450 deletions(-) rename Content.Client/{Psionics/GlimmerMonitor => Nyanotrasen/CartridgeLoader/Cartridges}/GlimmerMonitorUi.cs (92%) rename Content.Client/{Psionics/GlimmerMonitor => Nyanotrasen/CartridgeLoader/Cartridges}/GlimmerMonitorUiFragment.xaml (93%) rename Content.Client/{Psionics/GlimmerMonitor => Nyanotrasen/CartridgeLoader/Cartridges}/GlimmerMonitorUiFragment.xaml.cs (96%) rename Content.Client/{Psionics/Telepathy => Nyanotrasen/Chat}/PsionicChatUpdateSystem.cs (92%) rename Content.Client/{ => Nyanotrasen}/Psionics/Glimmer/GlimmerReactiveVisuals.cs (100%) rename Content.Client/{Psionics/UserInterface => Nyanotrasen/Psionics/UI}/AcceptPsionicsEUI.cs (100%) rename Content.Client/{Psionics/UserInterface => Nyanotrasen/Psionics/UI}/AcceptPsionicsWindow.cs (100%) rename Content.Client/{Psionics => Nyanotrasen}/UserInterface/GlimmerGraph.cs (97%) delete mode 100644 Content.Server/Administration/Managers/AdminManager.Metrics.cs delete mode 100644 Content.Server/Atmos/Commands/SetMapAtmosCommand.cs create mode 100644 Content.Server/Atmos/EntitySystems/AtmosObstructionEnumerator.cs rename Content.Server/{ => Nyanotrasen/Abilities}/Psionics/Abilities/DispelPowerSystem.cs (83%) create mode 100644 Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs rename Content.Server/{ => Nyanotrasen/Abilities}/Psionics/Abilities/MindSwapPowerSystem.cs (78%) rename Content.Server/{ => Nyanotrasen/Abilities}/Psionics/Abilities/MindSwappedComponent.cs (79%) rename Content.Server/{ => Nyanotrasen/Abilities}/Psionics/Abilities/NoosphericZapPowerSystem.cs (54%) rename Content.Server/{ => Nyanotrasen/Abilities}/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs (57%) create mode 100644 Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs create mode 100644 Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs create mode 100644 Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs rename Content.Server/{Psionics/Abilities => Nyanotrasen/Abilities/Psionics}/PsionicAbilitiesSystem.cs (54%) rename Content.Server/{Psionics => Nyanotrasen}/Audio/GlimmerSoundComponent.cs (80%) rename Content.Server/{Psionics/Telepathy/TelepathyChatSystem.cs => Nyanotrasen/Chat/NyanoChatSystem.cs} (85%) rename Content.Server/{Psionics/Telepathy => Nyanotrasen/Chat}/TSayCommand.cs (95%) rename Content.Server/{Psionics/Telepathy => Nyanotrasen/Chat}/TelepathicRepeaterComponent.cs (82%) create mode 100644 Content.Server/Nyanotrasen/Objectives/Components/BecomePsionicConditionComponent.cs create mode 100644 Content.Server/Nyanotrasen/Objectives/Systems/BecomePsionicConditionSystem.cs rename Content.Server/{ => Nyanotrasen}/Psionics/AcceptPsionicsEui.cs (95%) rename Content.Server/{ => Nyanotrasen}/Psionics/AntiPsychicWeaponComponent.cs (100%) rename Content.Server/{ => Nyanotrasen}/Psionics/Dreams/DreamSystem.cs (93%) rename Content.Server/{ => Nyanotrasen}/Psionics/Glimmer/GlimmerCommands.cs (100%) rename Content.Server/{ => Nyanotrasen}/Psionics/Glimmer/GlimmerReactiveSystem.cs (99%) rename Content.Server/{ => Nyanotrasen}/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs (94%) rename Content.Server/{ => Nyanotrasen}/Psionics/Glimmer/Structures/GlimmerSourceComponent.cs (100%) rename Content.Server/{ => Nyanotrasen}/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs (100%) rename Content.Server/{ => Nyanotrasen}/Psionics/Invisibility/PsionicInvisibilitySystem.cs (88%) rename Content.Server/{ => Nyanotrasen}/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs (95%) rename Content.Server/{ => Nyanotrasen}/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs (95%) rename Content.Server/{ => Nyanotrasen}/Psionics/Invisibility/PsionicallyInvisibleComponent.cs (100%) create mode 100644 Content.Server/Nyanotrasen/Psionics/PotentialPsionicComponent.cs rename Content.Server/{ => Nyanotrasen}/Psionics/PsionicAwaitingPlayerComponent.cs (100%) rename Content.Server/{ => Nyanotrasen}/Psionics/PsionicBonusChanceComponent.cs (100%) rename Content.Server/{ => Nyanotrasen}/Psionics/PsionicsCommands.cs (84%) rename Content.Server/{ => Nyanotrasen}/Psionics/PsionicsSystem.cs (91%) delete mode 100644 Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs delete mode 100644 Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs delete mode 100644 Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs delete mode 100644 Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs delete mode 100644 Content.Server/Psionics/Abilities/TelegnosisPowerSystem.cs delete mode 100644 Content.Server/Psionics/PotentialPsionicComponent.cs rename Content.Shared/{ => Nyanotrasen/Abilities}/Psionics/Abilities/AcceptPsionicsEuiMessage.cs (100%) rename Content.Shared/{ => Nyanotrasen/Abilities}/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs (77%) rename Content.Shared/{ => Nyanotrasen/Abilities}/Psionics/Abilities/Dispel/DispelPowerComponent.cs (79%) rename Content.Shared/{ => Nyanotrasen/Abilities}/Psionics/Abilities/Dispel/DispellableComponent.cs (69%) create mode 100644 Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs create mode 100644 Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerSystem.cs create mode 100644 Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs rename Content.Shared/{ => Nyanotrasen/Abilities}/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs (76%) rename Content.Shared/{ => Nyanotrasen/Abilities}/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs (77%) rename Content.Shared/{ => Nyanotrasen/Abilities}/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs (71%) rename Content.Shared/{ => Nyanotrasen/Abilities}/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs (94%) rename Content.Shared/{ => Nyanotrasen/Abilities}/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs (76%) rename Content.Shared/{ => Nyanotrasen/Abilities}/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs (79%) rename Content.Shared/{ => Nyanotrasen/Abilities}/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs (73%) create mode 100644 Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs rename Content.Shared/{ => Nyanotrasen/Abilities}/Psionics/Items/ClothingGrantPsionicPowerComponent.cs (84%) rename Content.Shared/{ => Nyanotrasen/Abilities}/Psionics/Items/HeadCageComponent.cs (96%) rename Content.Shared/{ => Nyanotrasen/Abilities}/Psionics/Items/HeadCagedComponent.cs (81%) rename Content.Shared/{ => Nyanotrasen/Abilities}/Psionics/Items/PsionicItemsSystem.cs (98%) rename Content.Shared/{ => Nyanotrasen/Abilities}/Psionics/Items/TinfoilHatComponent.cs (90%) rename Content.Shared/{ => Nyanotrasen/Abilities}/Psionics/PsionicComponent.cs (51%) rename Content.Shared/{ => Nyanotrasen/Abilities}/Psionics/PsionicInsulationComponent.cs (82%) rename Content.Shared/{ => Nyanotrasen/Abilities}/Psionics/PsionicsDisabledComponent.cs (84%) rename Content.Shared/{ => Nyanotrasen/Abilities}/Psionics/SharedPsionicAbilitiesSystem.cs (97%) create mode 100644 Content.Shared/Nyanotrasen/Actions/Events/MassSleepPowerActionEvent.cs delete mode 100644 Content.Shared/Nyanotrasen/Actions/Events/RegenerativeStasisPowerActionEvent.cs create mode 100644 Content.Shared/Nyanotrasen/Psionics/Events.cs rename Content.Shared/{ => Nyanotrasen}/Psionics/Glimmer/GlimmerSystem.cs (98%) rename Content.Shared/{ => Nyanotrasen}/Psionics/Glimmer/SharedGlimmerReactiveComponent.cs (100%) rename Content.Shared/{ => Nyanotrasen}/Psionics/Glimmer/SharedGlimmerReactiveVisuals.cs (100%) delete mode 100644 Content.Shared/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs delete mode 100644 Content.Shared/Psionics/Abilities/RegenerativeStasis/RegenerativeStasisPowerComponent.cs delete mode 100644 Content.Shared/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs delete mode 100644 Content.Shared/Psionics/Events.cs delete mode 100644 Content.Shared/Psionics/SharedPsionicSystem.Insulated.cs delete mode 100644 Resources/Audio/Nyanotrasen/heartbeat_fast.ogg delete mode 100644 Resources/Locale/en-US/atmos/commands.ftl delete mode 100644 Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl delete mode 100644 Resources/Prototypes/Nyanotrasen/Traits/psionics.yml delete mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi/equipped-OUTERCLOTHING.png delete mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi/icon.png delete mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi/meta.json delete mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi/equipped-OUTERCLOTHING.png delete mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi/icon.png delete mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi/meta.json delete mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/hi_corpo_jacket.rsi/equipped-OUTERCLOTHING.png delete mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/hi_corpo_jacket.rsi/icon.png delete mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/hi_corpo_jacket.rsi/meta.json delete mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/hm_corpo_jacket.rsi/equipped-OUTERCLOTHING.png delete mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/hm_corpo_jacket.rsi/icon.png delete mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/hm_corpo_jacket.rsi/meta.json delete mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/id_corpo_jacket.rsi/equipped-OUTERCLOTHING.png delete mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/id_corpo_jacket.rsi/icon.png delete mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/id_corpo_jacket.rsi/meta.json diff --git a/.github/workflows/build-docfx.yml b/.github/workflows/build-docfx.yml index d37e37026d7..ca1a6f0af12 100644 --- a/.github/workflows/build-docfx.yml +++ b/.github/workflows/build-docfx.yml @@ -21,7 +21,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v3.2.0 with: - dotnet-version: 8.0.100 + dotnet-version: 8.0.x - name: Install dependencies run: dotnet restore diff --git a/Content.Client/Atmos/Overlays/GasTileOverlay.cs b/Content.Client/Atmos/Overlays/GasTileOverlay.cs index f4dc274a4e5..ef65d43fe85 100644 --- a/Content.Client/Atmos/Overlays/GasTileOverlay.cs +++ b/Content.Client/Atmos/Overlays/GasTileOverlay.cs @@ -8,6 +8,7 @@ using Robust.Client.Graphics; using Robust.Client.ResourceManagement; using Robust.Shared.Enums; +using Robust.Shared.Graphics; using Robust.Shared.Graphics.RSI; using Robust.Shared.Map; using Robust.Shared.Map.Components; @@ -22,7 +23,7 @@ public sealed class GasTileOverlay : Overlay private readonly IEntityManager _entManager; private readonly IMapManager _mapManager; - public override OverlaySpace Space => OverlaySpace.WorldSpaceEntities | OverlaySpace.WorldSpaceBelowWorld; + public override OverlaySpace Space => OverlaySpace.WorldSpaceEntities; private readonly ShaderInstance _shader; // Gas overlays @@ -78,8 +79,7 @@ public GasTileOverlay(GasTileOverlaySystem system, IEntityManager entManager, IR var rsi = resourceCache.GetResource(animated.RsiPath).RSI; var stateId = animated.RsiState; - if (!rsi.TryGetState(stateId, out var state)) - continue; + if (!rsi.TryGetState(stateId, out var state)) continue; _frames[i] = state.GetFrames(RsiDirection.South); _frameDelays[i] = state.GetDelays(); @@ -111,8 +111,7 @@ protected override void FrameUpdate(FrameEventArgs args) for (var i = 0; i < _gasCount; i++) { var delays = _frameDelays[i]; - if (delays.Length == 0) - continue; + if (delays.Length == 0) continue; var frameCount = _frameCounter[i]; _timer[i] += args.DeltaSeconds; @@ -128,8 +127,7 @@ protected override void FrameUpdate(FrameEventArgs args) for (var i = 0; i < FireStates; i++) { var delays = _fireFrameDelays[i]; - if (delays.Length == 0) - continue; + if (delays.Length == 0) continue; var frameCount = _fireFrameCounter[i]; _fireTimer[i] += args.DeltaSeconds; @@ -163,10 +161,26 @@ protected override void Draw(in OverlayDrawArgs args) var mapUid = _mapManager.GetMapEntityId(args.MapId); if (_entManager.TryGetComponent(mapUid, out var atmos)) - DrawMapOverlay(drawHandle, args, mapUid, atmos); + { + var bottomLeft = args.WorldAABB.BottomLeft.Floored(); + var topRight = args.WorldAABB.TopRight.Ceiled(); - if (args.Space != OverlaySpace.WorldSpaceEntities) - return; + for (var x = bottomLeft.X; x <= topRight.X; x++) + { + for (var y = bottomLeft.Y; y <= topRight.Y; y++) + { + var tilePosition = new Vector2(x, y); + + for (var i = 0; i < atmos.OverlayData.Opacity.Length; i++) + { + var opacity = atmos.OverlayData.Opacity[i]; + + if (opacity > 0) + args.WorldHandle.DrawTexture(_frames[i][_frameCounter[i]], tilePosition, Color.White.WithAlpha(opacity)); + } + } + } + } // TODO: WorldBounds callback. _mapManager.FindGridsIntersecting(args.MapId, args.WorldAABB, ref gridState, @@ -251,41 +265,5 @@ protected override void Draw(in OverlayDrawArgs args) drawHandle.UseShader(null); drawHandle.SetTransform(Matrix3.Identity); } - - private void DrawMapOverlay( - DrawingHandleWorld handle, - OverlayDrawArgs args, - EntityUid map, - MapAtmosphereComponent atmos) - { - var mapGrid = _entManager.HasComponent(map); - - // map-grid atmospheres get drawn above grids - if (mapGrid && args.Space != OverlaySpace.WorldSpaceEntities) - return; - - // Normal map atmospheres get drawn below grids - if (!mapGrid && args.Space != OverlaySpace.WorldSpaceBelowWorld) - return; - - var bottomLeft = args.WorldAABB.BottomLeft.Floored(); - var topRight = args.WorldAABB.TopRight.Ceiled(); - - for (var x = bottomLeft.X; x <= topRight.X; x++) - { - for (var y = bottomLeft.Y; y <= topRight.Y; y++) - { - var tilePosition = new Vector2(x, y); - - for (var i = 0; i < atmos.OverlayData.Opacity.Length; i++) - { - var opacity = atmos.OverlayData.Opacity[i]; - - if (opacity > 0) - handle.DrawTexture(_frames[i][_frameCounter[i]], tilePosition, Color.White.WithAlpha(opacity)); - } - } - } - } } } diff --git a/Content.Client/Mapping/MappingSystem.cs b/Content.Client/Mapping/MappingSystem.cs index 8daf193dfeb..4456be36a65 100644 --- a/Content.Client/Mapping/MappingSystem.cs +++ b/Content.Client/Mapping/MappingSystem.cs @@ -83,7 +83,7 @@ private void OnFillActionSlot(FillActionSlotEvent ev) if (tileDef is not ContentTileDefinition contentTileDef) return; - var tileIcon = contentTileDef.MapAtmosphere + var tileIcon = contentTileDef.IsSpace ? _spaceIcon : new Texture(contentTileDef.Sprite!.Value); diff --git a/Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUi.cs b/Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUi.cs similarity index 92% rename from Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUi.cs rename to Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUi.cs index 0d8accb9f86..0b5fc7ad38c 100644 --- a/Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUi.cs +++ b/Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUi.cs @@ -1,11 +1,10 @@ using Robust.Client.GameObjects; using Robust.Client.UserInterface; -using Content.Client.Psionics.UI; using Content.Client.UserInterface.Fragments; using Content.Shared.CartridgeLoader.Cartridges; using Content.Shared.CartridgeLoader; -namespace Content.Client.Psionics.GlimmerMonitor; +namespace Content.Client.Nyanotrasen.CartridgeLoader.Cartridges; public sealed partial class GlimmerMonitorUi : UIFragment { diff --git a/Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUiFragment.xaml b/Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUiFragment.xaml similarity index 93% rename from Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUiFragment.xaml rename to Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUiFragment.xaml index 3044680e27b..119a1831e6e 100644 --- a/Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUiFragment.xaml +++ b/Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUiFragment.xaml @@ -1,4 +1,4 @@ - diff --git a/Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUiFragment.xaml.cs b/Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUiFragment.xaml.cs similarity index 96% rename from Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUiFragment.xaml.cs rename to Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUiFragment.xaml.cs index 58bbee38a2f..43d9202aa45 100644 --- a/Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUiFragment.xaml.cs +++ b/Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUiFragment.xaml.cs @@ -1,12 +1,12 @@ using System.Linq; using System.Numerics; -using Content.Client.Psionics.UI; +using Content.Client.Nyanotrasen.UserInterface; using Robust.Client.AutoGenerated; using Robust.Client.ResourceManagement; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; -namespace Content.Client.Psionics.GlimmerMonitor; +namespace Content.Client.Nyanotrasen.CartridgeLoader.Cartridges; [GenerateTypedNameReferences] public sealed partial class GlimmerMonitorUiFragment : BoxContainer diff --git a/Content.Client/Psionics/Telepathy/PsionicChatUpdateSystem.cs b/Content.Client/Nyanotrasen/Chat/PsionicChatUpdateSystem.cs similarity index 92% rename from Content.Client/Psionics/Telepathy/PsionicChatUpdateSystem.cs rename to Content.Client/Nyanotrasen/Chat/PsionicChatUpdateSystem.cs index 7bb88764a1f..84602052fe7 100644 --- a/Content.Client/Psionics/Telepathy/PsionicChatUpdateSystem.cs +++ b/Content.Client/Nyanotrasen/Chat/PsionicChatUpdateSystem.cs @@ -1,8 +1,8 @@ -using Content.Shared.Psionics.Abilities; +using Content.Shared.Abilities.Psionics; using Content.Client.Chat.Managers; using Robust.Client.Player; -namespace Content.Client.Psionics.Chat +namespace Content.Client.Nyanotrasen.Chat { public sealed class PsionicChatUpdateSystem : EntitySystem { diff --git a/Content.Client/Psionics/Glimmer/GlimmerReactiveVisuals.cs b/Content.Client/Nyanotrasen/Psionics/Glimmer/GlimmerReactiveVisuals.cs similarity index 100% rename from Content.Client/Psionics/Glimmer/GlimmerReactiveVisuals.cs rename to Content.Client/Nyanotrasen/Psionics/Glimmer/GlimmerReactiveVisuals.cs diff --git a/Content.Client/Psionics/UserInterface/AcceptPsionicsEUI.cs b/Content.Client/Nyanotrasen/Psionics/UI/AcceptPsionicsEUI.cs similarity index 100% rename from Content.Client/Psionics/UserInterface/AcceptPsionicsEUI.cs rename to Content.Client/Nyanotrasen/Psionics/UI/AcceptPsionicsEUI.cs diff --git a/Content.Client/Psionics/UserInterface/AcceptPsionicsWindow.cs b/Content.Client/Nyanotrasen/Psionics/UI/AcceptPsionicsWindow.cs similarity index 100% rename from Content.Client/Psionics/UserInterface/AcceptPsionicsWindow.cs rename to Content.Client/Nyanotrasen/Psionics/UI/AcceptPsionicsWindow.cs diff --git a/Content.Client/Psionics/UserInterface/GlimmerGraph.cs b/Content.Client/Nyanotrasen/UserInterface/GlimmerGraph.cs similarity index 97% rename from Content.Client/Psionics/UserInterface/GlimmerGraph.cs rename to Content.Client/Nyanotrasen/UserInterface/GlimmerGraph.cs index 111c810acb1..c4a9109dcd8 100644 --- a/Content.Client/Psionics/UserInterface/GlimmerGraph.cs +++ b/Content.Client/Nyanotrasen/UserInterface/GlimmerGraph.cs @@ -4,7 +4,7 @@ using Robust.Client.ResourceManagement; using Robust.Client.UserInterface; -namespace Content.Client.Psionics.UI; +namespace Content.Client.Nyanotrasen.UserInterface; public sealed class GlimmerGraph : Control { diff --git a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs index f0537079b97..ce5cf421aef 100644 --- a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs +++ b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs @@ -403,7 +403,7 @@ private void InputManagerOnFirstChanceOnKeyEvent(KeyEventArgs keyEvent, KeyEvent Mod1 = mods[0], Mod2 = mods[1], Mod3 = mods[2], - Priority = _currentlyRebinding.Binding?.Priority ?? 0, + Priority = 0, Type = bindType, CanFocus = key == Keyboard.Key.MouseLeft || key == Keyboard.Key.MouseRight diff --git a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs index 79c1909ebaf..ff4972d9d08 100644 --- a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs +++ b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs @@ -20,6 +20,7 @@ using Content.Shared.Examine; using Content.Shared.Input; using Content.Shared.Radio; +using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.Input; using Robust.Client.Player; @@ -36,7 +37,7 @@ using Robust.Shared.Replays; using Robust.Shared.Timing; using Robust.Shared.Utility; -using Content.Client.Psionics.Chat; +using Content.Client.Nyanotrasen.Chat; //Nyano - Summary: chat namespace. namespace Content.Client.UserInterface.Systems.Chat; @@ -60,7 +61,7 @@ public sealed class ChatUIController : UIController [UISystemDependency] private readonly GhostSystem? _ghost = default; [UISystemDependency] private readonly TypingIndicatorSystem? _typingIndicator = default; [UISystemDependency] private readonly ChatSystem? _chatSys = default; - [UISystemDependency] private readonly PsionicChatUpdateSystem? _psionic = default!; //EE - Summary: makes the psionic chat available. + [UISystemDependency] private readonly PsionicChatUpdateSystem? _psionic = default!; //Nyano - Summary: makes the psionic chat available. [ValidatePrototypeId] private const string ChatNamePalette = "ChatNames"; @@ -81,7 +82,7 @@ public sealed class ChatUIController : UIController {SharedChatSystem.AdminPrefix, ChatSelectChannel.Admin}, {SharedChatSystem.RadioCommonPrefix, ChatSelectChannel.Radio}, {SharedChatSystem.DeadPrefix, ChatSelectChannel.Dead}, - {SharedChatSystem.TelepathicPrefix, ChatSelectChannel.Telepathic} //EE - Summary: adds the telepathic prefix =. + {SharedChatSystem.TelepathicPrefix, ChatSelectChannel.Telepathic} //Nyano - Summary: adds the telepathic prefix =. }; public static readonly Dictionary ChannelPrefixes = new() @@ -95,7 +96,7 @@ public sealed class ChatUIController : UIController {ChatSelectChannel.Admin, SharedChatSystem.AdminPrefix}, {ChatSelectChannel.Radio, SharedChatSystem.RadioCommonPrefix}, {ChatSelectChannel.Dead, SharedChatSystem.DeadPrefix}, - {ChatSelectChannel.Telepathic, SharedChatSystem.TelepathicPrefix } //EE - Summary: associates telepathic with =. + {ChatSelectChannel.Telepathic, SharedChatSystem.TelepathicPrefix } //Nyano - Summary: associates telepathic with =. }; /// diff --git a/Content.IntegrationTests/Tests/Body/LungTest.cs b/Content.IntegrationTests/Tests/Body/LungTest.cs index f2e19849b00..d0325480acd 100644 --- a/Content.IntegrationTests/Tests/Body/LungTest.cs +++ b/Content.IntegrationTests/Tests/Body/LungTest.cs @@ -128,7 +128,7 @@ await server.WaitAssertion(() => metaSys.Update(1.0f); metaSys.Update(1.0f); respSys.Update(2.0f); - Assert.That(GetMapMoles(), Is.EqualTo(startingMoles).Within(0.0002)); + Assert.That(GetMapMoles(), Is.EqualTo(startingMoles).Within(0.0001)); }); } diff --git a/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs b/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs index 88448e7b800..84e1afaf45c 100644 --- a/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs +++ b/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs @@ -1006,10 +1006,15 @@ protected async Task AddAtmosphere(EntityUid? uid = null) await Server.WaitPost(() => { var atmosSystem = SEntMan.System(); + var atmos = SEntMan.EnsureComponent(target); var moles = new float[Atmospherics.AdjustedNumberOfGases]; moles[(int) Gas.Oxygen] = 21.824779f; moles[(int) Gas.Nitrogen] = 82.10312f; - atmosSystem.SetMapAtmosphere(target, false, new GasMixture(moles, Atmospherics.T20C)); + atmosSystem.SetMapAtmosphere(target, false, new GasMixture(2500) + { + Temperature = 293.15f, + Moles = moles, + }, atmos); }); } diff --git a/Content.Server/Abilities/Mime/MimePowersSystem.cs b/Content.Server/Abilities/Mime/MimePowersSystem.cs index b3bd3392434..c1d2643d6fa 100644 --- a/Content.Server/Abilities/Mime/MimePowersSystem.cs +++ b/Content.Server/Abilities/Mime/MimePowersSystem.cs @@ -10,7 +10,7 @@ using Robust.Shared.Containers; using Robust.Shared.Map; using Robust.Shared.Timing; -using Content.Shared.Psionics.Abilities; +using Content.Shared.Abilities.Psionics; //Nyano - Summary: Makes Mime psionic. using Content.Shared.Speech.Muting; namespace Content.Server.Abilities.Mime diff --git a/Content.Server/Administration/Managers/AdminManager.Metrics.cs b/Content.Server/Administration/Managers/AdminManager.Metrics.cs deleted file mode 100644 index 2fea931f1b9..00000000000 --- a/Content.Server/Administration/Managers/AdminManager.Metrics.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System.Diagnostics.Metrics; -using System.Runtime.InteropServices; -using Content.Server.Afk; -using Robust.Server.DataMetrics; - -namespace Content.Server.Administration.Managers; - -// Handles metrics reporting for active admin count and such. - -public sealed partial class AdminManager -{ - private Dictionary? _adminOnlineCounts; - - private const int SentinelRankId = -1; - - [Dependency] private readonly IMetricsManager _metrics = default!; - [Dependency] private readonly IAfkManager _afkManager = default!; - [Dependency] private readonly IMeterFactory _meterFactory = default!; - - private void InitializeMetrics() - { - _metrics.UpdateMetrics += MetricsOnUpdateMetrics; - - var meter = _meterFactory.Create("SS14.AdminManager"); - - meter.CreateObservableGauge( - "admins_online_count", - MeasureAdminCount, - null, - "The count of online admins"); - } - - private void MetricsOnUpdateMetrics() - { - _sawmill.Verbose("Updating metrics"); - - var dict = new Dictionary(); - - foreach (var (session, reg) in _admins) - { - var rankId = reg.RankId ?? SentinelRankId; - - ref var counts = ref CollectionsMarshal.GetValueRefOrAddDefault(dict, rankId, out _); - - if (reg.Data.Active) - { - if (_afkManager.IsAfk(session)) - counts.afk += 1; - else - counts.active += 1; - } - else - { - counts.deadminned += 1; - } - } - - // Neither prometheus-net nor dotnet-counters seem to handle stuff well if we STOP returning measurements. - // i.e. if the last admin with a rank disconnects. - // So if we have EVER reported a rank, always keep reporting it. - if (_adminOnlineCounts != null) - { - foreach (var rank in _adminOnlineCounts.Keys) - { - CollectionsMarshal.GetValueRefOrAddDefault(dict, rank, out _); - } - } - - // Make sure "no rank" is always available. Avoid "no data". - CollectionsMarshal.GetValueRefOrAddDefault(dict, SentinelRankId, out _); - - _adminOnlineCounts = dict; - } - - private IEnumerable> MeasureAdminCount() - { - if (_adminOnlineCounts == null) - yield break; - - foreach (var (rank, (active, afk, deadminned)) in _adminOnlineCounts) - { - yield return new Measurement( - active, - new KeyValuePair("state", "active"), - new KeyValuePair("rank", rank == SentinelRankId ? "none" : rank.ToString())); - - yield return new Measurement( - afk, - new KeyValuePair("state", "afk"), - new KeyValuePair("rank", rank == SentinelRankId ? "none" : rank.ToString())); - - yield return new Measurement( - deadminned, - new KeyValuePair("state", "deadminned"), - new KeyValuePair("rank", rank == SentinelRankId ? "none" : rank.ToString())); - } - } -} diff --git a/Content.Server/Administration/Managers/AdminManager.cs b/Content.Server/Administration/Managers/AdminManager.cs index b1cca46e63f..4eaa08fe9dd 100644 --- a/Content.Server/Administration/Managers/AdminManager.cs +++ b/Content.Server/Administration/Managers/AdminManager.cs @@ -23,7 +23,7 @@ namespace Content.Server.Administration.Managers { - public sealed partial class AdminManager : IAdminManager, IPostInjectInit, IConGroupControllerImplementation + public sealed class AdminManager : IAdminManager, IPostInjectInit, IConGroupControllerImplementation { [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IServerDbManager _dbManager = default!; @@ -34,7 +34,6 @@ public sealed partial class AdminManager : IAdminManager, IPostInjectInit, IConG [Dependency] private readonly IServerConsoleHost _consoleHost = default!; [Dependency] private readonly IChatManager _chat = default!; [Dependency] private readonly ToolshedManager _toolshed = default!; - [Dependency] private readonly ILogManager _logManager = default!; private readonly Dictionary _admins = new(); private readonly HashSet _promotedPlayers = new(); @@ -50,8 +49,6 @@ public sealed partial class AdminManager : IAdminManager, IPostInjectInit, IConG private readonly AdminCommandPermissions _commandPermissions = new(); private readonly AdminCommandPermissions _toolshedCommandPermissions = new(); - private ISawmill _sawmill = default!; - public bool IsAdmin(ICommonSession session, bool includeDeAdmin = false) { return GetAdminData(session, includeDeAdmin) != null; @@ -184,8 +181,6 @@ public void ReloadAdminsWithRank(int rankId) public void Initialize() { - _sawmill = _logManager.GetSawmill("admin"); - _netMgr.RegisterNetMessage(); // Cache permissions for loaded console commands with the requisite attributes. @@ -239,8 +234,6 @@ public void Initialize() } _toolshed.ActivePermissionController = this; - - InitializeMetrics(); } public void PromoteHost(ICommonSession player) diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs b/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs index 8ee52ad03e7..8a819f59420 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs @@ -409,7 +409,7 @@ private void AddSmiteVerbs(GetVerbsEvent args) var fixtures = Comp(args.Target); xform.Anchored = false; // Just in case. _physics.SetBodyType(args.Target, BodyType.Dynamic, manager: fixtures, body: physics); - _physics.SetBodyStatus(args.Target, physics, BodyStatus.InAir); + _physics.SetBodyStatus(physics, BodyStatus.InAir); _physics.WakeBody(args.Target, manager: fixtures, body: physics); foreach (var fixture in fixtures.Fixtures.Values) @@ -424,8 +424,8 @@ private void AddSmiteVerbs(GetVerbsEvent args) _physics.SetLinearVelocity(args.Target, _random.NextVector2(1.5f, 1.5f), manager: fixtures, body: physics); _physics.SetAngularVelocity(args.Target, MathF.PI * 12, manager: fixtures, body: physics); - _physics.SetLinearDamping(args.Target, physics, 0f); - _physics.SetAngularDamping(args.Target, physics, 0f); + _physics.SetLinearDamping(physics, 0f); + _physics.SetAngularDamping(physics, 0f); }, Impact = LogImpact.Extreme, Message = Loc.GetString("admin-smite-pinball-description") @@ -444,7 +444,7 @@ private void AddSmiteVerbs(GetVerbsEvent args) xform.Anchored = false; // Just in case. _physics.SetBodyType(args.Target, BodyType.Dynamic, body: physics); - _physics.SetBodyStatus(args.Target, physics, BodyStatus.InAir); + _physics.SetBodyStatus(physics, BodyStatus.InAir); _physics.WakeBody(args.Target, manager: fixtures, body: physics); foreach (var fixture in fixtures.Fixtures.Values) @@ -454,8 +454,8 @@ private void AddSmiteVerbs(GetVerbsEvent args) _physics.SetLinearVelocity(args.Target, _random.NextVector2(8.0f, 8.0f), manager: fixtures, body: physics); _physics.SetAngularVelocity(args.Target, MathF.PI * 12, manager: fixtures, body: physics); - _physics.SetLinearDamping(args.Target, physics, 0f); - _physics.SetAngularDamping(args.Target, physics, 0f); + _physics.SetLinearDamping(physics, 0f); + _physics.SetAngularDamping(physics, 0f); }, Impact = LogImpact.Extreme, Message = Loc.GetString("admin-smite-yeet-description") diff --git a/Content.Server/Anomaly/AnomalySystem.Psionics.cs b/Content.Server/Anomaly/AnomalySystem.Psionics.cs index 84f200f47ba..95fda1d5035 100644 --- a/Content.Server/Anomaly/AnomalySystem.Psionics.cs +++ b/Content.Server/Anomaly/AnomalySystem.Psionics.cs @@ -1,4 +1,4 @@ -using Content.Server.Psionics.Abilities; +using Content.Server.Abilities.Psionics; //Nyano - Summary: the psniocs bin where dispel is located. using Content.Shared.Anomaly; using Content.Shared.Anomaly.Components; using Robust.Shared.Random; @@ -14,6 +14,8 @@ private void InitializePsionics() { SubscribeLocalEvent(OnDispelled); } + + //Nyano - Summary: gives dispellable behavior to Anomalies. private void OnDispelled(EntityUid uid, AnomalyComponent component, DispelledEvent args) { _dispel.DealDispelDamage(uid); diff --git a/Content.Server/Atmos/Commands/SetMapAtmosCommand.cs b/Content.Server/Atmos/Commands/SetMapAtmosCommand.cs deleted file mode 100644 index 6f04cfb2da6..00000000000 --- a/Content.Server/Atmos/Commands/SetMapAtmosCommand.cs +++ /dev/null @@ -1,94 +0,0 @@ -using Content.Server.Administration; -using Content.Server.Atmos.Components; -using Content.Server.Atmos.EntitySystems; -using Content.Shared.Administration; -using Content.Shared.Atmos; -using Robust.Shared.Console; -using Robust.Shared.Map; - -namespace Content.Server.Atmos.Commands; - -[AdminCommand(AdminFlags.Admin)] -public sealed class AddMapAtmosCommand : LocalizedCommands -{ - [Dependency] private readonly IEntityManager _entities = default!; - [Dependency] private readonly IMapManager _map = default!; - - private const string _cmd = "cmd-set-map-atmos"; - public override string Command => "setmapatmos"; - public override string Description => Loc.GetString($"{_cmd}-desc"); - public override string Help => Loc.GetString($"{_cmd}-help"); - - public override void Execute(IConsoleShell shell, string argStr, string[] args) - { - if (args.Length < 2) - { - shell.WriteLine(Help); - return; - } - - int.TryParse(args[0], out var id); - var map = _map.GetMapEntityId(new MapId(id)); - if (!map.IsValid()) - { - shell.WriteError(Loc.GetString("cmd-parse-failure-mapid", ("arg", args[0]))); - return; - } - - if (!bool.TryParse(args[1], out var space)) - { - shell.WriteError(Loc.GetString("cmd-parse-failure-bool", ("arg", args[1]))); - return; - } - - if (space || args.Length < 4) - { - _entities.RemoveComponent(map); - shell.WriteLine(Loc.GetString($"{_cmd}-removed", ("map", id))); - return; - } - - if (!float.TryParse(args[2], out var temp)) - { - shell.WriteError(Loc.GetString("cmd-parse-failure-float", ("arg", args[2]))); - return; - } - - var mix = new GasMixture(Atmospherics.CellVolume) {Temperature = Math.Min(temp, Atmospherics.TCMB)}; - for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++) - { - if (args.Length == 3 + i) - break; - - if (!float.TryParse(args[3+i], out var moles)) - { - shell.WriteError(Loc.GetString("cmd-parse-failure-float", ("arg", args[3+i]))); - return; - } - - mix.AdjustMoles(i, moles); - } - - var atmos = _entities.EntitySysManager.GetEntitySystem(); - atmos.SetMapAtmosphere(map, space, mix); - shell.WriteLine(Loc.GetString($"{_cmd}-updated", ("map", id))); - } - - public override CompletionResult GetCompletion(IConsoleShell shell, string[] args) - { - if (args.Length == 1) - return CompletionResult.FromHintOptions(CompletionHelper.MapIds(_entities), Loc.GetString($"{_cmd}-hint-map")); - - if (args.Length == 2) - return CompletionResult.FromHintOptions(new[]{ "false", "true"}, Loc.GetString($"{_cmd}-hint-space")); - - if (!bool.TryParse(args[1], out var space) || space) - return CompletionResult.Empty; - - if (args.Length == 3) - return CompletionResult.FromHint(Loc.GetString($"{_cmd}-hint-temp")); - - var gas = (Gas) args.Length - 4; - return CompletionResult.FromHint(Loc.GetString($"{_cmd}-hint-gas" , ("gas", gas.ToString()))); - } -} diff --git a/Content.Server/Atmos/Components/AirtightComponent.cs b/Content.Server/Atmos/Components/AirtightComponent.cs index ca107eafbe8..897981724c9 100644 --- a/Content.Server/Atmos/Components/AirtightComponent.cs +++ b/Content.Server/Atmos/Components/AirtightComponent.cs @@ -1,10 +1,9 @@ -using Content.Server.Atmos.EntitySystems; using Content.Shared.Atmos; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Server.Atmos.Components { - [RegisterComponent, Access(typeof(AirtightSystem))] + [RegisterComponent] public sealed partial class AirtightComponent : Component { public (EntityUid Grid, Vector2i Tile) LastPosition { get; set; } @@ -30,7 +29,6 @@ public sealed partial class AirtightComponent : Component [DataField("noAirWhenFullyAirBlocked")] public bool NoAirWhenFullyAirBlocked { get; set; } = true; - [Access(Other = AccessPermissions.ReadWriteExecute)] public AtmosDirection AirBlockedDirection => (AtmosDirection)CurrentAirBlockedDirection; } } diff --git a/Content.Server/Atmos/Components/GridAtmosphereComponent.cs b/Content.Server/Atmos/Components/GridAtmosphereComponent.cs index e682fd09644..7fcd63bc5d8 100644 --- a/Content.Server/Atmos/Components/GridAtmosphereComponent.cs +++ b/Content.Server/Atmos/Components/GridAtmosphereComponent.cs @@ -28,9 +28,6 @@ public sealed partial class GridAtmosphereComponent : Component [IncludeDataField(customTypeSerializer:typeof(TileAtmosCollectionSerializer))] public Dictionary Tiles = new(1000); - [ViewVariables] - public HashSet MapTiles = new(1000); - [ViewVariables] public readonly HashSet ActiveTiles = new(1000); @@ -83,10 +80,7 @@ public sealed partial class GridAtmosphereComponent : Component public readonly HashSet InvalidatedCoords = new(1000); [ViewVariables] - public readonly Queue CurrentRunInvalidatedTiles = new(); - - [ViewVariables] - public readonly List PossiblyDisconnectedTiles = new(100); + public readonly Queue CurrentRunInvalidatedCoordinates = new(); [ViewVariables] public int InvalidatedCoordsCount => InvalidatedCoords.Count; diff --git a/Content.Server/Atmos/Components/IgniteOnCollideComponent.cs b/Content.Server/Atmos/Components/IgniteOnCollideComponent.cs index 710c37b62fe..a58d3a3c122 100644 --- a/Content.Server/Atmos/Components/IgniteOnCollideComponent.cs +++ b/Content.Server/Atmos/Components/IgniteOnCollideComponent.cs @@ -1,6 +1,8 @@ +using Content.Server.Atmos.EntitySystems; + namespace Content.Server.Atmos.Components; -[RegisterComponent] +[RegisterComponent, Access(typeof(FlammableSystem))] public sealed partial class IgniteOnCollideComponent : Component { /// diff --git a/Content.Server/Atmos/Components/MapAtmosphereComponent.cs b/Content.Server/Atmos/Components/MapAtmosphereComponent.cs index 6bdef901d44..bbf5ea6403e 100644 --- a/Content.Server/Atmos/Components/MapAtmosphereComponent.cs +++ b/Content.Server/Atmos/Components/MapAtmosphereComponent.cs @@ -12,14 +12,12 @@ public sealed partial class MapAtmosphereComponent : SharedMapAtmosphereComponen /// /// The default GasMixture a map will have. Space mixture by default. /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - public GasMixture Mixture = GasMixture.SpaceGas; + [DataField("mixture"), ViewVariables(VVAccess.ReadWrite)] + public GasMixture? Mixture = GasMixture.SpaceGas; /// /// Whether empty tiles will be considered space or not. /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField("space"), ViewVariables(VVAccess.ReadWrite)] public bool Space = true; - - public SharedGasTileOverlaySystem.GasOverlayData Overlay; } diff --git a/Content.Server/Atmos/EntitySystems/AirtightSystem.cs b/Content.Server/Atmos/EntitySystems/AirtightSystem.cs index 548d6a36926..97dccbaabb7 100644 --- a/Content.Server/Atmos/EntitySystems/AirtightSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AirtightSystem.cs @@ -2,6 +2,7 @@ using Content.Server.Explosion.EntitySystems; using Content.Shared.Atmos; using JetBrains.Annotations; +using Robust.Shared.Map; using Robust.Shared.Map.Components; namespace Content.Server.Atmos.EntitySystems @@ -9,7 +10,7 @@ namespace Content.Server.Atmos.EntitySystems [UsedImplicitly] public sealed class AirtightSystem : EntitySystem { - [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Dependency] private readonly ExplosionSystem _explosionSystem = default!; @@ -120,16 +121,19 @@ public void UpdatePosition(Entity ent, TransformComponent? xf if (!xform.Anchored || !TryComp(xform.GridUid, out MapGridComponent? grid)) return; - var indices = _transform.GetGridTilePositionOrDefault((ent, xform), grid); - airtight.LastPosition = (xform.GridUid.Value, indices); - InvalidatePosition((xform.GridUid.Value, grid), indices); + airtight.LastPosition = (xform.GridUid.Value, grid.TileIndicesFor(xform.Coordinates)); + InvalidatePosition(airtight.LastPosition.Item1, airtight.LastPosition.Item2, airtight.FixVacuum && !airtight.AirBlocked); } - public void InvalidatePosition(Entity grid, Vector2i pos) + public void InvalidatePosition(EntityUid gridId, Vector2i pos, bool fixVacuum = false) { + if (!TryComp(gridId, out MapGridComponent? grid)) + return; + var query = EntityManager.GetEntityQuery(); - _explosionSystem.UpdateAirtightMap(grid, pos, grid, query); - _atmosphereSystem.InvalidateTile(grid.Owner, pos); + _explosionSystem.UpdateAirtightMap(gridId, pos, grid, query); + // TODO make atmos system use query + _atmosphereSystem.InvalidateTile(gridId, pos); } private AtmosDirection Rotate(AtmosDirection myDirection, Angle myAngle) diff --git a/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs b/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs index c0284f26c90..4af32fce58f 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs @@ -97,19 +97,22 @@ private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e) } } - private AtmosDebugOverlayData? ConvertTileToData(TileAtmosphere tile) + private AtmosDebugOverlayData ConvertTileToData(TileAtmosphere? tile) { + if (tile == null) + return default; + return new AtmosDebugOverlayData( tile.GridIndices, tile.Air?.Temperature ?? default, tile.Air?.Moles, tile.PressureDirection, tile.LastPressureDirection, - tile.AirtightData.BlockedDirections, + tile.BlockedAirflow, tile.ExcitedGroup?.GetHashCode(), tile.Space, - tile.MapAtmosphere, - tile.NoGridTile); + false, + false); } public override void Update(float frameTime) diff --git a/Content.Server/Atmos/EntitySystems/AtmosObstructionEnumerator.cs b/Content.Server/Atmos/EntitySystems/AtmosObstructionEnumerator.cs new file mode 100644 index 00000000000..aed009e9a12 --- /dev/null +++ b/Content.Server/Atmos/EntitySystems/AtmosObstructionEnumerator.cs @@ -0,0 +1,37 @@ +using System.Diagnostics.CodeAnalysis; +using Content.Server.Atmos.Components; +using Robust.Shared.Map; +using Robust.Shared.Map.Enumerators; + +namespace Content.Server.Atmos.EntitySystems; + +public struct AtmosObstructionEnumerator +{ + private AnchoredEntitiesEnumerator _enumerator; + private EntityQuery _query; + + public AtmosObstructionEnumerator(AnchoredEntitiesEnumerator enumerator, EntityQuery query) + { + _enumerator = enumerator; + _query = query; + } + + public bool MoveNext([NotNullWhen(true)] out AirtightComponent? airtight) + { + if (!_enumerator.MoveNext(out var uid)) + { + airtight = null; + return false; + } + + // No rider, it makes it uglier. + // ReSharper disable once ConvertIfStatementToReturnStatement + if (!_query.TryGetComponent(uid.Value, out airtight)) + { + // ReSharper disable once TailRecursiveCall + return MoveNext(out airtight); + } + + return true; + } +} diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs index cece99cacf6..310e602336a 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs @@ -85,10 +85,10 @@ public IEnumerable GetAllMixtures(EntityUid gridUid, bool excite = f return ev.Mixtures!; } - public void InvalidateTile(Entity entity, Vector2i tile) + public void InvalidateTile(EntityUid gridUid, Vector2i tile) { - if (_atmosQuery.Resolve(entity.Owner, ref entity.Comp, false)) - entity.Comp.InvalidatedCoords.Add(tile); + var ev = new InvalidateTileMethodEvent(gridUid, tile); + RaiseLocalEvent(gridUid, ref ev); } public GasMixture?[]? GetTileMixtures(EntityUid? gridUid, EntityUid? mapUid, List tiles, bool excite = false) @@ -176,11 +176,11 @@ public ReactionResult ReactTile(EntityUid gridId, Vector2i tile) public bool IsTileAirBlocked(EntityUid gridUid, Vector2i tile, AtmosDirection directions = AtmosDirection.All, MapGridComponent? mapGridComp = null) { - if (!Resolve(gridUid, ref mapGridComp)) - return false; + var ev = new IsTileAirBlockedMethodEvent(gridUid, tile, directions, mapGridComp); + RaiseLocalEvent(gridUid, ref ev); - var data = GetAirtightData(gridUid, mapGridComp, tile); - return data.BlockedDirections.IsFlagSet(directions); + // If nothing handled the event, it'll default to true. + return ev.Result; } public bool IsTileSpace(EntityUid? gridUid, EntityUid? mapUid, Vector2i tile, MapGridComponent? mapGridComp = null) @@ -231,6 +231,12 @@ public IEnumerable GetAdjacentTileMixtures(EntityUid gridUid, Vector return ev.Result ?? Enumerable.Empty(); } + public void UpdateAdjacent(EntityUid gridUid, Vector2i tile, MapGridComponent? mapGridComp = null) + { + var ev = new UpdateAdjacentMethodEvent(gridUid, tile, mapGridComp); + RaiseLocalEvent(gridUid, ref ev); + } + public void HotspotExpose(EntityUid gridUid, Vector2i tile, float exposedTemperature, float exposedVolume, EntityUid? sparkSourceUid = null, bool soh = false) { @@ -253,6 +259,12 @@ public bool IsHotspotActive(EntityUid gridUid, Vector2i tile) return ev.Result; } + public void FixTileVacuum(EntityUid gridUid, Vector2i tile) + { + var ev = new FixTileVacuumMethodEvent(gridUid, tile); + RaiseLocalEvent(gridUid, ref ev); + } + public void AddPipeNet(EntityUid gridUid, PipeNet pipeNet) { var ev = new AddPipeNetMethodEvent(gridUid, pipeNet); @@ -295,6 +307,9 @@ [ByRefEvent] private record struct IsSimulatedGridMethodEvent [ByRefEvent] private record struct GetAllMixturesMethodEvent (EntityUid Grid, bool Excite = false, IEnumerable? Mixtures = null, bool Handled = false); + [ByRefEvent] private record struct InvalidateTileMethodEvent + (EntityUid Grid, Vector2i Tile, bool Handled = false); + [ByRefEvent] private record struct GetTileMixturesMethodEvent (EntityUid? GridUid, EntityUid? MapUid, List Tiles, bool Excite = false, GasMixture?[]? Mixtures = null, bool Handled = false); @@ -304,6 +319,16 @@ [ByRefEvent] private record struct GetTileMixtureMethodEvent [ByRefEvent] private record struct ReactTileMethodEvent (EntityUid GridId, Vector2i Tile, ReactionResult Result = default, bool Handled = false); + [ByRefEvent] private record struct IsTileAirBlockedMethodEvent + (EntityUid Grid, Vector2i Tile, AtmosDirection Direction = AtmosDirection.All, MapGridComponent? MapGridComponent = null, bool Result = false, bool Handled = false) + { + /// + /// True if one of the enabled blockers has . Note + /// that this does not actually check if all directions are blocked. + /// + public bool NoAir = false; + } + [ByRefEvent] private record struct IsTileSpaceMethodEvent (EntityUid? Grid, EntityUid? Map, Vector2i Tile, MapGridComponent? MapGridComponent = null, bool Result = true, bool Handled = false); @@ -314,6 +339,9 @@ [ByRefEvent] private record struct GetAdjacentTileMixturesMethodEvent (EntityUid Grid, Vector2i Tile, bool IncludeBlocked, bool Excite, IEnumerable? Result = null, bool Handled = false); + [ByRefEvent] private record struct UpdateAdjacentMethodEvent + (EntityUid Grid, Vector2i Tile, MapGridComponent? MapGridComponent = null, bool Handled = false); + [ByRefEvent] private record struct HotspotExposeMethodEvent (EntityUid Grid, EntityUid? SparkSourceUid, Vector2i Tile, float ExposedTemperature, float ExposedVolume, bool soh, bool Handled = false); @@ -323,6 +351,9 @@ [ByRefEvent] private record struct HotspotExtinguishMethodEvent [ByRefEvent] private record struct IsHotspotActiveMethodEvent (EntityUid Grid, Vector2i Tile, bool Result = false, bool Handled = false); + [ByRefEvent] private record struct FixTileVacuumMethodEvent + (EntityUid Grid, Vector2i Tile, bool Handled = false); + [ByRefEvent] private record struct AddPipeNetMethodEvent (EntityUid Grid, PipeNet PipeNet, bool Handled = false); diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.ExcitedGroup.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.ExcitedGroup.cs index de4c9199cf7..1d809dcd032 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.ExcitedGroup.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.ExcitedGroup.cs @@ -72,8 +72,7 @@ private void ExcitedGroupSelfBreakdown(GridAtmosphereComponent gridAtmosphere, E var tileSize = excitedGroup.Tiles.Count; - if (excitedGroup.Disposed) - return; + if (excitedGroup.Disposed) return; if (tileSize == 0) { @@ -99,9 +98,7 @@ private void ExcitedGroupSelfBreakdown(GridAtmosphereComponent gridAtmosphere, E foreach (var tile in excitedGroup.Tiles) { - if (tile?.Air == null) - continue; - + if (tile?.Air == null) continue; tile.Air.CopyFromMutable(combined); InvalidateVisuals(tile.GridIndex, tile.GridIndices); } @@ -109,23 +106,21 @@ private void ExcitedGroupSelfBreakdown(GridAtmosphereComponent gridAtmosphere, E excitedGroup.BreakdownCooldown = 0; } - /// - /// This de-activates and removes all tiles in an excited group. - /// - private void DeactivateGroupTiles(GridAtmosphereComponent gridAtmosphere, ExcitedGroup excitedGroup) + private void ExcitedGroupDismantle(GridAtmosphereComponent gridAtmosphere, ExcitedGroup excitedGroup, bool unexcite = true) { foreach (var tile in excitedGroup.Tiles) { tile.ExcitedGroup = null; + + if (!unexcite) + continue; + RemoveActiveTile(gridAtmosphere, tile); } excitedGroup.Tiles.Clear(); } - /// - /// This removes an excited group without de-activating its tiles. - /// private void ExcitedGroupDispose(GridAtmosphereComponent gridAtmosphere, ExcitedGroup excitedGroup) { if (excitedGroup.Disposed) @@ -134,14 +129,9 @@ private void ExcitedGroupDispose(GridAtmosphereComponent gridAtmosphere, Excited DebugTools.Assert(gridAtmosphere.ExcitedGroups.Contains(excitedGroup), "Grid Atmosphere does not contain Excited Group!"); excitedGroup.Disposed = true; - gridAtmosphere.ExcitedGroups.Remove(excitedGroup); - - foreach (var tile in excitedGroup.Tiles) - { - tile.ExcitedGroup = null; - } - excitedGroup.Tiles.Clear(); + gridAtmosphere.ExcitedGroups.Remove(excitedGroup); + ExcitedGroupDismantle(gridAtmosphere, excitedGroup, false); } } } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs index d43cc81b0f8..1f1a208b24b 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs @@ -14,7 +14,6 @@ public sealed partial class AtmosphereSystem private void InitializeGridAtmosphere() { SubscribeLocalEvent(OnGridAtmosphereInit); - SubscribeLocalEvent(OnGridAtmosphereStartup); SubscribeLocalEvent(OnAtmosphereRemove); SubscribeLocalEvent(OnGridSplit); @@ -23,15 +22,19 @@ private void InitializeGridAtmosphere() SubscribeLocalEvent(GridHasAtmosphere); SubscribeLocalEvent(GridIsSimulated); SubscribeLocalEvent(GridGetAllMixtures); + SubscribeLocalEvent(GridInvalidateTile); SubscribeLocalEvent(GridGetTileMixture); SubscribeLocalEvent(GridGetTileMixtures); SubscribeLocalEvent(GridReactTile); + SubscribeLocalEvent(GridIsTileAirBlocked); SubscribeLocalEvent(GridIsTileSpace); SubscribeLocalEvent(GridGetAdjacentTiles); SubscribeLocalEvent(GridGetAdjacentTileMixtures); + SubscribeLocalEvent(GridUpdateAdjacent); SubscribeLocalEvent(GridHotspotExpose); SubscribeLocalEvent(GridHotspotExtinguish); SubscribeLocalEvent(GridIsHotspotActive); + SubscribeLocalEvent(GridFixTileVacuum); SubscribeLocalEvent(GridAddPipeNet); SubscribeLocalEvent(GridRemovePipeNet); SubscribeLocalEvent(GridAddAtmosDevice); @@ -53,23 +56,22 @@ private void OnAtmosphereRemove(EntityUid uid, GridAtmosphereComponent component } } - private void OnGridAtmosphereInit(EntityUid uid, GridAtmosphereComponent component, ComponentInit args) + private void OnGridAtmosphereInit(EntityUid uid, GridAtmosphereComponent gridAtmosphere, ComponentInit args) { base.Initialize(); + if (!TryComp(uid, out MapGridComponent? mapGrid)) + return; + EnsureComp(uid); - foreach (var tile in component.Tiles.Values) + + foreach (var (indices, tile) in gridAtmosphere.Tiles) { + gridAtmosphere.InvalidatedCoords.Add(indices); tile.GridIndex = uid; } - } - - private void OnGridAtmosphereStartup(EntityUid uid, GridAtmosphereComponent component, ComponentStartup args) - { - if (!TryComp(uid, out MapGridComponent? mapGrid)) - return; - InvalidateAllTiles((uid, mapGrid, component)); + GridRepopulateTiles((uid, mapGrid, gridAtmosphere)); } private void OnGridSplit(EntityUid uid, GridAtmosphereComponent originalGridAtmos, ref GridSplitEvent args) @@ -102,7 +104,8 @@ private void OnGridSplit(EntityUid uid, GridAtmosphereComponent originalGridAtmo continue; // Copy a bunch of data over... Not great, maybe put this in TileAtmosphere? - newTileAtmosphere.Air = tileAtmosphere.Air?.Clone(); + newTileAtmosphere.Air = tileAtmosphere.Air?.Clone() ?? null; + newTileAtmosphere.MolesArchived = newTileAtmosphere.Air == null ? null : new float[Atmospherics.AdjustedNumberOfGases]; newTileAtmosphere.Hotspot = tileAtmosphere.Hotspot; newTileAtmosphere.HeatCapacity = tileAtmosphere.HeatCapacity; newTileAtmosphere.Temperature = tileAtmosphere.Temperature; @@ -167,6 +170,15 @@ IEnumerable EnumerateMixtures(EntityUid gridUid, GridAtmosphereCompo args.Handled = true; } + private void GridInvalidateTile(EntityUid uid, GridAtmosphereComponent component, ref InvalidateTileMethodEvent args) + { + if (args.Handled) + return; + + component.InvalidatedCoords.Add(args.Tile); + args.Handled = true; + } + private void GridGetTileMixture(EntityUid uid, GridAtmosphereComponent component, ref GetTileMixtureMethodEvent args) { @@ -221,6 +233,43 @@ private void GridReactTile(EntityUid uid, GridAtmosphereComponent component, ref args.Handled = true; } + private void GridIsTileAirBlocked(EntityUid uid, GridAtmosphereComponent component, + ref IsTileAirBlockedMethodEvent args) + { + if (args.Handled) + return; + + var mapGridComp = args.MapGridComponent; + + if (!Resolve(uid, ref mapGridComp)) + return; + + var directions = AtmosDirection.Invalid; + + var enumerator = GetObstructingComponentsEnumerator(mapGridComp, args.Tile); + + while (enumerator.MoveNext(out var obstructingComponent)) + { + if (!obstructingComponent.AirBlocked) + continue; + + // We set the directions that are air-blocked so far, + // as you could have a full obstruction with only 4 directional air blockers. + directions |= obstructingComponent.AirBlockedDirection; + args.NoAir |= obstructingComponent.NoAirWhenFullyAirBlocked; + + if (directions.IsFlagSet(args.Direction)) + { + args.Result = true; + args.Handled = true; + return; + } + } + + args.Result = false; + args.Handled = true; + } + private void GridIsTileSpace(EntityUid uid, GridAtmosphereComponent component, ref IsTileSpaceMethodEvent args) { if (args.Handled) @@ -282,58 +331,71 @@ IEnumerable EnumerateAdjacent(GridAtmosphereComponent grid, TileAtmo args.Handled = true; } - /// - /// Update array of adjacent tiles and the adjacency flags. Optionally activates all tiles with modified adjacencies. - /// - private void UpdateAdjacentTiles( - Entity ent, - TileAtmosphere tile, - bool activate = false) + private void GridUpdateAdjacent(EntityUid uid, GridAtmosphereComponent component, + ref UpdateAdjacentMethodEvent args) { - var uid = ent.Owner; - var atmos = ent.Comp1; - var blockedDirs = tile.AirtightData.BlockedDirections; - if (activate) - AddActiveTile(atmos, tile); + if (args.Handled) + return; + + var mapGridComp = args.MapGridComponent; + + if (!Resolve(uid, ref mapGridComp)) + return; + + var xform = Transform(uid); + EntityUid? mapUid = _mapManager.MapExists(xform.MapID) ? _mapManager.GetMapEntityId(xform.MapID) : null; + + if (!component.Tiles.TryGetValue(args.Tile, out var tile)) + return; tile.AdjacentBits = AtmosDirection.Invalid; + tile.BlockedAirflow = GetBlockedDirections(mapGridComp, tile.GridIndices); + for (var i = 0; i < Atmospherics.Directions; i++) { var direction = (AtmosDirection) (1 << i); - var adjacentIndices = tile.GridIndices.Offset(direction); - TileAtmosphere? adjacent; - if (!tile.NoGridTile) - { - adjacent = GetOrNewTile(uid, atmos, adjacentIndices); - } - else if (!atmos.Tiles.TryGetValue(adjacentIndices, out adjacent)) + var otherIndices = tile.GridIndices.Offset(direction); + + if (!component.Tiles.TryGetValue(otherIndices, out var adjacent)) { - tile.AdjacentBits &= ~direction; - tile.AdjacentTiles[i] = null; - continue; + adjacent = new TileAtmosphere(tile.GridIndex, otherIndices, + GetTileMixture(null, mapUid, otherIndices), + space: IsTileSpace(null, mapUid, otherIndices, mapGridComp)); } - var adjBlockDirs = adjacent.AirtightData.BlockedDirections; - if (activate) - AddActiveTile(atmos, adjacent); - var oppositeDirection = direction.GetOpposite(); - if (adjBlockDirs.IsFlagSet(oppositeDirection) || blockedDirs.IsFlagSet(direction)) + + adjacent.BlockedAirflow = GetBlockedDirections(mapGridComp, adjacent.GridIndices); + + // Pass in MapGridComponent so we don't have to resolve it for every adjacent direction. + var tileBlockedEv = new IsTileAirBlockedMethodEvent(uid, tile.GridIndices, direction, mapGridComp); + GridIsTileAirBlocked(uid, component, ref tileBlockedEv); + + var adjacentBlockedEv = + new IsTileAirBlockedMethodEvent(uid, adjacent.GridIndices, oppositeDirection, mapGridComp); + GridIsTileAirBlocked(uid, component, ref adjacentBlockedEv); + + if (!adjacent.BlockedAirflow.IsFlagSet(oppositeDirection) && !tileBlockedEv.Result) + { + adjacent.AdjacentBits |= oppositeDirection; + adjacent.AdjacentTiles[oppositeDirection.ToIndex()] = tile; + } + else { - // Adjacency is blocked by some airtight entity. - tile.AdjacentBits &= ~direction; adjacent.AdjacentBits &= ~oppositeDirection; - tile.AdjacentTiles[i] = null; adjacent.AdjacentTiles[oppositeDirection.ToIndex()] = null; } - else + + if (!tile.BlockedAirflow.IsFlagSet(direction) && !adjacentBlockedEv.Result) { - // No airtight entity in the way. tile.AdjacentBits |= direction; - adjacent.AdjacentBits |= oppositeDirection; - tile.AdjacentTiles[i] = adjacent; - adjacent.AdjacentTiles[oppositeDirection.ToIndex()] = tile; + tile.AdjacentTiles[direction.ToIndex()] = adjacent; + } + else + { + tile.AdjacentBits &= ~direction; + tile.AdjacentTiles[direction.ToIndex()] = null; } DebugTools.Assert(!(tile.AdjacentBits.IsFlagSet(direction) ^ @@ -347,16 +409,6 @@ private void UpdateAdjacentTiles( tile.MonstermosInfo.CurrentTransferDirection = AtmosDirection.Invalid; } - private (GasMixture Air, bool IsSpace) GetDefaultMapAtmosphere(MapAtmosphereComponent? map) - { - if (map == null) - return (GasMixture.SpaceGas, true); - - var air = map.Mixture; - DebugTools.Assert(air.Immutable); - return (air, map.Space); - } - private void GridHotspotExpose(EntityUid uid, GridAtmosphereComponent component, ref HotspotExposeMethodEvent args) { if (args.Handled) @@ -399,50 +451,54 @@ private void GridIsHotspotActive(EntityUid uid, GridAtmosphereComponent componen args.Handled = true; } - private void GridFixTileVacuum( - Entity ent, - TileAtmosphere tile, - float volume) + private void GridFixTileVacuum(EntityUid uid, GridAtmosphereComponent component, ref FixTileVacuumMethodEvent args) { - DebugTools.AssertNotNull(tile.Air); - DebugTools.Assert(tile.Air?.Immutable == false ); - Array.Clear(tile.MolesArchived); - tile.ArchivedCycle = 0; + if (args.Handled) + return; + + var adjEv = new GetAdjacentTileMixturesMethodEvent(uid, args.Tile, false, true); + GridGetAdjacentTileMixtures(uid, component, ref adjEv); + + if (!adjEv.Handled || !component.Tiles.TryGetValue(args.Tile, out var tile)) + return; + + if (!TryComp(uid, out var mapGridComp)) + return; - var count = 0; - foreach (var adj in tile.AdjacentTiles) + var adjacent = adjEv.Result!.ToArray(); + + // Return early, let's not cause any funny NaNs or needless vacuums. + if (adjacent.Length == 0) + return; + + tile.Air = new GasMixture { - if (adj?.Air != null) - count++; - } + Volume = GetVolumeForTiles(mapGridComp, 1), + Temperature = Atmospherics.T20C + }; + + tile.MolesArchived = new float[Atmospherics.AdjustedNumberOfGases]; + tile.ArchivedCycle = 0; - var ratio = 1f / count; + var ratio = 1f / adjacent.Length; var totalTemperature = 0f; - foreach (var adj in tile.AdjacentTiles) + foreach (var adj in adjacent) { - if (adj?.Air == null) - continue; - totalTemperature += adj.Temperature; - // TODO ATMOS. Why is this removing and then re-adding air to the neighbouring tiles? - // Is it some rounding issue to do with Atmospherics.GasMinMoles? because otherwise this is just unnecessary. - // if we get rid of this, then this could also just add moles and then multiply by ratio at the end, rather - // than having to iterate over adjacent tiles twice. - // Remove a bit of gas from the adjacent ratio... - var mix = adj.Air.RemoveRatio(ratio); + var mix = adj.RemoveRatio(ratio); // And merge it to the new tile air. Merge(tile.Air, mix); // Return removed gas to its original mixture. - Merge(adj.Air, mix); + Merge(adj, mix); } // New temperature is the arithmetic mean of the sum of the adjacent temperatures... - tile.Air.Temperature = totalTemperature / count; + tile.Air.Temperature = totalTemperature / adjacent.Length; } private void GridAddPipeNet(EntityUid uid, GridAtmosphereComponent component, ref AddPipeNetMethodEvent args) @@ -491,21 +547,30 @@ private void GridRemoveAtmosDevice(EntityUid uid, GridAtmosphereComponent compon /// /// Repopulates all tiles on a grid atmosphere. /// - public void InvalidateAllTiles(Entity entity) + /// The grid where to get all valid tiles from. + /// The grid atmosphere where the tiles will be repopulated. + private void GridRepopulateTiles(Entity grid) { - var (uid, grid, atmos) = entity; - if (!Resolve(uid, ref grid, ref atmos)) - return; + var (uid, mapGrid, gridAtmosphere) = grid; + var volume = GetVolumeForTiles(mapGrid, 1); - foreach (var indices in atmos.Tiles.Keys) + foreach (var tile in mapGrid.GetAllTiles()) { - atmos.InvalidatedCoords.Add(indices); + if (!gridAtmosphere.Tiles.ContainsKey(tile.GridIndices)) + gridAtmosphere.Tiles[tile.GridIndices] = new TileAtmosphere(tile.GridUid, tile.GridIndices, + new GasMixture(volume) { Temperature = Atmospherics.T20C }); + + gridAtmosphere.InvalidatedCoords.Add(tile.GridIndices); } - var enumerator = _map.GetAllTilesEnumerator(uid, grid); - while (enumerator.MoveNext(out var tile)) + TryComp(uid, out GasTileOverlayComponent? overlay); + + // Gotta do this afterwards so we can properly update adjacent tiles. + foreach (var (position, _) in gridAtmosphere.Tiles.ToArray()) { - atmos.InvalidatedCoords.Add(tile.Value.GridIndices); + var ev = new UpdateAdjacentMethodEvent(uid, position); + GridUpdateAdjacent(uid, gridAtmosphere, ref ev); + InvalidateVisuals(uid, position, overlay); } } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs index 77b5bf18af2..53035e1ed3c 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs @@ -1,11 +1,13 @@ using Content.Server.Atmos.Components; using Content.Shared.Atmos; +using Content.Shared.Audio; using Content.Shared.Mobs.Components; using Content.Shared.Physics; using Robust.Shared.Audio; using Robust.Shared.Map; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; +using Robust.Shared.Player; using Robust.Shared.Random; using Robust.Shared.Utility; @@ -52,7 +54,7 @@ private void UpdateHighPressure(float frameTime) if (HasComp(uid) && TryComp(uid, out var body)) { - _physics.SetBodyStatus(uid, body, BodyStatus.OnGround); + _physics.SetBodyStatus(body, BodyStatus.OnGround); } if (TryComp(uid, out var fixtures)) @@ -75,7 +77,7 @@ private void AddMobMovedByPressure(EntityUid uid, MovedByPressureComponent compo if (!TryComp(uid, out var fixtures)) return; - _physics.SetBodyStatus(uid, body, BodyStatus.InAir); + _physics.SetBodyStatus(body, BodyStatus.InAir); foreach (var (id, fixture) in fixtures.Fixtures) { @@ -94,9 +96,9 @@ private void HighPressureMovements(Entity gridAtmospher // TODO ATMOS finish this // Don't play the space wind sound on tiles that are on fire... - if (tile.PressureDifference > 15 && !tile.Hotspot.Valid) + if(tile.PressureDifference > 15 && !tile.Hotspot.Valid) { - if (_spaceWindSoundCooldown == 0 && !string.IsNullOrEmpty(SpaceWindSound)) + if(_spaceWindSoundCooldown == 0 && !string.IsNullOrEmpty(SpaceWindSound)) { var coordinates = _mapSystem.ToCenterCoordinates(tile.GridIndex, tile.GridIndices); _audio.PlayPvs(SpaceWindSound, coordinates, AudioParams.Default.WithVariation(0.125f).WithVolume(MathHelper.Clamp(tile.PressureDifference / 10, 10, 100))); diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs index c27e18b55b0..795c6e0547e 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs @@ -1,13 +1,12 @@ using Content.Server.Atmos.Components; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; -using Robust.Shared.Utility; namespace Content.Server.Atmos.EntitySystems { public sealed partial class AtmosphereSystem { - private void ProcessCell(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, int fireCount, GasTileOverlayComponent visuals) + private void ProcessCell(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, int fireCount, GasTileOverlayComponent? visuals) { // Can't process a tile without air if (tile.Air == null) @@ -117,9 +116,15 @@ private void ProcessCell(GridAtmosphereComponent gridAtmosphere, TileAtmosphere private void Archive(TileAtmosphere tile, int fireCount) { if (tile.Air != null) + { tile.Air.Moles.AsSpan().CopyTo(tile.MolesArchived.AsSpan()); + tile.TemperatureArchived = tile.Air.Temperature; + } + else + { + tile.TemperatureArchived = tile.Temperature; + } - tile.TemperatureArchived = tile.Temperature; tile.ArchivedCycle = fireCount; } @@ -161,12 +166,6 @@ private void AddActiveTile(GridAtmosphereComponent gridAtmosphere, TileAtmospher /// Whether to dispose of the tile's private void RemoveActiveTile(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, bool disposeExcitedGroup = true) { - DebugTools.Assert(tile.Excited == gridAtmosphere.ActiveTiles.Contains(tile)); - DebugTools.Assert(tile.Excited || tile.ExcitedGroup == null); - - if (!tile.Excited) - return; - tile.Excited = false; gridAtmosphere.ActiveTiles.Remove(tile); @@ -187,6 +186,7 @@ public float GetHeatCapacityArchived(TileAtmosphere tile) if (tile.Air == null) return tile.HeatCapacity; + // Moles archived is not null if air is not null. return GetHeatCapacityCalculation(tile.MolesArchived!, tile.Space); } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs index ed105c8d33f..916191cb050 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs @@ -1,8 +1,6 @@ using Content.Server.Atmos.Components; using Content.Shared.Atmos.Components; using Robust.Shared.GameStates; -using Robust.Shared.Map.Components; -using Robust.Shared.Utility; namespace Content.Server.Atmos.EntitySystems; @@ -10,25 +8,10 @@ public partial class AtmosphereSystem { private void InitializeMap() { - SubscribeLocalEvent(OnMapStartup); - SubscribeLocalEvent(OnMapRemove); SubscribeLocalEvent(MapIsTileSpace); SubscribeLocalEvent(MapGetTileMixture); SubscribeLocalEvent(MapGetTileMixtures); SubscribeLocalEvent(OnMapGetState); - SubscribeLocalEvent(OnGridParentChanged); - } - - private void OnMapStartup(EntityUid uid, MapAtmosphereComponent component, ComponentInit args) - { - component.Mixture.MarkImmutable(); - component.Overlay = _gasTileOverlaySystem.GetOverlayData(component.Mixture); - } - - private void OnMapRemove(EntityUid uid, MapAtmosphereComponent component, ComponentRemove args) - { - if (!TerminatingOrDeleted(uid)) - RefreshAllGridMapAtmospheres(uid); } private void MapIsTileSpace(EntityUid uid, MapAtmosphereComponent component, ref IsTileSpaceMethodEvent args) @@ -45,115 +28,54 @@ private void MapGetTileMixture(EntityUid uid, MapAtmosphereComponent component, if (args.Handled) return; - args.Mixture = component.Mixture; + // Clone the mixture, if possible. + args.Mixture = component.Mixture?.Clone(); args.Handled = true; } private void MapGetTileMixtures(EntityUid uid, MapAtmosphereComponent component, ref GetTileMixturesMethodEvent args) { - if (args.Handled) + if (args.Handled || component.Mixture == null) return; args.Handled = true; args.Mixtures ??= new GasMixture?[args.Tiles.Count]; for (var i = 0; i < args.Tiles.Count; i++) { - args.Mixtures[i] ??= component.Mixture; + args.Mixtures[i] ??= component.Mixture.Clone(); } } private void OnMapGetState(EntityUid uid, MapAtmosphereComponent component, ref ComponentGetState args) { - args.State = new MapAtmosphereComponentState(component.Overlay); - } - - public void SetMapAtmosphere(EntityUid uid, bool space, GasMixture mixture) - { - DebugTools.Assert(HasComp(uid)); - var component = EnsureComp(uid); - SetMapGasMixture(uid, mixture, component, false); - SetMapSpace(uid, space, component, false); - RefreshAllGridMapAtmospheres(uid); + args.State = new MapAtmosphereComponentState(_gasTileOverlaySystem.GetOverlayData(component.Mixture)); } - public void SetMapGasMixture(EntityUid uid, GasMixture mixture, MapAtmosphereComponent? component = null, bool updateTiles = true) + public void SetMapAtmosphere(EntityUid uid, bool space, GasMixture mixture, MapAtmosphereComponent? component = null) { if (!Resolve(uid, ref component)) return; - if (!mixture.Immutable) - { - mixture = mixture.Clone(); - mixture.MarkImmutable(); - } - + component.Space = space; component.Mixture = mixture; - component.Overlay = _gasTileOverlaySystem.GetOverlayData(component.Mixture); - Dirty(uid, component); - if (updateTiles) - RefreshAllGridMapAtmospheres(uid); + Dirty(component); } - public void SetMapSpace(EntityUid uid, bool space, MapAtmosphereComponent? component = null, bool updateTiles = true) + public void SetMapGasMixture(EntityUid uid, GasMixture? mixture, MapAtmosphereComponent? component = null) { if (!Resolve(uid, ref component)) return; - if (component.Space == space) - return; - - component.Space = space; - - if (updateTiles) - RefreshAllGridMapAtmospheres(uid); - } - - /// - /// Forces a refresh of all MapAtmosphere tiles on every grid on a map. - /// - public void RefreshAllGridMapAtmospheres(EntityUid map) - { - DebugTools.Assert(HasComp(map)); - var enumerator = AllEntityQuery(); - while (enumerator.MoveNext(out var grid, out var atmos, out var xform)) - { - if (xform.MapUid == map) - RefreshMapAtmosphereTiles((grid, atmos)); - } - } - - /// - /// Forces a refresh of all MapAtmosphere tiles on a given grid. - /// - private void RefreshMapAtmosphereTiles(Entity grid) - { - if (!Resolve(grid.Owner, ref grid.Comp)) - return; - - var atmos = grid.Comp; - foreach (var tile in atmos.MapTiles) - { - RemoveMapAtmos(atmos, tile); - atmos.InvalidatedCoords.Add(tile.GridIndices); - } - atmos.MapTiles.Clear(); + component.Mixture = mixture; + Dirty(component); } - /// - /// Handles updating map-atmospheres when grids move across maps. - /// - private void OnGridParentChanged(Entity grid, ref EntParentChangedMessage args) + public void SetMapSpace(EntityUid uid, bool space, MapAtmosphereComponent? component = null) { - // Do nothing if detaching to nullspace - if (!args.Transform.ParentUid.IsValid()) + if (!Resolve(uid, ref component)) return; - // Avoid doing work if moving from a space-map to another space-map. - if (args.OldParent == null - || HasComp(args.OldParent) - || HasComp(args.Transform.ParentUid)) - { - RefreshMapAtmosphereTiles((grid, grid)); - } + component.Space = space; + Dirty(component); } } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs index f156125b0ff..aceda3cd332 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs @@ -5,6 +5,7 @@ using Content.Shared.Atmos; using Content.Shared.Atmos.Components; using Content.Shared.Database; +using Content.Shared.Doors.Components; using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Random; @@ -26,10 +27,7 @@ public sealed partial class AtmosphereSystem private readonly TileAtmosphere[] _depressurizeSpaceTiles = new TileAtmosphere[Atmospherics.MonstermosHardTileLimit]; private readonly TileAtmosphere[] _depressurizeProgressionOrder = new TileAtmosphere[Atmospherics.MonstermosHardTileLimit * 2]; - private void EqualizePressureInZone( - Entity ent, - TileAtmosphere tile, - int cycleNum) + private void EqualizePressureInZone(Entity ent, TileAtmosphere tile, int cycleNum, GasTileOverlayComponent? visuals) { if (tile.Air == null || (tile.MonstermosInfo.LastCycle >= cycleNum)) return; // Already done. @@ -58,7 +56,7 @@ private void EqualizePressureInZone( return; } - var gridAtmosphere = ent.Comp1; + var (_, mapGrid, gridAtmosphere) = ent; var queueCycle = ++gridAtmosphere.EqualizationQueueCycleControl; var totalMoles = 0f; _equalizeTiles[0] = tile; @@ -93,7 +91,7 @@ private void EqualizePressureInZone( { // Looks like someone opened an airlock to space! - ExplosivelyDepressurize(ent, tile, cycleNum); + ExplosivelyDepressurize(ent, tile, cycleNum, visuals); return; } } @@ -218,13 +216,9 @@ private void EqualizePressureInZone( for (var k = 0; k < Atmospherics.Directions; k++) { var direction = (AtmosDirection) (1 << k); - if (!otherTile.AdjacentBits.IsFlagSet(direction)) - continue; - - if (giver.MonstermosInfo.MoleDelta <= 0) - break; // We're done here now. Let's not do more work than needed. - + if (!otherTile.AdjacentBits.IsFlagSet(direction)) continue; var otherTile2 = otherTile.AdjacentTiles[k]; + if (giver.MonstermosInfo.MoleDelta <= 0) break; // We're done here now. Let's not do more work than needed. if (otherTile2 == null || otherTile2.MonstermosInfo.LastQueueCycle != queueCycle) continue; DebugTools.Assert(otherTile2.AdjacentBits.IsFlagSet(direction.GetOpposite())); if (otherTile2.MonstermosInfo.LastSlowQueueCycle == queueCycleSlow) continue; @@ -338,7 +332,7 @@ private void EqualizePressureInZone( for (var i = 0; i < tileCount; i++) { var otherTile = _equalizeTiles[i]!; - FinalizeEq(gridAtmosphere, otherTile, ent); + FinalizeEq(gridAtmosphere, otherTile, visuals); } for (var i = 0; i < tileCount; i++) @@ -347,17 +341,12 @@ private void EqualizePressureInZone( for (var j = 0; j < Atmospherics.Directions; j++) { var direction = (AtmosDirection) (1 << j); - if (!otherTile.AdjacentBits.IsFlagSet(direction)) - continue; - + if (!otherTile.AdjacentBits.IsFlagSet(direction)) continue; var otherTile2 = otherTile.AdjacentTiles[j]!; if (otherTile2.AdjacentBits == 0) continue; - DebugTools.Assert(otherTile2.AdjacentBits.IsFlagSet(direction.GetOpposite())); - if (otherTile2.Air != null && CompareExchange(otherTile2.Air, tile.Air) == GasCompareResult.NoExchange) - continue; - + if (otherTile2.Air != null && CompareExchange(otherTile2.Air, tile.Air) == GasCompareResult.NoExchange) continue; AddActiveTile(gridAtmosphere, otherTile2); break; } @@ -370,10 +359,7 @@ private void EqualizePressureInZone( Array.Clear(_equalizeQueue, 0, Atmospherics.MonstermosTileLimit); } - private void ExplosivelyDepressurize( - Entity ent, - TileAtmosphere tile, - int cycleNum) + private void ExplosivelyDepressurize(Entity ent, TileAtmosphere tile, int cycleNum, GasTileOverlayComponent? visuals) { // Check if explosive depressurization is enabled and if the tile is valid. if (!MonstermosDepressurization || tile.Air == null) @@ -382,7 +368,7 @@ private void ExplosivelyDepressurize( const int limit = Atmospherics.MonstermosHardTileLimit; var totalMolesRemoved = 0f; - var (owner, gridAtmosphere, visuals, mapGrid, _) = ent; + var (owner, mapGrid, gridAtmosphere) = ent; var queueCycle = ++gridAtmosphere.EqualizationQueueCycleControl; var tileCount = 0; @@ -402,27 +388,20 @@ private void ExplosivelyDepressurize( { for (var j = 0; j < Atmospherics.Directions; j++) { - var otherTile2 = otherTile.AdjacentTiles[j]; - if (otherTile2?.Air == null) - continue; - - if (otherTile2.MonstermosInfo.LastQueueCycle == queueCycle) - continue; - var direction = (AtmosDirection) (1 << j); - DebugTools.Assert(otherTile.AdjacentBits.IsFlagSet(direction)); + if (!otherTile.AdjacentBits.IsFlagSet(direction)) continue; + var otherTile2 = otherTile.AdjacentTiles[j]; + if (otherTile2?.Air == null) continue; DebugTools.Assert(otherTile2.AdjacentBits.IsFlagSet(direction.GetOpposite())); + if (otherTile2.MonstermosInfo.LastQueueCycle == queueCycle) continue; - ConsiderFirelocks(ent, otherTile, otherTile2); + ConsiderFirelocks((owner, gridAtmosphere), otherTile, otherTile2, visuals, mapGrid); // The firelocks might have closed on us. - if (!otherTile.AdjacentBits.IsFlagSet(direction)) - continue; - + if (!otherTile.AdjacentBits.IsFlagSet(direction)) continue; otherTile2.MonstermosInfo = new MonstermosInfo { LastQueueCycle = queueCycle }; _depressurizeTiles[tileCount++] = otherTile2; - if (tileCount >= limit) - break; + if (tileCount >= limit) break; } } else @@ -458,21 +437,13 @@ private void ExplosivelyDepressurize( // Flood fill into this new direction var direction = (AtmosDirection) (1 << j); // Tiles in _depressurizeProgressionOrder cannot have null air. - if (!otherTile.AdjacentBits.IsFlagSet(direction) && !otherTile.Space) - continue; - + if (!otherTile.AdjacentBits.IsFlagSet(direction) && !otherTile.Space) continue; var tile2 = otherTile.AdjacentTiles[j]; - if (tile2?.MonstermosInfo.LastQueueCycle != queueCycle) - continue; - + if (tile2?.MonstermosInfo.LastQueueCycle != queueCycle) continue; DebugTools.Assert(tile2.AdjacentBits.IsFlagSet(direction.GetOpposite())); // If flood fill has already reached this tile, continue. - if (tile2.MonstermosInfo.LastSlowQueueCycle == queueCycleSlow) - continue; - - if(tile2.Space) - continue; - + if (tile2.MonstermosInfo.LastSlowQueueCycle == queueCycleSlow) continue; + if(tile2.Space) continue; tile2.MonstermosInfo.CurrentTransferDirection = direction.GetOpposite(); tile2.MonstermosInfo.CurrentTransferAmount = 0.0f; tile2.PressureSpecificTarget = otherTile.PressureSpecificTarget; @@ -564,7 +535,7 @@ private void ExplosivelyDepressurize( _physics.ApplyAngularImpulse(owner, Vector2Helpers.Cross(tile.GridIndices - gridPhysics.LocalCenter, direction) * totalMolesRemoved, body: gridPhysics); } - if (tileCount > 10 && (totalMolesRemoved / tileCount) > 10) + if(tileCount > 10 && (totalMolesRemoved / tileCount) > 10) _adminLog.Add(LogType.ExplosiveDepressurization, LogImpact.High, $"Explosive depressurization removed {totalMolesRemoved} moles from {tileCount} tiles starting from position {tile.GridIndices:position} on grid ID {tile.GridIndex:grid}"); @@ -573,33 +544,36 @@ private void ExplosivelyDepressurize( Array.Clear(_depressurizeProgressionOrder, 0, Atmospherics.MonstermosHardTileLimit * 2); } - private void ConsiderFirelocks( - Entity ent, - TileAtmosphere tile, - TileAtmosphere other) + private void ConsiderFirelocks(Entity ent, TileAtmosphere tile, TileAtmosphere other, GasTileOverlayComponent? visuals, MapGridComponent mapGrid) { var reconsiderAdjacent = false; - var mapGrid = ent.Comp3; - foreach (var entity in _map.GetAnchoredEntities(ent.Owner, mapGrid, tile.GridIndices)) + foreach (var entity in mapGrid.GetAnchoredEntities(tile.GridIndices)) { - if (_firelockQuery.TryGetComponent(entity, out var firelock)) - reconsiderAdjacent |= _firelockSystem.EmergencyPressureStop(entity, firelock); + if (!TryComp(entity, out FirelockComponent? firelock)) + continue; + + reconsiderAdjacent |= _firelockSystem.EmergencyPressureStop(entity, firelock); } - foreach (var entity in _map.GetAnchoredEntities(ent.Owner, mapGrid, other.GridIndices)) + foreach (var entity in mapGrid.GetAnchoredEntities(other.GridIndices)) { - if (_firelockQuery.TryGetComponent(entity, out var firelock)) - reconsiderAdjacent |= _firelockSystem.EmergencyPressureStop(entity, firelock); + if (!TryComp(entity, out FirelockComponent? firelock)) + continue; + + reconsiderAdjacent |= _firelockSystem.EmergencyPressureStop(entity, firelock); } if (!reconsiderAdjacent) return; - UpdateAdjacentTiles(ent, tile); - UpdateAdjacentTiles(ent, other); - InvalidateVisuals(tile.GridIndex, tile.GridIndices, ent); - InvalidateVisuals(other.GridIndex, other.GridIndices, ent); + var (owner, gridAtmosphere) = ent; + var tileEv = new UpdateAdjacentMethodEvent(owner, tile.GridIndices); + var otherEv = new UpdateAdjacentMethodEvent(owner, other.GridIndices); + GridUpdateAdjacent(owner, gridAtmosphere, ref tileEv); + GridUpdateAdjacent(owner, gridAtmosphere, ref otherEv); + InvalidateVisuals(tile.GridIndex, tile.GridIndices, visuals); + InvalidateVisuals(other.GridIndex, other.GridIndices, visuals); } private void FinalizeEq(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, GasTileOverlayComponent? visuals) @@ -668,7 +642,7 @@ private void AdjustEqMovement(TileAtmosphere tile, AtmosDirection direction, flo if (adj == null) { var nonNull = tile.AdjacentTiles.Where(x => x != null).Count(); - Log.Error($"Encountered null adjacent tile in {nameof(AdjustEqMovement)}. Dir: {direction}, Tile: ({tile.GridIndex}, {tile.GridIndices}), non-null adj count: {nonNull}, Trace: {Environment.StackTrace}"); + Logger.Error($"Encountered null adjacent tile in {nameof(AdjustEqMovement)}. Dir: {direction}, Tile: {tile.Tile}, non-null adj count: {nonNull}, Trace: {Environment.StackTrace}"); return; } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs index 1f3ca2145b9..4f8df0af670 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs @@ -1,5 +1,6 @@ using Content.Server.Atmos.Components; using Content.Server.Atmos.Piping.Components; +using Content.Server.NodeContainer.NodeGroups; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; using Content.Shared.Maps; @@ -7,7 +8,6 @@ using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Timing; -using Robust.Shared.Utility; namespace Content.Server.Atmos.EntitySystems { @@ -30,249 +30,131 @@ public sealed partial class AtmosphereSystem private int _currentRunAtmosphereIndex; private bool _simulationPaused; - private TileAtmosphere GetOrNewTile(EntityUid owner, GridAtmosphereComponent atmosphere, Vector2i index) - { - var tile = atmosphere.Tiles.GetOrNew(index, out var existing); - if (existing) - return tile; - - atmosphere.InvalidatedCoords.Add(index); - tile.GridIndex = owner; - tile.GridIndices = index; - return tile; - } - - private readonly List> _currentRunAtmosphere = new(); + private readonly List> _currentRunAtmosphere = new(); /// /// Revalidates all invalid coordinates in a grid atmosphere. - /// I.e., process any tiles that have had their airtight blockers modified. /// /// The grid atmosphere in question. /// Whether the process succeeded or got paused due to time constrains. - private bool ProcessRevalidate(Entity ent) + private bool ProcessRevalidate(Entity ent, GasTileOverlayComponent? visuals) { - if (ent.Comp4.MapUid == null) - { - Log.Error($"Attempted to process atmosphere on a map-less grid? Grid: {ToPrettyString(ent)}"); - return true; - } - - var (uid, atmosphere, visuals, grid, xform) = ent; - var volume = GetVolumeForTiles(grid); - TryComp(xform.MapUid, out MapAtmosphereComponent? mapAtmos); - + var (owner, atmosphere) = ent; if (!atmosphere.ProcessingPaused) { - atmosphere.CurrentRunInvalidatedTiles.Clear(); - atmosphere.CurrentRunInvalidatedTiles.EnsureCapacity(atmosphere.InvalidatedCoords.Count); - foreach (var indices in atmosphere.InvalidatedCoords) + atmosphere.CurrentRunInvalidatedCoordinates.Clear(); + atmosphere.CurrentRunInvalidatedCoordinates.EnsureCapacity(atmosphere.InvalidatedCoords.Count); + foreach (var tile in atmosphere.InvalidatedCoords) { - var tile = GetOrNewTile(uid, atmosphere, indices); - atmosphere.CurrentRunInvalidatedTiles.Enqueue(tile); - - // Update tile.IsSpace and tile.MapAtmosphere, and tile.AirtightData. - UpdateTileData(ent, mapAtmos, tile); + atmosphere.CurrentRunInvalidatedCoordinates.Enqueue(tile); } atmosphere.InvalidatedCoords.Clear(); - - if (_simulationStopwatch.Elapsed.TotalMilliseconds >= AtmosMaxProcessTime) - return false; } - var number = 0; - while (atmosphere.CurrentRunInvalidatedTiles.TryDequeue(out var tile)) - { - DebugTools.Assert(atmosphere.Tiles.GetValueOrDefault(tile.GridIndices) == tile); - UpdateAdjacentTiles(ent, tile, activate: true); - UpdateTileAir(ent, tile, volume); - InvalidateVisuals(uid, tile.GridIndices, visuals); - - if (number++ < InvalidCoordinatesLagCheckIterations) - continue; - - number = 0; - // Process the rest next time. - if (_simulationStopwatch.Elapsed.TotalMilliseconds >= AtmosMaxProcessTime) - return false; - } + if (!TryComp(owner, out MapGridComponent? mapGridComp)) + return true; - TrimDisconnectedMapTiles(ent); - return true; - } + var mapUid = _mapManager.GetMapEntityIdOrThrow(Transform(owner).MapID); - /// - /// This method queued a tile and all of its neighbours up for processing by . - /// - public void QueueTileTrim(GridAtmosphereComponent atmos, TileAtmosphere tile) - { - if (!tile.TrimQueued) - { - tile.TrimQueued = true; - atmos.PossiblyDisconnectedTiles.Add(tile); - } + var volume = GetVolumeForTiles(mapGridComp); - for (var i = 0; i < Atmospherics.Directions; i++) + var number = 0; + while (atmosphere.CurrentRunInvalidatedCoordinates.TryDequeue(out var indices)) { - var direction = (AtmosDirection) (1 << i); - var indices = tile.GridIndices.Offset(direction); - if (atmos.Tiles.TryGetValue(indices, out var adj) - && adj.NoGridTile - && !adj.TrimQueued) + if (!atmosphere.Tiles.TryGetValue(indices, out var tile)) { - adj.TrimQueued = true; - atmos.PossiblyDisconnectedTiles.Add(adj); + tile = new TileAtmosphere(owner, indices, + new GasMixture(volume) { Temperature = Atmospherics.T20C }); + atmosphere.Tiles[indices] = tile; } - } - } - /// - /// Tiles in a are either grid-tiles, or they they should be are tiles - /// adjacent to grid-tiles that represent the map's atmosphere. This method trims any map-tiles that are no longer - /// adjacent to any grid-tiles. - /// - private void TrimDisconnectedMapTiles( - Entity ent) - { - var atmos = ent.Comp1; + var airBlockedEv = new IsTileAirBlockedMethodEvent(owner, indices, MapGridComponent:mapGridComp); + GridIsTileAirBlocked(owner, atmosphere, ref airBlockedEv); + var isAirBlocked = airBlockedEv.Result; - foreach (var tile in atmos.PossiblyDisconnectedTiles) - { - tile.TrimQueued = false; - if (!tile.NoGridTile) - continue; + var oldBlocked = tile.BlockedAirflow; + var updateAdjacentEv = new UpdateAdjacentMethodEvent(owner, indices, mapGridComp); + GridUpdateAdjacent(owner, atmosphere, ref updateAdjacentEv); - var connected = false; - for (var i = 0; i < Atmospherics.Directions; i++) + // Blocked airflow changed, rebuild excited groups! + if (tile.Excited && tile.BlockedAirflow != oldBlocked) { - var indices = tile.GridIndices.Offset((AtmosDirection) (1 << i)); - if (_map.TryGetTile(ent.Comp3, indices, out var gridTile) && !gridTile.IsEmpty) - { - connected = true; - break; - } + RemoveActiveTile(atmosphere, tile); } - if (!connected) + // Call this instead of the grid method as the map has a say on whether the tile is space or not. + if ((!mapGridComp.TryGetTileRef(indices, out var t) || t.IsSpace(_tileDefinitionManager)) && !isAirBlocked) { - RemoveActiveTile(atmos, tile); - atmos.Tiles.Remove(tile.GridIndices); + tile.Air = GetTileMixture(null, mapUid, indices); + tile.MolesArchived = tile.Air != null ? new float[Atmospherics.AdjustedNumberOfGases] : null; + tile.Space = IsTileSpace(null, mapUid, indices, mapGridComp); } - } - - atmos.PossiblyDisconnectedTiles.Clear(); - } - - /// - /// Checks whether a tile has a corresponding grid-tile, or whether it is a "map" tile. Also checks whether the - /// tile should be considered "space" - /// - private void UpdateTileData( - Entity ent, - MapAtmosphereComponent? mapAtmos, - TileAtmosphere tile) - { - var idx = tile.GridIndices; - bool mapAtmosphere; - if (_map.TryGetTile(ent.Comp3, idx, out var gTile) && !gTile.IsEmpty) - { - var contentDef = (ContentTileDefinition) _tileDefinitionManager[gTile.TypeId]; - mapAtmosphere = contentDef.MapAtmosphere; - tile.ThermalConductivity = contentDef.ThermalConductivity; - tile.HeatCapacity = contentDef.HeatCapacity; - tile.NoGridTile = false; - } - else - { - mapAtmosphere = true; - tile.ThermalConductivity = 0.5f; - tile.HeatCapacity = float.PositiveInfinity; - - if (!tile.NoGridTile) + else if (isAirBlocked) { - tile.NoGridTile = true; - - // This tile just became a non-grid atmos tile. - // It, or one of its neighbours, might now be completely disconnected from the grid. - QueueTileTrim(ent.Comp1, tile); + if (airBlockedEv.NoAir) + { + tile.Air = null; + tile.MolesArchived = null; + tile.ArchivedCycle = 0; + tile.LastShare = 0f; + tile.Hotspot = new Hotspot(); + } } - } + else + { + if (tile.Air == null && NeedsVacuumFixing(mapGridComp, indices)) + { + var vacuumEv = new FixTileVacuumMethodEvent(owner, indices); + GridFixTileVacuum(owner, atmosphere, ref vacuumEv); + } - UpdateAirtightData(ent.Owner, ent.Comp1, ent.Comp3, tile); + // Tile used to be space, but isn't anymore. + if (tile.Space || (tile.Air?.Immutable ?? false)) + { + tile.Air = null; + tile.MolesArchived = null; + tile.ArchivedCycle = 0; + tile.LastShare = 0f; + tile.Space = false; + } - if (mapAtmosphere) - { - if (!tile.MapAtmosphere) - { - (tile.Air, tile.Space) = GetDefaultMapAtmosphere(mapAtmos); - tile.MapAtmosphere = true; - ent.Comp1.MapTiles.Add(tile); + tile.Air ??= new GasMixture(volume){Temperature = Atmospherics.T20C}; + tile.MolesArchived ??= new float[Atmospherics.AdjustedNumberOfGases]; } - DebugTools.AssertNotNull(tile.Air); - DebugTools.Assert(tile.Air?.Immutable ?? false); - return; - } + // We activate the tile. + AddActiveTile(atmosphere, tile); - if (!tile.MapAtmosphere) - return; + // TODO ATMOS: Query all the contents of this tile (like walls) and calculate the correct thermal conductivity and heat capacity + var tileDef = mapGridComp.TryGetTileRef(indices, out var tileRef) + ? tileRef.GetContentTileDefinition(_tileDefinitionManager) + : null; - // Tile used to be exposed to the map's atmosphere, but isn't anymore. - RemoveMapAtmos(ent.Comp1, tile); - } + tile.ThermalConductivity = tileDef?.ThermalConductivity ?? 0.5f; + tile.HeatCapacity = tileDef?.HeatCapacity ?? float.PositiveInfinity; + InvalidateVisuals(owner, indices, visuals); - private void RemoveMapAtmos(GridAtmosphereComponent atmos, TileAtmosphere tile) - { - DebugTools.Assert(tile.MapAtmosphere); - DebugTools.AssertNotNull(tile.Air); - DebugTools.Assert(tile.Air?.Immutable ?? false); - tile.MapAtmosphere = false; - atmos.MapTiles.Remove(tile); - tile.Air = null; - Array.Clear(tile.MolesArchived); - tile.ArchivedCycle = 0; - tile.LastShare = 0f; - tile.Space = false; - } + for (var i = 0; i < Atmospherics.Directions; i++) + { + var direction = (AtmosDirection) (1 << i); + var otherIndices = indices.Offset(direction); - /// - /// Check whether a grid-tile should have an air mixture, and give it one if it doesn't already have one. - /// - private void UpdateTileAir( - Entity ent, - TileAtmosphere tile, - float volume) - { - if (tile.MapAtmosphere) - { - DebugTools.AssertNotNull(tile.Air); - DebugTools.Assert(tile.Air?.Immutable ?? false); - return; - } + if (atmosphere.Tiles.TryGetValue(otherIndices, out var otherTile)) + AddActiveTile(atmosphere, otherTile); + } - var data = tile.AirtightData; - var fullyBlocked = data.BlockedDirections == AtmosDirection.All; + if (number++ < InvalidCoordinatesLagCheckIterations) + continue; - if (fullyBlocked && data.NoAirWhenBlocked) - { - if (tile.Air == null) - return; - - tile.Air = null; - Array.Clear(tile.MolesArchived); - tile.ArchivedCycle = 0; - tile.LastShare = 0f; - tile.Hotspot = new Hotspot(); - return; + number = 0; + // Process the rest next time. + if (_simulationStopwatch.Elapsed.TotalMilliseconds >= AtmosMaxProcessTime) + { + return false; + } } - if (tile.Air != null) - return; - - tile.Air = new GasMixture(volume){Temperature = Atmospherics.T20C}; - - if (data.FixVacuum) - GridFixTileVacuum(ent, tile, volume); + return true; } private void QueueRunTiles( @@ -288,16 +170,19 @@ private void QueueRunTiles( } } - private bool ProcessTileEqualize(Entity ent) + private bool ProcessTileEqualize(Entity ent, GasTileOverlayComponent? visuals) { - var atmosphere = ent.Comp1; + var (uid, atmosphere) = ent; if (!atmosphere.ProcessingPaused) QueueRunTiles(atmosphere.CurrentRunTiles, atmosphere.ActiveTiles); + if (!TryComp(uid, out MapGridComponent? mapGridComp)) + throw new Exception("Tried to process a grid atmosphere on an entity that isn't a grid!"); + var number = 0; while (atmosphere.CurrentRunTiles.TryDequeue(out var tile)) { - EqualizePressureInZone(ent, tile, atmosphere.UpdateCounter); + EqualizePressureInZone((uid, mapGridComp, atmosphere), tile, atmosphere.UpdateCounter, visuals); if (number++ < LagCheckIterations) continue; @@ -313,7 +198,7 @@ private bool ProcessTileEqualize(Entity Atmospherics.ExcitedGroupBreakdownCycles) + if(excitedGroup.BreakdownCooldown > Atmospherics.ExcitedGroupBreakdownCycles) ExcitedGroupSelfBreakdown(gridAtmosphere, excitedGroup); - else if (excitedGroup.DismantleCooldown > Atmospherics.ExcitedGroupsDismantleCycles) - DeactivateGroupTiles(gridAtmosphere, excitedGroup); - // TODO ATMOS. What is the point of this? why is this only de-exciting the group? Shouldn't it also dismantle it? + + else if(excitedGroup.DismantleCooldown > Atmospherics.ExcitedGroupsDismantleCycles) + ExcitedGroupDismantle(gridAtmosphere, excitedGroup); if (number++ < LagCheckIterations) continue; @@ -550,10 +435,10 @@ private void UpdateProcessing(float frameTime) _currentRunAtmosphereIndex = 0; _currentRunAtmosphere.Clear(); - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var atmos, out var overlay, out var grid, out var xform )) + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var grid)) { - _currentRunAtmosphere.Add((uid, atmos, overlay, grid, xform)); + _currentRunAtmosphere.Add((uid, grid)); } } @@ -563,7 +448,8 @@ private void UpdateProcessing(float frameTime) for (; _currentRunAtmosphereIndex < _currentRunAtmosphere.Count; _currentRunAtmosphereIndex++) { var ent = _currentRunAtmosphere[_currentRunAtmosphereIndex]; - var (owner, atmosphere, visuals, grid, xform) = ent; + var (owner, atmosphere) = ent; + TryComp(owner, out GasTileOverlayComponent? visuals); if (!TryComp(owner, out TransformComponent? x) || x.MapUid == null @@ -588,14 +474,13 @@ private void UpdateProcessing(float frameTime) switch (atmosphere.State) { case AtmosphereProcessingState.Revalidate: - if (!ProcessRevalidate(ent)) + if (!ProcessRevalidate(ent, visuals)) { atmosphere.ProcessingPaused = true; return; } atmosphere.ProcessingPaused = false; - // Next state depends on whether monstermos equalization is enabled or not. // Note: We do this here instead of on the tile equalization step to prevent ending it early. // Therefore, a change to this CVar might only be applied after that step is over. @@ -604,7 +489,7 @@ private void UpdateProcessing(float frameTime) : AtmosphereProcessingState.ActiveTiles; continue; case AtmosphereProcessingState.TileEqualize: - if (!ProcessTileEqualize(ent)) + if (!ProcessTileEqualize(ent, visuals)) { atmosphere.ProcessingPaused = true; return; @@ -614,7 +499,7 @@ private void UpdateProcessing(float frameTime) atmosphere.State = AtmosphereProcessingState.ActiveTiles; continue; case AtmosphereProcessingState.ActiveTiles: - if (!ProcessActiveTiles(ent, ent)) + if (!ProcessActiveTiles(atmosphere, visuals)) { atmosphere.ProcessingPaused = true; return; @@ -635,7 +520,7 @@ private void UpdateProcessing(float frameTime) atmosphere.State = AtmosphereProcessingState.HighPressureDelta; continue; case AtmosphereProcessingState.HighPressureDelta: - if (!ProcessHighPressureDelta((ent, ent))) + if (!ProcessHighPressureDelta(ent)) { atmosphere.ProcessingPaused = true; return; diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs index 5c73cf11246..33fa16a6c68 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs @@ -1,6 +1,5 @@ using Content.Server.Atmos.Components; using Content.Shared.Atmos; -using Robust.Shared.Map.Components; namespace Content.Server.Atmos.EntitySystems { @@ -13,8 +12,7 @@ private void Superconduct(GridAtmosphereComponent gridAtmosphere, TileAtmosphere for(var i = 0; i < Atmospherics.Directions; i++) { var direction = (AtmosDirection) (1 << i); - if (!directions.IsFlagSet(direction)) - continue; + if (!directions.IsFlagSet(direction)) continue; var adjacent = tile.AdjacentTiles[direction.ToIndex()]; @@ -94,9 +92,7 @@ public void NeighborConductWithSource(GridAtmosphereComponent gridAtmosphere, Ti { if (tile.Air == null) { - // TODO ATMOS: why does this need to check if a tile exists if it doesn't use the tile? - if (TryComp(other.GridIndex, out var grid) - && _mapSystem.TryGetTileRef(other.GridIndex, grid, other.GridIndices, out var _)) + if (other.Tile != null) { TemperatureShareOpenToSolid(other, tile); } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Utils.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Utils.cs index 9b0d0d9670d..699c2a70aef 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Utils.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Utils.cs @@ -41,6 +41,20 @@ public void InvalidateVisuals(EntityUid gridUid, Vector2i tile, GasTileOverlayCo _gasTileOverlaySystem.Invalidate(gridUid, tile, comp); } + public bool NeedsVacuumFixing(MapGridComponent mapGrid, Vector2i indices) + { + var value = false; + + var enumerator = GetObstructingComponentsEnumerator(mapGrid, indices); + + while (enumerator.MoveNext(out var airtight)) + { + value |= airtight.FixVacuum; + } + + return value; + } + /// /// Gets the volume in liters for a number of tiles, on a specific grid. /// @@ -52,44 +66,34 @@ private float GetVolumeForTiles(MapGridComponent mapGrid, int tiles = 1) return Atmospherics.CellVolume * mapGrid.TileSize * tiles; } - public readonly record struct AirtightData(AtmosDirection BlockedDirections, bool NoAirWhenBlocked, - bool FixVacuum); - - private void UpdateAirtightData(EntityUid uid, GridAtmosphereComponent atmos, MapGridComponent grid, TileAtmosphere tile) + /// + /// Gets all obstructing instances in a specific tile. + /// + /// The grid where to get the tile. + /// The indices of the tile. + /// The enumerator for the airtight components. + public AtmosObstructionEnumerator GetObstructingComponentsEnumerator(MapGridComponent mapGrid, Vector2i tile) { - var oldBlocked = tile.AirtightData.BlockedDirections; - - tile.AirtightData = tile.NoGridTile - ? default - : GetAirtightData(uid, grid, tile.GridIndices); + var ancEnumerator = mapGrid.GetAnchoredEntitiesEnumerator(tile); + var airQuery = GetEntityQuery(); - if (tile.AirtightData.BlockedDirections != oldBlocked && tile.ExcitedGroup != null) - ExcitedGroupDispose(atmos, tile.ExcitedGroup); + var enumerator = new AtmosObstructionEnumerator(ancEnumerator, airQuery); + return enumerator; } - private AirtightData GetAirtightData(EntityUid uid, MapGridComponent grid, Vector2i tile) + private AtmosDirection GetBlockedDirections(MapGridComponent mapGrid, Vector2i indices) { - var blockedDirs = AtmosDirection.Invalid; - var noAirWhenBlocked = false; - var fixVacuum = false; + var value = AtmosDirection.Invalid; - foreach (var ent in _map.GetAnchoredEntities(uid, grid, tile)) - { - if (!_airtightQuery.TryGetComponent(ent, out var airtight)) - continue; - - if(!airtight.AirBlocked) - continue; + var enumerator = GetObstructingComponentsEnumerator(mapGrid, indices); - blockedDirs |= airtight.AirBlockedDirection; - noAirWhenBlocked |= airtight.NoAirWhenFullyAirBlocked; - fixVacuum |= airtight.FixVacuum; - - if (blockedDirs == AtmosDirection.All && noAirWhenBlocked && fixVacuum) - break; + while (enumerator.MoveNext(out var airtight)) + { + if(airtight.AirBlocked) + value |= airtight.AirBlockedDirection; } - return new AirtightData(blockedDirs, noAirWhenBlocked, fixVacuum); + return value; } /// diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs index d2f40e77169..dd2a9675591 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs @@ -4,7 +4,6 @@ using Content.Server.Fluids.EntitySystems; using Content.Server.NodeContainer.EntitySystems; using Content.Shared.Atmos.EntitySystems; -using Content.Shared.Doors.Components; using Content.Shared.Maps; using JetBrains.Annotations; using Robust.Server.GameObjects; @@ -41,9 +40,6 @@ public sealed partial class AtmosphereSystem : SharedAtmosphereSystem private const float ExposedUpdateDelay = 1f; private float _exposedTimer = 0f; - private EntityQuery _atmosQuery; - private EntityQuery _airtightQuery; - private EntityQuery _firelockQuery; private HashSet _entSet = new(); public override void Initialize() @@ -59,9 +55,6 @@ public override void Initialize() InitializeGridAtmosphere(); InitializeMap(); - _atmosQuery = GetEntityQuery(); - _airtightQuery = GetEntityQuery(); - _firelockQuery = GetEntityQuery(); SubscribeLocalEvent(OnTileChanged); diff --git a/Content.Server/Atmos/EntitySystems/AutomaticAtmosSystem.cs b/Content.Server/Atmos/EntitySystems/AutomaticAtmosSystem.cs index 70e3eef3c44..203c747e29e 100644 --- a/Content.Server/Atmos/EntitySystems/AutomaticAtmosSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AutomaticAtmosSystem.cs @@ -27,12 +27,8 @@ private void OnTileChanged(ref TileChangedEvent ev) // Also, these calls are surprisingly slow. // TODO: Make tiledefmanager cache the IsSpace property, and turn this lookup-through-two-interfaces into // TODO: a simple array lookup, as tile IDs are likely contiguous, and there's at most 2^16 possibilities anyway. - - var oldSpace = ev.OldTile.IsSpace(_tileDefinitionManager); - var newSpace = ev.NewTile.IsSpace(_tileDefinitionManager); - - if (!(oldSpace && !newSpace || - !oldSpace && newSpace) || + if (!((ev.OldTile.IsSpace(_tileDefinitionManager) && !ev.NewTile.IsSpace(_tileDefinitionManager)) || + (!ev.OldTile.IsSpace(_tileDefinitionManager) && ev.NewTile.IsSpace(_tileDefinitionManager))) || _atmosphereSystem.HasAtmosphere(ev.Entity)) return; diff --git a/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs b/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs index 552ee142329..6a2c8f0a7e5 100644 --- a/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs +++ b/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs @@ -260,13 +260,13 @@ private GasEntry[] GenerateGasEntryArray(GasMixture? mixture) { var gas = _atmo.GetGas(i); - if (mixture?[i] <= UIMinMoles) + if (mixture?.Moles[i] <= UIMinMoles) continue; if (mixture != null) { var gasName = Loc.GetString(gas.Name); - gases.Add(new GasEntry(gasName, mixture[i], gas.Color)); + gases.Add(new GasEntry(gasName, mixture.Moles[i], gas.Color)); } } diff --git a/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs b/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs index 397f0167a9b..8ae9517379e 100644 --- a/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs +++ b/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs @@ -171,7 +171,7 @@ public GasOverlayData GetOverlayData(GasMixture? mixture) { var id = VisibleGasId[i]; var gas = _atmosphereSystem.GetGas(id); - var moles = mixture?[id] ?? 0f; + var moles = mixture?.Moles[id] ?? 0f; ref var opacity = ref data.Opacity[i]; if (moles < gas.GasMolesVisible) @@ -216,13 +216,13 @@ private bool UpdateChunkTile(GridAtmosphereComponent gridAtmosphere, GasOverlayC oldData = new GasOverlayData(tile.Hotspot.State, oldData.Opacity); } - if (tile is {Air: not null, NoGridTile: false}) + if (tile.Air != null) { for (var i = 0; i < VisibleGasId.Length; i++) { var id = VisibleGasId[i]; var gas = _atmosphereSystem.GetGas(id); - var moles = tile.Air[id]; + var moles = tile.Air.Moles[id]; ref var oldOpacity = ref oldData.Opacity[i]; if (moles < gas.GasMolesVisible) diff --git a/Content.Server/Atmos/GasMixture.cs b/Content.Server/Atmos/GasMixture.cs index 77fd7018333..0a2ef235a71 100644 --- a/Content.Server/Atmos/GasMixture.cs +++ b/Content.Server/Atmos/GasMixture.cs @@ -3,7 +3,6 @@ using System.Runtime.CompilerServices; using Content.Server.Atmos.Reactions; using Content.Shared.Atmos; -using Content.Shared.Atmos.EntitySystems; using Robust.Shared.Serialization; using Robust.Shared.Utility; @@ -18,13 +17,11 @@ public sealed partial class GasMixture : IEquatable, ISerializationH { public static GasMixture SpaceGas => new() {Volume = Atmospherics.CellVolume, Temperature = Atmospherics.TCMB, Immutable = true}; - // No access, to ensure immutable mixtures are never accidentally mutated. - [Access(typeof(SharedAtmosphereSystem), typeof(SharedAtmosDebugOverlaySystem), Other = AccessPermissions.None)] - [DataField] + // This must always have a length that is a multiple of 4 for SIMD acceleration. + [DataField("moles")] + [ViewVariables(VVAccess.ReadWrite)] public float[] Moles = new float[Atmospherics.AdjustedNumberOfGases]; - public float this[int gas] => Moles[gas]; - [DataField("temperature")] [ViewVariables(VVAccess.ReadWrite)] private float _temperature = Atmospherics.TCMB; @@ -83,19 +80,6 @@ public GasMixture(float volume = 0f) Volume = volume; } - public GasMixture(float[] moles, float temp, float volume = Atmospherics.CellVolume) - { - if (moles.Length != Atmospherics.AdjustedNumberOfGases) - throw new InvalidOperationException($"Invalid mole array length"); - - if (volume < 0) - volume = 0; - - _temperature = temp; - Moles = moles; - Volume = volume; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public void MarkImmutable() { @@ -133,16 +117,15 @@ public void SetMoles(Gas gas, float quantity) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AdjustMoles(int gasId, float quantity) { - if (Immutable) - return; - - if (!float.IsFinite(quantity)) - throw new ArgumentException($"Invalid quantity \"{quantity}\" specified!", nameof(quantity)); + if (!Immutable) + { + if (!float.IsFinite(quantity)) + throw new ArgumentException($"Invalid quantity \"{quantity}\" specified!", nameof(quantity)); - // Clamping is needed because x - x can be negative with floating point numbers. If we don't - // clamp here, the caller always has to call GetMoles(), clamp, then SetMoles(). - ref var moles = ref Moles[gasId]; - moles = MathF.Max(moles + quantity, 0); + // Clamping is needed because x - x can be negative with floating point numbers. If we don't + // clamp here, the caller always has to call GetMoles(), clamp, then SetMoles(). + Moles[gasId] = MathF.Max(Moles[gasId] + quantity, 0); + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -180,8 +163,7 @@ public GasMixture RemoveRatio(float ratio) { var moles = Moles[i]; var otherMoles = removed.Moles[i]; - - if ((moles < Atmospherics.GasMinMoles || float.IsNaN(moles)) && !Immutable) + if (moles < Atmospherics.GasMinMoles || float.IsNaN(moles)) Moles[i] = 0; if (otherMoles < Atmospherics.GasMinMoles || float.IsNaN(otherMoles)) @@ -220,9 +202,6 @@ public void Multiply(float multiplier) void ISerializationHooks.AfterDeserialization() { - // ISerializationHooks is obsolete. - // TODO add fixed-length-array serializer - // The arrays MUST have a specific length. Array.Resize(ref Moles, Atmospherics.AdjustedNumberOfGases); } @@ -250,12 +229,8 @@ public override bool Equals(object? obj) public bool Equals(GasMixture? other) { - if (ReferenceEquals(this, other)) - return true; - - if (ReferenceEquals(null, other)) - return false; - + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; return Moles.SequenceEqual(other.Moles) && _temperature.Equals(other._temperature) && ReactionResults.SequenceEqual(other.ReactionResults) @@ -283,13 +258,11 @@ public override int GetHashCode() public GasMixture Clone() { - if (Immutable) - return this; - var newMixture = new GasMixture() { Moles = (float[])Moles.Clone(), _temperature = _temperature, + Immutable = Immutable, Volume = Volume, }; return newMixture; diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs index ad647fad1b8..64d02d793bc 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs @@ -136,7 +136,7 @@ private void OnCanisterChangeReleaseValve(EntityUid uid, GasCanisterComponent ca for (int i = 0; i < containedGasArray.Length; i++) { - containedGasDict.Add((Gas)i, canister.Air[i]); + containedGasDict.Add((Gas)i, canister.Air.Moles[i]); } _adminLogger.Add(LogType.CanisterValve, impact, $"{ToPrettyString(args.Session.AttachedEntity.GetValueOrDefault()):player} set the valve on {ToPrettyString(uid):canister} to {args.Valve:valveState} while it contained [{string.Join(", ", containedGasDict)}]"); diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCondenserSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCondenserSystem.cs index 852542ec6cd..491bf600627 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCondenserSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCondenserSystem.cs @@ -45,7 +45,7 @@ private void OnCondenserUpdated(Entity entity, ref AtmosD var removed = inlet.Air.Remove(molesToConvert); for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++) { - var moles = removed[i]; + var moles = removed.Moles[i]; if (moles <= 0) continue; diff --git a/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs b/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs index 71e4c2d0def..7d385c530a9 100644 --- a/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs +++ b/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs @@ -183,7 +183,13 @@ public void CopyTo(ISerializationManager serializationManager, Dictionary - /// Neighbouring tiles to which air can flow. This is a combination of this tile's unblocked direction, and the - /// unblocked directions on adjacent tiles. - /// [ViewVariables] public AtmosDirection AdjacentBits = AtmosDirection.Invalid; @@ -77,7 +72,10 @@ public sealed class TileAtmosphere : IGasMixtureHolder public EntityUid GridIndex { get; set; } [ViewVariables] - public Vector2i GridIndices; + public TileRef? Tile => GridIndices.GetTileRef(GridIndex); + + [ViewVariables] + public Vector2i GridIndices { get; } [ViewVariables] public ExcitedGroup? ExcitedGroup { get; set; } @@ -94,7 +92,7 @@ public sealed class TileAtmosphere : IGasMixtureHolder public float LastShare; [ViewVariables] - public readonly float[] MolesArchived = new float[Atmospherics.AdjustedNumberOfGases]; + public float[]? MolesArchived; GasMixture IGasMixtureHolder.Air { @@ -105,31 +103,8 @@ GasMixture IGasMixtureHolder.Air [ViewVariables] public float MaxFireTemperatureSustained { get; set; } - /// - /// If true, then this tile is directly exposed to the map's atmosphere, either because the grid has no tile at - /// this position, or because the tile type is not airtight. - /// - [ViewVariables] - public bool MapAtmosphere; - - /// - /// If true, this tile does not actually exist on the grid, it only exists to represent the map's atmosphere for - /// adjacent grid tiles. - /// [ViewVariables] - public bool NoGridTile; - - /// - /// If true, this tile is queued for processing in - /// - [ViewVariables] - public bool TrimQueued; - - /// - /// Cached information about airtight entities on this tile. This gets updated anytime a tile gets invalidated - /// (i.e., gets added to ). - /// - public AtmosphereSystem.AirtightData AirtightData; + public AtmosDirection BlockedAirflow { get; set; } = AtmosDirection.Invalid; public TileAtmosphere(EntityUid gridIndex, Vector2i gridIndices, GasMixture? mixture = null, bool immutable = false, bool space = false) { @@ -137,24 +112,10 @@ public TileAtmosphere(EntityUid gridIndex, Vector2i gridIndices, GasMixture? mix GridIndices = gridIndices; Air = mixture; Space = space; + MolesArchived = Air != null ? new float[Atmospherics.AdjustedNumberOfGases] : null; if(immutable) Air?.MarkImmutable(); } - - public TileAtmosphere(TileAtmosphere other) - { - GridIndex = other.GridIndex; - GridIndices = other.GridIndices; - Space = other.Space; - NoGridTile = other.NoGridTile; - MapAtmosphere = other.MapAtmosphere; - Air = other.Air?.Clone(); - Array.Copy(other.MolesArchived, MolesArchived, MolesArchived.Length); - } - - public TileAtmosphere() - { - } } } diff --git a/Content.Server/Body/Systems/LungSystem.cs b/Content.Server/Body/Systems/LungSystem.cs index 4b60f8814b5..b5bac507391 100644 --- a/Content.Server/Body/Systems/LungSystem.cs +++ b/Content.Server/Body/Systems/LungSystem.cs @@ -77,7 +77,7 @@ public void GasToReagent(EntityUid uid, LungComponent lung) foreach (var gas in Enum.GetValues()) { var i = (int) gas; - var moles = lung.Air[i]; + var moles = lung.Air.Moles[i]; if (moles <= 0) continue; var reagent = _atmosphereSystem.GasReagents[i]; diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs index 6cdb088dbb0..be6e8b78fef 100644 --- a/Content.Server/Chat/Systems/ChatSystem.cs +++ b/Content.Server/Chat/Systems/ChatSystem.cs @@ -7,7 +7,7 @@ using Content.Server.GameTicking; using Content.Server.Speech.Components; using Content.Server.Speech.EntitySystems; -using Content.Server.Psionics.Telepathy; +using Content.Server.Nyanotrasen.Chat; using Content.Server.Speech.Components; using Content.Server.Speech.EntitySystems; using Content.Server.Station.Components; diff --git a/Content.Server/Chemistry/EntitySystems/VaporSystem.cs b/Content.Server/Chemistry/EntitySystems/VaporSystem.cs index 7d3f70bc0d8..d945c1f818b 100644 --- a/Content.Server/Chemistry/EntitySystems/VaporSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/VaporSystem.cs @@ -64,8 +64,8 @@ public void Start(Entity vapor, TransformComponent vaporXform, V // Set Move if (EntityManager.TryGetComponent(vapor, out PhysicsComponent? physics)) { - _physics.SetLinearDamping(vapor, physics, 0f); - _physics.SetAngularDamping(vapor, physics, 0f); + _physics.SetLinearDamping(physics, 0f); + _physics.SetAngularDamping(physics, 0f); _throwing.TryThrow(vapor, dir, speed, user: user); diff --git a/Content.Server/Chemistry/ReagentEffects/ModifyLungGas.cs b/Content.Server/Chemistry/ReagentEffects/ModifyLungGas.cs index e7466fbc85d..e12cab80a91 100644 --- a/Content.Server/Chemistry/ReagentEffects/ModifyLungGas.cs +++ b/Content.Server/Chemistry/ReagentEffects/ModifyLungGas.cs @@ -16,15 +16,12 @@ public sealed partial class ModifyLungGas : ReagentEffect public override void Effect(ReagentEffectArgs args) { - if (!args.EntityManager.TryGetComponent(args.OrganEntity, out var lung)) - return; - - foreach (var (gas, ratio) in _ratios) + if (args.EntityManager.TryGetComponent(args.OrganEntity, out var lung)) { - var quantity = ratio * args.Quantity.Float() / Atmospherics.BreathMolesToReagentMultiplier; - if (quantity < 0) - quantity = Math.Max(quantity, -lung.Air[(int)gas]); - lung.Air.AdjustMoles(gas, quantity); + foreach (var (gas, ratio) in _ratios) + { + lung.Air.Moles[(int) gas] += (ratio * args.Quantity.Float()) / Atmospherics.BreathMolesToReagentMultiplier; + } } } } diff --git a/Content.Server/Construction/Conditions/ComponentInTile.cs b/Content.Server/Construction/Conditions/ComponentInTile.cs index 36705e4c0ee..8ab4046a721 100644 --- a/Content.Server/Construction/Conditions/ComponentInTile.cs +++ b/Content.Server/Construction/Conditions/ComponentInTile.cs @@ -3,7 +3,6 @@ using Content.Shared.Maps; using JetBrains.Annotations; using Robust.Shared.Map; -using Robust.Shared.Map.Components; using Robust.Shared.Utility; namespace Content.Server.Construction.Conditions @@ -49,15 +48,7 @@ public bool Condition(EntityUid uid, IEntityManager entityManager) var indices = transform.Coordinates.ToVector2i(entityManager, IoCManager.Resolve()); var lookup = entityManager.EntitySysManager.GetEntitySystem(); - - - if (!entityManager.TryGetComponent(transform.GridUid.Value, out var grid)) - return !HasEntity; - - if (!entityManager.System().TryGetTileRef(transform.GridUid.Value, grid, indices, out var tile)) - return !HasEntity; - - var entities = tile.GetEntitiesInTile(LookupFlags.Approximate | LookupFlags.Static, lookup); + var entities = indices.GetEntitiesInTile(transform.GridUid.Value, LookupFlags.Approximate | LookupFlags.Static, lookup); foreach (var ent in entities) { diff --git a/Content.Server/DeltaV/StationEvents/Events/GlimmerMobSpawnRule.cs b/Content.Server/DeltaV/StationEvents/Events/GlimmerMobSpawnRule.cs index 22d96a54146..ec9ec770313 100644 --- a/Content.Server/DeltaV/StationEvents/Events/GlimmerMobSpawnRule.cs +++ b/Content.Server/DeltaV/StationEvents/Events/GlimmerMobSpawnRule.cs @@ -5,7 +5,7 @@ using Content.Server.Psionics.Glimmer; using Content.Server.StationEvents.Components; using Content.Shared.Psionics.Glimmer; -using Content.Shared.Psionics.Abilities; +using Content.Shared.Abilities.Psionics; namespace Content.Server.StationEvents.Events; diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs index 4a9477e7443..31451c425f5 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs @@ -475,7 +475,7 @@ public void DamageFloorTile(TileRef tileRef, if (_tileDefinitionManager[tileRef.Tile.TypeId] is not ContentTileDefinition tileDef) return; - if (tileDef.MapAtmosphere) + if (tileDef.IsSpace) canCreateVacuum = true; // is already a vacuum. int tileBreakages = 0; @@ -491,7 +491,7 @@ public void DamageFloorTile(TileRef tileRef, if (_tileDefinitionManager[tileDef.BaseTurf] is not ContentTileDefinition newDef) break; - if (newDef.MapAtmosphere && !canCreateVacuum) + if (newDef.IsSpace && !canCreateVacuum) break; tileDef = newDef; diff --git a/Content.Server/ImmovableRod/ImmovableRodSystem.cs b/Content.Server/ImmovableRod/ImmovableRodSystem.cs index 31aa39cf03a..0fa8f7d292f 100644 --- a/Content.Server/ImmovableRod/ImmovableRodSystem.cs +++ b/Content.Server/ImmovableRod/ImmovableRodSystem.cs @@ -53,9 +53,9 @@ private void OnMapInit(EntityUid uid, ImmovableRodComponent component, MapInitEv { if (EntityManager.TryGetComponent(uid, out PhysicsComponent? phys)) { - _physics.SetLinearDamping(uid, phys, 0f); - _physics.SetFriction(uid, phys, 0f); - _physics.SetBodyStatus(uid, phys, BodyStatus.InAir); + _physics.SetLinearDamping(phys, 0f); + _physics.SetFriction(phys, 0f); + _physics.SetBodyStatus(phys, BodyStatus.InAir); if (!component.RandomizeVelocity) return; diff --git a/Content.Server/Psionics/Abilities/DispelPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/DispelPowerSystem.cs similarity index 83% rename from Content.Server/Psionics/Abilities/DispelPowerSystem.cs rename to Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/DispelPowerSystem.cs index cb7ef8313cd..d338a5a5bcb 100644 --- a/Content.Server/Psionics/Abilities/DispelPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/DispelPowerSystem.cs @@ -1,20 +1,24 @@ using Content.Shared.Actions; using Content.Shared.StatusEffect; -using Content.Shared.Psionics.Abilities; +using Content.Shared.Abilities.Psionics; using Content.Shared.Damage; using Content.Shared.Revenant.Components; using Content.Server.Guardian; using Content.Server.Bible.Components; using Content.Server.Popups; +using Robust.Shared.Prototypes; using Robust.Shared.Player; using Robust.Shared.Random; +using Robust.Shared.Timing; +using Content.Shared.Mind; using Content.Shared.Actions.Events; using Robust.Shared.Audio.Systems; -namespace Content.Server.Psionics.Abilities +namespace Content.Server.Abilities.Psionics { public sealed class DispelPowerSystem : EntitySystem { + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly StatusEffectsSystem _statusEffects = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly DamageableSystem _damageableSystem = default!; @@ -23,6 +27,8 @@ public sealed class DispelPowerSystem : EntitySystem [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly SharedMindSystem _mindSystem = default!; public override void Initialize() @@ -46,13 +52,10 @@ private void OnInit(EntityUid uid, DispelPowerComponent component, ComponentInit _actions.TryGetActionData( component.DispelActionEntity, out var actionData ); if (actionData is { UseDelay: not null }) _actions.StartUseDelay(component.DispelActionEntity); - if (TryComp(uid, out var psionic)) + if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) { + psionic.PsionicAbility = component.DispelActionEntity; psionic.ActivePowers.Add(component); - psionic.PsychicFeedback.Add(component.DispelFeedback); - //It's fully intended that Dispel doesn't increase Amplification, and instead heavily spikes Dampening - //Antimage archetype. - psionic.Dampening += 1f; } } @@ -63,16 +66,12 @@ private void OnShutdown(EntityUid uid, DispelPowerComponent component, Component if (TryComp(uid, out var psionic)) { psionic.ActivePowers.Remove(component); - psionic.PsychicFeedback.Remove(component.DispelFeedback); - psionic.Dampening -= 1f; } } private void OnPowerUsed(DispelPowerActionEvent args) { - if (HasComp(args.Target) || HasComp(args.Performer)) - return; - if (!TryComp(args.Performer, out var psionic) || !HasComp(args.Target)) + if (HasComp(args.Target)) return; var ev = new DispelledEvent(); @@ -81,9 +80,7 @@ private void OnPowerUsed(DispelPowerActionEvent args) if (ev.Handled) { args.Handled = true; - _psionics.LogPowerUsed(args.Performer, "dispel", - (int) MathF.Round(-2 * psionic.Dampening + psionic.Amplification), - (int) MathF.Round(-4 * psionic.Dampening + psionic.Amplification)); + _psionics.LogPowerUsed(args.Performer, "dispel"); } } @@ -99,7 +96,7 @@ private void OnDispelled(EntityUid uid, DispellableComponent component, Dispelle private void OnDmgDispelled(EntityUid uid, DamageOnDispelComponent component, DispelledEvent args) { var damage = component.Damage; - var modifier = 1 + component.Variance - _random.NextFloat(0, component.Variance * 2); + var modifier = (1 + component.Variance) - (_random.NextFloat(0, component.Variance * 2)); damage *= modifier; DealDispelDamage(uid, damage); @@ -148,3 +145,5 @@ public void DealDispelDamage(EntityUid uid, DamageSpecifier? damage = null) } public sealed class DispelledEvent : HandledEntityEventArgs {} } + + diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs new file mode 100644 index 00000000000..b775117b716 --- /dev/null +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs @@ -0,0 +1,74 @@ +using Content.Shared.Actions; +using Content.Shared.Abilities.Psionics; +using Content.Shared.StatusEffect; +using Content.Shared.Popups; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; +using Content.Shared.Mind; +using Content.Shared.Actions.Events; + +namespace Content.Server.Abilities.Psionics +{ + public sealed class MetapsionicPowerSystem : EntitySystem + { + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly StatusEffectsSystem _statusEffects = default!; + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly EntityLookupSystem _lookup = default!; + [Dependency] private readonly SharedPopupSystem _popups = default!; + [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly SharedMindSystem _mindSystem = default!; + + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnPowerUsed); + } + + private void OnInit(EntityUid uid, MetapsionicPowerComponent component, ComponentInit args) + { + _actions.AddAction(uid, ref component.MetapsionicActionEntity, component.MetapsionicActionId ); + _actions.TryGetActionData( component.MetapsionicActionEntity, out var actionData ); + if (actionData is { UseDelay: not null }) + _actions.StartUseDelay(component.MetapsionicActionEntity); + if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) + { + psionic.PsionicAbility = component.MetapsionicActionEntity; + psionic.ActivePowers.Add(component); + } + + } + + private void OnShutdown(EntityUid uid, MetapsionicPowerComponent component, ComponentShutdown args) + { + _actions.RemoveAction(uid, component.MetapsionicActionEntity); + + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Remove(component); + } + } + + private void OnPowerUsed(EntityUid uid, MetapsionicPowerComponent component, MetapsionicPowerActionEvent args) + { + foreach (var entity in _lookup.GetEntitiesInRange(uid, component.Range)) + { + if (HasComp(entity) && entity != uid && !HasComp(entity) && + !(HasComp(entity) && Transform(entity).ParentUid == uid)) + { + _popups.PopupEntity(Loc.GetString("metapsionic-pulse-success"), uid, uid, PopupType.LargeCaution); + args.Handled = true; + return; + } + } + _popups.PopupEntity(Loc.GetString("metapsionic-pulse-failure"), uid, uid, PopupType.Large); + _psionics.LogPowerUsed(uid, "metapsionic pulse", 2, 4); + + args.Handled = true; + } + } +} diff --git a/Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwapPowerSystem.cs similarity index 78% rename from Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs rename to Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwapPowerSystem.cs index 1e50a586b4f..b23224cab48 100644 --- a/Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwapPowerSystem.cs @@ -1,6 +1,5 @@ using Content.Shared.Actions; -using Content.Shared.Psionics.Abilities; -using Content.Shared.Psionics; +using Content.Shared.Abilities.Psionics; using Content.Shared.Speech; using Content.Shared.Stealth.Components; using Content.Shared.Mobs.Components; @@ -11,15 +10,19 @@ using Content.Server.Popups; using Content.Server.Psionics; using Content.Server.GameTicking; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; using Content.Shared.Mind; using Content.Shared.Actions.Events; -namespace Content.Server.Psionics.Abilities +namespace Content.Server.Abilities.Psionics { public sealed class MindSwapPowerSystem : EntitySystem { + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly MobStateSystem _mobStateSystem = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly MindSystem _mindSystem = default!; @@ -35,22 +38,20 @@ public override void Initialize() SubscribeLocalEvent(OnDispelled); SubscribeLocalEvent(OnMobStateChanged); SubscribeLocalEvent(OnGhostAttempt); + // SubscribeLocalEvent(OnSwapInit); - SubscribeLocalEvent(OnSwapShutdown); - SubscribeLocalEvent(OnInsulated); } private void OnInit(EntityUid uid, MindSwapPowerComponent component, ComponentInit args) { - _actions.AddAction(uid, ref component.MindSwapActionEntity, component.MindSwapActionId); - _actions.TryGetActionData( component.MindSwapActionEntity, out var actionData); + _actions.AddAction(uid, ref component.MindSwapActionEntity, component.MindSwapActionId ); + _actions.TryGetActionData( component.MindSwapActionEntity, out var actionData ); if (actionData is { UseDelay: not null }) _actions.StartUseDelay(component.MindSwapActionEntity); - if (TryComp(uid, out var psionic)) + if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) { + psionic.PsionicAbility = component.MindSwapActionEntity; psionic.ActivePowers.Add(component); - psionic.PsychicFeedback.Add(component.MindSwapFeedback); - psionic.Amplification += 1f; } } @@ -60,26 +61,20 @@ private void OnShutdown(EntityUid uid, MindSwapPowerComponent component, Compone if (TryComp(uid, out var psionic)) { psionic.ActivePowers.Remove(component); - psionic.PsychicFeedback.Remove(component.MindSwapFeedback); - psionic.Amplification -= 1f; } } private void OnPowerUsed(MindSwapPowerActionEvent args) { - if (!(TryComp(args.Target, out var damageable) && damageable.DamageContainerID == "Biological")) return; if (HasComp(args.Target)) return; - if (!TryComp(args.Performer, out var psionic)) - return; - Swap(args.Performer, args.Target); - _psionics.LogPowerUsed(args.Performer, "mind swap", (int) MathF.Round(psionic.Amplification / psionic.Dampening * 8), (int) MathF.Round(psionic.Amplification / psionic.Dampening * 12)); + _psionics.LogPowerUsed(args.Performer, "mind swap"); args.Handled = true; } @@ -130,8 +125,8 @@ private void OnDispelled(EntityUid uid, MindSwappedComponent component, Dispelle private void OnMobStateChanged(EntityUid uid, MindSwappedComponent component, MobStateChangedEvent args) { - if (args.NewMobState == MobState.Dead || args.NewMobState == MobState.Critical) - Swap(uid, component.OriginalEntity, true); + if (args.NewMobState == MobState.Dead) + RemComp(uid); } private void OnGhostAttempt(GhostAttemptHandleEvent args) @@ -156,21 +151,8 @@ private void OnSwapInit(EntityUid uid, MindSwappedComponent component, Component _actions.TryGetActionData( component.MindSwapReturnActionEntity, out var actionData ); if (actionData is { UseDelay: not null }) _actions.StartUseDelay(component.MindSwapReturnActionEntity); - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Add(component); - psionic.PsychicFeedback.Add(component.MindSwappedFeedback); - } - } - - private void OnSwapShutdown(EntityUid uid, MindSwappedComponent component, ComponentShutdown args) - { - _actions.RemoveAction(uid, component.MindSwapReturnActionEntity); - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Remove(component); - psionic.PsychicFeedback.Remove(component.MindSwappedFeedback); - } + if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) + psionic.PsionicAbility = component.MindSwapReturnActionEntity; } public void Swap(EntityUid performer, EntityUid target, bool end = false) @@ -183,13 +165,11 @@ public void Swap(EntityUid performer, EntityUid target, bool end = false) MindComponent? targetMind = null; // This is here to prevent missing MindContainerComponent Resolve errors. - if (!_mindSystem.TryGetMind(performer, out var performerMindId, out performerMind)) - { + if(!_mindSystem.TryGetMind(performer, out var performerMindId, out performerMind)){ performerMind = null; }; - if (!_mindSystem.TryGetMind(target, out var targetMindId, out targetMind)) - { + if(!_mindSystem.TryGetMind(target, out var targetMindId, out targetMind)){ targetMind = null; }; //This is a terrible way to 'unattach' minds. I wanted to use UnVisit but in TransferTo's code they say @@ -222,7 +202,7 @@ public void Swap(EntityUid performer, EntityUid target, bool end = false) perfComp.OriginalEntity = target; targetComp.OriginalEntity = performer; } - //It shouldn't actually be possible anymore to get trapped under most circumstances, but for niche edge cases, I am leaving this here + public void GetTrapped(EntityUid uid) { @@ -240,9 +220,5 @@ public void GetTrapped(EntityUid uid) _metaDataSystem.SetEntityDescription(uid, Loc.GetString("telegnostic-trapped-entity-desc")); } } - public void OnInsulated(EntityUid uid, MindSwappedComponent component, PsionicInsulationEvent args) - { - Swap(uid, component.OriginalEntity, true); - } } } diff --git a/Content.Server/Psionics/Abilities/MindSwappedComponent.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwappedComponent.cs similarity index 79% rename from Content.Server/Psionics/Abilities/MindSwappedComponent.cs rename to Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwappedComponent.cs index 82c0313bca6..72cd6a66ef9 100644 --- a/Content.Server/Psionics/Abilities/MindSwappedComponent.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwappedComponent.cs @@ -1,7 +1,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Server.Psionics.Abilities +namespace Content.Server.Abilities.Psionics { [RegisterComponent] public sealed partial class MindSwappedComponent : Component @@ -14,8 +14,5 @@ public sealed partial class MindSwappedComponent : Component [DataField("mindSwapReturnActionEntity")] public EntityUid? MindSwapReturnActionEntity; - - [DataField("mindSwappedFeedback")] - public string MindSwappedFeedback = "mindswapped-feedback"; } } diff --git a/Content.Server/Psionics/Abilities/NoosphericZapPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs similarity index 54% rename from Content.Server/Psionics/Abilities/NoosphericZapPowerSystem.cs rename to Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs index c935bc0123d..0fd261ef12f 100644 --- a/Content.Server/Psionics/Abilities/NoosphericZapPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs @@ -1,21 +1,26 @@ using Content.Shared.Actions; -using Content.Shared.Psionics.Abilities; +using Content.Shared.Abilities.Psionics; +using Content.Server.Psionics; using Content.Shared.StatusEffect; -using Content.Server.Electrocution; using Content.Server.Stunnable; using Content.Server.Beam; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; +using Content.Server.Mind; using Content.Shared.Actions.Events; -namespace Content.Server.Psionics.Abilities +namespace Content.Server.Abilities.Psionics { public sealed class NoosphericZapPowerSystem : EntitySystem { + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly StunSystem _stunSystem = default!; [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly BeamSystem _beam = default!; - [Dependency] private readonly ElectrocutionSystem _electrocution = default!; + [Dependency] private readonly MindSystem _mindSystem = default!; public override void Initialize() @@ -32,11 +37,10 @@ private void OnInit(EntityUid uid, NoosphericZapPowerComponent component, Compon _actions.TryGetActionData( component.NoosphericZapActionEntity, out var actionData ); if (actionData is { UseDelay: not null }) _actions.StartUseDelay(component.NoosphericZapActionEntity); - if (TryComp(uid, out var psionic)) + if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) { + psionic.PsionicAbility = component.NoosphericZapActionEntity; psionic.ActivePowers.Add(component); - psionic.PsychicFeedback.Add(component.NoosphericZapFeedback); - psionic.Amplification += 1f; } } @@ -46,34 +50,24 @@ private void OnShutdown(EntityUid uid, NoosphericZapPowerComponent component, Co if (TryComp(uid, out var psionic)) { psionic.ActivePowers.Remove(component); - psionic.PsychicFeedback.Remove(component.NoosphericZapFeedback); - psionic.Amplification -= 1f; } } private void OnPowerUsed(NoosphericZapPowerActionEvent args) { - if (!TryComp(args.Performer, out var psionic)) + if (!HasComp(args.Target)) return; - if (!HasComp(args.Target) && !HasComp(args.Performer)) - { - _beam.TryCreateBeam(args.Performer, args.Target, "LightningNoospheric"); - _stunSystem.TryParalyze(args.Target, TimeSpan.FromSeconds(1 * psionic.Amplification), false); + if (HasComp(args.Target)) + return; - _electrocution.TryDoElectrocution(args.Target, null, - (int) MathF.Round(5f * psionic.Amplification), - new TimeSpan((long) MathF.Round(1f * psionic.Amplification)), - true, - ignoreInsulation: true); + _beam.TryCreateBeam(args.Performer, args.Target, "LightningNoospheric"); - _statusEffectsSystem.TryAddStatusEffect(args.Target, "Stutter", TimeSpan.FromSeconds(2 * psionic.Amplification), false, "StutteringAccent"); + _stunSystem.TryParalyze(args.Target, TimeSpan.FromSeconds(5), false); + _statusEffectsSystem.TryAddStatusEffect(args.Target, "Stutter", TimeSpan.FromSeconds(10), false, "StutteringAccent"); - _psionics.LogPowerUsed(args.Performer, "noopsheric zap", - (int) MathF.Round(6 * psionic.Amplification - psionic.Dampening), - (int) MathF.Round(8 * psionic.Amplification - psionic.Dampening)); - args.Handled = true; - } + _psionics.LogPowerUsed(args.Performer, "noospheric zap"); + args.Handled = true; } } } diff --git a/Content.Server/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs similarity index 57% rename from Content.Server/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs rename to Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs index 0c50efb5cf3..5ca1dc7a6dc 100644 --- a/Content.Server/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs @@ -1,31 +1,31 @@ -using Content.Server.DoAfter; using Content.Shared.Actions; -using Content.Shared.Psionics.Abilities; +using Content.Shared.CombatMode.Pacification; +using Content.Shared.Abilities.Psionics; using Content.Shared.Damage; -using Content.Shared.DoAfter; using Content.Shared.Stunnable; using Content.Shared.Stealth; using Content.Shared.Stealth.Components; -using Content.Shared.Psionics.Events; +using Content.Server.Psionics; +using Robust.Shared.Prototypes; +using Robust.Shared.Player; +using Robust.Shared.Audio; +using Robust.Shared.Timing; +using Content.Server.Mind; using Content.Shared.Actions.Events; using Robust.Shared.Audio.Systems; -using Content.Shared.Interaction.Events; -using Content.Shared.Weapons.Ranged.Events; -using Content.Shared.Throwing; -using Robust.Shared.Timing; -using Content.Shared.Psionics; -namespace Content.Server.Psionics.Abilities +namespace Content.Server.Abilities.Psionics { public sealed class PsionicInvisibilityPowerSystem : EntitySystem { + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly SharedStunSystem _stunSystem = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly SharedStealthSystem _stealth = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly MindSystem _mindSystem = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; public override void Initialize() { @@ -37,61 +37,43 @@ public override void Initialize() SubscribeLocalEvent(OnStart); SubscribeLocalEvent(OnEnd); SubscribeLocalEvent(OnDamageChanged); - SubscribeLocalEvent(OnAttackAttempt); - SubscribeLocalEvent(OnShootAttempt); - SubscribeLocalEvent(OnThrowAttempt); - SubscribeLocalEvent(OnInsulated); } private void OnInit(EntityUid uid, PsionicInvisibilityPowerComponent component, ComponentInit args) { - _actions.AddAction(uid, ref component.PsionicInvisibilityActionEntity, component.PsionicInvisibilityActionId); - _actions.TryGetActionData( component.PsionicInvisibilityActionEntity, out var actionData); + _actions.AddAction(uid, ref component.PsionicInvisibilityActionEntity, component.PsionicInvisibilityActionId ); + _actions.TryGetActionData( component.PsionicInvisibilityActionEntity, out var actionData ); if (actionData is { UseDelay: not null }) _actions.StartUseDelay(component.PsionicInvisibilityActionEntity); - if (TryComp(uid, out var psionic)) + if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) { + psionic.PsionicAbility = component.PsionicInvisibilityActionEntity; psionic.ActivePowers.Add(component); - psionic.PsychicFeedback.Add(component.InvisibilityFeedback); - psionic.Amplification += 0.5f; } } private void OnShutdown(EntityUid uid, PsionicInvisibilityPowerComponent component, ComponentShutdown args) { - RemComp(uid); - RemComp(uid); _actions.RemoveAction(uid, component.PsionicInvisibilityActionEntity); if (TryComp(uid, out var psionic)) { psionic.ActivePowers.Remove(component); - psionic.PsychicFeedback.Remove(component.InvisibilityFeedback); - psionic.Amplification -= 0.5f; } } private void OnPowerUsed(EntityUid uid, PsionicInvisibilityPowerComponent component, PsionicInvisibilityPowerActionEvent args) { - if (!TryComp(uid, out var psionic)) - return; - - if (HasComp(uid)) + if (HasComp(uid)) return; - var ev = new PsionicInvisibilityTimerEvent(_gameTiming.CurTime); - var doAfterArgs = new DoAfterArgs(EntityManager, uid, component.UseTimer, ev, uid) { Hidden = true }; - _doAfterSystem.TryStartDoAfter(doAfterArgs); - ToggleInvisibility(args.Performer); var action = Spawn(PsionicInvisibilityUsedComponent.PsionicInvisibilityUsedActionPrototype); _actions.AddAction(uid, action, action); - _actions.TryGetActionData(action, out var actionData); + _actions.TryGetActionData( action, out var actionData ); if (actionData is { UseDelay: not null }) _actions.StartUseDelay(action); - _psionics.LogPowerUsed(uid, "psionic invisibility", - (int) MathF.Round(8 * psionic.Amplification - 2 * psionic.Dampening), - (int) MathF.Round(12 * psionic.Amplification - 2 * psionic.Dampening)); + _psionics.LogPowerUsed(uid, "psionic invisibility"); args.Handled = true; } @@ -107,6 +89,7 @@ private void OnPowerOff(RemovePsionicInvisibilityOffPowerActionEvent args) private void OnStart(EntityUid uid, PsionicInvisibilityUsedComponent component, ComponentInit args) { EnsureComp(uid); + EnsureComp(uid); var stealth = EnsureComp(uid); _stealth.SetVisibility(uid, 0.66f, stealth); _audio.PlayPvs("/Audio/Effects/toss.ogg", uid); @@ -119,37 +102,24 @@ private void OnEnd(EntityUid uid, PsionicInvisibilityUsedComponent component, Co return; RemComp(uid); + RemComp(uid); RemComp(uid); _audio.PlayPvs("/Audio/Effects/toss.ogg", uid); + //Pretty sure this DOESN'T work as intended. _actions.RemoveAction(uid, component.PsionicInvisibilityUsedActionEntity); - DirtyEntity(uid); - } - private void OnAttackAttempt(EntityUid uid, PsionicInvisibilityUsedComponent component, AttackAttemptEvent args) - { - RemComp(uid); - } - - private void OnShootAttempt(EntityUid uid, PsionicInvisibilityUsedComponent component, ShotAttemptedEvent args) - { - RemComp(uid); + _stunSystem.TryParalyze(uid, TimeSpan.FromSeconds(8), false); + DirtyEntity(uid); } - private void OnThrowAttempt(EntityUid uid, PsionicInvisibilityUsedComponent component, ThrowAttemptEvent args) - { - RemComp(uid); - } private void OnDamageChanged(EntityUid uid, PsionicInvisibilityUsedComponent component, DamageChangedEvent args) { - if (!TryComp(uid, out var psionic)) - return; - if (!args.DamageIncreased) return; ToggleInvisibility(uid); - _stunSystem.TryParalyze(uid, TimeSpan.FromSeconds(4f / psionic.Dampening + psionic.Amplification), false); } + public void ToggleInvisibility(EntityUid uid) { if (!HasComp(uid)) @@ -160,19 +130,5 @@ public void ToggleInvisibility(EntityUid uid) RemComp(uid); } } - - public void OnDoAfter(EntityUid uid, PsionicInvisibilityPowerComponent component, PsionicInvisibilityTimerEvent args) - { - RemComp(uid); - } - - private void OnInsulated(EntityUid uid, PsionicInvisibilityUsedComponent component, PsionicInsulationEvent args) - { - if (!TryComp(uid, out var psionic)) - return; - - RemComp(uid); - _stunSystem.TryParalyze(uid, TimeSpan.FromSeconds(4f / psionic.Dampening + psionic.Amplification), false); - } } } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs new file mode 100644 index 00000000000..2eca3173b6d --- /dev/null +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs @@ -0,0 +1,128 @@ +using Robust.Shared.Audio; +using Robust.Server.GameObjects; +using Robust.Shared.Player; +using Robust.Shared.Prototypes; +using Content.Server.Body.Components; +using Content.Server.Body.Systems; +using Content.Server.Chemistry.Containers.EntitySystems; +using Content.Server.Chemistry.EntitySystems; +using Content.Server.DoAfter; +using Content.Shared.Abilities.Psionics; +using Content.Shared.Actions; +using Content.Shared.Chemistry.Components; +using Content.Shared.DoAfter; +using Content.Shared.FixedPoint; +using Content.Shared.Popups; +using Content.Shared.Psionics.Events; +using Content.Shared.Tag; +using Content.Shared.Examine; +using static Content.Shared.Examine.ExamineSystemShared; +using Robust.Shared.Timing; +using Content.Server.Mind; +using Content.Shared.Actions.Events; +using Content.Shared.Chemistry.EntitySystems; +using Robust.Server.Audio; + +namespace Content.Server.Abilities.Psionics +{ + public sealed class PsionicRegenerationPowerSystem : EntitySystem + { + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!; + [Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!; + [Dependency] private readonly AudioSystem _audioSystem = default!; + [Dependency] private readonly TagSystem _tagSystem = default!; + [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly MindSystem _mindSystem = default!; + + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnPowerUsed); + + SubscribeLocalEvent(OnDispelled); + SubscribeLocalEvent(OnDoAfter); + } + + private void OnInit(EntityUid uid, PsionicRegenerationPowerComponent component, ComponentInit args) + { + _actions.AddAction(uid, ref component.PsionicRegenerationActionEntity, component.PsionicRegenerationActionId ); + _actions.TryGetActionData( component.PsionicRegenerationActionEntity, out var actionData ); + if (actionData is { UseDelay: not null }) + _actions.StartUseDelay(component.PsionicRegenerationActionEntity); + if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) + { + psionic.PsionicAbility = component.PsionicRegenerationActionEntity; + psionic.ActivePowers.Add(component); + } + } + + private void OnPowerUsed(EntityUid uid, PsionicRegenerationPowerComponent component, PsionicRegenerationPowerActionEvent args) + { + var ev = new PsionicRegenerationDoAfterEvent(_gameTiming.CurTime); + var doAfterArgs = new DoAfterArgs(EntityManager, uid, component.UseDelay, ev, uid); + + _doAfterSystem.TryStartDoAfter(doAfterArgs, out var doAfterId); + + component.DoAfter = doAfterId; + + _popupSystem.PopupEntity(Loc.GetString("psionic-regeneration-begin", ("entity", uid)), + uid, + // TODO: Use LoS-based Filter when one is available. + Filter.Pvs(uid).RemoveWhereAttachedEntity(entity => !ExamineSystemShared.InRangeUnOccluded(uid, entity, ExamineRange, null)), + true, + PopupType.Medium); + + _audioSystem.PlayPvs(component.SoundUse, component.Owner, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); + _psionics.LogPowerUsed(uid, "psionic regeneration"); + args.Handled = true; + } + + private void OnShutdown(EntityUid uid, PsionicRegenerationPowerComponent component, ComponentShutdown args) + { + _actions.RemoveAction(uid, component.PsionicRegenerationActionEntity); + + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Remove(component); + } + } + + private void OnDispelled(EntityUid uid, PsionicRegenerationPowerComponent component, DispelledEvent args) + { + if (component.DoAfter == null) + return; + + _doAfterSystem.Cancel(component.DoAfter); + component.DoAfter = null; + + args.Handled = true; + } + + private void OnDoAfter(EntityUid uid, PsionicRegenerationPowerComponent component, PsionicRegenerationDoAfterEvent args) + { + component.DoAfter = null; + + if (!TryComp(uid, out var stream)) + return; + + // DoAfter has no way to run a callback during the process to give + // small doses of the reagent, so we wait until either the action + // is cancelled (by being dispelled) or complete to give the + // appropriate dose. A timestamp delta is used to accomplish this. + var percentageComplete = Math.Min(1f, (_gameTiming.CurTime - args.StartedAt).TotalSeconds / component.UseDelay); + + var solution = new Solution(); + solution.AddReagent("PsionicRegenerationEssence", FixedPoint2.New(component.EssenceAmount * percentageComplete)); + _bloodstreamSystem.TryAddToChemicals(uid, solution, stream); + } + } +} + diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs new file mode 100644 index 00000000000..407b72c6b58 --- /dev/null +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs @@ -0,0 +1,66 @@ +using Content.Shared.Actions; +using Content.Shared.Abilities.Psionics; +using Content.Server.Atmos.Components; +using Content.Server.Atmos.EntitySystems; +using Content.Server.Popups; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; +using Content.Server.Mind; +using Content.Shared.Actions.Events; + +namespace Content.Server.Abilities.Psionics +{ + public sealed class PyrokinesisPowerSystem : EntitySystem + { + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly FlammableSystem _flammableSystem = default!; + [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; + [Dependency] private readonly PopupSystem _popupSystem = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly MindSystem _mindSystem = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnPowerUsed); + } + + private void OnInit(EntityUid uid, PyrokinesisPowerComponent component, ComponentInit args) + { + _actions.AddAction(uid, ref component.PyrokinesisActionEntity, component.PyrokinesisActionId ); + _actions.TryGetActionData( component.PyrokinesisActionEntity, out var actionData ); + if (actionData is { UseDelay: not null }) + _actions.StartUseDelay(component.PyrokinesisActionEntity); + if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) + { + psionic.PsionicAbility = component.PyrokinesisActionEntity; + psionic.ActivePowers.Add(component); + } + } + + private void OnShutdown(EntityUid uid, PyrokinesisPowerComponent component, ComponentShutdown args) + { + _actions.RemoveAction(uid, component.PyrokinesisActionEntity); + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Remove(component); + } + } + + private void OnPowerUsed(PyrokinesisPowerActionEvent args) + { + if (!TryComp(args.Target, out var flammableComponent)) + return; + + flammableComponent.FireStacks += 5; + _flammableSystem.Ignite(args.Target, args.Target); + _popupSystem.PopupEntity(Loc.GetString("pyrokinesis-power-used", ("target", args.Target)), args.Target, Shared.Popups.PopupType.LargeCaution); + + _psionics.LogPowerUsed(args.Performer, "pyrokinesis"); + args.Handled = true; + } + } +} diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs new file mode 100644 index 00000000000..f7ae04b61ea --- /dev/null +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs @@ -0,0 +1,67 @@ +using Content.Shared.Actions; +using Content.Shared.StatusEffect; +using Content.Shared.Abilities.Psionics; +using Content.Shared.Mind.Components; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; +using Content.Server.Mind; +using Content.Shared.Actions.Events; + +namespace Content.Server.Abilities.Psionics +{ + public sealed class TelegnosisPowerSystem : EntitySystem + { + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly StatusEffectsSystem _statusEffects = default!; + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly MindSwapPowerSystem _mindSwap = default!; + [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly MindSystem _mindSystem = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnPowerUsed); + SubscribeLocalEvent(OnMindRemoved); + } + + private void OnInit(EntityUid uid, TelegnosisPowerComponent component, ComponentInit args) + { + _actions.AddAction(uid, ref component.TelegnosisActionEntity, component.TelegnosisActionId ); + _actions.TryGetActionData( component.TelegnosisActionEntity, out var actionData ); + if (actionData is { UseDelay: not null }) + _actions.StartUseDelay(component.TelegnosisActionEntity); + if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) + { + psionic.PsionicAbility = component.TelegnosisActionEntity; + psionic.ActivePowers.Add(component); + } + } + + private void OnShutdown(EntityUid uid, TelegnosisPowerComponent component, ComponentShutdown args) + { + _actions.RemoveAction(uid, component.TelegnosisActionEntity); + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Remove(component); + } + } + + private void OnPowerUsed(EntityUid uid, TelegnosisPowerComponent component, TelegnosisPowerActionEvent args) + { + var projection = Spawn(component.Prototype, Transform(uid).Coordinates); + Transform(projection).AttachToGridOrMap(); + _mindSwap.Swap(uid, projection); + + _psionics.LogPowerUsed(uid, "telegnosis"); + args.Handled = true; + } + private void OnMindRemoved(EntityUid uid, TelegnosticProjectionComponent component, MindRemovedMessage args) + { + QueueDel(uid); + } + } +} diff --git a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/PsionicAbilitiesSystem.cs similarity index 54% rename from Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs rename to Content.Server/Nyanotrasen/Abilities/Psionics/PsionicAbilitiesSystem.cs index 915abd12224..ee16aaccfb6 100644 --- a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/PsionicAbilitiesSystem.cs @@ -1,41 +1,77 @@ -using Content.Shared.Psionics.Abilities; +using Content.Shared.Abilities.Psionics; using Content.Shared.Actions; using Content.Shared.Psionics.Glimmer; using Content.Shared.Random; using Content.Shared.Random.Helpers; +using Content.Server.EUI; +using Content.Server.Psionics; +using Content.Server.Mind; +using Content.Shared.Mind; +using Content.Shared.Mind.Components; using Content.Shared.StatusEffect; using Robust.Shared.Random; using Robust.Shared.Prototypes; +using Robust.Server.GameObjects; +using Robust.Server.Player; using Robust.Shared.Player; -using Content.Shared.Examine; -using Content.Shared.Popups; -using static Content.Shared.Examine.ExamineSystemShared; -namespace Content.Server.Psionics.Abilities +namespace Content.Server.Abilities.Psionics { public sealed class PsionicAbilitiesSystem : EntitySystem { [Dependency] private readonly IComponentFactory _componentFactory = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; + [Dependency] private readonly IPlayerManager _playerManager = default!; + [Dependency] private readonly EuiManager _euiManager = default!; [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; [Dependency] private readonly GlimmerSystem _glimmerSystem = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly SharedPopupSystem _popups = default!; + [Dependency] private readonly MindSystem _mindSystem = default!; public override void Initialize() { base.Initialize(); + SubscribeLocalEvent(OnPlayerAttached); } - /// - /// Adds a psychic power once a character rolls one. This used to be a system you have to select for. However the opt-in is no longer the text window, but is now done at character creation. - /// TODO: This is going to get removed when I reach Part 3 of my reworks, when I touch upon the GlimmerSystem itself and overhaul how players get powers. - /// - /// - /// - /// - public void AddPsionics(EntityUid uid) + private void OnPlayerAttached(EntityUid uid, PsionicAwaitingPlayerComponent component, PlayerAttachedEvent args) + { + if (TryComp(uid, out var bonus) && bonus.Warn == true) + _euiManager.OpenEui(new AcceptPsionicsEui(uid, this), args.Player); + else + AddRandomPsionicPower(uid); + RemCompDeferred(uid); + } + + public void AddPsionics(EntityUid uid, bool warn = true) + { + if (Deleted(uid)) + return; + + if (HasComp(uid)) + return; + + //Don't know if this will work. New mind state vs old. + if (!TryComp(uid, out var mindContainer) || + !_mindSystem.TryGetMind(uid, out _, out var mind )) + //|| + //!_mindSystem.TryGetMind(uid, out var mind, mindContainer)) + { + EnsureComp(uid); + return; + } + + if (!_mindSystem.TryGetSession(mind, out var client)) + return; + + if (warn && TryComp(uid, out var actor)) + _euiManager.OpenEui(new AcceptPsionicsEui(uid, this), client); + else + AddRandomPsionicPower(uid); + } + + public void AddPsionics(EntityUid uid, string powerComp) { if (Deleted(uid)) return; @@ -43,11 +79,17 @@ public void AddPsionics(EntityUid uid) if (HasComp(uid)) return; - AddRandomPsionicPower(uid); + AddComp(uid); + + var newComponent = (Component) _componentFactory.GetComponent(powerComp); + newComponent.Owner = uid; + + EntityManager.AddComponent(uid, newComponent); } + public void AddRandomPsionicPower(EntityUid uid) { - EnsureComp(uid, out var psionic); + AddComp(uid); if (!_prototypeManager.TryIndex("RandomPsionicPowerPool", out var pool)) { @@ -61,21 +103,11 @@ public void AddRandomPsionicPower(EntityUid uid) EntityManager.AddComponent(uid, newComponent); - _glimmerSystem.Glimmer += _random.Next((int) MathF.Round(psionic.Amplification * psionic.Dampening * 1), (int) MathF.Round(psionic.Amplification * psionic.Dampening * 5)); + _glimmerSystem.Glimmer += _random.Next(1, 5); } public void RemovePsionics(EntityUid uid) { - if (RemComp(uid)) - { - _popups.PopupEntity(Loc.GetString("mindbreaking-feedback", ("entity", uid)), - uid, - // TODO: Use LoS-based Filter when one is available. - Filter.Pvs(uid).RemoveWhereAttachedEntity(entity => !ExamineSystemShared.InRangeUnOccluded(uid, entity, ExamineRange, null)), - true, - PopupType.Medium); - } - if (!TryComp(uid, out var psionic)) return; @@ -98,15 +130,14 @@ public void RemovePsionics(EntityUid uid) if (psionic.PsionicAbility != null){ _actionsSystem.TryGetActionData( psionic.PsionicAbility, out var psiAbility ); if (psiAbility != null){ + var owner = psiAbility.Owner; _actionsSystem.RemoveAction(uid, psiAbility.Owner); } } _statusEffectsSystem.TryAddStatusEffect(uid, "Stutter", TimeSpan.FromMinutes(5), false, "StutteringAccent"); - _glimmerSystem.Glimmer += _random.Next((int) MathF.Round(psionic.Amplification * psionic.Dampening * -10), (int) MathF.Round(psionic.Amplification * psionic.Dampening * -5)); RemComp(uid); - RemComp(uid); } } } diff --git a/Content.Server/Psionics/Audio/GlimmerSoundComponent.cs b/Content.Server/Nyanotrasen/Audio/GlimmerSoundComponent.cs similarity index 80% rename from Content.Server/Psionics/Audio/GlimmerSoundComponent.cs rename to Content.Server/Nyanotrasen/Audio/GlimmerSoundComponent.cs index 9a6c62381be..850be3e831c 100644 --- a/Content.Server/Psionics/Audio/GlimmerSoundComponent.cs +++ b/Content.Server/Nyanotrasen/Audio/GlimmerSoundComponent.cs @@ -2,8 +2,12 @@ using Content.Shared.Audio; using Content.Shared.Psionics.Glimmer; using Robust.Shared.Audio; +using Robust.Shared.ComponentTrees; +using Robust.Shared.GameStates; +using Robust.Shared.Physics; +using Robust.Shared.Serialization; -namespace Content.Server.Psionics.Audio +namespace Content.Server.Audio { [RegisterComponent] [Access(typeof(SharedAmbientSoundSystem), typeof(GlimmerReactiveSystem))] diff --git a/Content.Server/Psionics/Telepathy/TelepathyChatSystem.cs b/Content.Server/Nyanotrasen/Chat/NyanoChatSystem.cs similarity index 85% rename from Content.Server/Psionics/Telepathy/TelepathyChatSystem.cs rename to Content.Server/Nyanotrasen/Chat/NyanoChatSystem.cs index ad49075e65a..58ed1782741 100644 --- a/Content.Server/Psionics/Telepathy/TelepathyChatSystem.cs +++ b/Content.Server/Nyanotrasen/Chat/NyanoChatSystem.cs @@ -2,7 +2,7 @@ using Content.Server.Administration.Managers; using Content.Server.Chat.Managers; using Content.Server.Chat.Systems; -using Content.Shared.Psionics.Abilities; +using Content.Shared.Abilities.Psionics; using Content.Shared.Bed.Sleep; using Content.Shared.Chat; using Content.Shared.Database; @@ -16,10 +16,10 @@ using System.Linq; using System.Text; -namespace Content.Server.Psionics.Telepathy +namespace Content.Server.Nyanotrasen.Chat { /// - /// Extensions for Telepathic Chat + /// Extensions for nyano's chat stuff /// public sealed class NyanoChatSystem : EntitySystem @@ -47,9 +47,7 @@ private IEnumerable GetAdminClients() private List GetDreamers(IEnumerable removeList) { var filtered = Filter.Empty() - .AddWhereAttachedEntity(entity => HasComp(entity) - || HasComp(entity) && !HasComp(entity) && !HasComp(entity) - || HasComp(entity) && !HasComp(entity) && !HasComp(entity)) + .AddWhereAttachedEntity(entity => HasComp(entity) || HasComp(entity) && !HasComp(entity) && !HasComp(entity)) .Recipients .Select(p => p.ConnectedClient); @@ -63,7 +61,7 @@ private List GetDreamers(IEnumerable removeList) private bool IsEligibleForTelepathy(EntityUid entity) { - return TryComp(entity, out var psionic) && psionic.Telepath + return HasComp(entity) && !HasComp(entity) && !HasComp(entity) && (!TryComp(entity, out var mobstate) || mobstate.CurrentState == MobState.Alive); @@ -94,9 +92,9 @@ public void SendTelepathicChat(EntityUid source, string message, bool hideChat) if (_random.Prob(0.1f)) _glimmerSystem.Glimmer++; - if (_random.Prob(Math.Min(0.33f + (float) _glimmerSystem.Glimmer / 1500, 1))) + if (_random.Prob(Math.Min(0.33f + ((float) _glimmerSystem.Glimmer / 1500), 1))) { - float obfuscation = 0.25f + (float) _glimmerSystem.Glimmer / 2000; + float obfuscation = (0.25f + (float) _glimmerSystem.Glimmer / 2000); var obfuscated = ObfuscateMessageReadability(message, obfuscation); _chatManager.ChatMessageToMany(ChatChannel.Telepathic, obfuscated, messageWrap, source, hideChat, false, GetDreamers(clients), Color.PaleVioletRed); } @@ -113,7 +111,7 @@ private string ObfuscateMessageReadability(string message, float chance) for (var i = 0; i < message.Length; i++) { - if (char.IsWhiteSpace(modifiedMessage[i])) + if (char.IsWhiteSpace((modifiedMessage[i]))) { continue; } diff --git a/Content.Server/Psionics/Telepathy/TSayCommand.cs b/Content.Server/Nyanotrasen/Chat/TSayCommand.cs similarity index 95% rename from Content.Server/Psionics/Telepathy/TSayCommand.cs rename to Content.Server/Nyanotrasen/Chat/TSayCommand.cs index 8fbaa5e17b2..9ba27b65d71 100644 --- a/Content.Server/Psionics/Telepathy/TSayCommand.cs +++ b/Content.Server/Nyanotrasen/Chat/TSayCommand.cs @@ -1,10 +1,11 @@ using Content.Server.Chat.Systems; using Content.Shared.Administration; +using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Enums; using Robust.Shared.Player; -namespace Content.Server.Psionics.Telepathy +namespace Content.Server.Chat.Commands { [AnyCommand] internal sealed class TSayCommand : IConsoleCommand diff --git a/Content.Server/Psionics/Telepathy/TelepathicRepeaterComponent.cs b/Content.Server/Nyanotrasen/Chat/TelepathicRepeaterComponent.cs similarity index 82% rename from Content.Server/Psionics/Telepathy/TelepathicRepeaterComponent.cs rename to Content.Server/Nyanotrasen/Chat/TelepathicRepeaterComponent.cs index 6e194f76c8f..fc199f4332a 100644 --- a/Content.Server/Psionics/Telepathy/TelepathicRepeaterComponent.cs +++ b/Content.Server/Nyanotrasen/Chat/TelepathicRepeaterComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Server.Psionics.Telepathy +namespace Content.Server.Nyanotrasen.Chat { /// /// Repeats whatever is happening in telepathic chat. diff --git a/Content.Server/Nyanotrasen/Chemistry/Effects/ChemRemovePsionic.cs b/Content.Server/Nyanotrasen/Chemistry/Effects/ChemRemovePsionic.cs index 0ce3f9d7c64..a23a5b3d77d 100644 --- a/Content.Server/Nyanotrasen/Chemistry/Effects/ChemRemovePsionic.cs +++ b/Content.Server/Nyanotrasen/Chemistry/Effects/ChemRemovePsionic.cs @@ -1,5 +1,5 @@ using Content.Shared.Chemistry.Reagent; -using Content.Server.Psionics.Abilities; +using Content.Server.Abilities.Psionics; using JetBrains.Annotations; using Robust.Shared.Prototypes; diff --git a/Content.Server/Nyanotrasen/Objectives/Components/BecomePsionicConditionComponent.cs b/Content.Server/Nyanotrasen/Objectives/Components/BecomePsionicConditionComponent.cs new file mode 100644 index 00000000000..3b677bab2d4 --- /dev/null +++ b/Content.Server/Nyanotrasen/Objectives/Components/BecomePsionicConditionComponent.cs @@ -0,0 +1,11 @@ +using Content.Server.Objectives.Systems; + +namespace Content.Server.Objectives.Components; + +/// +/// Requires that the player dies to be complete. +/// +[RegisterComponent, Access(typeof(BecomePsionicConditionSystem))] +public sealed partial class BecomePsionicConditionComponent : Component +{ +} \ No newline at end of file diff --git a/Content.Server/Nyanotrasen/Objectives/Systems/BecomePsionicConditionSystem.cs b/Content.Server/Nyanotrasen/Objectives/Systems/BecomePsionicConditionSystem.cs new file mode 100644 index 00000000000..d090c320a41 --- /dev/null +++ b/Content.Server/Nyanotrasen/Objectives/Systems/BecomePsionicConditionSystem.cs @@ -0,0 +1,32 @@ +using Content.Shared.Abilities.Psionics; +using Content.Server.Objectives.Components; +using Content.Shared.Mind; +using Content.Shared.Objectives.Components; + +namespace Content.Server.Objectives.Systems +{ + public sealed class BecomePsionicConditionSystem : EntitySystem + { + private EntityQuery _metaQuery; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnGetProgress); + } + + private void OnGetProgress(EntityUid uid, BecomePsionicConditionComponent comp, ref ObjectiveGetProgressEvent args) + { + args.Progress = GetProgress(args.Mind); + } + + private float GetProgress(MindComponent mind) + { + var entMan = IoCManager.Resolve(); + if (HasComp(mind.CurrentEntity)) + return 1; + return 0; + } + } +} diff --git a/Content.Server/Psionics/AcceptPsionicsEui.cs b/Content.Server/Nyanotrasen/Psionics/AcceptPsionicsEui.cs similarity index 95% rename from Content.Server/Psionics/AcceptPsionicsEui.cs rename to Content.Server/Nyanotrasen/Psionics/AcceptPsionicsEui.cs index 7c652664c64..80fd8946f28 100644 --- a/Content.Server/Psionics/AcceptPsionicsEui.cs +++ b/Content.Server/Nyanotrasen/Psionics/AcceptPsionicsEui.cs @@ -1,7 +1,7 @@ using Content.Shared.Psionics; using Content.Shared.Eui; using Content.Server.EUI; -using Content.Server.Psionics.Abilities; +using Content.Server.Abilities.Psionics; namespace Content.Server.Psionics { diff --git a/Content.Server/Psionics/AntiPsychicWeaponComponent.cs b/Content.Server/Nyanotrasen/Psionics/AntiPsychicWeaponComponent.cs similarity index 100% rename from Content.Server/Psionics/AntiPsychicWeaponComponent.cs rename to Content.Server/Nyanotrasen/Psionics/AntiPsychicWeaponComponent.cs diff --git a/Content.Server/Psionics/Dreams/DreamSystem.cs b/Content.Server/Nyanotrasen/Psionics/Dreams/DreamSystem.cs similarity index 93% rename from Content.Server/Psionics/Dreams/DreamSystem.cs rename to Content.Server/Nyanotrasen/Psionics/Dreams/DreamSystem.cs index 1731c7a9bf5..d6067717c94 100644 --- a/Content.Server/Psionics/Dreams/DreamSystem.cs +++ b/Content.Server/Nyanotrasen/Psionics/Dreams/DreamSystem.cs @@ -1,14 +1,17 @@ using Content.Shared.Dataset; using Content.Shared.Bed.Sleep; +using Content.Server.Chat.Systems; using Content.Server.Chat.Managers; using Robust.Shared.Random; using Robust.Shared.Prototypes; +using Robust.Server.GameObjects; using Robust.Shared.Player; namespace Content.Server.Psionics.Dreams { public sealed class DreamsSystem : EntitySystem { + [Dependency] private readonly ChatSystem _chat = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IChatManager _chatManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; diff --git a/Content.Server/Psionics/Glimmer/GlimmerCommands.cs b/Content.Server/Nyanotrasen/Psionics/Glimmer/GlimmerCommands.cs similarity index 100% rename from Content.Server/Psionics/Glimmer/GlimmerCommands.cs rename to Content.Server/Nyanotrasen/Psionics/Glimmer/GlimmerCommands.cs diff --git a/Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs b/Content.Server/Nyanotrasen/Psionics/Glimmer/GlimmerReactiveSystem.cs similarity index 99% rename from Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs rename to Content.Server/Nyanotrasen/Psionics/Glimmer/GlimmerReactiveSystem.cs index c0802c8b670..da3b07d6dab 100644 --- a/Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs +++ b/Content.Server/Nyanotrasen/Psionics/Glimmer/GlimmerReactiveSystem.cs @@ -1,12 +1,14 @@ -using Content.Server.Psionics.Audio; +using Content.Server.Audio; using Content.Server.Power.Components; using Content.Server.Electrocution; using Content.Server.Lightning; using Content.Server.Explosion.EntitySystems; +using Content.Server.Construction; using Content.Server.Ghost; using Content.Server.Revenant.EntitySystems; using Content.Shared.Audio; using Content.Shared.Construction.EntitySystems; +using Content.Shared.Coordinates.Helpers; using Content.Shared.GameTicking; using Content.Shared.Psionics.Glimmer; using Content.Shared.Verbs; @@ -14,6 +16,7 @@ using Content.Shared.Damage; using Content.Shared.Destructible; using Content.Shared.Construction.Components; +using Content.Shared.Mind; using Content.Shared.Mind.Components; using Content.Shared.Weapons.Melee.Components; using Robust.Shared.Audio; diff --git a/Content.Server/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs b/Content.Server/Nyanotrasen/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs similarity index 94% rename from Content.Server/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs rename to Content.Server/Nyanotrasen/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs index 57c74398b08..f0da85ce453 100644 --- a/Content.Server/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs +++ b/Content.Server/Nyanotrasen/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs @@ -4,6 +4,7 @@ using Content.Shared.CCVar; using Content.Shared.Psionics.Glimmer; using Content.Shared.GameTicking; +using Content.Server.CartridgeLoader.Cartridges; namespace Content.Server.Psionics.Glimmer { @@ -16,6 +17,7 @@ public sealed class PassiveGlimmerReductionSystem : EntitySystem [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; + [Dependency] private readonly GlimmerMonitorCartridgeSystem _cartridgeSys = default!; /// List of glimmer values spaced by minute. public List GlimmerValues = new(); diff --git a/Content.Server/Psionics/Glimmer/Structures/GlimmerSourceComponent.cs b/Content.Server/Nyanotrasen/Psionics/Glimmer/Structures/GlimmerSourceComponent.cs similarity index 100% rename from Content.Server/Psionics/Glimmer/Structures/GlimmerSourceComponent.cs rename to Content.Server/Nyanotrasen/Psionics/Glimmer/Structures/GlimmerSourceComponent.cs diff --git a/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs b/Content.Server/Nyanotrasen/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs similarity index 100% rename from Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs rename to Content.Server/Nyanotrasen/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs diff --git a/Content.Server/Psionics/Invisibility/PsionicInvisibilitySystem.cs b/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibilitySystem.cs similarity index 88% rename from Content.Server/Psionics/Invisibility/PsionicInvisibilitySystem.cs rename to Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibilitySystem.cs index 9583f45fdc9..31e6b89f13d 100644 --- a/Content.Server/Psionics/Invisibility/PsionicInvisibilitySystem.cs +++ b/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibilitySystem.cs @@ -1,6 +1,5 @@ -using Content.Shared.Psionics.Abilities; -using Content.Shared.Psionics; -using Content.Server.Psionics.Abilities; +using Content.Shared.Abilities.Psionics; +using Content.Server.Abilities.Psionics; using Content.Shared.Eye; using Content.Server.NPC.Systems; using Robust.Shared.Containers; @@ -21,6 +20,7 @@ public override void Initialize() SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnInsulInit); SubscribeLocalEvent(OnInsulShutdown); + SubscribeLocalEvent(OnEyeInit); /// Layer SubscribeLocalEvent(OnInvisInit); @@ -36,16 +36,10 @@ private void OnInit(EntityUid uid, PotentialPsionicComponent component, Componen SetCanSeePsionicInvisiblity(uid, false); } - /// - /// Being able to see invisible by default is no longer tracked by "Not having Potential Psionic". - /// Anything intended to be immune to invisibility(and mind magic in general) should instead have PsionicInsulation as a built-in component - /// - /// - /// - /// private void OnInsulInit(EntityUid uid, PsionicInsulationComponent component, ComponentInit args) { - RaiseLocalEvent(uid, new PsionicInsulationEvent()); + if (!HasComp(uid)) + return; if (HasComp(uid)) _invisSystem.ToggleInvisibility(uid); @@ -67,6 +61,9 @@ private void OnInsulInit(EntityUid uid, PsionicInsulationComponent component, Co private void OnInsulShutdown(EntityUid uid, PsionicInsulationComponent component, ComponentShutdown args) { + if (!HasComp(uid)) + return; + SetCanSeePsionicInvisiblity(uid, false); if (!HasComp(uid)) @@ -102,6 +99,10 @@ private void OnInvisShutdown(EntityUid uid, PsionicallyInvisibleComponent compon } } + private void OnEyeInit(EntityUid uid, EyeComponent component, ComponentInit args) + { + //SetCanSeePsionicInvisiblity(uid, true); //JJ Comment - Not allowed to modifies .yml on spawn any longer. See UninitializedSaveTest. + } private void OnEntInserted(EntityUid uid, PsionicallyInvisibleComponent component, EntInsertedIntoContainerMessage args) { DirtyEntity(args.Entity); @@ -124,7 +125,7 @@ public void SetCanSeePsionicInvisiblity(EntityUid uid, bool set) { if (EntityManager.TryGetComponent(uid, out EyeComponent? eye)) { - _eye.SetVisibilityMask(uid, eye.VisibilityMask & ~(int) VisibilityFlags.PsionicInvisibility, eye); + _eye.SetVisibilityMask(uid, eye.VisibilityMask & ~ (int) VisibilityFlags.PsionicInvisibility, eye); } } } diff --git a/Content.Server/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs b/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs similarity index 95% rename from Content.Server/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs rename to Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs index 268deddf6d9..859ceb7b83a 100644 --- a/Content.Server/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs +++ b/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs @@ -1,4 +1,5 @@ using Content.Shared.Whitelist; +using Robust.Shared.Timing; namespace Content.Server.Psionics { diff --git a/Content.Server/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs b/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs similarity index 95% rename from Content.Server/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs rename to Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs index 403e0592617..cec755e3260 100644 --- a/Content.Server/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs +++ b/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs @@ -2,6 +2,7 @@ using Content.Shared.Stealth.Components; using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Systems; +using Robust.Shared.Timing; namespace Content.Server.Psionics { @@ -11,6 +12,7 @@ namespace Content.Server.Psionics public sealed class PsionicInvisibleContactsSystem : EntitySystem { [Dependency] private readonly SharedStealthSystem _stealth = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; public override void Initialize() { diff --git a/Content.Server/Psionics/Invisibility/PsionicallyInvisibleComponent.cs b/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicallyInvisibleComponent.cs similarity index 100% rename from Content.Server/Psionics/Invisibility/PsionicallyInvisibleComponent.cs rename to Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicallyInvisibleComponent.cs diff --git a/Content.Server/Nyanotrasen/Psionics/PotentialPsionicComponent.cs b/Content.Server/Nyanotrasen/Psionics/PotentialPsionicComponent.cs new file mode 100644 index 00000000000..9499497cd1d --- /dev/null +++ b/Content.Server/Nyanotrasen/Psionics/PotentialPsionicComponent.cs @@ -0,0 +1,14 @@ +namespace Content.Server.Psionics +{ + [RegisterComponent] + public sealed partial class PotentialPsionicComponent : Component + { + [DataField("chance")] + public float Chance = 0.04f; + + /// + /// YORO (you only reroll once) + /// + public bool Rerolled = false; + } +} diff --git a/Content.Server/Psionics/PsionicAwaitingPlayerComponent.cs b/Content.Server/Nyanotrasen/Psionics/PsionicAwaitingPlayerComponent.cs similarity index 100% rename from Content.Server/Psionics/PsionicAwaitingPlayerComponent.cs rename to Content.Server/Nyanotrasen/Psionics/PsionicAwaitingPlayerComponent.cs diff --git a/Content.Server/Psionics/PsionicBonusChanceComponent.cs b/Content.Server/Nyanotrasen/Psionics/PsionicBonusChanceComponent.cs similarity index 100% rename from Content.Server/Psionics/PsionicBonusChanceComponent.cs rename to Content.Server/Nyanotrasen/Psionics/PsionicBonusChanceComponent.cs diff --git a/Content.Server/Psionics/PsionicsCommands.cs b/Content.Server/Nyanotrasen/Psionics/PsionicsCommands.cs similarity index 84% rename from Content.Server/Psionics/PsionicsCommands.cs rename to Content.Server/Nyanotrasen/Psionics/PsionicsCommands.cs index 3f9ee794b38..959251d1fb7 100644 --- a/Content.Server/Psionics/PsionicsCommands.cs +++ b/Content.Server/Nyanotrasen/Psionics/PsionicsCommands.cs @@ -1,8 +1,9 @@ using Content.Server.Administration; using Content.Shared.Administration; -using Content.Shared.Psionics.Abilities; +using Content.Shared.Abilities.Psionics; using Content.Shared.Mobs.Components; using Robust.Shared.Console; +using Robust.Server.GameObjects; using Content.Shared.Actions; using Robust.Shared.Player; @@ -18,8 +19,7 @@ public async void Execute(IConsoleShell shell, string argStr, string[] args) { SharedActionsSystem actions = default!; var entMan = IoCManager.Resolve(); - foreach (var (actor, psionic, meta) in entMan.EntityQuery()) - { + foreach (var (actor, mob, psionic, meta) in entMan.EntityQuery()){ // filter out xenos, etc, with innate telepathy actions.TryGetActionData( psionic.PsionicAbility, out var actionData ); if (actionData == null || actionData.ToString() == null) diff --git a/Content.Server/Psionics/PsionicsSystem.cs b/Content.Server/Nyanotrasen/Psionics/PsionicsSystem.cs similarity index 91% rename from Content.Server/Psionics/PsionicsSystem.cs rename to Content.Server/Nyanotrasen/Psionics/PsionicsSystem.cs index bf829477609..5a96af2e96b 100644 --- a/Content.Server/Psionics/PsionicsSystem.cs +++ b/Content.Server/Nyanotrasen/Psionics/PsionicsSystem.cs @@ -1,14 +1,19 @@ -using Content.Shared.Psionics.Abilities; +using Content.Shared.Abilities.Psionics; using Content.Shared.StatusEffect; +using Content.Shared.Mobs; using Content.Shared.Psionics.Glimmer; using Content.Shared.Weapons.Melee.Events; using Content.Shared.Damage.Events; +using Content.Shared.IdentityManagement; using Content.Shared.CCVar; -using Content.Server.Psionics.Abilities; +using Content.Server.Abilities.Psionics; +using Content.Server.Chat.Systems; using Content.Server.Electrocution; using Content.Server.NPC.Components; using Content.Server.NPC.Systems; +using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; +using Robust.Shared.Player; using Robust.Shared.Configuration; using Robust.Shared.Random; @@ -22,6 +27,7 @@ public sealed class PsionicsSystem : EntitySystem [Dependency] private readonly ElectrocutionSystem _electrocutionSystem = default!; [Dependency] private readonly MindSwapPowerSystem _mindSwapPowerSystem = default!; [Dependency] private readonly GlimmerSystem _glimmerSystem = default!; + [Dependency] private readonly ChatSystem _chat = default!; [Dependency] private readonly NpcFactionSystem _npcFactonSystem = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; @@ -48,7 +54,6 @@ public override void Initialize() SubscribeLocalEvent(OnStamHit); SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnRemove); } @@ -82,11 +87,7 @@ private void OnMeleeHit(EntityUid uid, AntiPsionicWeaponComponent component, Mel _electrocutionSystem.TryDoElectrocution(args.User, null, 20, TimeSpan.FromSeconds(5), false); } } - private void OnStartup(EntityUid uid, PsionicComponent component, MapInitEvent args) - { - component.Amplification = _random.NextFloat(0.3f, 1.1f); - component.Dampening = _random.NextFloat(0.3f, 1.1f); - } + private void OnInit(EntityUid uid, PsionicComponent component, ComponentInit args) { if (!component.Removable) @@ -103,7 +104,7 @@ private void OnInit(EntityUid uid, PsionicComponent component, ComponentInit arg private void OnRemove(EntityUid uid, PsionicComponent component, ComponentRemove args) { - if (!HasComp(uid)) + if (!TryComp(uid, out var factions)) return; _npcFactonSystem.RemoveFaction(uid, "PsionicInterloper"); @@ -143,14 +144,14 @@ public void RollPsionics(EntityUid uid, PotentialPsionicComponent component, boo } if (applyGlimmer) - chance += (float) _glimmerSystem.Glimmer / 1000; + chance += ((float) _glimmerSystem.Glimmer / 1000); chance *= multiplier; chance = Math.Clamp(chance, 0, 1); if (_random.Prob(chance)) - _psionicAbilitiesSystem.AddPsionics(uid); + _psionicAbilitiesSystem.AddPsionics(uid, warn); } public void RerollPsionics(EntityUid uid, PotentialPsionicComponent? psionic = null, float bonusMuliplier = 1f) diff --git a/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs b/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs index 24459d29e22..148598fe2c3 100644 --- a/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs +++ b/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs @@ -5,7 +5,7 @@ using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Fluids.EntitySystems; using Content.Server.Psionics; -using Content.Shared.Psionics.Abilities; +using Content.Shared.Abilities.Psionics; using Content.Shared.Chat; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.EntitySystems; diff --git a/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs b/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs index b8cdcb56d47..bc3c22cc350 100644 --- a/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs +++ b/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs @@ -1,4 +1,4 @@ -using Content.Server.Psionics.Abilities; +using Content.Server.Abilities.Psionics; using Content.Server.Chat.Systems; using Content.Server.Radio.Components; using Content.Server.Radio.EntitySystems; diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/GlimmerWispSpawnRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/GlimmerWispSpawnRule.cs index 89b5a176f24..66eea988aeb 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/GlimmerWispSpawnRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/GlimmerWispSpawnRule.cs @@ -5,7 +5,7 @@ using Content.Server.Psionics.Glimmer; using Content.Server.StationEvents.Components; using Content.Shared.Psionics.Glimmer; -using Content.Shared.Psionics.Abilities; +using Content.Shared.Abilities.Psionics; namespace Content.Server.StationEvents.Events; diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/MassMindSwapRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/MassMindSwapRule.cs index 89f3bc97501..63944563269 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/MassMindSwapRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/MassMindSwapRule.cs @@ -1,9 +1,10 @@ +using Robust.Server.GameObjects; using Robust.Shared.Random; -using Content.Server.Psionics.Abilities; +using Content.Server.Abilities.Psionics; using Content.Server.GameTicking.Rules.Components; using Content.Server.Psionics; using Content.Server.StationEvents.Components; -using Content.Shared.Psionics.Abilities; +using Content.Shared.Abilities.Psionics; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Robust.Shared.Player; diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericFryRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericFryRule.cs index 6a2c1c3ba7d..c04543d2195 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericFryRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericFryRule.cs @@ -10,7 +10,7 @@ using Content.Server.Power.EntitySystems; using Content.Server.Psionics.Glimmer; using Content.Server.StationEvents.Components; -using Content.Shared.Psionics.Abilities; +using Content.Shared.Abilities.Psionics; using Content.Shared.Damage; using Content.Shared.Inventory; using Content.Shared.Mobs.Components; diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericStormRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericStormRule.cs index 8812ed1fe37..175318e15bd 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericStormRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericStormRule.cs @@ -1,9 +1,9 @@ using Robust.Shared.Random; -using Content.Server.Psionics.Abilities; +using Content.Server.Abilities.Psionics; using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; using Content.Server.Psionics; -using Content.Shared.Psionics.Abilities; +using Content.Shared.Abilities.Psionics; using Content.Shared.Mobs.Systems; using Content.Shared.Psionics.Glimmer; using Content.Shared.Zombies; diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericZapRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericZapRule.cs index 3672d317d9e..82c3d72b139 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericZapRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericZapRule.cs @@ -3,7 +3,7 @@ using Content.Server.Psionics; using Content.Server.StationEvents.Components; using Content.Server.Stunnable; -using Content.Shared.Psionics.Abilities; +using Content.Shared.Abilities.Psionics; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Content.Shared.StatusEffect; diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/PsionicCatGotYourTongueRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/PsionicCatGotYourTongueRule.cs index 753b2e25729..63e0a435cb0 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/PsionicCatGotYourTongueRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/PsionicCatGotYourTongueRule.cs @@ -4,7 +4,7 @@ using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; using Content.Shared.Mobs.Components; -using Content.Shared.Psionics.Abilities; +using Content.Shared.Abilities.Psionics; using Content.Shared.StatusEffect; using Content.Shared.Mobs.Systems; using Robust.Shared.Audio.Systems; diff --git a/Content.Server/Parallax/BiomeSystem.cs b/Content.Server/Parallax/BiomeSystem.cs index 83cf9b9cb2d..c4c2300870d 100644 --- a/Content.Server/Parallax/BiomeSystem.cs +++ b/Content.Server/Parallax/BiomeSystem.cs @@ -1001,13 +1001,20 @@ public void EnsurePlanet(EntityUid mapUid, BiomeTemplatePrototype biomeTemplate, light.AmbientLightColor = Color.FromHex("#D8B059"); Dirty(mapUid, light, metadata); + // Atmos + var atmos = EnsureComp(mapUid); + var moles = new float[Atmospherics.AdjustedNumberOfGases]; moles[(int) Gas.Oxygen] = 21.824779f; moles[(int) Gas.Nitrogen] = 82.10312f; - var mixture = new GasMixture(moles, Atmospherics.T20C); + var mixture = new GasMixture(2500) + { + Temperature = 293.15f, + Moles = moles, + }; - _atmos.SetMapAtmosphere(mapUid, false, mixture); + _atmos.SetMapAtmosphere(mapUid, false, mixture, atmos); } /// diff --git a/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.Emitter.cs b/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.Emitter.cs index 06f1b6b154c..46b25163cc0 100644 --- a/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.Emitter.cs +++ b/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.Emitter.cs @@ -28,7 +28,7 @@ private void FireEmitter(EntityUid uid, ParticleAcceleratorPowerState strength, if (TryComp(emitted, out var particlePhys)) { var angle = _transformSystem.GetWorldRotation(uid, xformQuery); - _physicsSystem.SetBodyStatus(emitted, particlePhys, BodyStatus.InAir); + _physicsSystem.SetBodyStatus(particlePhys, BodyStatus.InAir); var velocity = angle.ToWorldVec() * 20f; if (TryComp(uid, out var phys)) diff --git a/Content.Server/Physics/Controllers/ChasingWalkSystem.cs b/Content.Server/Physics/Controllers/ChasingWalkSystem.cs index 618dd4156fc..215e7e3124e 100644 --- a/Content.Server/Physics/Controllers/ChasingWalkSystem.cs +++ b/Content.Server/Physics/Controllers/ChasingWalkSystem.cs @@ -97,6 +97,6 @@ private void ForceImpulse(EntityUid uid, ChasingWalkComponent component) var speed = delta.Length() > 0 ? delta.Normalized() * component.Speed : Vector2.Zero; _physics.SetLinearVelocity(uid, speed); - _physics.SetBodyStatus(uid, physics, BodyStatus.InAir); //If this is not done, from the explosion up close, the tesla will "Fall" to the ground, and almost stop moving. + _physics.SetBodyStatus(physics, BodyStatus.InAir); //If this is not done, from the explosion up close, the tesla will "Fall" to the ground, and almost stop moving. } } diff --git a/Content.Server/Power/Generator/GasPowerReceiverSystem.cs b/Content.Server/Power/Generator/GasPowerReceiverSystem.cs index 76cf90c3693..c61599edfc9 100644 --- a/Content.Server/Power/Generator/GasPowerReceiverSystem.cs +++ b/Content.Server/Power/Generator/GasPowerReceiverSystem.cs @@ -37,7 +37,7 @@ private void OnDeviceUpdated(EntityUid uid, GasPowerReceiverComponent component, if (pipe.Air.Temperature <= component.MaxTemperature) { // we have enough gas, so we consume it and are powered - if (pipe.Air[(int) component.TargetGas] > component.MolesConsumedSec * timeDelta) + if (pipe.Air.Moles[(int) component.TargetGas] > component.MolesConsumedSec * timeDelta) { pipe.Air.AdjustMoles(component.TargetGas, -component.MolesConsumedSec * timeDelta); SetPowered(uid, component, true); diff --git a/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs b/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs deleted file mode 100644 index 7b3a417c53f..00000000000 --- a/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs +++ /dev/null @@ -1,188 +0,0 @@ -using Content.Shared.Actions; -using Content.Shared.Actions.Events; -using Content.Shared.Psionics.Abilities; -using Content.Shared.DoAfter; -using Content.Shared.Examine; -using static Content.Shared.Examine.ExamineSystemShared; -using Content.Shared.Popups; -using Robust.Server.Audio; -using Robust.Shared.Audio; -using Robust.Shared.Timing; -using Robust.Shared.Player; -using Content.Server.DoAfter; -using Content.Shared.Psionics.Events; -using Content.Server.Psionics; - -namespace Content.Server.Psionics.Abilities -{ - public sealed class MetapsionicPowerSystem : EntitySystem - { - [Dependency] private readonly SharedActionsSystem _actions = default!; - [Dependency] private readonly EntityLookupSystem _lookup = default!; - [Dependency] private readonly SharedPopupSystem _popups = default!; - [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; - [Dependency] private readonly AudioSystem _audioSystem = default!; - - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnShutdown); - SubscribeLocalEvent(OnWidePowerUsed); - SubscribeLocalEvent(OnFocusedPowerUsed); - SubscribeLocalEvent(OnDoAfter); - } - - private void OnInit(EntityUid uid, MetapsionicPowerComponent component, ComponentInit args) - { - if (!TryComp(uid, out ActionsComponent? comp)) - return; - _actions.AddAction(uid, ref component.ActionWideMetapsionicEntity, component.ActionWideMetapsionic, component: comp); - _actions.AddAction(uid, ref component.ActionFocusedMetapsionicEntity, component.ActionFocusedMetapsionic, component: comp); - _actions.TryGetActionData(component.ActionWideMetapsionicEntity, out var actionData); - if (actionData is { UseDelay: not null }) - { - _actions.StartUseDelay(component.ActionWideMetapsionicEntity); - _actions.StartUseDelay(component.ActionFocusedMetapsionicEntity); - } - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Add(component); - psionic.PsychicFeedback.Add(component.MetapsionicFeedback); - psionic.Amplification += 0.1f; - psionic.Dampening += 0.5f; - } - - } - - private void UpdateActions(EntityUid uid, MetapsionicPowerComponent? component = null) - { - if (!Resolve(uid, ref component)) - return; - _actions.StartUseDelay(component.ActionWideMetapsionicEntity); - _actions.StartUseDelay(component.ActionFocusedMetapsionicEntity); - } - - private void OnShutdown(EntityUid uid, MetapsionicPowerComponent component, ComponentShutdown args) - { - _actions.RemoveAction(uid, component.ActionWideMetapsionicEntity); - _actions.RemoveAction(uid, component.ActionFocusedMetapsionicEntity); - - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Remove(component); - psionic.PsychicFeedback.Remove(component.MetapsionicFeedback); - psionic.Amplification -= 0.1f; - psionic.Dampening -= 0.5f; - } - } - - private void OnWidePowerUsed(EntityUid uid, MetapsionicPowerComponent component, WideMetapsionicPowerActionEvent args) - { - if (HasComp(uid)) - return; - - if (!TryComp(uid, out var psionic)) - return; - - foreach (var entity in _lookup.GetEntitiesInRange(uid, component.Range)) - { - if (HasComp(entity) && entity != uid && !HasComp(entity) && - !(HasComp(entity) && Transform(entity).ParentUid == uid)) - { - _popups.PopupEntity(Loc.GetString("metapsionic-pulse-success"), uid, uid, PopupType.LargeCaution); - args.Handled = true; - return; - } - } - _popups.PopupEntity(Loc.GetString("metapsionic-pulse-failure"), uid, uid, PopupType.Large); - _psionics.LogPowerUsed(uid, "metapsionic pulse", - (int) MathF.Round(2 * psionic.Amplification - psionic.Dampening), - (int) MathF.Round(4 * psionic.Amplification - psionic.Dampening)); - UpdateActions(uid, component); - args.Handled = true; - } - - private void OnFocusedPowerUsed(FocusedMetapsionicPowerActionEvent args) - { - if (!TryComp(args.Performer, out var psionic)) - return; - - if (HasComp(args.Target)) - return; - - if (!TryComp(args.Performer, out var component)) - return; - - var ev = new FocusedMetapsionicDoAfterEvent(_gameTiming.CurTime); - - _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.Performer, component.UseDelay - psionic.Amplification, ev, args.Performer, args.Target, args.Performer) - { - BlockDuplicate = true, - BreakOnUserMove = true, - BreakOnTargetMove = true, - BreakOnDamage = true, - }, out var doAfterId); - - component.DoAfter = doAfterId; - - _popups.PopupEntity(Loc.GetString("focused-metapsionic-pulse-begin", ("entity", args.Target)), - args.Performer, - // TODO: Use LoS-based Filter when one is available. - Filter.Pvs(args.Performer).RemoveWhereAttachedEntity(entity => !ExamineSystemShared.InRangeUnOccluded(args.Performer, entity, ExamineRange, null)), - true, - PopupType.Medium); - - _audioSystem.PlayPvs(component.SoundUse, args.Performer, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); - _psionics.LogPowerUsed(args.Performer, "focused metapsionic pulse", - (int) MathF.Round(3 * psionic.Amplification - psionic.Dampening), - (int) MathF.Round(6 * psionic.Amplification - psionic.Dampening)); - args.Handled = true; - - UpdateActions(args.Performer, component); - } - - private void OnDoAfter(EntityUid uid, MetapsionicPowerComponent component, FocusedMetapsionicDoAfterEvent args) - { - if (!TryComp(args.Target, out var psychic)) - return; - - component.DoAfter = null; - - if (args.Target == null) return; - - if (TryComp(args.Target, out var swapped)) - { - _popups.PopupEntity(Loc.GetString(swapped.MindSwappedFeedback, ("entity", args.Target)), uid, uid, PopupType.LargeCaution); - return; - } - - if (args.Target == uid) - { - _popups.PopupEntity(Loc.GetString("metapulse-self", ("entity", args.Target)), uid, uid, PopupType.LargeCaution); - return; - } - - if (!HasComp(args.Target)) - { - _popups.PopupEntity(Loc.GetString("no-powers", ("entity", args.Target)), uid, uid, PopupType.LargeCaution); - return; - } - - if (HasComp(args.Target) & !HasComp(args.Target)) - { - _popups.PopupEntity(Loc.GetString("psychic-potential", ("entity", args.Target)), uid, uid, PopupType.LargeCaution); - return; - } - - foreach (var psychicFeedback in psychic.PsychicFeedback) - { - _popups.PopupEntity(Loc.GetString(psychicFeedback, ("entity", args.Target)), uid, uid, PopupType.LargeCaution); - } - - } - } -} diff --git a/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs b/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs deleted file mode 100644 index 6958170a5c2..00000000000 --- a/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs +++ /dev/null @@ -1,179 +0,0 @@ -using Robust.Shared.Audio; -using Robust.Shared.Player; -using Content.Server.Body.Components; -using Content.Server.Body.Systems; -using Content.Server.DoAfter; -using Content.Shared.Psionics.Abilities; -using Content.Shared.Actions; -using Content.Shared.Chemistry.Components; -using Content.Shared.DoAfter; -using Content.Shared.FixedPoint; -using Content.Shared.Mobs; -using Content.Shared.Popups; -using Content.Shared.Psionics.Events; -using Content.Shared.Examine; -using Robust.Shared.Timing; -using Content.Shared.Actions.Events; -using Robust.Server.Audio; - -namespace Content.Server.Psionics.Abilities -{ - public sealed class PsionicRegenerationPowerSystem : EntitySystem - { - [Dependency] private readonly SharedActionsSystem _actions = default!; - [Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!; - [Dependency] private readonly AudioSystem _audioSystem = default!; - [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; - [Dependency] private readonly SharedPopupSystem _popupSystem = default!; - [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly ExamineSystemShared _examine = default!; - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnShutdown); - SubscribeLocalEvent(OnPowerUsed); - SubscribeLocalEvent(OnMobStateChangedEvent); - SubscribeLocalEvent(OnDispelled); - SubscribeLocalEvent(OnDoAfter); - } - - private void OnInit(EntityUid uid, PsionicRegenerationPowerComponent component, ComponentInit args) - { - _actions.AddAction(uid, ref component.PsionicRegenerationActionEntity, component.PsionicRegenerationActionId ); - _actions.TryGetActionData( component.PsionicRegenerationActionEntity, out var actionData ); - if (actionData is { UseDelay: not null }) - _actions.StartUseDelay(component.PsionicRegenerationActionEntity); - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Add(component); - psionic.PsychicFeedback.Add(component.RegenerationFeedback); - psionic.Amplification += 0.5f; - psionic.Dampening += 0.5f; - } - } - - private void OnPowerUsed(EntityUid uid, PsionicRegenerationPowerComponent component, PsionicRegenerationPowerActionEvent args) - { - if (!TryComp(uid, out var psionic)) - return; - - var ev = new PsionicRegenerationDoAfterEvent(_gameTiming.CurTime); - var doAfterArgs = new DoAfterArgs(EntityManager, uid, component.UseDelay, ev, uid); - - //Prevent the power from ignoring its own cooldown - _actions.TryGetActionData(component.PsionicRegenerationActionEntity, out var actionData); - var curTime = _gameTiming.CurTime; - if (actionData != null && actionData.Cooldown.HasValue && actionData.Cooldown.Value.End > curTime) - return; - - _doAfterSystem.TryStartDoAfter(doAfterArgs, out var doAfterId); - - component.DoAfter = doAfterId; - - _popupSystem.PopupEntity(Loc.GetString("psionic-regeneration-begin", ("entity", uid)), uid, PopupType.Medium); - _audioSystem.PlayPvs(component.SoundUse, uid, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); - - _psionics.LogPowerUsed(uid, "psionic regeneration", - (int) Math.Round(6 * psionic.Amplification - psionic.Dampening), - (int) Math.Round(8 * psionic.Amplification - psionic.Dampening)); - - args.Handled = true; - } - - /// - /// Regenerators automatically activate upon crit, provided the power was off cooldown at that exact point in time. - /// Self-rescusitation is also far more costly, and extremely obvious - /// - /// - /// - /// - private void OnMobStateChangedEvent(EntityUid uid, PsionicRegenerationPowerComponent component, MobStateChangedEvent args) - { - if (!TryComp(uid, out var psionic)) - return; - - if (HasComp(uid)) - return; - - if (args.NewMobState is MobState.Critical) - { - _actions.TryGetActionData(component.PsionicRegenerationActionEntity, out var actionData); - var curTime = _gameTiming.CurTime; - if (actionData != null && actionData.Cooldown.HasValue && actionData.Cooldown.Value.End > curTime) - return; - - if (actionData is { UseDelay: not null }) - { - component.SelfRevive = true; - _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, uid, component.UseDelay, new PsionicRegenerationDoAfterEvent(_gameTiming.CurTime), uid, args.Target, uid) - { - BreakOnUserMove = false, - BreakOnTargetMove = false, - BreakOnWeightlessMove = false, - BreakOnDamage = false, - RequireCanInteract = false, - }); - _popupSystem.PopupEntity(Loc.GetString("psionic-regeneration-self-revive", ("entity", uid)), uid, PopupType.MediumCaution); - _audioSystem.PlayPvs(component.SoundUse, uid, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); - - _psionics.LogPowerUsed(uid, "psionic regeneration", - (int) Math.Round(10 * psionic.Amplification - 2 * psionic.Dampening), - (int) Math.Round(20 * psionic.Amplification - 2 * psionic.Dampening)); - - _actions.StartUseDelay(component.PsionicRegenerationActionEntity); - } - } - } - - private void OnShutdown(EntityUid uid, PsionicRegenerationPowerComponent component, ComponentShutdown args) - { - _actions.RemoveAction(uid, component.PsionicRegenerationActionEntity); - - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Remove(component); - psionic.PsychicFeedback.Remove(component.RegenerationFeedback); - psionic.Amplification -= 0.5f; - psionic.Dampening -= 0.5f; - } - } - - private void OnDispelled(EntityUid uid, PsionicRegenerationPowerComponent component, DispelledEvent args) - { - if (component.DoAfter == null) - return; - - _doAfterSystem.Cancel(component.DoAfter); - component.DoAfter = null; - - args.Handled = true; - } - - private void OnDoAfter(EntityUid uid, PsionicRegenerationPowerComponent component, PsionicRegenerationDoAfterEvent args) - { - component.DoAfter = null; - - if (!TryComp(uid, out var psionic)) - return; - - if (!TryComp(uid, out var stream)) - return; - - var percentageComplete = Math.Min(1f, (_gameTiming.CurTime - args.StartedAt).TotalSeconds / component.UseDelay); - - var solution = new Solution(); - solution.AddReagent("PsionicRegenerationEssence", FixedPoint2.New(Math.Min(component.EssenceAmount * percentageComplete + 10f * psionic.Dampening, 15f))); - _bloodstreamSystem.TryAddToChemicals(uid, solution, stream); - if (component.SelfRevive == true) - { - var critSolution = new Solution(); - critSolution.AddReagent("Epinephrine", MathF.Min(5 + 5 * psionic.Dampening, 15)); - _bloodstreamSystem.TryAddToChemicals(uid, critSolution, stream); - component.SelfRevive = false; - } - } - } -} diff --git a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs deleted file mode 100644 index 77075dab206..00000000000 --- a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs +++ /dev/null @@ -1,93 +0,0 @@ -using Content.Shared.Actions; -using Content.Shared.Psionics.Abilities; -using Content.Server.Atmos.Components; -using Content.Server.Weapons.Ranged.Systems; -using Robust.Server.GameObjects; -using Content.Shared.Actions.Events; -using Content.Server.Explosion.Components; -using Content.Shared.Mobs.Components; -using Robust.Shared.Map; - -namespace Content.Server.Psionics.Abilities -{ - public sealed class PyrokinesisPowerSystem : EntitySystem - { - [Dependency] private readonly TransformSystem _xform = default!; - [Dependency] private readonly SharedActionsSystem _actions = default!; - [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; - [Dependency] private readonly GunSystem _gunSystem = default!; - [Dependency] private readonly SharedTransformSystem _transformSystem = default!; - [Dependency] private readonly PhysicsSystem _physics = default!; - [Dependency] private readonly IMapManager _mapManager = default!; - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnShutdown); - SubscribeLocalEvent(OnPowerUsed); - } - - private void OnInit(EntityUid uid, PyrokinesisPowerComponent component, ComponentInit args) - { - _actions.AddAction(uid, ref component.PyrokinesisActionEntity, component.PyrokinesisActionId); - _actions.TryGetActionData( component.PyrokinesisActionEntity, out var actionData); - if (actionData is { UseDelay: not null }) - _actions.StartUseDelay(component.PyrokinesisActionEntity); - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Add(component); - psionic.PsychicFeedback.Add(component.PyrokinesisFeedback); - psionic.Amplification += 1f; - } - } - - private void OnShutdown(EntityUid uid, PyrokinesisPowerComponent component, ComponentShutdown args) - { - _actions.RemoveAction(uid, component.PyrokinesisActionEntity); - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Remove(component); - psionic.PsychicFeedback.Remove(component.PyrokinesisFeedback); - psionic.Amplification -= 1f; - } - } - - private void OnPowerUsed(PyrokinesisPowerActionEvent args) - { - if (!TryComp(args.Performer, out var psionic)) - return; - - if (!HasComp(args.Performer)) - { - var xformQuery = GetEntityQuery(); - var xform = xformQuery.GetComponent(args.Performer); - - var mapPos = xform.Coordinates.ToMap(EntityManager, _xform); - var spawnCoords = _mapManager.TryFindGridAt(mapPos, out var gridUid, out _) - ? xform.Coordinates.WithEntityId(gridUid, EntityManager) - : new(_mapManager.GetMapEntityId(mapPos.MapId), mapPos.Position); - - var ent = Spawn("ProjectileAnomalyFireball", spawnCoords); - - if (TryComp(ent, out var fireball)) - { - fireball.MaxIntensity = (int) MathF.Round(20 * psionic.Amplification - 10 * psionic.Dampening); - - if (psionic.Amplification > 5 && EnsureComp(ent, out var ignite)) - { - ignite.FireStacks = 0.2f * psionic.Amplification - 0.1f * psionic.Dampening; - } - } - - var direction = args.Target.Position; - - _gunSystem.ShootProjectile(ent, direction, new System.Numerics.Vector2(0, 0), args.Performer, args.Performer, 20f); - - _psionics.LogPowerUsed(args.Performer, "pyrokinesis", - (int) MathF.Round(6f * psionic.Amplification - psionic.Dampening), - (int) MathF.Round(8f * psionic.Amplification - psionic.Dampening)); - args.Handled = true; - } - } - } -} diff --git a/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs b/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs deleted file mode 100644 index e184b19396b..00000000000 --- a/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs +++ /dev/null @@ -1,76 +0,0 @@ -using Content.Server.Body.Systems; -using Content.Server.Body.Components; -using Content.Shared.Actions; -using Content.Shared.Chemistry.Components; -using Content.Shared.Bed.Sleep; -using Content.Shared.Psionics.Abilities; -using Robust.Shared.Prototypes; -using Robust.Shared.Timing; -using Content.Shared.Mind; -using Content.Shared.Actions.Events; -using Content.Shared.FixedPoint; - -namespace Content.Server.Psionics.Abilities -{ - public sealed class MassSleepPowerSystem : EntitySystem - { - [Dependency] private readonly SharedActionsSystem _actions = default!; - [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; - [Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!; - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnShutdown); - SubscribeLocalEvent(OnPowerUsed); - } - - private void OnInit(EntityUid uid, RegenerativeStasisPowerComponent component, ComponentInit args) - { - _actions.AddAction(uid, ref component.RegenerativeStasisActionEntity, component.RegenerativeStasisActionId); - _actions.TryGetActionData(component.RegenerativeStasisActionEntity, out var actionData); - if (actionData is { UseDelay: not null }) - _actions.StartUseDelay(component.RegenerativeStasisActionEntity); - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Add(component); - psionic.PsychicFeedback.Add(component.RegenerativeStasisFeedback); - psionic.Amplification += 0.5f; - psionic.Dampening += 0.5f; - } - } - - private void OnShutdown(EntityUid uid, RegenerativeStasisPowerComponent component, ComponentShutdown args) - { - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Remove(component); - psionic.PsychicFeedback.Remove(component.RegenerativeStasisFeedback); - psionic.Amplification -= 0.5f; - psionic.Dampening -= 0.5f; - } - _actions.RemoveAction(uid, component.RegenerativeStasisActionEntity); - } - - private void OnPowerUsed(EntityUid uid, RegenerativeStasisPowerComponent component, RegenerativeStasisPowerActionEvent args) - { - if (TryComp(uid, out var psionic) - && !HasComp(uid) - && !HasComp(args.Target) - && TryComp(args.Target, out var stream)) - { - var solution = new Solution(); - solution.AddReagent("PsionicRegenerationEssence", FixedPoint2.New(MathF.Min(2.5f * psionic.Amplification + psionic.Dampening, 15f))); - solution.AddReagent("Epinephrine", FixedPoint2.New(MathF.Min(2.5f * psionic.Dampening + psionic.Amplification, 15f))); - _bloodstreamSystem.TryAddToChemicals(args.Target, solution, stream); - EnsureComp(args.Target); - - _psionics.LogPowerUsed(uid, "regenerative stasis", - (int) Math.Round(4 * psionic.Amplification - psionic.Dampening), - (int) Math.Round(6 * psionic.Amplification - psionic.Dampening)); - args.Handled = true; - } - } - } -} diff --git a/Content.Server/Psionics/Abilities/TelegnosisPowerSystem.cs b/Content.Server/Psionics/Abilities/TelegnosisPowerSystem.cs deleted file mode 100644 index f03b001fc70..00000000000 --- a/Content.Server/Psionics/Abilities/TelegnosisPowerSystem.cs +++ /dev/null @@ -1,106 +0,0 @@ -using Content.Shared.Actions; -using Content.Shared.Psionics.Abilities; -using Content.Shared.Mind.Components; -using Content.Shared.Actions.Events; -using Content.Shared.Mobs; -using Content.Shared.Storage.Components; - -namespace Content.Server.Psionics.Abilities -{ - public sealed class TelegnosisPowerSystem : EntitySystem - { - [Dependency] private readonly SharedActionsSystem _actions = default!; - [Dependency] private readonly MindSwapPowerSystem _mindSwap = default!; - [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnShutdown); - SubscribeLocalEvent(OnPowerUsed); - SubscribeLocalEvent(OnMindRemoved); - SubscribeLocalEvent(OnDispelled); - SubscribeLocalEvent(OnMobstateChanged); - SubscribeLocalEvent(OnStorageInsertAttempt); - } - - private void OnInit(EntityUid uid, TelegnosisPowerComponent component, ComponentInit args) - { - _actions.AddAction(uid, ref component.TelegnosisActionEntity, component.TelegnosisActionId ); - _actions.TryGetActionData( component.TelegnosisActionEntity, out var actionData ); - if (actionData is { UseDelay: not null }) - _actions.StartUseDelay(component.TelegnosisActionEntity); - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Add(component); - psionic.PsychicFeedback.Add(component.TelegnosisFeedback); - psionic.Amplification += 0.3f; - psionic.Dampening += 0.3f; - } - } - - private void OnShutdown(EntityUid uid, TelegnosisPowerComponent component, ComponentShutdown args) - { - _actions.RemoveAction(uid, component.TelegnosisActionEntity); - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Remove(component); - psionic.PsychicFeedback.Remove(component.TelegnosisFeedback); - psionic.Amplification -= 0.3f; - psionic.Dampening -= 0.3f; - } - } - - private void OnPowerUsed(EntityUid uid, TelegnosisPowerComponent component, TelegnosisPowerActionEvent args) - { - if (!TryComp(uid, out var psionic)) - return; - - if (HasComp(uid)) - return; - - var projection = Spawn(component.Prototype, Transform(uid).Coordinates); - Transform(projection).AttachToGridOrMap(); - component.OriginalEntity = uid; - component.IsProjecting = true; - component.ProjectionUid = projection; - _mindSwap.Swap(uid, projection); - - if (EnsureComp(projection, out var projectionComponent)) - projectionComponent.OriginalEntity = uid; - - _psionics.LogPowerUsed(uid, "telegnosis", - (int) Math.Round(8f * psionic.Amplification - psionic.Dampening), - (int) Math.Round(12f * psionic.Amplification - psionic.Dampening)); - - args.Handled = true; - } - private void OnMindRemoved(EntityUid uid, TelegnosticProjectionComponent component, MindRemovedMessage args) - { - if (TryComp(component.OriginalEntity, out var originalEntity)) - originalEntity.IsProjecting = false; - - QueueDel(uid); - } - - private void OnDispelled(EntityUid uid, TelegnosisPowerComponent component, DispelledEvent args) - { - if (component.IsProjecting) - _mindSwap.Swap(uid, component.ProjectionUid); - } - - private void OnMobstateChanged(EntityUid uid, TelegnosisPowerComponent component, MobStateChangedEvent args) - { - if (component.IsProjecting && args.NewMobState is MobState.Critical - || component.IsProjecting && args.NewMobState is MobState.Dead) - _mindSwap.Swap(uid, component.ProjectionUid); - } - - private void OnStorageInsertAttempt(EntityUid uid, TelegnosisPowerComponent component, InsertIntoEntityStorageAttemptEvent args) - { - if (component.IsProjecting) - _mindSwap.Swap(uid, component.ProjectionUid); - } - } -} diff --git a/Content.Server/Psionics/PotentialPsionicComponent.cs b/Content.Server/Psionics/PotentialPsionicComponent.cs deleted file mode 100644 index e874296a4c3..00000000000 --- a/Content.Server/Psionics/PotentialPsionicComponent.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Content.Server.Psionics -{ - [RegisterComponent] - public sealed partial class PotentialPsionicComponent : Component - { - /// - /// The base chance of an entity rolling psychic powers, which is increased by other modifiers such as glimmer. - /// - /// - /// I have increased this to 10% up from its original value of 2%, because I estimate that most people won't take the Latent Psychic trait - /// Simply because they might not even know it exists - /// - [DataField("chance")] - public float Chance = 0.10f; - - /// - /// YORO (you only reroll once) - /// - public bool Rerolled = false; - } -} diff --git a/Content.Server/Salvage/SpawnSalvageMissionJob.cs b/Content.Server/Salvage/SpawnSalvageMissionJob.cs index e2b17b58724..2776db2283a 100644 --- a/Content.Server/Salvage/SpawnSalvageMissionJob.cs +++ b/Content.Server/Salvage/SpawnSalvageMissionJob.cs @@ -125,7 +125,11 @@ protected override async Task Process() air.Gases.CopyTo(moles, 0); var atmos = _entManager.EnsureComponent(mapUid); _entManager.System().SetMapSpace(mapUid, air.Space, atmos); - _entManager.System().SetMapGasMixture(mapUid, new GasMixture(moles, mission.Temperature), atmos); + _entManager.System().SetMapGasMixture(mapUid, new GasMixture(2500) + { + Temperature = mission.Temperature, + Moles = moles, + }, atmos); if (mission.Color != null) { diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs index e4e4534b0c5..f9ceab8f7b1 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs @@ -371,8 +371,8 @@ private void UpdateFTLStarting(Entity entity) Enable(uid, component: body); _physics.SetLinearVelocity(uid, new Vector2(0f, 20f), body: body); _physics.SetAngularVelocity(uid, 0f, body: body); - _physics.SetLinearDamping(uid, body, 0f); - _physics.SetAngularDamping(uid, body, 0f); + _physics.SetLinearDamping(body, 0f); + _physics.SetAngularDamping(body, 0f); _dockSystem.SetDockBolts(uid, true); _console.RefreshShuttleConsoles(uid); @@ -426,8 +426,8 @@ private void UpdateFTLArriving(Entity entity) _physics.SetLinearVelocity(uid, Vector2.Zero, body: body); _physics.SetAngularVelocity(uid, 0f, body: body); - _physics.SetLinearDamping(uid, body, entity.Comp2.LinearDamping); - _physics.SetAngularDamping(uid, body, entity.Comp2.AngularDamping); + _physics.SetLinearDamping(body, entity.Comp2.LinearDamping); + _physics.SetAngularDamping(body, entity.Comp2.AngularDamping); var target = entity.Comp1.TargetCoordinates; diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.cs index 7c42753a7de..8d44dae4b2e 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.cs @@ -129,10 +129,10 @@ public void Enable(EntityUid uid, FixturesComponent? manager = null, PhysicsComp return; _physics.SetBodyType(uid, BodyType.Dynamic, manager: manager, body: component); - _physics.SetBodyStatus(uid, component, BodyStatus.InAir); + _physics.SetBodyStatus(component, BodyStatus.InAir); _physics.SetFixedRotation(uid, false, manager: manager, body: component); - _physics.SetLinearDamping(uid, component, shuttle.LinearDamping); - _physics.SetAngularDamping(uid, component, shuttle.AngularDamping); + _physics.SetLinearDamping(component, shuttle.LinearDamping); + _physics.SetAngularDamping(component, shuttle.AngularDamping); } public void Disable(EntityUid uid, FixturesComponent? manager = null, PhysicsComponent? component = null) @@ -141,7 +141,7 @@ public void Disable(EntityUid uid, FixturesComponent? manager = null, PhysicsCom return; _physics.SetBodyType(uid, BodyType.Static, manager: manager, body: component); - _physics.SetBodyStatus(uid, component, BodyStatus.OnGround); + _physics.SetBodyStatus(component, BodyStatus.OnGround); _physics.SetFixedRotation(uid, true, manager: manager, body: component); } diff --git a/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs b/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs index ba07375699b..7784db015d3 100644 --- a/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs +++ b/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs @@ -13,7 +13,7 @@ using Robust.Shared.Map.Components; using Robust.Shared.Physics.Events; using Robust.Shared.Timing; -using Content.Shared.Psionics.Abilities; //EE - Summary: for the telegnostic projection. +using Content.Shared.Abilities.Psionics; //Nyano - Summary: for the telegnostic projection. namespace Content.Server.Singularity.EntitySystems; @@ -39,7 +39,7 @@ public override void Initialize() SubscribeLocalEvent(PreventConsume); SubscribeLocalEvent(PreventConsume); - SubscribeLocalEvent(PreventConsume); ///EE - Summary: the telegnositic projection has the same trait as ghosts. + SubscribeLocalEvent(PreventConsume); ///Nyano - Summary: the telegnositic projection has the same trait as ghosts. SubscribeLocalEvent(PreventConsume); SubscribeLocalEvent(OnHorizonMapInit); SubscribeLocalEvent(OnStartCollide); diff --git a/Content.Server/Spreader/SpreaderSystem.cs b/Content.Server/Spreader/SpreaderSystem.cs index 5b2f3298a2b..89951718236 100644 --- a/Content.Server/Spreader/SpreaderSystem.cs +++ b/Content.Server/Spreader/SpreaderSystem.cs @@ -18,7 +18,6 @@ namespace Content.Server.Spreader; /// public sealed class SpreaderSystem : EntitySystem { - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IRobustRandom _robustRandom = default!; [Dependency] private readonly SharedMapSystem _map = default!; @@ -34,8 +33,6 @@ public sealed class SpreaderSystem : EntitySystem // TODO PERFORMANCE Assign each prototype to an index and convert dictionary to array private readonly Dictionary> _gridUpdates = []; - private EntityQuery _query; - public const float SpreadCooldownSeconds = 1; [ValidatePrototypeId] @@ -50,8 +47,6 @@ public override void Initialize() SubscribeLocalEvent(OnTerminating); SetupPrototypes(); - - _query = GetEntityQuery(); } private void OnPrototypeReload(PrototypesReloadedEventArgs obj) @@ -71,7 +66,13 @@ private void SetupPrototypes() private void OnAirtightChanged(ref AirtightChanged ev) { - ActivateSpreadableNeighbors(ev.Entity, ev.Position); + var neighbors = GetSpreadableNeighbors(ev.Entity, ev.Airtight, ev.Position); + + foreach (var neighbor in neighbors) + { + if (!TerminatingOrDeleted(neighbor)) + EnsureComp(neighbor); + } } private void OnGridInit(GridInitializeEvent ev) @@ -81,7 +82,13 @@ private void OnGridInit(GridInitializeEvent ev) private void OnTerminating(Entity entity, ref EntityTerminatingEvent args) { - ActivateSpreadableNeighbors(entity); + var neighbors = GetSpreadableNeighbors(entity); + + foreach (var neighbor in neighbors) + { + if (!TerminatingOrDeleted(neighbor)) + EnsureComp(neighbor); + } } /// @@ -247,7 +254,8 @@ public void GetNeighbors(EntityUid uid, TransformComponent comp, ProtoId - /// This function activates all spreaders that are adjacent to a given entity. This also activates other spreaders - /// on the same tile as the current entity (for thin airtight entities like windoors). + /// Given an entity, this returns a list of all adjacent entities with a . /// - public void ActivateSpreadableNeighbors(EntityUid uid, (EntityUid Grid, Vector2i Tile)? position = null) + public List GetSpreadableNeighbors(EntityUid uid, AirtightComponent? comp = null, + (EntityUid Grid, Vector2i Tile)? position = null) { + Resolve(uid, ref comp, false); + var neighbors = new List(); + Vector2i tile; EntityUid ent; MapGridComponent? grid; @@ -303,40 +315,37 @@ public void ActivateSpreadableNeighbors(EntityUid uid, (EntityUid Grid, Vector2i { var transform = Transform(uid); if (!TryComp(transform.GridUid, out grid) || TerminatingOrDeleted(transform.GridUid.Value)) - return; - + return neighbors; tile = _map.TileIndicesFor(transform.GridUid.Value, grid, transform.Coordinates); ent = transform.GridUid.Value; } else { if (!TryComp(position.Value.Grid, out grid)) - return; - (ent, tile) = position.Value; + return neighbors; + tile = position.Value.Tile; + ent = position.Value.Grid; } - var anchored = _map.GetAnchoredEntitiesEnumerator(ent, grid, tile); - while (anchored.MoveNext(out var entity)) - { - if (entity == ent) - continue; - DebugTools.Assert(Transform(entity.Value).Anchored); - if (_query.HasComponent(ent) && !TerminatingOrDeleted(entity.Value)) - EnsureComp(entity.Value); - } + var spreaderQuery = GetEntityQuery(); for (var i = 0; i < Atmospherics.Directions; i++) { var direction = (AtmosDirection) (1 << i); - var adjacentTile = SharedMapSystem.GetDirection(tile, direction.ToDirection()); - anchored = _map.GetAnchoredEntitiesEnumerator(ent, grid, adjacentTile); + if (comp != null && !comp.AirBlockedDirection.IsFlagSet(direction)) + continue; - while (anchored.MoveNext(out var entity)) + var directionEnumerator = + _map.GetAnchoredEntitiesEnumerator(ent, grid, SharedMapSystem.GetDirection(tile, direction.ToDirection())); + + while (directionEnumerator.MoveNext(out var entity)) { DebugTools.Assert(Transform(entity.Value).Anchored); - if (_query.HasComponent(ent) && !TerminatingOrDeleted(entity.Value)) - EnsureComp(entity.Value); + if (spreaderQuery.HasComponent(entity) && !TerminatingOrDeleted(entity.Value)) + neighbors.Add(entity.Value); } } + + return neighbors; } } diff --git a/Content.Server/StationEvents/Events/MeteorSwarmRule.cs b/Content.Server/StationEvents/Events/MeteorSwarmRule.cs index ad56479b379..192a620c9fc 100644 --- a/Content.Server/StationEvents/Events/MeteorSwarmRule.cs +++ b/Content.Server/StationEvents/Events/MeteorSwarmRule.cs @@ -68,9 +68,9 @@ protected override void ActiveTick(EntityUid uid, MeteorSwarmRuleComponent compo var spawnPosition = new MapCoordinates(center + offset, mapId); var meteor = Spawn("MeteorLarge", spawnPosition); var physics = EntityManager.GetComponent(meteor); - _physics.SetBodyStatus(meteor, physics, BodyStatus.InAir); - _physics.SetLinearDamping(meteor, physics, 0f); - _physics.SetAngularDamping(meteor, physics, 0f); + _physics.SetBodyStatus(physics, BodyStatus.InAir); + _physics.SetLinearDamping(physics, 0f); + _physics.SetAngularDamping(physics, 0f); _physics.ApplyLinearImpulse(meteor, -offset.Normalized() * component.MeteorVelocity * physics.Mass, body: physics); _physics.ApplyAngularImpulse( meteor, diff --git a/Content.Server/Zombies/ZombieSystem.Transform.cs b/Content.Server/Zombies/ZombieSystem.Transform.cs index 53128aade31..daadd4b518b 100644 --- a/Content.Server/Zombies/ZombieSystem.Transform.cs +++ b/Content.Server/Zombies/ZombieSystem.Transform.cs @@ -16,7 +16,7 @@ using Content.Server.Roles; using Content.Server.Speech.Components; using Content.Server.Temperature.Components; -using Content.Shared.Psionics.Abilities; +using Content.Shared.Abilities.Psionics; using Content.Shared.CombatMode; using Content.Shared.CombatMode.Pacification; using Content.Shared.Damage; @@ -59,7 +59,9 @@ public sealed partial class ZombieSystem [Dependency] private readonly IChatManager _chatMan = default!; [Dependency] private readonly MindSystem _mind = default!; [Dependency] private readonly SharedRoleSystem _roles = default!; + [Dependency] private readonly MobThresholdSystem _mobThreshold = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly ActionsSystem _actions = default!; // DeltaV - No psionic zombies /// /// Handles an entity turning into a zombie when they die or go into crit diff --git a/Content.Shared/Atmos/Atmospherics.cs b/Content.Shared/Atmos/Atmospherics.cs index 6a8587ca239..7460e08e46f 100644 --- a/Content.Shared/Atmos/Atmospherics.cs +++ b/Content.Shared/Atmos/Atmospherics.cs @@ -8,6 +8,11 @@ namespace Content.Shared.Atmos /// public static class Atmospherics { + static Atmospherics() + { + AdjustedNumberOfGases = MathHelper.NextMultipleOf(TotalNumberOfGases, 4); + } + #region ATMOS /// /// The universal gas constant, in kPa*L/(K*mol) @@ -178,7 +183,7 @@ public static class Atmospherics /// This is the actual length of the gases arrays in mixtures. /// Set to the closest multiple of 4 relative to for SIMD reasons. /// - public const int AdjustedNumberOfGases = ((TotalNumberOfGases + 3) / 4) * 4; + public static readonly int AdjustedNumberOfGases; /// /// Amount of heat released per mole of burnt hydrogen or tritium (hydrogen isotope) diff --git a/Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs b/Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs index f468724db33..eb0079eb358 100644 --- a/Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs +++ b/Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs @@ -66,10 +66,7 @@ public static Vector2i GetGasChunkIndices(Vector2i indices) [Serializable, NetSerializable] public readonly struct GasOverlayData : IEquatable { - [ViewVariables] public readonly byte FireState; - - [ViewVariables] public readonly byte[] Opacity; // TODO change fire color based on temps diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs index 8172947a039..b58bdf83e49 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs @@ -358,7 +358,7 @@ public bool TryBuckle(EntityUid buckleUid, EntityUid userUid, EntityUid strapUid if (TryComp(buckleUid, out var physics)) { - _physics.ResetDynamics(buckleUid, physics); + _physics.ResetDynamics(physics); } if (!buckleComp.PullStrap && TryComp(strapUid, out var toPullable)) diff --git a/Content.Shared/Maps/ContentTileDefinition.cs b/Content.Shared/Maps/ContentTileDefinition.cs index 32f5db0e821..ce7980509eb 100644 --- a/Content.Shared/Maps/ContentTileDefinition.cs +++ b/Content.Shared/Maps/ContentTileDefinition.cs @@ -81,11 +81,7 @@ public sealed partial class ContentTileDefinition : IPrototype, IInheritingProto [DataField("itemDrop", customTypeSerializer:typeof(PrototypeIdSerializer))] public string ItemDropPrototypeName { get; private set; } = "FloorTileItemSteel"; - // TODO rename data-field in yaml - /// - /// Whether or not the tile is exposed to the map's atmosphere. - /// - [DataField("isSpace")] public bool MapAtmosphere { get; private set; } + [DataField("isSpace")] public bool IsSpace { get; private set; } /// /// Friction override for mob mover in diff --git a/Content.Shared/Maps/TurfHelpers.cs b/Content.Shared/Maps/TurfHelpers.cs index 58a5d133b55..a87b8c97d15 100644 --- a/Content.Shared/Maps/TurfHelpers.cs +++ b/Content.Shared/Maps/TurfHelpers.cs @@ -11,6 +11,22 @@ namespace Content.Shared.Maps // That, or make the interface arguments non-optional so people stop failing to pass them in. public static class TurfHelpers { + /// + /// Attempts to get the turf at map indices with grid id or null if no such turf is found. + /// + public static TileRef GetTileRef(this Vector2i vector2i, EntityUid gridId, IMapManager? mapManager = null) + { + mapManager ??= IoCManager.Resolve(); + + if (!mapManager.TryGetGrid(gridId, out var grid)) + return default; + + if (!grid.TryGetTileRef(vector2i, out var tile)) + return default; + + return tile; + } + /// /// Attempts to get the turf at a certain coordinates or null if no such turf is found. /// @@ -51,7 +67,7 @@ public static ContentTileDefinition GetContentTileDefinition(this Tile tile, ITi /// public static bool IsSpace(this Tile tile, ITileDefinitionManager? tileDefinitionManager = null) { - return tile.GetContentTileDefinition(tileDefinitionManager).MapAtmosphere; + return tile.GetContentTileDefinition(tileDefinitionManager).IsSpace; } /// @@ -99,6 +115,15 @@ public static IEnumerable GetEntitiesInTile(this EntityCoordinates co return GetEntitiesInTile(turf.Value, flags, lookupSystem); } + /// + /// Helper that returns all entities in a turf. + /// + [Obsolete("Use the lookup system")] + public static IEnumerable GetEntitiesInTile(this Vector2i indices, EntityUid gridId, LookupFlags flags = LookupFlags.Static, EntityLookupSystem? lookupSystem = null) + { + return GetEntitiesInTile(indices.GetTileRef(gridId), flags, lookupSystem); + } + /// /// Checks if a turf has something dense on it. /// diff --git a/Content.Shared/Movement/Systems/SharedJetpackSystem.cs b/Content.Shared/Movement/Systems/SharedJetpackSystem.cs index 8c42511f846..abe12b79d1a 100644 --- a/Content.Shared/Movement/Systems/SharedJetpackSystem.cs +++ b/Content.Shared/Movement/Systems/SharedJetpackSystem.cs @@ -92,7 +92,7 @@ private void SetupUser(EntityUid user, EntityUid jetpackUid) _mover.SetRelay(user, jetpackUid); if (TryComp(user, out var physics)) - _physics.SetBodyStatus(user, physics, BodyStatus.InAir); + _physics.SetBodyStatus(physics, BodyStatus.InAir); userComp.Jetpack = jetpackUid; } @@ -103,7 +103,7 @@ private void RemoveUser(EntityUid uid) return; if (TryComp(uid, out var physics)) - _physics.SetBodyStatus(uid, physics, BodyStatus.OnGround); + _physics.SetBodyStatus(physics, BodyStatus.OnGround); RemComp(uid); } diff --git a/Content.Shared/Psionics/Abilities/AcceptPsionicsEuiMessage.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/AcceptPsionicsEuiMessage.cs similarity index 100% rename from Content.Shared/Psionics/Abilities/AcceptPsionicsEuiMessage.cs rename to Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/AcceptPsionicsEuiMessage.cs diff --git a/Content.Shared/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs similarity index 77% rename from Content.Shared/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs rename to Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs index c3702880375..ce86111fc4b 100644 --- a/Content.Shared/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs @@ -1,6 +1,6 @@ using Content.Shared.Damage; -namespace Content.Shared.Psionics.Abilities +namespace Content.Shared.Abilities.Psionics { /// /// Takes damage when dispelled. @@ -9,7 +9,7 @@ namespace Content.Shared.Psionics.Abilities public sealed partial class DamageOnDispelComponent : Component { [DataField("damage", required: true)] - public DamageSpecifier Damage = default!; + public DamageSpecifier Damage = default!; [DataField("variance")] public float Variance = 0.5f; diff --git a/Content.Shared/Psionics/Abilities/Dispel/DispelPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DispelPowerComponent.cs similarity index 79% rename from Content.Shared/Psionics/Abilities/Dispel/DispelPowerComponent.cs rename to Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DispelPowerComponent.cs index 518a28b0967..cd887866364 100644 --- a/Content.Shared/Psionics/Abilities/Dispel/DispelPowerComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DispelPowerComponent.cs @@ -1,22 +1,20 @@ +using Content.Shared.Actions; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Psionics.Abilities +namespace Content.Shared.Abilities.Psionics { [RegisterComponent] public sealed partial class DispelPowerComponent : Component { [DataField("range")] public float Range = 10f; - + [DataField("dispelActionId", customTypeSerializer: typeof(PrototypeIdSerializer))] public string? DispelActionId = "ActionDispel"; [DataField("dispelActionEntity")] public EntityUid? DispelActionEntity; - - [DataField("dispelFeedback")] - public string DispelFeedback = "dispel-feedback"; } } diff --git a/Content.Shared/Psionics/Abilities/Dispel/DispellableComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DispellableComponent.cs similarity index 69% rename from Content.Shared/Psionics/Abilities/Dispel/DispellableComponent.cs rename to Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DispellableComponent.cs index 4bb5ee653d2..40352004187 100644 --- a/Content.Shared/Psionics/Abilities/Dispel/DispellableComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DispellableComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Shared.Psionics.Abilities +namespace Content.Shared.Abilities.Psionics { [RegisterComponent] public sealed partial class DispellableComponent : Component diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs new file mode 100644 index 00000000000..7d611c63dac --- /dev/null +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs @@ -0,0 +1,18 @@ +using Content.Shared.Actions; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Abilities.Psionics +{ + [RegisterComponent] + public sealed partial class MassSleepPowerComponent : Component + { + public float Radius = 1.25f; + [DataField("massSleepActionId", + customTypeSerializer: typeof(PrototypeIdSerializer))] + public string? MassSleepActionId = "ActionMassSleep"; + + [DataField("massSleepActionEntity")] + public EntityUid? MassSleepActionEntity; + } +} diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerSystem.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerSystem.cs new file mode 100644 index 00000000000..e36a3c70e8a --- /dev/null +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerSystem.cs @@ -0,0 +1,59 @@ +using Content.Shared.Actions; +using Content.Shared.Bed.Sleep; +using Content.Shared.Magic.Events; +using Content.Shared.Damage; +using Content.Shared.Mobs.Components; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; +using Content.Shared.Mind; +using Content.Shared.Actions.Events; + +namespace Content.Shared.Abilities.Psionics +{ + public sealed class MassSleepPowerSystem : EntitySystem + { + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly EntityLookupSystem _lookup = default!; + [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly SharedMindSystem _mindSystem = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnPowerUsed); + } + + private void OnInit(EntityUid uid, MassSleepPowerComponent component, ComponentInit args) + { + _actions.AddAction(uid, ref component.MassSleepActionEntity, component.MassSleepActionId ); + _actions.TryGetActionData( component.MassSleepActionEntity, out var actionData ); + if (actionData is { UseDelay: not null }) + _actions.StartUseDelay(component.MassSleepActionEntity); + if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) + psionic.PsionicAbility = component.MassSleepActionEntity; + } + + private void OnShutdown(EntityUid uid, MassSleepPowerComponent component, ComponentShutdown args) + { + _actions.RemoveAction(uid, component.MassSleepActionEntity); + } + + private void OnPowerUsed(EntityUid uid, MassSleepPowerComponent component, MassSleepPowerActionEvent args) + { + foreach (var entity in _lookup.GetEntitiesInRange(args.Target, component.Radius)) + { + if (HasComp(entity) && entity != uid && !HasComp(entity)) + { + if (TryComp(entity, out var damageable) && damageable.DamageContainerID == "Biological") + EnsureComp(entity); + } + } + _psionics.LogPowerUsed(uid, "mass sleep"); + args.Handled = true; + } + } +} diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs new file mode 100644 index 00000000000..c9d0130221a --- /dev/null +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs @@ -0,0 +1,21 @@ +using Content.Shared.Actions; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Abilities.Psionics +{ + [RegisterComponent] + public sealed partial class MetapsionicPowerComponent : Component + { + [DataField("range")] + public float Range = 5f; + + public InstantActionComponent? MetapsionicPowerAction = null; + [DataField("metapsionicActionId", + customTypeSerializer: typeof(PrototypeIdSerializer))] + public string? MetapsionicActionId = "ActionMetapsionic"; + + [DataField("metapsionicActionEntity")] + public EntityUid? MetapsionicActionEntity; + } +} diff --git a/Content.Shared/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs similarity index 76% rename from Content.Shared/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs rename to Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs index 94b73c41e38..6a3fc811c89 100644 --- a/Content.Shared/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs @@ -1,7 +1,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Psionics.Abilities +namespace Content.Shared.Abilities.Psionics { [RegisterComponent] public sealed partial class MindSwapPowerComponent : Component @@ -12,8 +12,5 @@ public sealed partial class MindSwapPowerComponent : Component [DataField("mindSwapActionEntity")] public EntityUid? MindSwapActionEntity; - - [DataField("mindSwapFeedback")] - public string MindSwapFeedback = "mind-swap-feedback"; } } diff --git a/Content.Shared/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs similarity index 77% rename from Content.Shared/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs rename to Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs index 997db65e1b1..0e91894b1dc 100644 --- a/Content.Shared/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs @@ -2,7 +2,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Psionics.Abilities +namespace Content.Shared.Abilities.Psionics { [RegisterComponent] public sealed partial class NoosphericZapPowerComponent : Component @@ -13,8 +13,5 @@ public sealed partial class NoosphericZapPowerComponent : Component [DataField("noosphericZapActionEntity")] public EntityUid? NoosphericZapActionEntity; - - [DataField("noosphericZapFeedback")] - public string NoosphericZapFeedback = "noospheric-zap-feedback"; } } diff --git a/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs similarity index 71% rename from Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs rename to Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs index d9c36f5b22a..3e198aa9303 100644 --- a/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs @@ -1,7 +1,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Psionics.Abilities +namespace Content.Shared.Abilities.Psionics { [RegisterComponent] public sealed partial class PsionicInvisibilityPowerComponent : Component @@ -12,11 +12,5 @@ public sealed partial class PsionicInvisibilityPowerComponent : Component [DataField("psionicInvisibilityActionEntity")] public EntityUid? PsionicInvisibilityActionEntity; - - [DataField("InvisibilityFeedback")] - public string InvisibilityFeedback = "invisibility-feedback"; - - [DataField("UseTimer")] - public float UseTimer = 30f; } } diff --git a/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs similarity index 94% rename from Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs rename to Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs index 2a9dd7642ba..9037b8bcdfe 100644 --- a/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs @@ -1,7 +1,6 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Shared.Psionics.Abilities +namespace Content.Shared.Abilities.Psionics { [RegisterComponent] public sealed partial class PsionicInvisibilityUsedComponent : Component diff --git a/Content.Shared/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs similarity index 76% rename from Content.Shared/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs rename to Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs index 3184bf7de5b..4a62e84d191 100644 --- a/Content.Shared/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs @@ -3,7 +3,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Psionics.Abilities +namespace Content.Shared.Abilities.Psionics { [RegisterComponent] public sealed partial class PsionicRegenerationPowerComponent : Component @@ -12,7 +12,7 @@ public sealed partial class PsionicRegenerationPowerComponent : Component public DoAfterId? DoAfter; [DataField("essence")] - public float EssenceAmount = 10; + public float EssenceAmount = 20; [DataField("useDelay")] public float UseDelay = 8f; @@ -26,12 +26,6 @@ public sealed partial class PsionicRegenerationPowerComponent : Component [DataField("psionicRegenerationActionEntity")] public EntityUid? PsionicRegenerationActionEntity; - - [DataField("regenerationFeedback")] - public string RegenerationFeedback = "regeneration-feedback"; - - [DataField("selfRevive")] - public bool SelfRevive { get; set; } = false; } } diff --git a/Content.Shared/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs similarity index 79% rename from Content.Shared/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs rename to Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs index 1f88741b9a9..28425afdb4c 100644 --- a/Content.Shared/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs @@ -2,7 +2,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Psionics.Abilities +namespace Content.Shared.Abilities.Psionics { [RegisterComponent] public sealed partial class PyrokinesisPowerComponent : Component @@ -14,8 +14,5 @@ public sealed partial class PyrokinesisPowerComponent : Component [DataField("pyrokinesisActionEntity")] public EntityUid? PyrokinesisActionEntity; - - [DataField("pyrokinesisFeedback")] - public string PyrokinesisFeedback = "pyrokinesis-feedback"; } } diff --git a/Content.Shared/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs similarity index 73% rename from Content.Shared/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs rename to Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs index f1a71332b18..51958822a41 100644 --- a/Content.Shared/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs @@ -3,7 +3,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Psionics.Abilities +namespace Content.Shared.Abilities.Psionics { [RegisterComponent] public sealed partial class TelegnosisPowerComponent : Component @@ -19,11 +19,5 @@ public sealed partial class TelegnosisPowerComponent : Component [DataField("telegnosisActionEntity")] public EntityUid? TelegnosisActionEntity; - - [DataField("telegnosisFeedback")] - public string TelegnosisFeedback = "telegnosis-feedback"; - public EntityUid OriginalEntity = default!; - public EntityUid ProjectionUid = default!; - public bool IsProjecting = false; } -} +} \ No newline at end of file diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs new file mode 100644 index 00000000000..9d627cb42d8 --- /dev/null +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs @@ -0,0 +1,6 @@ +namespace Content.Shared.Abilities.Psionics +{ + [RegisterComponent] + public sealed partial class TelegnosticProjectionComponent : Component + {} +} \ No newline at end of file diff --git a/Content.Shared/Psionics/Items/ClothingGrantPsionicPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/ClothingGrantPsionicPowerComponent.cs similarity index 84% rename from Content.Shared/Psionics/Items/ClothingGrantPsionicPowerComponent.cs rename to Content.Shared/Nyanotrasen/Abilities/Psionics/Items/ClothingGrantPsionicPowerComponent.cs index f09efc3064c..4cbb05c8395 100644 --- a/Content.Shared/Psionics/Items/ClothingGrantPsionicPowerComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/ClothingGrantPsionicPowerComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Shared.Psionics.Abilities +namespace Content.Shared.Abilities.Psionics { [RegisterComponent] public sealed partial class ClothingGrantPsionicPowerComponent : Component diff --git a/Content.Shared/Psionics/Items/HeadCageComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/HeadCageComponent.cs similarity index 96% rename from Content.Shared/Psionics/Items/HeadCageComponent.cs rename to Content.Shared/Nyanotrasen/Abilities/Psionics/Items/HeadCageComponent.cs index c03241e47c7..acaa832860f 100644 --- a/Content.Shared/Psionics/Items/HeadCageComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/HeadCageComponent.cs @@ -1,7 +1,7 @@ using System.Threading; using Robust.Shared.Audio; -namespace Content.Shared.Psionics.Abilities +namespace Content.Shared.Abilities.Psionics { [RegisterComponent] public sealed partial class HeadCageComponent : Component diff --git a/Content.Shared/Psionics/Items/HeadCagedComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/HeadCagedComponent.cs similarity index 81% rename from Content.Shared/Psionics/Items/HeadCagedComponent.cs rename to Content.Shared/Nyanotrasen/Abilities/Psionics/Items/HeadCagedComponent.cs index 0f826f7a05e..f8af46b8878 100644 --- a/Content.Shared/Psionics/Items/HeadCagedComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/HeadCagedComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Shared.Psionics.Abilities +namespace Content.Shared.Abilities.Psionics { [RegisterComponent] /// diff --git a/Content.Shared/Psionics/Items/PsionicItemsSystem.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/PsionicItemsSystem.cs similarity index 98% rename from Content.Shared/Psionics/Items/PsionicItemsSystem.cs rename to Content.Shared/Nyanotrasen/Abilities/Psionics/Items/PsionicItemsSystem.cs index 950353c5dfb..f88acf61f3c 100644 --- a/Content.Shared/Psionics/Items/PsionicItemsSystem.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/PsionicItemsSystem.cs @@ -2,7 +2,7 @@ using Content.Shared.Clothing.Components; using Content.Shared.StatusEffect; -namespace Content.Shared.Psionics.Abilities +namespace Content.Shared.Abilities.Psionics { public sealed class PsionicItemsSystem : EntitySystem { diff --git a/Content.Shared/Psionics/Items/TinfoilHatComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/TinfoilHatComponent.cs similarity index 90% rename from Content.Shared/Psionics/Items/TinfoilHatComponent.cs rename to Content.Shared/Nyanotrasen/Abilities/Psionics/Items/TinfoilHatComponent.cs index 6ef7bdc823b..5086b9f4977 100644 --- a/Content.Shared/Psionics/Items/TinfoilHatComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/TinfoilHatComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Shared.Psionics.Abilities +namespace Content.Shared.Abilities.Psionics { [RegisterComponent] public sealed partial class TinfoilHatComponent : Component diff --git a/Content.Shared/Psionics/PsionicComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicComponent.cs similarity index 51% rename from Content.Shared/Psionics/PsionicComponent.cs rename to Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicComponent.cs index 9a06e54cb31..9091e03cfc3 100644 --- a/Content.Shared/Psionics/PsionicComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicComponent.cs @@ -1,6 +1,7 @@ +using Content.Shared.Actions; using Robust.Shared.GameStates; -namespace Content.Shared.Psionics.Abilities +namespace Content.Shared.Abilities.Psionics { [RegisterComponent, NetworkedComponent] public sealed partial class PsionicComponent : Component @@ -14,17 +15,6 @@ public sealed partial class PsionicComponent : Component public bool Removable = true; [DataField("activePowers")] - public List ActivePowers = new(); - - [DataField("psychicFeedback")] - public List PsychicFeedback = new(); - - [DataField("amplification")] - public float Amplification = 0.1f; - - [DataField("dampening")] - public float Dampening = 0.1f; - public bool Telepath = false; - public bool InnatePsiChecked = false; + public HashSet ActivePowers = new(); } } diff --git a/Content.Shared/Psionics/PsionicInsulationComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicInsulationComponent.cs similarity index 82% rename from Content.Shared/Psionics/PsionicInsulationComponent.cs rename to Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicInsulationComponent.cs index 2ab054b1f8f..12370da5ae4 100644 --- a/Content.Shared/Psionics/PsionicInsulationComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicInsulationComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Shared.Psionics.Abilities +namespace Content.Shared.Abilities.Psionics { [RegisterComponent] public sealed partial class PsionicInsulationComponent : Component diff --git a/Content.Shared/Psionics/PsionicsDisabledComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicsDisabledComponent.cs similarity index 84% rename from Content.Shared/Psionics/PsionicsDisabledComponent.cs rename to Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicsDisabledComponent.cs index 00cf5506523..28e7157a9d2 100644 --- a/Content.Shared/Psionics/PsionicsDisabledComponent.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicsDisabledComponent.cs @@ -1,6 +1,6 @@ using Robust.Shared.GameStates; -namespace Content.Shared.Psionics.Abilities +namespace Content.Shared.Abilities.Psionics { /// /// Only use this for the status effect, please. diff --git a/Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/SharedPsionicAbilitiesSystem.cs similarity index 97% rename from Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs rename to Content.Shared/Nyanotrasen/Abilities/Psionics/SharedPsionicAbilitiesSystem.cs index 603c5188a52..2739d5ba31a 100644 --- a/Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs +++ b/Content.Shared/Nyanotrasen/Abilities/Psionics/SharedPsionicAbilitiesSystem.cs @@ -7,7 +7,7 @@ using Robust.Shared.Random; using Robust.Shared.Serialization; -namespace Content.Shared.Psionics.Abilities +namespace Content.Shared.Abilities.Psionics { public sealed class SharedPsionicAbilitiesSystem : EntitySystem { @@ -73,7 +73,7 @@ public void SetPsionicsThroughEligibility(EntityUid uid) if (actionData == null) return; - _actions.SetEnabled(uid, IsEligibleForPsionics(uid)); + _actions.SetEnabled(actionData.Owner, IsEligibleForPsionics(uid)); } private bool IsEligibleForPsionics(EntityUid uid) diff --git a/Content.Shared/Nyanotrasen/Actions/Events/MassSleepPowerActionEvent.cs b/Content.Shared/Nyanotrasen/Actions/Events/MassSleepPowerActionEvent.cs new file mode 100644 index 00000000000..6666ee48d6c --- /dev/null +++ b/Content.Shared/Nyanotrasen/Actions/Events/MassSleepPowerActionEvent.cs @@ -0,0 +1,2 @@ +namespace Content.Shared.Actions.Events; +public sealed partial class MassSleepPowerActionEvent : WorldTargetActionEvent {} diff --git a/Content.Shared/Nyanotrasen/Actions/Events/MetapsionicPowerActionEvent.cs b/Content.Shared/Nyanotrasen/Actions/Events/MetapsionicPowerActionEvent.cs index b7c3c8ad2d6..b28801efe74 100644 --- a/Content.Shared/Nyanotrasen/Actions/Events/MetapsionicPowerActionEvent.cs +++ b/Content.Shared/Nyanotrasen/Actions/Events/MetapsionicPowerActionEvent.cs @@ -1,3 +1,2 @@ namespace Content.Shared.Actions.Events; -public sealed partial class WideMetapsionicPowerActionEvent : InstantActionEvent { } -public sealed partial class FocusedMetapsionicPowerActionEvent : EntityTargetActionEvent { } +public sealed partial class MetapsionicPowerActionEvent : InstantActionEvent {} diff --git a/Content.Shared/Nyanotrasen/Actions/Events/PyrokinesisPowerActionEvent.cs b/Content.Shared/Nyanotrasen/Actions/Events/PyrokinesisPowerActionEvent.cs index 4639aadd55b..896ec0bb63d 100644 --- a/Content.Shared/Nyanotrasen/Actions/Events/PyrokinesisPowerActionEvent.cs +++ b/Content.Shared/Nyanotrasen/Actions/Events/PyrokinesisPowerActionEvent.cs @@ -1,4 +1,2 @@ namespace Content.Shared.Actions.Events; -public sealed partial class PyrokinesisPowerActionEvent : WorldTargetActionEvent {} - - +public sealed partial class PyrokinesisPowerActionEvent : EntityTargetActionEvent {} diff --git a/Content.Shared/Nyanotrasen/Actions/Events/RegenerativeStasisPowerActionEvent.cs b/Content.Shared/Nyanotrasen/Actions/Events/RegenerativeStasisPowerActionEvent.cs deleted file mode 100644 index 4435f475a44..00000000000 --- a/Content.Shared/Nyanotrasen/Actions/Events/RegenerativeStasisPowerActionEvent.cs +++ /dev/null @@ -1,2 +0,0 @@ -namespace Content.Shared.Actions.Events; -public sealed partial class RegenerativeStasisPowerActionEvent : EntityTargetActionEvent {} diff --git a/Content.Shared/Nyanotrasen/Psionics/Events.cs b/Content.Shared/Nyanotrasen/Psionics/Events.cs new file mode 100644 index 00000000000..cf9a50c6e18 --- /dev/null +++ b/Content.Shared/Nyanotrasen/Psionics/Events.cs @@ -0,0 +1,28 @@ +using Robust.Shared.Serialization; +using Content.Shared.DoAfter; + +namespace Content.Shared.Psionics.Events +{ + [Serializable, NetSerializable] + public sealed partial class PsionicRegenerationDoAfterEvent : DoAfterEvent + { + [DataField("startedAt", required: true)] + public TimeSpan StartedAt; + + private PsionicRegenerationDoAfterEvent() + { + } + + public PsionicRegenerationDoAfterEvent(TimeSpan startedAt) + { + StartedAt = startedAt; + } + + public override DoAfterEvent Clone() => this; + } + + [Serializable, NetSerializable] + public sealed partial class GlimmerWispDrainDoAfterEvent : SimpleDoAfterEvent + { + } +} diff --git a/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs b/Content.Shared/Nyanotrasen/Psionics/Glimmer/GlimmerSystem.cs similarity index 98% rename from Content.Shared/Psionics/Glimmer/GlimmerSystem.cs rename to Content.Shared/Nyanotrasen/Psionics/Glimmer/GlimmerSystem.cs index 8be02f936a9..31af85bbb51 100644 --- a/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs +++ b/Content.Shared/Nyanotrasen/Psionics/Glimmer/GlimmerSystem.cs @@ -40,7 +40,7 @@ public GlimmerTier GetGlimmerTier(int? glimmer = null) if (glimmer == null) glimmer = Glimmer; - return glimmer switch + return (glimmer) switch { <= 49 => GlimmerTier.Minimal, >= 50 and <= 99 => GlimmerTier.Low, diff --git a/Content.Shared/Psionics/Glimmer/SharedGlimmerReactiveComponent.cs b/Content.Shared/Nyanotrasen/Psionics/Glimmer/SharedGlimmerReactiveComponent.cs similarity index 100% rename from Content.Shared/Psionics/Glimmer/SharedGlimmerReactiveComponent.cs rename to Content.Shared/Nyanotrasen/Psionics/Glimmer/SharedGlimmerReactiveComponent.cs diff --git a/Content.Shared/Psionics/Glimmer/SharedGlimmerReactiveVisuals.cs b/Content.Shared/Nyanotrasen/Psionics/Glimmer/SharedGlimmerReactiveVisuals.cs similarity index 100% rename from Content.Shared/Psionics/Glimmer/SharedGlimmerReactiveVisuals.cs rename to Content.Shared/Nyanotrasen/Psionics/Glimmer/SharedGlimmerReactiveVisuals.cs diff --git a/Content.Shared/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs b/Content.Shared/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs deleted file mode 100644 index 2fbfe18327e..00000000000 --- a/Content.Shared/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Content.Shared.DoAfter; -using Robust.Shared.Audio; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Shared.Psionics.Abilities -{ - [RegisterComponent] - public sealed partial class MetapsionicPowerComponent : Component - { - [DataField("doAfter")] - public DoAfterId? DoAfter; - - [DataField("useDelay")] - public float UseDelay = 8f; - [DataField("soundUse")] - - public SoundSpecifier SoundUse = new SoundPathSpecifier("/Audio/Nyanotrasen/heartbeat_fast.ogg"); - - [DataField("range")] - public float Range = 5f; - - [DataField("actionWideMetapsionic", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string ActionWideMetapsionic = "ActionWideMetapsionic"; - - [DataField("actionWideMetapsionicEntity")] - public EntityUid? ActionWideMetapsionicEntity; - - [DataField("actionFocusedMetapsionic", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string ActionFocusedMetapsionic = "ActionFocusedMetapsionic"; - - [DataField("actionFocusedMetapsionicEntity")] - public EntityUid? ActionFocusedMetapsionicEntity; - - [DataField("metapsionicFeedback")] - public string MetapsionicFeedback = "metapsionic-feedback"; - } -} diff --git a/Content.Shared/Psionics/Abilities/RegenerativeStasis/RegenerativeStasisPowerComponent.cs b/Content.Shared/Psionics/Abilities/RegenerativeStasis/RegenerativeStasisPowerComponent.cs deleted file mode 100644 index 27a0903e224..00000000000 --- a/Content.Shared/Psionics/Abilities/RegenerativeStasis/RegenerativeStasisPowerComponent.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Content.Shared.Actions; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Shared.Psionics.Abilities -{ - [RegisterComponent] - public sealed partial class RegenerativeStasisPowerComponent : Component - { - [DataField("regenerativeStasisActionId", - customTypeSerializer: typeof(PrototypeIdSerializer))] - public string? RegenerativeStasisActionId = "ActionRegenerativeStasis"; - - [DataField("regenerativeStasisActionEntity")] - public EntityUid? RegenerativeStasisActionEntity; - - [DataField("regenerativeStasisFeedback")] - public string RegenerativeStasisFeedback = "regenerative-stasis-feedback"; - } -} diff --git a/Content.Shared/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs b/Content.Shared/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs deleted file mode 100644 index bc18ff9f3c2..00000000000 --- a/Content.Shared/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Content.Shared.Psionics.Abilities -{ - [RegisterComponent] - public sealed partial class TelegnosticProjectionComponent : Component - { - public EntityUid OriginalEntity = default!; - } -} diff --git a/Content.Shared/Psionics/Events.cs b/Content.Shared/Psionics/Events.cs deleted file mode 100644 index 45a00b5f048..00000000000 --- a/Content.Shared/Psionics/Events.cs +++ /dev/null @@ -1,64 +0,0 @@ -using Robust.Shared.Serialization; -using Content.Shared.DoAfter; - -namespace Content.Shared.Psionics.Events -{ - [Serializable, NetSerializable] - public sealed partial class PsionicRegenerationDoAfterEvent : DoAfterEvent - { - [DataField("startedAt", required: true)] - public TimeSpan StartedAt; - - private PsionicRegenerationDoAfterEvent() - { - } - - public PsionicRegenerationDoAfterEvent(TimeSpan startedAt) - { - StartedAt = startedAt; - } - - public override DoAfterEvent Clone() => this; - } - - [Serializable, NetSerializable] - public sealed partial class PsionicInvisibilityTimerEvent : DoAfterEvent - { - [DataField("startedAt", required: true)] - public TimeSpan StartedAt; - - private PsionicInvisibilityTimerEvent() - { - } - - public PsionicInvisibilityTimerEvent(TimeSpan startedAt) - { - StartedAt = startedAt; - } - - public override DoAfterEvent Clone() => this; - } - - [Serializable, NetSerializable] - public sealed partial class FocusedMetapsionicDoAfterEvent : DoAfterEvent - { - [DataField("startedAt", required: true)] - public TimeSpan StartedAt; - - private FocusedMetapsionicDoAfterEvent() - { - } - - public FocusedMetapsionicDoAfterEvent(TimeSpan startedAt) - { - StartedAt = startedAt; - } - - public override DoAfterEvent Clone() => this; - } - - [Serializable, NetSerializable] - public sealed partial class GlimmerWispDrainDoAfterEvent : SimpleDoAfterEvent - { - } -} diff --git a/Content.Shared/Psionics/SharedPsionicSystem.Insulated.cs b/Content.Shared/Psionics/SharedPsionicSystem.Insulated.cs deleted file mode 100644 index 5c89f39354c..00000000000 --- a/Content.Shared/Psionics/SharedPsionicSystem.Insulated.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Content.Shared.Psionics -{ - public readonly record struct PsionicInsulationEvent; -} diff --git a/Content.Shared/Throwing/ThrowingSystem.cs b/Content.Shared/Throwing/ThrowingSystem.cs index 01682863389..54294318315 100644 --- a/Content.Shared/Throwing/ThrowingSystem.cs +++ b/Content.Shared/Throwing/ThrowingSystem.cs @@ -160,7 +160,7 @@ public void TryThrow(EntityUid uid, } else { - _physics.SetBodyStatus(uid, physics, BodyStatus.InAir); + _physics.SetBodyStatus(physics, BodyStatus.InAir); } if (user == null) @@ -176,10 +176,10 @@ public void TryThrow(EntityUid uid, { var msg = new ThrowPushbackAttemptEvent(); RaiseLocalEvent(uid, msg); - const float massLimit = 5f; + const float MassLimit = 5f; if (!msg.Cancelled) - _physics.ApplyLinearImpulse(user.Value, -impulseVector / physics.Mass * pushbackRatio * MathF.Min(massLimit, physics.Mass), body: userPhysics); + _physics.ApplyLinearImpulse(user.Value, -impulseVector / physics.Mass * pushbackRatio * MathF.Min(MassLimit, physics.Mass), body: userPhysics); } } } diff --git a/Content.Shared/Throwing/ThrownItemSystem.cs b/Content.Shared/Throwing/ThrownItemSystem.cs index cc50094e3dd..b3b5bcf7870 100644 --- a/Content.Shared/Throwing/ThrownItemSystem.cs +++ b/Content.Shared/Throwing/ThrownItemSystem.cs @@ -93,7 +93,7 @@ public void StopThrow(EntityUid uid, ThrownItemComponent thrownItemComponent) { if (TryComp(uid, out var physics)) { - _physics.SetBodyStatus(uid, physics, BodyStatus.OnGround); + _physics.SetBodyStatus(physics, BodyStatus.OnGround); if (physics.Awake) _broadphase.RegenerateContacts(uid, physics); diff --git a/Content.Shared/Weapons/Melee/MeleeThrowOnHitSystem.cs b/Content.Shared/Weapons/Melee/MeleeThrowOnHitSystem.cs index e0696022606..e840bd1ddd5 100644 --- a/Content.Shared/Weapons/Melee/MeleeThrowOnHitSystem.cs +++ b/Content.Shared/Weapons/Melee/MeleeThrowOnHitSystem.cs @@ -74,7 +74,7 @@ private void OnThrownStartup(Entity ent, ref ComponentStar comp.PreviousStatus = body.BodyStatus; comp.ThrownEndTime = _timing.CurTime + TimeSpan.FromSeconds(comp.Lifetime); comp.MinLifetimeTime = _timing.CurTime + TimeSpan.FromSeconds(comp.MinLifetime); - _physics.SetBodyStatus(ent, body, BodyStatus.InAir); + _physics.SetBodyStatus(body, BodyStatus.InAir); _physics.SetLinearVelocity(ent, Vector2.Zero, body: body); _physics.ApplyLinearImpulse(ent, comp.Velocity * body.Mass, body: body); Dirty(ent, ent.Comp); @@ -83,7 +83,7 @@ private void OnThrownStartup(Entity ent, ref ComponentStar private void OnThrownShutdown(Entity ent, ref ComponentShutdown args) { if (TryComp(ent, out var body)) - _physics.SetBodyStatus(ent, body, ent.Comp.PreviousStatus); + _physics.SetBodyStatus(body,ent.Comp.PreviousStatus); var ev = new MeleeThrowOnHitEndEvent(); RaiseLocalEvent(ent, ref ev); } diff --git a/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs b/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs index 3a950bcd29e..177cb310d18 100644 --- a/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs +++ b/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs @@ -207,12 +207,12 @@ protected virtual void StartTether(EntityUid gunUid, BaseForceGunComponent compo TransformSystem.Unanchor(target, targetXform); component.Tethered = target; var tethered = EnsureComp(target); - _physics.SetBodyStatus(target, targetPhysics, BodyStatus.InAir, false); + _physics.SetBodyStatus(targetPhysics, BodyStatus.InAir, false); _physics.SetSleepingAllowed(target, targetPhysics, false); tethered.Tetherer = gunUid; tethered.OriginalAngularDamping = targetPhysics.AngularDamping; - _physics.SetAngularDamping(target, targetPhysics, 0f); - _physics.SetLinearDamping(target, targetPhysics, 0f); + _physics.SetAngularDamping(targetPhysics, 0f); + _physics.SetLinearDamping(targetPhysics, 0f); _physics.SetAngularVelocity(target, SpinVelocity, body: targetPhysics); _physics.WakeBody(target, body: targetPhysics); var thrown = EnsureComp(component.Tethered.Value); @@ -264,9 +264,9 @@ protected virtual void StopTether(EntityUid gunUid, BaseForceGunComponent compon _thrown.StopThrow(component.Tethered.Value, thrown); } - _physics.SetBodyStatus(component.Tethered.Value, targetPhysics, BodyStatus.OnGround); + _physics.SetBodyStatus(targetPhysics, BodyStatus.OnGround); _physics.SetSleepingAllowed(component.Tethered.Value, targetPhysics, true); - _physics.SetAngularDamping(component.Tethered.Value, targetPhysics, Comp(component.Tethered.Value).OriginalAngularDamping); + _physics.SetAngularDamping(targetPhysics, Comp(component.Tethered.Value).OriginalAngularDamping); } if (!transfer) diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs index d3aee5a48e9..36b5bbd1927 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs @@ -388,7 +388,7 @@ public abstract void Shoot( public void ShootProjectile(EntityUid uid, Vector2 direction, Vector2 gunVelocity, EntityUid gunUid, EntityUid? user = null, float speed = 20f) { var physics = EnsureComp(uid); - Physics.SetBodyStatus(uid, physics, BodyStatus.InAir); + Physics.SetBodyStatus(physics, BodyStatus.InAir); var targetMapVelocity = gunVelocity + direction.Normalized() * speed; var currentMapVelocity = Physics.GetMapLinearVelocity(uid, physics); diff --git a/Resources/Audio/Nyanotrasen/heartbeat_fast.ogg b/Resources/Audio/Nyanotrasen/heartbeat_fast.ogg deleted file mode 100644 index 85a034d9bd0017dafea7df4128235c815babac0c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 39983 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 diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index ba49523cfde..954f86aa044 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -4080,17 +4080,3 @@ Entries: you join when someone leaves. id: 6110 time: '2024-05-13T04:58:39.0000000+00:00' -- author: LovelyLophi - changes: - - type: Add - message: Added a number of new corporate coats to the Clothesmate. - id: 6111 - time: '2024-05-22T03:35:11.0000000+00:00' -- author: VMSolidus - changes: - - type: Tweak - message: >- - Syndicate Listening Posts can now appear any time in a round, and can - appear on low-pop servers. - id: 6112 - time: '2024-05-28T23:44:39.0000000+00:00' diff --git a/Resources/Credits/GitHub.txt b/Resources/Credits/GitHub.txt index db58663a2b2..3aea674fd94 100644 --- a/Resources/Credits/GitHub.txt +++ b/Resources/Credits/GitHub.txt @@ -1 +1 @@ -0x6273, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 4dplanner, 612git, 778b, Ablankmann, Acruid, actioninja, adamsong, Admiral-Obvious-001, Adrian16199, Aerocrux, Aexxie, africalimedrop, Agoichi, Ahion, AJCM-git, AjexRose, Alekshhh, AlexMorgan3817, AlmondFlour, AlphaQwerty, Altoids1, amylizzle, ancientpower, ArchPigeon, Arendian, arimah, Arteben, AruMoon, as334, AsikKEsel, asperger-sind, aspiringLich, avghdev, AzzyIsNotHere, BananaFlambe, BasedUser, BGare, BingoJohnson-zz, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, Boaz1111, BobdaBiscuit, brainfood1183, Brandon-Huu, Bribrooo, Bright0, brndd, BubblegumBlue, BYONDFuckery, c4llv07e, CakeQ, CaptainSqrBeard, Carbonhell, Carolyn3114, casperr04, CatTheSystem, Centronias, chairbender, Charlese2, Cheackraze, cheesePizza2, Chief-Engineer, chromiumboy, Chronophylos, clement-or, Clyybber, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, coolmankid12345, corentt, crazybrain23, creadth, CrigCrag, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, Daemon, daerSeebaer, dahnte, dakamakat, dakimasu, DamianX, DangerRevolution, daniel-cr, Darkenson, DawBla, dch-GH, Deahaka, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, deepdarkdepths, Delete69, deltanedas, DeltaV-Bot, DerbyX, DoctorBeard, DogZeroX, dontbetank, Doru991, DoubleRiceEddiedd, DrMelon, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, Dutch-VanDerLinde, Easypoller, eclips_e, EdenTheLiznerd, EEASAS, Efruit, ElectroSR, elthundercloud, Emisse, EmoGarbage404, Endecc, enumerate0, eoineoineoin, ERORR404V1, Errant-4, estacaoespacialpirata, exincore, exp111, Fahasor, FairlySadPanda, ficcialfaint, Fildrance, FillerVK, Fishfish458, Flareguy, FluffiestFloof, FluidRock, FoLoKe, fooberticus, Fortune117, freeman2651, Fromoriss, FungiFellow, GalacticChimp, gbasood, Geekyhobo, Genkail, Git-Nivrak, github-actions[bot], gituhabu, GNF54, Golinth, GoodWheatley, Gotimanga, graevy, GreyMario, Guess-My-Name, gusxyz, h3half, Hanzdegloker, Hardly3D, harikattar, Hebiman, Henry12116, HerCoyote23, Hmeister-real, HoofedEar, hord-brayden, hubismal, Hugal31, Hyenh, iacore, IamVelcroboy, icekot8, igorsaux, ike709, Illiux, Ilya246, IlyaElDunaev, Injazz, Insineer, IntegerTempest, Interrobang01, IProduceWidgets, ItsMeThom, j-giebel, Jackal298, Jackrost, jamessimo, janekvap, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JoeHammad1844, joelhed, JohnGinnane, johnku1, joshepvodka, jproads, Jrpl, juliangiebel, JustArt1m, JustCone14, JustinTether, JustinTrotter, KaiShibaa, kalane15, kalanosh, KEEYNy, Keikiru, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, KingFroozy, kira-er, Kit0vras, KittenColony, Kmc2000, Ko4ergaPunk, komunre, koteq, Krunklehorn, Kukutis96513, kxvvv, Lamrr, LankLTE, lapatison, Leander-0, leonardo-dabepis, LetterN, Level10Cybermancer, lever1209, LightVillet, liltenhead, LittleBuilderJane, Lomcastar, LordCarve, LordEclipse, LovelyLophi, LudwigVonChesterfield, Lukasz825700516, lunarcomets, luringens, lvvova1, lzimann, lzk228, M3739, MACMAN2003, Macoron, MagnusCrowe, ManelNavola, matthst, Matz05, MehimoNemo, MeltedPixel, MemeProof, Menshin, Mervill, metalgearsloth, mhamsterr, MilenVolf, Minty642, Mirino97, mirrorcult, MishaUnity, MisterMecky, Mith-randalf, Moneyl, Moomoobeef, moony, Morb0, Mr0maks, musicmanvr, Myakot, Myctai, N3X15, Nairodian, Naive817, namespace-Memory, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, nmajask, nok-ko, Nopey, notafet, notquitehadouken, noudoit, noverd, nuke-haus, NULL882, OCOtheOmega, OctoRocket, OldDanceJacket, onoira, Owai-Seek, pali6, Pangogie, patrikturi, PaulRitter, Peptide90, peptron1, Phantom-Lily, PHCodes, PixelTheKermit, PJB3005, Plykiya, pofitlo, pointer-to-null, PolterTzi, PoorMansDreams, potato1234x, ProfanedBane, PrPleGoo, ps3moira, Psychpsyo, psykzz, PuroSlavKing, quatre, QuietlyWhisper, qwerltaz, Radosvik, Radrark, Rainbeon, Rainfey, Rane, ravage123321, rbertoche, Redict, RedlineTriad, RednoWCirabrab, RemberBM, RemieRichards, RemTim, rene-descartes2021, RiceMar1244, RieBi, Rinkashikachi, Rockdtben, rolfero, rosieposieeee, Saakra, Samsterious, SaphireLattice, ScalyChimp, scrato, Scribbles0, Serkket, SethLafuente, ShadowCommander, Shadowtheprotogen546, SignalWalker, SimpleStation14, Simyon264, SirDragooon, Sirionaut, siyengar04, Skarletto, Skrauz, Skyedra, SlamBamActionman, Slava0135, Snowni, snowsignal, SonicHDC, SoulSloth, SpaceManiac, SpeltIncorrectyl, spoogemonster, ssdaniel24, Stealthbomber16, stellar-novas, StrawberryMoses, Subversionary, SweptWasTaken, Szunti, TadJohnson00, takemysoult, TaralGit, Tayrtahn, tday93, TekuNut, TemporalOroboros, tentekal, tgrkzus, thatrandomcanadianguy, TheArturZh, theashtronaut, thedraccx, themias, theomund, theOperand, TheShuEd, TimrodDX, Titian3, tkdrg, tmtmtl30, tom-leys, tomasalves8, Tomeno, tosatur, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, Tyler-IN, Tyzemol, UbaserB, UKNOWH, UnicornOnLSD, Uriende, UristMcDorf, Vaaankas, Varen, VasilisThePikachu, veliebm, Veritius, Verslebas, VigersRay, Visne, VMSolidus, volundr-, Voomra, Vordenburg, vulppine, waylon531, weaversam8, Willhelm53, wixoaGit, WlarusFromDaSpace, wrexbe, xRiriq, yathxyz, Ygg01, YotaXP, YuriyKiss, zach-hill, Zandario, Zap527, ZelteHonor, zerorulez, zionnBE, zlodo, ZNixian, ZoldorfTheWizard, Zumorica, Zymem +0x6273, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 4dplanner, 612git, 778b, Ablankmann, Acruid, actioninja, adamsong, Admiral-Obvious-001, Adrian16199, Aerocrux, Aexxie, africalimedrop, Agoichi, Ahion, AJCM-git, AjexRose, Alekshhh, AlexMorgan3817, AlmondFlour, AlphaQwerty, Altoids1, amylizzle, ancientpower, ArchPigeon, Arendian, arimah, Arteben, AruMoon, as334, AsikKEsel, asperger-sind, aspiringLich, avghdev, AzzyIsNotHere, BananaFlambe, BasedUser, BGare, BingoJohnson-zz, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, Boaz1111, BobdaBiscuit, brainfood1183, Brandon-Huu, Bribrooo, Bright0, brndd, BubblegumBlue, BYONDFuckery, c4llv07e, CakeQ, CaptainSqrBeard, Carbonhell, Carolyn3114, casperr04, CatTheSystem, Centronias, chairbender, Charlese2, Cheackraze, cheesePizza2, Chief-Engineer, chromiumboy, Chronophylos, clement-or, Clyybber, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, coolmankid12345, corentt, crazybrain23, creadth, CrigCrag, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, Daemon, daerSeebaer, dahnte, dakamakat, dakimasu, DamianX, DangerRevolution, daniel-cr, Darkenson, DawBla, dch-GH, Deahaka, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, deepdarkdepths, Delete69, deltanedas, DeltaV-Bot, DerbyX, DoctorBeard, DogZeroX, dontbetank, Doru991, DoubleRiceEddiedd, DrMelon, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, Dutch-VanDerLinde, Easypoller, eclips_e, EdenTheLiznerd, EEASAS, Efruit, ElectroSR, elthundercloud, Emisse, EmoGarbage404, Endecc, enumerate0, eoineoineoin, ERORR404V1, Errant-4, estacaoespacialpirata, exincore, exp111, Fahasor, FairlySadPanda, ficcialfaint, Fildrance, FillerVK, Fishfish458, Flareguy, FluffiestFloof, FluidRock, FoLoKe, fooberticus, Fortune117, freeman2651, Fromoriss, FungiFellow, GalacticChimp, gbasood, Geekyhobo, Genkail, Git-Nivrak, github-actions[bot], gituhabu, GNF54, Golinth, GoodWheatley, Gotimanga, graevy, GreyMario, Guess-My-Name, gusxyz, h3half, Hanzdegloker, Hardly3D, harikattar, Hebiman, Henry12116, HerCoyote23, Hmeister-real, HoofedEar, hord-brayden, hubismal, Hugal31, Hyenh, iacore, IamVelcroboy, icekot8, igorsaux, ike709, Illiux, Ilya246, IlyaElDunaev, Injazz, Insineer, IntegerTempest, Interrobang01, IProduceWidgets, ItsMeThom, j-giebel, Jackal298, Jackrost, jamessimo, janekvap, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JoeHammad1844, joelhed, JohnGinnane, johnku1, joshepvodka, jproads, Jrpl, juliangiebel, JustArt1m, JustCone14, JustinTether, JustinTrotter, KaiShibaa, kalane15, kalanosh, KEEYNy, Keikiru, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, KingFroozy, kira-er, Kit0vras, KittenColony, Kmc2000, Ko4ergaPunk, komunre, koteq, Krunklehorn, Kukutis96513, kxvvv, Lamrr, LankLTE, lapatison, Leander-0, leonardo-dabepis, LetterN, Level10Cybermancer, lever1209, LightVillet, liltenhead, LittleBuilderJane, Lomcastar, LordCarve, LordEclipse, LudwigVonChesterfield, Lukasz825700516, lunarcomets, luringens, lvvova1, lzimann, lzk228, M3739, MACMAN2003, Macoron, MagnusCrowe, ManelNavola, matthst, Matz05, MehimoNemo, MeltedPixel, MemeProof, Menshin, Mervill, metalgearsloth, mhamsterr, MilenVolf, Minty642, Mirino97, mirrorcult, MishaUnity, MisterMecky, Mith-randalf, Moneyl, Moomoobeef, moony, Morb0, Mr0maks, musicmanvr, Myakot, Myctai, N3X15, Nairodian, Naive817, namespace-Memory, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, nmajask, nok-ko, Nopey, notafet, notquitehadouken, noudoit, noverd, nuke-haus, NULL882, OCOtheOmega, OctoRocket, OldDanceJacket, onoira, Owai-Seek, pali6, Pangogie, patrikturi, PaulRitter, Peptide90, peptron1, Phantom-Lily, PHCodes, PixelTheKermit, PJB3005, Plykiya, pofitlo, pointer-to-null, PolterTzi, PoorMansDreams, potato1234x, ProfanedBane, PrPleGoo, ps3moira, Psychpsyo, psykzz, PuroSlavKing, quatre, QuietlyWhisper, qwerltaz, Radosvik, Radrark, Rainbeon, Rainfey, Rane, ravage123321, rbertoche, Redict, RedlineTriad, RednoWCirabrab, RemberBM, RemieRichards, RemTim, rene-descartes2021, RiceMar1244, RieBi, Rinkashikachi, Rockdtben, rolfero, rosieposieeee, Saakra, Samsterious, SaphireLattice, ScalyChimp, scrato, Scribbles0, Serkket, SethLafuente, ShadowCommander, Shadowtheprotogen546, SignalWalker, SimpleStation14, Simyon264, SirDragooon, Sirionaut, siyengar04, Skarletto, Skrauz, Skyedra, SlamBamActionman, Slava0135, Snowni, snowsignal, SonicHDC, SoulSloth, SpaceManiac, SpeltIncorrectyl, spoogemonster, ssdaniel24, Stealthbomber16, stellar-novas, StrawberryMoses, Subversionary, SweptWasTaken, Szunti, TadJohnson00, takemysoult, TaralGit, Tayrtahn, tday93, TekuNut, TemporalOroboros, tentekal, tgrkzus, thatrandomcanadianguy, TheArturZh, theashtronaut, thedraccx, themias, Theomund, theOperand, TheShuEd, TimrodDX, Titian3, tkdrg, tmtmtl30, tom-leys, tomasalves8, Tomeno, tosatur, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, Tyler-IN, Tyzemol, UbaserB, UKNOWH, UnicornOnLSD, Uriende, UristMcDorf, Vaaankas, Varen, VasilisThePikachu, veliebm, Veritius, Verslebas, VigersRay, Visne, VMSolidus, volundr-, Voomra, Vordenburg, vulppine, waylon531, weaversam8, Willhelm53, wixoaGit, WlarusFromDaSpace, wrexbe, xRiriq, yathxyz, Ygg01, YotaXP, YuriyKiss, zach-hill, Zandario, Zap527, ZelteHonor, zerorulez, zionnBE, zlodo, ZNixian, ZoldorfTheWizard, Zumorica, Zymem diff --git a/Resources/Locale/en-US/atmos/commands.ftl b/Resources/Locale/en-US/atmos/commands.ftl deleted file mode 100644 index 692908d42ad..00000000000 --- a/Resources/Locale/en-US/atmos/commands.ftl +++ /dev/null @@ -1,8 +0,0 @@ -cmd-set-map-atmos-desc = Sets a map's atmosphere -cmd-set-map-atmos-help = setmapatmos [ [moles...]] -cmd-set-map-atmos-removed = Atmosphere removed from map {$map} -cmd-set-map-atmos-updated = Atmosphere set for map {$map} -cmd-set-map-atmos-hint-map = -cmd-set-map-atmos-hint-space = -cmd-set-map-atmos-hint-temp = (float) -cmd-set-map-atmos-hint-gas = <{$gas} moles> (float) diff --git a/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl b/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl index 5b368e822f1..91ae21233a3 100644 --- a/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl +++ b/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl @@ -3,11 +3,8 @@ cage-resist-third-person = {CAPITALIZE(THE($user))} starts removing {POSS-ADJ($u cage-uncage-verb = Uncage -action-name-widemetapsionic = Wide Metapsionic Pulse -action-description-widemetapsionic = Send a mental pulse through the area to see if there are any psychics nearby. - -action-name-focusedmetapsionic = Focused Metapsionic Pulse -action-description-focusedmetapsionic = Probe an entity at close range to glean metaphorical information about any powers they may have +action-name-metapsionic = Metapsionic Pulse +action-description-metapsionic = Send a mental pulse through the area to see if there are any psychics nearby. metapsionic-pulse-success = You detect psychic presence nearby. metapsionic-pulse-failure = You don't detect any psychic presence nearby. @@ -16,8 +13,8 @@ metapsionic-pulse-power = You detect that {$power} was used nearby. action-name-dispel = Dispel action-description-dispel = Dispel summoned entities such as familiars or forcewalls. -action-name-regenerative-stasis = Regenerative Stasis -action-description-regenerative-stasis = Puts the target into a brief stasis, during which time their wounds rapidly heal. +action-name-mass-sleep = Mass Sleep +action-description-mass-sleep = Put targets in a small area to sleep. accept-psionics-window-title = Psionic! accept-psionics-window-prompt-text-part = You rolled a psionic power! @@ -66,14 +63,11 @@ action-name-noospheric-zap = Noospheric Zap action-description-noospheric-zap = Shocks the conciousness of the target and leaves them stunned and stuttering. action-name-pyrokinesis = Pyrokinesis -action-description-pyrokinesis = Hurl a small gateway to the plane of Gehenna at your target. +action-description-pyrokinesis = Light a flammable target on fire. +pyrokinesis-power-used = A wisp of flame engulfs {THE($target)}, igniting {OBJECT($target)}! action-name-psychokinesis = Psychokinesis action-description-psychokinesis = Bend the fabric of space to instantly move across it. action-name-rf-sensitivity = Toggle RF Sensitivity action-desc-rf-sensitivity = Toggle your ability to interpret radio waves on and off. - -trait-latent-psychic-desc = Your mind and soul are open to the noosphere, allowing for a limited use of Telepathy. - Thus, you are eligible for potentially receiving psychic powers. - It is possible that you may be hunted by otherworldly forces, so consider keeping your powers a secret. diff --git a/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl b/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl deleted file mode 100644 index 26d2acb87cd..00000000000 --- a/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl +++ /dev/null @@ -1,21 +0,0 @@ -# Feedback messages for Focused Metapsionic Pulse -metapulse-self = I AM. -no-powers = {CAPITALIZE($entity)} will never awaken from the dream in this life -psychic-potential = {CAPITALIZE($entity)} has a slim chance of awakening from the dream -dispel-feedback = {CAPITALIZE($entity)} is a mighty stone, standing against the currents of fate -metapsionic-feedback = {CAPITALIZE($entity)} gazes back upon thee -mind-swap-feedback = {CAPITALIZE($entity)}'s vessel seems fit for other souls -mindswapped-feedback = Cursed flesh! {CAPITALIZE($entity)} dwells within the wrong vessel! -noospheric-zap-feedback = {CAPITALIZE($entity)}'s soul writhes with thunder from beyond the veil -pyrokinesis-feedback = The Secret of Fire dwells within {CAPITALIZE($entity)} -invisibility-feedback = {CAPITALIZE($entity)}'s wyrd seeks to hide from thine gaze -telegnosis-feedback = {CAPITALIZE($entity)}'s soul travels across bridges composed of dreamlight -sophic-grammateus-feedback = SEEKER, YOU NEED ONLY ASK FOR MY WISDOM. -oracle-feedback = WHY DO YOU BOTHER ME SEEKER? HAVE I NOT MADE MY DESIRES CLEAR? -metempsychotic-machine-feedback = The sea of fate flows through this machine -ifrit-feedback = A spirit of Gehenna, bound by the will of a powerful psychic - -# Power PVS Messages -focused-metapsionic-pulse-begin = The air around {CAPITALIZE($entity)} begins to shimmer faintly -psionic-regeneration-self-revive = {CAPITALIZE($entity)} begins to visibly regenerate -mindbreaking-feedback = The light of life vanishes from {CAPITALIZE($entity)}'s eyes, leaving behind a husk pretending at sapience diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml b/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml index d0ae444bf77..2165fb4e585 100644 --- a/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml +++ b/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml @@ -33,7 +33,7 @@ sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base product: CrateVendingMachineRestockClothesFilled - cost: 8050 + cost: 7245 category: cargoproduct-category-name-service group: market diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml index 04cc2e3e19d..1dbc412a9c8 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml @@ -85,11 +85,6 @@ ClothingOuterCoatLettermanRed: 2 # Nyano - Clothing addition ClothingOuterDenimJacket: 2 # DeltaV - Clothing addition ClothingOuterCorporateJacket: 2 # DeltaV - Clothing addition - ClothingOuterCsCorporateJacket: 2 # Einstein Engines - Clothing addition - ClothingOuterEECorporateJacket: 2 # Einstein Engines - Clothing addition - ClothingOuterHICorporateJacket: 2 # Einstein Engines - Clothing addition - ClothingOuterHMCorporateJacket: 2 # Einstein Engines - Clothing addition - ClothingOuterIdCorporateJacket: 2 # Einstein Engines - Clothing addition ClothingShoesBootsFishing: 2 # Nyano - Clothing addition ClothingHeadTinfoil: 2 # Nyano - Clothing addition ClothingHeadFishCap: 2 diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml index 4f255cad211..771da36719f 100644 --- a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml +++ b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml @@ -84,10 +84,7 @@ - type: PotentialPsionic - type: Psionic removable: false - amplification: 4 - psychicFeedback: - - "ifrit-feedback" - - type: PyrokinesisPower + # - type: PyrokinesisPower # Pending psionic rework - type: Grammar attributes: proper: true @@ -106,7 +103,7 @@ requirements: - !type:DepartmentTimeRequirement department: Epistemics - time: 14400 + time: 14400 # DeltaV - 4 hours - type: entity parent: WelderExperimental diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/Player/harpy.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/Player/harpy.yml index e2541def035..1f4eb696c65 100644 --- a/Resources/Prototypes/DeltaV/Entities/Mobs/Player/harpy.yml +++ b/Resources/Prototypes/DeltaV/Entities/Mobs/Player/harpy.yml @@ -26,3 +26,4 @@ - type: NpcFactionMember factions: - NanoTrasen + - type: PotentialPsionic diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/Player/vulpkanin.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/Player/vulpkanin.yml index ea2357a5c06..06abe8c45fa 100644 --- a/Resources/Prototypes/DeltaV/Entities/Mobs/Player/vulpkanin.yml +++ b/Resources/Prototypes/DeltaV/Entities/Mobs/Player/vulpkanin.yml @@ -24,6 +24,7 @@ - type: NpcFactionMember factions: - NanoTrasen + - type: PotentialPsionic - type: Respirator damage: types: diff --git a/Resources/Prototypes/DeltaV/GameRules/events.yml b/Resources/Prototypes/DeltaV/GameRules/events.yml index 9391756492b..73b0ca6549c 100644 --- a/Resources/Prototypes/DeltaV/GameRules/events.yml +++ b/Resources/Prototypes/DeltaV/GameRules/events.yml @@ -52,8 +52,9 @@ noSpawn: true components: - type: StationEvent - weight: 7.5 - minimumPlayers: 10 + earliestStart: 15 + weight: 5 + minimumPlayers: 25 maxOccurrences: 1 duration: 1 - type: PirateRadioSpawnRule diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml index d45e8c3f3c2..4f0a0d0aafa 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml @@ -541,58 +541,3 @@ Quantity: 20 - type: ToggleableClothing clothingPrototype: ClothingHeadHatHoodWinterWeb - -- type: entity - parent: ClothingOuterWinterCoat - id: ClothingOuterCsCorporateJacket - name: Cybersun Corporate Jacket - description: A cozy jacket with the Cybersun logo printed on the back. Merchandise rewarded to stations with a safety factor of uhh... seven. - components: - - type: Sprite - sprite: Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi - - type: Clothing - sprite: Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi - -- type: entity - parent: ClothingOuterWinterCoat - id: ClothingOuterEECorporateJacket - name: Einstein Engines Corporate Jacket - description: A cozy jacket with the Einstein Engines logo printed on the back. Merchandise rewarded to stations with a safety factor of uhh... seven. - components: - - type: Sprite - sprite: Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi - - type: Clothing - sprite: Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi - -- type: entity - parent: ClothingOuterWinterCoat - id: ClothingOuterHICorporateJacket - name: Hephaestus Industries Corporate Jacket - description: A cozy jacket with the Hephaestus Industries logo printed on the back. Merchandise rewarded to stations with a safety factor of uhh... seven. - components: - - type: Sprite - sprite: Clothing/OuterClothing/WinterCoats/hi_corpo_jacket.rsi - - type: Clothing - sprite: Clothing/OuterClothing/WinterCoats/hi_corpo_jacket.rsi - -- type: entity - parent: ClothingOuterWinterCoat - id: ClothingOuterHMCorporateJacket - name: Hawkmoon Acquisitions Corporate Jacket - description: A cozy jacket with the Hawkmoon Acquisitions logo printed on the back. Merchandise rewarded to stations with a safety factor of uhh... seven. - components: - - type: Sprite - sprite: Clothing/OuterClothing/WinterCoats/hm_corpo_jacket.rsi - - type: Clothing - sprite: Clothing/OuterClothing/WinterCoats/hm_corpo_jacket.rsi - -- type: entity - parent: ClothingOuterWinterCoat - id: ClothingOuterIdCorporateJacket - name: Interdyne Corporate Jacket - description: A cozy jacket with the Interdyne logo printed on the back. Merchandise rewarded to stations with a safety factor of uhh... seven. - components: - - type: Sprite - sprite: Clothing/OuterClothing/WinterCoats/id_corpo_jacket.rsi - - type: Clothing - sprite: Clothing/OuterClothing/WinterCoats/id_corpo_jacket.rsi diff --git a/Resources/Prototypes/Entities/Mobs/Player/arachnid.yml b/Resources/Prototypes/Entities/Mobs/Player/arachnid.yml index d9dea3c18d9..5ebd43ddf48 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/arachnid.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/arachnid.yml @@ -11,3 +11,4 @@ damageRecovery: types: Asphyxiation: -0.5 + - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. diff --git a/Resources/Prototypes/Entities/Mobs/Player/diona.yml b/Resources/Prototypes/Entities/Mobs/Player/diona.yml index dfd5e9a1be7..28687c68bfc 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/diona.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/diona.yml @@ -11,6 +11,7 @@ damageRecovery: types: Asphyxiation: -1.0 + - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. # Reformed Diona - type: entity diff --git a/Resources/Prototypes/Entities/Mobs/Player/dwarf.yml b/Resources/Prototypes/Entities/Mobs/Player/dwarf.yml index d1de65df012..fb84ad3650f 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/dwarf.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/dwarf.yml @@ -3,3 +3,5 @@ name: Urist McHands The Dwarf parent: BaseMobDwarf id: MobDwarf + components: + - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Mobs/Player/human.yml b/Resources/Prototypes/Entities/Mobs/Player/human.yml index 9a7c2ee65ec..6197c82c021 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/human.yml @@ -3,6 +3,8 @@ name: Urist McHands parent: BaseMobHuman id: MobHuman + components: + - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. #Syndie - type: entity diff --git a/Resources/Prototypes/Entities/Mobs/Player/moth.yml b/Resources/Prototypes/Entities/Mobs/Player/moth.yml index 72feba958ab..ffdb36d86bd 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/moth.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/moth.yml @@ -3,3 +3,5 @@ name: Urist McFluff parent: BaseMobMoth id: MobMoth + components: + - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml b/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml index b9f265e0bcf..71d74222979 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml @@ -3,5 +3,7 @@ name: Urisst' Mzhand parent: BaseMobReptilian id: MobReptilian + components: + - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. #Weh diff --git a/Resources/Prototypes/Entities/Mobs/Player/slime.yml b/Resources/Prototypes/Entities/Mobs/Player/slime.yml index 4e5974b3084..79669a8fe2a 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/slime.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/slime.yml @@ -2,3 +2,5 @@ save: false parent: BaseMobSlimePerson id: MobSlimePerson + components: + - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Mobs/Species/human.yml b/Resources/Prototypes/Entities/Mobs/Species/human.yml index 900de77712e..7bf96efe2cc 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/human.yml @@ -16,6 +16,7 @@ spawned: - id: FoodMeatHuman amount: 5 + - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. - type: entity parent: BaseSpeciesDummy diff --git a/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/leaves.yml b/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/leaves.yml index b847416211d..e87fec22acc 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/leaves.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/leaves.yml @@ -17,7 +17,8 @@ reagents: - ReagentId: THC Quantity: 15 - + - type: StealTarget + stealGroup: Cannabis - type: entity name: dried cannabis leaves @@ -37,6 +38,8 @@ - type: Sprite sprite: Objects/Specific/Hydroponics/tobacco.rsi state: dried + - type: StealTarget + stealGroup: Cannabis - type: entity name: ground cannabis @@ -65,7 +68,8 @@ - Smokable - type: Item size: Tiny - + - type: StealTarget + stealGroup: Cannabis - type: entity name: tobacco leaves diff --git a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml index e14f29746dc..8d195a25bea 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml @@ -177,7 +177,7 @@ - Screwdriver - Wirecutter - Multitool - - WelderIndustrial + - Welder # cargo modules - type: entity diff --git a/Resources/Prototypes/Nyanotrasen/Actions/types.yml b/Resources/Prototypes/Nyanotrasen/Actions/types.yml index 55dd48e5470..e6e4bdc5a75 100644 --- a/Resources/Prototypes/Nyanotrasen/Actions/types.yml +++ b/Resources/Prototypes/Nyanotrasen/Actions/types.yml @@ -36,18 +36,18 @@ event: !type:DispelPowerActionEvent - type: entity - id: ActionRegenerativeStasis - name: action-name-regenerative-stasis - description: action-description-regenerative-stasis + id: ActionMassSleep + name: action-name-mass-sleep + description: action-description-mass-sleep noSpawn: true components: - - type: EntityTargetAction + - type: WorldTargetAction icon: Nyanotrasen/Interface/VerbIcons/mass_sleep.png useDelay: 60 checkCanAccess: false range: 8 itemIconStyle: BigAction - event: !type:RegenerativeStasisPowerActionEvent + event: !type:MassSleepPowerActionEvent - type: entity id: ActionMindSwap @@ -94,7 +94,7 @@ description: action-description-pyrokinesis noSpawn: true components: - - type: WorldTargetAction + - type: EntityTargetAction icon: Nyanotrasen/Interface/VerbIcons/pyrokinesis.png useDelay: 50 range: 6 @@ -103,29 +103,15 @@ event: !type:PyrokinesisPowerActionEvent - type: entity - id: ActionWideMetapsionic - name: action-name-widemetapsionic - description: action-description-widemetapsionic + id: ActionMetapsionic + name: action-name-metapsionic + description: action-description-metapsionic noSpawn: true components: - type: InstantAction icon: Nyanotrasen/Interface/VerbIcons/metapsionic.png useDelay: 45 - event: !type:WideMetapsionicPowerActionEvent - -- type: entity - id: ActionFocusedMetapsionic - name: action-name-focusedmetapsionic - description: action-description-focusedmetapsionic - noSpawn: true - components: - - type: EntityTargetAction - icon: Nyanotrasen/Interface/VerbIcons/metapsionic.png - useDelay: 45 - range: 3 - checkCanAccess: false - itemIconStyle: BigAction - event: !type:FocusedMetapsionicPowerActionEvent + event: !type:MetapsionicPowerActionEvent - type: entity id: ActionPsionicRegeneration diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/Oni.yml b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/Oni.yml index 1166d8a29f5..562b9c564ec 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/Oni.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/Oni.yml @@ -32,3 +32,4 @@ - type: NpcFactionMember factions: - NanoTrasen + - type: PotentialPsionic diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/felinid.yml b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/felinid.yml index 94ac8403adc..db7936cc5b4 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/felinid.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/felinid.yml @@ -49,3 +49,5 @@ - type: NpcFactionMember factions: - NanoTrasen + - type: PotentialPsionic + diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/metempsychoticMachine.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/metempsychoticMachine.yml index d773cf87c76..d8e791af1ed 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/metempsychoticMachine.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/metempsychoticMachine.yml @@ -22,7 +22,4 @@ NoMind: { state: pod_1 } Gore: { state: pod_1 } Idle: { state: pod_0 } - - type: PotentialPsionic - type: Psionic - psychicFeedback: - - "metempsychotic-machine-feedback" diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/oracle.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/oracle.yml index 58189e49cec..f7481abf1ed 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/oracle.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/oracle.yml @@ -16,10 +16,7 @@ - type: Oracle - type: Speech speechSounds: Tenor - - type: PotentialPsionic - type: Psionic - psychicFeedback: - - "oracle-feedback" - type: SolutionContainerManager solutions: fountain: diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml index 8e34a07ea5e..ae85cd25e03 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml @@ -29,8 +29,6 @@ - Science - type: PotentialPsionic #this makes her easier to access for glimmer events, dw about it - type: Psionic - psychicFeedback: - - "sophic-grammateus-feedback" - type: Grammar attributes: gender: female diff --git a/Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml b/Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml index e6e497003d5..53910a54a92 100644 --- a/Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml +++ b/Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml @@ -9,6 +9,29 @@ stealGroup: AntiPsychicKnife owner: job-name-mantis +- type: entity + id: BecomePsionicObjective + parent: BaseTraitorObjective + name: Become psionic + description: We need you to acquire psionics and keep them until your mission is complete. + noSpawn: true + components: + - type: NotJobsRequirement + jobs: + - Mime + - ForensicMantis + - type: Objective + difficulty: 2.5 + #unique: false + icon: + sprite: Nyanotrasen/Icons/psi.rsi + state: psi + - type: ObjectiveBlacklistRequirement + blacklist: + components: + - BecomeGolemCondition + - type: BecomePsionicCondition + #- type: entity # id: BecomeGolemObjective # parent: BaseTraitorObjective diff --git a/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml b/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml index 15b2cdd4fa7..c3e682e02a9 100644 --- a/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml +++ b/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml @@ -7,24 +7,22 @@ - !type:OverallPlaytimeRequirement time: 18000 - !type:DepartmentTimeRequirement - department: Epistemics + department: Epistemics # DeltaV - Epistemics Department replacing Science time: 3600 startingGear: ForensicMantisGear icon: "JobIconForensicMantis" supervisors: job-supervisors-rd - antagAdvantage: 5 - canBeAntag: true + antagAdvantage: 5 # DeltaV - From 4 to 5 + canBeAntag: true # DeltaV - Mantis is no longer a Detective + # whitelistRequired: true access: - Research - Maintenance - - Mantis + - Mantis # DeltaV - Psionic Mantis, see Resources/Prototypes/DeltaV/Access/epistemics.yml special: - !type:AddComponentSpecial components: - - type: PotentialPsionic - type: Psionic - amplification: 0.3 - dampening: 0.3 - type: MetapsionicPower - type: startingGear @@ -36,10 +34,11 @@ head: ClothingHeadHatFezMantis id: ForensicMantisPDA eyes: ClothingEyesGlassesSunglasses - ears: ClothingHeadsetScience + ears: ClothingHeadsetScience # DeltaV - Mantis is part of Epistemics gloves: ClothingHandsGlovesColorWhite outerClothing: ClothingOuterCoatMantis belt: ClothingBeltMantis + # pocket2: ForensicScanner # DeltaV - Mantis is no longer a Detective innerClothingSkirt: ClothingUniformSkirtMantis satchel: ClothingBackpackSatchelMantisFilled duffelbag: ClothingBackpackDuffelMantisFilled diff --git a/Resources/Prototypes/Nyanotrasen/Traits/psionics.yml b/Resources/Prototypes/Nyanotrasen/Traits/psionics.yml deleted file mode 100644 index 5fef3427703..00000000000 --- a/Resources/Prototypes/Nyanotrasen/Traits/psionics.yml +++ /dev/null @@ -1,6 +0,0 @@ -- type: trait - id: LatentPsychic - name: Latent Psychic - description: trait-latent-psychic-desc - components: - - type: PotentialPsionic diff --git a/Resources/Prototypes/Nyanotrasen/psionicPowers.yml b/Resources/Prototypes/Nyanotrasen/psionicPowers.yml index ca1764e204c..f40b688fd18 100644 --- a/Resources/Prototypes/Nyanotrasen/psionicPowers.yml +++ b/Resources/Prototypes/Nyanotrasen/psionicPowers.yml @@ -5,8 +5,6 @@ DispelPower: 1 TelegnosisPower: 1 PsionicRegenerationPower: 1 - RegenerativeStasisPower: 0.3 - PsionicInvisibilityPower: 0.15 + MassSleepPower: 0.3 +# PsionicInvisibilityPower: 0.15 MindSwapPower: 0.15 - NoosphericZapPower: 0.15 - PyrokinesisPower: 0.15 diff --git a/Resources/Prototypes/Objectives/objectiveGroups.yml b/Resources/Prototypes/Objectives/objectiveGroups.yml index d711e9a1b13..fba2c4cc172 100644 --- a/Resources/Prototypes/Objectives/objectiveGroups.yml +++ b/Resources/Prototypes/Objectives/objectiveGroups.yml @@ -39,6 +39,7 @@ EscapeShuttleObjective: 1 # DieObjective: 0.05 # DeltaV - Disable the lrp objective aka murderbone justification #HijackShuttleObjective: 0.02 + BecomePsionicObjective: 1 # Nyanotrasen - Become Psionic objective, see Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml #BecomeGolemObjective: 0.5 # Nyanotrasen - Become a golem objective, see Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml - type: weightedRandom diff --git a/Resources/Prototypes/Objectives/stealTargetGroups.yml b/Resources/Prototypes/Objectives/stealTargetGroups.yml index 006c061666b..fb1e5e76fc0 100644 --- a/Resources/Prototypes/Objectives/stealTargetGroups.yml +++ b/Resources/Prototypes/Objectives/stealTargetGroups.yml @@ -142,7 +142,12 @@ sprite: Objects/Misc/id_cards.rsi state: default - +- type: stealTargetGroup + id: Cannabis + name: cannabis + sprite: + sprite: Objects/Specific/Hydroponics/cannabis.rsi + state: produce - type: stealTargetGroup id: LAMP diff --git a/Resources/Prototypes/Objectives/thief.yml b/Resources/Prototypes/Objectives/thief.yml index 18154850973..66258870d61 100644 --- a/Resources/Prototypes/Objectives/thief.yml +++ b/Resources/Prototypes/Objectives/thief.yml @@ -142,7 +142,20 @@ - type: Objective difficulty: 0.7 - +- type: entity + noSpawn: true + parent: BaseThiefStealCollectionObjective + id: CannabisStealCollectionObjective + components: + - type: NotJobRequirement + job: Botanist + - type: StealCondition + stealGroup: Cannabis + minCollectionSize: 20 + maxCollectionSize: 30 + verifyMapExistence: false + - type: Objective + difficulty: 0.5 - type: entity noSpawn: true diff --git a/Resources/Prototypes/Roles/Jobs/Science/research_director.yml b/Resources/Prototypes/Roles/Jobs/Science/research_director.yml index ddb779669eb..19cf1419111 100644 --- a/Resources/Prototypes/Roles/Jobs/Science/research_director.yml +++ b/Resources/Prototypes/Roles/Jobs/Science/research_director.yml @@ -3,13 +3,13 @@ name: job-name-rd description: job-description-rd playTimeTracker: JobResearchDirector - antagAdvantage: 6 + antagAdvantage: 6 # DeltaV - Reduced TC: Head of Staff requirements: - !type:DepartmentTimeRequirement - department: Epistemics - time: 54000 + department: Epistemics # DeltaV - Epistemics Department replacing Science + time: 54000 # DeltaV - 15 hours - !type:OverallPlaytimeRequirement - time: 72000 + time: 72000 # DeltaV - 20 hours weight: 10 startingGear: ResearchDirectorGear icon: "JobIconResearchDirector" @@ -21,20 +21,20 @@ - Command - Maintenance - ResearchDirector - - Mantis - - Chapel + - Mantis # DeltaV - Psionic Mantis, see Resources/Prototypes/DeltaV/Access/epistemics.yml + - Chapel # DeltaV - Chaplain is in Epistemics - Cryogenics - special: + special: # Nyanotrasen - Mystagogue can use the Bible - !type:AddComponentSpecial components: - - type: BibleUser - - type: PotentialPsionic - - type: Psionic - dampening: 1 #Mystagogue gets a significant buff to his antimage abilities, making him better at dispelling than other people - - type: DispelPower - - type: CommandStaff + - type: BibleUser # Nyano - Lets them heal with bibles + - type: Psionic # Nyano - They start with telepathic chat + - type: DispelPower # Nyano - They get the Dispel psionic power on spawn - !type:AddImplantSpecial implants: [ MindShieldImplant ] + - !type:AddComponentSpecial + components: + - type: CommandStaff - type: startingGear id: ResearchDirectorGear @@ -44,7 +44,7 @@ shoes: ClothingShoesColorBrown id: RnDPDA ears: ClothingHeadsetRD - belt: BibleMystagogue + belt: BibleMystagogue # Nyanotrasen - Mystagogue book for their Ifrit innerClothingSkirt: ClothingUniformJumpskirtResearchDirector satchel: ClothingBackpackSatchelResearchDirectorFilled duffelbag: ClothingBackpackDuffelResearchDirectorFilled diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi/equipped-OUTERCLOTHING.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi/equipped-OUTERCLOTHING.png deleted file mode 100644 index 73e230e8a5f2088cbea061e045059ab6e5c52140..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8610 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 diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi/icon.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi/icon.png deleted file mode 100644 index f78a89945c3732976cfac3674fea17d416a0bbe7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5930 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 Y6YmP{KCGw>f(VDXJ9|4FUK=U<7ye`^m;e9( diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi/meta.json deleted file mode 100644 index 42d21c3d8ab..00000000000 --- a/Resources/Textures/Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi/meta.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "leonardo_dabepis on discord / @leonardo-dabepis on Tumblr, Edited by heartparkyheart on Discord", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - } - ] -} diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi/equipped-OUTERCLOTHING.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi/equipped-OUTERCLOTHING.png deleted file mode 100644 index 983c2534f4ceffdb575394b6b2077e250a9a07e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8514 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 C=v7$& diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi/icon.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi/icon.png deleted file mode 100644 index ba72253098481f5f357ad1a0fd752a9c1b23a2d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6063 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 NoE=>4&)9BC_#YSooM`|6 diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi/meta.json deleted file mode 100644 index 42d21c3d8ab..00000000000 --- a/Resources/Textures/Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi/meta.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "leonardo_dabepis on discord / @leonardo-dabepis on Tumblr, Edited by heartparkyheart on Discord", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - } - ] -} diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/hi_corpo_jacket.rsi/equipped-OUTERCLOTHING.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/hi_corpo_jacket.rsi/equipped-OUTERCLOTHING.png deleted file mode 100644 index f18a64ab9c0c4012305f51ab70dc2710c1131824..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8310 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 B7?S`1 diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/hm_corpo_jacket.rsi/icon.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/hm_corpo_jacket.rsi/icon.png deleted file mode 100644 index d80b56558a23c7c523173d543ae370b835f48ac8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6169 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 G68{IREn~+3 diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/id_corpo_jacket.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/id_corpo_jacket.rsi/meta.json deleted file mode 100644 index 42d21c3d8ab..00000000000 --- a/Resources/Textures/Clothing/OuterClothing/WinterCoats/id_corpo_jacket.rsi/meta.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "leonardo_dabepis on discord / @leonardo-dabepis on Tumblr, Edited by heartparkyheart on Discord", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - } - ] -} diff --git a/Resources/keybinds.yml b/Resources/keybinds.yml index 346156159a7..b8cfc40c1c4 100644 --- a/Resources/keybinds.yml +++ b/Resources/keybinds.yml @@ -167,7 +167,6 @@ binds: type: State key: MouseLeft canFocus: true - priority: 10 - function: RotateStoredItem type: State key: MouseRight diff --git a/global.json b/global.json index 2244195a209..391ba3c2a30 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { "version": "8.0.100", - "rollForward": "disable" + "rollForward": "latestFeature" } } From 3f44f9d1af13c3fd3216f1d87091eddee040e721 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 28 May 2024 22:05:40 -0400 Subject: [PATCH 31/82] Update PsionicRegenerationPowerSystem.cs --- .../PsionicRegenerationPowerSystem.cs | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs diff --git a/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs b/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs new file mode 100644 index 00000000000..882eb9e0b14 --- /dev/null +++ b/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs @@ -0,0 +1,190 @@ +using Robust.Shared.Audio; +using Robust.Shared.Player; +using Content.Server.Body.Components; +using Content.Server.Body.Systems; +using Content.Server.DoAfter; +using Content.Shared.Psionics.Abilities; +using Content.Shared.Actions; +using Content.Shared.Chemistry.Components; +using Content.Shared.DoAfter; +using Content.Shared.FixedPoint; +using Content.Shared.Mobs; +using Content.Shared.Popups; +using Content.Shared.Psionics.Events; +using Content.Shared.Examine; +using static Content.Shared.Examine.ExamineSystemShared; +using Robust.Shared.Timing; +using Content.Shared.Actions.Events; +using Robust.Server.Audio; + +namespace Content.Server.Psionics.Abilities +{ + public sealed class PsionicRegenerationPowerSystem : EntitySystem + { + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!; + [Dependency] private readonly AudioSystem _audioSystem = default!; + [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnPowerUsed); + SubscribeLocalEvent(OnMobStateChangedEvent); + SubscribeLocalEvent(OnDispelled); + SubscribeLocalEvent(OnDoAfter); + } + + private void OnInit(EntityUid uid, PsionicRegenerationPowerComponent component, ComponentInit args) + { + _actions.AddAction(uid, ref component.PsionicRegenerationActionEntity, component.PsionicRegenerationActionId ); + _actions.TryGetActionData( component.PsionicRegenerationActionEntity, out var actionData ); + if (actionData is { UseDelay: not null }) + _actions.StartUseDelay(component.PsionicRegenerationActionEntity); + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Add(component); + psionic.PsychicFeedback.Add(component.RegenerationFeedback); + psionic.Amplification += 0.5f; + psionic.Dampening += 0.5f; + } + } + + private void OnPowerUsed(EntityUid uid, PsionicRegenerationPowerComponent component, PsionicRegenerationPowerActionEvent args) + { + if (!TryComp(uid, out var psionic)) + return; + + var ev = new PsionicRegenerationDoAfterEvent(_gameTiming.CurTime); + var doAfterArgs = new DoAfterArgs(EntityManager, uid, component.UseDelay, ev, uid); + + //Prevent the power from ignoring its own cooldown + _actions.TryGetActionData(component.PsionicRegenerationActionEntity, out var actionData); + var curTime = _gameTiming.CurTime; + if (actionData != null && actionData.Cooldown.HasValue && actionData.Cooldown.Value.End > curTime) + return; + + _doAfterSystem.TryStartDoAfter(doAfterArgs, out var doAfterId); + + component.DoAfter = doAfterId; + + _popupSystem.PopupEntity(Loc.GetString("psionic-regeneration-begin", ("entity", uid)), + uid, + // TODO: Use LoS-based Filter when one is available. + Filter.Pvs(uid).RemoveWhereAttachedEntity(entity => !ExamineSystemShared.InRangeUnOccluded(uid, entity, ExamineRange, null)), + true, + PopupType.Medium); + + _audioSystem.PlayPvs(component.SoundUse, uid, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); + + _psionics.LogPowerUsed(uid, "psionic regeneration", + (int) Math.Round(6 * psionic.Amplification - psionic.Dampening), + (int) Math.Round(8 * psionic.Amplification - psionic.Dampening)); + + args.Handled = true; + } + + /// + /// Regenerators automatically activate upon crit, provided the power was off cooldown at that exact point in time. + /// Self-rescusitation is also far more costly, and extremely obvious + /// + /// + /// + /// + private void OnMobStateChangedEvent(EntityUid uid, PsionicRegenerationPowerComponent component, MobStateChangedEvent args) + { + if (!TryComp(uid, out var psionic)) + return; + + if (HasComp(uid)) + return; + + if (args.NewMobState is MobState.Critical) + { + _actions.TryGetActionData(component.PsionicRegenerationActionEntity, out var actionData); + var curTime = _gameTiming.CurTime; + if (actionData != null && actionData.Cooldown.HasValue && actionData.Cooldown.Value.End > curTime) + return; + + if (actionData is { UseDelay: not null }) + { + component.SelfRevive = true; + _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, uid, component.UseDelay, new PsionicRegenerationDoAfterEvent(_gameTiming.CurTime), uid, args.Target, uid) + { + BreakOnUserMove = false, + BreakOnTargetMove = false, + BreakOnWeightlessMove = false, + BreakOnDamage = false, + RequireCanInteract = false, + }); + _popupSystem.PopupEntity(Loc.GetString("psionic-regeneration-self-revive", ("entity", uid)), + uid, + // TODO: Use LoS-based Filter when one is available. + Filter.Pvs(uid).RemoveWhereAttachedEntity(entity => !ExamineSystemShared.InRangeUnOccluded(uid, entity, ExamineRange, null)), + true, + PopupType.MediumCaution); + _audioSystem.PlayPvs(component.SoundUse, uid, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); + + _psionics.LogPowerUsed(uid, "psionic regeneration", + (int) Math.Round(10 * psionic.Amplification - 2 * psionic.Dampening), + (int) Math.Round(20 * psionic.Amplification - 2 * psionic.Dampening)); + + _actions.StartUseDelay(component.PsionicRegenerationActionEntity); + } + } + } + + private void OnShutdown(EntityUid uid, PsionicRegenerationPowerComponent component, ComponentShutdown args) + { + _actions.RemoveAction(uid, component.PsionicRegenerationActionEntity); + + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Remove(component); + psionic.PsychicFeedback.Remove(component.RegenerationFeedback); + psionic.Amplification -= 0.5f; + psionic.Dampening -= 0.5f; + } + } + + private void OnDispelled(EntityUid uid, PsionicRegenerationPowerComponent component, DispelledEvent args) + { + if (component.DoAfter == null) + return; + + _doAfterSystem.Cancel(component.DoAfter); + component.DoAfter = null; + + args.Handled = true; + } + + private void OnDoAfter(EntityUid uid, PsionicRegenerationPowerComponent component, PsionicRegenerationDoAfterEvent args) + { + component.DoAfter = null; + + if (!TryComp(uid, out var psionic)) + return; + + if (!TryComp(uid, out var stream)) + return; + + var percentageComplete = Math.Min(1f, (_gameTiming.CurTime - args.StartedAt).TotalSeconds / component.UseDelay); + + var solution = new Solution(); + solution.AddReagent("PsionicRegenerationEssence", FixedPoint2.New(Math.Min(component.EssenceAmount * percentageComplete + 10f * psionic.Dampening, 15f))); + _bloodstreamSystem.TryAddToChemicals(uid, solution, stream); + if (component.SelfRevive == true) + { + var critSolution = new Solution(); + critSolution.AddReagent("Epinephrine", MathF.Min(5 + 5 * psionic.Dampening, 15)); + _bloodstreamSystem.TryAddToChemicals(uid, critSolution, stream); + component.SelfRevive = false; + } + } + } +} From 462e91c2cceee24954d4c7570ef5328994f251bd Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 28 May 2024 22:07:31 -0400 Subject: [PATCH 32/82] aaaaaaaaa --- .github/workflows/build-docfx.yml | 2 +- .../Atmos/Overlays/GasTileOverlay.cs | 70 ++-- Content.Client/Mapping/MappingSystem.cs | 2 +- .../Options/UI/Tabs/KeyRebindTab.xaml.cs | 2 +- .../Glimmer/GlimmerReactiveVisuals.cs | 0 .../GlimmerMonitor}/GlimmerMonitorUi.cs | 3 +- .../GlimmerMonitorUiFragment.xaml | 2 +- .../GlimmerMonitorUiFragment.xaml.cs | 4 +- .../Telepathy}/PsionicChatUpdateSystem.cs | 4 +- .../UserInterface}/AcceptPsionicsEUI.cs | 0 .../UserInterface}/AcceptPsionicsWindow.cs | 0 .../UserInterface/GlimmerGraph.cs | 2 +- .../Systems/Chat/ChatUIController.cs | 9 +- .../Tests/Body/LungTest.cs | 2 +- .../Interaction/InteractionTest.Helpers.cs | 7 +- .../Abilities/Mime/MimePowersSystem.cs | 2 +- .../Managers/AdminManager.Metrics.cs | 98 ++++++ .../Administration/Managers/AdminManager.cs | 9 +- .../Systems/AdminVerbSystem.Smites.cs | 12 +- .../Anomaly/AnomalySystem.Psionics.cs | 4 +- .../Atmos/Commands/SetMapAtmosCommand.cs | 94 +++++ .../Atmos/Components/AirtightComponent.cs | 4 +- .../Components/GridAtmosphereComponent.cs | 8 +- .../Components/IgniteOnCollideComponent.cs | 4 +- .../Components/MapAtmosphereComponent.cs | 8 +- .../Atmos/EntitySystems/AirtightSystem.cs | 18 +- .../EntitySystems/AtmosDebugOverlaySystem.cs | 11 +- .../AtmosObstructionEnumerator.cs | 37 -- .../EntitySystems/AtmosphereSystem.API.cs | 45 +-- .../AtmosphereSystem.ExcitedGroup.cs | 28 +- .../AtmosphereSystem.GridAtmosphere.cs | 247 +++++--------- .../AtmosphereSystem.HighPressureDelta.cs | 10 +- .../EntitySystems/AtmosphereSystem.LINDA.cs | 18 +- .../EntitySystems/AtmosphereSystem.Map.cs | 108 +++++- .../AtmosphereSystem.Monstermos.cs | 110 +++--- .../AtmosphereSystem.Processing.cs | 323 ++++++++++++------ .../AtmosphereSystem.Superconductivity.cs | 8 +- .../EntitySystems/AtmosphereSystem.Utils.cs | 62 ++-- .../Atmos/EntitySystems/AtmosphereSystem.cs | 7 + .../EntitySystems/AutomaticAtmosSystem.cs | 8 +- .../Atmos/EntitySystems/GasAnalyzerSystem.cs | 4 +- .../EntitySystems/GasTileOverlaySystem.cs | 6 +- Content.Server/Atmos/GasMixture.cs | 57 +++- .../Unary/EntitySystems/GasCanisterSystem.cs | 2 +- .../Unary/EntitySystems/GasCondenserSystem.cs | 2 +- .../TileAtmosCollectionSerializer.cs | 8 +- Content.Server/Atmos/TileAtmosphere.cs | 53 ++- Content.Server/Body/Systems/LungSystem.cs | 2 +- Content.Server/Chat/Systems/ChatSystem.cs | 2 +- .../Chemistry/EntitySystems/VaporSystem.cs | 4 +- .../Chemistry/ReagentEffects/ModifyLungGas.cs | 13 +- .../Conditions/ComponentInTile.cs | 11 +- .../Events/GlimmerMobSpawnRule.cs | 2 +- .../ExplosionSystem.Processing.cs | 4 +- .../ImmovableRod/ImmovableRodSystem.cs | 6 +- .../Abilities/MetapsionicPowerSystem.cs | 74 ---- .../PsionicRegenerationPowerSystem.cs | 128 ------- .../Abilities/PyrokinesisPowerSystem.cs | 66 ---- .../Abilities/TelegnosisPowerSystem.cs | 67 ---- .../Chemistry/Effects/ChemRemovePsionic.cs | 2 +- .../BecomePsionicConditionComponent.cs | 11 - .../Systems/BecomePsionicConditionSystem.cs | 32 -- .../Psionics/PotentialPsionicComponent.cs | 14 - .../Research/Oracle/OracleSystem.cs | 2 +- .../SophicScribe/SophicScribeSystem.cs | 2 +- .../Events/GlimmerWispSpawnRule.cs | 2 +- .../StationEvents/Events/MassMindSwapRule.cs | 5 +- .../StationEvents/Events/NoosphericFryRule.cs | 2 +- .../Events/NoosphericStormRule.cs | 4 +- .../StationEvents/Events/NoosphericZapRule.cs | 2 +- .../Events/PsionicCatGotYourTongueRule.cs | 2 +- Content.Server/Parallax/BiomeSystem.cs | 11 +- .../ParticleAcceleratorSystem.Emitter.cs | 2 +- .../Physics/Controllers/ChasingWalkSystem.cs | 2 +- .../Power/Generator/GasPowerReceiverSystem.cs | 2 +- .../Psionics/Abilities/DispelPowerSystem.cs | 31 +- .../Abilities/MetapsionicPowerSystem.cs | 188 ++++++++++ .../Psionics/Abilities/MindSwapPowerSystem.cs | 62 ++-- .../Abilities/MindSwappedComponent.cs | 5 +- .../Abilities/NoosphericZapPowerSystem.cs | 44 +-- .../Abilities}/PsionicAbilitiesSystem.cs | 89 ++--- .../PsionicInvisibilityPowerSystem.cs | 94 +++-- .../Abilities/PyrokinesisPowerSystem.cs | 93 +++++ .../RegenerativeStasisPowerSystem.cs | 76 +++++ .../Abilities/TelegnosisPowerSystem.cs | 106 ++++++ .../Psionics/AcceptPsionicsEui.cs | 2 +- .../Psionics/AntiPsychicWeaponComponent.cs | 0 .../Audio/GlimmerSoundComponent.cs | 6 +- .../Psionics/Dreams/DreamSystem.cs | 3 - .../Psionics/Glimmer/GlimmerCommands.cs | 0 .../Psionics/Glimmer/GlimmerReactiveSystem.cs | 5 +- .../Glimmer/PassiveGlimmerReductionSystem.cs | 2 - .../Structures/GlimmerSourceComponent.cs | 0 .../Structures/GlimmerStructuresSystem.cs | 0 .../Invisibility/PsionicInvisibilitySystem.cs | 25 +- .../PsionicInvisibleContactsComponent.cs | 1 - .../PsionicInvisibleContactsSystem.cs | 2 - .../PsionicallyInvisibleComponent.cs | 0 .../Psionics/PotentialPsionicComponent.cs | 21 ++ .../PsionicAwaitingPlayerComponent.cs | 0 .../Psionics/PsionicBonusChanceComponent.cs | 0 .../Psionics/PsionicsCommands.cs | 6 +- .../Psionics/PsionicsSystem.cs | 23 +- .../Telepathy}/TSayCommand.cs | 3 +- .../Telepathy}/TelepathicRepeaterComponent.cs | 2 +- .../Telepathy/TelepathyChatSystem.cs} | 18 +- .../Salvage/SpawnSalvageMissionJob.cs | 6 +- .../Systems/ShuttleSystem.FasterThanLight.cs | 8 +- .../Shuttles/Systems/ShuttleSystem.cs | 8 +- .../EntitySystems/EventHorizonSystem.cs | 4 +- Content.Server/Spreader/SpreaderSystem.cs | 69 ++-- .../StationEvents/Events/MeteorSwarmRule.cs | 6 +- .../Zombies/ZombieSystem.Transform.cs | 4 +- Content.Shared/Atmos/Atmospherics.cs | 7 +- .../SharedGasTileOverlaySystem.cs | 3 + .../Buckle/SharedBuckleSystem.Buckle.cs | 2 +- Content.Shared/Maps/ContentTileDefinition.cs | 6 +- Content.Shared/Maps/TurfHelpers.cs | 27 +- .../Movement/Systems/SharedJetpackSystem.cs | 4 +- .../MassSleep/MassSleepPowerComponent.cs | 18 - .../MassSleep/MassSleepPowerSystem.cs | 59 ---- .../Metapsionics/MetapsionicPowerComponent.cs | 21 -- .../TelegnosticProjectionComponent.cs | 6 - .../Events/MassSleepPowerActionEvent.cs | 2 - .../Events/MetapsionicPowerActionEvent.cs | 3 +- .../Events/PyrokinesisPowerActionEvent.cs | 4 +- .../RegenerativeStasisPowerActionEvent.cs | 2 + Content.Shared/Nyanotrasen/Psionics/Events.cs | 28 -- .../Abilities/AcceptPsionicsEuiMessage.cs | 0 .../Dispel/DamageOnDispelComponent.cs | 4 +- .../Abilities/Dispel/DispelPowerComponent.cs | 8 +- .../Abilities/Dispel/DispellableComponent.cs | 2 +- .../Metapsionics/MetapsionicPowerComponent.cs | 38 +++ .../MindSwap/MindSwapPowerComponent.cs | 5 +- .../NoosphericZapPowerComponent.cs | 5 +- .../PsionicInvisibilityPowerComponent.cs | 8 +- .../PsionicInvisibilityUsedComponent.cs | 3 +- .../PsionicRegenerationPowerComponent.cs | 10 +- .../Pyrokinesis/PyrokinesisPowerComponent.cs | 5 +- .../RegenerativeStasisPowerComponent.cs | 20 ++ .../Telegnosis/TelegnosisPowerComponent.cs | 10 +- .../TelegnosticProjectionComponent.cs | 8 + Content.Shared/Psionics/Events.cs | 64 ++++ .../Psionics/Glimmer/GlimmerSystem.cs | 2 +- .../Glimmer/SharedGlimmerReactiveComponent.cs | 0 .../Glimmer/SharedGlimmerReactiveVisuals.cs | 0 .../ClothingGrantPsionicPowerComponent.cs | 2 +- .../Psionics/Items/HeadCageComponent.cs | 2 +- .../Psionics/Items/HeadCagedComponent.cs | 2 +- .../Psionics/Items/PsionicItemsSystem.cs | 2 +- .../Psionics/Items/TinfoilHatComponent.cs | 2 +- .../Psionics/PsionicComponent.cs | 16 +- .../Psionics/PsionicInsulationComponent.cs | 2 +- .../Psionics/PsionicsDisabledComponent.cs | 2 +- .../Psionics/SharedPsionicAbilitiesSystem.cs | 4 +- .../Psionics/SharedPsionicSystem.Insulated.cs | 4 + Content.Shared/Throwing/ThrowingSystem.cs | 6 +- Content.Shared/Throwing/ThrownItemSystem.cs | 2 +- .../Weapons/Melee/MeleeThrowOnHitSystem.cs | 4 +- .../Weapons/Misc/SharedTetherGunSystem.cs | 10 +- .../Weapons/Ranged/Systems/SharedGunSystem.cs | 2 +- .../Audio/Nyanotrasen/heartbeat_fast.ogg | Bin 0 -> 39983 bytes Resources/Changelog/Changelog.yml | 14 + Resources/Credits/GitHub.txt | 2 +- Resources/Locale/en-US/atmos/commands.ftl | 8 + .../en-US/nyanotrasen/abilities/psionic.ftl | 18 +- .../nyanotrasen/psionics/psychic-feedback.ftl | 21 ++ .../Catalog/Cargo/cargo_vending.yml | 2 +- .../Inventories/clothesmate.yml | 5 + .../DeltaV/Entities/Mobs/NPCs/familiars.yml | 7 +- .../DeltaV/Entities/Mobs/Player/harpy.yml | 1 - .../DeltaV/Entities/Mobs/Player/vulpkanin.yml | 1 - .../Prototypes/DeltaV/GameRules/events.yml | 5 +- .../Clothing/OuterClothing/wintercoats.yml | 55 +++ .../Entities/Mobs/Player/arachnid.yml | 1 - .../Prototypes/Entities/Mobs/Player/diona.yml | 1 - .../Prototypes/Entities/Mobs/Player/dwarf.yml | 2 - .../Prototypes/Entities/Mobs/Player/human.yml | 2 - .../Prototypes/Entities/Mobs/Player/moth.yml | 2 - .../Entities/Mobs/Player/reptilian.yml | 2 - .../Prototypes/Entities/Mobs/Player/slime.yml | 2 - .../Entities/Mobs/Species/human.yml | 1 - .../Objects/Specific/Hydroponics/leaves.yml | 8 +- .../Specific/Robotics/borg_modules.yml | 2 +- .../Prototypes/Nyanotrasen/Actions/types.yml | 34 +- .../Nyanotrasen/Entities/Mobs/Player/Oni.yml | 1 - .../Entities/Mobs/Player/felinid.yml | 2 - .../Machines/metempsychoticMachine.yml | 3 + .../Entities/Structures/Research/oracle.yml | 3 + .../Structures/Research/sophicscribe.yml | 2 + .../Nyanotrasen/Objectives/traitor.yml | 23 -- .../Roles/Jobs/Epistemics/forensicmantis.yml | 15 +- .../Nyanotrasen/Traits/psionics.yml | 6 + .../Prototypes/Nyanotrasen/psionicPowers.yml | 6 +- .../Prototypes/Objectives/objectiveGroups.yml | 1 - .../Objectives/stealTargetGroups.yml | 7 +- Resources/Prototypes/Objectives/thief.yml | 15 +- .../Roles/Jobs/Science/research_director.yml | 28 +- .../equipped-OUTERCLOTHING.png | Bin 0 -> 8610 bytes .../WinterCoats/cs_corpo_jacket.rsi/icon.png | Bin 0 -> 5930 bytes .../WinterCoats/cs_corpo_jacket.rsi/meta.json | 18 + .../equipped-OUTERCLOTHING.png | Bin 0 -> 8514 bytes .../WinterCoats/ee_corpo_jacket.rsi/icon.png | Bin 0 -> 6063 bytes .../WinterCoats/ee_corpo_jacket.rsi/meta.json | 18 + .../equipped-OUTERCLOTHING.png | Bin 0 -> 8310 bytes .../WinterCoats/hi_corpo_jacket.rsi/icon.png | Bin 0 -> 5980 bytes .../WinterCoats/hi_corpo_jacket.rsi/meta.json | 18 + .../equipped-OUTERCLOTHING.png | Bin 0 -> 9341 bytes .../WinterCoats/hm_corpo_jacket.rsi/icon.png | Bin 0 -> 6169 bytes .../WinterCoats/hm_corpo_jacket.rsi/meta.json | 18 + .../equipped-OUTERCLOTHING.png | Bin 0 -> 9025 bytes .../WinterCoats/id_corpo_jacket.rsi/icon.png | Bin 0 -> 5955 bytes .../WinterCoats/id_corpo_jacket.rsi/meta.json | 18 + Resources/keybinds.yml | 1 + global.json | 2 +- 215 files changed, 2271 insertions(+), 1588 deletions(-) rename Content.Client/{Nyanotrasen => }/Psionics/Glimmer/GlimmerReactiveVisuals.cs (100%) rename Content.Client/{Nyanotrasen/CartridgeLoader/Cartridges => Psionics/GlimmerMonitor}/GlimmerMonitorUi.cs (92%) rename Content.Client/{Nyanotrasen/CartridgeLoader/Cartridges => Psionics/GlimmerMonitor}/GlimmerMonitorUiFragment.xaml (93%) rename Content.Client/{Nyanotrasen/CartridgeLoader/Cartridges => Psionics/GlimmerMonitor}/GlimmerMonitorUiFragment.xaml.cs (96%) rename Content.Client/{Nyanotrasen/Chat => Psionics/Telepathy}/PsionicChatUpdateSystem.cs (92%) rename Content.Client/{Nyanotrasen/Psionics/UI => Psionics/UserInterface}/AcceptPsionicsEUI.cs (100%) rename Content.Client/{Nyanotrasen/Psionics/UI => Psionics/UserInterface}/AcceptPsionicsWindow.cs (100%) rename Content.Client/{Nyanotrasen => Psionics}/UserInterface/GlimmerGraph.cs (97%) create mode 100644 Content.Server/Administration/Managers/AdminManager.Metrics.cs create mode 100644 Content.Server/Atmos/Commands/SetMapAtmosCommand.cs delete mode 100644 Content.Server/Atmos/EntitySystems/AtmosObstructionEnumerator.cs delete mode 100644 Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs delete mode 100644 Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs delete mode 100644 Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs delete mode 100644 Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs delete mode 100644 Content.Server/Nyanotrasen/Objectives/Components/BecomePsionicConditionComponent.cs delete mode 100644 Content.Server/Nyanotrasen/Objectives/Systems/BecomePsionicConditionSystem.cs delete mode 100644 Content.Server/Nyanotrasen/Psionics/PotentialPsionicComponent.cs rename Content.Server/{Nyanotrasen/Abilities => }/Psionics/Abilities/DispelPowerSystem.cs (83%) create mode 100644 Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs rename Content.Server/{Nyanotrasen/Abilities => }/Psionics/Abilities/MindSwapPowerSystem.cs (78%) rename Content.Server/{Nyanotrasen/Abilities => }/Psionics/Abilities/MindSwappedComponent.cs (79%) rename Content.Server/{Nyanotrasen/Abilities => }/Psionics/Abilities/NoosphericZapPowerSystem.cs (54%) rename Content.Server/{Nyanotrasen/Abilities/Psionics => Psionics/Abilities}/PsionicAbilitiesSystem.cs (54%) rename Content.Server/{Nyanotrasen/Abilities => }/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs (57%) create mode 100644 Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs create mode 100644 Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs create mode 100644 Content.Server/Psionics/Abilities/TelegnosisPowerSystem.cs rename Content.Server/{Nyanotrasen => }/Psionics/AcceptPsionicsEui.cs (95%) rename Content.Server/{Nyanotrasen => }/Psionics/AntiPsychicWeaponComponent.cs (100%) rename Content.Server/{Nyanotrasen => Psionics}/Audio/GlimmerSoundComponent.cs (80%) rename Content.Server/{Nyanotrasen => }/Psionics/Dreams/DreamSystem.cs (93%) rename Content.Server/{Nyanotrasen => }/Psionics/Glimmer/GlimmerCommands.cs (100%) rename Content.Server/{Nyanotrasen => }/Psionics/Glimmer/GlimmerReactiveSystem.cs (99%) rename Content.Server/{Nyanotrasen => }/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs (94%) rename Content.Server/{Nyanotrasen => }/Psionics/Glimmer/Structures/GlimmerSourceComponent.cs (100%) rename Content.Server/{Nyanotrasen => }/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs (100%) rename Content.Server/{Nyanotrasen => }/Psionics/Invisibility/PsionicInvisibilitySystem.cs (88%) rename Content.Server/{Nyanotrasen => }/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs (95%) rename Content.Server/{Nyanotrasen => }/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs (95%) rename Content.Server/{Nyanotrasen => }/Psionics/Invisibility/PsionicallyInvisibleComponent.cs (100%) create mode 100644 Content.Server/Psionics/PotentialPsionicComponent.cs rename Content.Server/{Nyanotrasen => }/Psionics/PsionicAwaitingPlayerComponent.cs (100%) rename Content.Server/{Nyanotrasen => }/Psionics/PsionicBonusChanceComponent.cs (100%) rename Content.Server/{Nyanotrasen => }/Psionics/PsionicsCommands.cs (84%) rename Content.Server/{Nyanotrasen => }/Psionics/PsionicsSystem.cs (91%) rename Content.Server/{Nyanotrasen/Chat => Psionics/Telepathy}/TSayCommand.cs (95%) rename Content.Server/{Nyanotrasen/Chat => Psionics/Telepathy}/TelepathicRepeaterComponent.cs (82%) rename Content.Server/{Nyanotrasen/Chat/NyanoChatSystem.cs => Psionics/Telepathy/TelepathyChatSystem.cs} (85%) delete mode 100644 Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs delete mode 100644 Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerSystem.cs delete mode 100644 Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs delete mode 100644 Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs delete mode 100644 Content.Shared/Nyanotrasen/Actions/Events/MassSleepPowerActionEvent.cs create mode 100644 Content.Shared/Nyanotrasen/Actions/Events/RegenerativeStasisPowerActionEvent.cs delete mode 100644 Content.Shared/Nyanotrasen/Psionics/Events.cs rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/AcceptPsionicsEuiMessage.cs (100%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs (77%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/Dispel/DispelPowerComponent.cs (79%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/Dispel/DispellableComponent.cs (69%) create mode 100644 Content.Shared/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs (76%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs (77%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs (71%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs (94%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs (76%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs (79%) create mode 100644 Content.Shared/Psionics/Abilities/RegenerativeStasis/RegenerativeStasisPowerComponent.cs rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs (73%) create mode 100644 Content.Shared/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs create mode 100644 Content.Shared/Psionics/Events.cs rename Content.Shared/{Nyanotrasen => }/Psionics/Glimmer/GlimmerSystem.cs (98%) rename Content.Shared/{Nyanotrasen => }/Psionics/Glimmer/SharedGlimmerReactiveComponent.cs (100%) rename Content.Shared/{Nyanotrasen => }/Psionics/Glimmer/SharedGlimmerReactiveVisuals.cs (100%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Items/ClothingGrantPsionicPowerComponent.cs (84%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Items/HeadCageComponent.cs (96%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Items/HeadCagedComponent.cs (81%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Items/PsionicItemsSystem.cs (98%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/Items/TinfoilHatComponent.cs (90%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/PsionicComponent.cs (51%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/PsionicInsulationComponent.cs (82%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/PsionicsDisabledComponent.cs (84%) rename Content.Shared/{Nyanotrasen/Abilities => }/Psionics/SharedPsionicAbilitiesSystem.cs (97%) create mode 100644 Content.Shared/Psionics/SharedPsionicSystem.Insulated.cs create mode 100644 Resources/Audio/Nyanotrasen/heartbeat_fast.ogg create mode 100644 Resources/Locale/en-US/atmos/commands.ftl create mode 100644 Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl create mode 100644 Resources/Prototypes/Nyanotrasen/Traits/psionics.yml create mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi/equipped-OUTERCLOTHING.png create mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi/icon.png create mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi/meta.json create mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi/equipped-OUTERCLOTHING.png create mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi/icon.png create mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi/meta.json create mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/hi_corpo_jacket.rsi/equipped-OUTERCLOTHING.png create mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/hi_corpo_jacket.rsi/icon.png create mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/hi_corpo_jacket.rsi/meta.json create mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/hm_corpo_jacket.rsi/equipped-OUTERCLOTHING.png create mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/hm_corpo_jacket.rsi/icon.png create mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/hm_corpo_jacket.rsi/meta.json create mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/id_corpo_jacket.rsi/equipped-OUTERCLOTHING.png create mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/id_corpo_jacket.rsi/icon.png create mode 100644 Resources/Textures/Clothing/OuterClothing/WinterCoats/id_corpo_jacket.rsi/meta.json diff --git a/.github/workflows/build-docfx.yml b/.github/workflows/build-docfx.yml index ca1a6f0af12..d37e37026d7 100644 --- a/.github/workflows/build-docfx.yml +++ b/.github/workflows/build-docfx.yml @@ -21,7 +21,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v3.2.0 with: - dotnet-version: 8.0.x + dotnet-version: 8.0.100 - name: Install dependencies run: dotnet restore diff --git a/Content.Client/Atmos/Overlays/GasTileOverlay.cs b/Content.Client/Atmos/Overlays/GasTileOverlay.cs index ef65d43fe85..f4dc274a4e5 100644 --- a/Content.Client/Atmos/Overlays/GasTileOverlay.cs +++ b/Content.Client/Atmos/Overlays/GasTileOverlay.cs @@ -8,7 +8,6 @@ using Robust.Client.Graphics; using Robust.Client.ResourceManagement; using Robust.Shared.Enums; -using Robust.Shared.Graphics; using Robust.Shared.Graphics.RSI; using Robust.Shared.Map; using Robust.Shared.Map.Components; @@ -23,7 +22,7 @@ public sealed class GasTileOverlay : Overlay private readonly IEntityManager _entManager; private readonly IMapManager _mapManager; - public override OverlaySpace Space => OverlaySpace.WorldSpaceEntities; + public override OverlaySpace Space => OverlaySpace.WorldSpaceEntities | OverlaySpace.WorldSpaceBelowWorld; private readonly ShaderInstance _shader; // Gas overlays @@ -79,7 +78,8 @@ public GasTileOverlay(GasTileOverlaySystem system, IEntityManager entManager, IR var rsi = resourceCache.GetResource(animated.RsiPath).RSI; var stateId = animated.RsiState; - if (!rsi.TryGetState(stateId, out var state)) continue; + if (!rsi.TryGetState(stateId, out var state)) + continue; _frames[i] = state.GetFrames(RsiDirection.South); _frameDelays[i] = state.GetDelays(); @@ -111,7 +111,8 @@ protected override void FrameUpdate(FrameEventArgs args) for (var i = 0; i < _gasCount; i++) { var delays = _frameDelays[i]; - if (delays.Length == 0) continue; + if (delays.Length == 0) + continue; var frameCount = _frameCounter[i]; _timer[i] += args.DeltaSeconds; @@ -127,7 +128,8 @@ protected override void FrameUpdate(FrameEventArgs args) for (var i = 0; i < FireStates; i++) { var delays = _fireFrameDelays[i]; - if (delays.Length == 0) continue; + if (delays.Length == 0) + continue; var frameCount = _fireFrameCounter[i]; _fireTimer[i] += args.DeltaSeconds; @@ -161,26 +163,10 @@ protected override void Draw(in OverlayDrawArgs args) var mapUid = _mapManager.GetMapEntityId(args.MapId); if (_entManager.TryGetComponent(mapUid, out var atmos)) - { - var bottomLeft = args.WorldAABB.BottomLeft.Floored(); - var topRight = args.WorldAABB.TopRight.Ceiled(); - - for (var x = bottomLeft.X; x <= topRight.X; x++) - { - for (var y = bottomLeft.Y; y <= topRight.Y; y++) - { - var tilePosition = new Vector2(x, y); - - for (var i = 0; i < atmos.OverlayData.Opacity.Length; i++) - { - var opacity = atmos.OverlayData.Opacity[i]; + DrawMapOverlay(drawHandle, args, mapUid, atmos); - if (opacity > 0) - args.WorldHandle.DrawTexture(_frames[i][_frameCounter[i]], tilePosition, Color.White.WithAlpha(opacity)); - } - } - } - } + if (args.Space != OverlaySpace.WorldSpaceEntities) + return; // TODO: WorldBounds callback. _mapManager.FindGridsIntersecting(args.MapId, args.WorldAABB, ref gridState, @@ -265,5 +251,41 @@ protected override void Draw(in OverlayDrawArgs args) drawHandle.UseShader(null); drawHandle.SetTransform(Matrix3.Identity); } + + private void DrawMapOverlay( + DrawingHandleWorld handle, + OverlayDrawArgs args, + EntityUid map, + MapAtmosphereComponent atmos) + { + var mapGrid = _entManager.HasComponent(map); + + // map-grid atmospheres get drawn above grids + if (mapGrid && args.Space != OverlaySpace.WorldSpaceEntities) + return; + + // Normal map atmospheres get drawn below grids + if (!mapGrid && args.Space != OverlaySpace.WorldSpaceBelowWorld) + return; + + var bottomLeft = args.WorldAABB.BottomLeft.Floored(); + var topRight = args.WorldAABB.TopRight.Ceiled(); + + for (var x = bottomLeft.X; x <= topRight.X; x++) + { + for (var y = bottomLeft.Y; y <= topRight.Y; y++) + { + var tilePosition = new Vector2(x, y); + + for (var i = 0; i < atmos.OverlayData.Opacity.Length; i++) + { + var opacity = atmos.OverlayData.Opacity[i]; + + if (opacity > 0) + handle.DrawTexture(_frames[i][_frameCounter[i]], tilePosition, Color.White.WithAlpha(opacity)); + } + } + } + } } } diff --git a/Content.Client/Mapping/MappingSystem.cs b/Content.Client/Mapping/MappingSystem.cs index 4456be36a65..8daf193dfeb 100644 --- a/Content.Client/Mapping/MappingSystem.cs +++ b/Content.Client/Mapping/MappingSystem.cs @@ -83,7 +83,7 @@ private void OnFillActionSlot(FillActionSlotEvent ev) if (tileDef is not ContentTileDefinition contentTileDef) return; - var tileIcon = contentTileDef.IsSpace + var tileIcon = contentTileDef.MapAtmosphere ? _spaceIcon : new Texture(contentTileDef.Sprite!.Value); diff --git a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs index ce5cf421aef..f0537079b97 100644 --- a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs +++ b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs @@ -403,7 +403,7 @@ private void InputManagerOnFirstChanceOnKeyEvent(KeyEventArgs keyEvent, KeyEvent Mod1 = mods[0], Mod2 = mods[1], Mod3 = mods[2], - Priority = 0, + Priority = _currentlyRebinding.Binding?.Priority ?? 0, Type = bindType, CanFocus = key == Keyboard.Key.MouseLeft || key == Keyboard.Key.MouseRight diff --git a/Content.Client/Nyanotrasen/Psionics/Glimmer/GlimmerReactiveVisuals.cs b/Content.Client/Psionics/Glimmer/GlimmerReactiveVisuals.cs similarity index 100% rename from Content.Client/Nyanotrasen/Psionics/Glimmer/GlimmerReactiveVisuals.cs rename to Content.Client/Psionics/Glimmer/GlimmerReactiveVisuals.cs diff --git a/Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUi.cs b/Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUi.cs similarity index 92% rename from Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUi.cs rename to Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUi.cs index 0b5fc7ad38c..0d8accb9f86 100644 --- a/Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUi.cs +++ b/Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUi.cs @@ -1,10 +1,11 @@ using Robust.Client.GameObjects; using Robust.Client.UserInterface; +using Content.Client.Psionics.UI; using Content.Client.UserInterface.Fragments; using Content.Shared.CartridgeLoader.Cartridges; using Content.Shared.CartridgeLoader; -namespace Content.Client.Nyanotrasen.CartridgeLoader.Cartridges; +namespace Content.Client.Psionics.GlimmerMonitor; public sealed partial class GlimmerMonitorUi : UIFragment { diff --git a/Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUiFragment.xaml b/Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUiFragment.xaml similarity index 93% rename from Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUiFragment.xaml rename to Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUiFragment.xaml index 119a1831e6e..3044680e27b 100644 --- a/Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUiFragment.xaml +++ b/Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUiFragment.xaml @@ -1,4 +1,4 @@ - diff --git a/Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUiFragment.xaml.cs b/Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUiFragment.xaml.cs similarity index 96% rename from Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUiFragment.xaml.cs rename to Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUiFragment.xaml.cs index 43d9202aa45..58bbee38a2f 100644 --- a/Content.Client/Nyanotrasen/CartridgeLoader/Cartridges/GlimmerMonitorUiFragment.xaml.cs +++ b/Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUiFragment.xaml.cs @@ -1,12 +1,12 @@ using System.Linq; using System.Numerics; -using Content.Client.Nyanotrasen.UserInterface; +using Content.Client.Psionics.UI; using Robust.Client.AutoGenerated; using Robust.Client.ResourceManagement; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; -namespace Content.Client.Nyanotrasen.CartridgeLoader.Cartridges; +namespace Content.Client.Psionics.GlimmerMonitor; [GenerateTypedNameReferences] public sealed partial class GlimmerMonitorUiFragment : BoxContainer diff --git a/Content.Client/Nyanotrasen/Chat/PsionicChatUpdateSystem.cs b/Content.Client/Psionics/Telepathy/PsionicChatUpdateSystem.cs similarity index 92% rename from Content.Client/Nyanotrasen/Chat/PsionicChatUpdateSystem.cs rename to Content.Client/Psionics/Telepathy/PsionicChatUpdateSystem.cs index 84602052fe7..7bb88764a1f 100644 --- a/Content.Client/Nyanotrasen/Chat/PsionicChatUpdateSystem.cs +++ b/Content.Client/Psionics/Telepathy/PsionicChatUpdateSystem.cs @@ -1,8 +1,8 @@ -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Client.Chat.Managers; using Robust.Client.Player; -namespace Content.Client.Nyanotrasen.Chat +namespace Content.Client.Psionics.Chat { public sealed class PsionicChatUpdateSystem : EntitySystem { diff --git a/Content.Client/Nyanotrasen/Psionics/UI/AcceptPsionicsEUI.cs b/Content.Client/Psionics/UserInterface/AcceptPsionicsEUI.cs similarity index 100% rename from Content.Client/Nyanotrasen/Psionics/UI/AcceptPsionicsEUI.cs rename to Content.Client/Psionics/UserInterface/AcceptPsionicsEUI.cs diff --git a/Content.Client/Nyanotrasen/Psionics/UI/AcceptPsionicsWindow.cs b/Content.Client/Psionics/UserInterface/AcceptPsionicsWindow.cs similarity index 100% rename from Content.Client/Nyanotrasen/Psionics/UI/AcceptPsionicsWindow.cs rename to Content.Client/Psionics/UserInterface/AcceptPsionicsWindow.cs diff --git a/Content.Client/Nyanotrasen/UserInterface/GlimmerGraph.cs b/Content.Client/Psionics/UserInterface/GlimmerGraph.cs similarity index 97% rename from Content.Client/Nyanotrasen/UserInterface/GlimmerGraph.cs rename to Content.Client/Psionics/UserInterface/GlimmerGraph.cs index c4a9109dcd8..111c810acb1 100644 --- a/Content.Client/Nyanotrasen/UserInterface/GlimmerGraph.cs +++ b/Content.Client/Psionics/UserInterface/GlimmerGraph.cs @@ -4,7 +4,7 @@ using Robust.Client.ResourceManagement; using Robust.Client.UserInterface; -namespace Content.Client.Nyanotrasen.UserInterface; +namespace Content.Client.Psionics.UI; public sealed class GlimmerGraph : Control { diff --git a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs index ff4972d9d08..79c1909ebaf 100644 --- a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs +++ b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs @@ -20,7 +20,6 @@ using Content.Shared.Examine; using Content.Shared.Input; using Content.Shared.Radio; -using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.Input; using Robust.Client.Player; @@ -37,7 +36,7 @@ using Robust.Shared.Replays; using Robust.Shared.Timing; using Robust.Shared.Utility; -using Content.Client.Nyanotrasen.Chat; //Nyano - Summary: chat namespace. +using Content.Client.Psionics.Chat; namespace Content.Client.UserInterface.Systems.Chat; @@ -61,7 +60,7 @@ public sealed class ChatUIController : UIController [UISystemDependency] private readonly GhostSystem? _ghost = default; [UISystemDependency] private readonly TypingIndicatorSystem? _typingIndicator = default; [UISystemDependency] private readonly ChatSystem? _chatSys = default; - [UISystemDependency] private readonly PsionicChatUpdateSystem? _psionic = default!; //Nyano - Summary: makes the psionic chat available. + [UISystemDependency] private readonly PsionicChatUpdateSystem? _psionic = default!; //EE - Summary: makes the psionic chat available. [ValidatePrototypeId] private const string ChatNamePalette = "ChatNames"; @@ -82,7 +81,7 @@ public sealed class ChatUIController : UIController {SharedChatSystem.AdminPrefix, ChatSelectChannel.Admin}, {SharedChatSystem.RadioCommonPrefix, ChatSelectChannel.Radio}, {SharedChatSystem.DeadPrefix, ChatSelectChannel.Dead}, - {SharedChatSystem.TelepathicPrefix, ChatSelectChannel.Telepathic} //Nyano - Summary: adds the telepathic prefix =. + {SharedChatSystem.TelepathicPrefix, ChatSelectChannel.Telepathic} //EE - Summary: adds the telepathic prefix =. }; public static readonly Dictionary ChannelPrefixes = new() @@ -96,7 +95,7 @@ public sealed class ChatUIController : UIController {ChatSelectChannel.Admin, SharedChatSystem.AdminPrefix}, {ChatSelectChannel.Radio, SharedChatSystem.RadioCommonPrefix}, {ChatSelectChannel.Dead, SharedChatSystem.DeadPrefix}, - {ChatSelectChannel.Telepathic, SharedChatSystem.TelepathicPrefix } //Nyano - Summary: associates telepathic with =. + {ChatSelectChannel.Telepathic, SharedChatSystem.TelepathicPrefix } //EE - Summary: associates telepathic with =. }; /// diff --git a/Content.IntegrationTests/Tests/Body/LungTest.cs b/Content.IntegrationTests/Tests/Body/LungTest.cs index d0325480acd..f2e19849b00 100644 --- a/Content.IntegrationTests/Tests/Body/LungTest.cs +++ b/Content.IntegrationTests/Tests/Body/LungTest.cs @@ -128,7 +128,7 @@ await server.WaitAssertion(() => metaSys.Update(1.0f); metaSys.Update(1.0f); respSys.Update(2.0f); - Assert.That(GetMapMoles(), Is.EqualTo(startingMoles).Within(0.0001)); + Assert.That(GetMapMoles(), Is.EqualTo(startingMoles).Within(0.0002)); }); } diff --git a/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs b/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs index 84e1afaf45c..88448e7b800 100644 --- a/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs +++ b/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs @@ -1006,15 +1006,10 @@ protected async Task AddAtmosphere(EntityUid? uid = null) await Server.WaitPost(() => { var atmosSystem = SEntMan.System(); - var atmos = SEntMan.EnsureComponent(target); var moles = new float[Atmospherics.AdjustedNumberOfGases]; moles[(int) Gas.Oxygen] = 21.824779f; moles[(int) Gas.Nitrogen] = 82.10312f; - atmosSystem.SetMapAtmosphere(target, false, new GasMixture(2500) - { - Temperature = 293.15f, - Moles = moles, - }, atmos); + atmosSystem.SetMapAtmosphere(target, false, new GasMixture(moles, Atmospherics.T20C)); }); } diff --git a/Content.Server/Abilities/Mime/MimePowersSystem.cs b/Content.Server/Abilities/Mime/MimePowersSystem.cs index c1d2643d6fa..b3bd3392434 100644 --- a/Content.Server/Abilities/Mime/MimePowersSystem.cs +++ b/Content.Server/Abilities/Mime/MimePowersSystem.cs @@ -10,7 +10,7 @@ using Robust.Shared.Containers; using Robust.Shared.Map; using Robust.Shared.Timing; -using Content.Shared.Abilities.Psionics; //Nyano - Summary: Makes Mime psionic. +using Content.Shared.Psionics.Abilities; using Content.Shared.Speech.Muting; namespace Content.Server.Abilities.Mime diff --git a/Content.Server/Administration/Managers/AdminManager.Metrics.cs b/Content.Server/Administration/Managers/AdminManager.Metrics.cs new file mode 100644 index 00000000000..2fea931f1b9 --- /dev/null +++ b/Content.Server/Administration/Managers/AdminManager.Metrics.cs @@ -0,0 +1,98 @@ +using System.Diagnostics.Metrics; +using System.Runtime.InteropServices; +using Content.Server.Afk; +using Robust.Server.DataMetrics; + +namespace Content.Server.Administration.Managers; + +// Handles metrics reporting for active admin count and such. + +public sealed partial class AdminManager +{ + private Dictionary? _adminOnlineCounts; + + private const int SentinelRankId = -1; + + [Dependency] private readonly IMetricsManager _metrics = default!; + [Dependency] private readonly IAfkManager _afkManager = default!; + [Dependency] private readonly IMeterFactory _meterFactory = default!; + + private void InitializeMetrics() + { + _metrics.UpdateMetrics += MetricsOnUpdateMetrics; + + var meter = _meterFactory.Create("SS14.AdminManager"); + + meter.CreateObservableGauge( + "admins_online_count", + MeasureAdminCount, + null, + "The count of online admins"); + } + + private void MetricsOnUpdateMetrics() + { + _sawmill.Verbose("Updating metrics"); + + var dict = new Dictionary(); + + foreach (var (session, reg) in _admins) + { + var rankId = reg.RankId ?? SentinelRankId; + + ref var counts = ref CollectionsMarshal.GetValueRefOrAddDefault(dict, rankId, out _); + + if (reg.Data.Active) + { + if (_afkManager.IsAfk(session)) + counts.afk += 1; + else + counts.active += 1; + } + else + { + counts.deadminned += 1; + } + } + + // Neither prometheus-net nor dotnet-counters seem to handle stuff well if we STOP returning measurements. + // i.e. if the last admin with a rank disconnects. + // So if we have EVER reported a rank, always keep reporting it. + if (_adminOnlineCounts != null) + { + foreach (var rank in _adminOnlineCounts.Keys) + { + CollectionsMarshal.GetValueRefOrAddDefault(dict, rank, out _); + } + } + + // Make sure "no rank" is always available. Avoid "no data". + CollectionsMarshal.GetValueRefOrAddDefault(dict, SentinelRankId, out _); + + _adminOnlineCounts = dict; + } + + private IEnumerable> MeasureAdminCount() + { + if (_adminOnlineCounts == null) + yield break; + + foreach (var (rank, (active, afk, deadminned)) in _adminOnlineCounts) + { + yield return new Measurement( + active, + new KeyValuePair("state", "active"), + new KeyValuePair("rank", rank == SentinelRankId ? "none" : rank.ToString())); + + yield return new Measurement( + afk, + new KeyValuePair("state", "afk"), + new KeyValuePair("rank", rank == SentinelRankId ? "none" : rank.ToString())); + + yield return new Measurement( + deadminned, + new KeyValuePair("state", "deadminned"), + new KeyValuePair("rank", rank == SentinelRankId ? "none" : rank.ToString())); + } + } +} diff --git a/Content.Server/Administration/Managers/AdminManager.cs b/Content.Server/Administration/Managers/AdminManager.cs index 4eaa08fe9dd..b1cca46e63f 100644 --- a/Content.Server/Administration/Managers/AdminManager.cs +++ b/Content.Server/Administration/Managers/AdminManager.cs @@ -23,7 +23,7 @@ namespace Content.Server.Administration.Managers { - public sealed class AdminManager : IAdminManager, IPostInjectInit, IConGroupControllerImplementation + public sealed partial class AdminManager : IAdminManager, IPostInjectInit, IConGroupControllerImplementation { [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IServerDbManager _dbManager = default!; @@ -34,6 +34,7 @@ public sealed class AdminManager : IAdminManager, IPostInjectInit, IConGroupCont [Dependency] private readonly IServerConsoleHost _consoleHost = default!; [Dependency] private readonly IChatManager _chat = default!; [Dependency] private readonly ToolshedManager _toolshed = default!; + [Dependency] private readonly ILogManager _logManager = default!; private readonly Dictionary _admins = new(); private readonly HashSet _promotedPlayers = new(); @@ -49,6 +50,8 @@ public sealed class AdminManager : IAdminManager, IPostInjectInit, IConGroupCont private readonly AdminCommandPermissions _commandPermissions = new(); private readonly AdminCommandPermissions _toolshedCommandPermissions = new(); + private ISawmill _sawmill = default!; + public bool IsAdmin(ICommonSession session, bool includeDeAdmin = false) { return GetAdminData(session, includeDeAdmin) != null; @@ -181,6 +184,8 @@ public void ReloadAdminsWithRank(int rankId) public void Initialize() { + _sawmill = _logManager.GetSawmill("admin"); + _netMgr.RegisterNetMessage(); // Cache permissions for loaded console commands with the requisite attributes. @@ -234,6 +239,8 @@ public void Initialize() } _toolshed.ActivePermissionController = this; + + InitializeMetrics(); } public void PromoteHost(ICommonSession player) diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs b/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs index 8a819f59420..8ee52ad03e7 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs @@ -409,7 +409,7 @@ private void AddSmiteVerbs(GetVerbsEvent args) var fixtures = Comp(args.Target); xform.Anchored = false; // Just in case. _physics.SetBodyType(args.Target, BodyType.Dynamic, manager: fixtures, body: physics); - _physics.SetBodyStatus(physics, BodyStatus.InAir); + _physics.SetBodyStatus(args.Target, physics, BodyStatus.InAir); _physics.WakeBody(args.Target, manager: fixtures, body: physics); foreach (var fixture in fixtures.Fixtures.Values) @@ -424,8 +424,8 @@ private void AddSmiteVerbs(GetVerbsEvent args) _physics.SetLinearVelocity(args.Target, _random.NextVector2(1.5f, 1.5f), manager: fixtures, body: physics); _physics.SetAngularVelocity(args.Target, MathF.PI * 12, manager: fixtures, body: physics); - _physics.SetLinearDamping(physics, 0f); - _physics.SetAngularDamping(physics, 0f); + _physics.SetLinearDamping(args.Target, physics, 0f); + _physics.SetAngularDamping(args.Target, physics, 0f); }, Impact = LogImpact.Extreme, Message = Loc.GetString("admin-smite-pinball-description") @@ -444,7 +444,7 @@ private void AddSmiteVerbs(GetVerbsEvent args) xform.Anchored = false; // Just in case. _physics.SetBodyType(args.Target, BodyType.Dynamic, body: physics); - _physics.SetBodyStatus(physics, BodyStatus.InAir); + _physics.SetBodyStatus(args.Target, physics, BodyStatus.InAir); _physics.WakeBody(args.Target, manager: fixtures, body: physics); foreach (var fixture in fixtures.Fixtures.Values) @@ -454,8 +454,8 @@ private void AddSmiteVerbs(GetVerbsEvent args) _physics.SetLinearVelocity(args.Target, _random.NextVector2(8.0f, 8.0f), manager: fixtures, body: physics); _physics.SetAngularVelocity(args.Target, MathF.PI * 12, manager: fixtures, body: physics); - _physics.SetLinearDamping(physics, 0f); - _physics.SetAngularDamping(physics, 0f); + _physics.SetLinearDamping(args.Target, physics, 0f); + _physics.SetAngularDamping(args.Target, physics, 0f); }, Impact = LogImpact.Extreme, Message = Loc.GetString("admin-smite-yeet-description") diff --git a/Content.Server/Anomaly/AnomalySystem.Psionics.cs b/Content.Server/Anomaly/AnomalySystem.Psionics.cs index 95fda1d5035..84f200f47ba 100644 --- a/Content.Server/Anomaly/AnomalySystem.Psionics.cs +++ b/Content.Server/Anomaly/AnomalySystem.Psionics.cs @@ -1,4 +1,4 @@ -using Content.Server.Abilities.Psionics; //Nyano - Summary: the psniocs bin where dispel is located. +using Content.Server.Psionics.Abilities; using Content.Shared.Anomaly; using Content.Shared.Anomaly.Components; using Robust.Shared.Random; @@ -14,8 +14,6 @@ private void InitializePsionics() { SubscribeLocalEvent(OnDispelled); } - - //Nyano - Summary: gives dispellable behavior to Anomalies. private void OnDispelled(EntityUid uid, AnomalyComponent component, DispelledEvent args) { _dispel.DealDispelDamage(uid); diff --git a/Content.Server/Atmos/Commands/SetMapAtmosCommand.cs b/Content.Server/Atmos/Commands/SetMapAtmosCommand.cs new file mode 100644 index 00000000000..6f04cfb2da6 --- /dev/null +++ b/Content.Server/Atmos/Commands/SetMapAtmosCommand.cs @@ -0,0 +1,94 @@ +using Content.Server.Administration; +using Content.Server.Atmos.Components; +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Administration; +using Content.Shared.Atmos; +using Robust.Shared.Console; +using Robust.Shared.Map; + +namespace Content.Server.Atmos.Commands; + +[AdminCommand(AdminFlags.Admin)] +public sealed class AddMapAtmosCommand : LocalizedCommands +{ + [Dependency] private readonly IEntityManager _entities = default!; + [Dependency] private readonly IMapManager _map = default!; + + private const string _cmd = "cmd-set-map-atmos"; + public override string Command => "setmapatmos"; + public override string Description => Loc.GetString($"{_cmd}-desc"); + public override string Help => Loc.GetString($"{_cmd}-help"); + + public override void Execute(IConsoleShell shell, string argStr, string[] args) + { + if (args.Length < 2) + { + shell.WriteLine(Help); + return; + } + + int.TryParse(args[0], out var id); + var map = _map.GetMapEntityId(new MapId(id)); + if (!map.IsValid()) + { + shell.WriteError(Loc.GetString("cmd-parse-failure-mapid", ("arg", args[0]))); + return; + } + + if (!bool.TryParse(args[1], out var space)) + { + shell.WriteError(Loc.GetString("cmd-parse-failure-bool", ("arg", args[1]))); + return; + } + + if (space || args.Length < 4) + { + _entities.RemoveComponent(map); + shell.WriteLine(Loc.GetString($"{_cmd}-removed", ("map", id))); + return; + } + + if (!float.TryParse(args[2], out var temp)) + { + shell.WriteError(Loc.GetString("cmd-parse-failure-float", ("arg", args[2]))); + return; + } + + var mix = new GasMixture(Atmospherics.CellVolume) {Temperature = Math.Min(temp, Atmospherics.TCMB)}; + for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++) + { + if (args.Length == 3 + i) + break; + + if (!float.TryParse(args[3+i], out var moles)) + { + shell.WriteError(Loc.GetString("cmd-parse-failure-float", ("arg", args[3+i]))); + return; + } + + mix.AdjustMoles(i, moles); + } + + var atmos = _entities.EntitySysManager.GetEntitySystem(); + atmos.SetMapAtmosphere(map, space, mix); + shell.WriteLine(Loc.GetString($"{_cmd}-updated", ("map", id))); + } + + public override CompletionResult GetCompletion(IConsoleShell shell, string[] args) + { + if (args.Length == 1) + return CompletionResult.FromHintOptions(CompletionHelper.MapIds(_entities), Loc.GetString($"{_cmd}-hint-map")); + + if (args.Length == 2) + return CompletionResult.FromHintOptions(new[]{ "false", "true"}, Loc.GetString($"{_cmd}-hint-space")); + + if (!bool.TryParse(args[1], out var space) || space) + return CompletionResult.Empty; + + if (args.Length == 3) + return CompletionResult.FromHint(Loc.GetString($"{_cmd}-hint-temp")); + + var gas = (Gas) args.Length - 4; + return CompletionResult.FromHint(Loc.GetString($"{_cmd}-hint-gas" , ("gas", gas.ToString()))); + } +} diff --git a/Content.Server/Atmos/Components/AirtightComponent.cs b/Content.Server/Atmos/Components/AirtightComponent.cs index 897981724c9..ca107eafbe8 100644 --- a/Content.Server/Atmos/Components/AirtightComponent.cs +++ b/Content.Server/Atmos/Components/AirtightComponent.cs @@ -1,9 +1,10 @@ +using Content.Server.Atmos.EntitySystems; using Content.Shared.Atmos; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Server.Atmos.Components { - [RegisterComponent] + [RegisterComponent, Access(typeof(AirtightSystem))] public sealed partial class AirtightComponent : Component { public (EntityUid Grid, Vector2i Tile) LastPosition { get; set; } @@ -29,6 +30,7 @@ public sealed partial class AirtightComponent : Component [DataField("noAirWhenFullyAirBlocked")] public bool NoAirWhenFullyAirBlocked { get; set; } = true; + [Access(Other = AccessPermissions.ReadWriteExecute)] public AtmosDirection AirBlockedDirection => (AtmosDirection)CurrentAirBlockedDirection; } } diff --git a/Content.Server/Atmos/Components/GridAtmosphereComponent.cs b/Content.Server/Atmos/Components/GridAtmosphereComponent.cs index 7fcd63bc5d8..e682fd09644 100644 --- a/Content.Server/Atmos/Components/GridAtmosphereComponent.cs +++ b/Content.Server/Atmos/Components/GridAtmosphereComponent.cs @@ -28,6 +28,9 @@ public sealed partial class GridAtmosphereComponent : Component [IncludeDataField(customTypeSerializer:typeof(TileAtmosCollectionSerializer))] public Dictionary Tiles = new(1000); + [ViewVariables] + public HashSet MapTiles = new(1000); + [ViewVariables] public readonly HashSet ActiveTiles = new(1000); @@ -80,7 +83,10 @@ public sealed partial class GridAtmosphereComponent : Component public readonly HashSet InvalidatedCoords = new(1000); [ViewVariables] - public readonly Queue CurrentRunInvalidatedCoordinates = new(); + public readonly Queue CurrentRunInvalidatedTiles = new(); + + [ViewVariables] + public readonly List PossiblyDisconnectedTiles = new(100); [ViewVariables] public int InvalidatedCoordsCount => InvalidatedCoords.Count; diff --git a/Content.Server/Atmos/Components/IgniteOnCollideComponent.cs b/Content.Server/Atmos/Components/IgniteOnCollideComponent.cs index a58d3a3c122..710c37b62fe 100644 --- a/Content.Server/Atmos/Components/IgniteOnCollideComponent.cs +++ b/Content.Server/Atmos/Components/IgniteOnCollideComponent.cs @@ -1,8 +1,6 @@ -using Content.Server.Atmos.EntitySystems; - namespace Content.Server.Atmos.Components; -[RegisterComponent, Access(typeof(FlammableSystem))] +[RegisterComponent] public sealed partial class IgniteOnCollideComponent : Component { /// diff --git a/Content.Server/Atmos/Components/MapAtmosphereComponent.cs b/Content.Server/Atmos/Components/MapAtmosphereComponent.cs index bbf5ea6403e..6bdef901d44 100644 --- a/Content.Server/Atmos/Components/MapAtmosphereComponent.cs +++ b/Content.Server/Atmos/Components/MapAtmosphereComponent.cs @@ -12,12 +12,14 @@ public sealed partial class MapAtmosphereComponent : SharedMapAtmosphereComponen /// /// The default GasMixture a map will have. Space mixture by default. /// - [DataField("mixture"), ViewVariables(VVAccess.ReadWrite)] - public GasMixture? Mixture = GasMixture.SpaceGas; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public GasMixture Mixture = GasMixture.SpaceGas; /// /// Whether empty tiles will be considered space or not. /// - [DataField("space"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public bool Space = true; + + public SharedGasTileOverlaySystem.GasOverlayData Overlay; } diff --git a/Content.Server/Atmos/EntitySystems/AirtightSystem.cs b/Content.Server/Atmos/EntitySystems/AirtightSystem.cs index 97dccbaabb7..548d6a36926 100644 --- a/Content.Server/Atmos/EntitySystems/AirtightSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AirtightSystem.cs @@ -2,7 +2,6 @@ using Content.Server.Explosion.EntitySystems; using Content.Shared.Atmos; using JetBrains.Annotations; -using Robust.Shared.Map; using Robust.Shared.Map.Components; namespace Content.Server.Atmos.EntitySystems @@ -10,7 +9,7 @@ namespace Content.Server.Atmos.EntitySystems [UsedImplicitly] public sealed class AirtightSystem : EntitySystem { - [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Dependency] private readonly ExplosionSystem _explosionSystem = default!; @@ -121,19 +120,16 @@ public void UpdatePosition(Entity ent, TransformComponent? xf if (!xform.Anchored || !TryComp(xform.GridUid, out MapGridComponent? grid)) return; - airtight.LastPosition = (xform.GridUid.Value, grid.TileIndicesFor(xform.Coordinates)); - InvalidatePosition(airtight.LastPosition.Item1, airtight.LastPosition.Item2, airtight.FixVacuum && !airtight.AirBlocked); + var indices = _transform.GetGridTilePositionOrDefault((ent, xform), grid); + airtight.LastPosition = (xform.GridUid.Value, indices); + InvalidatePosition((xform.GridUid.Value, grid), indices); } - public void InvalidatePosition(EntityUid gridId, Vector2i pos, bool fixVacuum = false) + public void InvalidatePosition(Entity grid, Vector2i pos) { - if (!TryComp(gridId, out MapGridComponent? grid)) - return; - var query = EntityManager.GetEntityQuery(); - _explosionSystem.UpdateAirtightMap(gridId, pos, grid, query); - // TODO make atmos system use query - _atmosphereSystem.InvalidateTile(gridId, pos); + _explosionSystem.UpdateAirtightMap(grid, pos, grid, query); + _atmosphereSystem.InvalidateTile(grid.Owner, pos); } private AtmosDirection Rotate(AtmosDirection myDirection, Angle myAngle) diff --git a/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs b/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs index 4af32fce58f..c0284f26c90 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs @@ -97,22 +97,19 @@ private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e) } } - private AtmosDebugOverlayData ConvertTileToData(TileAtmosphere? tile) + private AtmosDebugOverlayData? ConvertTileToData(TileAtmosphere tile) { - if (tile == null) - return default; - return new AtmosDebugOverlayData( tile.GridIndices, tile.Air?.Temperature ?? default, tile.Air?.Moles, tile.PressureDirection, tile.LastPressureDirection, - tile.BlockedAirflow, + tile.AirtightData.BlockedDirections, tile.ExcitedGroup?.GetHashCode(), tile.Space, - false, - false); + tile.MapAtmosphere, + tile.NoGridTile); } public override void Update(float frameTime) diff --git a/Content.Server/Atmos/EntitySystems/AtmosObstructionEnumerator.cs b/Content.Server/Atmos/EntitySystems/AtmosObstructionEnumerator.cs deleted file mode 100644 index aed009e9a12..00000000000 --- a/Content.Server/Atmos/EntitySystems/AtmosObstructionEnumerator.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Content.Server.Atmos.Components; -using Robust.Shared.Map; -using Robust.Shared.Map.Enumerators; - -namespace Content.Server.Atmos.EntitySystems; - -public struct AtmosObstructionEnumerator -{ - private AnchoredEntitiesEnumerator _enumerator; - private EntityQuery _query; - - public AtmosObstructionEnumerator(AnchoredEntitiesEnumerator enumerator, EntityQuery query) - { - _enumerator = enumerator; - _query = query; - } - - public bool MoveNext([NotNullWhen(true)] out AirtightComponent? airtight) - { - if (!_enumerator.MoveNext(out var uid)) - { - airtight = null; - return false; - } - - // No rider, it makes it uglier. - // ReSharper disable once ConvertIfStatementToReturnStatement - if (!_query.TryGetComponent(uid.Value, out airtight)) - { - // ReSharper disable once TailRecursiveCall - return MoveNext(out airtight); - } - - return true; - } -} diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs index 310e602336a..cece99cacf6 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs @@ -85,10 +85,10 @@ public IEnumerable GetAllMixtures(EntityUid gridUid, bool excite = f return ev.Mixtures!; } - public void InvalidateTile(EntityUid gridUid, Vector2i tile) + public void InvalidateTile(Entity entity, Vector2i tile) { - var ev = new InvalidateTileMethodEvent(gridUid, tile); - RaiseLocalEvent(gridUid, ref ev); + if (_atmosQuery.Resolve(entity.Owner, ref entity.Comp, false)) + entity.Comp.InvalidatedCoords.Add(tile); } public GasMixture?[]? GetTileMixtures(EntityUid? gridUid, EntityUid? mapUid, List tiles, bool excite = false) @@ -176,11 +176,11 @@ public ReactionResult ReactTile(EntityUid gridId, Vector2i tile) public bool IsTileAirBlocked(EntityUid gridUid, Vector2i tile, AtmosDirection directions = AtmosDirection.All, MapGridComponent? mapGridComp = null) { - var ev = new IsTileAirBlockedMethodEvent(gridUid, tile, directions, mapGridComp); - RaiseLocalEvent(gridUid, ref ev); + if (!Resolve(gridUid, ref mapGridComp)) + return false; - // If nothing handled the event, it'll default to true. - return ev.Result; + var data = GetAirtightData(gridUid, mapGridComp, tile); + return data.BlockedDirections.IsFlagSet(directions); } public bool IsTileSpace(EntityUid? gridUid, EntityUid? mapUid, Vector2i tile, MapGridComponent? mapGridComp = null) @@ -231,12 +231,6 @@ public IEnumerable GetAdjacentTileMixtures(EntityUid gridUid, Vector return ev.Result ?? Enumerable.Empty(); } - public void UpdateAdjacent(EntityUid gridUid, Vector2i tile, MapGridComponent? mapGridComp = null) - { - var ev = new UpdateAdjacentMethodEvent(gridUid, tile, mapGridComp); - RaiseLocalEvent(gridUid, ref ev); - } - public void HotspotExpose(EntityUid gridUid, Vector2i tile, float exposedTemperature, float exposedVolume, EntityUid? sparkSourceUid = null, bool soh = false) { @@ -259,12 +253,6 @@ public bool IsHotspotActive(EntityUid gridUid, Vector2i tile) return ev.Result; } - public void FixTileVacuum(EntityUid gridUid, Vector2i tile) - { - var ev = new FixTileVacuumMethodEvent(gridUid, tile); - RaiseLocalEvent(gridUid, ref ev); - } - public void AddPipeNet(EntityUid gridUid, PipeNet pipeNet) { var ev = new AddPipeNetMethodEvent(gridUid, pipeNet); @@ -307,9 +295,6 @@ [ByRefEvent] private record struct IsSimulatedGridMethodEvent [ByRefEvent] private record struct GetAllMixturesMethodEvent (EntityUid Grid, bool Excite = false, IEnumerable? Mixtures = null, bool Handled = false); - [ByRefEvent] private record struct InvalidateTileMethodEvent - (EntityUid Grid, Vector2i Tile, bool Handled = false); - [ByRefEvent] private record struct GetTileMixturesMethodEvent (EntityUid? GridUid, EntityUid? MapUid, List Tiles, bool Excite = false, GasMixture?[]? Mixtures = null, bool Handled = false); @@ -319,16 +304,6 @@ [ByRefEvent] private record struct GetTileMixtureMethodEvent [ByRefEvent] private record struct ReactTileMethodEvent (EntityUid GridId, Vector2i Tile, ReactionResult Result = default, bool Handled = false); - [ByRefEvent] private record struct IsTileAirBlockedMethodEvent - (EntityUid Grid, Vector2i Tile, AtmosDirection Direction = AtmosDirection.All, MapGridComponent? MapGridComponent = null, bool Result = false, bool Handled = false) - { - /// - /// True if one of the enabled blockers has . Note - /// that this does not actually check if all directions are blocked. - /// - public bool NoAir = false; - } - [ByRefEvent] private record struct IsTileSpaceMethodEvent (EntityUid? Grid, EntityUid? Map, Vector2i Tile, MapGridComponent? MapGridComponent = null, bool Result = true, bool Handled = false); @@ -339,9 +314,6 @@ [ByRefEvent] private record struct GetAdjacentTileMixturesMethodEvent (EntityUid Grid, Vector2i Tile, bool IncludeBlocked, bool Excite, IEnumerable? Result = null, bool Handled = false); - [ByRefEvent] private record struct UpdateAdjacentMethodEvent - (EntityUid Grid, Vector2i Tile, MapGridComponent? MapGridComponent = null, bool Handled = false); - [ByRefEvent] private record struct HotspotExposeMethodEvent (EntityUid Grid, EntityUid? SparkSourceUid, Vector2i Tile, float ExposedTemperature, float ExposedVolume, bool soh, bool Handled = false); @@ -351,9 +323,6 @@ [ByRefEvent] private record struct HotspotExtinguishMethodEvent [ByRefEvent] private record struct IsHotspotActiveMethodEvent (EntityUid Grid, Vector2i Tile, bool Result = false, bool Handled = false); - [ByRefEvent] private record struct FixTileVacuumMethodEvent - (EntityUid Grid, Vector2i Tile, bool Handled = false); - [ByRefEvent] private record struct AddPipeNetMethodEvent (EntityUid Grid, PipeNet PipeNet, bool Handled = false); diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.ExcitedGroup.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.ExcitedGroup.cs index 1d809dcd032..de4c9199cf7 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.ExcitedGroup.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.ExcitedGroup.cs @@ -72,7 +72,8 @@ private void ExcitedGroupSelfBreakdown(GridAtmosphereComponent gridAtmosphere, E var tileSize = excitedGroup.Tiles.Count; - if (excitedGroup.Disposed) return; + if (excitedGroup.Disposed) + return; if (tileSize == 0) { @@ -98,7 +99,9 @@ private void ExcitedGroupSelfBreakdown(GridAtmosphereComponent gridAtmosphere, E foreach (var tile in excitedGroup.Tiles) { - if (tile?.Air == null) continue; + if (tile?.Air == null) + continue; + tile.Air.CopyFromMutable(combined); InvalidateVisuals(tile.GridIndex, tile.GridIndices); } @@ -106,21 +109,23 @@ private void ExcitedGroupSelfBreakdown(GridAtmosphereComponent gridAtmosphere, E excitedGroup.BreakdownCooldown = 0; } - private void ExcitedGroupDismantle(GridAtmosphereComponent gridAtmosphere, ExcitedGroup excitedGroup, bool unexcite = true) + /// + /// This de-activates and removes all tiles in an excited group. + /// + private void DeactivateGroupTiles(GridAtmosphereComponent gridAtmosphere, ExcitedGroup excitedGroup) { foreach (var tile in excitedGroup.Tiles) { tile.ExcitedGroup = null; - - if (!unexcite) - continue; - RemoveActiveTile(gridAtmosphere, tile); } excitedGroup.Tiles.Clear(); } + /// + /// This removes an excited group without de-activating its tiles. + /// private void ExcitedGroupDispose(GridAtmosphereComponent gridAtmosphere, ExcitedGroup excitedGroup) { if (excitedGroup.Disposed) @@ -129,9 +134,14 @@ private void ExcitedGroupDispose(GridAtmosphereComponent gridAtmosphere, Excited DebugTools.Assert(gridAtmosphere.ExcitedGroups.Contains(excitedGroup), "Grid Atmosphere does not contain Excited Group!"); excitedGroup.Disposed = true; - gridAtmosphere.ExcitedGroups.Remove(excitedGroup); - ExcitedGroupDismantle(gridAtmosphere, excitedGroup, false); + + foreach (var tile in excitedGroup.Tiles) + { + tile.ExcitedGroup = null; + } + + excitedGroup.Tiles.Clear(); } } } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs index 1f1a208b24b..d43cc81b0f8 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs @@ -14,6 +14,7 @@ public sealed partial class AtmosphereSystem private void InitializeGridAtmosphere() { SubscribeLocalEvent(OnGridAtmosphereInit); + SubscribeLocalEvent(OnGridAtmosphereStartup); SubscribeLocalEvent(OnAtmosphereRemove); SubscribeLocalEvent(OnGridSplit); @@ -22,19 +23,15 @@ private void InitializeGridAtmosphere() SubscribeLocalEvent(GridHasAtmosphere); SubscribeLocalEvent(GridIsSimulated); SubscribeLocalEvent(GridGetAllMixtures); - SubscribeLocalEvent(GridInvalidateTile); SubscribeLocalEvent(GridGetTileMixture); SubscribeLocalEvent(GridGetTileMixtures); SubscribeLocalEvent(GridReactTile); - SubscribeLocalEvent(GridIsTileAirBlocked); SubscribeLocalEvent(GridIsTileSpace); SubscribeLocalEvent(GridGetAdjacentTiles); SubscribeLocalEvent(GridGetAdjacentTileMixtures); - SubscribeLocalEvent(GridUpdateAdjacent); SubscribeLocalEvent(GridHotspotExpose); SubscribeLocalEvent(GridHotspotExtinguish); SubscribeLocalEvent(GridIsHotspotActive); - SubscribeLocalEvent(GridFixTileVacuum); SubscribeLocalEvent(GridAddPipeNet); SubscribeLocalEvent(GridRemovePipeNet); SubscribeLocalEvent(GridAddAtmosDevice); @@ -56,22 +53,23 @@ private void OnAtmosphereRemove(EntityUid uid, GridAtmosphereComponent component } } - private void OnGridAtmosphereInit(EntityUid uid, GridAtmosphereComponent gridAtmosphere, ComponentInit args) + private void OnGridAtmosphereInit(EntityUid uid, GridAtmosphereComponent component, ComponentInit args) { base.Initialize(); - if (!TryComp(uid, out MapGridComponent? mapGrid)) - return; - EnsureComp(uid); - - foreach (var (indices, tile) in gridAtmosphere.Tiles) + foreach (var tile in component.Tiles.Values) { - gridAtmosphere.InvalidatedCoords.Add(indices); tile.GridIndex = uid; } + } + + private void OnGridAtmosphereStartup(EntityUid uid, GridAtmosphereComponent component, ComponentStartup args) + { + if (!TryComp(uid, out MapGridComponent? mapGrid)) + return; - GridRepopulateTiles((uid, mapGrid, gridAtmosphere)); + InvalidateAllTiles((uid, mapGrid, component)); } private void OnGridSplit(EntityUid uid, GridAtmosphereComponent originalGridAtmos, ref GridSplitEvent args) @@ -104,8 +102,7 @@ private void OnGridSplit(EntityUid uid, GridAtmosphereComponent originalGridAtmo continue; // Copy a bunch of data over... Not great, maybe put this in TileAtmosphere? - newTileAtmosphere.Air = tileAtmosphere.Air?.Clone() ?? null; - newTileAtmosphere.MolesArchived = newTileAtmosphere.Air == null ? null : new float[Atmospherics.AdjustedNumberOfGases]; + newTileAtmosphere.Air = tileAtmosphere.Air?.Clone(); newTileAtmosphere.Hotspot = tileAtmosphere.Hotspot; newTileAtmosphere.HeatCapacity = tileAtmosphere.HeatCapacity; newTileAtmosphere.Temperature = tileAtmosphere.Temperature; @@ -170,15 +167,6 @@ IEnumerable EnumerateMixtures(EntityUid gridUid, GridAtmosphereCompo args.Handled = true; } - private void GridInvalidateTile(EntityUid uid, GridAtmosphereComponent component, ref InvalidateTileMethodEvent args) - { - if (args.Handled) - return; - - component.InvalidatedCoords.Add(args.Tile); - args.Handled = true; - } - private void GridGetTileMixture(EntityUid uid, GridAtmosphereComponent component, ref GetTileMixtureMethodEvent args) { @@ -233,43 +221,6 @@ private void GridReactTile(EntityUid uid, GridAtmosphereComponent component, ref args.Handled = true; } - private void GridIsTileAirBlocked(EntityUid uid, GridAtmosphereComponent component, - ref IsTileAirBlockedMethodEvent args) - { - if (args.Handled) - return; - - var mapGridComp = args.MapGridComponent; - - if (!Resolve(uid, ref mapGridComp)) - return; - - var directions = AtmosDirection.Invalid; - - var enumerator = GetObstructingComponentsEnumerator(mapGridComp, args.Tile); - - while (enumerator.MoveNext(out var obstructingComponent)) - { - if (!obstructingComponent.AirBlocked) - continue; - - // We set the directions that are air-blocked so far, - // as you could have a full obstruction with only 4 directional air blockers. - directions |= obstructingComponent.AirBlockedDirection; - args.NoAir |= obstructingComponent.NoAirWhenFullyAirBlocked; - - if (directions.IsFlagSet(args.Direction)) - { - args.Result = true; - args.Handled = true; - return; - } - } - - args.Result = false; - args.Handled = true; - } - private void GridIsTileSpace(EntityUid uid, GridAtmosphereComponent component, ref IsTileSpaceMethodEvent args) { if (args.Handled) @@ -331,71 +282,58 @@ IEnumerable EnumerateAdjacent(GridAtmosphereComponent grid, TileAtmo args.Handled = true; } - private void GridUpdateAdjacent(EntityUid uid, GridAtmosphereComponent component, - ref UpdateAdjacentMethodEvent args) + /// + /// Update array of adjacent tiles and the adjacency flags. Optionally activates all tiles with modified adjacencies. + /// + private void UpdateAdjacentTiles( + Entity ent, + TileAtmosphere tile, + bool activate = false) { - if (args.Handled) - return; - - var mapGridComp = args.MapGridComponent; - - if (!Resolve(uid, ref mapGridComp)) - return; - - var xform = Transform(uid); - EntityUid? mapUid = _mapManager.MapExists(xform.MapID) ? _mapManager.GetMapEntityId(xform.MapID) : null; - - if (!component.Tiles.TryGetValue(args.Tile, out var tile)) - return; + var uid = ent.Owner; + var atmos = ent.Comp1; + var blockedDirs = tile.AirtightData.BlockedDirections; + if (activate) + AddActiveTile(atmos, tile); tile.AdjacentBits = AtmosDirection.Invalid; - tile.BlockedAirflow = GetBlockedDirections(mapGridComp, tile.GridIndices); - for (var i = 0; i < Atmospherics.Directions; i++) { var direction = (AtmosDirection) (1 << i); + var adjacentIndices = tile.GridIndices.Offset(direction); - var otherIndices = tile.GridIndices.Offset(direction); - - if (!component.Tiles.TryGetValue(otherIndices, out var adjacent)) + TileAtmosphere? adjacent; + if (!tile.NoGridTile) { - adjacent = new TileAtmosphere(tile.GridIndex, otherIndices, - GetTileMixture(null, mapUid, otherIndices), - space: IsTileSpace(null, mapUid, otherIndices, mapGridComp)); + adjacent = GetOrNewTile(uid, atmos, adjacentIndices); } - - var oppositeDirection = direction.GetOpposite(); - - adjacent.BlockedAirflow = GetBlockedDirections(mapGridComp, adjacent.GridIndices); - - // Pass in MapGridComponent so we don't have to resolve it for every adjacent direction. - var tileBlockedEv = new IsTileAirBlockedMethodEvent(uid, tile.GridIndices, direction, mapGridComp); - GridIsTileAirBlocked(uid, component, ref tileBlockedEv); - - var adjacentBlockedEv = - new IsTileAirBlockedMethodEvent(uid, adjacent.GridIndices, oppositeDirection, mapGridComp); - GridIsTileAirBlocked(uid, component, ref adjacentBlockedEv); - - if (!adjacent.BlockedAirflow.IsFlagSet(oppositeDirection) && !tileBlockedEv.Result) + else if (!atmos.Tiles.TryGetValue(adjacentIndices, out adjacent)) { - adjacent.AdjacentBits |= oppositeDirection; - adjacent.AdjacentTiles[oppositeDirection.ToIndex()] = tile; + tile.AdjacentBits &= ~direction; + tile.AdjacentTiles[i] = null; + continue; } - else + + var adjBlockDirs = adjacent.AirtightData.BlockedDirections; + if (activate) + AddActiveTile(atmos, adjacent); + + var oppositeDirection = direction.GetOpposite(); + if (adjBlockDirs.IsFlagSet(oppositeDirection) || blockedDirs.IsFlagSet(direction)) { + // Adjacency is blocked by some airtight entity. + tile.AdjacentBits &= ~direction; adjacent.AdjacentBits &= ~oppositeDirection; + tile.AdjacentTiles[i] = null; adjacent.AdjacentTiles[oppositeDirection.ToIndex()] = null; } - - if (!tile.BlockedAirflow.IsFlagSet(direction) && !adjacentBlockedEv.Result) - { - tile.AdjacentBits |= direction; - tile.AdjacentTiles[direction.ToIndex()] = adjacent; - } else { - tile.AdjacentBits &= ~direction; - tile.AdjacentTiles[direction.ToIndex()] = null; + // No airtight entity in the way. + tile.AdjacentBits |= direction; + adjacent.AdjacentBits |= oppositeDirection; + tile.AdjacentTiles[i] = adjacent; + adjacent.AdjacentTiles[oppositeDirection.ToIndex()] = tile; } DebugTools.Assert(!(tile.AdjacentBits.IsFlagSet(direction) ^ @@ -409,6 +347,16 @@ private void GridUpdateAdjacent(EntityUid uid, GridAtmosphereComponent component tile.MonstermosInfo.CurrentTransferDirection = AtmosDirection.Invalid; } + private (GasMixture Air, bool IsSpace) GetDefaultMapAtmosphere(MapAtmosphereComponent? map) + { + if (map == null) + return (GasMixture.SpaceGas, true); + + var air = map.Mixture; + DebugTools.Assert(air.Immutable); + return (air, map.Space); + } + private void GridHotspotExpose(EntityUid uid, GridAtmosphereComponent component, ref HotspotExposeMethodEvent args) { if (args.Handled) @@ -451,54 +399,50 @@ private void GridIsHotspotActive(EntityUid uid, GridAtmosphereComponent componen args.Handled = true; } - private void GridFixTileVacuum(EntityUid uid, GridAtmosphereComponent component, ref FixTileVacuumMethodEvent args) + private void GridFixTileVacuum( + Entity ent, + TileAtmosphere tile, + float volume) { - if (args.Handled) - return; - - var adjEv = new GetAdjacentTileMixturesMethodEvent(uid, args.Tile, false, true); - GridGetAdjacentTileMixtures(uid, component, ref adjEv); - - if (!adjEv.Handled || !component.Tiles.TryGetValue(args.Tile, out var tile)) - return; - - if (!TryComp(uid, out var mapGridComp)) - return; - - var adjacent = adjEv.Result!.ToArray(); - - // Return early, let's not cause any funny NaNs or needless vacuums. - if (adjacent.Length == 0) - return; + DebugTools.AssertNotNull(tile.Air); + DebugTools.Assert(tile.Air?.Immutable == false ); + Array.Clear(tile.MolesArchived); + tile.ArchivedCycle = 0; - tile.Air = new GasMixture + var count = 0; + foreach (var adj in tile.AdjacentTiles) { - Volume = GetVolumeForTiles(mapGridComp, 1), - Temperature = Atmospherics.T20C - }; - - tile.MolesArchived = new float[Atmospherics.AdjustedNumberOfGases]; - tile.ArchivedCycle = 0; + if (adj?.Air != null) + count++; + } - var ratio = 1f / adjacent.Length; + var ratio = 1f / count; var totalTemperature = 0f; - foreach (var adj in adjacent) + foreach (var adj in tile.AdjacentTiles) { + if (adj?.Air == null) + continue; + totalTemperature += adj.Temperature; + // TODO ATMOS. Why is this removing and then re-adding air to the neighbouring tiles? + // Is it some rounding issue to do with Atmospherics.GasMinMoles? because otherwise this is just unnecessary. + // if we get rid of this, then this could also just add moles and then multiply by ratio at the end, rather + // than having to iterate over adjacent tiles twice. + // Remove a bit of gas from the adjacent ratio... - var mix = adj.RemoveRatio(ratio); + var mix = adj.Air.RemoveRatio(ratio); // And merge it to the new tile air. Merge(tile.Air, mix); // Return removed gas to its original mixture. - Merge(adj, mix); + Merge(adj.Air, mix); } // New temperature is the arithmetic mean of the sum of the adjacent temperatures... - tile.Air.Temperature = totalTemperature / adjacent.Length; + tile.Air.Temperature = totalTemperature / count; } private void GridAddPipeNet(EntityUid uid, GridAtmosphereComponent component, ref AddPipeNetMethodEvent args) @@ -547,30 +491,21 @@ private void GridRemoveAtmosDevice(EntityUid uid, GridAtmosphereComponent compon /// /// Repopulates all tiles on a grid atmosphere. /// - /// The grid where to get all valid tiles from. - /// The grid atmosphere where the tiles will be repopulated. - private void GridRepopulateTiles(Entity grid) + public void InvalidateAllTiles(Entity entity) { - var (uid, mapGrid, gridAtmosphere) = grid; - var volume = GetVolumeForTiles(mapGrid, 1); + var (uid, grid, atmos) = entity; + if (!Resolve(uid, ref grid, ref atmos)) + return; - foreach (var tile in mapGrid.GetAllTiles()) + foreach (var indices in atmos.Tiles.Keys) { - if (!gridAtmosphere.Tiles.ContainsKey(tile.GridIndices)) - gridAtmosphere.Tiles[tile.GridIndices] = new TileAtmosphere(tile.GridUid, tile.GridIndices, - new GasMixture(volume) { Temperature = Atmospherics.T20C }); - - gridAtmosphere.InvalidatedCoords.Add(tile.GridIndices); + atmos.InvalidatedCoords.Add(indices); } - TryComp(uid, out GasTileOverlayComponent? overlay); - - // Gotta do this afterwards so we can properly update adjacent tiles. - foreach (var (position, _) in gridAtmosphere.Tiles.ToArray()) + var enumerator = _map.GetAllTilesEnumerator(uid, grid); + while (enumerator.MoveNext(out var tile)) { - var ev = new UpdateAdjacentMethodEvent(uid, position); - GridUpdateAdjacent(uid, gridAtmosphere, ref ev); - InvalidateVisuals(uid, position, overlay); + atmos.InvalidatedCoords.Add(tile.Value.GridIndices); } } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs index 53035e1ed3c..77b5bf18af2 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs @@ -1,13 +1,11 @@ using Content.Server.Atmos.Components; using Content.Shared.Atmos; -using Content.Shared.Audio; using Content.Shared.Mobs.Components; using Content.Shared.Physics; using Robust.Shared.Audio; using Robust.Shared.Map; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; -using Robust.Shared.Player; using Robust.Shared.Random; using Robust.Shared.Utility; @@ -54,7 +52,7 @@ private void UpdateHighPressure(float frameTime) if (HasComp(uid) && TryComp(uid, out var body)) { - _physics.SetBodyStatus(body, BodyStatus.OnGround); + _physics.SetBodyStatus(uid, body, BodyStatus.OnGround); } if (TryComp(uid, out var fixtures)) @@ -77,7 +75,7 @@ private void AddMobMovedByPressure(EntityUid uid, MovedByPressureComponent compo if (!TryComp(uid, out var fixtures)) return; - _physics.SetBodyStatus(body, BodyStatus.InAir); + _physics.SetBodyStatus(uid, body, BodyStatus.InAir); foreach (var (id, fixture) in fixtures.Fixtures) { @@ -96,9 +94,9 @@ private void HighPressureMovements(Entity gridAtmospher // TODO ATMOS finish this // Don't play the space wind sound on tiles that are on fire... - if(tile.PressureDifference > 15 && !tile.Hotspot.Valid) + if (tile.PressureDifference > 15 && !tile.Hotspot.Valid) { - if(_spaceWindSoundCooldown == 0 && !string.IsNullOrEmpty(SpaceWindSound)) + if (_spaceWindSoundCooldown == 0 && !string.IsNullOrEmpty(SpaceWindSound)) { var coordinates = _mapSystem.ToCenterCoordinates(tile.GridIndex, tile.GridIndices); _audio.PlayPvs(SpaceWindSound, coordinates, AudioParams.Default.WithVariation(0.125f).WithVolume(MathHelper.Clamp(tile.PressureDifference / 10, 10, 100))); diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs index 795c6e0547e..c27e18b55b0 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs @@ -1,12 +1,13 @@ using Content.Server.Atmos.Components; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; +using Robust.Shared.Utility; namespace Content.Server.Atmos.EntitySystems { public sealed partial class AtmosphereSystem { - private void ProcessCell(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, int fireCount, GasTileOverlayComponent? visuals) + private void ProcessCell(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, int fireCount, GasTileOverlayComponent visuals) { // Can't process a tile without air if (tile.Air == null) @@ -116,15 +117,9 @@ private void ProcessCell(GridAtmosphereComponent gridAtmosphere, TileAtmosphere private void Archive(TileAtmosphere tile, int fireCount) { if (tile.Air != null) - { tile.Air.Moles.AsSpan().CopyTo(tile.MolesArchived.AsSpan()); - tile.TemperatureArchived = tile.Air.Temperature; - } - else - { - tile.TemperatureArchived = tile.Temperature; - } + tile.TemperatureArchived = tile.Temperature; tile.ArchivedCycle = fireCount; } @@ -166,6 +161,12 @@ private void AddActiveTile(GridAtmosphereComponent gridAtmosphere, TileAtmospher /// Whether to dispose of the tile's private void RemoveActiveTile(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, bool disposeExcitedGroup = true) { + DebugTools.Assert(tile.Excited == gridAtmosphere.ActiveTiles.Contains(tile)); + DebugTools.Assert(tile.Excited || tile.ExcitedGroup == null); + + if (!tile.Excited) + return; + tile.Excited = false; gridAtmosphere.ActiveTiles.Remove(tile); @@ -186,7 +187,6 @@ public float GetHeatCapacityArchived(TileAtmosphere tile) if (tile.Air == null) return tile.HeatCapacity; - // Moles archived is not null if air is not null. return GetHeatCapacityCalculation(tile.MolesArchived!, tile.Space); } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs index 916191cb050..ed105c8d33f 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs @@ -1,6 +1,8 @@ using Content.Server.Atmos.Components; using Content.Shared.Atmos.Components; using Robust.Shared.GameStates; +using Robust.Shared.Map.Components; +using Robust.Shared.Utility; namespace Content.Server.Atmos.EntitySystems; @@ -8,10 +10,25 @@ public partial class AtmosphereSystem { private void InitializeMap() { + SubscribeLocalEvent(OnMapStartup); + SubscribeLocalEvent(OnMapRemove); SubscribeLocalEvent(MapIsTileSpace); SubscribeLocalEvent(MapGetTileMixture); SubscribeLocalEvent(MapGetTileMixtures); SubscribeLocalEvent(OnMapGetState); + SubscribeLocalEvent(OnGridParentChanged); + } + + private void OnMapStartup(EntityUid uid, MapAtmosphereComponent component, ComponentInit args) + { + component.Mixture.MarkImmutable(); + component.Overlay = _gasTileOverlaySystem.GetOverlayData(component.Mixture); + } + + private void OnMapRemove(EntityUid uid, MapAtmosphereComponent component, ComponentRemove args) + { + if (!TerminatingOrDeleted(uid)) + RefreshAllGridMapAtmospheres(uid); } private void MapIsTileSpace(EntityUid uid, MapAtmosphereComponent component, ref IsTileSpaceMethodEvent args) @@ -28,54 +45,115 @@ private void MapGetTileMixture(EntityUid uid, MapAtmosphereComponent component, if (args.Handled) return; - // Clone the mixture, if possible. - args.Mixture = component.Mixture?.Clone(); + args.Mixture = component.Mixture; args.Handled = true; } private void MapGetTileMixtures(EntityUid uid, MapAtmosphereComponent component, ref GetTileMixturesMethodEvent args) { - if (args.Handled || component.Mixture == null) + if (args.Handled) return; args.Handled = true; args.Mixtures ??= new GasMixture?[args.Tiles.Count]; for (var i = 0; i < args.Tiles.Count; i++) { - args.Mixtures[i] ??= component.Mixture.Clone(); + args.Mixtures[i] ??= component.Mixture; } } private void OnMapGetState(EntityUid uid, MapAtmosphereComponent component, ref ComponentGetState args) { - args.State = new MapAtmosphereComponentState(_gasTileOverlaySystem.GetOverlayData(component.Mixture)); + args.State = new MapAtmosphereComponentState(component.Overlay); + } + + public void SetMapAtmosphere(EntityUid uid, bool space, GasMixture mixture) + { + DebugTools.Assert(HasComp(uid)); + var component = EnsureComp(uid); + SetMapGasMixture(uid, mixture, component, false); + SetMapSpace(uid, space, component, false); + RefreshAllGridMapAtmospheres(uid); } - public void SetMapAtmosphere(EntityUid uid, bool space, GasMixture mixture, MapAtmosphereComponent? component = null) + public void SetMapGasMixture(EntityUid uid, GasMixture mixture, MapAtmosphereComponent? component = null, bool updateTiles = true) { if (!Resolve(uid, ref component)) return; - component.Space = space; + if (!mixture.Immutable) + { + mixture = mixture.Clone(); + mixture.MarkImmutable(); + } + component.Mixture = mixture; - Dirty(component); + component.Overlay = _gasTileOverlaySystem.GetOverlayData(component.Mixture); + Dirty(uid, component); + if (updateTiles) + RefreshAllGridMapAtmospheres(uid); } - public void SetMapGasMixture(EntityUid uid, GasMixture? mixture, MapAtmosphereComponent? component = null) + public void SetMapSpace(EntityUid uid, bool space, MapAtmosphereComponent? component = null, bool updateTiles = true) { if (!Resolve(uid, ref component)) return; - component.Mixture = mixture; - Dirty(component); + if (component.Space == space) + return; + + component.Space = space; + + if (updateTiles) + RefreshAllGridMapAtmospheres(uid); } - public void SetMapSpace(EntityUid uid, bool space, MapAtmosphereComponent? component = null) + /// + /// Forces a refresh of all MapAtmosphere tiles on every grid on a map. + /// + public void RefreshAllGridMapAtmospheres(EntityUid map) { - if (!Resolve(uid, ref component)) + DebugTools.Assert(HasComp(map)); + var enumerator = AllEntityQuery(); + while (enumerator.MoveNext(out var grid, out var atmos, out var xform)) + { + if (xform.MapUid == map) + RefreshMapAtmosphereTiles((grid, atmos)); + } + } + + /// + /// Forces a refresh of all MapAtmosphere tiles on a given grid. + /// + private void RefreshMapAtmosphereTiles(Entity grid) + { + if (!Resolve(grid.Owner, ref grid.Comp)) return; - component.Space = space; - Dirty(component); + var atmos = grid.Comp; + foreach (var tile in atmos.MapTiles) + { + RemoveMapAtmos(atmos, tile); + atmos.InvalidatedCoords.Add(tile.GridIndices); + } + atmos.MapTiles.Clear(); + } + + /// + /// Handles updating map-atmospheres when grids move across maps. + /// + private void OnGridParentChanged(Entity grid, ref EntParentChangedMessage args) + { + // Do nothing if detaching to nullspace + if (!args.Transform.ParentUid.IsValid()) + return; + + // Avoid doing work if moving from a space-map to another space-map. + if (args.OldParent == null + || HasComp(args.OldParent) + || HasComp(args.Transform.ParentUid)) + { + RefreshMapAtmosphereTiles((grid, grid)); + } } } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs index aceda3cd332..f156125b0ff 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs @@ -5,7 +5,6 @@ using Content.Shared.Atmos; using Content.Shared.Atmos.Components; using Content.Shared.Database; -using Content.Shared.Doors.Components; using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Random; @@ -27,7 +26,10 @@ public sealed partial class AtmosphereSystem private readonly TileAtmosphere[] _depressurizeSpaceTiles = new TileAtmosphere[Atmospherics.MonstermosHardTileLimit]; private readonly TileAtmosphere[] _depressurizeProgressionOrder = new TileAtmosphere[Atmospherics.MonstermosHardTileLimit * 2]; - private void EqualizePressureInZone(Entity ent, TileAtmosphere tile, int cycleNum, GasTileOverlayComponent? visuals) + private void EqualizePressureInZone( + Entity ent, + TileAtmosphere tile, + int cycleNum) { if (tile.Air == null || (tile.MonstermosInfo.LastCycle >= cycleNum)) return; // Already done. @@ -56,7 +58,7 @@ private void EqualizePressureInZone(Entity ent, TileAtmosphere tile, int cycleNum, GasTileOverlayComponent? visuals) + private void ExplosivelyDepressurize( + Entity ent, + TileAtmosphere tile, + int cycleNum) { // Check if explosive depressurization is enabled and if the tile is valid. if (!MonstermosDepressurization || tile.Air == null) @@ -368,7 +382,7 @@ private void ExplosivelyDepressurize(Entity= limit) break; + if (tileCount >= limit) + break; } } else @@ -437,13 +458,21 @@ private void ExplosivelyDepressurize(Entity 10 && (totalMolesRemoved / tileCount) > 10) + if (tileCount > 10 && (totalMolesRemoved / tileCount) > 10) _adminLog.Add(LogType.ExplosiveDepressurization, LogImpact.High, $"Explosive depressurization removed {totalMolesRemoved} moles from {tileCount} tiles starting from position {tile.GridIndices:position} on grid ID {tile.GridIndex:grid}"); @@ -544,36 +573,33 @@ private void ExplosivelyDepressurize(Entity ent, TileAtmosphere tile, TileAtmosphere other, GasTileOverlayComponent? visuals, MapGridComponent mapGrid) + private void ConsiderFirelocks( + Entity ent, + TileAtmosphere tile, + TileAtmosphere other) { var reconsiderAdjacent = false; - foreach (var entity in mapGrid.GetAnchoredEntities(tile.GridIndices)) + var mapGrid = ent.Comp3; + foreach (var entity in _map.GetAnchoredEntities(ent.Owner, mapGrid, tile.GridIndices)) { - if (!TryComp(entity, out FirelockComponent? firelock)) - continue; - - reconsiderAdjacent |= _firelockSystem.EmergencyPressureStop(entity, firelock); + if (_firelockQuery.TryGetComponent(entity, out var firelock)) + reconsiderAdjacent |= _firelockSystem.EmergencyPressureStop(entity, firelock); } - foreach (var entity in mapGrid.GetAnchoredEntities(other.GridIndices)) + foreach (var entity in _map.GetAnchoredEntities(ent.Owner, mapGrid, other.GridIndices)) { - if (!TryComp(entity, out FirelockComponent? firelock)) - continue; - - reconsiderAdjacent |= _firelockSystem.EmergencyPressureStop(entity, firelock); + if (_firelockQuery.TryGetComponent(entity, out var firelock)) + reconsiderAdjacent |= _firelockSystem.EmergencyPressureStop(entity, firelock); } if (!reconsiderAdjacent) return; - var (owner, gridAtmosphere) = ent; - var tileEv = new UpdateAdjacentMethodEvent(owner, tile.GridIndices); - var otherEv = new UpdateAdjacentMethodEvent(owner, other.GridIndices); - GridUpdateAdjacent(owner, gridAtmosphere, ref tileEv); - GridUpdateAdjacent(owner, gridAtmosphere, ref otherEv); - InvalidateVisuals(tile.GridIndex, tile.GridIndices, visuals); - InvalidateVisuals(other.GridIndex, other.GridIndices, visuals); + UpdateAdjacentTiles(ent, tile); + UpdateAdjacentTiles(ent, other); + InvalidateVisuals(tile.GridIndex, tile.GridIndices, ent); + InvalidateVisuals(other.GridIndex, other.GridIndices, ent); } private void FinalizeEq(GridAtmosphereComponent gridAtmosphere, TileAtmosphere tile, GasTileOverlayComponent? visuals) @@ -642,7 +668,7 @@ private void AdjustEqMovement(TileAtmosphere tile, AtmosDirection direction, flo if (adj == null) { var nonNull = tile.AdjacentTiles.Where(x => x != null).Count(); - Logger.Error($"Encountered null adjacent tile in {nameof(AdjustEqMovement)}. Dir: {direction}, Tile: {tile.Tile}, non-null adj count: {nonNull}, Trace: {Environment.StackTrace}"); + Log.Error($"Encountered null adjacent tile in {nameof(AdjustEqMovement)}. Dir: {direction}, Tile: ({tile.GridIndex}, {tile.GridIndices}), non-null adj count: {nonNull}, Trace: {Environment.StackTrace}"); return; } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs index 4f8df0af670..1f3ca2145b9 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs @@ -1,6 +1,5 @@ using Content.Server.Atmos.Components; using Content.Server.Atmos.Piping.Components; -using Content.Server.NodeContainer.NodeGroups; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; using Content.Shared.Maps; @@ -8,6 +7,7 @@ using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Timing; +using Robust.Shared.Utility; namespace Content.Server.Atmos.EntitySystems { @@ -30,131 +30,249 @@ public sealed partial class AtmosphereSystem private int _currentRunAtmosphereIndex; private bool _simulationPaused; - private readonly List> _currentRunAtmosphere = new(); + private TileAtmosphere GetOrNewTile(EntityUid owner, GridAtmosphereComponent atmosphere, Vector2i index) + { + var tile = atmosphere.Tiles.GetOrNew(index, out var existing); + if (existing) + return tile; + + atmosphere.InvalidatedCoords.Add(index); + tile.GridIndex = owner; + tile.GridIndices = index; + return tile; + } + + private readonly List> _currentRunAtmosphere = new(); /// /// Revalidates all invalid coordinates in a grid atmosphere. + /// I.e., process any tiles that have had their airtight blockers modified. /// /// The grid atmosphere in question. /// Whether the process succeeded or got paused due to time constrains. - private bool ProcessRevalidate(Entity ent, GasTileOverlayComponent? visuals) + private bool ProcessRevalidate(Entity ent) { - var (owner, atmosphere) = ent; + if (ent.Comp4.MapUid == null) + { + Log.Error($"Attempted to process atmosphere on a map-less grid? Grid: {ToPrettyString(ent)}"); + return true; + } + + var (uid, atmosphere, visuals, grid, xform) = ent; + var volume = GetVolumeForTiles(grid); + TryComp(xform.MapUid, out MapAtmosphereComponent? mapAtmos); + if (!atmosphere.ProcessingPaused) { - atmosphere.CurrentRunInvalidatedCoordinates.Clear(); - atmosphere.CurrentRunInvalidatedCoordinates.EnsureCapacity(atmosphere.InvalidatedCoords.Count); - foreach (var tile in atmosphere.InvalidatedCoords) + atmosphere.CurrentRunInvalidatedTiles.Clear(); + atmosphere.CurrentRunInvalidatedTiles.EnsureCapacity(atmosphere.InvalidatedCoords.Count); + foreach (var indices in atmosphere.InvalidatedCoords) { - atmosphere.CurrentRunInvalidatedCoordinates.Enqueue(tile); + var tile = GetOrNewTile(uid, atmosphere, indices); + atmosphere.CurrentRunInvalidatedTiles.Enqueue(tile); + + // Update tile.IsSpace and tile.MapAtmosphere, and tile.AirtightData. + UpdateTileData(ent, mapAtmos, tile); } atmosphere.InvalidatedCoords.Clear(); + + if (_simulationStopwatch.Elapsed.TotalMilliseconds >= AtmosMaxProcessTime) + return false; } - if (!TryComp(owner, out MapGridComponent? mapGridComp)) - return true; + var number = 0; + while (atmosphere.CurrentRunInvalidatedTiles.TryDequeue(out var tile)) + { + DebugTools.Assert(atmosphere.Tiles.GetValueOrDefault(tile.GridIndices) == tile); + UpdateAdjacentTiles(ent, tile, activate: true); + UpdateTileAir(ent, tile, volume); + InvalidateVisuals(uid, tile.GridIndices, visuals); - var mapUid = _mapManager.GetMapEntityIdOrThrow(Transform(owner).MapID); + if (number++ < InvalidCoordinatesLagCheckIterations) + continue; - var volume = GetVolumeForTiles(mapGridComp); + number = 0; + // Process the rest next time. + if (_simulationStopwatch.Elapsed.TotalMilliseconds >= AtmosMaxProcessTime) + return false; + } - var number = 0; - while (atmosphere.CurrentRunInvalidatedCoordinates.TryDequeue(out var indices)) + TrimDisconnectedMapTiles(ent); + return true; + } + + /// + /// This method queued a tile and all of its neighbours up for processing by . + /// + public void QueueTileTrim(GridAtmosphereComponent atmos, TileAtmosphere tile) + { + if (!tile.TrimQueued) { - if (!atmosphere.Tiles.TryGetValue(indices, out var tile)) + tile.TrimQueued = true; + atmos.PossiblyDisconnectedTiles.Add(tile); + } + + for (var i = 0; i < Atmospherics.Directions; i++) + { + var direction = (AtmosDirection) (1 << i); + var indices = tile.GridIndices.Offset(direction); + if (atmos.Tiles.TryGetValue(indices, out var adj) + && adj.NoGridTile + && !adj.TrimQueued) { - tile = new TileAtmosphere(owner, indices, - new GasMixture(volume) { Temperature = Atmospherics.T20C }); - atmosphere.Tiles[indices] = tile; + adj.TrimQueued = true; + atmos.PossiblyDisconnectedTiles.Add(adj); } + } + } - var airBlockedEv = new IsTileAirBlockedMethodEvent(owner, indices, MapGridComponent:mapGridComp); - GridIsTileAirBlocked(owner, atmosphere, ref airBlockedEv); - var isAirBlocked = airBlockedEv.Result; + /// + /// Tiles in a are either grid-tiles, or they they should be are tiles + /// adjacent to grid-tiles that represent the map's atmosphere. This method trims any map-tiles that are no longer + /// adjacent to any grid-tiles. + /// + private void TrimDisconnectedMapTiles( + Entity ent) + { + var atmos = ent.Comp1; - var oldBlocked = tile.BlockedAirflow; - var updateAdjacentEv = new UpdateAdjacentMethodEvent(owner, indices, mapGridComp); - GridUpdateAdjacent(owner, atmosphere, ref updateAdjacentEv); + foreach (var tile in atmos.PossiblyDisconnectedTiles) + { + tile.TrimQueued = false; + if (!tile.NoGridTile) + continue; - // Blocked airflow changed, rebuild excited groups! - if (tile.Excited && tile.BlockedAirflow != oldBlocked) + var connected = false; + for (var i = 0; i < Atmospherics.Directions; i++) { - RemoveActiveTile(atmosphere, tile); + var indices = tile.GridIndices.Offset((AtmosDirection) (1 << i)); + if (_map.TryGetTile(ent.Comp3, indices, out var gridTile) && !gridTile.IsEmpty) + { + connected = true; + break; + } } - // Call this instead of the grid method as the map has a say on whether the tile is space or not. - if ((!mapGridComp.TryGetTileRef(indices, out var t) || t.IsSpace(_tileDefinitionManager)) && !isAirBlocked) + if (!connected) { - tile.Air = GetTileMixture(null, mapUid, indices); - tile.MolesArchived = tile.Air != null ? new float[Atmospherics.AdjustedNumberOfGases] : null; - tile.Space = IsTileSpace(null, mapUid, indices, mapGridComp); + RemoveActiveTile(atmos, tile); + atmos.Tiles.Remove(tile.GridIndices); } - else if (isAirBlocked) + } + + atmos.PossiblyDisconnectedTiles.Clear(); + } + + /// + /// Checks whether a tile has a corresponding grid-tile, or whether it is a "map" tile. Also checks whether the + /// tile should be considered "space" + /// + private void UpdateTileData( + Entity ent, + MapAtmosphereComponent? mapAtmos, + TileAtmosphere tile) + { + var idx = tile.GridIndices; + bool mapAtmosphere; + if (_map.TryGetTile(ent.Comp3, idx, out var gTile) && !gTile.IsEmpty) + { + var contentDef = (ContentTileDefinition) _tileDefinitionManager[gTile.TypeId]; + mapAtmosphere = contentDef.MapAtmosphere; + tile.ThermalConductivity = contentDef.ThermalConductivity; + tile.HeatCapacity = contentDef.HeatCapacity; + tile.NoGridTile = false; + } + else + { + mapAtmosphere = true; + tile.ThermalConductivity = 0.5f; + tile.HeatCapacity = float.PositiveInfinity; + + if (!tile.NoGridTile) { - if (airBlockedEv.NoAir) - { - tile.Air = null; - tile.MolesArchived = null; - tile.ArchivedCycle = 0; - tile.LastShare = 0f; - tile.Hotspot = new Hotspot(); - } + tile.NoGridTile = true; + + // This tile just became a non-grid atmos tile. + // It, or one of its neighbours, might now be completely disconnected from the grid. + QueueTileTrim(ent.Comp1, tile); } - else - { - if (tile.Air == null && NeedsVacuumFixing(mapGridComp, indices)) - { - var vacuumEv = new FixTileVacuumMethodEvent(owner, indices); - GridFixTileVacuum(owner, atmosphere, ref vacuumEv); - } + } - // Tile used to be space, but isn't anymore. - if (tile.Space || (tile.Air?.Immutable ?? false)) - { - tile.Air = null; - tile.MolesArchived = null; - tile.ArchivedCycle = 0; - tile.LastShare = 0f; - tile.Space = false; - } + UpdateAirtightData(ent.Owner, ent.Comp1, ent.Comp3, tile); - tile.Air ??= new GasMixture(volume){Temperature = Atmospherics.T20C}; - tile.MolesArchived ??= new float[Atmospherics.AdjustedNumberOfGases]; + if (mapAtmosphere) + { + if (!tile.MapAtmosphere) + { + (tile.Air, tile.Space) = GetDefaultMapAtmosphere(mapAtmos); + tile.MapAtmosphere = true; + ent.Comp1.MapTiles.Add(tile); } - // We activate the tile. - AddActiveTile(atmosphere, tile); + DebugTools.AssertNotNull(tile.Air); + DebugTools.Assert(tile.Air?.Immutable ?? false); + return; + } - // TODO ATMOS: Query all the contents of this tile (like walls) and calculate the correct thermal conductivity and heat capacity - var tileDef = mapGridComp.TryGetTileRef(indices, out var tileRef) - ? tileRef.GetContentTileDefinition(_tileDefinitionManager) - : null; + if (!tile.MapAtmosphere) + return; - tile.ThermalConductivity = tileDef?.ThermalConductivity ?? 0.5f; - tile.HeatCapacity = tileDef?.HeatCapacity ?? float.PositiveInfinity; - InvalidateVisuals(owner, indices, visuals); + // Tile used to be exposed to the map's atmosphere, but isn't anymore. + RemoveMapAtmos(ent.Comp1, tile); + } - for (var i = 0; i < Atmospherics.Directions; i++) - { - var direction = (AtmosDirection) (1 << i); - var otherIndices = indices.Offset(direction); + private void RemoveMapAtmos(GridAtmosphereComponent atmos, TileAtmosphere tile) + { + DebugTools.Assert(tile.MapAtmosphere); + DebugTools.AssertNotNull(tile.Air); + DebugTools.Assert(tile.Air?.Immutable ?? false); + tile.MapAtmosphere = false; + atmos.MapTiles.Remove(tile); + tile.Air = null; + Array.Clear(tile.MolesArchived); + tile.ArchivedCycle = 0; + tile.LastShare = 0f; + tile.Space = false; + } - if (atmosphere.Tiles.TryGetValue(otherIndices, out var otherTile)) - AddActiveTile(atmosphere, otherTile); - } + /// + /// Check whether a grid-tile should have an air mixture, and give it one if it doesn't already have one. + /// + private void UpdateTileAir( + Entity ent, + TileAtmosphere tile, + float volume) + { + if (tile.MapAtmosphere) + { + DebugTools.AssertNotNull(tile.Air); + DebugTools.Assert(tile.Air?.Immutable ?? false); + return; + } - if (number++ < InvalidCoordinatesLagCheckIterations) - continue; + var data = tile.AirtightData; + var fullyBlocked = data.BlockedDirections == AtmosDirection.All; - number = 0; - // Process the rest next time. - if (_simulationStopwatch.Elapsed.TotalMilliseconds >= AtmosMaxProcessTime) - { - return false; - } + if (fullyBlocked && data.NoAirWhenBlocked) + { + if (tile.Air == null) + return; + + tile.Air = null; + Array.Clear(tile.MolesArchived); + tile.ArchivedCycle = 0; + tile.LastShare = 0f; + tile.Hotspot = new Hotspot(); + return; } - return true; + if (tile.Air != null) + return; + + tile.Air = new GasMixture(volume){Temperature = Atmospherics.T20C}; + + if (data.FixVacuum) + GridFixTileVacuum(ent, tile, volume); } private void QueueRunTiles( @@ -170,19 +288,16 @@ private void QueueRunTiles( } } - private bool ProcessTileEqualize(Entity ent, GasTileOverlayComponent? visuals) + private bool ProcessTileEqualize(Entity ent) { - var (uid, atmosphere) = ent; + var atmosphere = ent.Comp1; if (!atmosphere.ProcessingPaused) QueueRunTiles(atmosphere.CurrentRunTiles, atmosphere.ActiveTiles); - if (!TryComp(uid, out MapGridComponent? mapGridComp)) - throw new Exception("Tried to process a grid atmosphere on an entity that isn't a grid!"); - var number = 0; while (atmosphere.CurrentRunTiles.TryDequeue(out var tile)) { - EqualizePressureInZone((uid, mapGridComp, atmosphere), tile, atmosphere.UpdateCounter, visuals); + EqualizePressureInZone(ent, tile, atmosphere.UpdateCounter); if (number++ < LagCheckIterations) continue; @@ -198,7 +313,7 @@ private bool ProcessTileEqualize(Entity ent, GasTileOve return true; } - private bool ProcessActiveTiles(GridAtmosphereComponent atmosphere, GasTileOverlayComponent? visuals) + private bool ProcessActiveTiles(GridAtmosphereComponent atmosphere, GasTileOverlayComponent visuals) { if(!atmosphere.ProcessingPaused) QueueRunTiles(atmosphere.CurrentRunTiles, atmosphere.ActiveTiles); @@ -240,11 +355,11 @@ private bool ProcessExcitedGroups(GridAtmosphereComponent gridAtmosphere) excitedGroup.BreakdownCooldown++; excitedGroup.DismantleCooldown++; - if(excitedGroup.BreakdownCooldown > Atmospherics.ExcitedGroupBreakdownCycles) + if (excitedGroup.BreakdownCooldown > Atmospherics.ExcitedGroupBreakdownCycles) ExcitedGroupSelfBreakdown(gridAtmosphere, excitedGroup); - - else if(excitedGroup.DismantleCooldown > Atmospherics.ExcitedGroupsDismantleCycles) - ExcitedGroupDismantle(gridAtmosphere, excitedGroup); + else if (excitedGroup.DismantleCooldown > Atmospherics.ExcitedGroupsDismantleCycles) + DeactivateGroupTiles(gridAtmosphere, excitedGroup); + // TODO ATMOS. What is the point of this? why is this only de-exciting the group? Shouldn't it also dismantle it? if (number++ < LagCheckIterations) continue; @@ -435,10 +550,10 @@ private void UpdateProcessing(float frameTime) _currentRunAtmosphereIndex = 0; _currentRunAtmosphere.Clear(); - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var grid)) + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var atmos, out var overlay, out var grid, out var xform )) { - _currentRunAtmosphere.Add((uid, grid)); + _currentRunAtmosphere.Add((uid, atmos, overlay, grid, xform)); } } @@ -448,8 +563,7 @@ private void UpdateProcessing(float frameTime) for (; _currentRunAtmosphereIndex < _currentRunAtmosphere.Count; _currentRunAtmosphereIndex++) { var ent = _currentRunAtmosphere[_currentRunAtmosphereIndex]; - var (owner, atmosphere) = ent; - TryComp(owner, out GasTileOverlayComponent? visuals); + var (owner, atmosphere, visuals, grid, xform) = ent; if (!TryComp(owner, out TransformComponent? x) || x.MapUid == null @@ -474,13 +588,14 @@ private void UpdateProcessing(float frameTime) switch (atmosphere.State) { case AtmosphereProcessingState.Revalidate: - if (!ProcessRevalidate(ent, visuals)) + if (!ProcessRevalidate(ent)) { atmosphere.ProcessingPaused = true; return; } atmosphere.ProcessingPaused = false; + // Next state depends on whether monstermos equalization is enabled or not. // Note: We do this here instead of on the tile equalization step to prevent ending it early. // Therefore, a change to this CVar might only be applied after that step is over. @@ -489,7 +604,7 @@ private void UpdateProcessing(float frameTime) : AtmosphereProcessingState.ActiveTiles; continue; case AtmosphereProcessingState.TileEqualize: - if (!ProcessTileEqualize(ent, visuals)) + if (!ProcessTileEqualize(ent)) { atmosphere.ProcessingPaused = true; return; @@ -499,7 +614,7 @@ private void UpdateProcessing(float frameTime) atmosphere.State = AtmosphereProcessingState.ActiveTiles; continue; case AtmosphereProcessingState.ActiveTiles: - if (!ProcessActiveTiles(atmosphere, visuals)) + if (!ProcessActiveTiles(ent, ent)) { atmosphere.ProcessingPaused = true; return; @@ -520,7 +635,7 @@ private void UpdateProcessing(float frameTime) atmosphere.State = AtmosphereProcessingState.HighPressureDelta; continue; case AtmosphereProcessingState.HighPressureDelta: - if (!ProcessHighPressureDelta(ent)) + if (!ProcessHighPressureDelta((ent, ent))) { atmosphere.ProcessingPaused = true; return; diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs index 33fa16a6c68..5c73cf11246 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs @@ -1,5 +1,6 @@ using Content.Server.Atmos.Components; using Content.Shared.Atmos; +using Robust.Shared.Map.Components; namespace Content.Server.Atmos.EntitySystems { @@ -12,7 +13,8 @@ private void Superconduct(GridAtmosphereComponent gridAtmosphere, TileAtmosphere for(var i = 0; i < Atmospherics.Directions; i++) { var direction = (AtmosDirection) (1 << i); - if (!directions.IsFlagSet(direction)) continue; + if (!directions.IsFlagSet(direction)) + continue; var adjacent = tile.AdjacentTiles[direction.ToIndex()]; @@ -92,7 +94,9 @@ public void NeighborConductWithSource(GridAtmosphereComponent gridAtmosphere, Ti { if (tile.Air == null) { - if (other.Tile != null) + // TODO ATMOS: why does this need to check if a tile exists if it doesn't use the tile? + if (TryComp(other.GridIndex, out var grid) + && _mapSystem.TryGetTileRef(other.GridIndex, grid, other.GridIndices, out var _)) { TemperatureShareOpenToSolid(other, tile); } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Utils.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Utils.cs index 699c2a70aef..9b0d0d9670d 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Utils.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Utils.cs @@ -41,20 +41,6 @@ public void InvalidateVisuals(EntityUid gridUid, Vector2i tile, GasTileOverlayCo _gasTileOverlaySystem.Invalidate(gridUid, tile, comp); } - public bool NeedsVacuumFixing(MapGridComponent mapGrid, Vector2i indices) - { - var value = false; - - var enumerator = GetObstructingComponentsEnumerator(mapGrid, indices); - - while (enumerator.MoveNext(out var airtight)) - { - value |= airtight.FixVacuum; - } - - return value; - } - /// /// Gets the volume in liters for a number of tiles, on a specific grid. /// @@ -66,34 +52,44 @@ private float GetVolumeForTiles(MapGridComponent mapGrid, int tiles = 1) return Atmospherics.CellVolume * mapGrid.TileSize * tiles; } - /// - /// Gets all obstructing instances in a specific tile. - /// - /// The grid where to get the tile. - /// The indices of the tile. - /// The enumerator for the airtight components. - public AtmosObstructionEnumerator GetObstructingComponentsEnumerator(MapGridComponent mapGrid, Vector2i tile) + public readonly record struct AirtightData(AtmosDirection BlockedDirections, bool NoAirWhenBlocked, + bool FixVacuum); + + private void UpdateAirtightData(EntityUid uid, GridAtmosphereComponent atmos, MapGridComponent grid, TileAtmosphere tile) { - var ancEnumerator = mapGrid.GetAnchoredEntitiesEnumerator(tile); - var airQuery = GetEntityQuery(); + var oldBlocked = tile.AirtightData.BlockedDirections; + + tile.AirtightData = tile.NoGridTile + ? default + : GetAirtightData(uid, grid, tile.GridIndices); - var enumerator = new AtmosObstructionEnumerator(ancEnumerator, airQuery); - return enumerator; + if (tile.AirtightData.BlockedDirections != oldBlocked && tile.ExcitedGroup != null) + ExcitedGroupDispose(atmos, tile.ExcitedGroup); } - private AtmosDirection GetBlockedDirections(MapGridComponent mapGrid, Vector2i indices) + private AirtightData GetAirtightData(EntityUid uid, MapGridComponent grid, Vector2i tile) { - var value = AtmosDirection.Invalid; + var blockedDirs = AtmosDirection.Invalid; + var noAirWhenBlocked = false; + var fixVacuum = false; - var enumerator = GetObstructingComponentsEnumerator(mapGrid, indices); - - while (enumerator.MoveNext(out var airtight)) + foreach (var ent in _map.GetAnchoredEntities(uid, grid, tile)) { - if(airtight.AirBlocked) - value |= airtight.AirBlockedDirection; + if (!_airtightQuery.TryGetComponent(ent, out var airtight)) + continue; + + if(!airtight.AirBlocked) + continue; + + blockedDirs |= airtight.AirBlockedDirection; + noAirWhenBlocked |= airtight.NoAirWhenFullyAirBlocked; + fixVacuum |= airtight.FixVacuum; + + if (blockedDirs == AtmosDirection.All && noAirWhenBlocked && fixVacuum) + break; } - return value; + return new AirtightData(blockedDirs, noAirWhenBlocked, fixVacuum); } /// diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs index dd2a9675591..d2f40e77169 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs @@ -4,6 +4,7 @@ using Content.Server.Fluids.EntitySystems; using Content.Server.NodeContainer.EntitySystems; using Content.Shared.Atmos.EntitySystems; +using Content.Shared.Doors.Components; using Content.Shared.Maps; using JetBrains.Annotations; using Robust.Server.GameObjects; @@ -40,6 +41,9 @@ public sealed partial class AtmosphereSystem : SharedAtmosphereSystem private const float ExposedUpdateDelay = 1f; private float _exposedTimer = 0f; + private EntityQuery _atmosQuery; + private EntityQuery _airtightQuery; + private EntityQuery _firelockQuery; private HashSet _entSet = new(); public override void Initialize() @@ -55,6 +59,9 @@ public override void Initialize() InitializeGridAtmosphere(); InitializeMap(); + _atmosQuery = GetEntityQuery(); + _airtightQuery = GetEntityQuery(); + _firelockQuery = GetEntityQuery(); SubscribeLocalEvent(OnTileChanged); diff --git a/Content.Server/Atmos/EntitySystems/AutomaticAtmosSystem.cs b/Content.Server/Atmos/EntitySystems/AutomaticAtmosSystem.cs index 203c747e29e..70e3eef3c44 100644 --- a/Content.Server/Atmos/EntitySystems/AutomaticAtmosSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AutomaticAtmosSystem.cs @@ -27,8 +27,12 @@ private void OnTileChanged(ref TileChangedEvent ev) // Also, these calls are surprisingly slow. // TODO: Make tiledefmanager cache the IsSpace property, and turn this lookup-through-two-interfaces into // TODO: a simple array lookup, as tile IDs are likely contiguous, and there's at most 2^16 possibilities anyway. - if (!((ev.OldTile.IsSpace(_tileDefinitionManager) && !ev.NewTile.IsSpace(_tileDefinitionManager)) || - (!ev.OldTile.IsSpace(_tileDefinitionManager) && ev.NewTile.IsSpace(_tileDefinitionManager))) || + + var oldSpace = ev.OldTile.IsSpace(_tileDefinitionManager); + var newSpace = ev.NewTile.IsSpace(_tileDefinitionManager); + + if (!(oldSpace && !newSpace || + !oldSpace && newSpace) || _atmosphereSystem.HasAtmosphere(ev.Entity)) return; diff --git a/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs b/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs index 6a2c8f0a7e5..552ee142329 100644 --- a/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs +++ b/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs @@ -260,13 +260,13 @@ private GasEntry[] GenerateGasEntryArray(GasMixture? mixture) { var gas = _atmo.GetGas(i); - if (mixture?.Moles[i] <= UIMinMoles) + if (mixture?[i] <= UIMinMoles) continue; if (mixture != null) { var gasName = Loc.GetString(gas.Name); - gases.Add(new GasEntry(gasName, mixture.Moles[i], gas.Color)); + gases.Add(new GasEntry(gasName, mixture[i], gas.Color)); } } diff --git a/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs b/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs index 8ae9517379e..397f0167a9b 100644 --- a/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs +++ b/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs @@ -171,7 +171,7 @@ public GasOverlayData GetOverlayData(GasMixture? mixture) { var id = VisibleGasId[i]; var gas = _atmosphereSystem.GetGas(id); - var moles = mixture?.Moles[id] ?? 0f; + var moles = mixture?[id] ?? 0f; ref var opacity = ref data.Opacity[i]; if (moles < gas.GasMolesVisible) @@ -216,13 +216,13 @@ private bool UpdateChunkTile(GridAtmosphereComponent gridAtmosphere, GasOverlayC oldData = new GasOverlayData(tile.Hotspot.State, oldData.Opacity); } - if (tile.Air != null) + if (tile is {Air: not null, NoGridTile: false}) { for (var i = 0; i < VisibleGasId.Length; i++) { var id = VisibleGasId[i]; var gas = _atmosphereSystem.GetGas(id); - var moles = tile.Air.Moles[id]; + var moles = tile.Air[id]; ref var oldOpacity = ref oldData.Opacity[i]; if (moles < gas.GasMolesVisible) diff --git a/Content.Server/Atmos/GasMixture.cs b/Content.Server/Atmos/GasMixture.cs index 0a2ef235a71..77fd7018333 100644 --- a/Content.Server/Atmos/GasMixture.cs +++ b/Content.Server/Atmos/GasMixture.cs @@ -3,6 +3,7 @@ using System.Runtime.CompilerServices; using Content.Server.Atmos.Reactions; using Content.Shared.Atmos; +using Content.Shared.Atmos.EntitySystems; using Robust.Shared.Serialization; using Robust.Shared.Utility; @@ -17,11 +18,13 @@ public sealed partial class GasMixture : IEquatable, ISerializationH { public static GasMixture SpaceGas => new() {Volume = Atmospherics.CellVolume, Temperature = Atmospherics.TCMB, Immutable = true}; - // This must always have a length that is a multiple of 4 for SIMD acceleration. - [DataField("moles")] - [ViewVariables(VVAccess.ReadWrite)] + // No access, to ensure immutable mixtures are never accidentally mutated. + [Access(typeof(SharedAtmosphereSystem), typeof(SharedAtmosDebugOverlaySystem), Other = AccessPermissions.None)] + [DataField] public float[] Moles = new float[Atmospherics.AdjustedNumberOfGases]; + public float this[int gas] => Moles[gas]; + [DataField("temperature")] [ViewVariables(VVAccess.ReadWrite)] private float _temperature = Atmospherics.TCMB; @@ -80,6 +83,19 @@ public GasMixture(float volume = 0f) Volume = volume; } + public GasMixture(float[] moles, float temp, float volume = Atmospherics.CellVolume) + { + if (moles.Length != Atmospherics.AdjustedNumberOfGases) + throw new InvalidOperationException($"Invalid mole array length"); + + if (volume < 0) + volume = 0; + + _temperature = temp; + Moles = moles; + Volume = volume; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void MarkImmutable() { @@ -117,15 +133,16 @@ public void SetMoles(Gas gas, float quantity) [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AdjustMoles(int gasId, float quantity) { - if (!Immutable) - { - if (!float.IsFinite(quantity)) - throw new ArgumentException($"Invalid quantity \"{quantity}\" specified!", nameof(quantity)); + if (Immutable) + return; - // Clamping is needed because x - x can be negative with floating point numbers. If we don't - // clamp here, the caller always has to call GetMoles(), clamp, then SetMoles(). - Moles[gasId] = MathF.Max(Moles[gasId] + quantity, 0); - } + if (!float.IsFinite(quantity)) + throw new ArgumentException($"Invalid quantity \"{quantity}\" specified!", nameof(quantity)); + + // Clamping is needed because x - x can be negative with floating point numbers. If we don't + // clamp here, the caller always has to call GetMoles(), clamp, then SetMoles(). + ref var moles = ref Moles[gasId]; + moles = MathF.Max(moles + quantity, 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -163,7 +180,8 @@ public GasMixture RemoveRatio(float ratio) { var moles = Moles[i]; var otherMoles = removed.Moles[i]; - if (moles < Atmospherics.GasMinMoles || float.IsNaN(moles)) + + if ((moles < Atmospherics.GasMinMoles || float.IsNaN(moles)) && !Immutable) Moles[i] = 0; if (otherMoles < Atmospherics.GasMinMoles || float.IsNaN(otherMoles)) @@ -202,6 +220,9 @@ public void Multiply(float multiplier) void ISerializationHooks.AfterDeserialization() { + // ISerializationHooks is obsolete. + // TODO add fixed-length-array serializer + // The arrays MUST have a specific length. Array.Resize(ref Moles, Atmospherics.AdjustedNumberOfGases); } @@ -229,8 +250,12 @@ public override bool Equals(object? obj) public bool Equals(GasMixture? other) { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; + if (ReferenceEquals(this, other)) + return true; + + if (ReferenceEquals(null, other)) + return false; + return Moles.SequenceEqual(other.Moles) && _temperature.Equals(other._temperature) && ReactionResults.SequenceEqual(other.ReactionResults) @@ -258,11 +283,13 @@ public override int GetHashCode() public GasMixture Clone() { + if (Immutable) + return this; + var newMixture = new GasMixture() { Moles = (float[])Moles.Clone(), _temperature = _temperature, - Immutable = Immutable, Volume = Volume, }; return newMixture; diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs index 64d02d793bc..ad647fad1b8 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs @@ -136,7 +136,7 @@ private void OnCanisterChangeReleaseValve(EntityUid uid, GasCanisterComponent ca for (int i = 0; i < containedGasArray.Length; i++) { - containedGasDict.Add((Gas)i, canister.Air.Moles[i]); + containedGasDict.Add((Gas)i, canister.Air[i]); } _adminLogger.Add(LogType.CanisterValve, impact, $"{ToPrettyString(args.Session.AttachedEntity.GetValueOrDefault()):player} set the valve on {ToPrettyString(uid):canister} to {args.Valve:valveState} while it contained [{string.Join(", ", containedGasDict)}]"); diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCondenserSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCondenserSystem.cs index 491bf600627..852542ec6cd 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCondenserSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCondenserSystem.cs @@ -45,7 +45,7 @@ private void OnCondenserUpdated(Entity entity, ref AtmosD var removed = inlet.Air.Remove(molesToConvert); for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++) { - var moles = removed.Moles[i]; + var moles = removed[i]; if (moles <= 0) continue; diff --git a/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs b/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs index 7d385c530a9..71e4c2d0def 100644 --- a/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs +++ b/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs @@ -183,13 +183,7 @@ public void CopyTo(ISerializationManager serializationManager, Dictionary + /// Neighbouring tiles to which air can flow. This is a combination of this tile's unblocked direction, and the + /// unblocked directions on adjacent tiles. + /// [ViewVariables] public AtmosDirection AdjacentBits = AtmosDirection.Invalid; @@ -72,10 +77,7 @@ public sealed class TileAtmosphere : IGasMixtureHolder public EntityUid GridIndex { get; set; } [ViewVariables] - public TileRef? Tile => GridIndices.GetTileRef(GridIndex); - - [ViewVariables] - public Vector2i GridIndices { get; } + public Vector2i GridIndices; [ViewVariables] public ExcitedGroup? ExcitedGroup { get; set; } @@ -92,7 +94,7 @@ public sealed class TileAtmosphere : IGasMixtureHolder public float LastShare; [ViewVariables] - public float[]? MolesArchived; + public readonly float[] MolesArchived = new float[Atmospherics.AdjustedNumberOfGases]; GasMixture IGasMixtureHolder.Air { @@ -103,8 +105,31 @@ GasMixture IGasMixtureHolder.Air [ViewVariables] public float MaxFireTemperatureSustained { get; set; } + /// + /// If true, then this tile is directly exposed to the map's atmosphere, either because the grid has no tile at + /// this position, or because the tile type is not airtight. + /// + [ViewVariables] + public bool MapAtmosphere; + + /// + /// If true, this tile does not actually exist on the grid, it only exists to represent the map's atmosphere for + /// adjacent grid tiles. + /// [ViewVariables] - public AtmosDirection BlockedAirflow { get; set; } = AtmosDirection.Invalid; + public bool NoGridTile; + + /// + /// If true, this tile is queued for processing in + /// + [ViewVariables] + public bool TrimQueued; + + /// + /// Cached information about airtight entities on this tile. This gets updated anytime a tile gets invalidated + /// (i.e., gets added to ). + /// + public AtmosphereSystem.AirtightData AirtightData; public TileAtmosphere(EntityUid gridIndex, Vector2i gridIndices, GasMixture? mixture = null, bool immutable = false, bool space = false) { @@ -112,10 +137,24 @@ public TileAtmosphere(EntityUid gridIndex, Vector2i gridIndices, GasMixture? mix GridIndices = gridIndices; Air = mixture; Space = space; - MolesArchived = Air != null ? new float[Atmospherics.AdjustedNumberOfGases] : null; if(immutable) Air?.MarkImmutable(); } + + public TileAtmosphere(TileAtmosphere other) + { + GridIndex = other.GridIndex; + GridIndices = other.GridIndices; + Space = other.Space; + NoGridTile = other.NoGridTile; + MapAtmosphere = other.MapAtmosphere; + Air = other.Air?.Clone(); + Array.Copy(other.MolesArchived, MolesArchived, MolesArchived.Length); + } + + public TileAtmosphere() + { + } } } diff --git a/Content.Server/Body/Systems/LungSystem.cs b/Content.Server/Body/Systems/LungSystem.cs index b5bac507391..4b60f8814b5 100644 --- a/Content.Server/Body/Systems/LungSystem.cs +++ b/Content.Server/Body/Systems/LungSystem.cs @@ -77,7 +77,7 @@ public void GasToReagent(EntityUid uid, LungComponent lung) foreach (var gas in Enum.GetValues()) { var i = (int) gas; - var moles = lung.Air.Moles[i]; + var moles = lung.Air[i]; if (moles <= 0) continue; var reagent = _atmosphereSystem.GasReagents[i]; diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs index be6e8b78fef..6cdb088dbb0 100644 --- a/Content.Server/Chat/Systems/ChatSystem.cs +++ b/Content.Server/Chat/Systems/ChatSystem.cs @@ -7,7 +7,7 @@ using Content.Server.GameTicking; using Content.Server.Speech.Components; using Content.Server.Speech.EntitySystems; -using Content.Server.Nyanotrasen.Chat; +using Content.Server.Psionics.Telepathy; using Content.Server.Speech.Components; using Content.Server.Speech.EntitySystems; using Content.Server.Station.Components; diff --git a/Content.Server/Chemistry/EntitySystems/VaporSystem.cs b/Content.Server/Chemistry/EntitySystems/VaporSystem.cs index d945c1f818b..7d3f70bc0d8 100644 --- a/Content.Server/Chemistry/EntitySystems/VaporSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/VaporSystem.cs @@ -64,8 +64,8 @@ public void Start(Entity vapor, TransformComponent vaporXform, V // Set Move if (EntityManager.TryGetComponent(vapor, out PhysicsComponent? physics)) { - _physics.SetLinearDamping(physics, 0f); - _physics.SetAngularDamping(physics, 0f); + _physics.SetLinearDamping(vapor, physics, 0f); + _physics.SetAngularDamping(vapor, physics, 0f); _throwing.TryThrow(vapor, dir, speed, user: user); diff --git a/Content.Server/Chemistry/ReagentEffects/ModifyLungGas.cs b/Content.Server/Chemistry/ReagentEffects/ModifyLungGas.cs index e12cab80a91..e7466fbc85d 100644 --- a/Content.Server/Chemistry/ReagentEffects/ModifyLungGas.cs +++ b/Content.Server/Chemistry/ReagentEffects/ModifyLungGas.cs @@ -16,12 +16,15 @@ public sealed partial class ModifyLungGas : ReagentEffect public override void Effect(ReagentEffectArgs args) { - if (args.EntityManager.TryGetComponent(args.OrganEntity, out var lung)) + if (!args.EntityManager.TryGetComponent(args.OrganEntity, out var lung)) + return; + + foreach (var (gas, ratio) in _ratios) { - foreach (var (gas, ratio) in _ratios) - { - lung.Air.Moles[(int) gas] += (ratio * args.Quantity.Float()) / Atmospherics.BreathMolesToReagentMultiplier; - } + var quantity = ratio * args.Quantity.Float() / Atmospherics.BreathMolesToReagentMultiplier; + if (quantity < 0) + quantity = Math.Max(quantity, -lung.Air[(int)gas]); + lung.Air.AdjustMoles(gas, quantity); } } } diff --git a/Content.Server/Construction/Conditions/ComponentInTile.cs b/Content.Server/Construction/Conditions/ComponentInTile.cs index 8ab4046a721..36705e4c0ee 100644 --- a/Content.Server/Construction/Conditions/ComponentInTile.cs +++ b/Content.Server/Construction/Conditions/ComponentInTile.cs @@ -3,6 +3,7 @@ using Content.Shared.Maps; using JetBrains.Annotations; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Utility; namespace Content.Server.Construction.Conditions @@ -48,7 +49,15 @@ public bool Condition(EntityUid uid, IEntityManager entityManager) var indices = transform.Coordinates.ToVector2i(entityManager, IoCManager.Resolve()); var lookup = entityManager.EntitySysManager.GetEntitySystem(); - var entities = indices.GetEntitiesInTile(transform.GridUid.Value, LookupFlags.Approximate | LookupFlags.Static, lookup); + + + if (!entityManager.TryGetComponent(transform.GridUid.Value, out var grid)) + return !HasEntity; + + if (!entityManager.System().TryGetTileRef(transform.GridUid.Value, grid, indices, out var tile)) + return !HasEntity; + + var entities = tile.GetEntitiesInTile(LookupFlags.Approximate | LookupFlags.Static, lookup); foreach (var ent in entities) { diff --git a/Content.Server/DeltaV/StationEvents/Events/GlimmerMobSpawnRule.cs b/Content.Server/DeltaV/StationEvents/Events/GlimmerMobSpawnRule.cs index ec9ec770313..22d96a54146 100644 --- a/Content.Server/DeltaV/StationEvents/Events/GlimmerMobSpawnRule.cs +++ b/Content.Server/DeltaV/StationEvents/Events/GlimmerMobSpawnRule.cs @@ -5,7 +5,7 @@ using Content.Server.Psionics.Glimmer; using Content.Server.StationEvents.Components; using Content.Shared.Psionics.Glimmer; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; namespace Content.Server.StationEvents.Events; diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs index 31451c425f5..4a9477e7443 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs @@ -475,7 +475,7 @@ public void DamageFloorTile(TileRef tileRef, if (_tileDefinitionManager[tileRef.Tile.TypeId] is not ContentTileDefinition tileDef) return; - if (tileDef.IsSpace) + if (tileDef.MapAtmosphere) canCreateVacuum = true; // is already a vacuum. int tileBreakages = 0; @@ -491,7 +491,7 @@ public void DamageFloorTile(TileRef tileRef, if (_tileDefinitionManager[tileDef.BaseTurf] is not ContentTileDefinition newDef) break; - if (newDef.IsSpace && !canCreateVacuum) + if (newDef.MapAtmosphere && !canCreateVacuum) break; tileDef = newDef; diff --git a/Content.Server/ImmovableRod/ImmovableRodSystem.cs b/Content.Server/ImmovableRod/ImmovableRodSystem.cs index 0fa8f7d292f..31aa39cf03a 100644 --- a/Content.Server/ImmovableRod/ImmovableRodSystem.cs +++ b/Content.Server/ImmovableRod/ImmovableRodSystem.cs @@ -53,9 +53,9 @@ private void OnMapInit(EntityUid uid, ImmovableRodComponent component, MapInitEv { if (EntityManager.TryGetComponent(uid, out PhysicsComponent? phys)) { - _physics.SetLinearDamping(phys, 0f); - _physics.SetFriction(phys, 0f); - _physics.SetBodyStatus(phys, BodyStatus.InAir); + _physics.SetLinearDamping(uid, phys, 0f); + _physics.SetFriction(uid, phys, 0f); + _physics.SetBodyStatus(uid, phys, BodyStatus.InAir); if (!component.RandomizeVelocity) return; diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs deleted file mode 100644 index b775117b716..00000000000 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MetapsionicPowerSystem.cs +++ /dev/null @@ -1,74 +0,0 @@ -using Content.Shared.Actions; -using Content.Shared.Abilities.Psionics; -using Content.Shared.StatusEffect; -using Content.Shared.Popups; -using Robust.Shared.Prototypes; -using Robust.Shared.Timing; -using Content.Shared.Mind; -using Content.Shared.Actions.Events; - -namespace Content.Server.Abilities.Psionics -{ - public sealed class MetapsionicPowerSystem : EntitySystem - { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly StatusEffectsSystem _statusEffects = default!; - [Dependency] private readonly SharedActionsSystem _actions = default!; - [Dependency] private readonly EntityLookupSystem _lookup = default!; - [Dependency] private readonly SharedPopupSystem _popups = default!; - [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly SharedMindSystem _mindSystem = default!; - - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnShutdown); - SubscribeLocalEvent(OnPowerUsed); - } - - private void OnInit(EntityUid uid, MetapsionicPowerComponent component, ComponentInit args) - { - _actions.AddAction(uid, ref component.MetapsionicActionEntity, component.MetapsionicActionId ); - _actions.TryGetActionData( component.MetapsionicActionEntity, out var actionData ); - if (actionData is { UseDelay: not null }) - _actions.StartUseDelay(component.MetapsionicActionEntity); - if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - { - psionic.PsionicAbility = component.MetapsionicActionEntity; - psionic.ActivePowers.Add(component); - } - - } - - private void OnShutdown(EntityUid uid, MetapsionicPowerComponent component, ComponentShutdown args) - { - _actions.RemoveAction(uid, component.MetapsionicActionEntity); - - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Remove(component); - } - } - - private void OnPowerUsed(EntityUid uid, MetapsionicPowerComponent component, MetapsionicPowerActionEvent args) - { - foreach (var entity in _lookup.GetEntitiesInRange(uid, component.Range)) - { - if (HasComp(entity) && entity != uid && !HasComp(entity) && - !(HasComp(entity) && Transform(entity).ParentUid == uid)) - { - _popups.PopupEntity(Loc.GetString("metapsionic-pulse-success"), uid, uid, PopupType.LargeCaution); - args.Handled = true; - return; - } - } - _popups.PopupEntity(Loc.GetString("metapsionic-pulse-failure"), uid, uid, PopupType.Large); - _psionics.LogPowerUsed(uid, "metapsionic pulse", 2, 4); - - args.Handled = true; - } - } -} diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs deleted file mode 100644 index 2eca3173b6d..00000000000 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegenerationPowerSystem.cs +++ /dev/null @@ -1,128 +0,0 @@ -using Robust.Shared.Audio; -using Robust.Server.GameObjects; -using Robust.Shared.Player; -using Robust.Shared.Prototypes; -using Content.Server.Body.Components; -using Content.Server.Body.Systems; -using Content.Server.Chemistry.Containers.EntitySystems; -using Content.Server.Chemistry.EntitySystems; -using Content.Server.DoAfter; -using Content.Shared.Abilities.Psionics; -using Content.Shared.Actions; -using Content.Shared.Chemistry.Components; -using Content.Shared.DoAfter; -using Content.Shared.FixedPoint; -using Content.Shared.Popups; -using Content.Shared.Psionics.Events; -using Content.Shared.Tag; -using Content.Shared.Examine; -using static Content.Shared.Examine.ExamineSystemShared; -using Robust.Shared.Timing; -using Content.Server.Mind; -using Content.Shared.Actions.Events; -using Content.Shared.Chemistry.EntitySystems; -using Robust.Server.Audio; - -namespace Content.Server.Abilities.Psionics -{ - public sealed class PsionicRegenerationPowerSystem : EntitySystem - { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly SharedActionsSystem _actions = default!; - [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!; - [Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!; - [Dependency] private readonly AudioSystem _audioSystem = default!; - [Dependency] private readonly TagSystem _tagSystem = default!; - [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; - [Dependency] private readonly SharedPopupSystem _popupSystem = default!; - [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly MindSystem _mindSystem = default!; - - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnShutdown); - SubscribeLocalEvent(OnPowerUsed); - - SubscribeLocalEvent(OnDispelled); - SubscribeLocalEvent(OnDoAfter); - } - - private void OnInit(EntityUid uid, PsionicRegenerationPowerComponent component, ComponentInit args) - { - _actions.AddAction(uid, ref component.PsionicRegenerationActionEntity, component.PsionicRegenerationActionId ); - _actions.TryGetActionData( component.PsionicRegenerationActionEntity, out var actionData ); - if (actionData is { UseDelay: not null }) - _actions.StartUseDelay(component.PsionicRegenerationActionEntity); - if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - { - psionic.PsionicAbility = component.PsionicRegenerationActionEntity; - psionic.ActivePowers.Add(component); - } - } - - private void OnPowerUsed(EntityUid uid, PsionicRegenerationPowerComponent component, PsionicRegenerationPowerActionEvent args) - { - var ev = new PsionicRegenerationDoAfterEvent(_gameTiming.CurTime); - var doAfterArgs = new DoAfterArgs(EntityManager, uid, component.UseDelay, ev, uid); - - _doAfterSystem.TryStartDoAfter(doAfterArgs, out var doAfterId); - - component.DoAfter = doAfterId; - - _popupSystem.PopupEntity(Loc.GetString("psionic-regeneration-begin", ("entity", uid)), - uid, - // TODO: Use LoS-based Filter when one is available. - Filter.Pvs(uid).RemoveWhereAttachedEntity(entity => !ExamineSystemShared.InRangeUnOccluded(uid, entity, ExamineRange, null)), - true, - PopupType.Medium); - - _audioSystem.PlayPvs(component.SoundUse, component.Owner, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); - _psionics.LogPowerUsed(uid, "psionic regeneration"); - args.Handled = true; - } - - private void OnShutdown(EntityUid uid, PsionicRegenerationPowerComponent component, ComponentShutdown args) - { - _actions.RemoveAction(uid, component.PsionicRegenerationActionEntity); - - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Remove(component); - } - } - - private void OnDispelled(EntityUid uid, PsionicRegenerationPowerComponent component, DispelledEvent args) - { - if (component.DoAfter == null) - return; - - _doAfterSystem.Cancel(component.DoAfter); - component.DoAfter = null; - - args.Handled = true; - } - - private void OnDoAfter(EntityUid uid, PsionicRegenerationPowerComponent component, PsionicRegenerationDoAfterEvent args) - { - component.DoAfter = null; - - if (!TryComp(uid, out var stream)) - return; - - // DoAfter has no way to run a callback during the process to give - // small doses of the reagent, so we wait until either the action - // is cancelled (by being dispelled) or complete to give the - // appropriate dose. A timestamp delta is used to accomplish this. - var percentageComplete = Math.Min(1f, (_gameTiming.CurTime - args.StartedAt).TotalSeconds / component.UseDelay); - - var solution = new Solution(); - solution.AddReagent("PsionicRegenerationEssence", FixedPoint2.New(component.EssenceAmount * percentageComplete)); - _bloodstreamSystem.TryAddToChemicals(uid, solution, stream); - } - } -} - diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs deleted file mode 100644 index 407b72c6b58..00000000000 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs +++ /dev/null @@ -1,66 +0,0 @@ -using Content.Shared.Actions; -using Content.Shared.Abilities.Psionics; -using Content.Server.Atmos.Components; -using Content.Server.Atmos.EntitySystems; -using Content.Server.Popups; -using Robust.Shared.Prototypes; -using Robust.Shared.Timing; -using Content.Server.Mind; -using Content.Shared.Actions.Events; - -namespace Content.Server.Abilities.Psionics -{ - public sealed class PyrokinesisPowerSystem : EntitySystem - { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly SharedActionsSystem _actions = default!; - [Dependency] private readonly FlammableSystem _flammableSystem = default!; - [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; - [Dependency] private readonly PopupSystem _popupSystem = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly MindSystem _mindSystem = default!; - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnShutdown); - SubscribeLocalEvent(OnPowerUsed); - } - - private void OnInit(EntityUid uid, PyrokinesisPowerComponent component, ComponentInit args) - { - _actions.AddAction(uid, ref component.PyrokinesisActionEntity, component.PyrokinesisActionId ); - _actions.TryGetActionData( component.PyrokinesisActionEntity, out var actionData ); - if (actionData is { UseDelay: not null }) - _actions.StartUseDelay(component.PyrokinesisActionEntity); - if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - { - psionic.PsionicAbility = component.PyrokinesisActionEntity; - psionic.ActivePowers.Add(component); - } - } - - private void OnShutdown(EntityUid uid, PyrokinesisPowerComponent component, ComponentShutdown args) - { - _actions.RemoveAction(uid, component.PyrokinesisActionEntity); - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Remove(component); - } - } - - private void OnPowerUsed(PyrokinesisPowerActionEvent args) - { - if (!TryComp(args.Target, out var flammableComponent)) - return; - - flammableComponent.FireStacks += 5; - _flammableSystem.Ignite(args.Target, args.Target); - _popupSystem.PopupEntity(Loc.GetString("pyrokinesis-power-used", ("target", args.Target)), args.Target, Shared.Popups.PopupType.LargeCaution); - - _psionics.LogPowerUsed(args.Performer, "pyrokinesis"); - args.Handled = true; - } - } -} diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs deleted file mode 100644 index f7ae04b61ea..00000000000 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/TelegnosisPowerSystem.cs +++ /dev/null @@ -1,67 +0,0 @@ -using Content.Shared.Actions; -using Content.Shared.StatusEffect; -using Content.Shared.Abilities.Psionics; -using Content.Shared.Mind.Components; -using Robust.Shared.Prototypes; -using Robust.Shared.Timing; -using Content.Server.Mind; -using Content.Shared.Actions.Events; - -namespace Content.Server.Abilities.Psionics -{ - public sealed class TelegnosisPowerSystem : EntitySystem - { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly StatusEffectsSystem _statusEffects = default!; - [Dependency] private readonly SharedActionsSystem _actions = default!; - [Dependency] private readonly MindSwapPowerSystem _mindSwap = default!; - [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly MindSystem _mindSystem = default!; - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnShutdown); - SubscribeLocalEvent(OnPowerUsed); - SubscribeLocalEvent(OnMindRemoved); - } - - private void OnInit(EntityUid uid, TelegnosisPowerComponent component, ComponentInit args) - { - _actions.AddAction(uid, ref component.TelegnosisActionEntity, component.TelegnosisActionId ); - _actions.TryGetActionData( component.TelegnosisActionEntity, out var actionData ); - if (actionData is { UseDelay: not null }) - _actions.StartUseDelay(component.TelegnosisActionEntity); - if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - { - psionic.PsionicAbility = component.TelegnosisActionEntity; - psionic.ActivePowers.Add(component); - } - } - - private void OnShutdown(EntityUid uid, TelegnosisPowerComponent component, ComponentShutdown args) - { - _actions.RemoveAction(uid, component.TelegnosisActionEntity); - if (TryComp(uid, out var psionic)) - { - psionic.ActivePowers.Remove(component); - } - } - - private void OnPowerUsed(EntityUid uid, TelegnosisPowerComponent component, TelegnosisPowerActionEvent args) - { - var projection = Spawn(component.Prototype, Transform(uid).Coordinates); - Transform(projection).AttachToGridOrMap(); - _mindSwap.Swap(uid, projection); - - _psionics.LogPowerUsed(uid, "telegnosis"); - args.Handled = true; - } - private void OnMindRemoved(EntityUid uid, TelegnosticProjectionComponent component, MindRemovedMessage args) - { - QueueDel(uid); - } - } -} diff --git a/Content.Server/Nyanotrasen/Chemistry/Effects/ChemRemovePsionic.cs b/Content.Server/Nyanotrasen/Chemistry/Effects/ChemRemovePsionic.cs index a23a5b3d77d..0ce3f9d7c64 100644 --- a/Content.Server/Nyanotrasen/Chemistry/Effects/ChemRemovePsionic.cs +++ b/Content.Server/Nyanotrasen/Chemistry/Effects/ChemRemovePsionic.cs @@ -1,5 +1,5 @@ using Content.Shared.Chemistry.Reagent; -using Content.Server.Abilities.Psionics; +using Content.Server.Psionics.Abilities; using JetBrains.Annotations; using Robust.Shared.Prototypes; diff --git a/Content.Server/Nyanotrasen/Objectives/Components/BecomePsionicConditionComponent.cs b/Content.Server/Nyanotrasen/Objectives/Components/BecomePsionicConditionComponent.cs deleted file mode 100644 index 3b677bab2d4..00000000000 --- a/Content.Server/Nyanotrasen/Objectives/Components/BecomePsionicConditionComponent.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Content.Server.Objectives.Systems; - -namespace Content.Server.Objectives.Components; - -/// -/// Requires that the player dies to be complete. -/// -[RegisterComponent, Access(typeof(BecomePsionicConditionSystem))] -public sealed partial class BecomePsionicConditionComponent : Component -{ -} \ No newline at end of file diff --git a/Content.Server/Nyanotrasen/Objectives/Systems/BecomePsionicConditionSystem.cs b/Content.Server/Nyanotrasen/Objectives/Systems/BecomePsionicConditionSystem.cs deleted file mode 100644 index d090c320a41..00000000000 --- a/Content.Server/Nyanotrasen/Objectives/Systems/BecomePsionicConditionSystem.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Content.Shared.Abilities.Psionics; -using Content.Server.Objectives.Components; -using Content.Shared.Mind; -using Content.Shared.Objectives.Components; - -namespace Content.Server.Objectives.Systems -{ - public sealed class BecomePsionicConditionSystem : EntitySystem - { - private EntityQuery _metaQuery; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnGetProgress); - } - - private void OnGetProgress(EntityUid uid, BecomePsionicConditionComponent comp, ref ObjectiveGetProgressEvent args) - { - args.Progress = GetProgress(args.Mind); - } - - private float GetProgress(MindComponent mind) - { - var entMan = IoCManager.Resolve(); - if (HasComp(mind.CurrentEntity)) - return 1; - return 0; - } - } -} diff --git a/Content.Server/Nyanotrasen/Psionics/PotentialPsionicComponent.cs b/Content.Server/Nyanotrasen/Psionics/PotentialPsionicComponent.cs deleted file mode 100644 index 9499497cd1d..00000000000 --- a/Content.Server/Nyanotrasen/Psionics/PotentialPsionicComponent.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Content.Server.Psionics -{ - [RegisterComponent] - public sealed partial class PotentialPsionicComponent : Component - { - [DataField("chance")] - public float Chance = 0.04f; - - /// - /// YORO (you only reroll once) - /// - public bool Rerolled = false; - } -} diff --git a/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs b/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs index 148598fe2c3..24459d29e22 100644 --- a/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs +++ b/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs @@ -5,7 +5,7 @@ using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Fluids.EntitySystems; using Content.Server.Psionics; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Chat; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.EntitySystems; diff --git a/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs b/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs index bc3c22cc350..b8cdcb56d47 100644 --- a/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs +++ b/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs @@ -1,4 +1,4 @@ -using Content.Server.Abilities.Psionics; +using Content.Server.Psionics.Abilities; using Content.Server.Chat.Systems; using Content.Server.Radio.Components; using Content.Server.Radio.EntitySystems; diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/GlimmerWispSpawnRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/GlimmerWispSpawnRule.cs index 66eea988aeb..89b5a176f24 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/GlimmerWispSpawnRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/GlimmerWispSpawnRule.cs @@ -5,7 +5,7 @@ using Content.Server.Psionics.Glimmer; using Content.Server.StationEvents.Components; using Content.Shared.Psionics.Glimmer; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; namespace Content.Server.StationEvents.Events; diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/MassMindSwapRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/MassMindSwapRule.cs index 63944563269..89f3bc97501 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/MassMindSwapRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/MassMindSwapRule.cs @@ -1,10 +1,9 @@ -using Robust.Server.GameObjects; using Robust.Shared.Random; -using Content.Server.Abilities.Psionics; +using Content.Server.Psionics.Abilities; using Content.Server.GameTicking.Rules.Components; using Content.Server.Psionics; using Content.Server.StationEvents.Components; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Robust.Shared.Player; diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericFryRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericFryRule.cs index c04543d2195..6a2c1c3ba7d 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericFryRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericFryRule.cs @@ -10,7 +10,7 @@ using Content.Server.Power.EntitySystems; using Content.Server.Psionics.Glimmer; using Content.Server.StationEvents.Components; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Damage; using Content.Shared.Inventory; using Content.Shared.Mobs.Components; diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericStormRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericStormRule.cs index 175318e15bd..8812ed1fe37 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericStormRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericStormRule.cs @@ -1,9 +1,9 @@ using Robust.Shared.Random; -using Content.Server.Abilities.Psionics; +using Content.Server.Psionics.Abilities; using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; using Content.Server.Psionics; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Mobs.Systems; using Content.Shared.Psionics.Glimmer; using Content.Shared.Zombies; diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericZapRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericZapRule.cs index 82c3d72b139..3672d317d9e 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericZapRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericZapRule.cs @@ -3,7 +3,7 @@ using Content.Server.Psionics; using Content.Server.StationEvents.Components; using Content.Server.Stunnable; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Content.Shared.StatusEffect; diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/PsionicCatGotYourTongueRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/PsionicCatGotYourTongueRule.cs index 63e0a435cb0..753b2e25729 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/PsionicCatGotYourTongueRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/PsionicCatGotYourTongueRule.cs @@ -4,7 +4,7 @@ using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; using Content.Shared.Mobs.Components; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.StatusEffect; using Content.Shared.Mobs.Systems; using Robust.Shared.Audio.Systems; diff --git a/Content.Server/Parallax/BiomeSystem.cs b/Content.Server/Parallax/BiomeSystem.cs index c4c2300870d..83cf9b9cb2d 100644 --- a/Content.Server/Parallax/BiomeSystem.cs +++ b/Content.Server/Parallax/BiomeSystem.cs @@ -1001,20 +1001,13 @@ public void EnsurePlanet(EntityUid mapUid, BiomeTemplatePrototype biomeTemplate, light.AmbientLightColor = Color.FromHex("#D8B059"); Dirty(mapUid, light, metadata); - // Atmos - var atmos = EnsureComp(mapUid); - var moles = new float[Atmospherics.AdjustedNumberOfGases]; moles[(int) Gas.Oxygen] = 21.824779f; moles[(int) Gas.Nitrogen] = 82.10312f; - var mixture = new GasMixture(2500) - { - Temperature = 293.15f, - Moles = moles, - }; + var mixture = new GasMixture(moles, Atmospherics.T20C); - _atmos.SetMapAtmosphere(mapUid, false, mixture, atmos); + _atmos.SetMapAtmosphere(mapUid, false, mixture); } /// diff --git a/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.Emitter.cs b/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.Emitter.cs index 46b25163cc0..06f1b6b154c 100644 --- a/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.Emitter.cs +++ b/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.Emitter.cs @@ -28,7 +28,7 @@ private void FireEmitter(EntityUid uid, ParticleAcceleratorPowerState strength, if (TryComp(emitted, out var particlePhys)) { var angle = _transformSystem.GetWorldRotation(uid, xformQuery); - _physicsSystem.SetBodyStatus(particlePhys, BodyStatus.InAir); + _physicsSystem.SetBodyStatus(emitted, particlePhys, BodyStatus.InAir); var velocity = angle.ToWorldVec() * 20f; if (TryComp(uid, out var phys)) diff --git a/Content.Server/Physics/Controllers/ChasingWalkSystem.cs b/Content.Server/Physics/Controllers/ChasingWalkSystem.cs index 215e7e3124e..618dd4156fc 100644 --- a/Content.Server/Physics/Controllers/ChasingWalkSystem.cs +++ b/Content.Server/Physics/Controllers/ChasingWalkSystem.cs @@ -97,6 +97,6 @@ private void ForceImpulse(EntityUid uid, ChasingWalkComponent component) var speed = delta.Length() > 0 ? delta.Normalized() * component.Speed : Vector2.Zero; _physics.SetLinearVelocity(uid, speed); - _physics.SetBodyStatus(physics, BodyStatus.InAir); //If this is not done, from the explosion up close, the tesla will "Fall" to the ground, and almost stop moving. + _physics.SetBodyStatus(uid, physics, BodyStatus.InAir); //If this is not done, from the explosion up close, the tesla will "Fall" to the ground, and almost stop moving. } } diff --git a/Content.Server/Power/Generator/GasPowerReceiverSystem.cs b/Content.Server/Power/Generator/GasPowerReceiverSystem.cs index c61599edfc9..76cf90c3693 100644 --- a/Content.Server/Power/Generator/GasPowerReceiverSystem.cs +++ b/Content.Server/Power/Generator/GasPowerReceiverSystem.cs @@ -37,7 +37,7 @@ private void OnDeviceUpdated(EntityUid uid, GasPowerReceiverComponent component, if (pipe.Air.Temperature <= component.MaxTemperature) { // we have enough gas, so we consume it and are powered - if (pipe.Air.Moles[(int) component.TargetGas] > component.MolesConsumedSec * timeDelta) + if (pipe.Air[(int) component.TargetGas] > component.MolesConsumedSec * timeDelta) { pipe.Air.AdjustMoles(component.TargetGas, -component.MolesConsumedSec * timeDelta); SetPowered(uid, component, true); diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/DispelPowerSystem.cs b/Content.Server/Psionics/Abilities/DispelPowerSystem.cs similarity index 83% rename from Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/DispelPowerSystem.cs rename to Content.Server/Psionics/Abilities/DispelPowerSystem.cs index d338a5a5bcb..cb7ef8313cd 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/DispelPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/DispelPowerSystem.cs @@ -1,24 +1,20 @@ using Content.Shared.Actions; using Content.Shared.StatusEffect; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Damage; using Content.Shared.Revenant.Components; using Content.Server.Guardian; using Content.Server.Bible.Components; using Content.Server.Popups; -using Robust.Shared.Prototypes; using Robust.Shared.Player; using Robust.Shared.Random; -using Robust.Shared.Timing; -using Content.Shared.Mind; using Content.Shared.Actions.Events; using Robust.Shared.Audio.Systems; -namespace Content.Server.Abilities.Psionics +namespace Content.Server.Psionics.Abilities { public sealed class DispelPowerSystem : EntitySystem { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly StatusEffectsSystem _statusEffects = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly DamageableSystem _damageableSystem = default!; @@ -27,8 +23,6 @@ public sealed class DispelPowerSystem : EntitySystem [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly SharedMindSystem _mindSystem = default!; public override void Initialize() @@ -52,10 +46,13 @@ private void OnInit(EntityUid uid, DispelPowerComponent component, ComponentInit _actions.TryGetActionData( component.DispelActionEntity, out var actionData ); if (actionData is { UseDelay: not null }) _actions.StartUseDelay(component.DispelActionEntity); - if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) + if (TryComp(uid, out var psionic)) { - psionic.PsionicAbility = component.DispelActionEntity; psionic.ActivePowers.Add(component); + psionic.PsychicFeedback.Add(component.DispelFeedback); + //It's fully intended that Dispel doesn't increase Amplification, and instead heavily spikes Dampening + //Antimage archetype. + psionic.Dampening += 1f; } } @@ -66,12 +63,16 @@ private void OnShutdown(EntityUid uid, DispelPowerComponent component, Component if (TryComp(uid, out var psionic)) { psionic.ActivePowers.Remove(component); + psionic.PsychicFeedback.Remove(component.DispelFeedback); + psionic.Dampening -= 1f; } } private void OnPowerUsed(DispelPowerActionEvent args) { - if (HasComp(args.Target)) + if (HasComp(args.Target) || HasComp(args.Performer)) + return; + if (!TryComp(args.Performer, out var psionic) || !HasComp(args.Target)) return; var ev = new DispelledEvent(); @@ -80,7 +81,9 @@ private void OnPowerUsed(DispelPowerActionEvent args) if (ev.Handled) { args.Handled = true; - _psionics.LogPowerUsed(args.Performer, "dispel"); + _psionics.LogPowerUsed(args.Performer, "dispel", + (int) MathF.Round(-2 * psionic.Dampening + psionic.Amplification), + (int) MathF.Round(-4 * psionic.Dampening + psionic.Amplification)); } } @@ -96,7 +99,7 @@ private void OnDispelled(EntityUid uid, DispellableComponent component, Dispelle private void OnDmgDispelled(EntityUid uid, DamageOnDispelComponent component, DispelledEvent args) { var damage = component.Damage; - var modifier = (1 + component.Variance) - (_random.NextFloat(0, component.Variance * 2)); + var modifier = 1 + component.Variance - _random.NextFloat(0, component.Variance * 2); damage *= modifier; DealDispelDamage(uid, damage); @@ -145,5 +148,3 @@ public void DealDispelDamage(EntityUid uid, DamageSpecifier? damage = null) } public sealed class DispelledEvent : HandledEntityEventArgs {} } - - diff --git a/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs b/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs new file mode 100644 index 00000000000..7b3a417c53f --- /dev/null +++ b/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs @@ -0,0 +1,188 @@ +using Content.Shared.Actions; +using Content.Shared.Actions.Events; +using Content.Shared.Psionics.Abilities; +using Content.Shared.DoAfter; +using Content.Shared.Examine; +using static Content.Shared.Examine.ExamineSystemShared; +using Content.Shared.Popups; +using Robust.Server.Audio; +using Robust.Shared.Audio; +using Robust.Shared.Timing; +using Robust.Shared.Player; +using Content.Server.DoAfter; +using Content.Shared.Psionics.Events; +using Content.Server.Psionics; + +namespace Content.Server.Psionics.Abilities +{ + public sealed class MetapsionicPowerSystem : EntitySystem + { + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly EntityLookupSystem _lookup = default!; + [Dependency] private readonly SharedPopupSystem _popups = default!; + [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly AudioSystem _audioSystem = default!; + + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnWidePowerUsed); + SubscribeLocalEvent(OnFocusedPowerUsed); + SubscribeLocalEvent(OnDoAfter); + } + + private void OnInit(EntityUid uid, MetapsionicPowerComponent component, ComponentInit args) + { + if (!TryComp(uid, out ActionsComponent? comp)) + return; + _actions.AddAction(uid, ref component.ActionWideMetapsionicEntity, component.ActionWideMetapsionic, component: comp); + _actions.AddAction(uid, ref component.ActionFocusedMetapsionicEntity, component.ActionFocusedMetapsionic, component: comp); + _actions.TryGetActionData(component.ActionWideMetapsionicEntity, out var actionData); + if (actionData is { UseDelay: not null }) + { + _actions.StartUseDelay(component.ActionWideMetapsionicEntity); + _actions.StartUseDelay(component.ActionFocusedMetapsionicEntity); + } + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Add(component); + psionic.PsychicFeedback.Add(component.MetapsionicFeedback); + psionic.Amplification += 0.1f; + psionic.Dampening += 0.5f; + } + + } + + private void UpdateActions(EntityUid uid, MetapsionicPowerComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + _actions.StartUseDelay(component.ActionWideMetapsionicEntity); + _actions.StartUseDelay(component.ActionFocusedMetapsionicEntity); + } + + private void OnShutdown(EntityUid uid, MetapsionicPowerComponent component, ComponentShutdown args) + { + _actions.RemoveAction(uid, component.ActionWideMetapsionicEntity); + _actions.RemoveAction(uid, component.ActionFocusedMetapsionicEntity); + + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Remove(component); + psionic.PsychicFeedback.Remove(component.MetapsionicFeedback); + psionic.Amplification -= 0.1f; + psionic.Dampening -= 0.5f; + } + } + + private void OnWidePowerUsed(EntityUid uid, MetapsionicPowerComponent component, WideMetapsionicPowerActionEvent args) + { + if (HasComp(uid)) + return; + + if (!TryComp(uid, out var psionic)) + return; + + foreach (var entity in _lookup.GetEntitiesInRange(uid, component.Range)) + { + if (HasComp(entity) && entity != uid && !HasComp(entity) && + !(HasComp(entity) && Transform(entity).ParentUid == uid)) + { + _popups.PopupEntity(Loc.GetString("metapsionic-pulse-success"), uid, uid, PopupType.LargeCaution); + args.Handled = true; + return; + } + } + _popups.PopupEntity(Loc.GetString("metapsionic-pulse-failure"), uid, uid, PopupType.Large); + _psionics.LogPowerUsed(uid, "metapsionic pulse", + (int) MathF.Round(2 * psionic.Amplification - psionic.Dampening), + (int) MathF.Round(4 * psionic.Amplification - psionic.Dampening)); + UpdateActions(uid, component); + args.Handled = true; + } + + private void OnFocusedPowerUsed(FocusedMetapsionicPowerActionEvent args) + { + if (!TryComp(args.Performer, out var psionic)) + return; + + if (HasComp(args.Target)) + return; + + if (!TryComp(args.Performer, out var component)) + return; + + var ev = new FocusedMetapsionicDoAfterEvent(_gameTiming.CurTime); + + _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.Performer, component.UseDelay - psionic.Amplification, ev, args.Performer, args.Target, args.Performer) + { + BlockDuplicate = true, + BreakOnUserMove = true, + BreakOnTargetMove = true, + BreakOnDamage = true, + }, out var doAfterId); + + component.DoAfter = doAfterId; + + _popups.PopupEntity(Loc.GetString("focused-metapsionic-pulse-begin", ("entity", args.Target)), + args.Performer, + // TODO: Use LoS-based Filter when one is available. + Filter.Pvs(args.Performer).RemoveWhereAttachedEntity(entity => !ExamineSystemShared.InRangeUnOccluded(args.Performer, entity, ExamineRange, null)), + true, + PopupType.Medium); + + _audioSystem.PlayPvs(component.SoundUse, args.Performer, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); + _psionics.LogPowerUsed(args.Performer, "focused metapsionic pulse", + (int) MathF.Round(3 * psionic.Amplification - psionic.Dampening), + (int) MathF.Round(6 * psionic.Amplification - psionic.Dampening)); + args.Handled = true; + + UpdateActions(args.Performer, component); + } + + private void OnDoAfter(EntityUid uid, MetapsionicPowerComponent component, FocusedMetapsionicDoAfterEvent args) + { + if (!TryComp(args.Target, out var psychic)) + return; + + component.DoAfter = null; + + if (args.Target == null) return; + + if (TryComp(args.Target, out var swapped)) + { + _popups.PopupEntity(Loc.GetString(swapped.MindSwappedFeedback, ("entity", args.Target)), uid, uid, PopupType.LargeCaution); + return; + } + + if (args.Target == uid) + { + _popups.PopupEntity(Loc.GetString("metapulse-self", ("entity", args.Target)), uid, uid, PopupType.LargeCaution); + return; + } + + if (!HasComp(args.Target)) + { + _popups.PopupEntity(Loc.GetString("no-powers", ("entity", args.Target)), uid, uid, PopupType.LargeCaution); + return; + } + + if (HasComp(args.Target) & !HasComp(args.Target)) + { + _popups.PopupEntity(Loc.GetString("psychic-potential", ("entity", args.Target)), uid, uid, PopupType.LargeCaution); + return; + } + + foreach (var psychicFeedback in psychic.PsychicFeedback) + { + _popups.PopupEntity(Loc.GetString(psychicFeedback, ("entity", args.Target)), uid, uid, PopupType.LargeCaution); + } + + } + } +} diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwapPowerSystem.cs b/Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs similarity index 78% rename from Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwapPowerSystem.cs rename to Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs index b23224cab48..1e50a586b4f 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwapPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs @@ -1,5 +1,6 @@ using Content.Shared.Actions; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; +using Content.Shared.Psionics; using Content.Shared.Speech; using Content.Shared.Stealth.Components; using Content.Shared.Mobs.Components; @@ -10,19 +11,15 @@ using Content.Server.Popups; using Content.Server.Psionics; using Content.Server.GameTicking; -using Robust.Shared.Prototypes; -using Robust.Shared.Timing; using Content.Shared.Mind; using Content.Shared.Actions.Events; -namespace Content.Server.Abilities.Psionics +namespace Content.Server.Psionics.Abilities { public sealed class MindSwapPowerSystem : EntitySystem { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly MobStateSystem _mobStateSystem = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly MindSystem _mindSystem = default!; @@ -38,20 +35,22 @@ public override void Initialize() SubscribeLocalEvent(OnDispelled); SubscribeLocalEvent(OnMobStateChanged); SubscribeLocalEvent(OnGhostAttempt); - // SubscribeLocalEvent(OnSwapInit); + SubscribeLocalEvent(OnSwapShutdown); + SubscribeLocalEvent(OnInsulated); } private void OnInit(EntityUid uid, MindSwapPowerComponent component, ComponentInit args) { - _actions.AddAction(uid, ref component.MindSwapActionEntity, component.MindSwapActionId ); - _actions.TryGetActionData( component.MindSwapActionEntity, out var actionData ); + _actions.AddAction(uid, ref component.MindSwapActionEntity, component.MindSwapActionId); + _actions.TryGetActionData( component.MindSwapActionEntity, out var actionData); if (actionData is { UseDelay: not null }) _actions.StartUseDelay(component.MindSwapActionEntity); - if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) + if (TryComp(uid, out var psionic)) { - psionic.PsionicAbility = component.MindSwapActionEntity; psionic.ActivePowers.Add(component); + psionic.PsychicFeedback.Add(component.MindSwapFeedback); + psionic.Amplification += 1f; } } @@ -61,20 +60,26 @@ private void OnShutdown(EntityUid uid, MindSwapPowerComponent component, Compone if (TryComp(uid, out var psionic)) { psionic.ActivePowers.Remove(component); + psionic.PsychicFeedback.Remove(component.MindSwapFeedback); + psionic.Amplification -= 1f; } } private void OnPowerUsed(MindSwapPowerActionEvent args) { + if (!(TryComp(args.Target, out var damageable) && damageable.DamageContainerID == "Biological")) return; if (HasComp(args.Target)) return; + if (!TryComp(args.Performer, out var psionic)) + return; + Swap(args.Performer, args.Target); - _psionics.LogPowerUsed(args.Performer, "mind swap"); + _psionics.LogPowerUsed(args.Performer, "mind swap", (int) MathF.Round(psionic.Amplification / psionic.Dampening * 8), (int) MathF.Round(psionic.Amplification / psionic.Dampening * 12)); args.Handled = true; } @@ -125,8 +130,8 @@ private void OnDispelled(EntityUid uid, MindSwappedComponent component, Dispelle private void OnMobStateChanged(EntityUid uid, MindSwappedComponent component, MobStateChangedEvent args) { - if (args.NewMobState == MobState.Dead) - RemComp(uid); + if (args.NewMobState == MobState.Dead || args.NewMobState == MobState.Critical) + Swap(uid, component.OriginalEntity, true); } private void OnGhostAttempt(GhostAttemptHandleEvent args) @@ -151,8 +156,21 @@ private void OnSwapInit(EntityUid uid, MindSwappedComponent component, Component _actions.TryGetActionData( component.MindSwapReturnActionEntity, out var actionData ); if (actionData is { UseDelay: not null }) _actions.StartUseDelay(component.MindSwapReturnActionEntity); - if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - psionic.PsionicAbility = component.MindSwapReturnActionEntity; + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Add(component); + psionic.PsychicFeedback.Add(component.MindSwappedFeedback); + } + } + + private void OnSwapShutdown(EntityUid uid, MindSwappedComponent component, ComponentShutdown args) + { + _actions.RemoveAction(uid, component.MindSwapReturnActionEntity); + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Remove(component); + psionic.PsychicFeedback.Remove(component.MindSwappedFeedback); + } } public void Swap(EntityUid performer, EntityUid target, bool end = false) @@ -165,11 +183,13 @@ public void Swap(EntityUid performer, EntityUid target, bool end = false) MindComponent? targetMind = null; // This is here to prevent missing MindContainerComponent Resolve errors. - if(!_mindSystem.TryGetMind(performer, out var performerMindId, out performerMind)){ + if (!_mindSystem.TryGetMind(performer, out var performerMindId, out performerMind)) + { performerMind = null; }; - if(!_mindSystem.TryGetMind(target, out var targetMindId, out targetMind)){ + if (!_mindSystem.TryGetMind(target, out var targetMindId, out targetMind)) + { targetMind = null; }; //This is a terrible way to 'unattach' minds. I wanted to use UnVisit but in TransferTo's code they say @@ -202,7 +222,7 @@ public void Swap(EntityUid performer, EntityUid target, bool end = false) perfComp.OriginalEntity = target; targetComp.OriginalEntity = performer; } - + //It shouldn't actually be possible anymore to get trapped under most circumstances, but for niche edge cases, I am leaving this here public void GetTrapped(EntityUid uid) { @@ -220,5 +240,9 @@ public void GetTrapped(EntityUid uid) _metaDataSystem.SetEntityDescription(uid, Loc.GetString("telegnostic-trapped-entity-desc")); } } + public void OnInsulated(EntityUid uid, MindSwappedComponent component, PsionicInsulationEvent args) + { + Swap(uid, component.OriginalEntity, true); + } } } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwappedComponent.cs b/Content.Server/Psionics/Abilities/MindSwappedComponent.cs similarity index 79% rename from Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwappedComponent.cs rename to Content.Server/Psionics/Abilities/MindSwappedComponent.cs index 72cd6a66ef9..82c0313bca6 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/MindSwappedComponent.cs +++ b/Content.Server/Psionics/Abilities/MindSwappedComponent.cs @@ -1,7 +1,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Server.Abilities.Psionics +namespace Content.Server.Psionics.Abilities { [RegisterComponent] public sealed partial class MindSwappedComponent : Component @@ -14,5 +14,8 @@ public sealed partial class MindSwappedComponent : Component [DataField("mindSwapReturnActionEntity")] public EntityUid? MindSwapReturnActionEntity; + + [DataField("mindSwappedFeedback")] + public string MindSwappedFeedback = "mindswapped-feedback"; } } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs b/Content.Server/Psionics/Abilities/NoosphericZapPowerSystem.cs similarity index 54% rename from Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs rename to Content.Server/Psionics/Abilities/NoosphericZapPowerSystem.cs index 0fd261ef12f..c935bc0123d 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZapPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/NoosphericZapPowerSystem.cs @@ -1,26 +1,21 @@ using Content.Shared.Actions; -using Content.Shared.Abilities.Psionics; -using Content.Server.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.StatusEffect; +using Content.Server.Electrocution; using Content.Server.Stunnable; using Content.Server.Beam; -using Robust.Shared.Prototypes; -using Robust.Shared.Timing; -using Content.Server.Mind; using Content.Shared.Actions.Events; -namespace Content.Server.Abilities.Psionics +namespace Content.Server.Psionics.Abilities { public sealed class NoosphericZapPowerSystem : EntitySystem { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly StunSystem _stunSystem = default!; [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly BeamSystem _beam = default!; - [Dependency] private readonly MindSystem _mindSystem = default!; + [Dependency] private readonly ElectrocutionSystem _electrocution = default!; public override void Initialize() @@ -37,10 +32,11 @@ private void OnInit(EntityUid uid, NoosphericZapPowerComponent component, Compon _actions.TryGetActionData( component.NoosphericZapActionEntity, out var actionData ); if (actionData is { UseDelay: not null }) _actions.StartUseDelay(component.NoosphericZapActionEntity); - if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) + if (TryComp(uid, out var psionic)) { - psionic.PsionicAbility = component.NoosphericZapActionEntity; psionic.ActivePowers.Add(component); + psionic.PsychicFeedback.Add(component.NoosphericZapFeedback); + psionic.Amplification += 1f; } } @@ -50,24 +46,34 @@ private void OnShutdown(EntityUid uid, NoosphericZapPowerComponent component, Co if (TryComp(uid, out var psionic)) { psionic.ActivePowers.Remove(component); + psionic.PsychicFeedback.Remove(component.NoosphericZapFeedback); + psionic.Amplification -= 1f; } } private void OnPowerUsed(NoosphericZapPowerActionEvent args) { - if (!HasComp(args.Target)) + if (!TryComp(args.Performer, out var psionic)) return; - if (HasComp(args.Target)) - return; + if (!HasComp(args.Target) && !HasComp(args.Performer)) + { + _beam.TryCreateBeam(args.Performer, args.Target, "LightningNoospheric"); + _stunSystem.TryParalyze(args.Target, TimeSpan.FromSeconds(1 * psionic.Amplification), false); - _beam.TryCreateBeam(args.Performer, args.Target, "LightningNoospheric"); + _electrocution.TryDoElectrocution(args.Target, null, + (int) MathF.Round(5f * psionic.Amplification), + new TimeSpan((long) MathF.Round(1f * psionic.Amplification)), + true, + ignoreInsulation: true); - _stunSystem.TryParalyze(args.Target, TimeSpan.FromSeconds(5), false); - _statusEffectsSystem.TryAddStatusEffect(args.Target, "Stutter", TimeSpan.FromSeconds(10), false, "StutteringAccent"); + _statusEffectsSystem.TryAddStatusEffect(args.Target, "Stutter", TimeSpan.FromSeconds(2 * psionic.Amplification), false, "StutteringAccent"); - _psionics.LogPowerUsed(args.Performer, "noospheric zap"); - args.Handled = true; + _psionics.LogPowerUsed(args.Performer, "noopsheric zap", + (int) MathF.Round(6 * psionic.Amplification - psionic.Dampening), + (int) MathF.Round(8 * psionic.Amplification - psionic.Dampening)); + args.Handled = true; + } } } } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/PsionicAbilitiesSystem.cs b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs similarity index 54% rename from Content.Server/Nyanotrasen/Abilities/Psionics/PsionicAbilitiesSystem.cs rename to Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs index ee16aaccfb6..915abd12224 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/PsionicAbilitiesSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs @@ -1,77 +1,41 @@ -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Actions; using Content.Shared.Psionics.Glimmer; using Content.Shared.Random; using Content.Shared.Random.Helpers; -using Content.Server.EUI; -using Content.Server.Psionics; -using Content.Server.Mind; -using Content.Shared.Mind; -using Content.Shared.Mind.Components; using Content.Shared.StatusEffect; using Robust.Shared.Random; using Robust.Shared.Prototypes; -using Robust.Server.GameObjects; -using Robust.Server.Player; using Robust.Shared.Player; +using Content.Shared.Examine; +using Content.Shared.Popups; +using static Content.Shared.Examine.ExamineSystemShared; -namespace Content.Server.Abilities.Psionics +namespace Content.Server.Psionics.Abilities { public sealed class PsionicAbilitiesSystem : EntitySystem { [Dependency] private readonly IComponentFactory _componentFactory = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; - [Dependency] private readonly IPlayerManager _playerManager = default!; - [Dependency] private readonly EuiManager _euiManager = default!; [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; [Dependency] private readonly GlimmerSystem _glimmerSystem = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly MindSystem _mindSystem = default!; + [Dependency] private readonly SharedPopupSystem _popups = default!; public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnPlayerAttached); } - private void OnPlayerAttached(EntityUid uid, PsionicAwaitingPlayerComponent component, PlayerAttachedEvent args) - { - if (TryComp(uid, out var bonus) && bonus.Warn == true) - _euiManager.OpenEui(new AcceptPsionicsEui(uid, this), args.Player); - else - AddRandomPsionicPower(uid); - RemCompDeferred(uid); - } - - public void AddPsionics(EntityUid uid, bool warn = true) - { - if (Deleted(uid)) - return; - - if (HasComp(uid)) - return; - - //Don't know if this will work. New mind state vs old. - if (!TryComp(uid, out var mindContainer) || - !_mindSystem.TryGetMind(uid, out _, out var mind )) - //|| - //!_mindSystem.TryGetMind(uid, out var mind, mindContainer)) - { - EnsureComp(uid); - return; - } - - if (!_mindSystem.TryGetSession(mind, out var client)) - return; - - if (warn && TryComp(uid, out var actor)) - _euiManager.OpenEui(new AcceptPsionicsEui(uid, this), client); - else - AddRandomPsionicPower(uid); - } - - public void AddPsionics(EntityUid uid, string powerComp) + /// + /// Adds a psychic power once a character rolls one. This used to be a system you have to select for. However the opt-in is no longer the text window, but is now done at character creation. + /// TODO: This is going to get removed when I reach Part 3 of my reworks, when I touch upon the GlimmerSystem itself and overhaul how players get powers. + /// + /// + /// + /// + public void AddPsionics(EntityUid uid) { if (Deleted(uid)) return; @@ -79,17 +43,11 @@ public void AddPsionics(EntityUid uid, string powerComp) if (HasComp(uid)) return; - AddComp(uid); - - var newComponent = (Component) _componentFactory.GetComponent(powerComp); - newComponent.Owner = uid; - - EntityManager.AddComponent(uid, newComponent); + AddRandomPsionicPower(uid); } - public void AddRandomPsionicPower(EntityUid uid) { - AddComp(uid); + EnsureComp(uid, out var psionic); if (!_prototypeManager.TryIndex("RandomPsionicPowerPool", out var pool)) { @@ -103,11 +61,21 @@ public void AddRandomPsionicPower(EntityUid uid) EntityManager.AddComponent(uid, newComponent); - _glimmerSystem.Glimmer += _random.Next(1, 5); + _glimmerSystem.Glimmer += _random.Next((int) MathF.Round(psionic.Amplification * psionic.Dampening * 1), (int) MathF.Round(psionic.Amplification * psionic.Dampening * 5)); } public void RemovePsionics(EntityUid uid) { + if (RemComp(uid)) + { + _popups.PopupEntity(Loc.GetString("mindbreaking-feedback", ("entity", uid)), + uid, + // TODO: Use LoS-based Filter when one is available. + Filter.Pvs(uid).RemoveWhereAttachedEntity(entity => !ExamineSystemShared.InRangeUnOccluded(uid, entity, ExamineRange, null)), + true, + PopupType.Medium); + } + if (!TryComp(uid, out var psionic)) return; @@ -130,14 +98,15 @@ public void RemovePsionics(EntityUid uid) if (psionic.PsionicAbility != null){ _actionsSystem.TryGetActionData( psionic.PsionicAbility, out var psiAbility ); if (psiAbility != null){ - var owner = psiAbility.Owner; _actionsSystem.RemoveAction(uid, psiAbility.Owner); } } _statusEffectsSystem.TryAddStatusEffect(uid, "Stutter", TimeSpan.FromMinutes(5), false, "StutteringAccent"); + _glimmerSystem.Glimmer += _random.Next((int) MathF.Round(psionic.Amplification * psionic.Dampening * -10), (int) MathF.Round(psionic.Amplification * psionic.Dampening * -5)); RemComp(uid); + RemComp(uid); } } } diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs b/Content.Server/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs similarity index 57% rename from Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs rename to Content.Server/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs index 5ca1dc7a6dc..0c50efb5cf3 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs @@ -1,31 +1,31 @@ +using Content.Server.DoAfter; using Content.Shared.Actions; -using Content.Shared.CombatMode.Pacification; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Damage; +using Content.Shared.DoAfter; using Content.Shared.Stunnable; using Content.Shared.Stealth; using Content.Shared.Stealth.Components; -using Content.Server.Psionics; -using Robust.Shared.Prototypes; -using Robust.Shared.Player; -using Robust.Shared.Audio; -using Robust.Shared.Timing; -using Content.Server.Mind; +using Content.Shared.Psionics.Events; using Content.Shared.Actions.Events; using Robust.Shared.Audio.Systems; +using Content.Shared.Interaction.Events; +using Content.Shared.Weapons.Ranged.Events; +using Content.Shared.Throwing; +using Robust.Shared.Timing; +using Content.Shared.Psionics; -namespace Content.Server.Abilities.Psionics +namespace Content.Server.Psionics.Abilities { public sealed class PsionicInvisibilityPowerSystem : EntitySystem { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly SharedStunSystem _stunSystem = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly SharedStealthSystem _stealth = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly MindSystem _mindSystem = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; public override void Initialize() { @@ -37,43 +37,61 @@ public override void Initialize() SubscribeLocalEvent(OnStart); SubscribeLocalEvent(OnEnd); SubscribeLocalEvent(OnDamageChanged); + SubscribeLocalEvent(OnAttackAttempt); + SubscribeLocalEvent(OnShootAttempt); + SubscribeLocalEvent(OnThrowAttempt); + SubscribeLocalEvent(OnInsulated); } private void OnInit(EntityUid uid, PsionicInvisibilityPowerComponent component, ComponentInit args) { - _actions.AddAction(uid, ref component.PsionicInvisibilityActionEntity, component.PsionicInvisibilityActionId ); - _actions.TryGetActionData( component.PsionicInvisibilityActionEntity, out var actionData ); + _actions.AddAction(uid, ref component.PsionicInvisibilityActionEntity, component.PsionicInvisibilityActionId); + _actions.TryGetActionData( component.PsionicInvisibilityActionEntity, out var actionData); if (actionData is { UseDelay: not null }) _actions.StartUseDelay(component.PsionicInvisibilityActionEntity); - if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) + if (TryComp(uid, out var psionic)) { - psionic.PsionicAbility = component.PsionicInvisibilityActionEntity; psionic.ActivePowers.Add(component); + psionic.PsychicFeedback.Add(component.InvisibilityFeedback); + psionic.Amplification += 0.5f; } } private void OnShutdown(EntityUid uid, PsionicInvisibilityPowerComponent component, ComponentShutdown args) { + RemComp(uid); + RemComp(uid); _actions.RemoveAction(uid, component.PsionicInvisibilityActionEntity); if (TryComp(uid, out var psionic)) { psionic.ActivePowers.Remove(component); + psionic.PsychicFeedback.Remove(component.InvisibilityFeedback); + psionic.Amplification -= 0.5f; } } private void OnPowerUsed(EntityUid uid, PsionicInvisibilityPowerComponent component, PsionicInvisibilityPowerActionEvent args) { - if (HasComp(uid)) + if (!TryComp(uid, out var psionic)) + return; + + if (HasComp(uid)) return; + var ev = new PsionicInvisibilityTimerEvent(_gameTiming.CurTime); + var doAfterArgs = new DoAfterArgs(EntityManager, uid, component.UseTimer, ev, uid) { Hidden = true }; + _doAfterSystem.TryStartDoAfter(doAfterArgs); + ToggleInvisibility(args.Performer); var action = Spawn(PsionicInvisibilityUsedComponent.PsionicInvisibilityUsedActionPrototype); _actions.AddAction(uid, action, action); - _actions.TryGetActionData( action, out var actionData ); + _actions.TryGetActionData(action, out var actionData); if (actionData is { UseDelay: not null }) _actions.StartUseDelay(action); - _psionics.LogPowerUsed(uid, "psionic invisibility"); + _psionics.LogPowerUsed(uid, "psionic invisibility", + (int) MathF.Round(8 * psionic.Amplification - 2 * psionic.Dampening), + (int) MathF.Round(12 * psionic.Amplification - 2 * psionic.Dampening)); args.Handled = true; } @@ -89,7 +107,6 @@ private void OnPowerOff(RemovePsionicInvisibilityOffPowerActionEvent args) private void OnStart(EntityUid uid, PsionicInvisibilityUsedComponent component, ComponentInit args) { EnsureComp(uid); - EnsureComp(uid); var stealth = EnsureComp(uid); _stealth.SetVisibility(uid, 0.66f, stealth); _audio.PlayPvs("/Audio/Effects/toss.ogg", uid); @@ -102,24 +119,37 @@ private void OnEnd(EntityUid uid, PsionicInvisibilityUsedComponent component, Co return; RemComp(uid); - RemComp(uid); RemComp(uid); _audio.PlayPvs("/Audio/Effects/toss.ogg", uid); - //Pretty sure this DOESN'T work as intended. _actions.RemoveAction(uid, component.PsionicInvisibilityUsedActionEntity); - - _stunSystem.TryParalyze(uid, TimeSpan.FromSeconds(8), false); DirtyEntity(uid); } + private void OnAttackAttempt(EntityUid uid, PsionicInvisibilityUsedComponent component, AttackAttemptEvent args) + { + RemComp(uid); + } + + private void OnShootAttempt(EntityUid uid, PsionicInvisibilityUsedComponent component, ShotAttemptedEvent args) + { + RemComp(uid); + } + + private void OnThrowAttempt(EntityUid uid, PsionicInvisibilityUsedComponent component, ThrowAttemptEvent args) + { + RemComp(uid); + } private void OnDamageChanged(EntityUid uid, PsionicInvisibilityUsedComponent component, DamageChangedEvent args) { + if (!TryComp(uid, out var psionic)) + return; + if (!args.DamageIncreased) return; ToggleInvisibility(uid); + _stunSystem.TryParalyze(uid, TimeSpan.FromSeconds(4f / psionic.Dampening + psionic.Amplification), false); } - public void ToggleInvisibility(EntityUid uid) { if (!HasComp(uid)) @@ -130,5 +160,19 @@ public void ToggleInvisibility(EntityUid uid) RemComp(uid); } } + + public void OnDoAfter(EntityUid uid, PsionicInvisibilityPowerComponent component, PsionicInvisibilityTimerEvent args) + { + RemComp(uid); + } + + private void OnInsulated(EntityUid uid, PsionicInvisibilityUsedComponent component, PsionicInsulationEvent args) + { + if (!TryComp(uid, out var psionic)) + return; + + RemComp(uid); + _stunSystem.TryParalyze(uid, TimeSpan.FromSeconds(4f / psionic.Dampening + psionic.Amplification), false); + } } } diff --git a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs new file mode 100644 index 00000000000..77075dab206 --- /dev/null +++ b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs @@ -0,0 +1,93 @@ +using Content.Shared.Actions; +using Content.Shared.Psionics.Abilities; +using Content.Server.Atmos.Components; +using Content.Server.Weapons.Ranged.Systems; +using Robust.Server.GameObjects; +using Content.Shared.Actions.Events; +using Content.Server.Explosion.Components; +using Content.Shared.Mobs.Components; +using Robust.Shared.Map; + +namespace Content.Server.Psionics.Abilities +{ + public sealed class PyrokinesisPowerSystem : EntitySystem + { + [Dependency] private readonly TransformSystem _xform = default!; + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; + [Dependency] private readonly GunSystem _gunSystem = default!; + [Dependency] private readonly SharedTransformSystem _transformSystem = default!; + [Dependency] private readonly PhysicsSystem _physics = default!; + [Dependency] private readonly IMapManager _mapManager = default!; + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnPowerUsed); + } + + private void OnInit(EntityUid uid, PyrokinesisPowerComponent component, ComponentInit args) + { + _actions.AddAction(uid, ref component.PyrokinesisActionEntity, component.PyrokinesisActionId); + _actions.TryGetActionData( component.PyrokinesisActionEntity, out var actionData); + if (actionData is { UseDelay: not null }) + _actions.StartUseDelay(component.PyrokinesisActionEntity); + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Add(component); + psionic.PsychicFeedback.Add(component.PyrokinesisFeedback); + psionic.Amplification += 1f; + } + } + + private void OnShutdown(EntityUid uid, PyrokinesisPowerComponent component, ComponentShutdown args) + { + _actions.RemoveAction(uid, component.PyrokinesisActionEntity); + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Remove(component); + psionic.PsychicFeedback.Remove(component.PyrokinesisFeedback); + psionic.Amplification -= 1f; + } + } + + private void OnPowerUsed(PyrokinesisPowerActionEvent args) + { + if (!TryComp(args.Performer, out var psionic)) + return; + + if (!HasComp(args.Performer)) + { + var xformQuery = GetEntityQuery(); + var xform = xformQuery.GetComponent(args.Performer); + + var mapPos = xform.Coordinates.ToMap(EntityManager, _xform); + var spawnCoords = _mapManager.TryFindGridAt(mapPos, out var gridUid, out _) + ? xform.Coordinates.WithEntityId(gridUid, EntityManager) + : new(_mapManager.GetMapEntityId(mapPos.MapId), mapPos.Position); + + var ent = Spawn("ProjectileAnomalyFireball", spawnCoords); + + if (TryComp(ent, out var fireball)) + { + fireball.MaxIntensity = (int) MathF.Round(20 * psionic.Amplification - 10 * psionic.Dampening); + + if (psionic.Amplification > 5 && EnsureComp(ent, out var ignite)) + { + ignite.FireStacks = 0.2f * psionic.Amplification - 0.1f * psionic.Dampening; + } + } + + var direction = args.Target.Position; + + _gunSystem.ShootProjectile(ent, direction, new System.Numerics.Vector2(0, 0), args.Performer, args.Performer, 20f); + + _psionics.LogPowerUsed(args.Performer, "pyrokinesis", + (int) MathF.Round(6f * psionic.Amplification - psionic.Dampening), + (int) MathF.Round(8f * psionic.Amplification - psionic.Dampening)); + args.Handled = true; + } + } + } +} diff --git a/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs b/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs new file mode 100644 index 00000000000..e184b19396b --- /dev/null +++ b/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs @@ -0,0 +1,76 @@ +using Content.Server.Body.Systems; +using Content.Server.Body.Components; +using Content.Shared.Actions; +using Content.Shared.Chemistry.Components; +using Content.Shared.Bed.Sleep; +using Content.Shared.Psionics.Abilities; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; +using Content.Shared.Mind; +using Content.Shared.Actions.Events; +using Content.Shared.FixedPoint; + +namespace Content.Server.Psionics.Abilities +{ + public sealed class MassSleepPowerSystem : EntitySystem + { + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; + [Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnPowerUsed); + } + + private void OnInit(EntityUid uid, RegenerativeStasisPowerComponent component, ComponentInit args) + { + _actions.AddAction(uid, ref component.RegenerativeStasisActionEntity, component.RegenerativeStasisActionId); + _actions.TryGetActionData(component.RegenerativeStasisActionEntity, out var actionData); + if (actionData is { UseDelay: not null }) + _actions.StartUseDelay(component.RegenerativeStasisActionEntity); + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Add(component); + psionic.PsychicFeedback.Add(component.RegenerativeStasisFeedback); + psionic.Amplification += 0.5f; + psionic.Dampening += 0.5f; + } + } + + private void OnShutdown(EntityUid uid, RegenerativeStasisPowerComponent component, ComponentShutdown args) + { + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Remove(component); + psionic.PsychicFeedback.Remove(component.RegenerativeStasisFeedback); + psionic.Amplification -= 0.5f; + psionic.Dampening -= 0.5f; + } + _actions.RemoveAction(uid, component.RegenerativeStasisActionEntity); + } + + private void OnPowerUsed(EntityUid uid, RegenerativeStasisPowerComponent component, RegenerativeStasisPowerActionEvent args) + { + if (TryComp(uid, out var psionic) + && !HasComp(uid) + && !HasComp(args.Target) + && TryComp(args.Target, out var stream)) + { + var solution = new Solution(); + solution.AddReagent("PsionicRegenerationEssence", FixedPoint2.New(MathF.Min(2.5f * psionic.Amplification + psionic.Dampening, 15f))); + solution.AddReagent("Epinephrine", FixedPoint2.New(MathF.Min(2.5f * psionic.Dampening + psionic.Amplification, 15f))); + _bloodstreamSystem.TryAddToChemicals(args.Target, solution, stream); + EnsureComp(args.Target); + + _psionics.LogPowerUsed(uid, "regenerative stasis", + (int) Math.Round(4 * psionic.Amplification - psionic.Dampening), + (int) Math.Round(6 * psionic.Amplification - psionic.Dampening)); + args.Handled = true; + } + } + } +} diff --git a/Content.Server/Psionics/Abilities/TelegnosisPowerSystem.cs b/Content.Server/Psionics/Abilities/TelegnosisPowerSystem.cs new file mode 100644 index 00000000000..f03b001fc70 --- /dev/null +++ b/Content.Server/Psionics/Abilities/TelegnosisPowerSystem.cs @@ -0,0 +1,106 @@ +using Content.Shared.Actions; +using Content.Shared.Psionics.Abilities; +using Content.Shared.Mind.Components; +using Content.Shared.Actions.Events; +using Content.Shared.Mobs; +using Content.Shared.Storage.Components; + +namespace Content.Server.Psionics.Abilities +{ + public sealed class TelegnosisPowerSystem : EntitySystem + { + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly MindSwapPowerSystem _mindSwap = default!; + [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnPowerUsed); + SubscribeLocalEvent(OnMindRemoved); + SubscribeLocalEvent(OnDispelled); + SubscribeLocalEvent(OnMobstateChanged); + SubscribeLocalEvent(OnStorageInsertAttempt); + } + + private void OnInit(EntityUid uid, TelegnosisPowerComponent component, ComponentInit args) + { + _actions.AddAction(uid, ref component.TelegnosisActionEntity, component.TelegnosisActionId ); + _actions.TryGetActionData( component.TelegnosisActionEntity, out var actionData ); + if (actionData is { UseDelay: not null }) + _actions.StartUseDelay(component.TelegnosisActionEntity); + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Add(component); + psionic.PsychicFeedback.Add(component.TelegnosisFeedback); + psionic.Amplification += 0.3f; + psionic.Dampening += 0.3f; + } + } + + private void OnShutdown(EntityUid uid, TelegnosisPowerComponent component, ComponentShutdown args) + { + _actions.RemoveAction(uid, component.TelegnosisActionEntity); + if (TryComp(uid, out var psionic)) + { + psionic.ActivePowers.Remove(component); + psionic.PsychicFeedback.Remove(component.TelegnosisFeedback); + psionic.Amplification -= 0.3f; + psionic.Dampening -= 0.3f; + } + } + + private void OnPowerUsed(EntityUid uid, TelegnosisPowerComponent component, TelegnosisPowerActionEvent args) + { + if (!TryComp(uid, out var psionic)) + return; + + if (HasComp(uid)) + return; + + var projection = Spawn(component.Prototype, Transform(uid).Coordinates); + Transform(projection).AttachToGridOrMap(); + component.OriginalEntity = uid; + component.IsProjecting = true; + component.ProjectionUid = projection; + _mindSwap.Swap(uid, projection); + + if (EnsureComp(projection, out var projectionComponent)) + projectionComponent.OriginalEntity = uid; + + _psionics.LogPowerUsed(uid, "telegnosis", + (int) Math.Round(8f * psionic.Amplification - psionic.Dampening), + (int) Math.Round(12f * psionic.Amplification - psionic.Dampening)); + + args.Handled = true; + } + private void OnMindRemoved(EntityUid uid, TelegnosticProjectionComponent component, MindRemovedMessage args) + { + if (TryComp(component.OriginalEntity, out var originalEntity)) + originalEntity.IsProjecting = false; + + QueueDel(uid); + } + + private void OnDispelled(EntityUid uid, TelegnosisPowerComponent component, DispelledEvent args) + { + if (component.IsProjecting) + _mindSwap.Swap(uid, component.ProjectionUid); + } + + private void OnMobstateChanged(EntityUid uid, TelegnosisPowerComponent component, MobStateChangedEvent args) + { + if (component.IsProjecting && args.NewMobState is MobState.Critical + || component.IsProjecting && args.NewMobState is MobState.Dead) + _mindSwap.Swap(uid, component.ProjectionUid); + } + + private void OnStorageInsertAttempt(EntityUid uid, TelegnosisPowerComponent component, InsertIntoEntityStorageAttemptEvent args) + { + if (component.IsProjecting) + _mindSwap.Swap(uid, component.ProjectionUid); + } + } +} diff --git a/Content.Server/Nyanotrasen/Psionics/AcceptPsionicsEui.cs b/Content.Server/Psionics/AcceptPsionicsEui.cs similarity index 95% rename from Content.Server/Nyanotrasen/Psionics/AcceptPsionicsEui.cs rename to Content.Server/Psionics/AcceptPsionicsEui.cs index 80fd8946f28..7c652664c64 100644 --- a/Content.Server/Nyanotrasen/Psionics/AcceptPsionicsEui.cs +++ b/Content.Server/Psionics/AcceptPsionicsEui.cs @@ -1,7 +1,7 @@ using Content.Shared.Psionics; using Content.Shared.Eui; using Content.Server.EUI; -using Content.Server.Abilities.Psionics; +using Content.Server.Psionics.Abilities; namespace Content.Server.Psionics { diff --git a/Content.Server/Nyanotrasen/Psionics/AntiPsychicWeaponComponent.cs b/Content.Server/Psionics/AntiPsychicWeaponComponent.cs similarity index 100% rename from Content.Server/Nyanotrasen/Psionics/AntiPsychicWeaponComponent.cs rename to Content.Server/Psionics/AntiPsychicWeaponComponent.cs diff --git a/Content.Server/Nyanotrasen/Audio/GlimmerSoundComponent.cs b/Content.Server/Psionics/Audio/GlimmerSoundComponent.cs similarity index 80% rename from Content.Server/Nyanotrasen/Audio/GlimmerSoundComponent.cs rename to Content.Server/Psionics/Audio/GlimmerSoundComponent.cs index 850be3e831c..9a6c62381be 100644 --- a/Content.Server/Nyanotrasen/Audio/GlimmerSoundComponent.cs +++ b/Content.Server/Psionics/Audio/GlimmerSoundComponent.cs @@ -2,12 +2,8 @@ using Content.Shared.Audio; using Content.Shared.Psionics.Glimmer; using Robust.Shared.Audio; -using Robust.Shared.ComponentTrees; -using Robust.Shared.GameStates; -using Robust.Shared.Physics; -using Robust.Shared.Serialization; -namespace Content.Server.Audio +namespace Content.Server.Psionics.Audio { [RegisterComponent] [Access(typeof(SharedAmbientSoundSystem), typeof(GlimmerReactiveSystem))] diff --git a/Content.Server/Nyanotrasen/Psionics/Dreams/DreamSystem.cs b/Content.Server/Psionics/Dreams/DreamSystem.cs similarity index 93% rename from Content.Server/Nyanotrasen/Psionics/Dreams/DreamSystem.cs rename to Content.Server/Psionics/Dreams/DreamSystem.cs index d6067717c94..1731c7a9bf5 100644 --- a/Content.Server/Nyanotrasen/Psionics/Dreams/DreamSystem.cs +++ b/Content.Server/Psionics/Dreams/DreamSystem.cs @@ -1,17 +1,14 @@ using Content.Shared.Dataset; using Content.Shared.Bed.Sleep; -using Content.Server.Chat.Systems; using Content.Server.Chat.Managers; using Robust.Shared.Random; using Robust.Shared.Prototypes; -using Robust.Server.GameObjects; using Robust.Shared.Player; namespace Content.Server.Psionics.Dreams { public sealed class DreamsSystem : EntitySystem { - [Dependency] private readonly ChatSystem _chat = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IChatManager _chatManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; diff --git a/Content.Server/Nyanotrasen/Psionics/Glimmer/GlimmerCommands.cs b/Content.Server/Psionics/Glimmer/GlimmerCommands.cs similarity index 100% rename from Content.Server/Nyanotrasen/Psionics/Glimmer/GlimmerCommands.cs rename to Content.Server/Psionics/Glimmer/GlimmerCommands.cs diff --git a/Content.Server/Nyanotrasen/Psionics/Glimmer/GlimmerReactiveSystem.cs b/Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs similarity index 99% rename from Content.Server/Nyanotrasen/Psionics/Glimmer/GlimmerReactiveSystem.cs rename to Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs index da3b07d6dab..c0802c8b670 100644 --- a/Content.Server/Nyanotrasen/Psionics/Glimmer/GlimmerReactiveSystem.cs +++ b/Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs @@ -1,14 +1,12 @@ -using Content.Server.Audio; +using Content.Server.Psionics.Audio; using Content.Server.Power.Components; using Content.Server.Electrocution; using Content.Server.Lightning; using Content.Server.Explosion.EntitySystems; -using Content.Server.Construction; using Content.Server.Ghost; using Content.Server.Revenant.EntitySystems; using Content.Shared.Audio; using Content.Shared.Construction.EntitySystems; -using Content.Shared.Coordinates.Helpers; using Content.Shared.GameTicking; using Content.Shared.Psionics.Glimmer; using Content.Shared.Verbs; @@ -16,7 +14,6 @@ using Content.Shared.Damage; using Content.Shared.Destructible; using Content.Shared.Construction.Components; -using Content.Shared.Mind; using Content.Shared.Mind.Components; using Content.Shared.Weapons.Melee.Components; using Robust.Shared.Audio; diff --git a/Content.Server/Nyanotrasen/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs b/Content.Server/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs similarity index 94% rename from Content.Server/Nyanotrasen/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs rename to Content.Server/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs index f0da85ce453..57c74398b08 100644 --- a/Content.Server/Nyanotrasen/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs +++ b/Content.Server/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs @@ -4,7 +4,6 @@ using Content.Shared.CCVar; using Content.Shared.Psionics.Glimmer; using Content.Shared.GameTicking; -using Content.Server.CartridgeLoader.Cartridges; namespace Content.Server.Psionics.Glimmer { @@ -17,7 +16,6 @@ public sealed class PassiveGlimmerReductionSystem : EntitySystem [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; - [Dependency] private readonly GlimmerMonitorCartridgeSystem _cartridgeSys = default!; /// List of glimmer values spaced by minute. public List GlimmerValues = new(); diff --git a/Content.Server/Nyanotrasen/Psionics/Glimmer/Structures/GlimmerSourceComponent.cs b/Content.Server/Psionics/Glimmer/Structures/GlimmerSourceComponent.cs similarity index 100% rename from Content.Server/Nyanotrasen/Psionics/Glimmer/Structures/GlimmerSourceComponent.cs rename to Content.Server/Psionics/Glimmer/Structures/GlimmerSourceComponent.cs diff --git a/Content.Server/Nyanotrasen/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs b/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs similarity index 100% rename from Content.Server/Nyanotrasen/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs rename to Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs diff --git a/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibilitySystem.cs b/Content.Server/Psionics/Invisibility/PsionicInvisibilitySystem.cs similarity index 88% rename from Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibilitySystem.cs rename to Content.Server/Psionics/Invisibility/PsionicInvisibilitySystem.cs index 31e6b89f13d..9583f45fdc9 100644 --- a/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibilitySystem.cs +++ b/Content.Server/Psionics/Invisibility/PsionicInvisibilitySystem.cs @@ -1,5 +1,6 @@ -using Content.Shared.Abilities.Psionics; -using Content.Server.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; +using Content.Shared.Psionics; +using Content.Server.Psionics.Abilities; using Content.Shared.Eye; using Content.Server.NPC.Systems; using Robust.Shared.Containers; @@ -20,7 +21,6 @@ public override void Initialize() SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnInsulInit); SubscribeLocalEvent(OnInsulShutdown); - SubscribeLocalEvent(OnEyeInit); /// Layer SubscribeLocalEvent(OnInvisInit); @@ -36,10 +36,16 @@ private void OnInit(EntityUid uid, PotentialPsionicComponent component, Componen SetCanSeePsionicInvisiblity(uid, false); } + /// + /// Being able to see invisible by default is no longer tracked by "Not having Potential Psionic". + /// Anything intended to be immune to invisibility(and mind magic in general) should instead have PsionicInsulation as a built-in component + /// + /// + /// + /// private void OnInsulInit(EntityUid uid, PsionicInsulationComponent component, ComponentInit args) { - if (!HasComp(uid)) - return; + RaiseLocalEvent(uid, new PsionicInsulationEvent()); if (HasComp(uid)) _invisSystem.ToggleInvisibility(uid); @@ -61,9 +67,6 @@ private void OnInsulInit(EntityUid uid, PsionicInsulationComponent component, Co private void OnInsulShutdown(EntityUid uid, PsionicInsulationComponent component, ComponentShutdown args) { - if (!HasComp(uid)) - return; - SetCanSeePsionicInvisiblity(uid, false); if (!HasComp(uid)) @@ -99,10 +102,6 @@ private void OnInvisShutdown(EntityUid uid, PsionicallyInvisibleComponent compon } } - private void OnEyeInit(EntityUid uid, EyeComponent component, ComponentInit args) - { - //SetCanSeePsionicInvisiblity(uid, true); //JJ Comment - Not allowed to modifies .yml on spawn any longer. See UninitializedSaveTest. - } private void OnEntInserted(EntityUid uid, PsionicallyInvisibleComponent component, EntInsertedIntoContainerMessage args) { DirtyEntity(args.Entity); @@ -125,7 +124,7 @@ public void SetCanSeePsionicInvisiblity(EntityUid uid, bool set) { if (EntityManager.TryGetComponent(uid, out EyeComponent? eye)) { - _eye.SetVisibilityMask(uid, eye.VisibilityMask & ~ (int) VisibilityFlags.PsionicInvisibility, eye); + _eye.SetVisibilityMask(uid, eye.VisibilityMask & ~(int) VisibilityFlags.PsionicInvisibility, eye); } } } diff --git a/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs b/Content.Server/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs similarity index 95% rename from Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs rename to Content.Server/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs index 859ceb7b83a..268deddf6d9 100644 --- a/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs +++ b/Content.Server/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs @@ -1,5 +1,4 @@ using Content.Shared.Whitelist; -using Robust.Shared.Timing; namespace Content.Server.Psionics { diff --git a/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs b/Content.Server/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs similarity index 95% rename from Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs rename to Content.Server/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs index cec755e3260..403e0592617 100644 --- a/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs +++ b/Content.Server/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs @@ -2,7 +2,6 @@ using Content.Shared.Stealth.Components; using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Systems; -using Robust.Shared.Timing; namespace Content.Server.Psionics { @@ -12,7 +11,6 @@ namespace Content.Server.Psionics public sealed class PsionicInvisibleContactsSystem : EntitySystem { [Dependency] private readonly SharedStealthSystem _stealth = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; public override void Initialize() { diff --git a/Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicallyInvisibleComponent.cs b/Content.Server/Psionics/Invisibility/PsionicallyInvisibleComponent.cs similarity index 100% rename from Content.Server/Nyanotrasen/Psionics/Invisibility/PsionicallyInvisibleComponent.cs rename to Content.Server/Psionics/Invisibility/PsionicallyInvisibleComponent.cs diff --git a/Content.Server/Psionics/PotentialPsionicComponent.cs b/Content.Server/Psionics/PotentialPsionicComponent.cs new file mode 100644 index 00000000000..e874296a4c3 --- /dev/null +++ b/Content.Server/Psionics/PotentialPsionicComponent.cs @@ -0,0 +1,21 @@ +namespace Content.Server.Psionics +{ + [RegisterComponent] + public sealed partial class PotentialPsionicComponent : Component + { + /// + /// The base chance of an entity rolling psychic powers, which is increased by other modifiers such as glimmer. + /// + /// + /// I have increased this to 10% up from its original value of 2%, because I estimate that most people won't take the Latent Psychic trait + /// Simply because they might not even know it exists + /// + [DataField("chance")] + public float Chance = 0.10f; + + /// + /// YORO (you only reroll once) + /// + public bool Rerolled = false; + } +} diff --git a/Content.Server/Nyanotrasen/Psionics/PsionicAwaitingPlayerComponent.cs b/Content.Server/Psionics/PsionicAwaitingPlayerComponent.cs similarity index 100% rename from Content.Server/Nyanotrasen/Psionics/PsionicAwaitingPlayerComponent.cs rename to Content.Server/Psionics/PsionicAwaitingPlayerComponent.cs diff --git a/Content.Server/Nyanotrasen/Psionics/PsionicBonusChanceComponent.cs b/Content.Server/Psionics/PsionicBonusChanceComponent.cs similarity index 100% rename from Content.Server/Nyanotrasen/Psionics/PsionicBonusChanceComponent.cs rename to Content.Server/Psionics/PsionicBonusChanceComponent.cs diff --git a/Content.Server/Nyanotrasen/Psionics/PsionicsCommands.cs b/Content.Server/Psionics/PsionicsCommands.cs similarity index 84% rename from Content.Server/Nyanotrasen/Psionics/PsionicsCommands.cs rename to Content.Server/Psionics/PsionicsCommands.cs index 959251d1fb7..3f9ee794b38 100644 --- a/Content.Server/Nyanotrasen/Psionics/PsionicsCommands.cs +++ b/Content.Server/Psionics/PsionicsCommands.cs @@ -1,9 +1,8 @@ using Content.Server.Administration; using Content.Shared.Administration; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Mobs.Components; using Robust.Shared.Console; -using Robust.Server.GameObjects; using Content.Shared.Actions; using Robust.Shared.Player; @@ -19,7 +18,8 @@ public async void Execute(IConsoleShell shell, string argStr, string[] args) { SharedActionsSystem actions = default!; var entMan = IoCManager.Resolve(); - foreach (var (actor, mob, psionic, meta) in entMan.EntityQuery()){ + foreach (var (actor, psionic, meta) in entMan.EntityQuery()) + { // filter out xenos, etc, with innate telepathy actions.TryGetActionData( psionic.PsionicAbility, out var actionData ); if (actionData == null || actionData.ToString() == null) diff --git a/Content.Server/Nyanotrasen/Psionics/PsionicsSystem.cs b/Content.Server/Psionics/PsionicsSystem.cs similarity index 91% rename from Content.Server/Nyanotrasen/Psionics/PsionicsSystem.cs rename to Content.Server/Psionics/PsionicsSystem.cs index 5a96af2e96b..bf829477609 100644 --- a/Content.Server/Nyanotrasen/Psionics/PsionicsSystem.cs +++ b/Content.Server/Psionics/PsionicsSystem.cs @@ -1,19 +1,14 @@ -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.StatusEffect; -using Content.Shared.Mobs; using Content.Shared.Psionics.Glimmer; using Content.Shared.Weapons.Melee.Events; using Content.Shared.Damage.Events; -using Content.Shared.IdentityManagement; using Content.Shared.CCVar; -using Content.Server.Abilities.Psionics; -using Content.Server.Chat.Systems; +using Content.Server.Psionics.Abilities; using Content.Server.Electrocution; using Content.Server.NPC.Components; using Content.Server.NPC.Systems; -using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; -using Robust.Shared.Player; using Robust.Shared.Configuration; using Robust.Shared.Random; @@ -27,7 +22,6 @@ public sealed class PsionicsSystem : EntitySystem [Dependency] private readonly ElectrocutionSystem _electrocutionSystem = default!; [Dependency] private readonly MindSwapPowerSystem _mindSwapPowerSystem = default!; [Dependency] private readonly GlimmerSystem _glimmerSystem = default!; - [Dependency] private readonly ChatSystem _chat = default!; [Dependency] private readonly NpcFactionSystem _npcFactonSystem = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; @@ -54,6 +48,7 @@ public override void Initialize() SubscribeLocalEvent(OnStamHit); SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnRemove); } @@ -87,7 +82,11 @@ private void OnMeleeHit(EntityUid uid, AntiPsionicWeaponComponent component, Mel _electrocutionSystem.TryDoElectrocution(args.User, null, 20, TimeSpan.FromSeconds(5), false); } } - + private void OnStartup(EntityUid uid, PsionicComponent component, MapInitEvent args) + { + component.Amplification = _random.NextFloat(0.3f, 1.1f); + component.Dampening = _random.NextFloat(0.3f, 1.1f); + } private void OnInit(EntityUid uid, PsionicComponent component, ComponentInit args) { if (!component.Removable) @@ -104,7 +103,7 @@ private void OnInit(EntityUid uid, PsionicComponent component, ComponentInit arg private void OnRemove(EntityUid uid, PsionicComponent component, ComponentRemove args) { - if (!TryComp(uid, out var factions)) + if (!HasComp(uid)) return; _npcFactonSystem.RemoveFaction(uid, "PsionicInterloper"); @@ -144,14 +143,14 @@ public void RollPsionics(EntityUid uid, PotentialPsionicComponent component, boo } if (applyGlimmer) - chance += ((float) _glimmerSystem.Glimmer / 1000); + chance += (float) _glimmerSystem.Glimmer / 1000; chance *= multiplier; chance = Math.Clamp(chance, 0, 1); if (_random.Prob(chance)) - _psionicAbilitiesSystem.AddPsionics(uid, warn); + _psionicAbilitiesSystem.AddPsionics(uid); } public void RerollPsionics(EntityUid uid, PotentialPsionicComponent? psionic = null, float bonusMuliplier = 1f) diff --git a/Content.Server/Nyanotrasen/Chat/TSayCommand.cs b/Content.Server/Psionics/Telepathy/TSayCommand.cs similarity index 95% rename from Content.Server/Nyanotrasen/Chat/TSayCommand.cs rename to Content.Server/Psionics/Telepathy/TSayCommand.cs index 9ba27b65d71..8fbaa5e17b2 100644 --- a/Content.Server/Nyanotrasen/Chat/TSayCommand.cs +++ b/Content.Server/Psionics/Telepathy/TSayCommand.cs @@ -1,11 +1,10 @@ using Content.Server.Chat.Systems; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Enums; using Robust.Shared.Player; -namespace Content.Server.Chat.Commands +namespace Content.Server.Psionics.Telepathy { [AnyCommand] internal sealed class TSayCommand : IConsoleCommand diff --git a/Content.Server/Nyanotrasen/Chat/TelepathicRepeaterComponent.cs b/Content.Server/Psionics/Telepathy/TelepathicRepeaterComponent.cs similarity index 82% rename from Content.Server/Nyanotrasen/Chat/TelepathicRepeaterComponent.cs rename to Content.Server/Psionics/Telepathy/TelepathicRepeaterComponent.cs index fc199f4332a..6e194f76c8f 100644 --- a/Content.Server/Nyanotrasen/Chat/TelepathicRepeaterComponent.cs +++ b/Content.Server/Psionics/Telepathy/TelepathicRepeaterComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Server.Nyanotrasen.Chat +namespace Content.Server.Psionics.Telepathy { /// /// Repeats whatever is happening in telepathic chat. diff --git a/Content.Server/Nyanotrasen/Chat/NyanoChatSystem.cs b/Content.Server/Psionics/Telepathy/TelepathyChatSystem.cs similarity index 85% rename from Content.Server/Nyanotrasen/Chat/NyanoChatSystem.cs rename to Content.Server/Psionics/Telepathy/TelepathyChatSystem.cs index 58ed1782741..ad49075e65a 100644 --- a/Content.Server/Nyanotrasen/Chat/NyanoChatSystem.cs +++ b/Content.Server/Psionics/Telepathy/TelepathyChatSystem.cs @@ -2,7 +2,7 @@ using Content.Server.Administration.Managers; using Content.Server.Chat.Managers; using Content.Server.Chat.Systems; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.Bed.Sleep; using Content.Shared.Chat; using Content.Shared.Database; @@ -16,10 +16,10 @@ using System.Linq; using System.Text; -namespace Content.Server.Nyanotrasen.Chat +namespace Content.Server.Psionics.Telepathy { /// - /// Extensions for nyano's chat stuff + /// Extensions for Telepathic Chat /// public sealed class NyanoChatSystem : EntitySystem @@ -47,7 +47,9 @@ private IEnumerable GetAdminClients() private List GetDreamers(IEnumerable removeList) { var filtered = Filter.Empty() - .AddWhereAttachedEntity(entity => HasComp(entity) || HasComp(entity) && !HasComp(entity) && !HasComp(entity)) + .AddWhereAttachedEntity(entity => HasComp(entity) + || HasComp(entity) && !HasComp(entity) && !HasComp(entity) + || HasComp(entity) && !HasComp(entity) && !HasComp(entity)) .Recipients .Select(p => p.ConnectedClient); @@ -61,7 +63,7 @@ private List GetDreamers(IEnumerable removeList) private bool IsEligibleForTelepathy(EntityUid entity) { - return HasComp(entity) + return TryComp(entity, out var psionic) && psionic.Telepath && !HasComp(entity) && !HasComp(entity) && (!TryComp(entity, out var mobstate) || mobstate.CurrentState == MobState.Alive); @@ -92,9 +94,9 @@ public void SendTelepathicChat(EntityUid source, string message, bool hideChat) if (_random.Prob(0.1f)) _glimmerSystem.Glimmer++; - if (_random.Prob(Math.Min(0.33f + ((float) _glimmerSystem.Glimmer / 1500), 1))) + if (_random.Prob(Math.Min(0.33f + (float) _glimmerSystem.Glimmer / 1500, 1))) { - float obfuscation = (0.25f + (float) _glimmerSystem.Glimmer / 2000); + float obfuscation = 0.25f + (float) _glimmerSystem.Glimmer / 2000; var obfuscated = ObfuscateMessageReadability(message, obfuscation); _chatManager.ChatMessageToMany(ChatChannel.Telepathic, obfuscated, messageWrap, source, hideChat, false, GetDreamers(clients), Color.PaleVioletRed); } @@ -111,7 +113,7 @@ private string ObfuscateMessageReadability(string message, float chance) for (var i = 0; i < message.Length; i++) { - if (char.IsWhiteSpace((modifiedMessage[i]))) + if (char.IsWhiteSpace(modifiedMessage[i])) { continue; } diff --git a/Content.Server/Salvage/SpawnSalvageMissionJob.cs b/Content.Server/Salvage/SpawnSalvageMissionJob.cs index 2776db2283a..e2b17b58724 100644 --- a/Content.Server/Salvage/SpawnSalvageMissionJob.cs +++ b/Content.Server/Salvage/SpawnSalvageMissionJob.cs @@ -125,11 +125,7 @@ protected override async Task Process() air.Gases.CopyTo(moles, 0); var atmos = _entManager.EnsureComponent(mapUid); _entManager.System().SetMapSpace(mapUid, air.Space, atmos); - _entManager.System().SetMapGasMixture(mapUid, new GasMixture(2500) - { - Temperature = mission.Temperature, - Moles = moles, - }, atmos); + _entManager.System().SetMapGasMixture(mapUid, new GasMixture(moles, mission.Temperature), atmos); if (mission.Color != null) { diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs index f9ceab8f7b1..e4e4534b0c5 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs @@ -371,8 +371,8 @@ private void UpdateFTLStarting(Entity entity) Enable(uid, component: body); _physics.SetLinearVelocity(uid, new Vector2(0f, 20f), body: body); _physics.SetAngularVelocity(uid, 0f, body: body); - _physics.SetLinearDamping(body, 0f); - _physics.SetAngularDamping(body, 0f); + _physics.SetLinearDamping(uid, body, 0f); + _physics.SetAngularDamping(uid, body, 0f); _dockSystem.SetDockBolts(uid, true); _console.RefreshShuttleConsoles(uid); @@ -426,8 +426,8 @@ private void UpdateFTLArriving(Entity entity) _physics.SetLinearVelocity(uid, Vector2.Zero, body: body); _physics.SetAngularVelocity(uid, 0f, body: body); - _physics.SetLinearDamping(body, entity.Comp2.LinearDamping); - _physics.SetAngularDamping(body, entity.Comp2.AngularDamping); + _physics.SetLinearDamping(uid, body, entity.Comp2.LinearDamping); + _physics.SetAngularDamping(uid, body, entity.Comp2.AngularDamping); var target = entity.Comp1.TargetCoordinates; diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.cs index 8d44dae4b2e..7c42753a7de 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.cs @@ -129,10 +129,10 @@ public void Enable(EntityUid uid, FixturesComponent? manager = null, PhysicsComp return; _physics.SetBodyType(uid, BodyType.Dynamic, manager: manager, body: component); - _physics.SetBodyStatus(component, BodyStatus.InAir); + _physics.SetBodyStatus(uid, component, BodyStatus.InAir); _physics.SetFixedRotation(uid, false, manager: manager, body: component); - _physics.SetLinearDamping(component, shuttle.LinearDamping); - _physics.SetAngularDamping(component, shuttle.AngularDamping); + _physics.SetLinearDamping(uid, component, shuttle.LinearDamping); + _physics.SetAngularDamping(uid, component, shuttle.AngularDamping); } public void Disable(EntityUid uid, FixturesComponent? manager = null, PhysicsComponent? component = null) @@ -141,7 +141,7 @@ public void Disable(EntityUid uid, FixturesComponent? manager = null, PhysicsCom return; _physics.SetBodyType(uid, BodyType.Static, manager: manager, body: component); - _physics.SetBodyStatus(component, BodyStatus.OnGround); + _physics.SetBodyStatus(uid, component, BodyStatus.OnGround); _physics.SetFixedRotation(uid, true, manager: manager, body: component); } diff --git a/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs b/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs index 7784db015d3..ba07375699b 100644 --- a/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs +++ b/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs @@ -13,7 +13,7 @@ using Robust.Shared.Map.Components; using Robust.Shared.Physics.Events; using Robust.Shared.Timing; -using Content.Shared.Abilities.Psionics; //Nyano - Summary: for the telegnostic projection. +using Content.Shared.Psionics.Abilities; //EE - Summary: for the telegnostic projection. namespace Content.Server.Singularity.EntitySystems; @@ -39,7 +39,7 @@ public override void Initialize() SubscribeLocalEvent(PreventConsume); SubscribeLocalEvent(PreventConsume); - SubscribeLocalEvent(PreventConsume); ///Nyano - Summary: the telegnositic projection has the same trait as ghosts. + SubscribeLocalEvent(PreventConsume); ///EE - Summary: the telegnositic projection has the same trait as ghosts. SubscribeLocalEvent(PreventConsume); SubscribeLocalEvent(OnHorizonMapInit); SubscribeLocalEvent(OnStartCollide); diff --git a/Content.Server/Spreader/SpreaderSystem.cs b/Content.Server/Spreader/SpreaderSystem.cs index 89951718236..5b2f3298a2b 100644 --- a/Content.Server/Spreader/SpreaderSystem.cs +++ b/Content.Server/Spreader/SpreaderSystem.cs @@ -18,6 +18,7 @@ namespace Content.Server.Spreader; /// public sealed class SpreaderSystem : EntitySystem { + [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IRobustRandom _robustRandom = default!; [Dependency] private readonly SharedMapSystem _map = default!; @@ -33,6 +34,8 @@ public sealed class SpreaderSystem : EntitySystem // TODO PERFORMANCE Assign each prototype to an index and convert dictionary to array private readonly Dictionary> _gridUpdates = []; + private EntityQuery _query; + public const float SpreadCooldownSeconds = 1; [ValidatePrototypeId] @@ -47,6 +50,8 @@ public override void Initialize() SubscribeLocalEvent(OnTerminating); SetupPrototypes(); + + _query = GetEntityQuery(); } private void OnPrototypeReload(PrototypesReloadedEventArgs obj) @@ -66,13 +71,7 @@ private void SetupPrototypes() private void OnAirtightChanged(ref AirtightChanged ev) { - var neighbors = GetSpreadableNeighbors(ev.Entity, ev.Airtight, ev.Position); - - foreach (var neighbor in neighbors) - { - if (!TerminatingOrDeleted(neighbor)) - EnsureComp(neighbor); - } + ActivateSpreadableNeighbors(ev.Entity, ev.Position); } private void OnGridInit(GridInitializeEvent ev) @@ -82,13 +81,7 @@ private void OnGridInit(GridInitializeEvent ev) private void OnTerminating(Entity entity, ref EntityTerminatingEvent args) { - var neighbors = GetSpreadableNeighbors(entity); - - foreach (var neighbor in neighbors) - { - if (!TerminatingOrDeleted(neighbor)) - EnsureComp(neighbor); - } + ActivateSpreadableNeighbors(entity); } /// @@ -254,8 +247,7 @@ public void GetNeighbors(EntityUid uid, TransformComponent comp, ProtoId - /// Given an entity, this returns a list of all adjacent entities with a . + /// This function activates all spreaders that are adjacent to a given entity. This also activates other spreaders + /// on the same tile as the current entity (for thin airtight entities like windoors). /// - public List GetSpreadableNeighbors(EntityUid uid, AirtightComponent? comp = null, - (EntityUid Grid, Vector2i Tile)? position = null) + public void ActivateSpreadableNeighbors(EntityUid uid, (EntityUid Grid, Vector2i Tile)? position = null) { - Resolve(uid, ref comp, false); - var neighbors = new List(); - Vector2i tile; EntityUid ent; MapGridComponent? grid; @@ -315,37 +303,40 @@ public List GetSpreadableNeighbors(EntityUid uid, AirtightComponent? { var transform = Transform(uid); if (!TryComp(transform.GridUid, out grid) || TerminatingOrDeleted(transform.GridUid.Value)) - return neighbors; + return; + tile = _map.TileIndicesFor(transform.GridUid.Value, grid, transform.Coordinates); ent = transform.GridUid.Value; } else { if (!TryComp(position.Value.Grid, out grid)) - return neighbors; - tile = position.Value.Tile; - ent = position.Value.Grid; + return; + (ent, tile) = position.Value; } - var spreaderQuery = GetEntityQuery(); + var anchored = _map.GetAnchoredEntitiesEnumerator(ent, grid, tile); + while (anchored.MoveNext(out var entity)) + { + if (entity == ent) + continue; + DebugTools.Assert(Transform(entity.Value).Anchored); + if (_query.HasComponent(ent) && !TerminatingOrDeleted(entity.Value)) + EnsureComp(entity.Value); + } for (var i = 0; i < Atmospherics.Directions; i++) { var direction = (AtmosDirection) (1 << i); - if (comp != null && !comp.AirBlockedDirection.IsFlagSet(direction)) - continue; + var adjacentTile = SharedMapSystem.GetDirection(tile, direction.ToDirection()); + anchored = _map.GetAnchoredEntitiesEnumerator(ent, grid, adjacentTile); - var directionEnumerator = - _map.GetAnchoredEntitiesEnumerator(ent, grid, SharedMapSystem.GetDirection(tile, direction.ToDirection())); - - while (directionEnumerator.MoveNext(out var entity)) + while (anchored.MoveNext(out var entity)) { DebugTools.Assert(Transform(entity.Value).Anchored); - if (spreaderQuery.HasComponent(entity) && !TerminatingOrDeleted(entity.Value)) - neighbors.Add(entity.Value); + if (_query.HasComponent(ent) && !TerminatingOrDeleted(entity.Value)) + EnsureComp(entity.Value); } } - - return neighbors; } } diff --git a/Content.Server/StationEvents/Events/MeteorSwarmRule.cs b/Content.Server/StationEvents/Events/MeteorSwarmRule.cs index 192a620c9fc..ad56479b379 100644 --- a/Content.Server/StationEvents/Events/MeteorSwarmRule.cs +++ b/Content.Server/StationEvents/Events/MeteorSwarmRule.cs @@ -68,9 +68,9 @@ protected override void ActiveTick(EntityUid uid, MeteorSwarmRuleComponent compo var spawnPosition = new MapCoordinates(center + offset, mapId); var meteor = Spawn("MeteorLarge", spawnPosition); var physics = EntityManager.GetComponent(meteor); - _physics.SetBodyStatus(physics, BodyStatus.InAir); - _physics.SetLinearDamping(physics, 0f); - _physics.SetAngularDamping(physics, 0f); + _physics.SetBodyStatus(meteor, physics, BodyStatus.InAir); + _physics.SetLinearDamping(meteor, physics, 0f); + _physics.SetAngularDamping(meteor, physics, 0f); _physics.ApplyLinearImpulse(meteor, -offset.Normalized() * component.MeteorVelocity * physics.Mass, body: physics); _physics.ApplyAngularImpulse( meteor, diff --git a/Content.Server/Zombies/ZombieSystem.Transform.cs b/Content.Server/Zombies/ZombieSystem.Transform.cs index daadd4b518b..53128aade31 100644 --- a/Content.Server/Zombies/ZombieSystem.Transform.cs +++ b/Content.Server/Zombies/ZombieSystem.Transform.cs @@ -16,7 +16,7 @@ using Content.Server.Roles; using Content.Server.Speech.Components; using Content.Server.Temperature.Components; -using Content.Shared.Abilities.Psionics; +using Content.Shared.Psionics.Abilities; using Content.Shared.CombatMode; using Content.Shared.CombatMode.Pacification; using Content.Shared.Damage; @@ -59,9 +59,7 @@ public sealed partial class ZombieSystem [Dependency] private readonly IChatManager _chatMan = default!; [Dependency] private readonly MindSystem _mind = default!; [Dependency] private readonly SharedRoleSystem _roles = default!; - [Dependency] private readonly MobThresholdSystem _mobThreshold = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly ActionsSystem _actions = default!; // DeltaV - No psionic zombies /// /// Handles an entity turning into a zombie when they die or go into crit diff --git a/Content.Shared/Atmos/Atmospherics.cs b/Content.Shared/Atmos/Atmospherics.cs index 7460e08e46f..6a8587ca239 100644 --- a/Content.Shared/Atmos/Atmospherics.cs +++ b/Content.Shared/Atmos/Atmospherics.cs @@ -8,11 +8,6 @@ namespace Content.Shared.Atmos /// public static class Atmospherics { - static Atmospherics() - { - AdjustedNumberOfGases = MathHelper.NextMultipleOf(TotalNumberOfGases, 4); - } - #region ATMOS /// /// The universal gas constant, in kPa*L/(K*mol) @@ -183,7 +178,7 @@ static Atmospherics() /// This is the actual length of the gases arrays in mixtures. /// Set to the closest multiple of 4 relative to for SIMD reasons. /// - public static readonly int AdjustedNumberOfGases; + public const int AdjustedNumberOfGases = ((TotalNumberOfGases + 3) / 4) * 4; /// /// Amount of heat released per mole of burnt hydrogen or tritium (hydrogen isotope) diff --git a/Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs b/Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs index eb0079eb358..f468724db33 100644 --- a/Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs +++ b/Content.Shared/Atmos/EntitySystems/SharedGasTileOverlaySystem.cs @@ -66,7 +66,10 @@ public static Vector2i GetGasChunkIndices(Vector2i indices) [Serializable, NetSerializable] public readonly struct GasOverlayData : IEquatable { + [ViewVariables] public readonly byte FireState; + + [ViewVariables] public readonly byte[] Opacity; // TODO change fire color based on temps diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs index b58bdf83e49..8172947a039 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs @@ -358,7 +358,7 @@ public bool TryBuckle(EntityUid buckleUid, EntityUid userUid, EntityUid strapUid if (TryComp(buckleUid, out var physics)) { - _physics.ResetDynamics(physics); + _physics.ResetDynamics(buckleUid, physics); } if (!buckleComp.PullStrap && TryComp(strapUid, out var toPullable)) diff --git a/Content.Shared/Maps/ContentTileDefinition.cs b/Content.Shared/Maps/ContentTileDefinition.cs index ce7980509eb..32f5db0e821 100644 --- a/Content.Shared/Maps/ContentTileDefinition.cs +++ b/Content.Shared/Maps/ContentTileDefinition.cs @@ -81,7 +81,11 @@ public sealed partial class ContentTileDefinition : IPrototype, IInheritingProto [DataField("itemDrop", customTypeSerializer:typeof(PrototypeIdSerializer))] public string ItemDropPrototypeName { get; private set; } = "FloorTileItemSteel"; - [DataField("isSpace")] public bool IsSpace { get; private set; } + // TODO rename data-field in yaml + /// + /// Whether or not the tile is exposed to the map's atmosphere. + /// + [DataField("isSpace")] public bool MapAtmosphere { get; private set; } /// /// Friction override for mob mover in diff --git a/Content.Shared/Maps/TurfHelpers.cs b/Content.Shared/Maps/TurfHelpers.cs index a87b8c97d15..58a5d133b55 100644 --- a/Content.Shared/Maps/TurfHelpers.cs +++ b/Content.Shared/Maps/TurfHelpers.cs @@ -11,22 +11,6 @@ namespace Content.Shared.Maps // That, or make the interface arguments non-optional so people stop failing to pass them in. public static class TurfHelpers { - /// - /// Attempts to get the turf at map indices with grid id or null if no such turf is found. - /// - public static TileRef GetTileRef(this Vector2i vector2i, EntityUid gridId, IMapManager? mapManager = null) - { - mapManager ??= IoCManager.Resolve(); - - if (!mapManager.TryGetGrid(gridId, out var grid)) - return default; - - if (!grid.TryGetTileRef(vector2i, out var tile)) - return default; - - return tile; - } - /// /// Attempts to get the turf at a certain coordinates or null if no such turf is found. /// @@ -67,7 +51,7 @@ public static ContentTileDefinition GetContentTileDefinition(this Tile tile, ITi /// public static bool IsSpace(this Tile tile, ITileDefinitionManager? tileDefinitionManager = null) { - return tile.GetContentTileDefinition(tileDefinitionManager).IsSpace; + return tile.GetContentTileDefinition(tileDefinitionManager).MapAtmosphere; } /// @@ -115,15 +99,6 @@ public static IEnumerable GetEntitiesInTile(this EntityCoordinates co return GetEntitiesInTile(turf.Value, flags, lookupSystem); } - /// - /// Helper that returns all entities in a turf. - /// - [Obsolete("Use the lookup system")] - public static IEnumerable GetEntitiesInTile(this Vector2i indices, EntityUid gridId, LookupFlags flags = LookupFlags.Static, EntityLookupSystem? lookupSystem = null) - { - return GetEntitiesInTile(indices.GetTileRef(gridId), flags, lookupSystem); - } - /// /// Checks if a turf has something dense on it. /// diff --git a/Content.Shared/Movement/Systems/SharedJetpackSystem.cs b/Content.Shared/Movement/Systems/SharedJetpackSystem.cs index abe12b79d1a..8c42511f846 100644 --- a/Content.Shared/Movement/Systems/SharedJetpackSystem.cs +++ b/Content.Shared/Movement/Systems/SharedJetpackSystem.cs @@ -92,7 +92,7 @@ private void SetupUser(EntityUid user, EntityUid jetpackUid) _mover.SetRelay(user, jetpackUid); if (TryComp(user, out var physics)) - _physics.SetBodyStatus(physics, BodyStatus.InAir); + _physics.SetBodyStatus(user, physics, BodyStatus.InAir); userComp.Jetpack = jetpackUid; } @@ -103,7 +103,7 @@ private void RemoveUser(EntityUid uid) return; if (TryComp(uid, out var physics)) - _physics.SetBodyStatus(physics, BodyStatus.OnGround); + _physics.SetBodyStatus(uid, physics, BodyStatus.OnGround); RemComp(uid); } diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs deleted file mode 100644 index 7d611c63dac..00000000000 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerComponent.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Content.Shared.Actions; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Shared.Abilities.Psionics -{ - [RegisterComponent] - public sealed partial class MassSleepPowerComponent : Component - { - public float Radius = 1.25f; - [DataField("massSleepActionId", - customTypeSerializer: typeof(PrototypeIdSerializer))] - public string? MassSleepActionId = "ActionMassSleep"; - - [DataField("massSleepActionEntity")] - public EntityUid? MassSleepActionEntity; - } -} diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerSystem.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerSystem.cs deleted file mode 100644 index e36a3c70e8a..00000000000 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MassSleep/MassSleepPowerSystem.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Content.Shared.Actions; -using Content.Shared.Bed.Sleep; -using Content.Shared.Magic.Events; -using Content.Shared.Damage; -using Content.Shared.Mobs.Components; -using Robust.Shared.Prototypes; -using Robust.Shared.Timing; -using Content.Shared.Mind; -using Content.Shared.Actions.Events; - -namespace Content.Shared.Abilities.Psionics -{ - public sealed class MassSleepPowerSystem : EntitySystem - { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly SharedActionsSystem _actions = default!; - [Dependency] private readonly EntityLookupSystem _lookup = default!; - [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly SharedMindSystem _mindSystem = default!; - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnShutdown); - SubscribeLocalEvent(OnPowerUsed); - } - - private void OnInit(EntityUid uid, MassSleepPowerComponent component, ComponentInit args) - { - _actions.AddAction(uid, ref component.MassSleepActionEntity, component.MassSleepActionId ); - _actions.TryGetActionData( component.MassSleepActionEntity, out var actionData ); - if (actionData is { UseDelay: not null }) - _actions.StartUseDelay(component.MassSleepActionEntity); - if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - psionic.PsionicAbility = component.MassSleepActionEntity; - } - - private void OnShutdown(EntityUid uid, MassSleepPowerComponent component, ComponentShutdown args) - { - _actions.RemoveAction(uid, component.MassSleepActionEntity); - } - - private void OnPowerUsed(EntityUid uid, MassSleepPowerComponent component, MassSleepPowerActionEvent args) - { - foreach (var entity in _lookup.GetEntitiesInRange(args.Target, component.Radius)) - { - if (HasComp(entity) && entity != uid && !HasComp(entity)) - { - if (TryComp(entity, out var damageable) && damageable.DamageContainerID == "Biological") - EnsureComp(entity); - } - } - _psionics.LogPowerUsed(uid, "mass sleep"); - args.Handled = true; - } - } -} diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs deleted file mode 100644 index c9d0130221a..00000000000 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Content.Shared.Actions; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Shared.Abilities.Psionics -{ - [RegisterComponent] - public sealed partial class MetapsionicPowerComponent : Component - { - [DataField("range")] - public float Range = 5f; - - public InstantActionComponent? MetapsionicPowerAction = null; - [DataField("metapsionicActionId", - customTypeSerializer: typeof(PrototypeIdSerializer))] - public string? MetapsionicActionId = "ActionMetapsionic"; - - [DataField("metapsionicActionEntity")] - public EntityUid? MetapsionicActionEntity; - } -} diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs b/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs deleted file mode 100644 index 9d627cb42d8..00000000000 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Content.Shared.Abilities.Psionics -{ - [RegisterComponent] - public sealed partial class TelegnosticProjectionComponent : Component - {} -} \ No newline at end of file diff --git a/Content.Shared/Nyanotrasen/Actions/Events/MassSleepPowerActionEvent.cs b/Content.Shared/Nyanotrasen/Actions/Events/MassSleepPowerActionEvent.cs deleted file mode 100644 index 6666ee48d6c..00000000000 --- a/Content.Shared/Nyanotrasen/Actions/Events/MassSleepPowerActionEvent.cs +++ /dev/null @@ -1,2 +0,0 @@ -namespace Content.Shared.Actions.Events; -public sealed partial class MassSleepPowerActionEvent : WorldTargetActionEvent {} diff --git a/Content.Shared/Nyanotrasen/Actions/Events/MetapsionicPowerActionEvent.cs b/Content.Shared/Nyanotrasen/Actions/Events/MetapsionicPowerActionEvent.cs index b28801efe74..b7c3c8ad2d6 100644 --- a/Content.Shared/Nyanotrasen/Actions/Events/MetapsionicPowerActionEvent.cs +++ b/Content.Shared/Nyanotrasen/Actions/Events/MetapsionicPowerActionEvent.cs @@ -1,2 +1,3 @@ namespace Content.Shared.Actions.Events; -public sealed partial class MetapsionicPowerActionEvent : InstantActionEvent {} +public sealed partial class WideMetapsionicPowerActionEvent : InstantActionEvent { } +public sealed partial class FocusedMetapsionicPowerActionEvent : EntityTargetActionEvent { } diff --git a/Content.Shared/Nyanotrasen/Actions/Events/PyrokinesisPowerActionEvent.cs b/Content.Shared/Nyanotrasen/Actions/Events/PyrokinesisPowerActionEvent.cs index 896ec0bb63d..4639aadd55b 100644 --- a/Content.Shared/Nyanotrasen/Actions/Events/PyrokinesisPowerActionEvent.cs +++ b/Content.Shared/Nyanotrasen/Actions/Events/PyrokinesisPowerActionEvent.cs @@ -1,2 +1,4 @@ namespace Content.Shared.Actions.Events; -public sealed partial class PyrokinesisPowerActionEvent : EntityTargetActionEvent {} +public sealed partial class PyrokinesisPowerActionEvent : WorldTargetActionEvent {} + + diff --git a/Content.Shared/Nyanotrasen/Actions/Events/RegenerativeStasisPowerActionEvent.cs b/Content.Shared/Nyanotrasen/Actions/Events/RegenerativeStasisPowerActionEvent.cs new file mode 100644 index 00000000000..4435f475a44 --- /dev/null +++ b/Content.Shared/Nyanotrasen/Actions/Events/RegenerativeStasisPowerActionEvent.cs @@ -0,0 +1,2 @@ +namespace Content.Shared.Actions.Events; +public sealed partial class RegenerativeStasisPowerActionEvent : EntityTargetActionEvent {} diff --git a/Content.Shared/Nyanotrasen/Psionics/Events.cs b/Content.Shared/Nyanotrasen/Psionics/Events.cs deleted file mode 100644 index cf9a50c6e18..00000000000 --- a/Content.Shared/Nyanotrasen/Psionics/Events.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Robust.Shared.Serialization; -using Content.Shared.DoAfter; - -namespace Content.Shared.Psionics.Events -{ - [Serializable, NetSerializable] - public sealed partial class PsionicRegenerationDoAfterEvent : DoAfterEvent - { - [DataField("startedAt", required: true)] - public TimeSpan StartedAt; - - private PsionicRegenerationDoAfterEvent() - { - } - - public PsionicRegenerationDoAfterEvent(TimeSpan startedAt) - { - StartedAt = startedAt; - } - - public override DoAfterEvent Clone() => this; - } - - [Serializable, NetSerializable] - public sealed partial class GlimmerWispDrainDoAfterEvent : SimpleDoAfterEvent - { - } -} diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/AcceptPsionicsEuiMessage.cs b/Content.Shared/Psionics/Abilities/AcceptPsionicsEuiMessage.cs similarity index 100% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/AcceptPsionicsEuiMessage.cs rename to Content.Shared/Psionics/Abilities/AcceptPsionicsEuiMessage.cs diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs b/Content.Shared/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs similarity index 77% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs rename to Content.Shared/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs index ce86111fc4b..c3702880375 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs +++ b/Content.Shared/Psionics/Abilities/Dispel/DamageOnDispelComponent.cs @@ -1,6 +1,6 @@ using Content.Shared.Damage; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { /// /// Takes damage when dispelled. @@ -9,7 +9,7 @@ namespace Content.Shared.Abilities.Psionics public sealed partial class DamageOnDispelComponent : Component { [DataField("damage", required: true)] - public DamageSpecifier Damage = default!; + public DamageSpecifier Damage = default!; [DataField("variance")] public float Variance = 0.5f; diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DispelPowerComponent.cs b/Content.Shared/Psionics/Abilities/Dispel/DispelPowerComponent.cs similarity index 79% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DispelPowerComponent.cs rename to Content.Shared/Psionics/Abilities/Dispel/DispelPowerComponent.cs index cd887866364..518a28b0967 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DispelPowerComponent.cs +++ b/Content.Shared/Psionics/Abilities/Dispel/DispelPowerComponent.cs @@ -1,20 +1,22 @@ -using Content.Shared.Actions; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class DispelPowerComponent : Component { [DataField("range")] public float Range = 10f; - + [DataField("dispelActionId", customTypeSerializer: typeof(PrototypeIdSerializer))] public string? DispelActionId = "ActionDispel"; [DataField("dispelActionEntity")] public EntityUid? DispelActionEntity; + + [DataField("dispelFeedback")] + public string DispelFeedback = "dispel-feedback"; } } diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DispellableComponent.cs b/Content.Shared/Psionics/Abilities/Dispel/DispellableComponent.cs similarity index 69% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DispellableComponent.cs rename to Content.Shared/Psionics/Abilities/Dispel/DispellableComponent.cs index 40352004187..4bb5ee653d2 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Dispel/DispellableComponent.cs +++ b/Content.Shared/Psionics/Abilities/Dispel/DispellableComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class DispellableComponent : Component diff --git a/Content.Shared/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs b/Content.Shared/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs new file mode 100644 index 00000000000..2fbfe18327e --- /dev/null +++ b/Content.Shared/Psionics/Abilities/Metapsionics/MetapsionicPowerComponent.cs @@ -0,0 +1,38 @@ +using Content.Shared.DoAfter; +using Robust.Shared.Audio; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Psionics.Abilities +{ + [RegisterComponent] + public sealed partial class MetapsionicPowerComponent : Component + { + [DataField("doAfter")] + public DoAfterId? DoAfter; + + [DataField("useDelay")] + public float UseDelay = 8f; + [DataField("soundUse")] + + public SoundSpecifier SoundUse = new SoundPathSpecifier("/Audio/Nyanotrasen/heartbeat_fast.ogg"); + + [DataField("range")] + public float Range = 5f; + + [DataField("actionWideMetapsionic", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string ActionWideMetapsionic = "ActionWideMetapsionic"; + + [DataField("actionWideMetapsionicEntity")] + public EntityUid? ActionWideMetapsionicEntity; + + [DataField("actionFocusedMetapsionic", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string ActionFocusedMetapsionic = "ActionFocusedMetapsionic"; + + [DataField("actionFocusedMetapsionicEntity")] + public EntityUid? ActionFocusedMetapsionicEntity; + + [DataField("metapsionicFeedback")] + public string MetapsionicFeedback = "metapsionic-feedback"; + } +} diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs b/Content.Shared/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs similarity index 76% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs rename to Content.Shared/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs index 6a3fc811c89..94b73c41e38 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs +++ b/Content.Shared/Psionics/Abilities/MindSwap/MindSwapPowerComponent.cs @@ -1,7 +1,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class MindSwapPowerComponent : Component @@ -12,5 +12,8 @@ public sealed partial class MindSwapPowerComponent : Component [DataField("mindSwapActionEntity")] public EntityUid? MindSwapActionEntity; + + [DataField("mindSwapFeedback")] + public string MindSwapFeedback = "mind-swap-feedback"; } } diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs b/Content.Shared/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs similarity index 77% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs rename to Content.Shared/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs index 0e91894b1dc..997db65e1b1 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs +++ b/Content.Shared/Psionics/Abilities/NoosphericZap/NoosphericZapPowerComponent.cs @@ -2,7 +2,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class NoosphericZapPowerComponent : Component @@ -13,5 +13,8 @@ public sealed partial class NoosphericZapPowerComponent : Component [DataField("noosphericZapActionEntity")] public EntityUid? NoosphericZapActionEntity; + + [DataField("noosphericZapFeedback")] + public string NoosphericZapFeedback = "noospheric-zap-feedback"; } } diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs b/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs similarity index 71% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs rename to Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs index 3e198aa9303..d9c36f5b22a 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs +++ b/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerComponent.cs @@ -1,7 +1,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class PsionicInvisibilityPowerComponent : Component @@ -12,5 +12,11 @@ public sealed partial class PsionicInvisibilityPowerComponent : Component [DataField("psionicInvisibilityActionEntity")] public EntityUid? PsionicInvisibilityActionEntity; + + [DataField("InvisibilityFeedback")] + public string InvisibilityFeedback = "invisibility-feedback"; + + [DataField("UseTimer")] + public float UseTimer = 30f; } } diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs b/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs similarity index 94% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs rename to Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs index 9037b8bcdfe..2a9dd7642ba 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs +++ b/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs @@ -1,6 +1,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Abilities.Psionics + +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class PsionicInvisibilityUsedComponent : Component diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs b/Content.Shared/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs similarity index 76% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs rename to Content.Shared/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs index 4a62e84d191..3184bf7de5b 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs +++ b/Content.Shared/Psionics/Abilities/PsionicRegeneration/PsionicRegenerationPowerComponent.cs @@ -3,7 +3,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class PsionicRegenerationPowerComponent : Component @@ -12,7 +12,7 @@ public sealed partial class PsionicRegenerationPowerComponent : Component public DoAfterId? DoAfter; [DataField("essence")] - public float EssenceAmount = 20; + public float EssenceAmount = 10; [DataField("useDelay")] public float UseDelay = 8f; @@ -26,6 +26,12 @@ public sealed partial class PsionicRegenerationPowerComponent : Component [DataField("psionicRegenerationActionEntity")] public EntityUid? PsionicRegenerationActionEntity; + + [DataField("regenerationFeedback")] + public string RegenerationFeedback = "regeneration-feedback"; + + [DataField("selfRevive")] + public bool SelfRevive { get; set; } = false; } } diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs b/Content.Shared/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs similarity index 79% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs rename to Content.Shared/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs index 28425afdb4c..1f88741b9a9 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs +++ b/Content.Shared/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs @@ -2,7 +2,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class PyrokinesisPowerComponent : Component @@ -14,5 +14,8 @@ public sealed partial class PyrokinesisPowerComponent : Component [DataField("pyrokinesisActionEntity")] public EntityUid? PyrokinesisActionEntity; + + [DataField("pyrokinesisFeedback")] + public string PyrokinesisFeedback = "pyrokinesis-feedback"; } } diff --git a/Content.Shared/Psionics/Abilities/RegenerativeStasis/RegenerativeStasisPowerComponent.cs b/Content.Shared/Psionics/Abilities/RegenerativeStasis/RegenerativeStasisPowerComponent.cs new file mode 100644 index 00000000000..27a0903e224 --- /dev/null +++ b/Content.Shared/Psionics/Abilities/RegenerativeStasis/RegenerativeStasisPowerComponent.cs @@ -0,0 +1,20 @@ +using Content.Shared.Actions; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Psionics.Abilities +{ + [RegisterComponent] + public sealed partial class RegenerativeStasisPowerComponent : Component + { + [DataField("regenerativeStasisActionId", + customTypeSerializer: typeof(PrototypeIdSerializer))] + public string? RegenerativeStasisActionId = "ActionRegenerativeStasis"; + + [DataField("regenerativeStasisActionEntity")] + public EntityUid? RegenerativeStasisActionEntity; + + [DataField("regenerativeStasisFeedback")] + public string RegenerativeStasisFeedback = "regenerative-stasis-feedback"; + } +} diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs b/Content.Shared/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs similarity index 73% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs rename to Content.Shared/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs index 51958822a41..f1a71332b18 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs +++ b/Content.Shared/Psionics/Abilities/Telegnosis/TelegnosisPowerComponent.cs @@ -3,7 +3,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class TelegnosisPowerComponent : Component @@ -19,5 +19,11 @@ public sealed partial class TelegnosisPowerComponent : Component [DataField("telegnosisActionEntity")] public EntityUid? TelegnosisActionEntity; + + [DataField("telegnosisFeedback")] + public string TelegnosisFeedback = "telegnosis-feedback"; + public EntityUid OriginalEntity = default!; + public EntityUid ProjectionUid = default!; + public bool IsProjecting = false; } -} \ No newline at end of file +} diff --git a/Content.Shared/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs b/Content.Shared/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs new file mode 100644 index 00000000000..bc18ff9f3c2 --- /dev/null +++ b/Content.Shared/Psionics/Abilities/Telegnosis/TelegnosticProjectionComponent.cs @@ -0,0 +1,8 @@ +namespace Content.Shared.Psionics.Abilities +{ + [RegisterComponent] + public sealed partial class TelegnosticProjectionComponent : Component + { + public EntityUid OriginalEntity = default!; + } +} diff --git a/Content.Shared/Psionics/Events.cs b/Content.Shared/Psionics/Events.cs new file mode 100644 index 00000000000..45a00b5f048 --- /dev/null +++ b/Content.Shared/Psionics/Events.cs @@ -0,0 +1,64 @@ +using Robust.Shared.Serialization; +using Content.Shared.DoAfter; + +namespace Content.Shared.Psionics.Events +{ + [Serializable, NetSerializable] + public sealed partial class PsionicRegenerationDoAfterEvent : DoAfterEvent + { + [DataField("startedAt", required: true)] + public TimeSpan StartedAt; + + private PsionicRegenerationDoAfterEvent() + { + } + + public PsionicRegenerationDoAfterEvent(TimeSpan startedAt) + { + StartedAt = startedAt; + } + + public override DoAfterEvent Clone() => this; + } + + [Serializable, NetSerializable] + public sealed partial class PsionicInvisibilityTimerEvent : DoAfterEvent + { + [DataField("startedAt", required: true)] + public TimeSpan StartedAt; + + private PsionicInvisibilityTimerEvent() + { + } + + public PsionicInvisibilityTimerEvent(TimeSpan startedAt) + { + StartedAt = startedAt; + } + + public override DoAfterEvent Clone() => this; + } + + [Serializable, NetSerializable] + public sealed partial class FocusedMetapsionicDoAfterEvent : DoAfterEvent + { + [DataField("startedAt", required: true)] + public TimeSpan StartedAt; + + private FocusedMetapsionicDoAfterEvent() + { + } + + public FocusedMetapsionicDoAfterEvent(TimeSpan startedAt) + { + StartedAt = startedAt; + } + + public override DoAfterEvent Clone() => this; + } + + [Serializable, NetSerializable] + public sealed partial class GlimmerWispDrainDoAfterEvent : SimpleDoAfterEvent + { + } +} diff --git a/Content.Shared/Nyanotrasen/Psionics/Glimmer/GlimmerSystem.cs b/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs similarity index 98% rename from Content.Shared/Nyanotrasen/Psionics/Glimmer/GlimmerSystem.cs rename to Content.Shared/Psionics/Glimmer/GlimmerSystem.cs index 31af85bbb51..8be02f936a9 100644 --- a/Content.Shared/Nyanotrasen/Psionics/Glimmer/GlimmerSystem.cs +++ b/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs @@ -40,7 +40,7 @@ public GlimmerTier GetGlimmerTier(int? glimmer = null) if (glimmer == null) glimmer = Glimmer; - return (glimmer) switch + return glimmer switch { <= 49 => GlimmerTier.Minimal, >= 50 and <= 99 => GlimmerTier.Low, diff --git a/Content.Shared/Nyanotrasen/Psionics/Glimmer/SharedGlimmerReactiveComponent.cs b/Content.Shared/Psionics/Glimmer/SharedGlimmerReactiveComponent.cs similarity index 100% rename from Content.Shared/Nyanotrasen/Psionics/Glimmer/SharedGlimmerReactiveComponent.cs rename to Content.Shared/Psionics/Glimmer/SharedGlimmerReactiveComponent.cs diff --git a/Content.Shared/Nyanotrasen/Psionics/Glimmer/SharedGlimmerReactiveVisuals.cs b/Content.Shared/Psionics/Glimmer/SharedGlimmerReactiveVisuals.cs similarity index 100% rename from Content.Shared/Nyanotrasen/Psionics/Glimmer/SharedGlimmerReactiveVisuals.cs rename to Content.Shared/Psionics/Glimmer/SharedGlimmerReactiveVisuals.cs diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/ClothingGrantPsionicPowerComponent.cs b/Content.Shared/Psionics/Items/ClothingGrantPsionicPowerComponent.cs similarity index 84% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Items/ClothingGrantPsionicPowerComponent.cs rename to Content.Shared/Psionics/Items/ClothingGrantPsionicPowerComponent.cs index 4cbb05c8395..f09efc3064c 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/ClothingGrantPsionicPowerComponent.cs +++ b/Content.Shared/Psionics/Items/ClothingGrantPsionicPowerComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class ClothingGrantPsionicPowerComponent : Component diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/HeadCageComponent.cs b/Content.Shared/Psionics/Items/HeadCageComponent.cs similarity index 96% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Items/HeadCageComponent.cs rename to Content.Shared/Psionics/Items/HeadCageComponent.cs index acaa832860f..c03241e47c7 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/HeadCageComponent.cs +++ b/Content.Shared/Psionics/Items/HeadCageComponent.cs @@ -1,7 +1,7 @@ using System.Threading; using Robust.Shared.Audio; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class HeadCageComponent : Component diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/HeadCagedComponent.cs b/Content.Shared/Psionics/Items/HeadCagedComponent.cs similarity index 81% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Items/HeadCagedComponent.cs rename to Content.Shared/Psionics/Items/HeadCagedComponent.cs index f8af46b8878..0f826f7a05e 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/HeadCagedComponent.cs +++ b/Content.Shared/Psionics/Items/HeadCagedComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] /// diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/PsionicItemsSystem.cs b/Content.Shared/Psionics/Items/PsionicItemsSystem.cs similarity index 98% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Items/PsionicItemsSystem.cs rename to Content.Shared/Psionics/Items/PsionicItemsSystem.cs index f88acf61f3c..950353c5dfb 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/PsionicItemsSystem.cs +++ b/Content.Shared/Psionics/Items/PsionicItemsSystem.cs @@ -2,7 +2,7 @@ using Content.Shared.Clothing.Components; using Content.Shared.StatusEffect; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { public sealed class PsionicItemsSystem : EntitySystem { diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/TinfoilHatComponent.cs b/Content.Shared/Psionics/Items/TinfoilHatComponent.cs similarity index 90% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/Items/TinfoilHatComponent.cs rename to Content.Shared/Psionics/Items/TinfoilHatComponent.cs index 5086b9f4977..6ef7bdc823b 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/Items/TinfoilHatComponent.cs +++ b/Content.Shared/Psionics/Items/TinfoilHatComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class TinfoilHatComponent : Component diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicComponent.cs b/Content.Shared/Psionics/PsionicComponent.cs similarity index 51% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicComponent.cs rename to Content.Shared/Psionics/PsionicComponent.cs index 9091e03cfc3..9a06e54cb31 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicComponent.cs +++ b/Content.Shared/Psionics/PsionicComponent.cs @@ -1,7 +1,6 @@ -using Content.Shared.Actions; using Robust.Shared.GameStates; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent, NetworkedComponent] public sealed partial class PsionicComponent : Component @@ -15,6 +14,17 @@ public sealed partial class PsionicComponent : Component public bool Removable = true; [DataField("activePowers")] - public HashSet ActivePowers = new(); + public List ActivePowers = new(); + + [DataField("psychicFeedback")] + public List PsychicFeedback = new(); + + [DataField("amplification")] + public float Amplification = 0.1f; + + [DataField("dampening")] + public float Dampening = 0.1f; + public bool Telepath = false; + public bool InnatePsiChecked = false; } } diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicInsulationComponent.cs b/Content.Shared/Psionics/PsionicInsulationComponent.cs similarity index 82% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicInsulationComponent.cs rename to Content.Shared/Psionics/PsionicInsulationComponent.cs index 12370da5ae4..2ab054b1f8f 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicInsulationComponent.cs +++ b/Content.Shared/Psionics/PsionicInsulationComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { [RegisterComponent] public sealed partial class PsionicInsulationComponent : Component diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicsDisabledComponent.cs b/Content.Shared/Psionics/PsionicsDisabledComponent.cs similarity index 84% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicsDisabledComponent.cs rename to Content.Shared/Psionics/PsionicsDisabledComponent.cs index 28e7157a9d2..00cf5506523 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/PsionicsDisabledComponent.cs +++ b/Content.Shared/Psionics/PsionicsDisabledComponent.cs @@ -1,6 +1,6 @@ using Robust.Shared.GameStates; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { /// /// Only use this for the status effect, please. diff --git a/Content.Shared/Nyanotrasen/Abilities/Psionics/SharedPsionicAbilitiesSystem.cs b/Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs similarity index 97% rename from Content.Shared/Nyanotrasen/Abilities/Psionics/SharedPsionicAbilitiesSystem.cs rename to Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs index 2739d5ba31a..603c5188a52 100644 --- a/Content.Shared/Nyanotrasen/Abilities/Psionics/SharedPsionicAbilitiesSystem.cs +++ b/Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs @@ -7,7 +7,7 @@ using Robust.Shared.Random; using Robust.Shared.Serialization; -namespace Content.Shared.Abilities.Psionics +namespace Content.Shared.Psionics.Abilities { public sealed class SharedPsionicAbilitiesSystem : EntitySystem { @@ -73,7 +73,7 @@ public void SetPsionicsThroughEligibility(EntityUid uid) if (actionData == null) return; - _actions.SetEnabled(actionData.Owner, IsEligibleForPsionics(uid)); + _actions.SetEnabled(uid, IsEligibleForPsionics(uid)); } private bool IsEligibleForPsionics(EntityUid uid) diff --git a/Content.Shared/Psionics/SharedPsionicSystem.Insulated.cs b/Content.Shared/Psionics/SharedPsionicSystem.Insulated.cs new file mode 100644 index 00000000000..5c89f39354c --- /dev/null +++ b/Content.Shared/Psionics/SharedPsionicSystem.Insulated.cs @@ -0,0 +1,4 @@ +namespace Content.Shared.Psionics +{ + public readonly record struct PsionicInsulationEvent; +} diff --git a/Content.Shared/Throwing/ThrowingSystem.cs b/Content.Shared/Throwing/ThrowingSystem.cs index 54294318315..01682863389 100644 --- a/Content.Shared/Throwing/ThrowingSystem.cs +++ b/Content.Shared/Throwing/ThrowingSystem.cs @@ -160,7 +160,7 @@ public void TryThrow(EntityUid uid, } else { - _physics.SetBodyStatus(physics, BodyStatus.InAir); + _physics.SetBodyStatus(uid, physics, BodyStatus.InAir); } if (user == null) @@ -176,10 +176,10 @@ public void TryThrow(EntityUid uid, { var msg = new ThrowPushbackAttemptEvent(); RaiseLocalEvent(uid, msg); - const float MassLimit = 5f; + const float massLimit = 5f; if (!msg.Cancelled) - _physics.ApplyLinearImpulse(user.Value, -impulseVector / physics.Mass * pushbackRatio * MathF.Min(MassLimit, physics.Mass), body: userPhysics); + _physics.ApplyLinearImpulse(user.Value, -impulseVector / physics.Mass * pushbackRatio * MathF.Min(massLimit, physics.Mass), body: userPhysics); } } } diff --git a/Content.Shared/Throwing/ThrownItemSystem.cs b/Content.Shared/Throwing/ThrownItemSystem.cs index b3b5bcf7870..cc50094e3dd 100644 --- a/Content.Shared/Throwing/ThrownItemSystem.cs +++ b/Content.Shared/Throwing/ThrownItemSystem.cs @@ -93,7 +93,7 @@ public void StopThrow(EntityUid uid, ThrownItemComponent thrownItemComponent) { if (TryComp(uid, out var physics)) { - _physics.SetBodyStatus(physics, BodyStatus.OnGround); + _physics.SetBodyStatus(uid, physics, BodyStatus.OnGround); if (physics.Awake) _broadphase.RegenerateContacts(uid, physics); diff --git a/Content.Shared/Weapons/Melee/MeleeThrowOnHitSystem.cs b/Content.Shared/Weapons/Melee/MeleeThrowOnHitSystem.cs index e840bd1ddd5..e0696022606 100644 --- a/Content.Shared/Weapons/Melee/MeleeThrowOnHitSystem.cs +++ b/Content.Shared/Weapons/Melee/MeleeThrowOnHitSystem.cs @@ -74,7 +74,7 @@ private void OnThrownStartup(Entity ent, ref ComponentStar comp.PreviousStatus = body.BodyStatus; comp.ThrownEndTime = _timing.CurTime + TimeSpan.FromSeconds(comp.Lifetime); comp.MinLifetimeTime = _timing.CurTime + TimeSpan.FromSeconds(comp.MinLifetime); - _physics.SetBodyStatus(body, BodyStatus.InAir); + _physics.SetBodyStatus(ent, body, BodyStatus.InAir); _physics.SetLinearVelocity(ent, Vector2.Zero, body: body); _physics.ApplyLinearImpulse(ent, comp.Velocity * body.Mass, body: body); Dirty(ent, ent.Comp); @@ -83,7 +83,7 @@ private void OnThrownStartup(Entity ent, ref ComponentStar private void OnThrownShutdown(Entity ent, ref ComponentShutdown args) { if (TryComp(ent, out var body)) - _physics.SetBodyStatus(body,ent.Comp.PreviousStatus); + _physics.SetBodyStatus(ent, body, ent.Comp.PreviousStatus); var ev = new MeleeThrowOnHitEndEvent(); RaiseLocalEvent(ent, ref ev); } diff --git a/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs b/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs index 177cb310d18..3a950bcd29e 100644 --- a/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs +++ b/Content.Shared/Weapons/Misc/SharedTetherGunSystem.cs @@ -207,12 +207,12 @@ protected virtual void StartTether(EntityUid gunUid, BaseForceGunComponent compo TransformSystem.Unanchor(target, targetXform); component.Tethered = target; var tethered = EnsureComp(target); - _physics.SetBodyStatus(targetPhysics, BodyStatus.InAir, false); + _physics.SetBodyStatus(target, targetPhysics, BodyStatus.InAir, false); _physics.SetSleepingAllowed(target, targetPhysics, false); tethered.Tetherer = gunUid; tethered.OriginalAngularDamping = targetPhysics.AngularDamping; - _physics.SetAngularDamping(targetPhysics, 0f); - _physics.SetLinearDamping(targetPhysics, 0f); + _physics.SetAngularDamping(target, targetPhysics, 0f); + _physics.SetLinearDamping(target, targetPhysics, 0f); _physics.SetAngularVelocity(target, SpinVelocity, body: targetPhysics); _physics.WakeBody(target, body: targetPhysics); var thrown = EnsureComp(component.Tethered.Value); @@ -264,9 +264,9 @@ protected virtual void StopTether(EntityUid gunUid, BaseForceGunComponent compon _thrown.StopThrow(component.Tethered.Value, thrown); } - _physics.SetBodyStatus(targetPhysics, BodyStatus.OnGround); + _physics.SetBodyStatus(component.Tethered.Value, targetPhysics, BodyStatus.OnGround); _physics.SetSleepingAllowed(component.Tethered.Value, targetPhysics, true); - _physics.SetAngularDamping(targetPhysics, Comp(component.Tethered.Value).OriginalAngularDamping); + _physics.SetAngularDamping(component.Tethered.Value, targetPhysics, Comp(component.Tethered.Value).OriginalAngularDamping); } if (!transfer) diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs index 36b5bbd1927..d3aee5a48e9 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs @@ -388,7 +388,7 @@ public abstract void Shoot( public void ShootProjectile(EntityUid uid, Vector2 direction, Vector2 gunVelocity, EntityUid gunUid, EntityUid? user = null, float speed = 20f) { var physics = EnsureComp(uid); - Physics.SetBodyStatus(physics, BodyStatus.InAir); + Physics.SetBodyStatus(uid, physics, BodyStatus.InAir); var targetMapVelocity = gunVelocity + direction.Normalized() * speed; var currentMapVelocity = Physics.GetMapLinearVelocity(uid, physics); diff --git a/Resources/Audio/Nyanotrasen/heartbeat_fast.ogg b/Resources/Audio/Nyanotrasen/heartbeat_fast.ogg new file mode 100644 index 0000000000000000000000000000000000000000..85a034d9bd0017dafea7df4128235c815babac0c GIT binary patch literal 39983 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 literal 0 HcmV?d00001 diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 954f86aa044..ba49523cfde 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -4080,3 +4080,17 @@ Entries: you join when someone leaves. id: 6110 time: '2024-05-13T04:58:39.0000000+00:00' +- author: LovelyLophi + changes: + - type: Add + message: Added a number of new corporate coats to the Clothesmate. + id: 6111 + time: '2024-05-22T03:35:11.0000000+00:00' +- author: VMSolidus + changes: + - type: Tweak + message: >- + Syndicate Listening Posts can now appear any time in a round, and can + appear on low-pop servers. + id: 6112 + time: '2024-05-28T23:44:39.0000000+00:00' diff --git a/Resources/Credits/GitHub.txt b/Resources/Credits/GitHub.txt index 3aea674fd94..db58663a2b2 100644 --- a/Resources/Credits/GitHub.txt +++ b/Resources/Credits/GitHub.txt @@ -1 +1 @@ -0x6273, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 4dplanner, 612git, 778b, Ablankmann, Acruid, actioninja, adamsong, Admiral-Obvious-001, Adrian16199, Aerocrux, Aexxie, africalimedrop, Agoichi, Ahion, AJCM-git, AjexRose, Alekshhh, AlexMorgan3817, AlmondFlour, AlphaQwerty, Altoids1, amylizzle, ancientpower, ArchPigeon, Arendian, arimah, Arteben, AruMoon, as334, AsikKEsel, asperger-sind, aspiringLich, avghdev, AzzyIsNotHere, BananaFlambe, BasedUser, BGare, BingoJohnson-zz, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, Boaz1111, BobdaBiscuit, brainfood1183, Brandon-Huu, Bribrooo, Bright0, brndd, BubblegumBlue, BYONDFuckery, c4llv07e, CakeQ, CaptainSqrBeard, Carbonhell, Carolyn3114, casperr04, CatTheSystem, Centronias, chairbender, Charlese2, Cheackraze, cheesePizza2, Chief-Engineer, chromiumboy, Chronophylos, clement-or, Clyybber, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, coolmankid12345, corentt, crazybrain23, creadth, CrigCrag, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, Daemon, daerSeebaer, dahnte, dakamakat, dakimasu, DamianX, DangerRevolution, daniel-cr, Darkenson, DawBla, dch-GH, Deahaka, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, deepdarkdepths, Delete69, deltanedas, DeltaV-Bot, DerbyX, DoctorBeard, DogZeroX, dontbetank, Doru991, DoubleRiceEddiedd, DrMelon, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, Dutch-VanDerLinde, Easypoller, eclips_e, EdenTheLiznerd, EEASAS, Efruit, ElectroSR, elthundercloud, Emisse, EmoGarbage404, Endecc, enumerate0, eoineoineoin, ERORR404V1, Errant-4, estacaoespacialpirata, exincore, exp111, Fahasor, FairlySadPanda, ficcialfaint, Fildrance, FillerVK, Fishfish458, Flareguy, FluffiestFloof, FluidRock, FoLoKe, fooberticus, Fortune117, freeman2651, Fromoriss, FungiFellow, GalacticChimp, gbasood, Geekyhobo, Genkail, Git-Nivrak, github-actions[bot], gituhabu, GNF54, Golinth, GoodWheatley, Gotimanga, graevy, GreyMario, Guess-My-Name, gusxyz, h3half, Hanzdegloker, Hardly3D, harikattar, Hebiman, Henry12116, HerCoyote23, Hmeister-real, HoofedEar, hord-brayden, hubismal, Hugal31, Hyenh, iacore, IamVelcroboy, icekot8, igorsaux, ike709, Illiux, Ilya246, IlyaElDunaev, Injazz, Insineer, IntegerTempest, Interrobang01, IProduceWidgets, ItsMeThom, j-giebel, Jackal298, Jackrost, jamessimo, janekvap, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JoeHammad1844, joelhed, JohnGinnane, johnku1, joshepvodka, jproads, Jrpl, juliangiebel, JustArt1m, JustCone14, JustinTether, JustinTrotter, KaiShibaa, kalane15, kalanosh, KEEYNy, Keikiru, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, KingFroozy, kira-er, Kit0vras, KittenColony, Kmc2000, Ko4ergaPunk, komunre, koteq, Krunklehorn, Kukutis96513, kxvvv, Lamrr, LankLTE, lapatison, Leander-0, leonardo-dabepis, LetterN, Level10Cybermancer, lever1209, LightVillet, liltenhead, LittleBuilderJane, Lomcastar, LordCarve, LordEclipse, LudwigVonChesterfield, Lukasz825700516, lunarcomets, luringens, lvvova1, lzimann, lzk228, M3739, MACMAN2003, Macoron, MagnusCrowe, ManelNavola, matthst, Matz05, MehimoNemo, MeltedPixel, MemeProof, Menshin, Mervill, metalgearsloth, mhamsterr, MilenVolf, Minty642, Mirino97, mirrorcult, MishaUnity, MisterMecky, Mith-randalf, Moneyl, Moomoobeef, moony, Morb0, Mr0maks, musicmanvr, Myakot, Myctai, N3X15, Nairodian, Naive817, namespace-Memory, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, nmajask, nok-ko, Nopey, notafet, notquitehadouken, noudoit, noverd, nuke-haus, NULL882, OCOtheOmega, OctoRocket, OldDanceJacket, onoira, Owai-Seek, pali6, Pangogie, patrikturi, PaulRitter, Peptide90, peptron1, Phantom-Lily, PHCodes, PixelTheKermit, PJB3005, Plykiya, pofitlo, pointer-to-null, PolterTzi, PoorMansDreams, potato1234x, ProfanedBane, PrPleGoo, ps3moira, Psychpsyo, psykzz, PuroSlavKing, quatre, QuietlyWhisper, qwerltaz, Radosvik, Radrark, Rainbeon, Rainfey, Rane, ravage123321, rbertoche, Redict, RedlineTriad, RednoWCirabrab, RemberBM, RemieRichards, RemTim, rene-descartes2021, RiceMar1244, RieBi, Rinkashikachi, Rockdtben, rolfero, rosieposieeee, Saakra, Samsterious, SaphireLattice, ScalyChimp, scrato, Scribbles0, Serkket, SethLafuente, ShadowCommander, Shadowtheprotogen546, SignalWalker, SimpleStation14, Simyon264, SirDragooon, Sirionaut, siyengar04, Skarletto, Skrauz, Skyedra, SlamBamActionman, Slava0135, Snowni, snowsignal, SonicHDC, SoulSloth, SpaceManiac, SpeltIncorrectyl, spoogemonster, ssdaniel24, Stealthbomber16, stellar-novas, StrawberryMoses, Subversionary, SweptWasTaken, Szunti, TadJohnson00, takemysoult, TaralGit, Tayrtahn, tday93, TekuNut, TemporalOroboros, tentekal, tgrkzus, thatrandomcanadianguy, TheArturZh, theashtronaut, thedraccx, themias, Theomund, theOperand, TheShuEd, TimrodDX, Titian3, tkdrg, tmtmtl30, tom-leys, tomasalves8, Tomeno, tosatur, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, Tyler-IN, Tyzemol, UbaserB, UKNOWH, UnicornOnLSD, Uriende, UristMcDorf, Vaaankas, Varen, VasilisThePikachu, veliebm, Veritius, Verslebas, VigersRay, Visne, VMSolidus, volundr-, Voomra, Vordenburg, vulppine, waylon531, weaversam8, Willhelm53, wixoaGit, WlarusFromDaSpace, wrexbe, xRiriq, yathxyz, Ygg01, YotaXP, YuriyKiss, zach-hill, Zandario, Zap527, ZelteHonor, zerorulez, zionnBE, zlodo, ZNixian, ZoldorfTheWizard, Zumorica, Zymem +0x6273, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 4dplanner, 612git, 778b, Ablankmann, Acruid, actioninja, adamsong, Admiral-Obvious-001, Adrian16199, Aerocrux, Aexxie, africalimedrop, Agoichi, Ahion, AJCM-git, AjexRose, Alekshhh, AlexMorgan3817, AlmondFlour, AlphaQwerty, Altoids1, amylizzle, ancientpower, ArchPigeon, Arendian, arimah, Arteben, AruMoon, as334, AsikKEsel, asperger-sind, aspiringLich, avghdev, AzzyIsNotHere, BananaFlambe, BasedUser, BGare, BingoJohnson-zz, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, Boaz1111, BobdaBiscuit, brainfood1183, Brandon-Huu, Bribrooo, Bright0, brndd, BubblegumBlue, BYONDFuckery, c4llv07e, CakeQ, CaptainSqrBeard, Carbonhell, Carolyn3114, casperr04, CatTheSystem, Centronias, chairbender, Charlese2, Cheackraze, cheesePizza2, Chief-Engineer, chromiumboy, Chronophylos, clement-or, Clyybber, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, coolmankid12345, corentt, crazybrain23, creadth, CrigCrag, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, Daemon, daerSeebaer, dahnte, dakamakat, dakimasu, DamianX, DangerRevolution, daniel-cr, Darkenson, DawBla, dch-GH, Deahaka, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, deepdarkdepths, Delete69, deltanedas, DeltaV-Bot, DerbyX, DoctorBeard, DogZeroX, dontbetank, Doru991, DoubleRiceEddiedd, DrMelon, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, Dutch-VanDerLinde, Easypoller, eclips_e, EdenTheLiznerd, EEASAS, Efruit, ElectroSR, elthundercloud, Emisse, EmoGarbage404, Endecc, enumerate0, eoineoineoin, ERORR404V1, Errant-4, estacaoespacialpirata, exincore, exp111, Fahasor, FairlySadPanda, ficcialfaint, Fildrance, FillerVK, Fishfish458, Flareguy, FluffiestFloof, FluidRock, FoLoKe, fooberticus, Fortune117, freeman2651, Fromoriss, FungiFellow, GalacticChimp, gbasood, Geekyhobo, Genkail, Git-Nivrak, github-actions[bot], gituhabu, GNF54, Golinth, GoodWheatley, Gotimanga, graevy, GreyMario, Guess-My-Name, gusxyz, h3half, Hanzdegloker, Hardly3D, harikattar, Hebiman, Henry12116, HerCoyote23, Hmeister-real, HoofedEar, hord-brayden, hubismal, Hugal31, Hyenh, iacore, IamVelcroboy, icekot8, igorsaux, ike709, Illiux, Ilya246, IlyaElDunaev, Injazz, Insineer, IntegerTempest, Interrobang01, IProduceWidgets, ItsMeThom, j-giebel, Jackal298, Jackrost, jamessimo, janekvap, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JoeHammad1844, joelhed, JohnGinnane, johnku1, joshepvodka, jproads, Jrpl, juliangiebel, JustArt1m, JustCone14, JustinTether, JustinTrotter, KaiShibaa, kalane15, kalanosh, KEEYNy, Keikiru, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, KingFroozy, kira-er, Kit0vras, KittenColony, Kmc2000, Ko4ergaPunk, komunre, koteq, Krunklehorn, Kukutis96513, kxvvv, Lamrr, LankLTE, lapatison, Leander-0, leonardo-dabepis, LetterN, Level10Cybermancer, lever1209, LightVillet, liltenhead, LittleBuilderJane, Lomcastar, LordCarve, LordEclipse, LovelyLophi, LudwigVonChesterfield, Lukasz825700516, lunarcomets, luringens, lvvova1, lzimann, lzk228, M3739, MACMAN2003, Macoron, MagnusCrowe, ManelNavola, matthst, Matz05, MehimoNemo, MeltedPixel, MemeProof, Menshin, Mervill, metalgearsloth, mhamsterr, MilenVolf, Minty642, Mirino97, mirrorcult, MishaUnity, MisterMecky, Mith-randalf, Moneyl, Moomoobeef, moony, Morb0, Mr0maks, musicmanvr, Myakot, Myctai, N3X15, Nairodian, Naive817, namespace-Memory, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, nmajask, nok-ko, Nopey, notafet, notquitehadouken, noudoit, noverd, nuke-haus, NULL882, OCOtheOmega, OctoRocket, OldDanceJacket, onoira, Owai-Seek, pali6, Pangogie, patrikturi, PaulRitter, Peptide90, peptron1, Phantom-Lily, PHCodes, PixelTheKermit, PJB3005, Plykiya, pofitlo, pointer-to-null, PolterTzi, PoorMansDreams, potato1234x, ProfanedBane, PrPleGoo, ps3moira, Psychpsyo, psykzz, PuroSlavKing, quatre, QuietlyWhisper, qwerltaz, Radosvik, Radrark, Rainbeon, Rainfey, Rane, ravage123321, rbertoche, Redict, RedlineTriad, RednoWCirabrab, RemberBM, RemieRichards, RemTim, rene-descartes2021, RiceMar1244, RieBi, Rinkashikachi, Rockdtben, rolfero, rosieposieeee, Saakra, Samsterious, SaphireLattice, ScalyChimp, scrato, Scribbles0, Serkket, SethLafuente, ShadowCommander, Shadowtheprotogen546, SignalWalker, SimpleStation14, Simyon264, SirDragooon, Sirionaut, siyengar04, Skarletto, Skrauz, Skyedra, SlamBamActionman, Slava0135, Snowni, snowsignal, SonicHDC, SoulSloth, SpaceManiac, SpeltIncorrectyl, spoogemonster, ssdaniel24, Stealthbomber16, stellar-novas, StrawberryMoses, Subversionary, SweptWasTaken, Szunti, TadJohnson00, takemysoult, TaralGit, Tayrtahn, tday93, TekuNut, TemporalOroboros, tentekal, tgrkzus, thatrandomcanadianguy, TheArturZh, theashtronaut, thedraccx, themias, theomund, theOperand, TheShuEd, TimrodDX, Titian3, tkdrg, tmtmtl30, tom-leys, tomasalves8, Tomeno, tosatur, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, Tyler-IN, Tyzemol, UbaserB, UKNOWH, UnicornOnLSD, Uriende, UristMcDorf, Vaaankas, Varen, VasilisThePikachu, veliebm, Veritius, Verslebas, VigersRay, Visne, VMSolidus, volundr-, Voomra, Vordenburg, vulppine, waylon531, weaversam8, Willhelm53, wixoaGit, WlarusFromDaSpace, wrexbe, xRiriq, yathxyz, Ygg01, YotaXP, YuriyKiss, zach-hill, Zandario, Zap527, ZelteHonor, zerorulez, zionnBE, zlodo, ZNixian, ZoldorfTheWizard, Zumorica, Zymem diff --git a/Resources/Locale/en-US/atmos/commands.ftl b/Resources/Locale/en-US/atmos/commands.ftl new file mode 100644 index 00000000000..692908d42ad --- /dev/null +++ b/Resources/Locale/en-US/atmos/commands.ftl @@ -0,0 +1,8 @@ +cmd-set-map-atmos-desc = Sets a map's atmosphere +cmd-set-map-atmos-help = setmapatmos [ [moles...]] +cmd-set-map-atmos-removed = Atmosphere removed from map {$map} +cmd-set-map-atmos-updated = Atmosphere set for map {$map} +cmd-set-map-atmos-hint-map = +cmd-set-map-atmos-hint-space = +cmd-set-map-atmos-hint-temp = (float) +cmd-set-map-atmos-hint-gas = <{$gas} moles> (float) diff --git a/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl b/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl index 91ae21233a3..5b368e822f1 100644 --- a/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl +++ b/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl @@ -3,8 +3,11 @@ cage-resist-third-person = {CAPITALIZE(THE($user))} starts removing {POSS-ADJ($u cage-uncage-verb = Uncage -action-name-metapsionic = Metapsionic Pulse -action-description-metapsionic = Send a mental pulse through the area to see if there are any psychics nearby. +action-name-widemetapsionic = Wide Metapsionic Pulse +action-description-widemetapsionic = Send a mental pulse through the area to see if there are any psychics nearby. + +action-name-focusedmetapsionic = Focused Metapsionic Pulse +action-description-focusedmetapsionic = Probe an entity at close range to glean metaphorical information about any powers they may have metapsionic-pulse-success = You detect psychic presence nearby. metapsionic-pulse-failure = You don't detect any psychic presence nearby. @@ -13,8 +16,8 @@ metapsionic-pulse-power = You detect that {$power} was used nearby. action-name-dispel = Dispel action-description-dispel = Dispel summoned entities such as familiars or forcewalls. -action-name-mass-sleep = Mass Sleep -action-description-mass-sleep = Put targets in a small area to sleep. +action-name-regenerative-stasis = Regenerative Stasis +action-description-regenerative-stasis = Puts the target into a brief stasis, during which time their wounds rapidly heal. accept-psionics-window-title = Psionic! accept-psionics-window-prompt-text-part = You rolled a psionic power! @@ -63,11 +66,14 @@ action-name-noospheric-zap = Noospheric Zap action-description-noospheric-zap = Shocks the conciousness of the target and leaves them stunned and stuttering. action-name-pyrokinesis = Pyrokinesis -action-description-pyrokinesis = Light a flammable target on fire. -pyrokinesis-power-used = A wisp of flame engulfs {THE($target)}, igniting {OBJECT($target)}! +action-description-pyrokinesis = Hurl a small gateway to the plane of Gehenna at your target. action-name-psychokinesis = Psychokinesis action-description-psychokinesis = Bend the fabric of space to instantly move across it. action-name-rf-sensitivity = Toggle RF Sensitivity action-desc-rf-sensitivity = Toggle your ability to interpret radio waves on and off. + +trait-latent-psychic-desc = Your mind and soul are open to the noosphere, allowing for a limited use of Telepathy. + Thus, you are eligible for potentially receiving psychic powers. + It is possible that you may be hunted by otherworldly forces, so consider keeping your powers a secret. diff --git a/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl b/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl new file mode 100644 index 00000000000..26d2acb87cd --- /dev/null +++ b/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl @@ -0,0 +1,21 @@ +# Feedback messages for Focused Metapsionic Pulse +metapulse-self = I AM. +no-powers = {CAPITALIZE($entity)} will never awaken from the dream in this life +psychic-potential = {CAPITALIZE($entity)} has a slim chance of awakening from the dream +dispel-feedback = {CAPITALIZE($entity)} is a mighty stone, standing against the currents of fate +metapsionic-feedback = {CAPITALIZE($entity)} gazes back upon thee +mind-swap-feedback = {CAPITALIZE($entity)}'s vessel seems fit for other souls +mindswapped-feedback = Cursed flesh! {CAPITALIZE($entity)} dwells within the wrong vessel! +noospheric-zap-feedback = {CAPITALIZE($entity)}'s soul writhes with thunder from beyond the veil +pyrokinesis-feedback = The Secret of Fire dwells within {CAPITALIZE($entity)} +invisibility-feedback = {CAPITALIZE($entity)}'s wyrd seeks to hide from thine gaze +telegnosis-feedback = {CAPITALIZE($entity)}'s soul travels across bridges composed of dreamlight +sophic-grammateus-feedback = SEEKER, YOU NEED ONLY ASK FOR MY WISDOM. +oracle-feedback = WHY DO YOU BOTHER ME SEEKER? HAVE I NOT MADE MY DESIRES CLEAR? +metempsychotic-machine-feedback = The sea of fate flows through this machine +ifrit-feedback = A spirit of Gehenna, bound by the will of a powerful psychic + +# Power PVS Messages +focused-metapsionic-pulse-begin = The air around {CAPITALIZE($entity)} begins to shimmer faintly +psionic-regeneration-self-revive = {CAPITALIZE($entity)} begins to visibly regenerate +mindbreaking-feedback = The light of life vanishes from {CAPITALIZE($entity)}'s eyes, leaving behind a husk pretending at sapience diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml b/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml index 2165fb4e585..d0ae444bf77 100644 --- a/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml +++ b/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml @@ -33,7 +33,7 @@ sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base product: CrateVendingMachineRestockClothesFilled - cost: 7245 + cost: 8050 category: cargoproduct-category-name-service group: market diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml index 1dbc412a9c8..04cc2e3e19d 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml @@ -85,6 +85,11 @@ ClothingOuterCoatLettermanRed: 2 # Nyano - Clothing addition ClothingOuterDenimJacket: 2 # DeltaV - Clothing addition ClothingOuterCorporateJacket: 2 # DeltaV - Clothing addition + ClothingOuterCsCorporateJacket: 2 # Einstein Engines - Clothing addition + ClothingOuterEECorporateJacket: 2 # Einstein Engines - Clothing addition + ClothingOuterHICorporateJacket: 2 # Einstein Engines - Clothing addition + ClothingOuterHMCorporateJacket: 2 # Einstein Engines - Clothing addition + ClothingOuterIdCorporateJacket: 2 # Einstein Engines - Clothing addition ClothingShoesBootsFishing: 2 # Nyano - Clothing addition ClothingHeadTinfoil: 2 # Nyano - Clothing addition ClothingHeadFishCap: 2 diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml index 771da36719f..4f255cad211 100644 --- a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml +++ b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml @@ -84,7 +84,10 @@ - type: PotentialPsionic - type: Psionic removable: false - # - type: PyrokinesisPower # Pending psionic rework + amplification: 4 + psychicFeedback: + - "ifrit-feedback" + - type: PyrokinesisPower - type: Grammar attributes: proper: true @@ -103,7 +106,7 @@ requirements: - !type:DepartmentTimeRequirement department: Epistemics - time: 14400 # DeltaV - 4 hours + time: 14400 - type: entity parent: WelderExperimental diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/Player/harpy.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/Player/harpy.yml index 1f4eb696c65..e2541def035 100644 --- a/Resources/Prototypes/DeltaV/Entities/Mobs/Player/harpy.yml +++ b/Resources/Prototypes/DeltaV/Entities/Mobs/Player/harpy.yml @@ -26,4 +26,3 @@ - type: NpcFactionMember factions: - NanoTrasen - - type: PotentialPsionic diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/Player/vulpkanin.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/Player/vulpkanin.yml index 06abe8c45fa..ea2357a5c06 100644 --- a/Resources/Prototypes/DeltaV/Entities/Mobs/Player/vulpkanin.yml +++ b/Resources/Prototypes/DeltaV/Entities/Mobs/Player/vulpkanin.yml @@ -24,7 +24,6 @@ - type: NpcFactionMember factions: - NanoTrasen - - type: PotentialPsionic - type: Respirator damage: types: diff --git a/Resources/Prototypes/DeltaV/GameRules/events.yml b/Resources/Prototypes/DeltaV/GameRules/events.yml index 73b0ca6549c..9391756492b 100644 --- a/Resources/Prototypes/DeltaV/GameRules/events.yml +++ b/Resources/Prototypes/DeltaV/GameRules/events.yml @@ -52,9 +52,8 @@ noSpawn: true components: - type: StationEvent - earliestStart: 15 - weight: 5 - minimumPlayers: 25 + weight: 7.5 + minimumPlayers: 10 maxOccurrences: 1 duration: 1 - type: PirateRadioSpawnRule diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml index 4f0a0d0aafa..d45e8c3f3c2 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml @@ -541,3 +541,58 @@ Quantity: 20 - type: ToggleableClothing clothingPrototype: ClothingHeadHatHoodWinterWeb + +- type: entity + parent: ClothingOuterWinterCoat + id: ClothingOuterCsCorporateJacket + name: Cybersun Corporate Jacket + description: A cozy jacket with the Cybersun logo printed on the back. Merchandise rewarded to stations with a safety factor of uhh... seven. + components: + - type: Sprite + sprite: Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi + - type: Clothing + sprite: Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi + +- type: entity + parent: ClothingOuterWinterCoat + id: ClothingOuterEECorporateJacket + name: Einstein Engines Corporate Jacket + description: A cozy jacket with the Einstein Engines logo printed on the back. Merchandise rewarded to stations with a safety factor of uhh... seven. + components: + - type: Sprite + sprite: Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi + - type: Clothing + sprite: Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi + +- type: entity + parent: ClothingOuterWinterCoat + id: ClothingOuterHICorporateJacket + name: Hephaestus Industries Corporate Jacket + description: A cozy jacket with the Hephaestus Industries logo printed on the back. Merchandise rewarded to stations with a safety factor of uhh... seven. + components: + - type: Sprite + sprite: Clothing/OuterClothing/WinterCoats/hi_corpo_jacket.rsi + - type: Clothing + sprite: Clothing/OuterClothing/WinterCoats/hi_corpo_jacket.rsi + +- type: entity + parent: ClothingOuterWinterCoat + id: ClothingOuterHMCorporateJacket + name: Hawkmoon Acquisitions Corporate Jacket + description: A cozy jacket with the Hawkmoon Acquisitions logo printed on the back. Merchandise rewarded to stations with a safety factor of uhh... seven. + components: + - type: Sprite + sprite: Clothing/OuterClothing/WinterCoats/hm_corpo_jacket.rsi + - type: Clothing + sprite: Clothing/OuterClothing/WinterCoats/hm_corpo_jacket.rsi + +- type: entity + parent: ClothingOuterWinterCoat + id: ClothingOuterIdCorporateJacket + name: Interdyne Corporate Jacket + description: A cozy jacket with the Interdyne logo printed on the back. Merchandise rewarded to stations with a safety factor of uhh... seven. + components: + - type: Sprite + sprite: Clothing/OuterClothing/WinterCoats/id_corpo_jacket.rsi + - type: Clothing + sprite: Clothing/OuterClothing/WinterCoats/id_corpo_jacket.rsi diff --git a/Resources/Prototypes/Entities/Mobs/Player/arachnid.yml b/Resources/Prototypes/Entities/Mobs/Player/arachnid.yml index 5ebd43ddf48..d9dea3c18d9 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/arachnid.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/arachnid.yml @@ -11,4 +11,3 @@ damageRecovery: types: Asphyxiation: -0.5 - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. diff --git a/Resources/Prototypes/Entities/Mobs/Player/diona.yml b/Resources/Prototypes/Entities/Mobs/Player/diona.yml index 28687c68bfc..dfd5e9a1be7 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/diona.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/diona.yml @@ -11,7 +11,6 @@ damageRecovery: types: Asphyxiation: -1.0 - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. # Reformed Diona - type: entity diff --git a/Resources/Prototypes/Entities/Mobs/Player/dwarf.yml b/Resources/Prototypes/Entities/Mobs/Player/dwarf.yml index fb84ad3650f..d1de65df012 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/dwarf.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/dwarf.yml @@ -3,5 +3,3 @@ name: Urist McHands The Dwarf parent: BaseMobDwarf id: MobDwarf - components: - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Mobs/Player/human.yml b/Resources/Prototypes/Entities/Mobs/Player/human.yml index 6197c82c021..9a7c2ee65ec 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/human.yml @@ -3,8 +3,6 @@ name: Urist McHands parent: BaseMobHuman id: MobHuman - components: - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. #Syndie - type: entity diff --git a/Resources/Prototypes/Entities/Mobs/Player/moth.yml b/Resources/Prototypes/Entities/Mobs/Player/moth.yml index ffdb36d86bd..72feba958ab 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/moth.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/moth.yml @@ -3,5 +3,3 @@ name: Urist McFluff parent: BaseMobMoth id: MobMoth - components: - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml b/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml index 71d74222979..b9f265e0bcf 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml @@ -3,7 +3,5 @@ name: Urisst' Mzhand parent: BaseMobReptilian id: MobReptilian - components: - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. #Weh diff --git a/Resources/Prototypes/Entities/Mobs/Player/slime.yml b/Resources/Prototypes/Entities/Mobs/Player/slime.yml index 79669a8fe2a..4e5974b3084 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/slime.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/slime.yml @@ -2,5 +2,3 @@ save: false parent: BaseMobSlimePerson id: MobSlimePerson - components: - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Mobs/Species/human.yml b/Resources/Prototypes/Entities/Mobs/Species/human.yml index 7bf96efe2cc..900de77712e 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/human.yml @@ -16,7 +16,6 @@ spawned: - id: FoodMeatHuman amount: 5 - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. - type: entity parent: BaseSpeciesDummy diff --git a/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/leaves.yml b/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/leaves.yml index e87fec22acc..b847416211d 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/leaves.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/leaves.yml @@ -17,8 +17,7 @@ reagents: - ReagentId: THC Quantity: 15 - - type: StealTarget - stealGroup: Cannabis + - type: entity name: dried cannabis leaves @@ -38,8 +37,6 @@ - type: Sprite sprite: Objects/Specific/Hydroponics/tobacco.rsi state: dried - - type: StealTarget - stealGroup: Cannabis - type: entity name: ground cannabis @@ -68,8 +65,7 @@ - Smokable - type: Item size: Tiny - - type: StealTarget - stealGroup: Cannabis + - type: entity name: tobacco leaves diff --git a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml index 8d195a25bea..e14f29746dc 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml @@ -177,7 +177,7 @@ - Screwdriver - Wirecutter - Multitool - - Welder + - WelderIndustrial # cargo modules - type: entity diff --git a/Resources/Prototypes/Nyanotrasen/Actions/types.yml b/Resources/Prototypes/Nyanotrasen/Actions/types.yml index e6e4bdc5a75..55dd48e5470 100644 --- a/Resources/Prototypes/Nyanotrasen/Actions/types.yml +++ b/Resources/Prototypes/Nyanotrasen/Actions/types.yml @@ -36,18 +36,18 @@ event: !type:DispelPowerActionEvent - type: entity - id: ActionMassSleep - name: action-name-mass-sleep - description: action-description-mass-sleep + id: ActionRegenerativeStasis + name: action-name-regenerative-stasis + description: action-description-regenerative-stasis noSpawn: true components: - - type: WorldTargetAction + - type: EntityTargetAction icon: Nyanotrasen/Interface/VerbIcons/mass_sleep.png useDelay: 60 checkCanAccess: false range: 8 itemIconStyle: BigAction - event: !type:MassSleepPowerActionEvent + event: !type:RegenerativeStasisPowerActionEvent - type: entity id: ActionMindSwap @@ -94,7 +94,7 @@ description: action-description-pyrokinesis noSpawn: true components: - - type: EntityTargetAction + - type: WorldTargetAction icon: Nyanotrasen/Interface/VerbIcons/pyrokinesis.png useDelay: 50 range: 6 @@ -103,15 +103,29 @@ event: !type:PyrokinesisPowerActionEvent - type: entity - id: ActionMetapsionic - name: action-name-metapsionic - description: action-description-metapsionic + id: ActionWideMetapsionic + name: action-name-widemetapsionic + description: action-description-widemetapsionic noSpawn: true components: - type: InstantAction icon: Nyanotrasen/Interface/VerbIcons/metapsionic.png useDelay: 45 - event: !type:MetapsionicPowerActionEvent + event: !type:WideMetapsionicPowerActionEvent + +- type: entity + id: ActionFocusedMetapsionic + name: action-name-focusedmetapsionic + description: action-description-focusedmetapsionic + noSpawn: true + components: + - type: EntityTargetAction + icon: Nyanotrasen/Interface/VerbIcons/metapsionic.png + useDelay: 45 + range: 3 + checkCanAccess: false + itemIconStyle: BigAction + event: !type:FocusedMetapsionicPowerActionEvent - type: entity id: ActionPsionicRegeneration diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/Oni.yml b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/Oni.yml index 562b9c564ec..1166d8a29f5 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/Oni.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/Oni.yml @@ -32,4 +32,3 @@ - type: NpcFactionMember factions: - NanoTrasen - - type: PotentialPsionic diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/felinid.yml b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/felinid.yml index db7936cc5b4..94ac8403adc 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/felinid.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Player/felinid.yml @@ -49,5 +49,3 @@ - type: NpcFactionMember factions: - NanoTrasen - - type: PotentialPsionic - diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/metempsychoticMachine.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/metempsychoticMachine.yml index d8e791af1ed..d773cf87c76 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/metempsychoticMachine.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/metempsychoticMachine.yml @@ -22,4 +22,7 @@ NoMind: { state: pod_1 } Gore: { state: pod_1 } Idle: { state: pod_0 } + - type: PotentialPsionic - type: Psionic + psychicFeedback: + - "metempsychotic-machine-feedback" diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/oracle.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/oracle.yml index f7481abf1ed..58189e49cec 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/oracle.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/oracle.yml @@ -16,7 +16,10 @@ - type: Oracle - type: Speech speechSounds: Tenor + - type: PotentialPsionic - type: Psionic + psychicFeedback: + - "oracle-feedback" - type: SolutionContainerManager solutions: fountain: diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml index ae85cd25e03..8e34a07ea5e 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml @@ -29,6 +29,8 @@ - Science - type: PotentialPsionic #this makes her easier to access for glimmer events, dw about it - type: Psionic + psychicFeedback: + - "sophic-grammateus-feedback" - type: Grammar attributes: gender: female diff --git a/Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml b/Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml index 53910a54a92..e6e497003d5 100644 --- a/Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml +++ b/Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml @@ -9,29 +9,6 @@ stealGroup: AntiPsychicKnife owner: job-name-mantis -- type: entity - id: BecomePsionicObjective - parent: BaseTraitorObjective - name: Become psionic - description: We need you to acquire psionics and keep them until your mission is complete. - noSpawn: true - components: - - type: NotJobsRequirement - jobs: - - Mime - - ForensicMantis - - type: Objective - difficulty: 2.5 - #unique: false - icon: - sprite: Nyanotrasen/Icons/psi.rsi - state: psi - - type: ObjectiveBlacklistRequirement - blacklist: - components: - - BecomeGolemCondition - - type: BecomePsionicCondition - #- type: entity # id: BecomeGolemObjective # parent: BaseTraitorObjective diff --git a/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml b/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml index c3e682e02a9..15b2cdd4fa7 100644 --- a/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml +++ b/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml @@ -7,22 +7,24 @@ - !type:OverallPlaytimeRequirement time: 18000 - !type:DepartmentTimeRequirement - department: Epistemics # DeltaV - Epistemics Department replacing Science + department: Epistemics time: 3600 startingGear: ForensicMantisGear icon: "JobIconForensicMantis" supervisors: job-supervisors-rd - antagAdvantage: 5 # DeltaV - From 4 to 5 - canBeAntag: true # DeltaV - Mantis is no longer a Detective - # whitelistRequired: true + antagAdvantage: 5 + canBeAntag: true access: - Research - Maintenance - - Mantis # DeltaV - Psionic Mantis, see Resources/Prototypes/DeltaV/Access/epistemics.yml + - Mantis special: - !type:AddComponentSpecial components: + - type: PotentialPsionic - type: Psionic + amplification: 0.3 + dampening: 0.3 - type: MetapsionicPower - type: startingGear @@ -34,11 +36,10 @@ head: ClothingHeadHatFezMantis id: ForensicMantisPDA eyes: ClothingEyesGlassesSunglasses - ears: ClothingHeadsetScience # DeltaV - Mantis is part of Epistemics + ears: ClothingHeadsetScience gloves: ClothingHandsGlovesColorWhite outerClothing: ClothingOuterCoatMantis belt: ClothingBeltMantis - # pocket2: ForensicScanner # DeltaV - Mantis is no longer a Detective innerClothingSkirt: ClothingUniformSkirtMantis satchel: ClothingBackpackSatchelMantisFilled duffelbag: ClothingBackpackDuffelMantisFilled diff --git a/Resources/Prototypes/Nyanotrasen/Traits/psionics.yml b/Resources/Prototypes/Nyanotrasen/Traits/psionics.yml new file mode 100644 index 00000000000..5fef3427703 --- /dev/null +++ b/Resources/Prototypes/Nyanotrasen/Traits/psionics.yml @@ -0,0 +1,6 @@ +- type: trait + id: LatentPsychic + name: Latent Psychic + description: trait-latent-psychic-desc + components: + - type: PotentialPsionic diff --git a/Resources/Prototypes/Nyanotrasen/psionicPowers.yml b/Resources/Prototypes/Nyanotrasen/psionicPowers.yml index f40b688fd18..ca1764e204c 100644 --- a/Resources/Prototypes/Nyanotrasen/psionicPowers.yml +++ b/Resources/Prototypes/Nyanotrasen/psionicPowers.yml @@ -5,6 +5,8 @@ DispelPower: 1 TelegnosisPower: 1 PsionicRegenerationPower: 1 - MassSleepPower: 0.3 -# PsionicInvisibilityPower: 0.15 + RegenerativeStasisPower: 0.3 + PsionicInvisibilityPower: 0.15 MindSwapPower: 0.15 + NoosphericZapPower: 0.15 + PyrokinesisPower: 0.15 diff --git a/Resources/Prototypes/Objectives/objectiveGroups.yml b/Resources/Prototypes/Objectives/objectiveGroups.yml index fba2c4cc172..d711e9a1b13 100644 --- a/Resources/Prototypes/Objectives/objectiveGroups.yml +++ b/Resources/Prototypes/Objectives/objectiveGroups.yml @@ -39,7 +39,6 @@ EscapeShuttleObjective: 1 # DieObjective: 0.05 # DeltaV - Disable the lrp objective aka murderbone justification #HijackShuttleObjective: 0.02 - BecomePsionicObjective: 1 # Nyanotrasen - Become Psionic objective, see Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml #BecomeGolemObjective: 0.5 # Nyanotrasen - Become a golem objective, see Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml - type: weightedRandom diff --git a/Resources/Prototypes/Objectives/stealTargetGroups.yml b/Resources/Prototypes/Objectives/stealTargetGroups.yml index fb1e5e76fc0..006c061666b 100644 --- a/Resources/Prototypes/Objectives/stealTargetGroups.yml +++ b/Resources/Prototypes/Objectives/stealTargetGroups.yml @@ -142,12 +142,7 @@ sprite: Objects/Misc/id_cards.rsi state: default -- type: stealTargetGroup - id: Cannabis - name: cannabis - sprite: - sprite: Objects/Specific/Hydroponics/cannabis.rsi - state: produce + - type: stealTargetGroup id: LAMP diff --git a/Resources/Prototypes/Objectives/thief.yml b/Resources/Prototypes/Objectives/thief.yml index 66258870d61..18154850973 100644 --- a/Resources/Prototypes/Objectives/thief.yml +++ b/Resources/Prototypes/Objectives/thief.yml @@ -142,20 +142,7 @@ - type: Objective difficulty: 0.7 -- type: entity - noSpawn: true - parent: BaseThiefStealCollectionObjective - id: CannabisStealCollectionObjective - components: - - type: NotJobRequirement - job: Botanist - - type: StealCondition - stealGroup: Cannabis - minCollectionSize: 20 - maxCollectionSize: 30 - verifyMapExistence: false - - type: Objective - difficulty: 0.5 + - type: entity noSpawn: true diff --git a/Resources/Prototypes/Roles/Jobs/Science/research_director.yml b/Resources/Prototypes/Roles/Jobs/Science/research_director.yml index 19cf1419111..ddb779669eb 100644 --- a/Resources/Prototypes/Roles/Jobs/Science/research_director.yml +++ b/Resources/Prototypes/Roles/Jobs/Science/research_director.yml @@ -3,13 +3,13 @@ name: job-name-rd description: job-description-rd playTimeTracker: JobResearchDirector - antagAdvantage: 6 # DeltaV - Reduced TC: Head of Staff + antagAdvantage: 6 requirements: - !type:DepartmentTimeRequirement - department: Epistemics # DeltaV - Epistemics Department replacing Science - time: 54000 # DeltaV - 15 hours + department: Epistemics + time: 54000 - !type:OverallPlaytimeRequirement - time: 72000 # DeltaV - 20 hours + time: 72000 weight: 10 startingGear: ResearchDirectorGear icon: "JobIconResearchDirector" @@ -21,20 +21,20 @@ - Command - Maintenance - ResearchDirector - - Mantis # DeltaV - Psionic Mantis, see Resources/Prototypes/DeltaV/Access/epistemics.yml - - Chapel # DeltaV - Chaplain is in Epistemics + - Mantis + - Chapel - Cryogenics - special: # Nyanotrasen - Mystagogue can use the Bible + special: - !type:AddComponentSpecial components: - - type: BibleUser # Nyano - Lets them heal with bibles - - type: Psionic # Nyano - They start with telepathic chat - - type: DispelPower # Nyano - They get the Dispel psionic power on spawn + - type: BibleUser + - type: PotentialPsionic + - type: Psionic + dampening: 1 #Mystagogue gets a significant buff to his antimage abilities, making him better at dispelling than other people + - type: DispelPower + - type: CommandStaff - !type:AddImplantSpecial implants: [ MindShieldImplant ] - - !type:AddComponentSpecial - components: - - type: CommandStaff - type: startingGear id: ResearchDirectorGear @@ -44,7 +44,7 @@ shoes: ClothingShoesColorBrown id: RnDPDA ears: ClothingHeadsetRD - belt: BibleMystagogue # Nyanotrasen - Mystagogue book for their Ifrit + belt: BibleMystagogue innerClothingSkirt: ClothingUniformJumpskirtResearchDirector satchel: ClothingBackpackSatchelResearchDirectorFilled duffelbag: ClothingBackpackDuffelResearchDirectorFilled diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi/equipped-OUTERCLOTHING.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi/equipped-OUTERCLOTHING.png new file mode 100644 index 0000000000000000000000000000000000000000..73e230e8a5f2088cbea061e045059ab6e5c52140 GIT binary patch literal 8610 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi/icon.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f78a89945c3732976cfac3674fea17d416a0bbe7 GIT binary patch literal 5930 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 Y6YmP{KCGw>f(VDXJ9|4FUK=U<7ye`^m;e9( literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi/meta.json new file mode 100644 index 00000000000..42d21c3d8ab --- /dev/null +++ b/Resources/Textures/Clothing/OuterClothing/WinterCoats/cs_corpo_jacket.rsi/meta.json @@ -0,0 +1,18 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "leonardo_dabepis on discord / @leonardo-dabepis on Tumblr, Edited by heartparkyheart on Discord", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi/equipped-OUTERCLOTHING.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi/equipped-OUTERCLOTHING.png new file mode 100644 index 0000000000000000000000000000000000000000..983c2534f4ceffdb575394b6b2077e250a9a07e1 GIT binary patch literal 8514 zcmeHMc{G&m`=63M#u7;iW63sVFoqfXzGVr?7RJnAFf*93CsC0~qU?LJl%)t+LYA^i zB3meX)aZud(ZEC&hNbE{J#IaGtcwP^IXg4zOK)8-S?S$Cc?x>hlzok0RR9n z>FH{kQa)ApPdXaP^)b$K6aZkh3NW`Mo1%RAJiLfbICm@`+1~@phxNlb0RVnOi-}fV zg4Ik~dzB0jenhA(GcB}1;mg;cmmM*^uHH6_8{c>=^kUB=?jG^*^i)Ia^s7AIqE!*y z8aIuzwiZ3E@+g}V$vfx0SGv0NggpAjI6!h`Cwz5jQT?O&B-iqjp7bsInVn(4M&_z$ zFxRYXC9jHI-ka+tDokr8Ir7Yiw#9+MC^?ny6VDpQl!H7fwmvnS z2@hXOiAvu#AH74I8EIxz4qhCXr~!&I?BK`0G~N`fdGh^C^V0c^;uGQlVt&Pn+BFi0 zbRN0!xnpn8*WL)FyNX6DjJ#a)-Zz zuJ-VsFhKrF2{@YSDK|Iyw?Lp%^pV7TODpUcnjbDZ z(5ndQN)Oav-tgbNp*v~$fF+qzpxuP167)O zG1)hCV})y8C%G17>lc>wjjG@JVn@i<%P%Y&O?)QfHS@{t;!Fpfz#Z6E5e@BA_%-@V zPD%c8qR+bETMXiod8k;S{G#%z0BZdtnAoVM!1HL)cXB69BRK2*%S$5{JO3f~x z>u!X#e00gyB-k~D!=H`2LjGivqjr<}S4~^G5Zdl~N1yZQrcYa}I*K@3Zt_@S$_FHf ztOB8WHH`j&X)n+lrz=(NB#TeQdol*IA)GU}7^4GkC7bz=uWR+j^_BaBe4I0_(z@>R;*&|#MDUo z_qxN1o@pov5iX;&9vhvsF<)3hA`k}4%$90ejbDu-$hOFr=FFA0xW!AXtJ*?i-EU6^ zeyxbjo$o0&omX4O#BSxWDoipH-b`0=|ttQRp%-X}M$&q6I-rj1HFcP1hXunj9LuPg5 z`?(Ts?M|gHrMKC*j#LM9HX9V|-4a-d5Rk4VXaK30)cbNmsS|FUO>2BIn88R8ZVZ3_ zHU#L0${u>bAP<_Bq5z+_BU?)VvVu$$d-KdPZ%;AH^pl zH-Il%>UZgmxaC12if$(Hms+h4alMY&z8P9A9A?LItky=6svmYYUtYB%o>Q*iArHsW zmy25+x-95Y8Y}-r&jk-${fJ(hw3#AL+g$GEkszUqq9FI%iPD~=*0UF1y2c2XfGkm3 zH!1)Gg}5+9sRmV=y?E33LQsnD^+}5pB0177{HoUgEj290VR|WKDbIRd{UU3^a>}~H z$C?~0HOo;&jioD0@2u?Zv5&swwzEsUzt)YP6I3hc!9O+uzZE|!DIVL>=)21fgwlli z@-dQp!|~JE_wyPR`++)fR3$zqn(s?pI2qa=5punYU9ke>XzS5QptUY}q3EO?IE&2# zf8^pOY6L-=H_9NPl`STK!7TZk*PqkM>3&P9KTbW(FZ>`0Z4=_yr|nph;4F6fd9=vN zT$NHSuiz}#9ZkW(L+4YXWBs2dN1n7~FCO`Ff&L{Glfgr-TifkbMnQ{L>{~;MS}!Pgqkc!V5wjBENDiRw$v!+1ZhP=|~tkokq1p1szp4z`~< z>GM{39P~};!dc%j@>s-a+i2m!?iD?j72Y1OML>0EqWzz(tm~WXrDaU$bqAagF|VkW zdJVtO_=1yv#-A>PztRRCogS@{*#)VMG3J<_x0;>0p~GU@Iw8KW60P`kefIP-N!sCM zi6A+7M1e++j@OQ+n*50ohxwQG7PYDsohe&us`XQ`B0eR?k{2MxhI%<(l9v>Z^sKu! zl$9!it%nz~I=X3y1-42A9KnR`X@jwn#>EPo}KXv<)#9dRTUL1Pf=V?ED+sed4 zIU_e&Y(kTH^}5bet^0wu`M}pyFGiN!`>Y(p!~CJI&su~y=_u=!tvq?E-zeWy*5Z0e zPikQ9ZLDm$V5>yE?mWh;!@9dBHCEo0#=@rI>)TxLQ~g2qKAI7b#gp@0RQ#OvT9a^d zg3I8Ivl2M~L)y8@vHJ{gCsV9y4z1feS8ATjOkOrM+wt7?womyIs#WO68v@vV2?y8< z>bcc8XU4tg8V{NXHk8VQ&%4~dhi``#bDR)8dD@Dq>|}3eiTAZp)w~YjGe`YseU^Zp z8z+4F8U2<{`PUE3xb==CY=I{~L?Rqj@71oK8ybe|GrO7AGCw}U?u`&ncsZ$id*@Dh zOUe>6Qb;A~smdH}*aO?+VqK58dRHTE*TIW2U*Dm+7M@nmA=m+KWHnvuC>P&)-McH4 z17C7OrO48*ie{TNM~ZAPKdK8AdGJ0C_Q6cdeeMz0H#*^*9cy^8W|FkIIE?e`YnX6O zH1{2CAhr1quwvskQmSp$6YS7SkXPz?`>-55)nOZ&Bko0WMX6T$nV(MfmQy#O3`~;nD8NzjpcV&D%OWrh$hahfE*iZ?FI0%#mTh zo%bn>8N?n+|8nk59PgWov}{Z3E1w#Tgy&i>A#n0kackNYL`TSK)@fgR#XiM63bDI=$rr@ zw-|#<#28Upk-a`#PP?JyA!NqqPzR)tUSE00Wdhxa79EGjx%apHfis+u!x}7(Jxp!F z=R)6VtMgr;i(rF0(Z$aUbE&d;w(Z;r5YyH#>jfjqP%S5ZFye zMA}TUziP#5Hn(^B{Vr*F*BiL3EVmNhsxv2n!}a_SEh-?c2&`$W z(^G-E;~Wm@MRuu7Y`=j(J?0L8}pMj_!&^eLZXbL83D;^R10U=u?!+pb&M==6&M;`cd& zklvfVBgx#ak|yL%gs0W`hUTR+`8<#9VV+{ouQ~hLry%^~{<;2MMb)jTobg0PUe z1qQg;B-2o>C^A!dfN@BS$*pUcqV6~cI*ouuthL7m9sDQ7Ph^;RT@8SJb}mRS=33n2iiB~ zcVI48Zs}T^SEVKNhlVh8<%~T9h|ny1LZrfZVf2iPdJp$ zC2O>KTK28G_?pJJu&iNs=Dc6tYo5U)-xo$kQj(m?wF?uH)}JR`_8FZE8Y+E`4^Mxl z6Xa`<=<2f3ox*?8!kM)xTWi?-0Xwbdgpr^@R#c}!$M#^{bV;!FY-~CJJi`iFt1VCF z`8Ig}QstME9flxI>fpDm8RQsl^_II*OmE^9^dIhp+Xfqddr-46`zl*W@)$SQm6f5v z@sldVmACa*1ct%Ycka<%{7TED5#;lI^CP3>kmPpwy^c3}n1scvw-${an~Uf@%kI;v zCMbkW#V7Mh(cwMI_9m2CZR_G3mlTE;6q@V$RfW})w&aR=lErSCc@zTxhX^}NYo6nJ9W0|E!)28rI3*b-A#$#yR|MYZ=ybo{X-U>syVLf0pmPr<-(BMV z^?^<6P2hl-jlQU9Olr-ONODbcUSd;a>eg;Rm;Y#&Kl3KqKkMUrCiQwTuCXkaja_f|)Uw>BdCh5)n%%LD85ir03Ytyz27$1}W7nInp~baqR>C}z zqYWSo%ZwWeUaFrMv*$T3o2L|h$#*<+f|s^#?h)3_@(D^{=Ge8ZYXa9VwQeG!s`TX1 zoq`X2+7=pwx&+U`$odk|xh+@B4Wze*j)H`Aga z##U3i3da3BryrAnI+?rmt9Ai=71Zg;X&as&{nNu)D#B&*=j`KBw8u2Z3S6U=T&%9% zTYa2EZ2XKQe;CA_*#T2yei*W+MP(wW3omrb+qcd+r)Jsc7PYZoZ0M3)Yuk;x4(X^_rX!N_m+ldk!T`b5``f;VkQ0X9+d4r0HCPi=Yc}IVaa@sSZ5qT3A9{Y z2jatFlt33`4WWh}8dw*cZh#loEWpSd9pHvWU_dI$42ph83IHBUM)CRK-3cV5pAzT* z7fHF_7ehdN2PR}UC6J||37-bh3(E(Sgh@idT7EbmX^=7lpQ0DW32CaS{R@Kfqy%yy zlRc0Sh_A1&q_2!5(aRYkg+L%6P-%#?G?-!mCixS{C_gZPB(M+h6GIbALVMvn$T%W_ zZyyuoNc1Kvfj|^J-yiYeJq!*1geQ=Gu|VMi;)n8pNJ&B=cs%5H4-#3+hXV2|p#SJW zGN=4X0x`vsh~8dktd{U99-8iIAl;wh#i%BWI*8&XHl(Bw~# zeF~g$c#i`w3fX_NB;%a^BI|Fl?Q0Iw`8^Pd`=7Xfv;HIZ17nJnp&?R}i1ywOPft?` zv_C!)Lqy{+$b(x)M;WLS0xbhZpwVzJOb#Xkc0@SJgE2DlFenTGmy(xu`VC5tKq8|E zXzV@|1zZwG!9k<3STsh)2@I2wrd(hc6xh)T>I9a?KoL?-7^o9QPUbfVV=o+~D^c#h zN3{=yp+I5bQZi7e92N|h!D7KMX&4lYkcCNuQBqKhjGUAVC05h{6b6mdCVJsflyc(m zC}%9hgW!Ci*e4vRW}>GAl9q)2B{6YFk)0?GlsSMSV2Hk?zf|TpJl2ei+UHYBP6{R~ zjgXd-laYqPp|HPJQo{?2A``vL zi9~lL(0)*S`<{QQ4Ji`}gCe6eQDiIy6e5(-Dk%7H15(BJHd7@U*; z|7E>DefSiA7F`!dqKxlDt1}GdM>x9K%z>ZL?JQ#+OM}y_zSQr=qbA&=sFexdFH2m-A zB%%}97v+UjbEfb};fm6r2VC)q{3?~`-|c-}u={nOP)6Yh{2OH;$ggA}`zyvD*(yT* z7axiT2EQ#a6u+M`%F;zy2_b(jg}?aPUv&P9uU~ceFOEQg{&$dn#P7d!{Y%$BV&ESc z|Jz;v()EuR_(#V7cGv$KT?~J1rmzIcHy~fiR_XjDt}Mzni^kDFM-#BO|IVn%y+@JI zd+1t`002pW{qvAtwu%o$NK4i;)S{iGK6ID{aaNPB3IL!Y=xM5%Q~rZZsyBXT!qZ$g z%z(GF4W+B+FdMi1fDLK7mLEd(Nqs!xWcaBU2ri1JqcKsIfH33QgxeP3St& zV8UQyuk39beGlR~I(Qcs2;Y5-jPP0s)?tYx~|C6)0L7lPJ@X z7f+j$X>lySudrwg_EN~d05h$=$XZbQIb>qllGjY(#^n#U{PGil$k3M-ql#mm7vp1} z&l@z)i+mNZyt$Fp5~Yf?0~RblqHU=fAD9|w3l3gAO0-w@1dlNpZ44_sQhU#_klL#l z3xv~59=|OL=;pY=L9J_k=u;f}ZFN){mChJnnwW?n;c!r+>gD>EL-`*k>JdMl2gVc< z7oQGNJvMRMU7N70@kW&FZJ~&~`lH3?d3ka0&&%Qm6{Hk#|9C4@J33m0zq&PY4|of@y%}(3cD?IO z8pPvVEO6o!M#80cUY2R$a*fTj?)}*3UWa>u7CqPOfwc?EezjH+NIL1kLL=*Pcv%#LBUL=~{r{yclnN zKc9S`+y^9uYd}WT%u&sV*r+S7??5ey$KO&FF{A}vp){B}sqQpjE;LNb`ZQ!Bg6zL?8g*igflH;a{&|hUO**7*estXK@S`w-D_@W&rnn$r6vRuY-9OfMT-tJV7awXX`A!G;QfcY#hO5@$rfOhTz3lbg)iZFO*S%1iFi=z< z;83Gg!glN(qEXa1K4|yB*|=JX({!PHl%wcKFd+P1eg<7LjMQT C=v7$& literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi/icon.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ba72253098481f5f357ad1a0fd752a9c1b23a2d5 GIT binary patch literal 6063 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 NoE=>4&)9BC_#YSooM`|6 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi/meta.json new file mode 100644 index 00000000000..42d21c3d8ab --- /dev/null +++ b/Resources/Textures/Clothing/OuterClothing/WinterCoats/ee_corpo_jacket.rsi/meta.json @@ -0,0 +1,18 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "leonardo_dabepis on discord / @leonardo-dabepis on Tumblr, Edited by heartparkyheart on Discord", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/hi_corpo_jacket.rsi/equipped-OUTERCLOTHING.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/hi_corpo_jacket.rsi/equipped-OUTERCLOTHING.png new file mode 100644 index 0000000000000000000000000000000000000000..f18a64ab9c0c4012305f51ab70dc2710c1131824 GIT binary patch literal 8310 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 B7?S`1 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/hm_corpo_jacket.rsi/icon.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/hm_corpo_jacket.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d80b56558a23c7c523173d543ae370b835f48ac8 GIT binary patch literal 6169 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 G68{IREn~+3 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/id_corpo_jacket.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/id_corpo_jacket.rsi/meta.json new file mode 100644 index 00000000000..42d21c3d8ab --- /dev/null +++ b/Resources/Textures/Clothing/OuterClothing/WinterCoats/id_corpo_jacket.rsi/meta.json @@ -0,0 +1,18 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "leonardo_dabepis on discord / @leonardo-dabepis on Tumblr, Edited by heartparkyheart on Discord", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + } + ] +} diff --git a/Resources/keybinds.yml b/Resources/keybinds.yml index b8cfc40c1c4..346156159a7 100644 --- a/Resources/keybinds.yml +++ b/Resources/keybinds.yml @@ -167,6 +167,7 @@ binds: type: State key: MouseLeft canFocus: true + priority: 10 - function: RotateStoredItem type: State key: MouseRight diff --git a/global.json b/global.json index 391ba3c2a30..2244195a209 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { "version": "8.0.100", - "rollForward": "latestFeature" + "rollForward": "disable" } } From c4db83104568f47794f79ea9e9a0896e092a7442 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 28 May 2024 22:10:05 -0400 Subject: [PATCH 33/82] Update PsionicRegenerationPowerSystem.cs --- .../Abilities/PsionicRegenerationPowerSystem.cs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs b/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs index 882eb9e0b14..893d1bc4cfa 100644 --- a/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs @@ -73,13 +73,7 @@ private void OnPowerUsed(EntityUid uid, PsionicRegenerationPowerComponent compon component.DoAfter = doAfterId; - _popupSystem.PopupEntity(Loc.GetString("psionic-regeneration-begin", ("entity", uid)), - uid, - // TODO: Use LoS-based Filter when one is available. - Filter.Pvs(uid).RemoveWhereAttachedEntity(entity => !ExamineSystemShared.InRangeUnOccluded(uid, entity, ExamineRange, null)), - true, - PopupType.Medium); - + _popupSystem.PopupEntity(Loc.GetString("psionic-regeneration-begin", ("entity", uid)), uid, PopupType.Medium); _audioSystem.PlayPvs(component.SoundUse, uid, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); _psionics.LogPowerUsed(uid, "psionic regeneration", @@ -122,12 +116,7 @@ private void OnMobStateChangedEvent(EntityUid uid, PsionicRegenerationPowerCompo BreakOnDamage = false, RequireCanInteract = false, }); - _popupSystem.PopupEntity(Loc.GetString("psionic-regeneration-self-revive", ("entity", uid)), - uid, - // TODO: Use LoS-based Filter when one is available. - Filter.Pvs(uid).RemoveWhereAttachedEntity(entity => !ExamineSystemShared.InRangeUnOccluded(uid, entity, ExamineRange, null)), - true, - PopupType.MediumCaution); + _popupSystem.PopupEntity(Loc.GetString("psionic-regeneration-self-revive", ("entity", uid)), uid, PopupType.MediumCaution); _audioSystem.PlayPvs(component.SoundUse, uid, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); _psionics.LogPowerUsed(uid, "psionic regeneration", From cefe228d3e4401e9811aa35c64ebf46e01fd70c9 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 28 May 2024 22:13:59 -0400 Subject: [PATCH 34/82] fun pvs fixes --- .../Psionics/Abilities/MetapsionicPowerSystem.cs | 7 +------ .../Psionics/Abilities/PsionicAbilitiesSystem.cs | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs b/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs index 7b3a417c53f..78842c6443d 100644 --- a/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs @@ -129,12 +129,7 @@ private void OnFocusedPowerUsed(FocusedMetapsionicPowerActionEvent args) component.DoAfter = doAfterId; - _popups.PopupEntity(Loc.GetString("focused-metapsionic-pulse-begin", ("entity", args.Target)), - args.Performer, - // TODO: Use LoS-based Filter when one is available. - Filter.Pvs(args.Performer).RemoveWhereAttachedEntity(entity => !ExamineSystemShared.InRangeUnOccluded(args.Performer, entity, ExamineRange, null)), - true, - PopupType.Medium); + _popups.PopupEntity(Loc.GetString("focused-metapsionic-pulse-begin", ("entity", args.Target)), args.Performer, PopupType.Medium); _audioSystem.PlayPvs(component.SoundUse, args.Performer, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); _psionics.LogPowerUsed(args.Performer, "focused metapsionic pulse", diff --git a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs index 915abd12224..c81d3d7a0b0 100644 --- a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs @@ -68,12 +68,7 @@ public void RemovePsionics(EntityUid uid) { if (RemComp(uid)) { - _popups.PopupEntity(Loc.GetString("mindbreaking-feedback", ("entity", uid)), - uid, - // TODO: Use LoS-based Filter when one is available. - Filter.Pvs(uid).RemoveWhereAttachedEntity(entity => !ExamineSystemShared.InRangeUnOccluded(uid, entity, ExamineRange, null)), - true, - PopupType.Medium); + _popups.PopupEntity(Loc.GetString("mindbreaking-feedback", ("entity", uid)), uid, PopupType.Medium); } if (!TryComp(uid, out var psionic)) From c416d4063e61bcf687ca171fa59319cddcebea74 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Wed, 29 May 2024 12:49:44 -0400 Subject: [PATCH 35/82] Update DispelPowerSystem.cs --- Content.Server/Psionics/Abilities/DispelPowerSystem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Content.Server/Psionics/Abilities/DispelPowerSystem.cs b/Content.Server/Psionics/Abilities/DispelPowerSystem.cs index cb7ef8313cd..67176c3a3d2 100644 --- a/Content.Server/Psionics/Abilities/DispelPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/DispelPowerSystem.cs @@ -82,8 +82,8 @@ private void OnPowerUsed(DispelPowerActionEvent args) { args.Handled = true; _psionics.LogPowerUsed(args.Performer, "dispel", - (int) MathF.Round(-2 * psionic.Dampening + psionic.Amplification), - (int) MathF.Round(-4 * psionic.Dampening + psionic.Amplification)); + (int) MathF.Round(-4 * psionic.Dampening + psionic.Amplification), + (int) MathF.Round(-2 * psionic.Dampening + psionic.Amplification)); } } From e3fb4543b057a73998c76738c4f3eea90e30e350 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Mon, 10 Jun 2024 18:43:47 -0400 Subject: [PATCH 36/82] Fixing invisibility, more feedback messages --- .../Abilities/MetapsionicPowerSystem.cs | 11 ++-- .../RegenerativeStasisPowerSystem.cs | 1 + .../Invisibility/PsionicInvisibilitySystem.cs | 2 + .../PsionicInvisibilityPowerSystem.cs | 42 ++++++------- .../PsionicInvisibilityUsedComponent.cs | 7 ++- .../PsionicInvisibleContactsComponent.cs | 2 +- .../PsionicInvisibleContactsSystem.cs | 2 +- .../PsionicallyInvisibleComponent.cs | 2 +- Content.Shared/Psionics/PsionicComponent.cs | 2 +- .../en-US/nyanotrasen/abilities/psionic.ftl | 7 +-- .../nyanotrasen/psionics/psychic-feedback.ftl | 25 +++++++- .../Entities/Mobs/NPCs/elemental.yml | 29 +++++++++ .../Prototypes/Entities/Mobs/NPCs/flesh.yml | 5 ++ .../Structures/Specific/Anomaly/anomalies.yml | 62 ++++++++++++++++++- .../Structures/Research/glimmer_prober.yml | 10 +++ 15 files changed, 166 insertions(+), 43 deletions(-) rename {Content.Server/Psionics/Abilities => Content.Shared/Psionics/Abilities/PsionicInvisibility}/PsionicInvisibilityPowerSystem.cs (86%) rename {Content.Server/Psionics/Invisibility => Content.Shared/Psionics/Abilities/PsionicInvisibility}/PsionicInvisibleContactsComponent.cs (93%) rename {Content.Server/Psionics/Invisibility => Content.Shared/Psionics/Abilities/PsionicInvisibility}/PsionicInvisibleContactsSystem.cs (98%) rename {Content.Server/Psionics/Invisibility => Content.Shared/Psionics/Abilities/PsionicInvisibility}/PsionicallyInvisibleComponent.cs (76%) diff --git a/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs b/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs index 78842c6443d..38135e9a977 100644 --- a/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs @@ -142,9 +142,6 @@ private void OnFocusedPowerUsed(FocusedMetapsionicPowerActionEvent args) private void OnDoAfter(EntityUid uid, MetapsionicPowerComponent component, FocusedMetapsionicDoAfterEvent args) { - if (!TryComp(args.Target, out var psychic)) - return; - component.DoAfter = null; if (args.Target == null) return; @@ -173,11 +170,13 @@ private void OnDoAfter(EntityUid uid, MetapsionicPowerComponent component, Focus return; } - foreach (var psychicFeedback in psychic.PsychicFeedback) + if (TryComp(args.Target, out var psychic)) { - _popups.PopupEntity(Loc.GetString(psychicFeedback, ("entity", args.Target)), uid, uid, PopupType.LargeCaution); + foreach (var psychicFeedback in psychic.PsychicFeedback) + { + _popups.PopupEntity(Loc.GetString(psychicFeedback, ("entity", args.Target)), uid, uid, PopupType.LargeCaution); + } } - } } } diff --git a/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs b/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs index e184b19396b..8f187b71f33 100644 --- a/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs @@ -63,6 +63,7 @@ private void OnPowerUsed(EntityUid uid, RegenerativeStasisPowerComponent compone var solution = new Solution(); solution.AddReagent("PsionicRegenerationEssence", FixedPoint2.New(MathF.Min(2.5f * psionic.Amplification + psionic.Dampening, 15f))); solution.AddReagent("Epinephrine", FixedPoint2.New(MathF.Min(2.5f * psionic.Dampening + psionic.Amplification, 15f))); + solution.AddReagent("Nocturine", 10f + (1 * psionic.Amplification + psionic.Dampening)); _bloodstreamSystem.TryAddToChemicals(args.Target, solution, stream); EnsureComp(args.Target); diff --git a/Content.Server/Psionics/Invisibility/PsionicInvisibilitySystem.cs b/Content.Server/Psionics/Invisibility/PsionicInvisibilitySystem.cs index 9583f45fdc9..19c1a2c616c 100644 --- a/Content.Server/Psionics/Invisibility/PsionicInvisibilitySystem.cs +++ b/Content.Server/Psionics/Invisibility/PsionicInvisibilitySystem.cs @@ -89,6 +89,7 @@ private void OnInvisInit(EntityUid uid, PsionicallyInvisibleComponent component, _visibilitySystem.AddLayer(uid, visibility, (int) VisibilityFlags.PsionicInvisibility, false); _visibilitySystem.RemoveLayer(uid, visibility, (int) VisibilityFlags.Normal, false); _visibilitySystem.RefreshVisibility(uid, visibility); + SetCanSeePsionicInvisiblity(uid, true); } @@ -99,6 +100,7 @@ private void OnInvisShutdown(EntityUid uid, PsionicallyInvisibleComponent compon _visibilitySystem.RemoveLayer(uid, visibility, (int) VisibilityFlags.PsionicInvisibility, false); _visibilitySystem.AddLayer(uid, visibility, (int) VisibilityFlags.Normal, false); _visibilitySystem.RefreshVisibility(uid, visibility); + SetCanSeePsionicInvisiblity(uid, false); } } diff --git a/Content.Server/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs b/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerSystem.cs similarity index 86% rename from Content.Server/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs rename to Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerSystem.cs index 0c50efb5cf3..28378d363ec 100644 --- a/Content.Server/Psionics/Abilities/PsionicInvisibilityPowerSystem.cs +++ b/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerSystem.cs @@ -1,6 +1,4 @@ -using Content.Server.DoAfter; using Content.Shared.Actions; -using Content.Shared.Psionics.Abilities; using Content.Shared.Damage; using Content.Shared.DoAfter; using Content.Shared.Stunnable; @@ -13,9 +11,9 @@ using Content.Shared.Weapons.Ranged.Events; using Content.Shared.Throwing; using Robust.Shared.Timing; -using Content.Shared.Psionics; +using System.Xml; -namespace Content.Server.Psionics.Abilities +namespace Content.Shared.Psionics.Abilities { public sealed class PsionicInvisibilityPowerSystem : EntitySystem { @@ -25,7 +23,7 @@ public sealed class PsionicInvisibilityPowerSystem : EntitySystem [Dependency] private readonly SharedStealthSystem _stealth = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; public override void Initialize() { @@ -80,26 +78,24 @@ private void OnPowerUsed(EntityUid uid, PsionicInvisibilityPowerComponent compon var ev = new PsionicInvisibilityTimerEvent(_gameTiming.CurTime); var doAfterArgs = new DoAfterArgs(EntityManager, uid, component.UseTimer, ev, uid) { Hidden = true }; - _doAfterSystem.TryStartDoAfter(doAfterArgs); - - ToggleInvisibility(args.Performer); - var action = Spawn(PsionicInvisibilityUsedComponent.PsionicInvisibilityUsedActionPrototype); - _actions.AddAction(uid, action, action); - _actions.TryGetActionData(action, out var actionData); - if (actionData is { UseDelay: not null }) - _actions.StartUseDelay(action); - - _psionics.LogPowerUsed(uid, "psionic invisibility", - (int) MathF.Round(8 * psionic.Amplification - 2 * psionic.Dampening), - (int) MathF.Round(12 * psionic.Amplification - 2 * psionic.Dampening)); - args.Handled = true; + if (_doAfterSystem.TryStartDoAfter(doAfterArgs, out var doAfterId)) + { + ToggleInvisibility(args.Performer); + if (TryComp(uid, out var invis)) + { + _actions.AddAction(uid, ref invis.PsionicInvisibilityUsedActionEntity, invis.PsionicInvisibilityUsedActionId); + invis.DoAfter = doAfterId; + } + + _psionics.LogPowerUsed(uid, "psionic invisibility", + (int) MathF.Round(8 * psionic.Amplification - 2 * psionic.Dampening), + (int) MathF.Round(12 * psionic.Amplification - 2 * psionic.Dampening)); + args.Handled = true; + } } private void OnPowerOff(RemovePsionicInvisibilityOffPowerActionEvent args) { - if (!HasComp(args.Performer)) - return; - ToggleInvisibility(args.Performer); args.Handled = true; } @@ -118,6 +114,7 @@ private void OnEnd(EntityUid uid, PsionicInvisibilityUsedComponent component, Co if (Terminating(uid)) return; + _doAfterSystem.Cancel(component.DoAfter); RemComp(uid); RemComp(uid); _audio.PlayPvs("/Audio/Effects/toss.ogg", uid); @@ -163,7 +160,8 @@ public void ToggleInvisibility(EntityUid uid) public void OnDoAfter(EntityUid uid, PsionicInvisibilityPowerComponent component, PsionicInvisibilityTimerEvent args) { - RemComp(uid); + if (!args.Cancelled) + RemComp(uid); } private void OnInsulated(EntityUid uid, PsionicInvisibilityUsedComponent component, PsionicInsulationEvent args) diff --git a/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs b/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs index 2a9dd7642ba..22d1b928553 100644 --- a/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs +++ b/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityUsedComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared.DoAfter; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; @@ -6,13 +7,13 @@ namespace Content.Shared.Psionics.Abilities [RegisterComponent] public sealed partial class PsionicInvisibilityUsedComponent : Component { - [ValidatePrototypeId] - public const string PsionicInvisibilityUsedActionPrototype = "ActionPsionicInvisibilityUsed"; - [DataField("psionicInvisibilityUsedActionId", + [DataField("psionicInvisibilityActionId", customTypeSerializer: typeof(PrototypeIdSerializer))] public string? PsionicInvisibilityUsedActionId = "ActionPsionicInvisibilityUsed"; [DataField("psionicInvisibilityUsedActionEntity")] public EntityUid? PsionicInvisibilityUsedActionEntity; + + public DoAfterId? DoAfter; } } diff --git a/Content.Server/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs b/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibleContactsComponent.cs similarity index 93% rename from Content.Server/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs rename to Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibleContactsComponent.cs index 268deddf6d9..376414eedce 100644 --- a/Content.Server/Psionics/Invisibility/PsionicInvisibleContactsComponent.cs +++ b/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibleContactsComponent.cs @@ -1,6 +1,6 @@ using Content.Shared.Whitelist; -namespace Content.Server.Psionics +namespace Content.Shared.Psionics { [RegisterComponent] public sealed partial class PsionicInvisibleContactsComponent : Component diff --git a/Content.Server/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs b/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibleContactsSystem.cs similarity index 98% rename from Content.Server/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs rename to Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibleContactsSystem.cs index 403e0592617..f71605238ae 100644 --- a/Content.Server/Psionics/Invisibility/PsionicInvisibleContactsSystem.cs +++ b/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibleContactsSystem.cs @@ -3,7 +3,7 @@ using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Systems; -namespace Content.Server.Psionics +namespace Content.Shared.Psionics { /// /// Allows an entity to become psionically invisible when touching certain entities. diff --git a/Content.Server/Psionics/Invisibility/PsionicallyInvisibleComponent.cs b/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicallyInvisibleComponent.cs similarity index 76% rename from Content.Server/Psionics/Invisibility/PsionicallyInvisibleComponent.cs rename to Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicallyInvisibleComponent.cs index 5352f5737f2..87d3f250b1e 100644 --- a/Content.Server/Psionics/Invisibility/PsionicallyInvisibleComponent.cs +++ b/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicallyInvisibleComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Server.Psionics +namespace Content.Shared.Psionics { [RegisterComponent] public sealed partial class PsionicallyInvisibleComponent : Component diff --git a/Content.Shared/Psionics/PsionicComponent.cs b/Content.Shared/Psionics/PsionicComponent.cs index 9a06e54cb31..35ceb82c876 100644 --- a/Content.Shared/Psionics/PsionicComponent.cs +++ b/Content.Shared/Psionics/PsionicComponent.cs @@ -24,7 +24,7 @@ public sealed partial class PsionicComponent : Component [DataField("dampening")] public float Dampening = 0.1f; - public bool Telepath = false; + public bool Telepath = true; public bool InnatePsiChecked = false; } } diff --git a/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl b/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl index 5b368e822f1..d46a05e9c98 100644 --- a/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl +++ b/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl @@ -26,13 +26,10 @@ accept-psionics-window-prompt-text-part = You rolled a psionic power! Do you still wish to be psionic? action-name-psionic-invisibility = Psionic Invisibility -action-description-psionic-invisibility = Render yourself invisible to any entity that could potentially be psychic. Borgs, animals, and so on are not affected. - -action-name-psionic-invisibility = Psionic Invisibility -action-description-psionic-invisibility = Render yourself invisible to any entity that could potentially be psychic. Borgs, animals, and so on are not affected. +action-description-psionic-invisibility = Telepathically remove yourself from the vision of anyone not psionically insulated. action-name-psionic-invisibility-off = Turn Off Psionic Invisibility -action-description-psionic-invisibility-off = Return to visibility, and receive a stun. +action-description-psionic-invisibility-off = End your invisibility early. action-name-mind-swap = Mind Swap action-description-mind-swap = Swap minds with the target. Either can change back after 20 seconds. diff --git a/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl b/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl index 26d2acb87cd..30dde33451d 100644 --- a/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl +++ b/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl @@ -10,10 +10,31 @@ noospheric-zap-feedback = {CAPITALIZE($entity)}'s soul writhes with thunder from pyrokinesis-feedback = The Secret of Fire dwells within {CAPITALIZE($entity)} invisibility-feedback = {CAPITALIZE($entity)}'s wyrd seeks to hide from thine gaze telegnosis-feedback = {CAPITALIZE($entity)}'s soul travels across bridges composed of dreamlight -sophic-grammateus-feedback = SEEKER, YOU NEED ONLY ASK FOR MY WISDOM. -oracle-feedback = WHY DO YOU BOTHER ME SEEKER? HAVE I NOT MADE MY DESIRES CLEAR? metempsychotic-machine-feedback = The sea of fate flows through this machine +regeneration-feedback = {CAPITALIZE($entity)} possesses an overwhelming will to live +regenerative-stasis-feedback = {CAPITALIZE($entity)} possesses an overwhelming will such that others may live + +# Entity Feedback Messages ifrit-feedback = A spirit of Gehenna, bound by the will of a powerful psychic +prober-feedback = A mirror into the end of time, the screaming of dead stars emanates from this machine +drain-feedback = A mirror into a realm where the stars sit still forever, a cold and distant malevolence stares back +sophic-grammateus-feedback = SEEKER, YOU NEED ONLY ASK FOR MY WISDOM. +oracle-feedback = WHY DO YOU BOTHER ME SEEKER? HAVE I NOT MADE MY DESIRES CLEAR? +orecrab-feedback = Heralds of the Lord of Earth, summoned to this realm from Grome's kingdom +reagent-slime-feedback = Heralds of the Lord of Water, summoned to this realm from Straasha's kingdom. +flesh-golem-feedback = Abominations pulled from dead realms, twisted amalgamations of those fallen to the influence of primordial Chaos + +# Anomaly Feedback Messages +anomaly-pyroclastic-feedback = A small mirror to the plane of Gehenna, truth lies within the Secret of Fire +anomaly-gravity-feedback = Violet and crimson, blue of blue, impossibly dark yet greater than the whitest of white, a black star shines weakly at the end of it all +anomaly-electricity-feedback = A mirror to a realm tiled by silicon, the lifeblood of artificial thought flows from it +anomaly-flesh-feedback = From within it comes the suffering of damned mutants howling for all eternity +anomaly-bluespace-feedback = A bridge of dreamlight, crossing into the space between realms of the multiverse +anomaly-ice-feedback = Walls of blackened stone, ruin and famine wait for those who fall within +anomaly-rock-feedback = A vast old oak dwells high over a plane of stone, it turns to stare back +anomaly-flora-feedback = Musical notes drift around you, playfully beckoning, they wish to feast +anomaly-liquid-feedback = A realm of twisting currents. Its placidity is a lie. The eyes within stare hungrilly +anomaly-shadow-feedback = At the end of time, when all suns have set forever, there amidst the void stands a monument to past sins. # Power PVS Messages focused-metapsionic-pulse-begin = The air around {CAPITALIZE($entity)} begins to shimmer faintly diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml b/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml index 01fce382e37..fda467cb32d 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml @@ -101,6 +101,12 @@ - SimpleHostile - type: Damageable damageContainer: StructuralInorganic + - type: PotentialPsionic + - type: Psionic + removable: false + dampening: 1 + psychicFeedback: + - "orecrab-feedback" - type: entity parent: MobOreCrab @@ -292,6 +298,12 @@ solution: bloodstream - type: DrainableSolution solution: bloodstream + - type: PotentialPsionic + - type: Psionic + removable: false + amplification: 1 + psychicFeedback: + - "reagent-slime-feedback" - type: entity name: Reagent Slime Spawner @@ -529,3 +541,20 @@ - map: [ "enum.DamageStateVisualLayers.Base" ] state: alive color: "#3e901c" + +- type: entity + id: ReagentSlimeLoto + parent: ReagentSlime + suffix: LotophagoiOil + components: + - type: Bloodstream + bloodReagent: LotophagoiOil + - type: PointLight + color: "#ffbf00" + - type: Sprite + drawdepth: Mobs + sprite: Mobs/Aliens/elemental.rsi + layers: + - map: [ "enum.DamageStateVisualLayers.Base" ] + state: alive + color: "#ffbf00" diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/flesh.yml b/Resources/Prototypes/Entities/Mobs/NPCs/flesh.yml index 06ab02dedc9..93081d382a2 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/flesh.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/flesh.yml @@ -54,6 +54,11 @@ Slash: 6 - type: ReplacementAccent accent: genericAggressive + - type: Psionic + removable: false + amplification: 1 + psychicFeedback: + - "flesh-golem-feedback" - type: entity parent: BaseMobFlesh diff --git a/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml b/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml index 43c0bdce12f..9a2bd4af69f 100644 --- a/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml +++ b/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml @@ -48,7 +48,7 @@ sound: path: /Audio/Effects/teleport_arrival.ogg - type: Psionic #Nyano - Summary: makes psionic on creation. - - type: GlimmerSource #Nyano - Summary: makes this a potential source of Glimmer. + - type: GlimmerSource #Nyano - Summary: makes this a potential source of Glimmer. active: false - type: entity @@ -99,6 +99,12 @@ - type: IgniteOnCollide fixtureId: fix1 fireStacks: 1 + - type: PotentialPsionic + - type: Psionic + removable: false + amplification: 5 + psychicFeedback: + - "anomaly-pyroclastic-feedback" - type: entity id: AnomalyGravity @@ -131,6 +137,12 @@ - type: SingularityDistortion intensity: 1000 falloffPower: 2.7 + - type: PotentialPsionic + - type: Psionic + removable: false + amplification: 5 + psychicFeedback: + - "anomaly-gravity-feedback" - type: entity id: AnomalyElectricity @@ -154,6 +166,12 @@ castShadows: false - type: ElectricityAnomaly - type: Electrified + - type: PotentialPsionic + - type: Psionic + removable: false + amplification: 5 + psychicFeedback: + - "anomaly-electricity-feedback" - type: entity id: AnomalyFlesh @@ -245,6 +263,12 @@ - MobFleshClamp - MobFleshLover - FleshKudzu + - type: PotentialPsionic + - type: Psionic + removable: false + amplification: 5 + psychicFeedback: + - "anomaly-flesh-feedback" - type: entity id: AnomalyBluespace @@ -295,6 +319,12 @@ anomalyContactDamage: types: Radiation: 10 + - type: PotentialPsionic + - type: Psionic + removable: false + amplification: 5 + psychicFeedback: + - "anomaly-bluespace-feedback" - type: entity id: AnomalyIce @@ -344,6 +374,12 @@ releasedGas: 8 # Frezon. Please replace if there is a better way to specify this releaseOnMaxSeverity: true spawnRadius: 0 + - type: PotentialPsionic + - type: Psionic + removable: false + amplification: 5 + psychicFeedback: + - "anomaly-ice-feedback" - type: entity id: AnomalyRockBase @@ -380,6 +416,12 @@ maxAmount: 50 maxRange: 12 floor: FloorAsteroidTile + - type: PotentialPsionic + - type: Psionic + removable: false + amplification: 5 + psychicFeedback: + - "anomaly-rock-feedback" - type: entity id: AnomalyRockUranium @@ -637,6 +679,12 @@ maxRange: 6 spawns: - KudzuFlowerAngry + - type: PotentialPsionic + - type: Psionic + removable: false + amplification: 5 + psychicFeedback: + - "anomaly-flora-feedback" - type: entity id: AnomalyFloraBulb @@ -795,6 +843,12 @@ solution: anomaly - type: InjectableSolution solution: beaker + - type: PotentialPsionic + - type: Psionic + removable: false + amplification: 5 + psychicFeedback: + - "anomaly-liquid-feedback" - type: entity id: AnomalyShadow @@ -849,3 +903,9 @@ - type: Tag tags: - SpookyFog + - type: PotentialPsionic + - type: Psionic + removable: false + amplification: 5 + psychicFeedback: + - "anomaly-shadow-feedback" diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/glimmer_prober.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/glimmer_prober.yml index e157f8b7ff4..eca5b5e3758 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/glimmer_prober.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/glimmer_prober.yml @@ -4,7 +4,12 @@ name: glimmer prober description: Probes the noösphere to generate research points. Might be worth turning off if glimmer is a problem. components: + - type: PotentialPsionic - type: Psionic + removable: false + amplification: 10 + psychicFeedback: + - "prober-feedback" - type: GlimmerSource - type: Construction graph: GlimmerDevices @@ -90,7 +95,12 @@ name: glimmer drain description: Uses electricity to try and sort out the noösphere, reducing its level of entropy. components: + - type: PotentialPsionic - type: Psionic + removable: false + dampening: 10 + psychicFeedback: + - "drain-feedback" - type: GlimmerSource addToGlimmer: false - type: Construction From c2a20aae83dbe358230a5a5eb73c022efb7116de Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Mon, 10 Jun 2024 18:55:56 -0400 Subject: [PATCH 37/82] Update RegenerativeStasisPowerSystem.cs --- .../Psionics/Abilities/RegenerativeStasisPowerSystem.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs b/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs index 8f187b71f33..bc93afd7788 100644 --- a/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs @@ -65,7 +65,6 @@ private void OnPowerUsed(EntityUid uid, RegenerativeStasisPowerComponent compone solution.AddReagent("Epinephrine", FixedPoint2.New(MathF.Min(2.5f * psionic.Dampening + psionic.Amplification, 15f))); solution.AddReagent("Nocturine", 10f + (1 * psionic.Amplification + psionic.Dampening)); _bloodstreamSystem.TryAddToChemicals(args.Target, solution, stream); - EnsureComp(args.Target); _psionics.LogPowerUsed(uid, "regenerative stasis", (int) Math.Round(4 * psionic.Amplification - psionic.Dampening), From 5c5ad44a4cd5ee3445b2b9c93245c1ec47a40451 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Mon, 10 Jun 2024 19:46:29 -0400 Subject: [PATCH 38/82] Refactor mime psionics! --- .../Abilities/Mime/MimePowersComponent.cs | 12 ++++++ .../Abilities/Mime/MimePowersSystem.cs | 37 ++++++++++++++++--- .../Psionics/Telepathy/TelepathyChatSystem.cs | 8 ++++ Content.Shared/Psionics/PsionicComponent.cs | 1 + .../nyanotrasen/psionics/psychic-feedback.ftl | 5 +++ 5 files changed, 57 insertions(+), 6 deletions(-) diff --git a/Content.Server/Abilities/Mime/MimePowersComponent.cs b/Content.Server/Abilities/Mime/MimePowersComponent.cs index fd4fc2c2af9..757528a9cbc 100644 --- a/Content.Server/Abilities/Mime/MimePowersComponent.cs +++ b/Content.Server/Abilities/Mime/MimePowersComponent.cs @@ -47,5 +47,17 @@ public sealed partial class MimePowersComponent : Component /// [DataField("vowCooldown")] public TimeSpan VowCooldown = TimeSpan.FromMinutes(5); + + /// + [DataField("mimeFeedback")] + public string MimeFeedback = "mime-feedback"; + + /// + [DataField("mimeBrokenFeedback")] + public string MimeBrokenFeedback = "mime-broken-feedback"; } } diff --git a/Content.Server/Abilities/Mime/MimePowersSystem.cs b/Content.Server/Abilities/Mime/MimePowersSystem.cs index b3bd3392434..e37864f2a35 100644 --- a/Content.Server/Abilities/Mime/MimePowersSystem.cs +++ b/Content.Server/Abilities/Mime/MimePowersSystem.cs @@ -58,14 +58,21 @@ private void OnComponentInit(EntityUid uid, MimePowersComponent component, Compo EnsureComp(uid); _alertsSystem.ShowAlert(uid, AlertType.VowOfSilence); _actionsSystem.AddAction(uid, ref component.InvisibleWallActionEntity, component.InvisibleWallAction, uid); - //Nyano - Summary: Add Psionic Ability to Mime. - if (TryComp(uid, out var psionic) && psionic.PsionicAbility == null) - psionic.PsionicAbility = component.InvisibleWallActionEntity; + + // Mimes gain their power from a special Vow, but this vow extends to Telepathic speech. + if (EnsureComp(uid, out var psionic)) + { + psionic.TelepathicMute = true; + psionic.ActivePowers.Add(component); + psionic.PsychicFeedback.Add(component.MimeFeedback); + psionic.Dampening += 1f; + } } /// /// Creates an invisible wall in a free space after some checks. /// + // TODO: Consider separating this out from the Mime entirely, and make a standalone "Telekinetic Barricade" power. private void OnInvisibleWall(EntityUid uid, MimePowersComponent component, InvisibleWallActionEvent args) { if (!component.Enabled) @@ -98,9 +105,11 @@ private void OnInvisibleWall(EntityUid uid, MimePowersComponent component, Invis return; } } - // Begin Nyano-code: mime powers are psionic. - _psionics.LogPowerUsed(uid, "invisible wall"); - // End Nyano-code. + if (TryComp(uid, out var psionic)) + _psionics.LogPowerUsed(uid, "invisible wall", + (int) Math.Round(4 * psionic.Amplification - psionic.Dampening), + (int) Math.Round(6 * psionic.Amplification - psionic.Dampening)); + _popupSystem.PopupEntity(Loc.GetString("mime-invisible-wall-popup", ("mime", uid)), uid); // Make sure we set the invisible wall to despawn properly Spawn(component.WallPrototype, _turf.GetTileCenter(tile.Value)); @@ -126,6 +135,14 @@ public void BreakVow(EntityUid uid, MimePowersComponent? mimePowers = null) _alertsSystem.ClearAlert(uid, AlertType.VowOfSilence); _alertsSystem.ShowAlert(uid, AlertType.VowBroken); _actionsSystem.RemoveAction(uid, mimePowers.InvisibleWallActionEntity); + if (TryComp(uid, out var psionic)) + { + psionic.TelepathicMute = false; + psionic.ActivePowers.Remove(mimePowers); + psionic.PsychicFeedback.Remove(mimePowers.MimeFeedback); + psionic.PsychicFeedback.Add(mimePowers.MimeBrokenFeedback); + psionic.Dampening -= 1f; + } } /// @@ -149,6 +166,14 @@ public void RetakeVow(EntityUid uid, MimePowersComponent? mimePowers = null) _alertsSystem.ClearAlert(uid, AlertType.VowBroken); _alertsSystem.ShowAlert(uid, AlertType.VowOfSilence); _actionsSystem.AddAction(uid, ref mimePowers.InvisibleWallActionEntity, mimePowers.InvisibleWallAction, uid); + if (TryComp(uid, out var psionic)) + { + psionic.TelepathicMute = true; + psionic.ActivePowers.Add(mimePowers); + psionic.PsychicFeedback.Add(mimePowers.MimeFeedback); + psionic.PsychicFeedback.Remove(mimePowers.MimeBrokenFeedback); + psionic.Dampening += 1f; + } } } } diff --git a/Content.Server/Psionics/Telepathy/TelepathyChatSystem.cs b/Content.Server/Psionics/Telepathy/TelepathyChatSystem.cs index ad49075e65a..2c6b93e2542 100644 --- a/Content.Server/Psionics/Telepathy/TelepathyChatSystem.cs +++ b/Content.Server/Psionics/Telepathy/TelepathyChatSystem.cs @@ -2,6 +2,7 @@ using Content.Server.Administration.Managers; using Content.Server.Chat.Managers; using Content.Server.Chat.Systems; +using Content.Server.Popups; using Content.Shared.Psionics.Abilities; using Content.Shared.Bed.Sleep; using Content.Shared.Chat; @@ -30,6 +31,7 @@ public sealed class NyanoChatSystem : EntitySystem [Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly GlimmerSystem _glimmerSystem = default!; [Dependency] private readonly ChatSystem _chatSystem = default!; + [Dependency] private readonly PopupSystem _popupSystem = default!; private IEnumerable GetPsionicChatClients() { return Filter.Empty() @@ -74,6 +76,12 @@ public void SendTelepathicChat(EntityUid source, string message, bool hideChat) if (!IsEligibleForTelepathy(source)) return; + if (TryComp(source, out var psionic) && psionic.TelepathicMute) + { + _popupSystem.PopupEntity(Loc.GetString("telepathic-mute-message"), source, source); + return; + } + var clients = GetPsionicChatClients(); var admins = GetAdminClients(); string messageWrap; diff --git a/Content.Shared/Psionics/PsionicComponent.cs b/Content.Shared/Psionics/PsionicComponent.cs index 35ceb82c876..c955626c53d 100644 --- a/Content.Shared/Psionics/PsionicComponent.cs +++ b/Content.Shared/Psionics/PsionicComponent.cs @@ -25,6 +25,7 @@ public sealed partial class PsionicComponent : Component [DataField("dampening")] public float Dampening = 0.1f; public bool Telepath = true; + public bool TelepathicMute = false; public bool InnatePsiChecked = false; } } diff --git a/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl b/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl index 30dde33451d..4af3ae267b3 100644 --- a/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl +++ b/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl @@ -13,6 +13,8 @@ telegnosis-feedback = {CAPITALIZE($entity)}'s soul travels across bridges compos metempsychotic-machine-feedback = The sea of fate flows through this machine regeneration-feedback = {CAPITALIZE($entity)} possesses an overwhelming will to live regenerative-stasis-feedback = {CAPITALIZE($entity)} possesses an overwhelming will such that others may live +mime-feedback = A servant of the Silent Dreamer, {CAPITALIZE($entity)} bears His power in exchange for a vow of silence +mime-broken-feedback = TREASONOUS VERMIN! {CAPITALIZE($entity)} HAS BETRAYED THEIR VOW! THE SILENT DREAMER DEMANDS THEIR HEAD! # Entity Feedback Messages ifrit-feedback = A spirit of Gehenna, bound by the will of a powerful psychic @@ -40,3 +42,6 @@ anomaly-shadow-feedback = At the end of time, when all suns have set forever, th focused-metapsionic-pulse-begin = The air around {CAPITALIZE($entity)} begins to shimmer faintly psionic-regeneration-self-revive = {CAPITALIZE($entity)} begins to visibly regenerate mindbreaking-feedback = The light of life vanishes from {CAPITALIZE($entity)}'s eyes, leaving behind a husk pretending at sapience + +# Misc Psionic Messages +telepathic-mute-message = You strain, but are unable to send your thoughts to the Noosphere From efccb4900dd72bbb3040eb7fd02e0aecb20c0c02 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Mon, 10 Jun 2024 19:50:05 -0400 Subject: [PATCH 39/82] Update mime.yml --- Resources/Prototypes/Roles/Jobs/Civilian/mime.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml b/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml index 8da2c34231b..253b5b89c1a 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml @@ -16,6 +16,7 @@ special: - !type:AddComponentSpecial components: + - type: PotentialPsionic - type: Psionic # Nyano - Summary: Makes the mime psionic. - type: MimePowers - type: FrenchAccent From c1cbaf9aa17c76779d8b3f05481427cb27003c13 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Mon, 10 Jun 2024 20:01:56 -0400 Subject: [PATCH 40/82] Purge a bunch of unused usings --- Content.Server/Abilities/Mime/MimePowersSystem.cs | 1 - Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs | 2 -- Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs | 4 ---- Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs | 1 - Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs | 3 --- .../Psionics/Abilities/PsionicRegenerationPowerSystem.cs | 3 --- Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs | 3 --- .../Psionics/Abilities/RegenerativeStasisPowerSystem.cs | 4 ---- .../Psionics/Invisibility/PsionicInvisibilitySystem.cs | 1 - Content.Server/Psionics/PsionicsCommands.cs | 1 - Content.Server/Psionics/PsionicsSystem.cs | 2 -- .../PsionicInvisibility/PsionicInvisibilityPowerSystem.cs | 1 - .../RegenerativeStasis/RegenerativeStasisPowerComponent.cs | 1 - 13 files changed, 27 deletions(-) diff --git a/Content.Server/Abilities/Mime/MimePowersSystem.cs b/Content.Server/Abilities/Mime/MimePowersSystem.cs index e37864f2a35..9c108c4bcf2 100644 --- a/Content.Server/Abilities/Mime/MimePowersSystem.cs +++ b/Content.Server/Abilities/Mime/MimePowersSystem.cs @@ -1,5 +1,4 @@ using Content.Server.Popups; -using Content.Server.Speech.Muting; using Content.Shared.Actions; using Content.Shared.Actions.Events; using Content.Shared.Alert; diff --git a/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs b/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs index 24459d29e22..3a0e912c08a 100644 --- a/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs +++ b/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs @@ -8,13 +8,11 @@ using Content.Shared.Psionics.Abilities; using Content.Shared.Chat; using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.Interaction; using Content.Shared.Mobs.Components; using Content.Shared.Psionics.Glimmer; using Content.Shared.Research.Prototypes; -using Robust.Server.GameObjects; using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; diff --git a/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs b/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs index 38135e9a977..dac38290f22 100644 --- a/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs @@ -2,16 +2,12 @@ using Content.Shared.Actions.Events; using Content.Shared.Psionics.Abilities; using Content.Shared.DoAfter; -using Content.Shared.Examine; -using static Content.Shared.Examine.ExamineSystemShared; using Content.Shared.Popups; using Robust.Server.Audio; using Robust.Shared.Audio; using Robust.Shared.Timing; -using Robust.Shared.Player; using Content.Server.DoAfter; using Content.Shared.Psionics.Events; -using Content.Server.Psionics; namespace Content.Server.Psionics.Abilities { diff --git a/Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs b/Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs index 1e50a586b4f..b0e27027ad5 100644 --- a/Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs @@ -9,7 +9,6 @@ using Content.Server.Mind; using Content.Shared.Mobs.Systems; using Content.Server.Popups; -using Content.Server.Psionics; using Content.Server.GameTicking; using Content.Shared.Mind; using Content.Shared.Actions.Events; diff --git a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs index c81d3d7a0b0..480cf561001 100644 --- a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs @@ -6,10 +6,7 @@ using Content.Shared.StatusEffect; using Robust.Shared.Random; using Robust.Shared.Prototypes; -using Robust.Shared.Player; -using Content.Shared.Examine; using Content.Shared.Popups; -using static Content.Shared.Examine.ExamineSystemShared; namespace Content.Server.Psionics.Abilities { diff --git a/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs b/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs index 893d1bc4cfa..715774ae1c7 100644 --- a/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs @@ -1,5 +1,4 @@ using Robust.Shared.Audio; -using Robust.Shared.Player; using Content.Server.Body.Components; using Content.Server.Body.Systems; using Content.Server.DoAfter; @@ -11,8 +10,6 @@ using Content.Shared.Mobs; using Content.Shared.Popups; using Content.Shared.Psionics.Events; -using Content.Shared.Examine; -using static Content.Shared.Examine.ExamineSystemShared; using Robust.Shared.Timing; using Content.Shared.Actions.Events; using Robust.Server.Audio; diff --git a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs index 77075dab206..e488aac7879 100644 --- a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs @@ -5,7 +5,6 @@ using Robust.Server.GameObjects; using Content.Shared.Actions.Events; using Content.Server.Explosion.Components; -using Content.Shared.Mobs.Components; using Robust.Shared.Map; namespace Content.Server.Psionics.Abilities @@ -16,8 +15,6 @@ public sealed class PyrokinesisPowerSystem : EntitySystem [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly GunSystem _gunSystem = default!; - [Dependency] private readonly SharedTransformSystem _transformSystem = default!; - [Dependency] private readonly PhysicsSystem _physics = default!; [Dependency] private readonly IMapManager _mapManager = default!; public override void Initialize() { diff --git a/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs b/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs index bc93afd7788..be435d1acc5 100644 --- a/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs @@ -2,11 +2,7 @@ using Content.Server.Body.Components; using Content.Shared.Actions; using Content.Shared.Chemistry.Components; -using Content.Shared.Bed.Sleep; using Content.Shared.Psionics.Abilities; -using Robust.Shared.Prototypes; -using Robust.Shared.Timing; -using Content.Shared.Mind; using Content.Shared.Actions.Events; using Content.Shared.FixedPoint; diff --git a/Content.Server/Psionics/Invisibility/PsionicInvisibilitySystem.cs b/Content.Server/Psionics/Invisibility/PsionicInvisibilitySystem.cs index 19c1a2c616c..c21444139d1 100644 --- a/Content.Server/Psionics/Invisibility/PsionicInvisibilitySystem.cs +++ b/Content.Server/Psionics/Invisibility/PsionicInvisibilitySystem.cs @@ -1,6 +1,5 @@ using Content.Shared.Psionics.Abilities; using Content.Shared.Psionics; -using Content.Server.Psionics.Abilities; using Content.Shared.Eye; using Content.Server.NPC.Systems; using Robust.Shared.Containers; diff --git a/Content.Server/Psionics/PsionicsCommands.cs b/Content.Server/Psionics/PsionicsCommands.cs index 3f9ee794b38..76c9022151e 100644 --- a/Content.Server/Psionics/PsionicsCommands.cs +++ b/Content.Server/Psionics/PsionicsCommands.cs @@ -1,7 +1,6 @@ using Content.Server.Administration; using Content.Shared.Administration; using Content.Shared.Psionics.Abilities; -using Content.Shared.Mobs.Components; using Robust.Shared.Console; using Content.Shared.Actions; using Robust.Shared.Player; diff --git a/Content.Server/Psionics/PsionicsSystem.cs b/Content.Server/Psionics/PsionicsSystem.cs index bf829477609..7e97af34b80 100644 --- a/Content.Server/Psionics/PsionicsSystem.cs +++ b/Content.Server/Psionics/PsionicsSystem.cs @@ -134,12 +134,10 @@ public void RollPsionics(EntityUid uid, PotentialPsionicComponent component, boo return; var chance = component.Chance; - var warn = true; if (TryComp(uid, out var bonus)) { chance *= bonus.Multiplier; chance += bonus.FlatBonus; - warn = bonus.Warn; } if (applyGlimmer) diff --git a/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerSystem.cs b/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerSystem.cs index 28378d363ec..29ee615dd49 100644 --- a/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerSystem.cs +++ b/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerSystem.cs @@ -11,7 +11,6 @@ using Content.Shared.Weapons.Ranged.Events; using Content.Shared.Throwing; using Robust.Shared.Timing; -using System.Xml; namespace Content.Shared.Psionics.Abilities { diff --git a/Content.Shared/Psionics/Abilities/RegenerativeStasis/RegenerativeStasisPowerComponent.cs b/Content.Shared/Psionics/Abilities/RegenerativeStasis/RegenerativeStasisPowerComponent.cs index 27a0903e224..7caa6100806 100644 --- a/Content.Shared/Psionics/Abilities/RegenerativeStasis/RegenerativeStasisPowerComponent.cs +++ b/Content.Shared/Psionics/Abilities/RegenerativeStasis/RegenerativeStasisPowerComponent.cs @@ -1,4 +1,3 @@ -using Content.Shared.Actions; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; From a26be0432b37946b2b60bef9299890b65df9cccd Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Sun, 16 Jun 2024 17:53:09 -0400 Subject: [PATCH 41/82] Psionic guidebook update! --- .../Entities/Clothing/Head/hats.yml | 3 + .../Entities/Structures/Research/oracle.yml | 3 + Resources/ServerInfo/Guidebook/Psionics.xml | 108 ++++++++++++++++++ .../Guidebook/Epistemics/Psionics.xml | 73 ------------ 4 files changed, 114 insertions(+), 73 deletions(-) create mode 100644 Resources/ServerInfo/Guidebook/Psionics.xml delete mode 100644 Resources/ServerInfo/Nyanotrasen/Guidebook/Epistemics/Psionics.xml diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Head/hats.yml b/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Head/hats.yml index 8278114d267..0a30756d724 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Head/hats.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Head/hats.yml @@ -118,6 +118,9 @@ Slash: 0.85 Piercing: 0.95 Radiation: 0.95 + - type: GuideHelp + guides: + - Psionics - type: entity parent: ClothingHeadBase diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/oracle.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/oracle.yml index 58189e49cec..8470737c702 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/oracle.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/oracle.yml @@ -45,3 +45,6 @@ - type: SpriteFade - type: Tag tags: [] + - type: GuideHelp + guides: + - Psionics diff --git a/Resources/ServerInfo/Guidebook/Psionics.xml b/Resources/ServerInfo/Guidebook/Psionics.xml new file mode 100644 index 00000000000..7645c3d80d4 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/Psionics.xml @@ -0,0 +1,108 @@ + +# Psionics +[color=#a4885c]Psionics[/color] are mental abilities that interface with the [color=#a4885c]noösphere[/color]. Humans have limited access to the noösphere's full potential, allowing some to find ways to command it. +The abilities originate from distorting a noöspheric imprint into a specific shape, a bit like a lock and key. Having powers is like possessing a ring of keys, with each key granting one ability. +Barring unusual circumstances, most psychics will only possess a single power, but there are hidden ways to obtain more. + +## Power Scaling +The relative strength of a psychic entity is given as two measurements, [color=#ff4500]Amplification (kα)[/color], and [color=#87cefa]Dampening (kδ)[/color]. [color=#ff4500]Amplification[/color] is a measure of +how forcefully an entity can manipulate the noösphere, bending its currents to their will. A Pyromancer with high Amplification can throw a deadlier firebolt, but the noösphere will respond in kind with a +proportionally greater increase in Glimmer. [color=#87cefa]Dampening[/color] by contrast is a measure of how controlled an entity is with their powers. With some exceptions, Dampening directly decreases +the amount of Glimmer generated by casting powers. + + +Many other creatures can have power scaling different from that of a human, and thus may interact with their powers in ways different from an equivalent humanoid psion. To give an example, an Ifrit will usually have +five times as much Amplification as the baseline, causing their Pyromancy to be substantially more dangerous than that of a human Pyromancer. + +## Psionic Potential +Not all individuals have the ability to become Psionic. Individuals who can are known as Latents. This is given by the Latent Psychic Trait that must be taken at character creation. Without said trait, an individual +may never become a psychic at any point in the round. There are extraordinarily rare exceptions to this rule, but none are known publicly. Latents have innate access to a minor form of Telepathy, which is +identical to that provided temporarily by powerful hallucinogens, as well as intense states of dreaming. They cannot speak Telepathically, however, until they have obtained the Telepathy power. + +## Telepathy +Nearly all forms of Psionic Powers also come with a secondary power called [color=#32cd32]Telepathy[/color], which works like a sort of noöspheric radio channel shared by all those who have psionic potential. +Telepathy is accessed by starting a message with the = sign. Telepathy requires that the user be alive and conscious, but is not inhibited by most sources of muteness. +It is notable that all Telepathic messages are fully anonymous, and are not guaranteed to come from a human being. Woe befalls the fool who blindly trusts what he hears telepathically. + +Not all Psionic entities have Telepathy, but most do. + +## Glimmer +[color=#a4885c]Glimmer[/color] is a more colloquial term for [color=#a4885c]noöspheric pressure[/color], measured in [color=#a4885c]milli-Psi (mΨ)[/color]. The noösphere can be considered analogous to a pool of still, +onyx black water. The waters have an inherent desire for stillness, for law, for an order of all things. The usage of psychic powers is like throwing a rock into the pool, creating waves that can be measured. As the waves +build up, primordial chaos can potentially enter through our realm through areas where the pool is at its thinnest. While exceptions exist, the psychic powers generally follow Gunderaan's First Law when increasing +Glimmer. Thus, Glimmer increases are given by the formula: + +ΔΨ = ~0.006 * kα - kδ + +Verbally, this law is read as, "Change in Glimmer is equal to approximately six milli-Psi times Amplification, minus Dampening." + + +The [color=#a4885c]sophic scribe[/color] tracks glimmer. + + + + + + +Epistemics can build devices to interact with glimmer. These are usually the main determiners of where glimmer is going. +[color=#a4885c]Glimmer probers[/color] will increase glimmer, but directly generate research points without further input. [color=#a4885c]Glimmer drains[/color] simply drain glimmer at the cost of electricity. + +Use of psionics will increase glimmer, as will [color=#a4885c]noöspheric storms[/color]. + +## Discharges +Glimmer will occasionally discharge if it's above 100 mΨ, causing a wide range of effects based on just how high it is. The most common is giving all entities with psionic potential a small seizure, +which is something most people working on stations with an Epistemics department have grown used to. + +## Acquiring Psionics + + +First, an individual must be a Latent Psychic. Without the Potential for powers, an individual can never in their life obtain psionic abilities. All Latent Psychics start with a +baseline 10% chance to start each round with a random psychic power. Some particular individuals may have a higher baseline chance. After this initial chance, individuals may obtain +powers during a round by certain acts, such as consuming large quantities of hallucinogenic drugs. When this happens, the local Glimmer also acts as a way of increasing the chances of +obtaining powers. Each individual has "One Free Reroll" of their powers, so use it wisely. + +The odds of obtaining powers via drug consumption are given by Gunderaan's Second Law: + +χ = (10 + 0.001Ψ + φ) * ψ + +Where χ is the percentage chance of obtaining powers, Ψ is the glimmer present during the roll, φ is the potential bonus chance some individuals may possess, and ψ is the potential multiplier +that a given hallucinogen may have. Not all hallucinogens have the same chance of granting powers. Most famously, Lotophagic Oil multiplies a user's chances of obtaining powers by 4. Some individuals may also have +an innate potential multiplier, such as the station's Chaplain. + +## Psionic Insulation + + + + + + +Psionic Insulation is a catch-all term for any source of protection from mind-affecting psionic powers, as well as some noöspheric discharges. It is most commonly obtained from wearing special +protective headgear, or from drugs such as Cryptobiolin that render one temporarily protected. Some entities can be innately insulated, such as nearly all forms of synthetic life, though +exceptions may exist. Rarer still, some humanoids may be born with an innate psionic insulation. + +## Handling Glimmer Emergencies + +Probers should be turned off before glimmer exceeds 500 mΨ. + + +Glimmer drains are quite effective at draining glimmer, taking it out as fast as a prober can put it in. + + +[color=#a4885c]Ectoplasm[/color], combined in a beaker with equal parts water, ash, blood, and plasma, will produce a normality crystal when heated enough. [color=#fcdf03]Use a hot plate for this.[/color] +Ectoplasm is needed for the construction of Glimmer Drains, and is a very rare substance that can only be obtained from noöspheric entities. + +## Mind Breaking + + + + + +Mind Breaking is the act of permanently destroyed an individual's link to the noösphere, and as such is considered by space law to be an act equivalent to Murder. It is NOT the job of any individual +on the station to go about mind breaking all psionics, such a thing must not be taken likely, and should only be performed under extreme circumstances. Once mind broken, an individual loses an essential +spark of humanity, making it so that for the rest of their natural life, they can never again be a psychic. + +Mind Breaking is performed by either imbibing a pill of Mindbreaker Toxin, or an injection of Soulbreaker. It is to be performed only as an emergency measure during a Code White situation, and only with +the permission of the station's Commanding Officer. Mind Breaking may also be given by the station's Commanding Officer as a Capital level punishment for the most egregious crimes, such as using psychic +powers to commit heinous acts. + + diff --git a/Resources/ServerInfo/Nyanotrasen/Guidebook/Epistemics/Psionics.xml b/Resources/ServerInfo/Nyanotrasen/Guidebook/Epistemics/Psionics.xml deleted file mode 100644 index 2911dae1557..00000000000 --- a/Resources/ServerInfo/Nyanotrasen/Guidebook/Epistemics/Psionics.xml +++ /dev/null @@ -1,73 +0,0 @@ - -# Psionics -[color=#a4885c]Psionics[/color] are mental abilities that interface with the [color=#a4885c]noösphere[/color]. Humans have limited access to the noösphere's full potential, allowing some to find ways to command it. -The abilities originate from distorting a noöspheric imprint into a specific shape, a bit like a lock and key. This means that humans can only have a single ability at a time. -An imprint shaped for metapsionics will not work for invisibility, and vice versa. - - -Many other creatures are much more in tune with it than humans, allowing them to access more powerful psionics like [color=#a4885c]kineses[/color]. - -## Telepathy -All psionic entities have a shared telepathic communication channel. It's anonymized, so you never know who you are talking to. Statistically, it probably is not human. - -## Glimmer -[color=#a4885c]Glimmer[/color] is a more colloquial term for [color=#a4885c]noöspheric pressure[/color], measured in [color=#a4885c]milli-Psi (mΨ)[/color]. The noösphere can be considered analogous to an atmosphere. In a localized area, everything will equalize towards a certain pressure that's based off of the total energy in the system. -Note that unlike atmospheres, areas of noopsheric pressure do not operate by physical contigiousness, but mental. This means that areas with intertwined destinies will experience the same latent glimmer regardless of physical separation. - - -The [color=#a4885c]sophic scribe[/color] tracks glimmer. - - - - - - -Epistemics can build devices to interact with glimmer. These are usually the main determiners of where glimmer is going. -[color=#a4885c]Glimmer probers[/color] will increase glimmer, but directly generate research points without further input. [color=#a4885c]Glimmer drains[/color] simply drain glimmer at the cost of electricity. - -Use of psionics will increase glimmer, as will [color=#a4885c]noöspheric storms[/color]. - -## Discharges -Glimmer will occasionally discharge if it's above 100 mΨ, causing a wide range of effects based on just how high it is. The most common is giving all entities with psionic potential a small seizure, -which is something most people working on stations with an Epistemics department have grown used to. - -## Acquiring Psionics - - -Psionics can be acquired in a number of ways. The oracle will sometimes dispense a strange liquid called [color=#a4885c]lotophagoi oil[/color], which at high glimmer levels is guaranteed to give psionics. - -Random discharges may give you psionics as the seizure knocks your noöspheric imprint into just the right shape. - -[color=#a4885c]Space drugs[/color] are an easier to acquire but much weaker alternative to lotophagoi oil. - -## Psionic Insulation - - - - - -[color=#a4885c]Insulative clothing[/color] and [color=#a4885c]cryptobiolin[/color] will render you immune to psionics, but prevent you from using any you have. - - -Security has a more forcible option for insulative clothing. - -## Handling Glimmer Emergencies - -Probers should be turned off before glimmer exceeds 500 mΨ. - - -Glimmer drains are quite effective at draining glimmer, taking it out as fast as a prober can put it in. - - -Sacrificing psychics will reduce glimmer instantly by a decent amount. - - -Metabolizing 20u or more of [color=#a4885c]mindbreaker[/color] will remove psionics from a person, meaning they will not generate any more glimmer. - - -[color=#a4885c]Soulbreaker[/color] shells will remove psionics from psychics they hit. - - -[color=#a4885c]Ectoplasm[/color], combined in a beaker with equal parts water, ash, blood, and plasma, will produce a normality crystal when heated enough. [color=#fcdf03]Use a hot plate for this.[/color] - - From bf981e4ab0da8e090cef7ba11aa27931f87c969d Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Sun, 16 Jun 2024 18:02:06 -0400 Subject: [PATCH 42/82] update guidebook --- Resources/Prototypes/Guidebook/psionics.yml | 9 +++++++++ .../Prototypes/Nyanotrasen/Guidebook/epistemics.yml | 10 ---------- 2 files changed, 9 insertions(+), 10 deletions(-) create mode 100644 Resources/Prototypes/Guidebook/psionics.yml diff --git a/Resources/Prototypes/Guidebook/psionics.yml b/Resources/Prototypes/Guidebook/psionics.yml new file mode 100644 index 00000000000..6dbc012915a --- /dev/null +++ b/Resources/Prototypes/Guidebook/psionics.yml @@ -0,0 +1,9 @@ +- type: guideEntry + id: Psionics + name: guide-entry-psionics + text: "/ServerInfo/Guidebook/Psionics.xml" + +# - type: guideEntry # When it's added +# id: AltarsGolemancy +# name: guide-entry-altars-golemancy +# text: "/ServerInfo/Nyanotrasen/Guidebook/Epistemics/Altar.xml" diff --git a/Resources/Prototypes/Nyanotrasen/Guidebook/epistemics.yml b/Resources/Prototypes/Nyanotrasen/Guidebook/epistemics.yml index 77b180d6ea1..1e2ace9a287 100644 --- a/Resources/Prototypes/Nyanotrasen/Guidebook/epistemics.yml +++ b/Resources/Prototypes/Nyanotrasen/Guidebook/epistemics.yml @@ -1,13 +1,3 @@ -- type: guideEntry - id: Psionics - name: guide-entry-psionics - text: "/ServerInfo/Nyanotrasen/Guidebook/Epistemics/Psionics.xml" - -# - type: guideEntry # When it's added -# id: AltarsGolemancy -# name: guide-entry-altars-golemancy -# text: "/ServerInfo/Nyanotrasen/Guidebook/Epistemics/Altar.xml" - - type: guideEntry id: ReverseEngineering name: guide-entry-reverse-engineering From e6e69c06de14a6ecb1f543816a797c73a7eba13f Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Thu, 20 Jun 2024 21:37:52 -0400 Subject: [PATCH 43/82] Now featuring trait points --- Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl | 4 ---- Resources/Locale/en-US/traits/categories.ftl | 1 + Resources/Locale/en-US/traits/traits.ftl | 5 +++++ Resources/Prototypes/Traits/categories.yml | 3 +++ Resources/Prototypes/{Nyanotrasen => }/Traits/psionics.yml | 4 ++-- 5 files changed, 11 insertions(+), 6 deletions(-) rename Resources/Prototypes/{Nyanotrasen => }/Traits/psionics.yml (54%) diff --git a/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl b/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl index d46a05e9c98..02800953b1e 100644 --- a/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl +++ b/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl @@ -70,7 +70,3 @@ action-description-psychokinesis = Bend the fabric of space to instantly move ac action-name-rf-sensitivity = Toggle RF Sensitivity action-desc-rf-sensitivity = Toggle your ability to interpret radio waves on and off. - -trait-latent-psychic-desc = Your mind and soul are open to the noosphere, allowing for a limited use of Telepathy. - Thus, you are eligible for potentially receiving psychic powers. - It is possible that you may be hunted by otherworldly forces, so consider keeping your powers a secret. diff --git a/Resources/Locale/en-US/traits/categories.ftl b/Resources/Locale/en-US/traits/categories.ftl index 56f0adeb479..153f8d01709 100644 --- a/Resources/Locale/en-US/traits/categories.ftl +++ b/Resources/Locale/en-US/traits/categories.ftl @@ -6,3 +6,4 @@ trait-category-Mental = Mental trait-category-Physical = Physical trait-category-Speech = Speech trait-category-Visual = Visual +trait-category-Psionic = Psionic diff --git a/Resources/Locale/en-US/traits/traits.ftl b/Resources/Locale/en-US/traits/traits.ftl index e9163bdb548..bfda7e48be7 100644 --- a/Resources/Locale/en-US/traits/traits.ftl +++ b/Resources/Locale/en-US/traits/traits.ftl @@ -31,3 +31,8 @@ trait-description-SocialAnxiety = You are anxious when you speak and stutter. trait-name-Snoring = Snoring trait-description-Snoring = You will snore while sleeping. + +trait-name-LatentPsychic = Latent Psychic +trait-description-LatentPsychic = Your mind and soul are open to the noosphere, allowing for a limited use of Telepathy. + Thus, you are eligible for potentially receiving psychic powers. + It is possible that you may be hunted by otherworldly forces, so consider keeping your powers a secret. diff --git a/Resources/Prototypes/Traits/categories.yml b/Resources/Prototypes/Traits/categories.yml index ba3fd7b3456..617aa5f2f91 100644 --- a/Resources/Prototypes/Traits/categories.yml +++ b/Resources/Prototypes/Traits/categories.yml @@ -17,3 +17,6 @@ - type: traitCategory id: Visual + +- type: traitCategory + id: Psionic diff --git a/Resources/Prototypes/Nyanotrasen/Traits/psionics.yml b/Resources/Prototypes/Traits/psionics.yml similarity index 54% rename from Resources/Prototypes/Nyanotrasen/Traits/psionics.yml rename to Resources/Prototypes/Traits/psionics.yml index 5fef3427703..01c8a5750eb 100644 --- a/Resources/Prototypes/Nyanotrasen/Traits/psionics.yml +++ b/Resources/Prototypes/Traits/psionics.yml @@ -1,6 +1,6 @@ - type: trait id: LatentPsychic - name: Latent Psychic - description: trait-latent-psychic-desc + category: Psionic + points: -1 components: - type: PotentialPsionic From df7a78bd7974fea56a90812728dee5cb3d23546e Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Mon, 24 Jun 2024 17:48:57 -0400 Subject: [PATCH 44/82] Fix fireball bug --- Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs index e488aac7879..3dabf2fd9b4 100644 --- a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs @@ -76,7 +76,7 @@ private void OnPowerUsed(PyrokinesisPowerActionEvent args) } } - var direction = args.Target.Position; + var direction = args.Target.ToMapPos(EntityManager, _xform) - spawnCoords.ToMapPos(EntityManager, _xform); _gunSystem.ShootProjectile(ent, direction, new System.Numerics.Vector2(0, 0), args.Performer, args.Performer, 20f); From 2c49d79364b76d72280e4e4681c31d830188bb74 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Mon, 24 Jun 2024 18:51:47 -0400 Subject: [PATCH 45/82] Update LogPowerUsed --- Content.Server/Abilities/Mime/MimePowersSystem.cs | 4 +--- .../Psionics/Abilities/DispelPowerSystem.cs | 7 ++++--- .../Psionics/Abilities/MetapsionicPowerSystem.cs | 9 +++------ .../Psionics/Abilities/MindSwapPowerSystem.cs | 2 +- .../Abilities/NoosphericZapPowerSystem.cs | 4 +--- .../Abilities/PsionicRegenerationPowerSystem.cs | 8 ++------ .../Psionics/Abilities/PyrokinesisPowerSystem.cs | 4 +--- .../Abilities/RegenerativeStasisPowerSystem.cs | 8 ++++---- .../Psionics/Abilities/TelegnosisPowerSystem.cs | 4 +--- .../PsionicInvisibilityPowerSystem.cs | 15 ++++++++++----- .../Psionics/SharedPsionicAbilitiesSystem.cs | 11 +++++++++-- .../nyanotrasen/psionics/psychic-feedback.ftl | 1 + 12 files changed, 38 insertions(+), 39 deletions(-) diff --git a/Content.Server/Abilities/Mime/MimePowersSystem.cs b/Content.Server/Abilities/Mime/MimePowersSystem.cs index 9c108c4bcf2..0a40350889e 100644 --- a/Content.Server/Abilities/Mime/MimePowersSystem.cs +++ b/Content.Server/Abilities/Mime/MimePowersSystem.cs @@ -105,9 +105,7 @@ private void OnInvisibleWall(EntityUid uid, MimePowersComponent component, Invis } } if (TryComp(uid, out var psionic)) - _psionics.LogPowerUsed(uid, "invisible wall", - (int) Math.Round(4 * psionic.Amplification - psionic.Dampening), - (int) Math.Round(6 * psionic.Amplification - psionic.Dampening)); + _psionics.LogPowerUsed(uid, "invisible wall", psionic, 4, 6); _popupSystem.PopupEntity(Loc.GetString("mime-invisible-wall-popup", ("mime", uid)), uid); // Make sure we set the invisible wall to despawn properly diff --git a/Content.Server/Psionics/Abilities/DispelPowerSystem.cs b/Content.Server/Psionics/Abilities/DispelPowerSystem.cs index 67176c3a3d2..3489b15bcf3 100644 --- a/Content.Server/Psionics/Abilities/DispelPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/DispelPowerSystem.cs @@ -1,6 +1,7 @@ using Content.Shared.Actions; using Content.Shared.StatusEffect; using Content.Shared.Psionics.Abilities; +using Content.Shared.Psionics.Glimmer; using Content.Shared.Damage; using Content.Shared.Revenant.Components; using Content.Server.Guardian; @@ -23,6 +24,7 @@ public sealed class DispelPowerSystem : EntitySystem [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; + [Dependency] private readonly GlimmerSystem _glimmerSystem = default!; public override void Initialize() @@ -81,9 +83,8 @@ private void OnPowerUsed(DispelPowerActionEvent args) if (ev.Handled) { args.Handled = true; - _psionics.LogPowerUsed(args.Performer, "dispel", - (int) MathF.Round(-4 * psionic.Dampening + psionic.Amplification), - (int) MathF.Round(-2 * psionic.Dampening + psionic.Amplification)); + _psionics.LogPowerUsed(args.Performer, "dispel", psionic, 1, 1, true); + _glimmerSystem.Glimmer -= _random.Next((int) Math.Round(2 * psionic.Dampening), (int) Math.Round(4 - psionic.Amplification)); } } diff --git a/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs b/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs index dac38290f22..d74f5efa430 100644 --- a/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs @@ -6,7 +6,6 @@ using Robust.Server.Audio; using Robust.Shared.Audio; using Robust.Shared.Timing; -using Content.Server.DoAfter; using Content.Shared.Psionics.Events; namespace Content.Server.Psionics.Abilities @@ -18,7 +17,7 @@ public sealed class MetapsionicPowerSystem : EntitySystem [Dependency] private readonly SharedPopupSystem _popups = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; [Dependency] private readonly AudioSystem _audioSystem = default!; @@ -95,9 +94,7 @@ private void OnWidePowerUsed(EntityUid uid, MetapsionicPowerComponent component, } } _popups.PopupEntity(Loc.GetString("metapsionic-pulse-failure"), uid, uid, PopupType.Large); - _psionics.LogPowerUsed(uid, "metapsionic pulse", - (int) MathF.Round(2 * psionic.Amplification - psionic.Dampening), - (int) MathF.Round(4 * psionic.Amplification - psionic.Dampening)); + _psionics.LogPowerUsed(uid, "metapsionic pulse", psionic, 2, 4); UpdateActions(uid, component); args.Handled = true; } @@ -128,7 +125,7 @@ private void OnFocusedPowerUsed(FocusedMetapsionicPowerActionEvent args) _popups.PopupEntity(Loc.GetString("focused-metapsionic-pulse-begin", ("entity", args.Target)), args.Performer, PopupType.Medium); _audioSystem.PlayPvs(component.SoundUse, args.Performer, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); - _psionics.LogPowerUsed(args.Performer, "focused metapsionic pulse", + _psionics.LogPowerUsed(args.Performer, "focused metapsionic pulse", psionic, (int) MathF.Round(3 * psionic.Amplification - psionic.Dampening), (int) MathF.Round(6 * psionic.Amplification - psionic.Dampening)); args.Handled = true; diff --git a/Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs b/Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs index b0e27027ad5..25f0434c797 100644 --- a/Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/MindSwapPowerSystem.cs @@ -78,7 +78,7 @@ private void OnPowerUsed(MindSwapPowerActionEvent args) Swap(args.Performer, args.Target); - _psionics.LogPowerUsed(args.Performer, "mind swap", (int) MathF.Round(psionic.Amplification / psionic.Dampening * 8), (int) MathF.Round(psionic.Amplification / psionic.Dampening * 12)); + _psionics.LogPowerUsed(args.Performer, "mind swap", psionic, 8, 12); args.Handled = true; } diff --git a/Content.Server/Psionics/Abilities/NoosphericZapPowerSystem.cs b/Content.Server/Psionics/Abilities/NoosphericZapPowerSystem.cs index c935bc0123d..8ab128cc1d6 100644 --- a/Content.Server/Psionics/Abilities/NoosphericZapPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/NoosphericZapPowerSystem.cs @@ -69,9 +69,7 @@ private void OnPowerUsed(NoosphericZapPowerActionEvent args) _statusEffectsSystem.TryAddStatusEffect(args.Target, "Stutter", TimeSpan.FromSeconds(2 * psionic.Amplification), false, "StutteringAccent"); - _psionics.LogPowerUsed(args.Performer, "noopsheric zap", - (int) MathF.Round(6 * psionic.Amplification - psionic.Dampening), - (int) MathF.Round(8 * psionic.Amplification - psionic.Dampening)); + _psionics.LogPowerUsed(args.Performer, "noopsheric zap", psionic, 6, 8); args.Handled = true; } } diff --git a/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs b/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs index 715774ae1c7..15fc092ebcf 100644 --- a/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicRegenerationPowerSystem.cs @@ -73,9 +73,7 @@ private void OnPowerUsed(EntityUid uid, PsionicRegenerationPowerComponent compon _popupSystem.PopupEntity(Loc.GetString("psionic-regeneration-begin", ("entity", uid)), uid, PopupType.Medium); _audioSystem.PlayPvs(component.SoundUse, uid, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); - _psionics.LogPowerUsed(uid, "psionic regeneration", - (int) Math.Round(6 * psionic.Amplification - psionic.Dampening), - (int) Math.Round(8 * psionic.Amplification - psionic.Dampening)); + _psionics.LogPowerUsed(uid, "psionic regeneration", psionic, 6, 8); args.Handled = true; } @@ -116,9 +114,7 @@ private void OnMobStateChangedEvent(EntityUid uid, PsionicRegenerationPowerCompo _popupSystem.PopupEntity(Loc.GetString("psionic-regeneration-self-revive", ("entity", uid)), uid, PopupType.MediumCaution); _audioSystem.PlayPvs(component.SoundUse, uid, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); - _psionics.LogPowerUsed(uid, "psionic regeneration", - (int) Math.Round(10 * psionic.Amplification - 2 * psionic.Dampening), - (int) Math.Round(20 * psionic.Amplification - 2 * psionic.Dampening)); + _psionics.LogPowerUsed(uid, "psionic regeneration", psionic, 10, 20); _actions.StartUseDelay(component.PsionicRegenerationActionEntity); } diff --git a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs index 3dabf2fd9b4..05c1e6ff46f 100644 --- a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs @@ -80,9 +80,7 @@ private void OnPowerUsed(PyrokinesisPowerActionEvent args) _gunSystem.ShootProjectile(ent, direction, new System.Numerics.Vector2(0, 0), args.Performer, args.Performer, 20f); - _psionics.LogPowerUsed(args.Performer, "pyrokinesis", - (int) MathF.Round(6f * psionic.Amplification - psionic.Dampening), - (int) MathF.Round(8f * psionic.Amplification - psionic.Dampening)); + _psionics.LogPowerUsed(args.Performer, "pyrokinesis", psionic, 6, 8); args.Handled = true; } } diff --git a/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs b/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs index be435d1acc5..cc67badbe72 100644 --- a/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/RegenerativeStasisPowerSystem.cs @@ -2,6 +2,7 @@ using Content.Server.Body.Components; using Content.Shared.Actions; using Content.Shared.Chemistry.Components; +using Content.Shared.Popups; using Content.Shared.Psionics.Abilities; using Content.Shared.Actions.Events; using Content.Shared.FixedPoint; @@ -13,6 +14,7 @@ public sealed class MassSleepPowerSystem : EntitySystem [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; public override void Initialize() { @@ -61,10 +63,8 @@ private void OnPowerUsed(EntityUid uid, RegenerativeStasisPowerComponent compone solution.AddReagent("Epinephrine", FixedPoint2.New(MathF.Min(2.5f * psionic.Dampening + psionic.Amplification, 15f))); solution.AddReagent("Nocturine", 10f + (1 * psionic.Amplification + psionic.Dampening)); _bloodstreamSystem.TryAddToChemicals(args.Target, solution, stream); - - _psionics.LogPowerUsed(uid, "regenerative stasis", - (int) Math.Round(4 * psionic.Amplification - psionic.Dampening), - (int) Math.Round(6 * psionic.Amplification - psionic.Dampening)); + _popupSystem.PopupEntity(Loc.GetString("regenerative-stasis-begin", ("entity", uid)), uid, PopupType.Medium); + _psionics.LogPowerUsed(uid, "regenerative stasis", psionic, 4, 6); args.Handled = true; } } diff --git a/Content.Server/Psionics/Abilities/TelegnosisPowerSystem.cs b/Content.Server/Psionics/Abilities/TelegnosisPowerSystem.cs index f03b001fc70..c5f8471a654 100644 --- a/Content.Server/Psionics/Abilities/TelegnosisPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/TelegnosisPowerSystem.cs @@ -70,9 +70,7 @@ private void OnPowerUsed(EntityUid uid, TelegnosisPowerComponent component, Tele if (EnsureComp(projection, out var projectionComponent)) projectionComponent.OriginalEntity = uid; - _psionics.LogPowerUsed(uid, "telegnosis", - (int) Math.Round(8f * psionic.Amplification - psionic.Dampening), - (int) Math.Round(12f * psionic.Amplification - psionic.Dampening)); + _psionics.LogPowerUsed(uid, "telegnosis", psionic, 8, 12); args.Handled = true; } diff --git a/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerSystem.cs b/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerSystem.cs index 29ee615dd49..540dc03341b 100644 --- a/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerSystem.cs +++ b/Content.Shared/Psionics/Abilities/PsionicInvisibility/PsionicInvisibilityPowerSystem.cs @@ -6,6 +6,7 @@ using Content.Shared.Stealth.Components; using Content.Shared.Psionics.Events; using Content.Shared.Actions.Events; +using Robust.Shared.Network; using Robust.Shared.Audio.Systems; using Content.Shared.Interaction.Events; using Content.Shared.Weapons.Ranged.Events; @@ -23,6 +24,7 @@ public sealed class PsionicInvisibilityPowerSystem : EntitySystem [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly INetManager _net = default!; public override void Initialize() { @@ -86,9 +88,7 @@ private void OnPowerUsed(EntityUid uid, PsionicInvisibilityPowerComponent compon invis.DoAfter = doAfterId; } - _psionics.LogPowerUsed(uid, "psionic invisibility", - (int) MathF.Round(8 * psionic.Amplification - 2 * psionic.Dampening), - (int) MathF.Round(12 * psionic.Amplification - 2 * psionic.Dampening)); + _psionics.LogPowerUsed(uid, "psionic invisibility", psionic, 8, 12); args.Handled = true; } } @@ -104,7 +104,9 @@ private void OnStart(EntityUid uid, PsionicInvisibilityUsedComponent component, EnsureComp(uid); var stealth = EnsureComp(uid); _stealth.SetVisibility(uid, 0.66f, stealth); - _audio.PlayPvs("/Audio/Effects/toss.ogg", uid); + + if (_net.IsServer) + _audio.PlayPvs("/Audio/Effects/toss.ogg", uid); } @@ -116,7 +118,10 @@ private void OnEnd(EntityUid uid, PsionicInvisibilityUsedComponent component, Co _doAfterSystem.Cancel(component.DoAfter); RemComp(uid); RemComp(uid); - _audio.PlayPvs("/Audio/Effects/toss.ogg", uid); + + if (_net.IsServer) + _audio.PlayPvs("/Audio/Effects/toss.ogg", uid); + _actions.RemoveAction(uid, component.PsionicInvisibilityUsedActionEntity); DirtyEntity(uid); } diff --git a/Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs b/Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs index 603c5188a52..cf3bafab5ad 100644 --- a/Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs +++ b/Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs @@ -82,13 +82,20 @@ private bool IsEligibleForPsionics(EntityUid uid) && (!TryComp(uid, out var mobstate) || mobstate.CurrentState == MobState.Alive); } - public void LogPowerUsed(EntityUid uid, string power, int minGlimmer = 8, int maxGlimmer = 12) + public void LogPowerUsed(EntityUid uid, string power, PsionicComponent? psionic = null, int minGlimmer = 8, int maxGlimmer = 12, bool overrideGlimmer = false) { _adminLogger.Add(Database.LogType.Psionics, Database.LogImpact.Medium, $"{ToPrettyString(uid):player} used {power}"); var ev = new PsionicPowerUsedEvent(uid, power); RaiseLocalEvent(uid, ev, false); - _glimmerSystem.Glimmer += _robustRandom.Next(minGlimmer, maxGlimmer); + if (!overrideGlimmer) + { + if (psionic == null) + _glimmerSystem.Glimmer += _robustRandom.Next(minGlimmer, maxGlimmer); + else _glimmerSystem.Glimmer += _robustRandom.Next( + (int) Math.Round(minGlimmer * psionic.Amplification - psionic.Dampening), + (int) Math.Round(maxGlimmer * psionic.Amplification - psionic.Dampening)); + } } } diff --git a/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl b/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl index 4af3ae267b3..446573b7a99 100644 --- a/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl +++ b/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl @@ -42,6 +42,7 @@ anomaly-shadow-feedback = At the end of time, when all suns have set forever, th focused-metapsionic-pulse-begin = The air around {CAPITALIZE($entity)} begins to shimmer faintly psionic-regeneration-self-revive = {CAPITALIZE($entity)} begins to visibly regenerate mindbreaking-feedback = The light of life vanishes from {CAPITALIZE($entity)}'s eyes, leaving behind a husk pretending at sapience +regenerative-stasis-begin = {CAPITALIZE($entity)} swoons for a moment, then begins visibly regenerating # Misc Psionic Messages telepathic-mute-message = You strain, but are unable to send your thoughts to the Noosphere From c4890df868e22a286f8ee9df5b6ccb96e31b12a4 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Mon, 24 Jun 2024 22:47:26 -0400 Subject: [PATCH 46/82] Fixing bug with starting stat modifiers --- Content.Server/Psionics/PsionicsSystem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Content.Server/Psionics/PsionicsSystem.cs b/Content.Server/Psionics/PsionicsSystem.cs index 7e97af34b80..04a7597c900 100644 --- a/Content.Server/Psionics/PsionicsSystem.cs +++ b/Content.Server/Psionics/PsionicsSystem.cs @@ -84,8 +84,8 @@ private void OnMeleeHit(EntityUid uid, AntiPsionicWeaponComponent component, Mel } private void OnStartup(EntityUid uid, PsionicComponent component, MapInitEvent args) { - component.Amplification = _random.NextFloat(0.3f, 1.1f); - component.Dampening = _random.NextFloat(0.3f, 1.1f); + component.Amplification += _random.NextFloat(0.3f, 1.1f); + component.Dampening += _random.NextFloat(0.3f, 1.1f); } private void OnInit(EntityUid uid, PsionicComponent component, ComponentInit args) { From afff07816ec32ac465b77bb37f61ab8c793c81ed Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Wed, 26 Jun 2024 19:00:18 -0400 Subject: [PATCH 47/82] More updates --- .../Abilities/MetapsionicPowerSystem.cs | 7 ++-- .../Abilities/PyrokinesisPowerSystem.cs | 32 +++++++++---------- .../Structures/GlimmerStructuresSystem.cs | 8 +++++ .../nyanotrasen/psionics/psychic-feedback.ftl | 1 + .../Entities/Mobs/NPCs/glimmer_creatures.yml | 4 +++ 5 files changed, 31 insertions(+), 21 deletions(-) diff --git a/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs b/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs index d74f5efa430..8c72a02737b 100644 --- a/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/MetapsionicPowerSystem.cs @@ -125,9 +125,7 @@ private void OnFocusedPowerUsed(FocusedMetapsionicPowerActionEvent args) _popups.PopupEntity(Loc.GetString("focused-metapsionic-pulse-begin", ("entity", args.Target)), args.Performer, PopupType.Medium); _audioSystem.PlayPvs(component.SoundUse, args.Performer, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f)); - _psionics.LogPowerUsed(args.Performer, "focused metapsionic pulse", psionic, - (int) MathF.Round(3 * psionic.Amplification - psionic.Dampening), - (int) MathF.Round(6 * psionic.Amplification - psionic.Dampening)); + _psionics.LogPowerUsed(args.Performer, "focused metapsionic pulse", psionic, 3, 6); args.Handled = true; UpdateActions(args.Performer, component); @@ -137,7 +135,8 @@ private void OnDoAfter(EntityUid uid, MetapsionicPowerComponent component, Focus { component.DoAfter = null; - if (args.Target == null) return; + if (args.Target == null || args.Cancelled) + return; if (TryComp(args.Target, out var swapped)) { diff --git a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs index 05c1e6ff46f..c69e05af452 100644 --- a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs @@ -1,5 +1,6 @@ using Content.Shared.Actions; using Content.Shared.Psionics.Abilities; +using Content.Shared.Psionics.Glimmer; using Content.Server.Atmos.Components; using Content.Server.Weapons.Ranged.Systems; using Robust.Server.GameObjects; @@ -15,7 +16,7 @@ public sealed class PyrokinesisPowerSystem : EntitySystem [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly GunSystem _gunSystem = default!; - [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly GlimmerSystem _glimmerSystem = default!; public override void Initialize() { base.Initialize(); @@ -51,29 +52,26 @@ private void OnShutdown(EntityUid uid, PyrokinesisPowerComponent component, Comp private void OnPowerUsed(PyrokinesisPowerActionEvent args) { - if (!TryComp(args.Performer, out var psionic)) - return; - - if (!HasComp(args.Performer)) + if (!HasComp(args.Performer) + && TryComp(args.Performer, out var psionic)) { - var xformQuery = GetEntityQuery(); - var xform = xformQuery.GetComponent(args.Performer); - - var mapPos = xform.Coordinates.ToMap(EntityManager, _xform); - var spawnCoords = _mapManager.TryFindGridAt(mapPos, out var gridUid, out _) - ? xform.Coordinates.WithEntityId(gridUid, EntityManager) - : new(_mapManager.GetMapEntityId(mapPos.MapId), mapPos.Position); + var spawnCoords = Transform(args.Performer).Coordinates; var ent = Spawn("ProjectileAnomalyFireball", spawnCoords); if (TryComp(ent, out var fireball)) { - fireball.MaxIntensity = (int) MathF.Round(20 * psionic.Amplification - 10 * psionic.Dampening); + fireball.MaxIntensity = (int) MathF.Round(5 * psionic.Amplification); + fireball.IntensitySlope = (int) MathF.Round(1 * psionic.Amplification); + fireball.TotalIntensity = (int) MathF.Round(10 * psionic.Amplification); + + if (_glimmerSystem.Glimmer >= 500) + fireball.CanCreateVacuum = true; + else fireball.CanCreateVacuum = false; - if (psionic.Amplification > 5 && EnsureComp(ent, out var ignite)) - { - ignite.FireStacks = 0.2f * psionic.Amplification - 0.1f * psionic.Dampening; - } + if (psionic.Amplification > 5) + if (EnsureComp(ent, out var ignite)) + ignite.FireStacks = 0.2f * psionic.Amplification; } var direction = args.Target.ToMapPos(EntityManager, _xform) - spawnCoords.ToMapPos(EntityManager, _xform); diff --git a/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs b/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs index 75125569cb5..5d16c4e5e42 100644 --- a/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs +++ b/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs @@ -2,6 +2,7 @@ using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Shared.Anomaly.Components; +using Content.Shared.Mobs; using Content.Shared.Psionics.Glimmer; namespace Content.Server.Psionics.Glimmer @@ -22,6 +23,7 @@ public override void Initialize() SubscribeLocalEvent(OnAnomalyPulse); SubscribeLocalEvent(OnAnomalySupercritical); + SubscribeLocalEvent(OnMobStateChanged); } private void OnAnomalyVesselPowerChanged(EntityUid uid, AnomalyVesselComponent component, ref PowerChangedEvent args) @@ -53,6 +55,12 @@ private void OnAnomalySupercritical(EntityUid uid, GlimmerSourceComponent compon _glimmerSystem.Glimmer += 100; } + private void OnMobStateChanged(EntityUid uid, GlimmerSourceComponent component, ref MobStateChangedEvent args) + { + if (args.NewMobState != MobState.Alive) + component.Active = false; + } + public override void Update(float frameTime) { base.Update(frameTime); diff --git a/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl b/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl index 446573b7a99..2add055f7bd 100644 --- a/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl +++ b/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl @@ -25,6 +25,7 @@ oracle-feedback = WHY DO YOU BOTHER ME SEEKER? HAVE I NOT MADE MY DESIRES CLEAR? orecrab-feedback = Heralds of the Lord of Earth, summoned to this realm from Grome's kingdom reagent-slime-feedback = Heralds of the Lord of Water, summoned to this realm from Straasha's kingdom. flesh-golem-feedback = Abominations pulled from dead realms, twisted amalgamations of those fallen to the influence of primordial Chaos +glimmer-mite-feedback = A semi-corporeal parasite native to the dreamlight, its presence here brings forth the screams of dead stars. # Anomaly Feedback Messages anomaly-pyroclastic-feedback = A small mirror to the plane of Gehenna, truth lies within the Secret of Fire diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/glimmer_creatures.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/glimmer_creatures.yml index e3eb9cd6de8..1f1000f04a7 100644 --- a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/glimmer_creatures.yml +++ b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/glimmer_creatures.yml @@ -24,6 +24,10 @@ Quantity: 15 - type: PotentialPsionic - type: Psionic + removable: false + amplification: 1 + psychicFeedback: + - "glimmer-mite-feedback" - type: GlimmerSource - type: AmbientSound range: 6 From d0cb65af8f5d3ed6c8d97d3fd4bb920ca2fce2ea Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Thu, 27 Jun 2024 21:04:42 -0400 Subject: [PATCH 48/82] Partial Glimmer Refactor & Pyromancy Full Refactor --- .../ChangeGlimmerReactionEffect.cs | 2 +- .../Systems/RaiseGlimmerConditionSystem.cs | 5 +- .../Research/Oracle/OracleSystem.cs | 2 +- .../SophicScribe/SophicScribeSystem.cs | 8 +- .../StationEvents/Events/FreeProberRule.cs | 2 +- .../Events/GlimmerEventSystem.cs | 2 +- .../StationEvents/Events/NoosphericFryRule.cs | 4 +- .../Events/NoosphericStormRule.cs | 2 +- .../Psionics/Abilities/DispelPowerSystem.cs | 2 +- .../Abilities/PsionicAbilitiesSystem.cs | 4 +- .../Abilities/PyrokinesisPowerSystem.cs | 87 +++++++++++++++++-- .../Psionics/Glimmer/GlimmerCommands.cs | 4 +- .../Psionics/Glimmer/GlimmerReactiveSystem.cs | 18 ++-- .../Glimmer/PassiveGlimmerReductionSystem.cs | 43 +++------ .../Structures/GlimmerStructuresSystem.cs | 8 +- Content.Server/Psionics/PsionicsSystem.cs | 2 +- .../Psionics/Telepathy/TelepathyChatSystem.cs | 6 +- .../StationEvents/EventManagerSystem.cs | 4 +- .../Systems/ArtifactAnalyzerSystem.cs | 4 +- Content.Shared/CCVar/CCVars.cs | 8 +- .../Events/PyrokinesisPowerActionEvent.cs | 1 + .../Pyrokinesis/PyrokinesisPowerComponent.cs | 28 +++++- .../PyrokinesisPrechargeComponent.cs | 0 Content.Shared/Psionics/Events.cs | 18 ++++ .../Psionics/Glimmer/GlimmerSystem.cs | 77 ++++++++++++++-- .../Psionics/SharedPsionicAbilitiesSystem.cs | 8 +- .../customization/character-requirements.ftl | 2 +- .../en-US/nyanotrasen/abilities/psionic.ftl | 5 +- .../nyanotrasen/psionics/psychic-feedback.ftl | 4 + Resources/Locale/en-US/traits/traits.ftl | 12 +++ .../Prototypes/Nyanotrasen/Actions/types.yml | 16 +++- Resources/Prototypes/Traits/psionics.yml | 33 +++++++ 32 files changed, 317 insertions(+), 104 deletions(-) create mode 100644 Content.Shared/Psionics/Abilities/Pyrokinesis/PyrokinesisPrechargeComponent.cs diff --git a/Content.Server/Nyanotrasen/Chemistry/ReactionEffects/ChangeGlimmerReactionEffect.cs b/Content.Server/Nyanotrasen/Chemistry/ReactionEffects/ChangeGlimmerReactionEffect.cs index 65aaf350cba..cd7010700a1 100644 --- a/Content.Server/Nyanotrasen/Chemistry/ReactionEffects/ChangeGlimmerReactionEffect.cs +++ b/Content.Server/Nyanotrasen/Chemistry/ReactionEffects/ChangeGlimmerReactionEffect.cs @@ -21,6 +21,6 @@ public override void Effect(ReagentEffectArgs args) { var glimmersys = args.EntityManager.EntitySysManager.GetEntitySystem(); - glimmersys.Glimmer += Count; + glimmersys.DeltaGlimmerInput(Count); } } diff --git a/Content.Server/Nyanotrasen/Objectives/Systems/RaiseGlimmerConditionSystem.cs b/Content.Server/Nyanotrasen/Objectives/Systems/RaiseGlimmerConditionSystem.cs index d7aae44afa7..5d2cd3fa633 100644 --- a/Content.Server/Nyanotrasen/Objectives/Systems/RaiseGlimmerConditionSystem.cs +++ b/Content.Server/Nyanotrasen/Objectives/Systems/RaiseGlimmerConditionSystem.cs @@ -6,8 +6,8 @@ namespace Content.Server.Objectives.Systems { public sealed class RaiseGlimmerConditionSystem : EntitySystem { - [Dependency] private readonly IEntitySystemManager _sysMan = default!; [Dependency] private readonly MetaDataSystem _metaData = default!; + [Dependency] private readonly GlimmerSystem _glimmer = default!; public override void Initialize() { base.Initialize(); @@ -32,8 +32,7 @@ private void OnGetProgress(EntityUid uid, RaiseGlimmerConditionComponent comp, r private float GetProgress(int target) { - var glimmer = _sysMan.GetEntitySystem().Glimmer; - var progress = Math.Min((float) glimmer / (float) target, 1f); + var progress = Math.Min((float) _glimmer.GlimmerOutput / (float) target, 1f); return progress; } } diff --git a/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs b/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs index 3a0e912c08a..c3eced61da9 100644 --- a/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs +++ b/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs @@ -166,7 +166,7 @@ private void DispenseLiquidReward(EntityUid uid, OracleComponent component) .Where(x => !x.Abstract) .Select(x => x.ID).ToList(); - var amount = 20 + _random.Next(1, 30) + _glimmerSystem.Glimmer / 10f; + var amount = 20 + _random.Next(1, 30) + _glimmerSystem.GlimmerOutput / 10f; amount = (float) Math.Round(amount); var sol = new Solution(); diff --git a/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs b/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs index b8cdcb56d47..b1a6c1e9de1 100644 --- a/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs +++ b/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs @@ -23,7 +23,7 @@ public override void Update(float frameTime) { base.Update(frameTime); - if (_glimmerSystem.Glimmer == 0) + if (_glimmerSystem.GlimmerOutput == 0) return; // yes, return. Glimmer value is global. var curTime = _timing.CurTime; @@ -37,7 +37,7 @@ public override void Update(float frameTime) if (!TryComp(scribe, out var radio)) continue; - var message = Loc.GetString("glimmer-report", ("level", _glimmerSystem.Glimmer)); + var message = Loc.GetString("glimmer-report", ("level", (int) Math.Round(_glimmerSystem.GlimmerOutput))); var channel = _prototypeManager.Index("Science"); _radioSystem.SendRadioMessage(scribe, message, channel, scribe); @@ -61,7 +61,7 @@ private void OnInteractHand(EntityUid uid, SophicScribeComponent component, Inte component.StateTime = _timing.CurTime + component.StateCD; - _chat.TrySendInGameICMessage(uid, Loc.GetString("glimmer-report", ("level", _glimmerSystem.Glimmer)), InGameICChatType.Speak, true); + _chat.TrySendInGameICMessage(uid, Loc.GetString("glimmer-report", ("level", (int) Math.Round(_glimmerSystem.GlimmerOutput))), InGameICChatType.Speak, true); } private void OnGlimmerEventEnded(GlimmerEventEndedEvent args) @@ -78,7 +78,7 @@ private void OnGlimmerEventEnded(GlimmerEventEndedEvent args) speaker = swapped.OriginalEntity; } - var message = Loc.GetString(args.Message, ("decrease", args.GlimmerBurned), ("level", _glimmerSystem.Glimmer)); + var message = Loc.GetString(args.Message, ("decrease", args.GlimmerBurned), ("level", (int) Math.Round(_glimmerSystem.GlimmerOutput))); var channel = _prototypeManager.Index("Common"); _radioSystem.SendRadioMessage(speaker, message, channel, speaker); } diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/FreeProberRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/FreeProberRule.cs index 0aa8ecc47cc..46dff726e55 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/FreeProberRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/FreeProberRule.cs @@ -36,7 +36,7 @@ protected override void Started(EntityUid uid, FreeProberRuleComponent component } } - if (PossibleSpawns.Count == 0 || _glimmerSystem.Glimmer >= 500 || _robustRandom.Prob(0.25f)) + if (PossibleSpawns.Count == 0 || _glimmerSystem.GlimmerOutput >= 500 || _robustRandom.Prob(0.25f)) { var queryBattery = EntityQueryEnumerator(); while (query.MoveNext(out var battery, out var _)) diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/GlimmerEventSystem.cs b/Content.Server/Nyanotrasen/StationEvents/Events/GlimmerEventSystem.cs index a3d36ae7157..078826604eb 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/GlimmerEventSystem.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/GlimmerEventSystem.cs @@ -13,7 +13,7 @@ protected override void Ended(EntityUid uid, GlimmerEventComponent component, Ga base.Ended(uid, component, gameRule, args); var glimmerBurned = RobustRandom.Next(component.GlimmerBurnLower, component.GlimmerBurnUpper); - _glimmerSystem.Glimmer -= glimmerBurned; + _glimmerSystem.DeltaGlimmerInput(-glimmerBurned); var reportEv = new GlimmerEventEndedEvent(component.SophicReport, glimmerBurned); RaiseLocalEvent(reportEv); diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericFryRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericFryRule.cs index 6a2c1c3ba7d..cf7b8e6cc9c 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericFryRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericFryRule.cs @@ -77,7 +77,7 @@ protected override void Started(EntityUid uid, NoosphericFryRuleComponent compon damage.DamageDict.Add("Heat", 2.5); damage.DamageDict.Add("Shock", 2.5); - if (_glimmerSystem.Glimmer > 500 && _glimmerSystem.Glimmer < 750) + if (_glimmerSystem.GlimmerOutput > 500 && _glimmerSystem.GlimmerOutput < 750) { damage *= 2; if (TryComp(pair.wearer, out var flammableComponent)) @@ -85,7 +85,7 @@ protected override void Started(EntityUid uid, NoosphericFryRuleComponent compon flammableComponent.FireStacks += 1; _flammableSystem.Ignite(pair.wearer, pair.wearer, flammableComponent); } - } else if (_glimmerSystem.Glimmer > 750) + } else if (_glimmerSystem.GlimmerOutput > 750) { damage *= 3; if (TryComp(pair.wearer, out var flammableComponent)) diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericStormRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericStormRule.cs index 8812ed1fe37..c26ab1481ac 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericStormRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericStormRule.cs @@ -54,6 +54,6 @@ protected override void Started(EntityUid uid, NoosphericStormRuleComponent comp //var glimmerSeverityMod = 1 + (component.GlimmerSeverityCoefficient * (GetSeverityModifier() - 1f)); var glimmerAdded = (int) baseGlimmerAdd; // Math.Round(baseGlimmerAdd * glimmerSeverityMod); - _glimmerSystem.Glimmer += glimmerAdded; + _glimmerSystem.DeltaGlimmerInput(glimmerAdded); } } diff --git a/Content.Server/Psionics/Abilities/DispelPowerSystem.cs b/Content.Server/Psionics/Abilities/DispelPowerSystem.cs index 3489b15bcf3..33c6b5dcaed 100644 --- a/Content.Server/Psionics/Abilities/DispelPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/DispelPowerSystem.cs @@ -84,7 +84,7 @@ private void OnPowerUsed(DispelPowerActionEvent args) { args.Handled = true; _psionics.LogPowerUsed(args.Performer, "dispel", psionic, 1, 1, true); - _glimmerSystem.Glimmer -= _random.Next((int) Math.Round(2 * psionic.Dampening), (int) Math.Round(4 - psionic.Amplification)); + _glimmerSystem.DeltaGlimmerInput(-_random.NextFloat(2 * psionic.Dampening - psionic.Amplification, 4 * psionic.Dampening - psionic.Amplification)); } } diff --git a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs index 480cf561001..9de4e412c81 100644 --- a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs @@ -58,7 +58,7 @@ public void AddRandomPsionicPower(EntityUid uid) EntityManager.AddComponent(uid, newComponent); - _glimmerSystem.Glimmer += _random.Next((int) MathF.Round(psionic.Amplification * psionic.Dampening * 1), (int) MathF.Round(psionic.Amplification * psionic.Dampening * 5)); + _glimmerSystem.DeltaGlimmerInput(_random.NextFloat(psionic.Amplification * psionic.Dampening, psionic.Amplification * psionic.Dampening * 5)); } public void RemovePsionics(EntityUid uid) @@ -96,7 +96,7 @@ public void RemovePsionics(EntityUid uid) _statusEffectsSystem.TryAddStatusEffect(uid, "Stutter", TimeSpan.FromMinutes(5), false, "StutteringAccent"); - _glimmerSystem.Glimmer += _random.Next((int) MathF.Round(psionic.Amplification * psionic.Dampening * -10), (int) MathF.Round(psionic.Amplification * psionic.Dampening * -5)); + _glimmerSystem.DeltaGlimmerOutput(-_random.NextFloat((int) MathF.Round(psionic.Amplification * psionic.Dampening * 5), (int) MathF.Round(psionic.Amplification * psionic.Dampening * 10))); RemComp(uid); RemComp(uid); } diff --git a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs index c69e05af452..0e7269c6b8d 100644 --- a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs @@ -1,4 +1,5 @@ using Content.Shared.Actions; +using Content.Shared.DoAfter; using Content.Shared.Psionics.Abilities; using Content.Shared.Psionics.Glimmer; using Content.Server.Atmos.Components; @@ -6,7 +7,13 @@ using Robust.Server.GameObjects; using Content.Shared.Actions.Events; using Content.Server.Explosion.Components; +using Robust.Server.Audio; using Robust.Shared.Map; +using Robust.Shared.Timing; +using Content.Shared.Popups; +using Content.Shared.Mobs; +using Linguini.Syntax.Ast; +using Content.Shared.Psionics.Events; namespace Content.Server.Psionics.Abilities { @@ -17,20 +24,26 @@ public sealed class PyrokinesisPowerSystem : EntitySystem [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!; [Dependency] private readonly GunSystem _gunSystem = default!; [Dependency] private readonly GlimmerSystem _glimmerSystem = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly AudioSystem _audioSystem = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent(OnPowerUsed); + SubscribeLocalEvent(OnPrecharge); + SubscribeLocalEvent(OnDoAfter); } private void OnInit(EntityUid uid, PyrokinesisPowerComponent component, ComponentInit args) { - _actions.AddAction(uid, ref component.PyrokinesisActionEntity, component.PyrokinesisActionId); - _actions.TryGetActionData( component.PyrokinesisActionEntity, out var actionData); + _actions.AddAction(uid, ref component.PyrokinesisPrechargeActionEntity, component.PyrokinesisPrechargeActionId); + _actions.TryGetActionData( component.PyrokinesisPrechargeActionEntity, out var actionData); if (actionData is { UseDelay: not null }) - _actions.StartUseDelay(component.PyrokinesisActionEntity); + _actions.StartUseDelay(component.PyrokinesisPrechargeActionEntity); if (TryComp(uid, out var psionic)) { psionic.ActivePowers.Add(component); @@ -39,9 +52,46 @@ private void OnInit(EntityUid uid, PyrokinesisPowerComponent component, Componen } } + private void OnPrecharge(PyrokinesisPrechargeActionEvent args) + { + if (!HasComp(args.Performer) + && TryComp(args.Performer, out var psionic) + && TryComp(args.Performer, out var pyroComp)) + { + _actions.AddAction(args.Performer, ref pyroComp.PyrokinesisActionEntity, pyroComp.PyrokinesisActionId); + _actions.TryGetActionData(pyroComp.PyrokinesisActionEntity, out var actionData); + if (actionData is { UseDelay: not null }) + _actions.StartUseDelay(pyroComp.PyrokinesisActionEntity); + _actions.TryGetActionData(pyroComp.PyrokinesisPrechargeActionEntity, out var prechargeData); + if (prechargeData is { UseDelay: not null }) + _actions.StartUseDelay(pyroComp.PyrokinesisPrechargeActionEntity); + + if (_glimmerSystem.GlimmerOutput >= 100 * psionic.Dampening) + { + _popup.PopupEntity(Loc.GetString(pyroComp.PyrokinesisObviousPopup, ("entity", args.Performer)), args.Performer, PopupType.Medium); + _audioSystem.PlayPvs(pyroComp.SoundUse, args.Performer); + } + else + _popup.PopupEntity(Loc.GetString(pyroComp.PyrokinesisSubtlePopup), args.Performer, args.Performer, PopupType.Medium); + + pyroComp.FireballThrown = false; + + var ev = new PyrokinesisPrechargeDoAfterEvent(_gameTiming.CurTime); + var duration = TimeSpan.FromSeconds(pyroComp.ResetDuration.Seconds + psionic.Dampening); + + _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.Performer, duration, ev, args.Performer, args.Performer, args.Performer) + { + BlockDuplicate = true, + Hidden = true, + }, out var doAfterId); + + pyroComp.ResetDoAfter = doAfterId; + } + } + private void OnShutdown(EntityUid uid, PyrokinesisPowerComponent component, ComponentShutdown args) { - _actions.RemoveAction(uid, component.PyrokinesisActionEntity); + _actions.RemoveAction(uid, component.PyrokinesisPrechargeActionEntity); if (TryComp(uid, out var psionic)) { psionic.ActivePowers.Remove(component); @@ -53,7 +103,8 @@ private void OnShutdown(EntityUid uid, PyrokinesisPowerComponent component, Comp private void OnPowerUsed(PyrokinesisPowerActionEvent args) { if (!HasComp(args.Performer) - && TryComp(args.Performer, out var psionic)) + && TryComp(args.Performer, out var psionic) + && TryComp(args.Performer, out var pyroComp)) { var spawnCoords = Transform(args.Performer).Coordinates; @@ -61,11 +112,11 @@ private void OnPowerUsed(PyrokinesisPowerActionEvent args) if (TryComp(ent, out var fireball)) { - fireball.MaxIntensity = (int) MathF.Round(5 * psionic.Amplification); + fireball.MaxIntensity = (int) MathF.Round(2 * psionic.Amplification); fireball.IntensitySlope = (int) MathF.Round(1 * psionic.Amplification); - fireball.TotalIntensity = (int) MathF.Round(10 * psionic.Amplification); + fireball.TotalIntensity = (int) MathF.Round(25 * psionic.Amplification); - if (_glimmerSystem.Glimmer >= 500) + if (_glimmerSystem.GlimmerOutput >= 500) fireball.CanCreateVacuum = true; else fireball.CanCreateVacuum = false; @@ -77,10 +128,28 @@ private void OnPowerUsed(PyrokinesisPowerActionEvent args) var direction = args.Target.ToMapPos(EntityManager, _xform) - spawnCoords.ToMapPos(EntityManager, _xform); _gunSystem.ShootProjectile(ent, direction, new System.Numerics.Vector2(0, 0), args.Performer, args.Performer, 20f); - + _actions.RemoveAction(args.Performer, pyroComp.PyrokinesisActionEntity); + _doAfterSystem.Cancel(pyroComp.ResetDoAfter); _psionics.LogPowerUsed(args.Performer, "pyrokinesis", psionic, 6, 8); + pyroComp.FireballThrown = true; args.Handled = true; } } + + private void OnDoAfter(EntityUid uid, PyrokinesisPowerComponent component, PyrokinesisPrechargeDoAfterEvent args) + { + if (!args.Cancelled && TryComp(uid, out var psionic)) + { + if (!component.FireballThrown) + { + _actions.TryGetActionData(component.PyrokinesisPrechargeActionEntity, out var actionData); + if (actionData is { UseDelay: not null }) + _actions.SetCooldown(component.PyrokinesisPrechargeActionEntity, TimeSpan.FromSeconds(15 - psionic.Dampening)); + + _popup.PopupEntity(Loc.GetString(component.PyrokinesisRefundCooldown), uid, uid, PopupType.Medium); + } + _actions.RemoveAction(uid, component.PyrokinesisActionEntity); + } + } } } diff --git a/Content.Server/Psionics/Glimmer/GlimmerCommands.cs b/Content.Server/Psionics/Glimmer/GlimmerCommands.cs index 744f4cdb9a8..d17f1c04565 100644 --- a/Content.Server/Psionics/Glimmer/GlimmerCommands.cs +++ b/Content.Server/Psionics/Glimmer/GlimmerCommands.cs @@ -14,7 +14,7 @@ public sealed class GlimmerShowCommand : IConsoleCommand public async void Execute(IConsoleShell shell, string argStr, string[] args) { var entMan = IoCManager.Resolve(); - shell.WriteLine(entMan.EntitySysManager.GetEntitySystem().Glimmer.ToString()); + shell.WriteLine(entMan.EntitySysManager.GetEntitySystem().GlimmerOutput.ToString()); } } @@ -34,6 +34,6 @@ public async void Execute(IConsoleShell shell, string argStr, string[] args) return; var entMan = IoCManager.Resolve(); - entMan.EntitySysManager.GetEntitySystem().Glimmer = glimmerValue; + entMan.EntitySysManager.GetEntitySystem().SetGlimmerOutput(glimmerValue); } } diff --git a/Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs b/Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs index c0802c8b670..85034574885 100644 --- a/Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs +++ b/Content.Server/Psionics/Glimmer/GlimmerReactiveSystem.cs @@ -176,7 +176,7 @@ private void AddShockVerb(EntityUid uid, SharedGlimmerReactiveComponent componen Act = () => { _sharedAudioSystem.PlayPvs(component.ShockNoises, args.User); - _electrocutionSystem.TryDoElectrocution(args.User, null, _glimmerSystem.Glimmer / 200, TimeSpan.FromSeconds((float) _glimmerSystem.Glimmer / 100), false); + _electrocutionSystem.TryDoElectrocution(args.User, null, (int) Math.Round(_glimmerSystem.GlimmerOutput / 200), TimeSpan.FromSeconds((float) _glimmerSystem.GlimmerOutput / 100), false); }, Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/Spare/poweronoff.svg.192dpi.png")), Text = Loc.GetString("power-switch-component-toggle-verb"), @@ -190,7 +190,7 @@ private void OnDamageChanged(EntityUid uid, SharedGlimmerReactiveComponent compo if (args.Origin == null) return; - if (!_random.Prob((float) _glimmerSystem.Glimmer / 1000)) + if (!_random.Prob(_glimmerSystem.GlimmerOutput / 1000)) return; var tier = _glimmerSystem.GetGlimmerTier(); @@ -207,13 +207,13 @@ private void OnDestroyed(EntityUid uid, SharedGlimmerReactiveComponent component if (tier < GlimmerTier.High) return; - var totalIntensity = (float) (_glimmerSystem.Glimmer * 2); - var slope = (float) (11 - _glimmerSystem.Glimmer / 100); + var totalIntensity = (float) (_glimmerSystem.GlimmerOutput * 2); + var slope = (float) (11 - _glimmerSystem.GlimmerOutput / 100); var maxIntensity = 20; - var removed = (float) _glimmerSystem.Glimmer * _random.NextFloat(0.1f, 0.15f); - _glimmerSystem.Glimmer -= (int) removed; - BeamRandomNearProber(uid, _glimmerSystem.Glimmer / 350, _glimmerSystem.Glimmer / 50); + var removed = (float) _glimmerSystem.GlimmerOutput * _random.NextFloat(0.1f, 0.15f); + _glimmerSystem.DeltaGlimmerOutput(-removed); + BeamRandomNearProber(uid, (int) Math.Round(_glimmerSystem.GlimmerOutput / 350), _glimmerSystem.GlimmerOutput / 50); _explosionSystem.QueueExplosion(uid, "Default", totalIntensity, slope, maxIntensity); } @@ -222,7 +222,7 @@ private void OnUnanchorAttempt(EntityUid uid, SharedGlimmerReactiveComponent com if (_glimmerSystem.GetGlimmerTier() >= GlimmerTier.Dangerous) { _sharedAudioSystem.PlayPvs(component.ShockNoises, args.User); - _electrocutionSystem.TryDoElectrocution(args.User, null, _glimmerSystem.Glimmer / 200, TimeSpan.FromSeconds((float) _glimmerSystem.Glimmer / 100), false); + _electrocutionSystem.TryDoElectrocution(args.User, null, (int) Math.Round(_glimmerSystem.GlimmerOutput / 200), TimeSpan.FromSeconds((float) _glimmerSystem.GlimmerOutput / 100), false); args.Cancel(); } } @@ -265,7 +265,7 @@ private void Beam(EntityUid prober, EntityUid target, GlimmerTier tier, bool obe if (!lxform.Coordinates.TryDistance(EntityManager, txform.Coordinates, out var distance)) return; - if (distance > (float) (_glimmerSystem.Glimmer / 100)) + if (distance > (float) (_glimmerSystem.GlimmerOutput / 100)) return; string beamproto; diff --git a/Content.Server/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs b/Content.Server/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs index 57c74398b08..a17a97410ac 100644 --- a/Content.Server/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs +++ b/Content.Server/Psionics/Glimmer/PassiveGlimmerReductionSystem.cs @@ -1,9 +1,7 @@ -using Robust.Shared.Random; using Robust.Shared.Timing; using Robust.Shared.Configuration; using Content.Shared.CCVar; using Content.Shared.Psionics.Glimmer; -using Content.Shared.GameTicking; namespace Content.Server.Psionics.Glimmer { @@ -13,7 +11,6 @@ namespace Content.Server.Psionics.Glimmer public sealed class PassiveGlimmerReductionSystem : EntitySystem { [Dependency] private readonly GlimmerSystem _glimmerSystem = default!; - [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; @@ -21,58 +18,38 @@ public sealed class PassiveGlimmerReductionSystem : EntitySystem public List GlimmerValues = new(); public TimeSpan TargetUpdatePeriod = TimeSpan.FromSeconds(6); - - private int _updateIncrementor; public TimeSpan NextUpdateTime = default!; public TimeSpan LastUpdateTime = default!; - private float _glimmerLostPerSecond; + private float _glimmerLinearDecay; + private bool _enabled; public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnRoundRestartCleanup); - _cfg.OnValueChanged(CCVars.GlimmerLostPerSecond, UpdatePassiveGlimmer, true); - } - - private void OnRoundRestartCleanup(RoundRestartCleanupEvent args) - { - GlimmerValues.Clear(); + _cfg.OnValueChanged(CCVars.GlimmerLinearDecayPerMinute, UpdatePassiveGlimmer, true); + _enabled = _cfg.GetCVar(CCVars.GlimmerEnabled); + _cfg.OnValueChanged(CCVars.GlimmerEnabled, value => _enabled = value, true); } public override void Update(float frameTime) { base.Update(frameTime); + if (!_enabled) + return; var curTime = _timing.CurTime; if (NextUpdateTime > curTime) return; + var glimmerDecay = _glimmerLinearDecay / (60 / TargetUpdatePeriod.Seconds); - var delta = curTime - LastUpdateTime; - var maxGlimmerLost = (int) Math.Round(delta.TotalSeconds * _glimmerLostPerSecond); - - // It used to be 75% to lose one glimmer per ten seconds, but now it's 50% per six seconds. - // The probability is exactly the same over the same span of time. (0.25 ^ 3 == 0.5 ^ 6) - // This math is just easier to do for pausing's sake. - var actualGlimmerLost = _random.Next(0, 1 + maxGlimmerLost); - - _glimmerSystem.Glimmer -= actualGlimmerLost; - - _updateIncrementor++; - - // Since we normally update every 6 seconds, this works out to a minute. - if (_updateIncrementor == 10) - { - GlimmerValues.Add(_glimmerSystem.Glimmer); - - _updateIncrementor = 0; - } + _glimmerSystem.DeltaGlimmerOutput(-glimmerDecay); NextUpdateTime = curTime + TargetUpdatePeriod; LastUpdateTime = curTime; } - private void UpdatePassiveGlimmer(float value) => _glimmerLostPerSecond = value; + private void UpdatePassiveGlimmer(float value) => _glimmerLinearDecay = value; } } diff --git a/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs b/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs index 5d16c4e5e42..5e0e3f04cff 100644 --- a/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs +++ b/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs @@ -47,12 +47,12 @@ private void OnAnomalyPulse(EntityUid uid, GlimmerSourceComponent component, ref // component. if (TryComp(uid, out var anomaly)) - _glimmerSystem.Glimmer += (int) (5f * anomaly.Severity); + _glimmerSystem.DeltaGlimmerInput(5f * anomaly.Severity); } private void OnAnomalySupercritical(EntityUid uid, GlimmerSourceComponent component, ref AnomalySupercriticalEvent args) { - _glimmerSystem.Glimmer += 100; + _glimmerSystem.DeltaGlimmerOutput(100); } private void OnMobStateChanged(EntityUid uid, GlimmerSourceComponent component, ref MobStateChangedEvent args) @@ -79,11 +79,11 @@ public override void Update(float frameTime) source.Accumulator -= source.SecondsPerGlimmer; if (source.AddToGlimmer) { - _glimmerSystem.Glimmer++; + _glimmerSystem.DeltaGlimmerInput(1); } else { - _glimmerSystem.Glimmer--; + _glimmerSystem.DeltaGlimmerInput(1); } } } diff --git a/Content.Server/Psionics/PsionicsSystem.cs b/Content.Server/Psionics/PsionicsSystem.cs index 04a7597c900..06250f77ba3 100644 --- a/Content.Server/Psionics/PsionicsSystem.cs +++ b/Content.Server/Psionics/PsionicsSystem.cs @@ -141,7 +141,7 @@ public void RollPsionics(EntityUid uid, PotentialPsionicComponent component, boo } if (applyGlimmer) - chance += (float) _glimmerSystem.Glimmer / 1000; + chance += (float) _glimmerSystem.GlimmerOutput / 1000; chance *= multiplier; diff --git a/Content.Server/Psionics/Telepathy/TelepathyChatSystem.cs b/Content.Server/Psionics/Telepathy/TelepathyChatSystem.cs index 2c6b93e2542..917511d1477 100644 --- a/Content.Server/Psionics/Telepathy/TelepathyChatSystem.cs +++ b/Content.Server/Psionics/Telepathy/TelepathyChatSystem.cs @@ -100,11 +100,11 @@ public void SendTelepathicChat(EntityUid source, string message, bool hideChat) _chatManager.ChatMessageToMany(ChatChannel.Telepathic, message, adminMessageWrap, source, hideChat, true, admins, Color.PaleVioletRed); if (_random.Prob(0.1f)) - _glimmerSystem.Glimmer++; + _glimmerSystem.DeltaGlimmerInput(1); - if (_random.Prob(Math.Min(0.33f + (float) _glimmerSystem.Glimmer / 1500, 1))) + if (_random.Prob(Math.Min(0.33f + (float) _glimmerSystem.GlimmerOutput / 1500, 1))) { - float obfuscation = 0.25f + (float) _glimmerSystem.Glimmer / 2000; + float obfuscation = 0.25f + (float) _glimmerSystem.GlimmerOutput / 2000; var obfuscated = ObfuscateMessageReadability(message, obfuscation); _chatManager.ChatMessageToMany(ChatChannel.Telepathic, obfuscated, messageWrap, source, hideChat, false, GetDreamers(clients), Color.PaleVioletRed); } diff --git a/Content.Server/StationEvents/EventManagerSystem.cs b/Content.Server/StationEvents/EventManagerSystem.cs index 261e8ca46dd..d33a373b377 100644 --- a/Content.Server/StationEvents/EventManagerSystem.cs +++ b/Content.Server/StationEvents/EventManagerSystem.cs @@ -191,8 +191,8 @@ private bool CanRun(EntityPrototype prototype, StationEventComponent stationEven // This could not be cleanly done anywhere else. if (_configurationManager.GetCVar(CCVars.GlimmerEnabled) && prototype.TryGetComponent(out var glimmerEvent) && - (_glimmerSystem.Glimmer < glimmerEvent.MinimumGlimmer || - _glimmerSystem.Glimmer > glimmerEvent.MaximumGlimmer)) + (_glimmerSystem.GlimmerOutput < glimmerEvent.MinimumGlimmer || + _glimmerSystem.GlimmerOutput > glimmerEvent.MaximumGlimmer)) { return false; } diff --git a/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactAnalyzerSystem.cs b/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactAnalyzerSystem.cs index 27caebef808..de869ab7e89 100644 --- a/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactAnalyzerSystem.cs +++ b/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactAnalyzerSystem.cs @@ -366,13 +366,11 @@ private void OnExtractButton(EntityUid uid, AnalysisConsoleComponent component, _research.ModifyServerPoints(server.Value, pointValue, serverComponent); _artifact.AdjustConsumedPoints(artifact.Value, pointValue); - // Nyano - Summary - Begin modified code block: tie artifacts to glimmer. if (TryComp(component.AnalyzerEntity.Value, out var analyzer) && analyzer != null) { - _glimmerSystem.Glimmer += (int) pointValue / analyzer.ExtractRatio; + _glimmerSystem.DeltaGlimmerInput(pointValue / analyzer.ExtractRatio); } - // Nyano - End modified code block. _audio.PlayPvs(component.ExtractSound, component.AnalyzerEntity.Value, AudioParams.Default.WithVolume(2f)); diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs index 7d7f3c70449..926701400ea 100644 --- a/Content.Shared/CCVar/CCVars.cs +++ b/Content.Shared/CCVar/CCVars.cs @@ -2141,11 +2141,11 @@ public static readonly CVarDef CVarDef.Create("glimmer.enabled", true, CVar.REPLICATED); /// - /// Passive glimmer drain per second. - /// Note that this is randomized and this is an average value. + /// The rate at which glimmer linearly decays. Since glimmer increases (usually) follow a logistic curve, this means glimmer + /// becomes increasingly harder to raise after ~502 points. /// - public static readonly CVarDef GlimmerLostPerSecond = - CVarDef.Create("glimmer.passive_drain_per_second", 0.1f, CVar.SERVERONLY); + public static readonly CVarDef GlimmerLinearDecayPerMinute = + CVarDef.Create("glimmer.linear_decay_per_minute", 6f, CVar.SERVERONLY); /// /// Whether random rolls for psionics are allowed. diff --git a/Content.Shared/Nyanotrasen/Actions/Events/PyrokinesisPowerActionEvent.cs b/Content.Shared/Nyanotrasen/Actions/Events/PyrokinesisPowerActionEvent.cs index 4639aadd55b..2493be58fab 100644 --- a/Content.Shared/Nyanotrasen/Actions/Events/PyrokinesisPowerActionEvent.cs +++ b/Content.Shared/Nyanotrasen/Actions/Events/PyrokinesisPowerActionEvent.cs @@ -1,4 +1,5 @@ namespace Content.Shared.Actions.Events; public sealed partial class PyrokinesisPowerActionEvent : WorldTargetActionEvent {} +public sealed partial class PyrokinesisPrechargeActionEvent : InstantActionEvent {} diff --git a/Content.Shared/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs b/Content.Shared/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs index 1f88741b9a9..b95ead8ec1a 100644 --- a/Content.Shared/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs +++ b/Content.Shared/Psionics/Abilities/Pyrokinesis/PyrokinesisPowerComponent.cs @@ -1,4 +1,5 @@ -using Content.Shared.Actions; +using Content.Shared.DoAfter; +using Robust.Shared.Audio; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; @@ -7,7 +8,13 @@ namespace Content.Shared.Psionics.Abilities [RegisterComponent] public sealed partial class PyrokinesisPowerComponent : Component { - public EntityTargetActionComponent? PyrokinesisPowerAction = null; + [DataField("pyrokinesisPrechargeActionId", + customTypeSerializer: typeof(PrototypeIdSerializer))] + public string? PyrokinesisPrechargeActionId = "ActionPrechargePyrokinesis"; + + [DataField("pyrokinesisPrechargeActionEntity")] + public EntityUid? PyrokinesisPrechargeActionEntity; + [DataField("pyrokinesisActionId", customTypeSerializer: typeof(PrototypeIdSerializer))] public string? PyrokinesisActionId = "ActionPyrokinesis"; @@ -17,5 +24,22 @@ public sealed partial class PyrokinesisPowerComponent : Component [DataField("pyrokinesisFeedback")] public string PyrokinesisFeedback = "pyrokinesis-feedback"; + + [DataField] + public string PyrokinesisObviousPopup = "pyrokinesis-obvious"; + + [DataField] + public string PyrokinesisSubtlePopup = "pyrokinesis-subtle"; + + [DataField] + public string PyrokinesisRefundCooldown = "pyrokinesis-refund-cooldown"; + + public DoAfterId? ResetDoAfter; + public bool FireballThrown; + + [DataField] + public SoundSpecifier SoundUse = new SoundPathSpecifier("/Audio/Items/welder.ogg"); + [DataField] + public TimeSpan ResetDuration = TimeSpan.FromSeconds(7); } } diff --git a/Content.Shared/Psionics/Abilities/Pyrokinesis/PyrokinesisPrechargeComponent.cs b/Content.Shared/Psionics/Abilities/Pyrokinesis/PyrokinesisPrechargeComponent.cs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Content.Shared/Psionics/Events.cs b/Content.Shared/Psionics/Events.cs index 45a00b5f048..88cf17a4a2f 100644 --- a/Content.Shared/Psionics/Events.cs +++ b/Content.Shared/Psionics/Events.cs @@ -57,6 +57,24 @@ public FocusedMetapsionicDoAfterEvent(TimeSpan startedAt) public override DoAfterEvent Clone() => this; } + [Serializable, NetSerializable] + public sealed partial class PyrokinesisPrechargeDoAfterEvent : DoAfterEvent + { + [DataField("startedAt", required: true)] + public TimeSpan StartedAt; + + private PyrokinesisPrechargeDoAfterEvent() + { + } + + public PyrokinesisPrechargeDoAfterEvent(TimeSpan startedAt) + { + StartedAt = startedAt; + } + + public override DoAfterEvent Clone() => this; + } + [Serializable, NetSerializable] public sealed partial class GlimmerWispDrainDoAfterEvent : SimpleDoAfterEvent { diff --git a/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs b/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs index 8be02f936a9..8d1393b8846 100644 --- a/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs +++ b/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs @@ -11,11 +11,32 @@ namespace Content.Shared.Psionics.Glimmer public sealed class GlimmerSystem : EntitySystem { [Dependency] private readonly IConfigurationManager _cfg = default!; - private int _glimmer = 0; - public int Glimmer + private float _glimmerInput = 0; + /// + /// GlimmerInput represents the system-facing value of the station's glimmer, and is given by f(y) for this graph: https://www.desmos.com/calculator/posutiq38e + /// Where x = GlimmerOutput and y = GlimmerInput + /// + /// + /// This is private set for a good reason, if you're looking to change it, do so via DeltaGlimmerInput or SetGlimmerInput + /// + public float GlimmerInput + { + get { return _glimmerInput; } + private set { _glimmerInput = _enabled ? Math.Min(value, 0) : 0; } + } + private float _glimmerOutput = 0; + + /// + /// Glimmer Output represents the player-facing value of the station's glimmer, and is given by f(x) for this graph: https://www.desmos.com/calculator/posutiq38e + /// Where x = GlimmerInput and y = GlimmerOutput + /// + /// + /// This is private set for a good reason, if you're looking to change it, do so via DeltaGlimmerOutput or SetGlimmerOutput + /// + public float GlimmerOutput { - get { return _glimmer; } - set { _glimmer = _enabled ? Math.Clamp(value, 0, 1000) : 0; } + get { return _glimmerOutput; } + private set { _glimmerOutput = _enabled ? Math.Min(value, 0) : 0; } } private bool _enabled; public override void Initialize() @@ -28,17 +49,18 @@ public override void Initialize() private void Reset(RoundRestartCleanupEvent args) { - Glimmer = 0; + GlimmerInput = 0; + GlimmerOutput = 0; } /// /// Return an abstracted range of a glimmer count. /// /// What glimmer count to check. Uses the current glimmer by default. - public GlimmerTier GetGlimmerTier(int? glimmer = null) + public GlimmerTier GetGlimmerTier(float? glimmer = null) { if (glimmer == null) - glimmer = Glimmer; + glimmer = GlimmerOutput; return glimmer switch { @@ -50,6 +72,47 @@ public GlimmerTier GetGlimmerTier(int? glimmer = null) _ => GlimmerTier.Critical, }; } + + // Ignore the bracket warnings on these, Intellisense is wrong and doesn't understand polynomials. + /// + /// The primary intended accessors for + /// + /// + public void DeltaGlimmerInput(float delta) + { + if (_enabled && delta != 0) + { + GlimmerInput += delta; + GlimmerOutput = (2000 / (1 + MathF.Pow(MathF.E, -.0022f * GlimmerInput))) - 1000; + } + } + + public void DeltaGlimmerOutput(float delta) + { + if (_enabled && delta != 0) + { + GlimmerOutput += delta; + GlimmerInput = (2000 / (1 + MathF.Pow(MathF.E, -.0022f * GlimmerOutput))) - 1000; + } + } + + public void SetGlimmerOutput(float set) + { + if (_enabled && set != 0) + { + GlimmerOutput = set; + GlimmerInput = (2000 / (1 + MathF.Pow(MathF.E, -.0022f * GlimmerOutput))) - 1000; + } + } + + public void SetGlimmerInput(float set) + { + if (_enabled && set != 0) + { + GlimmerInput = set; + GlimmerOutput = (2000 / (1 + MathF.Pow(MathF.E, -.0022f * GlimmerOutput))) - 1000; + } + } } [Serializable, NetSerializable] diff --git a/Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs b/Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs index cf3bafab5ad..f905ec4dd44 100644 --- a/Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs +++ b/Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs @@ -91,10 +91,10 @@ public void LogPowerUsed(EntityUid uid, string power, PsionicComponent? psionic if (!overrideGlimmer) { if (psionic == null) - _glimmerSystem.Glimmer += _robustRandom.Next(minGlimmer, maxGlimmer); - else _glimmerSystem.Glimmer += _robustRandom.Next( - (int) Math.Round(minGlimmer * psionic.Amplification - psionic.Dampening), - (int) Math.Round(maxGlimmer * psionic.Amplification - psionic.Dampening)); + _glimmerSystem.DeltaGlimmerInput(_robustRandom.NextFloat(minGlimmer, maxGlimmer)); + else _glimmerSystem.DeltaGlimmerInput(_robustRandom.NextFloat( + minGlimmer * psionic.Amplification - psionic.Dampening, + maxGlimmer * psionic.Amplification - psionic.Dampening)); } } } diff --git a/Resources/Locale/en-US/customization/character-requirements.ftl b/Resources/Locale/en-US/customization/character-requirements.ftl index b073bdb773f..e7bcf0669f7 100644 --- a/Resources/Locale/en-US/customization/character-requirements.ftl +++ b/Resources/Locale/en-US/customization/character-requirements.ftl @@ -9,7 +9,7 @@ character-species-requirement = You must {$inverted -> character-trait-requirement = You must {$inverted -> [true] not have *[other] have -} the trait [color=lightblue]{$trait}[/color] +} the trait [color=lightblue]{$traits}[/color] character-backpack-type-requirement = You must {$inverted -> [true] not use *[other] use diff --git a/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl b/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl index 02800953b1e..c3a9641768f 100644 --- a/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl +++ b/Resources/Locale/en-US/nyanotrasen/abilities/psionic.ftl @@ -63,7 +63,10 @@ action-name-noospheric-zap = Noospheric Zap action-description-noospheric-zap = Shocks the conciousness of the target and leaves them stunned and stuttering. action-name-pyrokinesis = Pyrokinesis -action-description-pyrokinesis = Hurl a small gateway to the plane of Gehenna at your target. +action-description-pyrokinesis = Hurl a fire bolt at your target + +action-name-precharge-pyrokinesis = Precharge Pyrokinesis +action-description-precharge-pyrokinesis = Draw forth the Secret of Fire, and prepare to launch a fire bolt action-name-psychokinesis = Psychokinesis action-description-psychokinesis = Bend the fabric of space to instantly move across it. diff --git a/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl b/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl index 2add055f7bd..311d71d6ac7 100644 --- a/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl +++ b/Resources/Locale/en-US/nyanotrasen/psionics/psychic-feedback.ftl @@ -44,6 +44,10 @@ focused-metapsionic-pulse-begin = The air around {CAPITALIZE($entity)} begins to psionic-regeneration-self-revive = {CAPITALIZE($entity)} begins to visibly regenerate mindbreaking-feedback = The light of life vanishes from {CAPITALIZE($entity)}'s eyes, leaving behind a husk pretending at sapience regenerative-stasis-begin = {CAPITALIZE($entity)} swoons for a moment, then begins visibly regenerating +pyrokinesis-obvious = A mote of flame dances around {CAPITALIZE($entity)}'s fingers +pyrokinesis-subtle = You draw upon the Secret of Fire. + Use this action again to throw a fire bolt. +pyrokinesis-refund-cooldown = You reclaim some of the energy spent drawing forth the Secret of Fire # Misc Psionic Messages telepathic-mute-message = You strain, but are unable to send your thoughts to the Noosphere diff --git a/Resources/Locale/en-US/traits/traits.ftl b/Resources/Locale/en-US/traits/traits.ftl index bfda7e48be7..dc3d407e5e8 100644 --- a/Resources/Locale/en-US/traits/traits.ftl +++ b/Resources/Locale/en-US/traits/traits.ftl @@ -36,3 +36,15 @@ trait-name-LatentPsychic = Latent Psychic trait-description-LatentPsychic = Your mind and soul are open to the noosphere, allowing for a limited use of Telepathy. Thus, you are eligible for potentially receiving psychic powers. It is possible that you may be hunted by otherworldly forces, so consider keeping your powers a secret. + +trait-name-PsionicInsulation = χ Waveform Misalignment +trait-description-PsionicInsulation = Through a quirk of fate, your brainwaves are permanently out of phase with the noösphere + You are immune to both positive and negative effects of nearly all psychic powers, + But you can never be a psionic yourself in this life. This trait is incompatible with + all other psychic traits. + +trait-name-NaturalTelepath = Natural Telepath +trait-description-NaturalTelepath = As a naturally occuring Telepath, you are capable of fluent telepathic communication, regardless of + whether or not you possess any notable psychic powers. This offers all of the same benefits and + drawbacks of Latent Psychic, except that you are guaranteed to start with full Telepathy. You may + still gain powers as normal for a Latent Psychic. diff --git a/Resources/Prototypes/Nyanotrasen/Actions/types.yml b/Resources/Prototypes/Nyanotrasen/Actions/types.yml index 55dd48e5470..4ee617931dc 100644 --- a/Resources/Prototypes/Nyanotrasen/Actions/types.yml +++ b/Resources/Prototypes/Nyanotrasen/Actions/types.yml @@ -96,12 +96,24 @@ components: - type: WorldTargetAction icon: Nyanotrasen/Interface/VerbIcons/pyrokinesis.png - useDelay: 50 - range: 6 + useDelay: 1 + range: 15 checkCanAccess: false + checkCanInteract: true itemIconStyle: BigAction event: !type:PyrokinesisPowerActionEvent +- type: entity + id: ActionPrechargePyrokinesis + name: action-name-precharge-pyrokinesis + description: action-description-precharge-pyrokinesis + noSpawn: true + components: + - type: InstantAction + icon: Nyanotrasen/Interface/VerbIcons/pyrokinesis.png + useDelay: 50 + event: !type:PyrokinesisPrechargeActionEvent + - type: entity id: ActionWideMetapsionic name: action-name-widemetapsionic diff --git a/Resources/Prototypes/Traits/psionics.yml b/Resources/Prototypes/Traits/psionics.yml index 01c8a5750eb..277070617cf 100644 --- a/Resources/Prototypes/Traits/psionics.yml +++ b/Resources/Prototypes/Traits/psionics.yml @@ -4,3 +4,36 @@ points: -1 components: - type: PotentialPsionic + requirements: + - !type:CharacterTraitRequirement + inverted: true + traits: + - PsionicInsulation + - NaturalTelepath + +- type: trait + id: PsionicInsulation + category: Psionic + points: -5 + components: + - type: PsionicInsulation + requirements: + - !type:CharacterTraitRequirement + inverted: true + traits: + - LatentPsychic + - NaturalTelepath + +- type: trait + id: NaturalTelepath + category: Psionic + points: -3 + components: + - type: PotentialPsionic + - type: Psionic + requirements: + - !type:CharacterTraitRequirement + inverted: true + traits: + - LatentPsychic + - PsionicInsulation From 1c4f9e6b5381723cbcf9e9d6569f4fcd93e2d050 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Thu, 27 Jun 2024 21:43:58 -0400 Subject: [PATCH 49/82] Update GlimmerSystem.cs --- Content.Shared/Psionics/Glimmer/GlimmerSystem.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs b/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs index 8d1393b8846..45742d70b37 100644 --- a/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs +++ b/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs @@ -74,10 +74,6 @@ public GlimmerTier GetGlimmerTier(float? glimmer = null) } // Ignore the bracket warnings on these, Intellisense is wrong and doesn't understand polynomials. - /// - /// The primary intended accessors for - /// - /// public void DeltaGlimmerInput(float delta) { if (_enabled && delta != 0) From 84c154084ef7da470df8ca2423dfaef1a864e278 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Thu, 27 Jun 2024 21:46:26 -0400 Subject: [PATCH 50/82] Update GlimmerSystem.cs --- Content.Shared/Psionics/Glimmer/GlimmerSystem.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs b/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs index 45742d70b37..52e14a0747b 100644 --- a/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs +++ b/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs @@ -73,13 +73,12 @@ public GlimmerTier GetGlimmerTier(float? glimmer = null) }; } - // Ignore the bracket warnings on these, Intellisense is wrong and doesn't understand polynomials. public void DeltaGlimmerInput(float delta) { if (_enabled && delta != 0) { GlimmerInput += delta; - GlimmerOutput = (2000 / (1 + MathF.Pow(MathF.E, -.0022f * GlimmerInput))) - 1000; + GlimmerOutput = 2000 / (1 + MathF.Pow(MathF.E, -.0022f * GlimmerInput)) - 1000; } } @@ -88,7 +87,7 @@ public void DeltaGlimmerOutput(float delta) if (_enabled && delta != 0) { GlimmerOutput += delta; - GlimmerInput = (2000 / (1 + MathF.Pow(MathF.E, -.0022f * GlimmerOutput))) - 1000; + GlimmerInput = 2000 / (1 + MathF.Pow(MathF.E, -.0022f * GlimmerOutput)) - 1000; } } @@ -97,7 +96,7 @@ public void SetGlimmerOutput(float set) if (_enabled && set != 0) { GlimmerOutput = set; - GlimmerInput = (2000 / (1 + MathF.Pow(MathF.E, -.0022f * GlimmerOutput))) - 1000; + GlimmerInput = 2000 / (1 + MathF.Pow(MathF.E, -.0022f * GlimmerOutput)) - 1000; } } @@ -106,7 +105,7 @@ public void SetGlimmerInput(float set) if (_enabled && set != 0) { GlimmerInput = set; - GlimmerOutput = (2000 / (1 + MathF.Pow(MathF.E, -.0022f * GlimmerOutput))) - 1000; + GlimmerOutput = 2000 / (1 + MathF.Pow(MathF.E, -.0022f * GlimmerOutput)) - 1000; } } } From c5b0e49b24f63c5a59fda414fc9aebfe19bf8bf9 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Thu, 27 Jun 2024 22:12:33 -0400 Subject: [PATCH 51/82] Got this backwards --- Content.Shared/Psionics/Glimmer/GlimmerSystem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs b/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs index 52e14a0747b..9f924ad9a26 100644 --- a/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs +++ b/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs @@ -22,7 +22,7 @@ public sealed class GlimmerSystem : EntitySystem public float GlimmerInput { get { return _glimmerInput; } - private set { _glimmerInput = _enabled ? Math.Min(value, 0) : 0; } + private set { _glimmerInput = _enabled ? Math.Max(value, 0) : 0; } } private float _glimmerOutput = 0; @@ -36,7 +36,7 @@ public float GlimmerInput public float GlimmerOutput { get { return _glimmerOutput; } - private set { _glimmerOutput = _enabled ? Math.Min(value, 0) : 0; } + private set { _glimmerOutput = _enabled ? Math.Max(value, 0) : 0; } } private bool _enabled; public override void Initialize() From 2ed8c5dac03b95f1b6c94c4647cd4011dad12325 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Fri, 28 Jun 2024 00:13:33 -0400 Subject: [PATCH 52/82] More glimmer updates --- .../GlimmerMonitor/GlimmerMonitorUiFragment.xaml | 1 + .../GlimmerMonitorUiFragment.xaml.cs | 16 ++++++++-------- .../Glimmer/PassiveGlimmerReductionSystem.cs | 2 ++ .../Structures/GlimmerStructuresSystem.cs | 6 ++++-- Content.Shared/Psionics/Glimmer/GlimmerSystem.cs | 3 ++- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUiFragment.xaml b/Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUiFragment.xaml index 3044680e27b..ade0720696b 100644 --- a/Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUiFragment.xaml +++ b/Content.Client/Psionics/GlimmerMonitor/GlimmerMonitorUiFragment.xaml @@ -3,6 +3,7 @@ [ViewVariables(VVAccess.ReadWrite)] [DataField("stripTimeReduction")] - public float StripTimeReduction = 0.5f; + public TimeSpan StripTimeReduction = TimeSpan.FromSeconds(0.5f); /// /// Should it notify the user if they're stripping a pocket? diff --git a/Content.Shared/Strip/SharedStrippableSystem.cs b/Content.Shared/Strip/SharedStrippableSystem.cs index a698ae5035a..7afd4f245a1 100644 --- a/Content.Shared/Strip/SharedStrippableSystem.cs +++ b/Content.Shared/Strip/SharedStrippableSystem.cs @@ -14,12 +14,12 @@ public override void Initialize() SubscribeLocalEvent(OnDragDrop); } - public (float Time, bool Stealth) GetStripTimeModifiers(EntityUid user, EntityUid target, float initialTime) + public (TimeSpan Time, bool Stealth) GetStripTimeModifiers(EntityUid user, EntityUid target, TimeSpan initialTime) { var userEv = new BeforeStripEvent(initialTime); - RaiseLocalEvent(user, userEv); + RaiseLocalEvent(user, ref userEv); var ev = new BeforeGettingStrippedEvent(userEv.Time, userEv.Stealth); - RaiseLocalEvent(target, ev); + RaiseLocalEvent(target, ref ev); return (ev.Time, ev.Stealth); } diff --git a/Content.Shared/Strip/ThievingSystem.cs b/Content.Shared/Strip/ThievingSystem.cs index 0ef4b66571f..2b3d3b38a00 100644 --- a/Content.Shared/Strip/ThievingSystem.cs +++ b/Content.Shared/Strip/ThievingSystem.cs @@ -1,4 +1,5 @@ using Content.Shared.Inventory; +using Content.Shared.Strip; using Content.Shared.Strip.Components; namespace Content.Shared.Strip; From ba2d53845e3f365a7423ac8f9ab6ee491e76d60d Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Mon, 1 Jul 2024 18:37:29 -0400 Subject: [PATCH 55/82] Make Spent Casing Ejection Not Suck (#478) # Description Part of #467, #460, and #474 This is a small PR that corrects a math error in SharedGunSystem, causing shell casings to be "Thrown" directly downwards instead of in an actually cinematic and exciting arc. While I'm at it, I also corrected the fixture of base shell casings to favor "Bounciness", and decreased its mass to approximately 100 grams. Finally, I added a sound for when casings bounce off of walls, which wasn't present before. https://github.com/Simple-Station/Einstein-Engines/assets/16548818/56bb4ecc-d5eb-4b36-853b-42f05374150d :cl: - fix: Spent bullet casings now fly away from a shooter in a cinematic manner, rather than fall at their feet. Co-authored-by: Danger Revolution! <142105406+DangerRevolution@users.noreply.github.com> --- Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs | 2 +- .../Guns/Ammunition/Cartridges/base_cartridge.yml | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs index cadb0a4b215..ff8b102bb57 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs @@ -443,7 +443,7 @@ protected void EjectCartridge( { Angle ejectAngle = angle.Value; ejectAngle += 3.7f; // 212 degrees; casings should eject slightly to the right and behind of a gun - ThrowingSystem.TryThrow(entity, ejectAngle.ToVec().Normalized() / 100, 5f); + ThrowingSystem.TryThrow(entity, ejectAngle.ToVec(), 625f); } if (playSound && TryComp(entity, out var cartridge)) { diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/base_cartridge.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/base_cartridge.yml index e188ee8c658..3bef413dffa 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/base_cartridge.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/base_cartridge.yml @@ -11,10 +11,10 @@ shape: !type:PhysShapeAabb bounds: "-0.10,-0.05,0.10,0.05" - density: 20 + density: 0.5 mask: - ItemMask - restitution: 0.3 # fite me + restitution: 0.7 # Small and bouncy friction: 0.2 - type: Tag tags: @@ -23,6 +23,11 @@ size: Tiny - type: SpaceGarbage - type: EmitSoundOnLand + sound: + path: /Audio/Weapons/Guns/Casings/casing_fall_1.ogg + params: + volume: -1 + - type: EmitSoundOnCollide sound: path: /Audio/Weapons/Guns/Casings/casing_fall_2.ogg params: From 2e712c00249cfe5bd254462a1efa1b6c8a1ec6bd Mon Sep 17 00:00:00 2001 From: SimpleStation Changelogs Date: Mon, 1 Jul 2024 22:37:52 +0000 Subject: [PATCH 56/82] Automatic Changelog Update (#478) --- Resources/Changelog/Changelog.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 6fe7b0ff689..515c1832db1 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -4257,3 +4257,11 @@ Entries: message: Most items now take time to equip and unequip, especially space suits. id: 6132 time: '2024-06-30T18:22:28.0000000+00:00' +- author: VMSolidus + changes: + - type: Fix + message: >- + Spent bullet casings now fly away from a shooter in a cinematic manner, + rather than fall at their feet. + id: 6133 + time: '2024-07-01T22:37:29.0000000+00:00' From 8bbcafa009cc04e44f25dac57c56d4492c87afa3 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Mon, 1 Jul 2024 18:45:04 -0400 Subject: [PATCH 57/82] New glimmer functions --- .../Abilities/PyrokinesisPowerSystem.cs | 15 ++-- .../Structures/GlimmerStructuresSystem.cs | 12 ++- .../Psionics/Glimmer/GlimmerSystem.cs | 74 +++++++++++++++++-- Content.Shared/Psionics/PsionicComponent.cs | 14 +++- 4 files changed, 96 insertions(+), 19 deletions(-) diff --git a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs index 90a28eb6ae1..07ada4c0c5d 100644 --- a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs @@ -11,6 +11,7 @@ using Robust.Shared.Timing; using Content.Shared.Popups; using Content.Shared.Psionics.Events; +using Content.Shared.Psionics; namespace Content.Server.Psionics.Abilities { @@ -38,7 +39,7 @@ public override void Initialize() private void OnInit(EntityUid uid, PyrokinesisPowerComponent component, ComponentInit args) { _actions.AddAction(uid, ref component.PyrokinesisPrechargeActionEntity, component.PyrokinesisPrechargeActionId); - _actions.TryGetActionData( component.PyrokinesisPrechargeActionEntity, out var actionData); + _actions.TryGetActionData(component.PyrokinesisPrechargeActionEntity, out var actionData); if (actionData is { UseDelay: not null }) _actions.StartUseDelay(component.PyrokinesisPrechargeActionEntity); if (TryComp(uid, out var psionic)) @@ -107,13 +108,17 @@ private void OnPowerUsed(PyrokinesisPowerActionEvent args) var ent = Spawn("ProjectileAnomalyFireball", spawnCoords); + if (_glimmerSystem.GlimmerOutput >= 25 * psionic.Dampening) + EnsureComp(ent); + if (TryComp(ent, out var fireball)) { - fireball.MaxIntensity = (int) MathF.Round(2 * psionic.Amplification); - fireball.IntensitySlope = (int) MathF.Round(1 * psionic.Amplification); - fireball.TotalIntensity = (int) MathF.Round(25 * psionic.Amplification); + var psionicFactor = psionic.Amplification * _glimmerSystem.GetGlimmerEquilibriumRatio(); + fireball.MaxIntensity = 2 * psionicFactor; + fireball.IntensitySlope = 1 * psionicFactor; + fireball.TotalIntensity = 25 * psionicFactor; - if (_glimmerSystem.GlimmerOutput >= 500) + if (_glimmerSystem.GlimmerOutput >= _glimmerSystem.GlimmerEquilibrium) fireball.CanCreateVacuum = true; else fireball.CanCreateVacuum = false; diff --git a/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs b/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs index 09e33dd4144..b8649f71a5f 100644 --- a/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs +++ b/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs @@ -76,16 +76,20 @@ public override void Update(float frameTime) if (source.Accumulator > source.SecondsPerGlimmer) { + var glimmerEquilibrium = _glimmerSystem.GlimmerEquilibrium; source.Accumulator -= source.SecondsPerGlimmer; + + // Shorthand explanation: + // This makes glimmer far more "Swingy", by making both positive and negative glimmer sources scale quite dramatically with glimmer if (source.AddToGlimmer) { - //If we're above the equilibrium point of 500, increase the output of passive glimmer sources to help fight against linear decay - //Even with this, don't expect probers to ever get to mind swap levels of power without any help - _glimmerSystem.DeltaGlimmerInput(_glimmerSystem.GlimmerOutput > 500 ? MathF.Round(_glimmerSystem.GlimmerOutput / 100) : 1f); + _glimmerSystem.DeltaGlimmerInput((_glimmerSystem.GlimmerOutput > glimmerEquilibrium ? _glimmerSystem.GetGlimmerOutputInteger() : 1f) + * (_glimmerSystem.GlimmerOutput < glimmerEquilibrium ? _glimmerSystem.GetGlimmerEquilibriumRatio() : 1f)); } else { - _glimmerSystem.DeltaGlimmerInput(-1); + _glimmerSystem.DeltaGlimmerInput(-(_glimmerSystem.GlimmerOutput > glimmerEquilibrium ? _glimmerSystem.GetGlimmerOutputInteger() : 1f) + * (_glimmerSystem.GlimmerOutput > glimmerEquilibrium ? _glimmerSystem.GetGlimmerEquilibriumRatio() : 1f)); } } } diff --git a/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs b/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs index d50b6fb2f6d..f40a916f487 100644 --- a/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs +++ b/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs @@ -2,7 +2,6 @@ using Robust.Shared.Configuration; using Content.Shared.CCVar; using Content.Shared.GameTicking; -using Content.Shared.Mobs; namespace Content.Shared.Psionics.Glimmer { @@ -12,6 +11,7 @@ namespace Content.Shared.Psionics.Glimmer public sealed class GlimmerSystem : EntitySystem { [Dependency] private readonly IConfigurationManager _cfg = default!; + private float _glimmerInput = 0; /// /// GlimmerInput represents the system-facing value of the station's glimmer, and is given by f(y) for this graph: https://www.desmos.com/calculator/posutiq38e @@ -27,6 +27,19 @@ public float GlimmerInput } private float _glimmerOutput = 0; + /// + /// This constant is equal to the intersection of the Glimmer Equation(https://www.desmos.com/calculator/posutiq38e) and the line Y = X. + /// + private const float _glimmerEquilibrium = 502.941f; + + /// + /// This constant is equal to the intersection of the Glimmer Equation(https://www.desmos.com/calculator/posutiq38e) and the line Y = X. + /// + public float GlimmerEquilibrium + { + get { return _glimmerEquilibrium; } + } + /// /// Glimmer Output represents the player-facing value of the station's glimmer, and is given by f(x) for this graph: https://www.desmos.com/calculator/posutiq38e /// Where x = GlimmerInput and y = GlimmerOutput @@ -55,7 +68,8 @@ private void Reset(RoundRestartCleanupEvent args) } /// - /// Return an abstracted range of a glimmer count. + /// Return an abstracted range of a glimmer count. This is a legacy system used to support the Prober, + /// and is the lowest form of abstracted glimmer. It's meant more for sprite states than math. /// /// What glimmer count to check. Uses the current glimmer by default. public GlimmerTier GetGlimmerTier(float? glimmer = null) @@ -66,14 +80,30 @@ public GlimmerTier GetGlimmerTier(float? glimmer = null) return glimmer switch { <= 49 => GlimmerTier.Minimal, - >= 50 and <= 99 => GlimmerTier.Low, - >= 100 and <= 299 => GlimmerTier.Moderate, - >= 300 and <= 499 => GlimmerTier.High, - >= 500 and <= 899 => GlimmerTier.Dangerous, + >= 50 and <= 399 => GlimmerTier.Low, + >= 400 and <= 599 => GlimmerTier.Moderate, + >= 600 and <= 699 => GlimmerTier.High, + >= 700 and <= 899 => GlimmerTier.Dangerous, _ => GlimmerTier.Critical, }; } + /// + /// Returns a 0 through 10 range of glimmer. Do not divide by this for any reason. + /// + /// + public int GetGlimmerOutputInteger() + { + if (!_enabled) + return 1; + else return (int) MathF.Round(GlimmerOutput / 1000); + } + + /// + /// This is the public facing function for modifying Glimmer based on the log scale. Simply add or subtract to this with any nonzero number + /// Go through this if you want glimmer to be modified faster if its below 502.941f, and slower if above said equilibrium + /// + /// public void DeltaGlimmerInput(float delta) { if (_enabled && delta != 0) @@ -83,6 +113,11 @@ public void DeltaGlimmerInput(float delta) } } + /// + /// This is the public facing function for modifying Glimmer based on a linear scale. Simply add or subtract to this with any nonzero number. + /// This is primarily intended for load bearing systems such as Probers and Drainers, and should not be called by most things by design. + /// + /// public void DeltaGlimmerOutput(float delta) { if (_enabled && delta != 0) @@ -92,23 +127,46 @@ public void DeltaGlimmerOutput(float delta) } } + /// + /// This directly sets the Player-Facing side of Glimmer to a given value, and is not intended to be called by anything other than admin commands. + /// This is clamped between 0 and 999.999f + /// + /// public void SetGlimmerOutput(float set) { if (_enabled && set != 0) { - GlimmerOutput = set; + GlimmerOutput = Math.Clamp(set, 0, 999.999f); GlimmerInput = 2000 / (1 + MathF.Pow(MathF.E, -.0022f * GlimmerOutput)) - 1000; } } + /// + /// This directly sets the code-facing side of Glimmer to a given value, and is not intended to be called by anything other than admin commands. + /// This accepts any positive float input. + /// + /// public void SetGlimmerInput(float set) { - if (_enabled && set != 0) + if (_enabled && set >= 0) { GlimmerInput = set; GlimmerOutput = 2000 / (1 + MathF.Pow(MathF.E, -.0022f * GlimmerOutput)) - 1000; } } + + /// + /// Outputs the ratio between actual glimmer and glimmer equilibrium(The intersection of the Glimmer Equation and the line y = x). + /// This will return 0.01f if glimmer is 0, and 1 if glimmer is disabled. + /// + public float GetGlimmerEquilibriumRatio() + { + if (!_enabled) + return 1; + else if (GlimmerOutput == 0) + return 0.01f; + else return GlimmerOutput / GlimmerEquilibrium; + } } [Serializable, NetSerializable] diff --git a/Content.Shared/Psionics/PsionicComponent.cs b/Content.Shared/Psionics/PsionicComponent.cs index c955626c53d..748b8ddd92a 100644 --- a/Content.Shared/Psionics/PsionicComponent.cs +++ b/Content.Shared/Psionics/PsionicComponent.cs @@ -19,10 +19,20 @@ public sealed partial class PsionicComponent : Component [DataField("psychicFeedback")] public List PsychicFeedback = new(); - [DataField("amplification")] + /// + /// An abstraction of how "Powerful" a psychic is. This is most commonly used as a multiplier on numerical outputs for psychic powers. + /// + /// + /// For an ordinary human, this will be between 0.5 and 1.2, but may be higher for some entities. + /// + [DataField] public float Amplification = 0.1f; - [DataField("dampening")] + /// + /// An abstraction of how much "Control" a psychic has over their powers. This is most commonly used to decrease glimmer output of powers, + /// or to make obvious powers less likely to be obvious. + /// + [DataField] public float Dampening = 0.1f; public bool Telepath = true; public bool TelepathicMute = false; From c8e0572c675b51d78681637c89de8b4c7d3c5a9f Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Mon, 1 Jul 2024 19:22:48 -0400 Subject: [PATCH 58/82] simplify GlimmerEquilibrium constant --- .../Psionics/Abilities/PyrokinesisPowerSystem.cs | 2 +- .../Glimmer/Structures/GlimmerStructuresSystem.cs | 2 +- Content.Shared/Psionics/Glimmer/GlimmerSystem.cs | 9 +-------- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs index 07ada4c0c5d..f3e2cc69fd5 100644 --- a/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/PyrokinesisPowerSystem.cs @@ -118,7 +118,7 @@ private void OnPowerUsed(PyrokinesisPowerActionEvent args) fireball.IntensitySlope = 1 * psionicFactor; fireball.TotalIntensity = 25 * psionicFactor; - if (_glimmerSystem.GlimmerOutput >= _glimmerSystem.GlimmerEquilibrium) + if (_glimmerSystem.GlimmerOutput >= GlimmerSystem.GlimmerEquilibrium) fireball.CanCreateVacuum = true; else fireball.CanCreateVacuum = false; diff --git a/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs b/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs index b8649f71a5f..309bd732ef7 100644 --- a/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs +++ b/Content.Server/Psionics/Glimmer/Structures/GlimmerStructuresSystem.cs @@ -76,7 +76,7 @@ public override void Update(float frameTime) if (source.Accumulator > source.SecondsPerGlimmer) { - var glimmerEquilibrium = _glimmerSystem.GlimmerEquilibrium; + var glimmerEquilibrium = GlimmerSystem.GlimmerEquilibrium; source.Accumulator -= source.SecondsPerGlimmer; // Shorthand explanation: diff --git a/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs b/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs index f40a916f487..b376f8aab79 100644 --- a/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs +++ b/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs @@ -30,15 +30,8 @@ public float GlimmerInput /// /// This constant is equal to the intersection of the Glimmer Equation(https://www.desmos.com/calculator/posutiq38e) and the line Y = X. /// - private const float _glimmerEquilibrium = 502.941f; + public const float GlimmerEquilibrium = 502.941f; - /// - /// This constant is equal to the intersection of the Glimmer Equation(https://www.desmos.com/calculator/posutiq38e) and the line Y = X. - /// - public float GlimmerEquilibrium - { - get { return _glimmerEquilibrium; } - } /// /// Glimmer Output represents the player-facing value of the station's glimmer, and is given by f(x) for this graph: https://www.desmos.com/calculator/posutiq38e From 35eb6f6a0266b26ba605ab330c3c5ee0cf757aaf Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Mon, 1 Jul 2024 19:40:53 -0400 Subject: [PATCH 59/82] Some more small optimizations --- Content.Server/Psionics/Abilities/DispelPowerSystem.cs | 6 +++++- Content.Shared/Psionics/Glimmer/GlimmerSystem.cs | 8 ++++++++ Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs | 3 ++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Content.Server/Psionics/Abilities/DispelPowerSystem.cs b/Content.Server/Psionics/Abilities/DispelPowerSystem.cs index 33c6b5dcaed..73c6f5d339c 100644 --- a/Content.Server/Psionics/Abilities/DispelPowerSystem.cs +++ b/Content.Server/Psionics/Abilities/DispelPowerSystem.cs @@ -84,7 +84,11 @@ private void OnPowerUsed(DispelPowerActionEvent args) { args.Handled = true; _psionics.LogPowerUsed(args.Performer, "dispel", psionic, 1, 1, true); - _glimmerSystem.DeltaGlimmerInput(-_random.NextFloat(2 * psionic.Dampening - psionic.Amplification, 4 * psionic.Dampening - psionic.Amplification)); + + // Redundant check here as well for a small performance optimization + // Dispel has its own niche equations for glimmer. + if (_glimmerSystem.GetGlimmerEnabled()) + _glimmerSystem.DeltaGlimmerOutput(-_random.NextFloat(2 * psionic.Dampening - psionic.Amplification, 4 * psionic.Dampening - psionic.Amplification)); } } diff --git a/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs b/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs index b376f8aab79..9b8d20b295d 100644 --- a/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs +++ b/Content.Shared/Psionics/Glimmer/GlimmerSystem.cs @@ -160,6 +160,14 @@ public float GetGlimmerEquilibriumRatio() return 0.01f; else return GlimmerOutput / GlimmerEquilibrium; } + + /// + /// Returns the GlimmerEnabled CVar, useful for niche early exits in systems that otherwise don't have any calls to CVars. + /// + public bool GetGlimmerEnabled() + { + return _enabled; + } } [Serializable, NetSerializable] diff --git a/Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs b/Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs index f905ec4dd44..4dd8fa2442f 100644 --- a/Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs +++ b/Content.Shared/Psionics/SharedPsionicAbilitiesSystem.cs @@ -88,7 +88,8 @@ public void LogPowerUsed(EntityUid uid, string power, PsionicComponent? psionic var ev = new PsionicPowerUsedEvent(uid, power); RaiseLocalEvent(uid, ev, false); - if (!overrideGlimmer) + //Redundant check for the GlimmerEnabled CVar because I want to skip this math too if its turned off. + if (_glimmerSystem.GetGlimmerEnabled() && !overrideGlimmer) { if (psionic == null) _glimmerSystem.DeltaGlimmerInput(_robustRandom.NextFloat(minGlimmer, maxGlimmer)); From 631a4bfa46fd58b5045380d8de06370a7af416ff Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Mon, 1 Jul 2024 20:09:16 -0400 Subject: [PATCH 60/82] Removing the single power requirement We now have a glimmer system that can accommodate and account for lots of psychics with multiple powers. --- Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs index 9de4e412c81..ed75d097c01 100644 --- a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs @@ -37,9 +37,6 @@ public void AddPsionics(EntityUid uid) if (Deleted(uid)) return; - if (HasComp(uid)) - return; - AddRandomPsionicPower(uid); } public void AddRandomPsionicPower(EntityUid uid) From 2f2f658a09e62f5e63196097f92121dffa8ffdb6 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Mon, 1 Jul 2024 20:10:44 -0400 Subject: [PATCH 61/82] Ye --- .../Nyanotrasen/StationEvents/Events/NoosphericStormRule.cs | 2 +- Content.Server/Psionics/PsionicsSystem.cs | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericStormRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericStormRule.cs index c26ab1481ac..021c9591022 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericStormRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericStormRule.cs @@ -30,7 +30,7 @@ protected override void Started(EntityUid uid, NoosphericStormRuleComponent comp continue; // Skip over those who are already psionic or those who are insulated, or zombies. - if (HasComp(potentialPsionic) || HasComp(potentialPsionic) || HasComp(potentialPsionic)) + if (HasComp(potentialPsionic) || HasComp(potentialPsionic)) continue; validList.Add(potentialPsionic); diff --git a/Content.Server/Psionics/PsionicsSystem.cs b/Content.Server/Psionics/PsionicsSystem.cs index 06250f77ba3..6799b0bd3f5 100644 --- a/Content.Server/Psionics/PsionicsSystem.cs +++ b/Content.Server/Psionics/PsionicsSystem.cs @@ -127,9 +127,6 @@ private void OnStamHit(EntityUid uid, AntiPsionicWeaponComponent component, Stam public void RollPsionics(EntityUid uid, PotentialPsionicComponent component, bool applyGlimmer = true, float multiplier = 1f) { - if (HasComp(uid)) - return; - if (!_cfg.GetCVar(CCVars.PsionicRollsEnabled)) return; From 7c7ab3f240a96e5633273168481d1158de67d6ef Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Mon, 1 Jul 2024 21:11:01 -0400 Subject: [PATCH 62/82] Update PsionicAbilitiesSystem.cs --- .../Abilities/PsionicAbilitiesSystem.cs | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs index ed75d097c01..27e93678f21 100644 --- a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs @@ -7,6 +7,7 @@ using Robust.Shared.Random; using Robust.Shared.Prototypes; using Content.Shared.Popups; +using Content.Server.MassMedia.Components; namespace Content.Server.Psionics.Abilities { @@ -37,25 +38,35 @@ public void AddPsionics(EntityUid uid) if (Deleted(uid)) return; - AddRandomPsionicPower(uid); + var rollCount = 0; + while (rollCount < 3) + { + if (AddRandomPsionicPower(uid)) + break; + + rollCount++; + } + } - public void AddRandomPsionicPower(EntityUid uid) + public bool AddRandomPsionicPower(EntityUid uid) { EnsureComp(uid, out var psionic); if (!_prototypeManager.TryIndex("RandomPsionicPowerPool", out var pool)) { Logger.Error("Can't index the random psionic power pool!"); - return; + return false; } - // uh oh, stinky! - var newComponent = (Component) _componentFactory.GetComponent(pool.Pick()); - newComponent.Owner = uid; - - EntityManager.AddComponent(uid, newComponent); + var newComponent = _componentFactory.GetComponent(pool.Pick()); - _glimmerSystem.DeltaGlimmerInput(_random.NextFloat(psionic.Amplification * psionic.Dampening, psionic.Amplification * psionic.Dampening * 5)); + if (!EntityManager.HasComponent(uid, newComponent.GetType())) + { + EntityManager.AddComponent(uid, newComponent); + _glimmerSystem.DeltaGlimmerInput(_random.NextFloat(psionic.Amplification * psionic.Dampening, psionic.Amplification * psionic.Dampening * 5)); + return true; + } + return false; } public void RemovePsionics(EntityUid uid) @@ -93,7 +104,7 @@ public void RemovePsionics(EntityUid uid) _statusEffectsSystem.TryAddStatusEffect(uid, "Stutter", TimeSpan.FromMinutes(5), false, "StutteringAccent"); - _glimmerSystem.DeltaGlimmerOutput(-_random.NextFloat((int) MathF.Round(psionic.Amplification * psionic.Dampening * 5), (int) MathF.Round(psionic.Amplification * psionic.Dampening * 10))); + _glimmerSystem.DeltaGlimmerOutput(-_random.NextFloat(psionic.Amplification * psionic.Dampening * 5, psionic.Amplification * psionic.Dampening * 10)); RemComp(uid); RemComp(uid); } From 10ea788420d744d3a5ea39a0d34ed10bd89808fc Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Mon, 1 Jul 2024 21:32:50 -0400 Subject: [PATCH 63/82] 1984 a while loop and make this actually work without needing one. --- .../Abilities/PsionicAbilitiesSystem.cs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs index 27e93678f21..b839622014d 100644 --- a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs @@ -38,35 +38,35 @@ public void AddPsionics(EntityUid uid) if (Deleted(uid)) return; - var rollCount = 0; - while (rollCount < 3) - { - if (AddRandomPsionicPower(uid)) - break; - - rollCount++; - } + AddRandomPsionicPower(uid); } - public bool AddRandomPsionicPower(EntityUid uid) + public void AddRandomPsionicPower(EntityUid uid) { EnsureComp(uid, out var psionic); if (!_prototypeManager.TryIndex("RandomPsionicPowerPool", out var pool)) { Logger.Error("Can't index the random psionic power pool!"); - return false; + return; } - var newComponent = _componentFactory.GetComponent(pool.Pick()); + var newPool = pool; + foreach (var component in pool.Weights.Keys) + { + var checkedComponent = _componentFactory.GetComponent(component); + if (EntityManager.HasComponent(uid, checkedComponent.GetType())) + newPool.Weights.Remove(component); + } - if (!EntityManager.HasComponent(uid, newComponent.GetType())) + if (newPool.Weights.Keys != null) { + var newComponent = _componentFactory.GetComponent(newPool.Pick()); + EntityManager.AddComponent(uid, newComponent); _glimmerSystem.DeltaGlimmerInput(_random.NextFloat(psionic.Amplification * psionic.Dampening, psionic.Amplification * psionic.Dampening * 5)); - return true; } - return false; + return; } public void RemovePsionics(EntityUid uid) From 8e9afa0c7ade0e79e3e959cf911051687c5b8d8c Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Mon, 1 Jul 2024 21:35:05 -0400 Subject: [PATCH 64/82] Update PsionicAbilitiesSystem.cs --- Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs index b839622014d..24e6bbb8d3b 100644 --- a/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs +++ b/Content.Server/Psionics/Abilities/PsionicAbilitiesSystem.cs @@ -7,7 +7,6 @@ using Robust.Shared.Random; using Robust.Shared.Prototypes; using Content.Shared.Popups; -using Content.Server.MassMedia.Components; namespace Content.Server.Psionics.Abilities { From 44e29dd8ce0b32b70dad42780583fbdc3e5b49b5 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Mon, 1 Jul 2024 22:43:20 -0400 Subject: [PATCH 65/82] Zap now unlocks the next power roll. --- .../StationEvents/Events/NoosphericZapRule.cs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericZapRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericZapRule.cs index 3672d317d9e..a11faa06933 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericZapRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericZapRule.cs @@ -35,19 +35,15 @@ protected override void Started(EntityUid uid, NoosphericZapRuleComponent compon _stunSystem.TryParalyze(psion, TimeSpan.FromSeconds(5), false); _statusEffectsSystem.TryAddStatusEffect(psion, "Stutter", TimeSpan.FromSeconds(10), false, "StutteringAccent"); - if (HasComp(psion)) - _popupSystem.PopupEntity(Loc.GetString("noospheric-zap-seize"), psion, psion, Shared.Popups.PopupType.LargeCaution); + if (potentialPsionicComponent.Rerolled) + { + potentialPsionicComponent.Rerolled = false; + _popupSystem.PopupEntity(Loc.GetString("noospheric-zap-seize-potential-regained"), psion, psion, Shared.Popups.PopupType.LargeCaution); + } else { - if (potentialPsionicComponent.Rerolled) - { - potentialPsionicComponent.Rerolled = false; - _popupSystem.PopupEntity(Loc.GetString("noospheric-zap-seize-potential-regained"), psion, psion, Shared.Popups.PopupType.LargeCaution); - } else - { - _psionicsSystem.RollPsionics(psion, potentialPsionicComponent, multiplier: 0.25f); - _popupSystem.PopupEntity(Loc.GetString("noospheric-zap-seize"), psion, psion, Shared.Popups.PopupType.LargeCaution); - } + _psionicsSystem.RollPsionics(psion, potentialPsionicComponent, multiplier: 0.25f); + _popupSystem.PopupEntity(Loc.GetString("noospheric-zap-seize"), psion, psion, Shared.Popups.PopupType.LargeCaution); } } } From 864ba53a5cf17963608a4325a23b6a27afc6f5ea Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Mon, 1 Jul 2024 22:45:33 -0400 Subject: [PATCH 66/82] Revenant moved to new crit threshold --- Resources/Prototypes/Nyanotrasen/GameRules/events.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Nyanotrasen/GameRules/events.yml b/Resources/Prototypes/Nyanotrasen/GameRules/events.yml index f5626a0406f..decdcfdda26 100644 --- a/Resources/Prototypes/Nyanotrasen/GameRules/events.yml +++ b/Resources/Prototypes/Nyanotrasen/GameRules/events.yml @@ -145,7 +145,7 @@ noSpawn: true components: - type: GlimmerEvent - minimumGlimmer: 500 + minimumGlimmer: 700 maximumGlimmer: 900 report: glimmer-event-report-signatures - type: GlimmerRevenantRule From d461f4fe176ab24b8278d17b500424c840a6348d Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 2 Jul 2024 01:35:29 -0400 Subject: [PATCH 67/82] Don't look at this please. --- Content.Client/Entry/EntryPoint.cs | 1 + .../TypingIndicator/TypingIndicatorSystem.cs | 2 +- .../Components/NPCConversationComponent.cs | 152 +++++ .../NPC/Events/NPCConversationEvents.cs | 63 ++ .../NPCConversationTreePrototype.cs | 154 +++++ .../NPC/Systems/NPCConversationSystem.cs | 558 ++++++++++++++++++ .../SophicScribe/SophicScribeSystem.cs | 36 ++ .../Locale/en-US/npc/conversation/sophia.ftl | 82 +++ .../Structures/Research/sophicscribe.yml | 194 +++++- 9 files changed, 1240 insertions(+), 2 deletions(-) create mode 100644 Content.Server/NPC/Components/NPCConversationComponent.cs create mode 100644 Content.Server/NPC/Events/NPCConversationEvents.cs create mode 100644 Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs create mode 100644 Content.Server/NPC/Systems/NPCConversationSystem.cs create mode 100644 Resources/Locale/en-US/npc/conversation/sophia.ftl diff --git a/Content.Client/Entry/EntryPoint.cs b/Content.Client/Entry/EntryPoint.cs index a1fc68bbd2f..8636e0eb6aa 100644 --- a/Content.Client/Entry/EntryPoint.cs +++ b/Content.Client/Entry/EntryPoint.cs @@ -125,6 +125,7 @@ public override void Init() _prototypeManager.RegisterIgnore("alertLevels"); _prototypeManager.RegisterIgnore("nukeopsRole"); _prototypeManager.RegisterIgnore("stationGoal"); + _prototypeManager.RegisterIgnore("npcConversationTree"); _componentFactory.GenerateNetIds(); _adminManager.Initialize(); diff --git a/Content.Server/Chat/TypingIndicator/TypingIndicatorSystem.cs b/Content.Server/Chat/TypingIndicator/TypingIndicatorSystem.cs index c923738930a..443923f675c 100644 --- a/Content.Server/Chat/TypingIndicator/TypingIndicatorSystem.cs +++ b/Content.Server/Chat/TypingIndicator/TypingIndicatorSystem.cs @@ -54,7 +54,7 @@ private void OnClientTypingChanged(TypingChangedEvent ev, EntitySessionEventArgs SetTypingIndicatorEnabled(uid.Value, ev.IsTyping); } - private void SetTypingIndicatorEnabled(EntityUid uid, bool isEnabled, AppearanceComponent? appearance = null) + public void SetTypingIndicatorEnabled(EntityUid uid, bool isEnabled, AppearanceComponent? appearance = null) { if (!Resolve(uid, ref appearance, false)) return; diff --git a/Content.Server/NPC/Components/NPCConversationComponent.cs b/Content.Server/NPC/Components/NPCConversationComponent.cs new file mode 100644 index 00000000000..c2a8ca31d7d --- /dev/null +++ b/Content.Server/NPC/Components/NPCConversationComponent.cs @@ -0,0 +1,152 @@ +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Content.Server.NPC.Events; +using Content.Server.NPC.Prototypes; +using Content.Server.NPC.Systems; + +namespace Content.Server.NPC.Components; + +[RegisterComponent] +[Access(typeof(NPCConversationSystem))] +public sealed partial class NPCConversationComponent : Component +{ + /// + /// Whether or not the listening logic is turned on. + /// + /// + /// Queued responses will still play through, but no new attempts to listen will be made. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("enabled")] + public bool Enabled = true; + + /* NYI: + /// + /// The NPC will pay attention when one of these words are said. + /// + [ViewVariables] + [DataField("aliases")] + public List Aliases = new(); + */ + + [ViewVariables] + [DataField("tree", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] + public string? ConversationTreeId; + + /// + /// This is the cached prototype. + /// + [ViewVariables] + public NPCConversationTreePrototype ConversationTree = default!; + + /// + /// Topics that are unlocked in the NPC's conversation tree. + /// + [ViewVariables] + public HashSet UnlockedTopics = new(); + + /// + /// How long until we stop paying attention to someone for a prompt. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("attentionSpan")] + public TimeSpan AttentionSpan = TimeSpan.FromSeconds(20); + + /// + /// This is the minimum delay before the NPC makes a response. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("delayBeforeResponse")] + public TimeSpan DelayBeforeResponse = TimeSpan.FromSeconds(0.3); + + /// + /// This is the approximate delay per letter typed in text. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("typingDelay")] + public TimeSpan TypingDelay = TimeSpan.FromSeconds(0.05); + + [ViewVariables] + public Stack ResponseQueue = new(); + + /// + /// This is when the NPC will respond with its top response. + /// + [ViewVariables] + [DataField("nextResponse", customTypeSerializer: typeof(TimeOffsetSerializer))] + public TimeSpan NextResponse; + + /// + /// This is the direction the NPC was facing before looking towards a conversation partner. + /// + [ViewVariables] + public Angle OriginalFacing; + + /// + /// This is who the NPC is paying attention to for conversation. + /// + [ViewVariables] + public EntityUid? AttendingTo; + + /// + /// This is when the NPC will stop paying attention to a specific person. + /// + [ViewVariables] + [DataField("nextAttentionLoss", customTypeSerializer: typeof(TimeOffsetSerializer))] + public TimeSpan NextAttentionLoss; + + /// + /// This event is fired the next time the NPC hears something from the + /// person they're speaking with and it takes control of the response. + /// + [ViewVariables] + public NPCConversationListenEvent? ListeningEvent; + +#region Idle Chatter + + /// + /// Whether or not the NPC will say things unprompted. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("idleEnabled")] + public bool IdleEnabled = true; + + /// + /// This is the approximate delay between idle chats. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("idleChatDelay")] + public TimeSpan IdleChatDelay = TimeSpan.FromMinutes(3); + + /// + /// This is the order in which idle chat lines are given. + /// + /// + /// This is randomized both on init and when the lines have been exhausted + /// to prevent repeating lines twice in a row and to avoid predictable patterns. + /// + /// It technically reduces randomness, with the benefit of less repetition. + /// + [ViewVariables(VVAccess.ReadWrite)] + public List IdleChatOrder = new(); + + /// + /// This is the next idle chat line that will be used. + /// + [ViewVariables(VVAccess.ReadWrite)] + public int IdleChatIndex = 0; + + /// + /// This is when the NPC will say something out of its list of idle lines. + /// + /// + /// This is reset every time the NPC speaks. + /// + [ViewVariables] + [DataField("nextIdleChat", customTypeSerializer: typeof(TimeOffsetSerializer))] + public TimeSpan NextIdleChat; + +#endregion + +} + diff --git a/Content.Server/NPC/Events/NPCConversationEvents.cs b/Content.Server/NPC/Events/NPCConversationEvents.cs new file mode 100644 index 00000000000..eb04f59bdd5 --- /dev/null +++ b/Content.Server/NPC/Events/NPCConversationEvents.cs @@ -0,0 +1,63 @@ +using Robust.Shared.Audio; +using Content.Server.NPC.Systems; + +namespace Content.Server.NPC.Events; + +/// +/// This is used for dynamic responses and post-response events. +/// +[ImplicitDataDefinitionForInheritors] +[Access(typeof(NPCConversationSystem))] +public abstract partial class NPCConversationEvent : EntityEventArgs +{ + /// + /// This is the entity that the NPC is speaking to. + /// + public EntityUid? TalkingTo; +} + +/// +/// This event type is raised when an NPC hears a response when it was set to listen for one. +/// +/// +/// Set Handled to true when you want the NPC to stop listening. +/// The NPC will otherwise keep listening and block any attempt to find a prompt in the speaker's words. +/// +[ImplicitDataDefinitionForInheritors] +[Access(typeof(NPCConversationSystem))] +public abstract partial class NPCConversationListenEvent : HandledEntityEventArgs +{ + /// + /// This is the entity that said the message. + /// + public EntityUid? Speaker; + + /// + /// This is the original message that the NPC heard. + /// + public string Message = default!; + + /// + /// This is the message, parsed into separate words. + /// + public List Words = default!; +} + +public sealed partial class NPCConversationHelpEvent : NPCConversationEvent +{ + [DataField("text")] + public string? Text; + + [DataField("audio")] + public SoundSpecifier? Audio; +} + +/// +/// This event can be raised after a response to cause an NPC to stop paying attention to someone. +/// +public sealed partial class NPCConversationByeEvent : NPCConversationEvent { } + +// The following classes help demonstrate some of the features of the system. +// They may be separated out at some point. +public sealed partial class NPCConversationToldNameEvent : NPCConversationListenEvent { } + diff --git a/Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs b/Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs new file mode 100644 index 00000000000..20a616d8308 --- /dev/null +++ b/Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs @@ -0,0 +1,154 @@ +using Robust.Shared.Audio; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using Content.Server.NPC.Events; + +namespace Content.Server.NPC.Prototypes; + +[Prototype("npcConversationTree")] +public sealed class NPCConversationTreePrototype : IPrototype, ISerializationHooks +{ + [ViewVariables] + [IdDataField] + public string ID { get; } = default!; + + /// + /// Dialogue contains all the topics to which an NPC can discuss. + /// + [ViewVariables] + [DataField("dialogue", required: true)] + public readonly NPCTopic[] Dialogue = default!; + + /// + /// Attention responses are what the NPC says when they start paying + /// attention to you without a specific question or prompt to respond to. + /// + [ViewVariables] + [DataField("attention", required: true)] + public readonly NPCResponse[] Attention = default!; + + /// + /// Idle responses are just things the NPC will say when nothing else is + /// going on, after some time. + /// + [ViewVariables] + [DataField("idle", required: true)] + public readonly NPCResponse[] Idle = default!; + + /// + /// Unknown responses are what the NPC says when they can't respond to a + /// particular question or prompt. + /// + [ViewVariables] + [DataField("unknown", required: true)] + public readonly NPCResponse[] Unknown = default!; + + /// + /// Custom responses are available to use in extensions to the NPC + /// Conversation system. + /// + // NOTE: This may be removed in favor of storing NPCResponses on custom + // components, i.e. an NPCShopkeeperComponent, but for now, it lives here + // to help demonstrate some features. + [ViewVariables] + [DataField("custom")] + public readonly Dictionary Custom = default!; + + /// + /// This exists as a quick way to map a prompt to a topic. + /// + public readonly Dictionary PromptToTopic = new(); + + // ISerializationHooks _is_ obsolete, but ConstructionGraphPrototype is using it as of this commit, + // and I'm not quite sure how to otherwise do this. + // + // I will look at that prototype when ISerializationHooks is phased out. + void ISerializationHooks.AfterDeserialization() + { + // Cache the strings mapping to prompts. + foreach (var topic in Dialogue) + { + foreach (var prompt in topic.Prompts) + { + PromptToTopic[prompt] = topic; + } + } + } +} + +[DataDefinition] +public sealed partial class NPCTopic +{ + [DataField] + public string[] Prompts = default!; + + /// + /// This determines the likelihood of this topic being selected over any + /// other, given the existence of multiple candidates. + /// + [DataField] + public float Weight = 1.0f; + + /// + /// Locked topics will not be accessible through dialogue until unlocked. + /// + [DataField] + public bool Locked; + + /// + /// Hidden topics won't show up in any form of "help" question. + /// + [DataField] + public bool Hidden; + + [DataField("responses", required: true)] + public NPCResponse[] Responses = default!; +} + +[DataDefinition] +public sealed partial class NPCResponse +{ + public NPCResponse() { } + + public NPCResponse(string? text, SoundSpecifier? audio = null, NPCConversationEvent? ev = null) + { + Text = text; + Audio = audio; + Event = ev; + } + + public override string ToString() + { + return $"NPCResponse({Text})"; + } + + [DataField] + public string? Text; + + [DataField] + public SoundSpecifier? Audio; + + /* [DataField("emote")] */ + /* public string? Emote; */ + + /// + /// This event is raised when the response is queued, + /// for the purpose of dynamic responses. + /// + [DataField] + public NPCConversationEvent? Is; + + /// + /// This event is raised after the response is made. + /// + [DataField] + public NPCConversationEvent? Event; + + /// + /// This event is raised when the NPC next hears a response, + /// allowing the response to be processed by other systems. + /// + [DataField] + public NPCConversationListenEvent? ListenEvent; +} + diff --git a/Content.Server/NPC/Systems/NPCConversationSystem.cs b/Content.Server/NPC/Systems/NPCConversationSystem.cs new file mode 100644 index 00000000000..015adb19de5 --- /dev/null +++ b/Content.Server/NPC/Systems/NPCConversationSystem.cs @@ -0,0 +1,558 @@ +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text.RegularExpressions; +using Robust.Server.GameObjects; +using Robust.Shared.Audio; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; +using Robust.Shared.Timing; +using Content.Server.Chat.Systems; +using Content.Server.Chat.TypingIndicator; +using Content.Server.NPC.HTN; +using Content.Server.NPC.Components; +using Content.Server.NPC.Events; +using Content.Server.NPC.Prototypes; +using Content.Server.Speech; +using Content.Shared.Interaction; +using Content.Server.Radio.Components; + +namespace Content.Server.NPC.Systems; + +public sealed class NPCConversationSystem : EntitySystem +{ + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly IPrototypeManager _prototype = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + [Dependency] private readonly ChatSystem _chatSystem = default!; + [Dependency] private readonly NPCSystem _npcSystem = default!; + [Dependency] private readonly RotateToFaceSystem _rotateToFaceSystem = default!; + [Dependency] private readonly TransformSystem _transformSystem = default!; + [Dependency] private readonly TypingIndicatorSystem _typingIndicatorSystem = default!; + + private ISawmill _sawmill = default!; + + // TODO: attention attenuation. distance, facing, visible + // TODO: attending to multiple people, multiple streams of conversation + // TODO: multi-word prompts + // TODO: nameless prompting (pointing is good) + // TODO: aliases + + public static readonly string[] QuestionWords = { "who", "what", "when", "why", "where", "how" }; + public static readonly string[] Copulae = { "is", "are" }; + + public override void Initialize() + { + base.Initialize(); + + _sawmill = Logger.GetSawmill("npc.conversation"); + + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnUnpaused); + SubscribeLocalEvent(OnListenAttempt); + SubscribeLocalEvent(OnListen); + + SubscribeLocalEvent(OnBye); + SubscribeLocalEvent(OnHelp); + + SubscribeLocalEvent(OnToldName); + } + +#region API + + /// + /// Toggle the ability of an NPC to listen for topics. + /// + public void EnableConversation(EntityUid uid, bool enable = true, NPCConversationComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + component.Enabled = enable; + } + + /// + /// Toggle the NPC's willingness to make idle comments. + /// + public void EnableIdleChat(EntityUid uid, bool enable = true, NPCConversationComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + component.IdleEnabled = enable; + } + + /// + /// Return locked status of a dialogue topic. + /// + public bool IsDialogueLocked(EntityUid uid, string option, NPCConversationComponent? component = null) + { + if (!Resolve(uid, ref component)) + return true; + + if (!component.ConversationTree.PromptToTopic.TryGetValue(option, out var topic)) + { + _sawmill.Warning($"Tried to check locked status of missing dialogue option `{option}` on {ToPrettyString(uid)}"); + return true; + } + + if (component.UnlockedTopics.Contains(topic)) + return false; + + return topic.Locked; + } + + /// + /// Unlock dialogue options normally locked in an NPC's conversation tree. + /// + public void UnlockDialogue(EntityUid uid, string option, NPCConversationComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + if (component.ConversationTree.PromptToTopic.TryGetValue(option, out var topic)) + component.UnlockedTopics.Add(topic); + else + _sawmill.Warning($"Tried to unlock missing dialogue option `{option}` on {ToPrettyString(uid)}"); + } + + /// + public void UnlockDialogue(EntityUid uid, HashSet options, NPCConversationComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + foreach (var option in options) + UnlockDialogue(uid, option, component); + } + + /// + /// Queue a response for an NPC with a visible typing indicator and delay between messages. + /// + /// + /// This can be used as opposed to the typical method. + /// + public void QueueResponse(EntityUid uid, NPCResponse response, NPCConversationComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + if (response.Is is {} ev) + { + // This is a dynamic response which will call QueueResponse with static responses of its own. + ev.TalkingTo = component.AttendingTo; + RaiseLocalEvent(uid, (object) ev); + return; + } + + if (component.ResponseQueue.Count == 0) + { + DelayResponse(uid, component, response); + _typingIndicatorSystem.SetTypingIndicatorEnabled(uid, true); + } + + component.ResponseQueue.Push(response); + } + + /// + /// Make an NPC stop paying attention to someone. + /// + public void LoseAttention(EntityUid uid, NPCConversationComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + component.AttendingTo = null; + component.ListeningEvent = null; + _rotateToFaceSystem.TryFaceAngle(uid, component.OriginalFacing); + } + +#endregion + + private void DelayResponse(EntityUid uid, NPCConversationComponent component, NPCResponse response) + { + if (response.Text == null) + return; + + component.NextResponse = _gameTiming.CurTime + + component.DelayBeforeResponse + + component.TypingDelay.TotalSeconds * TimeSpan.FromSeconds(response.Text.Length) * + _random.NextDouble(0.9, 1.1); + } + + private IEnumerable GetAvailableTopics(EntityUid uid, NPCConversationComponent component) + { + HashSet availableTopics = new(); + + foreach (var topic in component.ConversationTree.Dialogue) + { + if (!topic.Locked || component.UnlockedTopics.Contains(topic)) + availableTopics.Add(topic); + } + + return availableTopics; + } + + private IEnumerable GetVisibleTopics(EntityUid uid, NPCConversationComponent component) + { + HashSet visibleTopics = new(); + + foreach (var topic in component.ConversationTree.Dialogue) + { + if (!topic.Hidden && (!topic.Locked || component.UnlockedTopics.Contains(topic))) + visibleTopics.Add(topic); + } + + return visibleTopics; + } + + private void OnInit(EntityUid uid, NPCConversationComponent component, ComponentInit args) + { + if (component.ConversationTreeId == null) + return; + + component.ConversationTree = _prototype.Index(component.ConversationTreeId); + component.NextIdleChat = _gameTiming.CurTime + component.IdleChatDelay; + + for (var i = 0; i < component.ConversationTree.Idle.Length; ++i) + component.IdleChatOrder.Add(i); + + _random.Shuffle(component.IdleChatOrder); + } + + private void OnUnpaused(EntityUid uid, NPCConversationComponent component, ref EntityUnpausedEvent args) + { + component.NextResponse += args.PausedTime; + component.NextAttentionLoss += args.PausedTime; + component.NextIdleChat += args.PausedTime; + } + + private bool TryGetIdleChatLine(EntityUid uid, NPCConversationComponent component, [NotNullWhen(true)] out NPCResponse? line) + { + line = null; + + if (component.IdleChatOrder.Count() == 0) + return false; + + if (++component.IdleChatIndex == component.IdleChatOrder.Count()) + { + // Exhausted all lines in the pre-shuffled order. + // Reset the index and shuffle again. + component.IdleChatIndex = 0; + _random.Shuffle(component.IdleChatOrder); + } + + var index = component.IdleChatOrder[component.IdleChatIndex]; + + line = component.ConversationTree.Idle[index]; + + return true; + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var component)) + { + var curTime = _gameTiming.CurTime; + + if (curTime >= component.NextResponse && component.ResponseQueue.Count > 0) + { + // Make a response. + Respond(uid, component, component.ResponseQueue.Pop()); + } + + if (curTime >= component.NextAttentionLoss && component.AttendingTo != null) + { + // Forget who we were talking to. + LoseAttention(uid, component); + } + + if (component.IdleEnabled && + curTime >= component.NextIdleChat && + TryGetIdleChatLine(uid, component, out var line)) + { + Respond(uid, component, line); + } + } + } + + private void OnListenAttempt(EntityUid uid, NPCConversationComponent component, ListenAttemptEvent args) + { + if (!component.Enabled || + // Don't listen to myself... + uid == args.Source || + // Don't bother listening to other NPCs. For now. + HasComp(args.Source) || + // We're already "typing" a response, so do that first. + component.ResponseQueue.Count > 0) + { + args.Cancel(); + } + } + + private void PayAttentionTo(EntityUid uid, NPCConversationComponent component, EntityUid speaker) + { + component.AttendingTo = speaker; + component.NextAttentionLoss = _gameTiming.CurTime + component.AttentionSpan; + component.OriginalFacing = _transformSystem.GetWorldRotation(uid); + } + + private void Respond(EntityUid uid, NPCConversationComponent component, NPCResponse response) + { + if (component.ResponseQueue.Count == 0) + _typingIndicatorSystem.SetTypingIndicatorEnabled(uid, false); + else + DelayResponse(uid, component, component.ResponseQueue.Peek()); + + if (component.AttendingTo != null) + { + // TODO: This line is a mouthful. Maybe write a public API that supports EntityCoordinates later? + var speakerCoords = Transform(component.AttendingTo.Value).Coordinates.ToMap(EntityManager, _transformSystem).Position; + _rotateToFaceSystem.TryFaceCoordinates(uid, speakerCoords); + } + + if (response.Event is {} ev) + { + ev.TalkingTo = component.AttendingTo; + RaiseLocalEvent(uid, (object) ev); + } + + if (response.ListenEvent != null) + component.ListeningEvent = response.ListenEvent; + + if (response.Text != null) + _chatSystem.TrySendInGameICMessage(uid, Loc.GetString(response.Text), InGameICChatType.Speak, false); + + if (response.Audio != null) + _audioSystem.PlayPvs(response.Audio, uid, + // TODO: Allow this to be configured per NPC/response. + AudioParams.Default + .WithVolume(8f) + .WithMaxDistance(9f) + .WithRolloffFactor(0.5f)); + + // Refresh our attention. + component.NextAttentionLoss = _gameTiming.CurTime + component.AttentionSpan; + component.NextIdleChat = component.NextAttentionLoss + component.IdleChatDelay; + } + + private List ParseMessageIntoWords(string message) + { + return Regex.Replace(message.Trim().ToLower(), @"(\p{P})", "") + .Split() + .ToList(); + } + + private bool FindResponse(EntityUid uid, NPCConversationComponent component, List words, [NotNullWhen(true)] out NPCResponse? response) + { + response = null; + + var availableTopics = GetAvailableTopics(uid, component); + + // Some topics are more interesting than others. + var greatestWeight = 0f; + NPCTopic? candidate = null; + + foreach (var word in words) + { + if (component.ConversationTree.PromptToTopic.TryGetValue(word, out var topic) && + availableTopics.Contains(topic) && + topic.Weight > greatestWeight) + { + greatestWeight = topic.Weight; + candidate = topic; + } + } + + if (candidate != null) + { + response = _random.Pick(candidate.Responses); + return true; + } + + return false; + } + + private bool JudgeQuestionLikelihood(EntityUid uid, NPCConversationComponent component, List words, string message) + { + if (message.Length > 0 && message[^1] == '?') + // A question mark is an absolute mark of a question. + return true; + + if (words.Count == 1) + // The usefulness of this is dubious, but it's definitely a question. + return QuestionWords.Contains(words[0]); + + if (words.Count >= 2) + return QuestionWords.Contains(words[0]) && Copulae.Contains(words[1]); + + return false; + } + + private void OnBye(EntityUid uid, NPCConversationComponent component, NPCConversationByeEvent args) + { + LoseAttention(uid, component); + } + + private void OnHelp(EntityUid uid, NPCConversationComponent component, NPCConversationHelpEvent args) + { + if (args.Text == null) + { + _sawmill.Error($"{ToPrettyString(uid)} heard a Help prompt but has no text for it."); + return; + } + + var availableTopics = GetVisibleTopics(uid, component); + var availablePrompts = availableTopics.Select(topic => topic.Prompts.FirstOrDefault()).ToArray(); + + string availablePromptsText; + if (availablePrompts.Count() <= 2) + { + availablePromptsText = Loc.GetString(args.Text, + ("availablePrompts", string.Join(" or ", availablePrompts)) + ); + } + else + { + availablePrompts[^1] = $"or {availablePrompts[^1]}"; + availablePromptsText = Loc.GetString(args.Text, + ("availablePrompts", string.Join(", ", availablePrompts)) + ); + } + + // Unlikely we'll be able to do audio that isn't hard-coded, + // so best to keep it general. + var response = new NPCResponse(availablePromptsText, args.Audio); + QueueResponse(uid, response, component); + } + + private void OnToldName(EntityUid uid, NPCConversationComponent component, NPCConversationListenEvent args) + { + if (!component.ConversationTree.Custom.TryGetValue("toldName", out var responses)) + return; + + var response = _random.Pick(responses); + if (response.Text == null) + { + _sawmill.Error($"{ToPrettyString(uid)} was told a name but had no text response."); + return; + } + + // The world's simplest heuristic for names: + if (args.Words.Count > 3) + { + // It didn't seem like a name, so wait for something that does. + return; + } + + var cleanedName = string.Join(" ", args.Words); + cleanedName = char.ToUpper(cleanedName[0]) + cleanedName.Remove(0, 1); + + var formattedResponse = new NPCResponse(Loc.GetString(response.Text, + ("name", cleanedName)), + response.Audio); + + QueueResponse(uid, formattedResponse, component); + args.Handled = true; + } + + private void OnListen(EntityUid uid, NPCConversationComponent component, ListenEvent args) + { + if (HasComp(args.Source)) + return; + + if (component.AttendingTo != null && component.AttendingTo != args.Source) + // Ignore someone speaking to us if we're already paying attention to someone else. + return; + + var words = ParseMessageIntoWords(args.Message); + if (words.Count == 0) + return; + + if (component.AttendingTo == args.Source) + { + // The person we're talking to said something to us. + + if (component.ListeningEvent is {} ev) + { + // We were waiting on this person to say something, and they've said something. + ev.Handled = false; + ev.Speaker = component.AttendingTo; + ev.Message = args.Message; + ev.Words = words; + RaiseLocalEvent(uid, (object) ev); + + if (ev.Handled) + component.ListeningEvent = null; + + return; + } + + // We're already paying attention to this person, + // so try to figure out if they said something we can talk about. + if (FindResponse(uid, component, words, out var response)) + { + // A response was found so go ahead with it. + QueueResponse(uid, response, component); + } + else if(JudgeQuestionLikelihood(uid, component, words, args.Message)) + { + // The message didn't match any of the prompts, but it seemed like a question. + var unknownResponse = _random.Pick(component.ConversationTree.Unknown); + QueueResponse(uid, unknownResponse, component); + } + + // If the message didn't seem like a question, + // and it didn't raise any of our topics, + // then politely ignore who we're talking with. + // + // It's better than spamming them with "I don't understand." + return; + } + + // See if someone said our name. + var myName = MetaData(uid).EntityName.ToLower(); + + // So this is a rough heuristic, but if our name occurs within the first three words, + // or is the very last one, someone might be trying to talk to us. + var payAttention = words[0] == myName || words[^1] == myName; + if (!payAttention) + { + for (int i = 1; i < Math.Min(2, words.Count); ++i) + { + if (words[i] == myName) + { + payAttention = true; + break; + } + } + } + + if (payAttention) + { + PayAttentionTo(uid, component, args.Source); + + if (!FindResponse(uid, component, words, out var response)) + { + if(JudgeQuestionLikelihood(uid, component, words, args.Message) && + // This subcondition exists to block our name being interpreted as a question in its own right. + words.Count > 1) + { + response = _random.Pick(component.ConversationTree.Unknown); + } + else + { + response = _random.Pick(component.ConversationTree.Attention); + } + } + + QueueResponse(uid, response, component); + } + } +} + diff --git a/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs b/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs index b1a6c1e9de1..ba5ff0a056d 100644 --- a/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs +++ b/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs @@ -1,5 +1,8 @@ using Content.Server.Psionics.Abilities; using Content.Server.Chat.Systems; +using Content.Server.NPC.Events; +using Content.Server.NPC.Systems; +using Content.Server.NPC.Prototypes; using Content.Server.Radio.Components; using Content.Server.Radio.EntitySystems; using Content.Server.StationEvents.Events; @@ -18,6 +21,8 @@ public sealed partial class SophicScribeSystem : EntitySystem [Dependency] private readonly RadioSystem _radioSystem = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly NPCConversationSystem _conversationSystem = default!; + protected ISawmill Sawmill = default!; public override void Update(float frameTime) { @@ -51,6 +56,32 @@ public override void Initialize() SubscribeLocalEvent(OnInteractHand); SubscribeLocalEvent(OnGlimmerEventEnded); + SubscribeLocalEvent(OnGetGlimmer); + } + + private void OnGetGlimmer(EntityUid uid, SophicScribeComponent component, NPCConversationGetGlimmerEvent args) + { + if (args.Text == null) + { + Sawmill.Error($"{uid} heard a glimmer reading prompt but has no text for it"); + return; + } + + var tier = _glimmerSystem.GetGlimmerTier() switch + { + GlimmerTier.Minimal => Loc.GetString("glimmer-reading-minimal"), + GlimmerTier.Low => Loc.GetString("glimmer-reading-low"), + GlimmerTier.Moderate => Loc.GetString("glimmer-reading-moderate"), + GlimmerTier.High => Loc.GetString("glimmer-reading-high"), + GlimmerTier.Dangerous => Loc.GetString("glimmer-reading-dangerous"), + _ => Loc.GetString("glimmer-reading-critical"), + }; + + var glimmerReadingText = Loc.GetString(args.Text, + ("glimmer", (int) Math.Round(_glimmerSystem.GlimmerOutput)), ("tier", tier)); + + var response = new NPCResponse(glimmerReadingText); + _conversationSystem.QueueResponse(uid, response); } private void OnInteractHand(EntityUid uid, SophicScribeComponent component, InteractHandEvent args) @@ -83,4 +114,9 @@ private void OnGlimmerEventEnded(GlimmerEventEndedEvent args) _radioSystem.SendRadioMessage(speaker, message, channel, speaker); } } + public sealed partial class NPCConversationGetGlimmerEvent : NPCConversationEvent + { + [DataField] + public string? Text; + } } diff --git a/Resources/Locale/en-US/npc/conversation/sophia.ftl b/Resources/Locale/en-US/npc/conversation/sophia.ftl new file mode 100644 index 00000000000..c832d9fc17f --- /dev/null +++ b/Resources/Locale/en-US/npc/conversation/sophia.ftl @@ -0,0 +1,82 @@ +sophia-response-name = You may call me Sophia. +sophia-response-help = You may inquire about one of the following topics: {$availablePrompts}. + +sophia-response-hello-1 = Greetings. +sophia-response-hello-2 = Salutations. + +sophia-response-bye-1 = Fare thee well. +sophia-response-bye-2 = Gods be with you. +sophia-response-bye-3 = Come back wiser. + +sophia-idle-phrase-1 = Mmmm, another portent. +sophia-idle-phrase-2 = The noösphere is quite beautiful today. However, I don't think I could describe it in a way you could understand. +sophia-idle-phrase-3 = I've been here before. You have, too. + +sophia-response-attention-1 = What is it? +sophia-response-attention-2 = What do you seek? +sophia-response-attention-3 = Out with it. + +sophia-response-sorry-1 = That's not a question for me. +sophia-response-sorry-2 = Ask someone else. +sophia-response-sorry-3 = Maybe I know the answer, maybe I do not. Either way, I will not be answering that question. + +sophia-response-nature = My nature doesn't really matter, does it? I'm fulfilling my purpose. Can you say the same, or are you just wasting time? + +sophia-response-epi = 'Epistemics' is a word. Aspiring Hellenes they are, they wished to displace the Latin 'science.' However, in English, epistemics has undesired connotations as a study of knowledge itself, even though the Greek word is a literal replacement for 'science.' + +sophia-response-mantis = 'Mantis' means seer, soothsayer, or prophet. They must be so named because they seek to uncover the truth. And, fittingly with their psionic aptitude, 'mantis' and 'mind' both descend, to the best of our knowledge, from an absolutely ancient word that sounded something like 'mentis.' + +sophia-response-mystagogue = 'Mystagogue' literally means 'leader of the mystics.' You may know the suffix -gogue from 'demogogue.' + +sophia-response-oracle = Oracle? I don't know much about her, and she isn't keen to share her secrets with me. + +sophia-response-psionics = Psionics are extraordinary abilities originating from one's mind. There doesn't seem to be any dominant word to refer to someone with the ability to practice these, although I prefer 'psion' or 'psychic.' + +sophia-response-noosphere = The noösphere is a field connecting all of consciousness. It's the medium through which psionics works. Its strength and effects on the illusory world of the material are based on its pressure. Colloquially, noöspheric pressure is called 'glimmer.' + +sophia-response-god = 'God' is such a vague term. There are so many entities out there that have defeated mortality. How you choose to regard them is your business. + +sophia-response-morphotype = In the first century PCC, several entities reshaped men into their image. I had done the same, if you would believe it. I can offer no evidence of their existence, other than faint memories. Any specific morphotype you want to know about? + +sophia-response-calendar = It's currently 417 PCC. The casuality crisis neccesitated a new year to count from. Due to the nature of the crisis, it can only be said with certainty that 1 PCC is between 2400 and 2700 CE. + +sophia-response-crisis = The first FTL travel was incompatible with the old ways. Fortunately, its resolution made more apparent the inherent futility in trying to give one history, one narrative, one account. Truth cannot be found in the material world, only higher ones. + +sophia-response-metempsychosis = You've died thousands of times, and you'll die thousands more. Some of those lives you may dedicate to trying to stop the cycle. We all carry at least some memory of past lives, usually temporally recent ones. One of the great mysteries of the persistence of fragments is the high concentration of memories from the early 21st century CE, which, inverse to other periods, seem to be more common among the ignorant. + +sophia-response-truth = If you seek the truth, you're in the wrong place. From a perspective tainted by material reality, the best you can hope is to try and divine higher truths that are not dependent on it. + +sophia-response-job = I observe the glimmer here, and record it. + +sophia-response-human = Humans were the base for all the others. But they, too, were shaped. Long, long before the others. + +sophia-response-felinid = Felinids were the first, and the most willing. In true feline nature, they shaped themselves. + +sophia-response-oni = Oni, it is said, originated in Sirius. The brightest star in the night sky from Earth may have attracted some chromatically inclined entities, explaining their vivid coloring. But, that's just speculation. + +sophia-response-arachne = Arachne are the strangest of them. They're not fully mortal. They took the form of humans, but not their genes. Their creator wrote his name in their stead. + +sophia-response-moth = Moths scarecely look human, but, strangely, their genes confirm they are. Their creator shares his name with a genus of moths, and was responsible for the other outlier. + +sophia-response-lamiae = So, you remember? You must be remembering their mythological namesake. If you've really retained that fleeting memory over so many metempsychoses... Perhaps I've said too much. + +sophia-response-cyno = Were those... no... So faint. Ignorance! You cannot remember them! It's impossible! + +sophia-response-harpy = Harpies, it is said, were once men and women, sculpted by greed for a purpose long gone. They were abandoned by their creators on a world named Valerian 4b. + +sophia-response-valerian = The Harpy homeworld? Magestic mountains gleaming in white, forests of brilliant scarlet, oceans wine dark, yet no light to be seen by mortal eyes. The Harpies were made to thrive there. To them, their world was bathed in beautiful silver light. + +sophia-response-grue = You do not know of those. You cannot. I had so hoped to live a few cycles under normal causality. + +sophia-response-abraxas = That's a name of power, and I avoid speaking of him. He's the least content to rest, and the most infatuated with creating things from ignorance. + +sophia-response-zork = You wander into the slavering fangs of a hungry grue. There, did you enjoy this game? + +sophia-response-glimmer = The current glimmer reading is {$glimmer}. {$tier} + +glimmer-reading-minimal = That is extremely low. Nothing bad will happen, but I hope this is not at the cost of progression in your understanding of the universe. +glimmer-reading-low = That is quite low. Just barely enough to register any psionic activity here. +glimmer-reading-moderate = That is about the expected level on a psionically active station. You may notice manageable, minor effects. +glimmer-reading-high = That is sure to start attracting attention, although still quite manageable. +glimmer-reading-dangerous = That's a bit concerning. You may want to redirect efforts to reducing it. +glimmer-reading-critical = That's apocalyptic, in the original sense of the word. That is, to say, revealing. This is the sort of time and place to acquire secret knowledge. diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml index 8e34a07ea5e..5213608d95e 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml @@ -1,7 +1,7 @@ - type: entity parent: BaseStructure id: SophicScribe - name: sophie + name: Sophie description: Latest reports on the Noösphere! components: - type: Sprite @@ -27,6 +27,10 @@ channels: - Common - Science + - type: ActiveListener + - type: TypingIndicator + - type: NPCConversation + tree: SophiaTree - type: PotentialPsionic #this makes her easier to access for glimmer events, dw about it - type: Psionic psychicFeedback: @@ -39,3 +43,191 @@ - type: GuideHelp guides: - Psionics + +- type: npcConversationTree + id: SophiaTree + dialogue: + - prompts: [glimmer, reading] + responses: + - is: !type:NPCConversationGetGlimmerEvent + text: sophia-response-glimmer + + - prompts: [purpose, job, occupation, profession] + weight: 0.5 + responses: + - text: sophia-response-job + + - prompts: [help, topics] + weight: 0.5 + hidden: true + responses: + - is: !type:NPCConversationHelpEvent + text: sophia-response-help + + - prompts: [nature, statue, snake, being] + weight: 0.3 + responses: + - text: sophia-response-nature + + - prompts: [epistemics, epi] + weight: 0.2 + responses: + - text: sophia-response-epi + + - prompts: [mantis] + weight: 0.2 + responses: + - text: sophia-response-mantis + + - prompts: [mystagogue, mysta] + weight: 0.2 + responses: + - text: sophia-response-mystagogue + + - prompts: [psionics, psychic] + weight: 0.2 + responses: + - text: sophia-response-psionics + + - prompts: [noösphere, noosphere] + weight: 0.2 + responses: + - text: sophia-response-noosphere + + - prompts: [metempsychosis, metempsychoses, reincarnation, death, dying, afterlife] + weight: 0.2 + responses: + - text: sophia-response-metempsychosis + + - prompts: [calendar] + weight: 0.2 + responses: + - text: sophia-response-calendar + + - prompts: [morphotypes, morphotype, species] + weight: 0.2 + responses: + - text: sophia-response-morphotype + + - prompts: [gods, god] + weight: 0.1 + hidden: true + responses: + - text: sophia-response-god + + - prompts: [truth, "true", "false", falsity, falsehood] + weight: 0.1 + hidden: true + responses: + - text: sophia-response-truth + + - prompts: [human, humans, humanoid, unmutated] + weight: 0.1 + hidden: true + responses: + - text: sophia-response-human + + - prompts: [felinid, felinids, felid, felids, catperson, catpeople] + weight: 0.1 + hidden: true + responses: + - text: sophia-response-felinid + + - prompts: [oni, onis] + weight: 0.1 + hidden: true + responses: + - text: sophia-response-oni + + - prompts: [arachne, arachnid, arachnids, spiderperson, spiderpeople] + weight: 0.1 + hidden: true + responses: + - text: sophia-response-arachne + + - prompts: [moth, moths, moff, moths] + weight: 0.1 + hidden: true + responses: + - text: sophia-response-moth + + - prompts: [lamiae, lamia, lamias] + weight: 0.1 + hidden: true + responses: + - text: sophia-response-lamiae + + - prompts: [grue, grues, batperson, batpeople] + weight: 0.1 + hidden: true + responses: + - text: sophia-response-grue + + - prompts: [cynocephalus, cynocephali, cyno, cynos] + weight: 0.1 + hidden: true + responses: + - text: sophia-response-cyno + + - prompts: [harpy, harpies] + weight: 0.1 + hidden: true + responses: + - text: sophia-response-harpy + + - prompts: [valerian, Valerian, 4b] + weight: 0.1 + hidden: true + responses: + - text: sophia-response-valerian + + - prompts: [crisis, causality] + weight: 0.1 + hidden: true + responses: + - text: sophia-response-crisis + + - prompts: [oracle] + weight: 0.1 + hidden: true + responses: + - text: sophia-response-oracle + + - prompts: [abraxas] + weight: 0.1 + hidden: true + responses: + - text: sophia-response-abraxas + + - prompts: [hi, hello, hey, greetings, salutations] + weight: 0.1 + hidden: true + responses: + - text: sophia-response-hello-1 + - text: sophia-response-hello-2 + + - prompts: [bye, goodbye, done, farewell, later, seeya] + weight: 0.1 + hidden: true + responses: + - text: sophia-response-bye-1 + event: !type:NPCConversationByeEvent + - text: sophia-response-bye-2 + event: !type:NPCConversationByeEvent + - text: sophia-response-bye-3 + event: !type:NPCConversationByeEvent + + attention: + - text: sophia-response-attention-1 + - text: sophia-response-attention-2 + - text: sophia-response-attention-3 + + idle: + - text: sophia-idle-phrase-1 + - text: sophia-idle-phrase-2 + - text: sophia-idle-phrase-3 + + unknown: + - text: sophia-response-sorry-1 + - text: sophia-response-sorry-2 + - text: sophia-response-sorry-3 From 4752115623ee410cd30942a1c67beab3c4f073ae Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 2 Jul 2024 01:54:53 -0400 Subject: [PATCH 68/82] First attempt at the error --- Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs b/Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs index 20a616d8308..a147cf1f74b 100644 --- a/Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs +++ b/Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs @@ -68,8 +68,12 @@ void ISerializationHooks.AfterDeserialization() // Cache the strings mapping to prompts. foreach (var topic in Dialogue) { + if (topic == null) + continue; foreach (var prompt in topic.Prompts) { + if (prompt == null) + continue; PromptToTopic[prompt] = topic; } } From 10803e1cbce75b27750646842ecffeb7071598b3 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 2 Jul 2024 03:01:49 -0400 Subject: [PATCH 69/82] Trying this --- Content.Server/Entry/EntryPoint.cs | 1 + Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Content.Server/Entry/EntryPoint.cs b/Content.Server/Entry/EntryPoint.cs index 28687d17cd7..2e8b298d080 100644 --- a/Content.Server/Entry/EntryPoint.cs +++ b/Content.Server/Entry/EntryPoint.cs @@ -70,6 +70,7 @@ public override void Init() prototypes.RegisterIgnore("parallax"); prototypes.RegisterIgnore("guideEntry"); + prototypes.RegisterIgnore("npcConversationTree"); ServerContentIoC.Register(); diff --git a/Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs b/Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs index a147cf1f74b..d1280723ec8 100644 --- a/Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs +++ b/Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs @@ -6,11 +6,11 @@ namespace Content.Server.NPC.Prototypes; [Prototype("npcConversationTree")] -public sealed class NPCConversationTreePrototype : IPrototype, ISerializationHooks +public sealed partial class NPCConversationTreePrototype : IPrototype, ISerializationHooks { [ViewVariables] [IdDataField] - public string ID { get; } = default!; + public string ID { get; private set; } = default!; /// /// Dialogue contains all the topics to which an NPC can discuss. From 7b89ce1326c74e9d813ac56b497951c867b3af3e Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 2 Jul 2024 03:15:06 -0400 Subject: [PATCH 70/82] Cherrypick "Fix StrippableSystem Blunders" (#504) --- Content.Server/Strip/StrippableSystem.cs | 16 +++++++++++----- .../Strip/Components/StrippableComponent.cs | 4 ++-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/Content.Server/Strip/StrippableSystem.cs b/Content.Server/Strip/StrippableSystem.cs index 950411a8e2c..3b38b65a19d 100644 --- a/Content.Server/Strip/StrippableSystem.cs +++ b/Content.Server/Strip/StrippableSystem.cs @@ -122,13 +122,12 @@ public override void StartOpeningStripper(EntityUid user, Entity strippable, ref StrippingSlotButtonPressed args) { if (args.Session.AttachedEntity is not { Valid: true } user || - !TryComp(user, out var userHands) || - !TryComp(strippable.Owner, out var targetHands)) + !TryComp(user, out var userHands)) return; if (args.IsHand) { - StripHand((user, userHands), (strippable.Owner, targetHands), args.Slot, strippable); + StripHand((user, userHands), (strippable.Owner, null), args.Slot, strippable); return; } @@ -478,6 +477,9 @@ private void StripInsertHand( !Resolve(target, ref target.Comp)) return; + if (!CanStripInsertHand(user, target, held, handName)) + return; + _handsSystem.TryDrop(user, checkActionBlocker: false, handsComp: user.Comp); _handsSystem.TryPickup(target, held, handName, checkActionBlocker: false, animateUser: stealth, animate: stealth, handsComp: target.Comp); _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has placed the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s hands"); @@ -542,7 +544,7 @@ private void StartStripRemoveHand( var (time, stealth) = GetStripTimeModifiers(user, target, targetStrippable.HandStripDelay); if (!stealth) - _popupSystem.PopupEntity( Loc.GetString("strippable-component-alert-owner", ("user", Identity.Entity(user, EntityManager)), ("item", item)), target, target); + _popupSystem.PopupEntity(Loc.GetString("strippable-component-alert-owner", ("user", Identity.Entity(user, EntityManager)), ("item", item)), target, target); var prefix = stealth ? "stealthily " : ""; _adminLogger.Add(LogType.Stripping, LogImpact.Low, $"{ToPrettyString(user):actor} is trying to {prefix}strip the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s hands"); @@ -569,12 +571,16 @@ private void StripRemoveHand( Entity user, Entity target, EntityUid item, + string handName, bool stealth) { if (!Resolve(user, ref user.Comp) || !Resolve(target, ref target.Comp)) return; + if (!CanStripRemoveHand(user, target, item, handName)) + return; + _handsSystem.TryDrop(target, item, checkActionBlocker: false, handsComp: target.Comp); _handsSystem.PickupOrDrop(user, item, animateUser: stealth, animate: stealth, handsComp: user.Comp); _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has stripped the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s hands"); @@ -625,7 +631,7 @@ private void OnStrippableDoAfterFinished(Entity entity, ref Stri { if (ev.InsertOrRemove) StripInsertHand((entity.Owner, entity.Comp), ev.Target.Value, ev.Used.Value, ev.SlotOrHandName, ev.Args.Hidden); - else StripRemoveHand((entity.Owner, entity.Comp), ev.Target.Value, ev.Used.Value, ev.Args.Hidden); + else StripRemoveHand((entity.Owner, entity.Comp), ev.Target.Value, ev.Used.Value, ev.SlotOrHandName, ev.Args.Hidden); } } } diff --git a/Content.Shared/Strip/Components/StrippableComponent.cs b/Content.Shared/Strip/Components/StrippableComponent.cs index 8bf09c3f4c6..4faca4d8f21 100644 --- a/Content.Shared/Strip/Components/StrippableComponent.cs +++ b/Content.Shared/Strip/Components/StrippableComponent.cs @@ -35,11 +35,11 @@ public sealed class StrippingEnsnareButtonPressed : BoundUserInterfaceMessage; public abstract class BaseBeforeStripEvent(TimeSpan initialTime, bool stealth = false) : EntityEventArgs, IInventoryRelayEvent { public readonly TimeSpan InitialTime = initialTime; - public TimeSpan Multiplier = TimeSpan.FromSeconds(1f); + public float Multiplier = 1f; public TimeSpan Additive = TimeSpan.Zero; public bool Stealth = stealth; - public TimeSpan Time => TimeSpan.FromSeconds(MathF.Max(InitialTime.Seconds * Multiplier.Seconds + Additive.Seconds, 0f)); + public TimeSpan Time => TimeSpan.FromSeconds(MathF.Max(InitialTime.Seconds * Multiplier + Additive.Seconds, 0f)); public SlotFlags TargetSlots { get; } = SlotFlags.GLOVES; } From 606a28d11e706681ec23f0db32eb01ddc0534a2d Mon Sep 17 00:00:00 2001 From: WarMechanic <69510347+WarMechanic@users.noreply.github.com> Date: Tue, 2 Jul 2024 17:18:27 +1000 Subject: [PATCH 71/82] Fix Loadouts Breaking when You Spend All Your Points (#506) # Description Self explanatory P.S. i genuinely dont know what the fuck i did, who wrote this? # TODO - [X] Fix shit # Media https://youtu.be/hbJbd5SgZ54 # Changelog :cl: - fix: Fixed loadouts becoming uneditable after spending all your points --- Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs b/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs index c797f02a754..04810b07719 100644 --- a/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs +++ b/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs @@ -2086,7 +2086,7 @@ void AddSelector(LoadoutPreferenceSelector selector, int points, string id) selector.PreferenceChanged += preference => { // Make sure they have enough loadout points - preference = preference ? CheckPoints(points, preference) : CheckPoints(-points, preference); + preference = preference ? CheckPoints(-points, preference) : CheckPoints(points, preference); // Update Preferences Profile = Profile?.WithLoadoutPreference(id, preference); From 0d0dd4c01bfd859004b3b399d482187e6ba58ea8 Mon Sep 17 00:00:00 2001 From: SimpleStation Changelogs Date: Tue, 2 Jul 2024 07:18:51 +0000 Subject: [PATCH 72/82] Automatic Changelog Update (#506) --- Resources/Changelog/Changelog.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 515c1832db1..e4e812edeb4 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -4265,3 +4265,9 @@ Entries: rather than fall at their feet. id: 6133 time: '2024-07-01T22:37:29.0000000+00:00' +- author: WarMechanic + changes: + - type: Fix + message: Fixed loadouts becoming uneditable after spending all your points + id: 6134 + time: '2024-07-02T07:18:27.0000000+00:00' From eaacdeaa57ee06826f18060553ef78abe575828d Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 2 Jul 2024 03:37:28 -0400 Subject: [PATCH 73/82] Revert "Trying this" This reverts commit 10803e1cbce75b27750646842ecffeb7071598b3. --- Content.Server/Entry/EntryPoint.cs | 1 - Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Content.Server/Entry/EntryPoint.cs b/Content.Server/Entry/EntryPoint.cs index 2e8b298d080..28687d17cd7 100644 --- a/Content.Server/Entry/EntryPoint.cs +++ b/Content.Server/Entry/EntryPoint.cs @@ -70,7 +70,6 @@ public override void Init() prototypes.RegisterIgnore("parallax"); prototypes.RegisterIgnore("guideEntry"); - prototypes.RegisterIgnore("npcConversationTree"); ServerContentIoC.Register(); diff --git a/Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs b/Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs index d1280723ec8..a147cf1f74b 100644 --- a/Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs +++ b/Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs @@ -6,11 +6,11 @@ namespace Content.Server.NPC.Prototypes; [Prototype("npcConversationTree")] -public sealed partial class NPCConversationTreePrototype : IPrototype, ISerializationHooks +public sealed class NPCConversationTreePrototype : IPrototype, ISerializationHooks { [ViewVariables] [IdDataField] - public string ID { get; private set; } = default!; + public string ID { get; } = default!; /// /// Dialogue contains all the topics to which an NPC can discuss. From 5fc1ce81388dc91f3a1ae1887e91d9835651bf14 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 2 Jul 2024 03:37:31 -0400 Subject: [PATCH 74/82] Revert "First attempt at the error" This reverts commit 4752115623ee410cd30942a1c67beab3c4f073ae. --- Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs b/Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs index a147cf1f74b..20a616d8308 100644 --- a/Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs +++ b/Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs @@ -68,12 +68,8 @@ void ISerializationHooks.AfterDeserialization() // Cache the strings mapping to prompts. foreach (var topic in Dialogue) { - if (topic == null) - continue; foreach (var prompt in topic.Prompts) { - if (prompt == null) - continue; PromptToTopic[prompt] = topic; } } From ffb9ec979ff9ffe76d81eeffa84cea0be45ac2fc Mon Sep 17 00:00:00 2001 From: Mnemotechnican <69920617+Mnemotechnician@users.noreply.github.com> Date: Tue, 2 Jul 2024 11:00:14 +0300 Subject: [PATCH 75/82] Unflip Hands for Felinid, Vulpkanin, Harpy (#503) # Description Cherry-picks https://github.com/DeltaV-Station/Delta-v/pull/1194 This is a minor issue in the yml files of custom species that will become a problem if we ever merge wizden's better hand indicators. This PR shouldn't require a preview; all credit goes to the original author of the fix. --- # Changelog Too minor for a cl. Or as some say, no cl no fun. Co-authored-by: Angelo Fallaria --- Resources/Prototypes/DeltaV/Body/Prototypes/harpy.yml | 5 ++--- Resources/Prototypes/DeltaV/Body/Prototypes/vulpkanin.yml | 6 +++--- .../Nyanotrasen/Entities/Body/Prototypes/felinid.yml | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Prototypes/DeltaV/Body/Prototypes/harpy.yml b/Resources/Prototypes/DeltaV/Body/Prototypes/harpy.yml index 5b3615c55d8..25988f4a3a8 100644 --- a/Resources/Prototypes/DeltaV/Body/Prototypes/harpy.yml +++ b/Resources/Prototypes/DeltaV/Body/Prototypes/harpy.yml @@ -13,10 +13,10 @@ torso: part: TorsoHarpy connections: - - left arm - right arm - - left leg + - left arm - right leg + - left leg organs: heart: OrganHumanHeart lungs: OrganHarpyLungs @@ -47,4 +47,3 @@ part: RightFootHarpy left foot: part: LeftFootHarpy - diff --git a/Resources/Prototypes/DeltaV/Body/Prototypes/vulpkanin.yml b/Resources/Prototypes/DeltaV/Body/Prototypes/vulpkanin.yml index 3d1552ac81f..cdf787e4736 100644 --- a/Resources/Prototypes/DeltaV/Body/Prototypes/vulpkanin.yml +++ b/Resources/Prototypes/DeltaV/Body/Prototypes/vulpkanin.yml @@ -1,4 +1,4 @@ -- type: body +- type: body name: "vulpkanin" id: Vulpkanin root: torso @@ -19,10 +19,10 @@ liver: OrganAnimalLiver kidneys: OrganHumanKidneys connections: - - left arm - right arm - - left leg + - left arm - right leg + - left leg right arm: part: RightArmVulpkanin connections: diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Body/Prototypes/felinid.yml b/Resources/Prototypes/Nyanotrasen/Entities/Body/Prototypes/felinid.yml index 6dd2a89e5a8..a09f3b6ab7f 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Body/Prototypes/felinid.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Body/Prototypes/felinid.yml @@ -13,10 +13,10 @@ torso: part: TorsoHuman connections: - - left arm - right arm - - left leg + - left arm - right leg + - left leg organs: heart: OrganAnimalHeart lungs: OrganHumanLungs From 7a124612a1b08b0d46f9baa2025c764d1b3a08de Mon Sep 17 00:00:00 2001 From: Mnemotechnican <69920617+Mnemotechnician@users.noreply.github.com> Date: Tue, 2 Jul 2024 11:01:35 +0300 Subject: [PATCH 76/82] Cherry-Pick the Secwatch Pda App (#502) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description Cherry-picks https://github.com/DeltaV-Station/Delta-v/pull/1237 All credit goes to the original author, deltanedas Adds a PDA app that lets seccies know who's wanted and who's about to be thrown out of an airlock without relying on the sechud and people having their IDs on them. # Media ![image](https://github.com/Simple-Station/Einstein-Engines/assets/69920617/37f5fa1a-27a5-4392-b4bb-be0f1016b499) (see the original PR for a better preview) # Changelog :cl: deltanedas - add: Security can find the new SecWatch™ app in their PDAs to see current suspects and wanted criminals. Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com> Co-authored-by: Azzy --- .../Cartridges/CrimeAssistUi.cs | 9 --- .../Cartridges/CrimeAssistUiFragment.xaml.cs | 3 - .../Cartridges/SecWatchEntryControl.xaml | 19 +++++ .../Cartridges/SecWatchEntryControl.xaml.cs | 21 ++++++ .../CartridgeLoader/Cartridges/SecWatchUi.cs | 27 +++++++ .../Cartridges/SecWatchUiFragment.xaml | 13 ++++ .../Cartridges/SecWatchUiFragment.xaml.cs | 25 +++++++ .../Cartridges/SecWatchCartridgeComponent.cs | 23 ++++++ .../Cartridges/SecWatchCartridgeSystem.cs | 73 +++++++++++++++++++ .../CrimeAssistCartridgeComponent.cs | 5 -- .../CrimeAssistCartridgeSystem.cs | 16 ---- .../Cartridges/CrimeAssistUiState.cs | 18 ----- .../Cartridges/SecWatchUiState.cs | 24 ++++++ .../deltav/cartridge-loader/secwatch.ftl | 5 ++ .../Entities/Objects/Devices/cartridges.yml | 22 +++++- .../DeltaV/Entities/Objects/Devices/pda.yml | 3 +- .../Entities/Objects/Devices/pda.yml | 24 ++++-- .../Entities/Objects/Devices/pda.yml | 3 +- 18 files changed, 271 insertions(+), 62 deletions(-) create mode 100644 Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml create mode 100644 Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml.cs create mode 100644 Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUi.cs create mode 100644 Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml create mode 100644 Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml.cs create mode 100644 Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeComponent.cs create mode 100644 Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeSystem.cs delete mode 100644 Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeComponent.cs delete mode 100644 Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeSystem.cs delete mode 100644 Content.Shared/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiState.cs create mode 100644 Content.Shared/DeltaV/CartridgeLoader/Cartridges/SecWatchUiState.cs create mode 100644 Resources/Locale/en-US/deltav/cartridge-loader/secwatch.ftl diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUi.cs b/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUi.cs index ea5aa3cf256..2dbe923b2a6 100644 --- a/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUi.cs +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUi.cs @@ -18,15 +18,6 @@ public override Control GetUIFragmentRoot() public override void Setup(BoundUserInterface userInterface, EntityUid? fragmentOwner) { _fragment = new CrimeAssistUiFragment(); - - _fragment.OnSync += _ => SendSyncMessage(userInterface); - } - - private void SendSyncMessage(BoundUserInterface userInterface) - { - var syncMessage = new CrimeAssistSyncMessageEvent(); - var message = new CartridgeUiMessage(syncMessage); - userInterface.SendMessage(message); } public override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiFragment.xaml.cs b/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiFragment.xaml.cs index e3163975d12..fb085a8a799 100644 --- a/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiFragment.xaml.cs +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiFragment.xaml.cs @@ -1,7 +1,6 @@ using Content.Client.Message; using Content.Shared.DeltaV.CartridgeLoader.Cartridges; using Robust.Client.AutoGenerated; -using Robust.Client.ResourceManagement; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; using Robust.Shared.Prototypes; @@ -13,9 +12,7 @@ namespace Content.Client.DeltaV.CartridgeLoader.Cartridges; public sealed partial class CrimeAssistUiFragment : BoxContainer { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly IResourceCache _resourceCache = default!; - public event Action? OnSync; private CrimeAssistPage _currentPage; private List? _pages; diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml new file mode 100644 index 00000000000..2de8a37ff77 --- /dev/null +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml @@ -0,0 +1,19 @@ + + + + + + + + + + diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml.cs b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml.cs new file mode 100644 index 00000000000..e8dd4eea446 --- /dev/null +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml.cs @@ -0,0 +1,21 @@ +using Content.Shared.CartridgeLoader.Cartridges; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.DeltaV.CartridgeLoader.Cartridges; + +[GenerateTypedNameReferences] +public sealed partial class SecWatchEntryControl : BoxContainer +{ + public SecWatchEntryControl(SecWatchEntry entry) + { + RobustXamlLoader.Load(this); + + Status.Text = Loc.GetString($"criminal-records-status-{entry.Status.ToString().ToLower()}"); + Title.Text = Loc.GetString("sec-watch-entry", ("name", entry.Name), ("job", entry.Job)); + + Reason.Text = entry.Reason ?? Loc.GetString("sec-watch-no-reason"); + } +} diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUi.cs b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUi.cs new file mode 100644 index 00000000000..da5ff825b91 --- /dev/null +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUi.cs @@ -0,0 +1,27 @@ +using Content.Client.UserInterface.Fragments; +using Content.Shared.CartridgeLoader; +using Content.Shared.CartridgeLoader.Cartridges; +using Robust.Client.UserInterface; + +namespace Content.Client.DeltaV.CartridgeLoader.Cartridges; + +public sealed partial class SecWatchUi : UIFragment +{ + private SecWatchUiFragment? _fragment; + + public override Control GetUIFragmentRoot() + { + return _fragment!; + } + + public override void Setup(BoundUserInterface ui, EntityUid? owner) + { + _fragment = new SecWatchUiFragment(); + } + + public override void UpdateState(BoundUserInterfaceState state) + { + if (state is SecWatchUiState cast) + _fragment?.UpdateState(cast); + } +} diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml new file mode 100644 index 00000000000..7fb2c42debc --- /dev/null +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml @@ -0,0 +1,13 @@ + + + + diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml.cs b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml.cs new file mode 100644 index 00000000000..ad152840529 --- /dev/null +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml.cs @@ -0,0 +1,25 @@ +using Content.Shared.CartridgeLoader.Cartridges; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.DeltaV.CartridgeLoader.Cartridges; + +[GenerateTypedNameReferences] +public sealed partial class SecWatchUiFragment : BoxContainer +{ + public SecWatchUiFragment() + { + RobustXamlLoader.Load(this); + } + + public void UpdateState(SecWatchUiState state) + { + NoEntries.Visible = state.Entries.Count == 0; + Entries.RemoveAllChildren(); + foreach (var entry in state.Entries) + { + Entries.AddChild(new SecWatchEntryControl(entry)); + } + } +} diff --git a/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeComponent.cs b/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeComponent.cs new file mode 100644 index 00000000000..7ccc90ef797 --- /dev/null +++ b/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeComponent.cs @@ -0,0 +1,23 @@ +using Content.Shared.Security; + +namespace Content.Server.CartridgeLoader.Cartridges; + +[RegisterComponent, Access(typeof(SecWatchCartridgeSystem))] +public sealed partial class SecWatchCartridgeComponent : Component +{ + /// + /// Only show people with these statuses. + /// + [DataField] + public List Statuses = new() + { + SecurityStatus.Suspected, + SecurityStatus.Wanted + }; + + /// + /// Station entity thats getting its records checked. + /// + [DataField] + public EntityUid? Station; +} diff --git a/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeSystem.cs b/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeSystem.cs new file mode 100644 index 00000000000..16da24514cb --- /dev/null +++ b/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeSystem.cs @@ -0,0 +1,73 @@ +using Content.Server.Station.Systems; +using Content.Server.StationRecords; +using Content.Server.StationRecords.Systems; +using Content.Shared.CartridgeLoader; +using Content.Shared.CartridgeLoader.Cartridges; +using Content.Shared.CriminalRecords; +using Content.Shared.StationRecords; + +namespace Content.Server.CartridgeLoader.Cartridges; + +public sealed class SecWatchCartridgeSystem : EntitySystem +{ + [Dependency] private readonly CartridgeLoaderSystem _cartridgeLoader = default!; + [Dependency] private readonly StationRecordsSystem _records = default!; + [Dependency] private readonly StationSystem _station = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnRecordModified); + + SubscribeLocalEvent(OnUiReady); + } + + private void OnRecordModified(RecordModifiedEvent args) + { + // when a record is modified update the ui of every loaded cartridge tuned to the same station + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var comp, out var cartridge)) + { + if (cartridge.LoaderUid is not {} loader || comp.Station != args.Station) + continue; + + UpdateUI((uid, comp), loader); + } + } + + private void OnUiReady(Entity ent, ref CartridgeUiReadyEvent args) + { + UpdateUI(ent, args.Loader); + } + + private void UpdateUI(Entity ent, EntityUid loader) + { + // if the loader is on a grid, update the station + // if it is off grid use the cached station + if (_station.GetOwningStation(loader) is {} station) + ent.Comp.Station = station; + + if (!TryComp(ent.Comp.Station, out var records)) + return; + + station = ent.Comp.Station.Value; + + var entries = new List(); + foreach (var (id, criminal) in _records.GetRecordsOfType(station, records)) + { + if (!ent.Comp.Statuses.Contains(criminal.Status)) + continue; + + var key = new StationRecordKey(id, station); + if (!_records.TryGetRecord(key, out var general, records)) + continue; + + var status = criminal.Status; + entries.Add(new SecWatchEntry(general.Name, general.JobTitle, criminal.Status, criminal.Reason)); + } + + var state = new SecWatchUiState(entries); + _cartridgeLoader.UpdateCartridgeUiState(loader, state); + } +} diff --git a/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeComponent.cs b/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeComponent.cs deleted file mode 100644 index 741a6134580..00000000000 --- a/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeComponent.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Content.Server.DeltaV.CartridgeLoader.Cartridges; - -[RegisterComponent] -public sealed partial class CrimeAssistCartridgeComponent : Component -{ } diff --git a/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeSystem.cs b/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeSystem.cs deleted file mode 100644 index 06732c2c534..00000000000 --- a/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeSystem.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Content.Shared.CartridgeLoader; -using Content.Server.DeltaV.CartridgeLoader; -using Content.Server.CartridgeLoader.Cartridges; -using Content.Server.CartridgeLoader; - -namespace Content.Server.DeltaV.CartridgeLoader.Cartridges; - -public sealed class CrimeAssistCartridgeSystem : EntitySystem -{ - [Dependency] private readonly CartridgeLoaderSystem? _cartridgeLoaderSystem = default!; - - public override void Initialize() - { - base.Initialize(); - } -} diff --git a/Content.Shared/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiState.cs b/Content.Shared/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiState.cs deleted file mode 100644 index dd820f1a0b3..00000000000 --- a/Content.Shared/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiState.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Content.Shared.CartridgeLoader; -using Robust.Shared.Serialization; - -namespace Content.Shared.DeltaV.CartridgeLoader.Cartridges; - -[Serializable, NetSerializable] -public sealed class CrimeAssistUiState : BoundUserInterfaceState -{ - public CrimeAssistUiState() - { } -} - -[Serializable, NetSerializable] -public sealed class CrimeAssistSyncMessageEvent : CartridgeMessageEvent -{ - public CrimeAssistSyncMessageEvent() - { } -} diff --git a/Content.Shared/DeltaV/CartridgeLoader/Cartridges/SecWatchUiState.cs b/Content.Shared/DeltaV/CartridgeLoader/Cartridges/SecWatchUiState.cs new file mode 100644 index 00000000000..068b54a6ffb --- /dev/null +++ b/Content.Shared/DeltaV/CartridgeLoader/Cartridges/SecWatchUiState.cs @@ -0,0 +1,24 @@ +using Content.Shared.Security; +using Robust.Shared.Serialization; + +namespace Content.Shared.CartridgeLoader.Cartridges; + +/// +/// Show a list of wanted and suspected people from criminal records. +/// +[Serializable, NetSerializable] +public sealed class SecWatchUiState : BoundUserInterfaceState +{ + public readonly List Entries; + + public SecWatchUiState(List entries) + { + Entries = entries; + } +} + +/// +/// Entry for a person who is wanted or suspected. +/// +[Serializable, NetSerializable] +public record struct SecWatchEntry(string Name, string Job, SecurityStatus Status, string? Reason); diff --git a/Resources/Locale/en-US/deltav/cartridge-loader/secwatch.ftl b/Resources/Locale/en-US/deltav/cartridge-loader/secwatch.ftl new file mode 100644 index 00000000000..a5b96eab08f --- /dev/null +++ b/Resources/Locale/en-US/deltav/cartridge-loader/secwatch.ftl @@ -0,0 +1,5 @@ +sec-watch-program-name = SecWatch +sec-watch-title = SecWatch 1.0 +sec-watch-no-entries = Everything's calm. Why not enjoy a Monkin Donut? +sec-watch-entry = {$name}, {$job} +sec-watch-no-reason = None given??? diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Devices/cartridges.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Devices/cartridges.yml index e3d5e9d2138..def215cee43 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Devices/cartridges.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Devices/cartridges.yml @@ -17,4 +17,24 @@ icon: sprite: DeltaV/Icons/cri.rsi state: cri - - type: CrimeAssistCartridge + +- type: entity + parent: BaseItem + id: SecWatchCartridge + name: sec watch cartridge + description: A cartridge that tracks the status of currently wanted individuals. + components: + - type: Sprite + sprite: DeltaV/Objects/Devices/cartridge.rsi + state: cart-cri + - type: Icon + sprite: DeltaV/Objects/Devices/cartridge.rsi + state: cart-cri + - type: UIFragment + ui: !type:SecWatchUi + - type: Cartridge + programName: sec-watch-program-name + icon: + sprite: Objects/Weapons/Melee/stunbaton.rsi + state: stunbaton_on + - type: SecWatchCartridge diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Devices/pda.yml index 6ee3a7543f7..d9607390cd7 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Devices/pda.yml @@ -20,12 +20,13 @@ map: [ "enum.PdaVisualLayers.IdLight" ] shader: "unshaded" visible: false - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge + - SecWatchCartridge - type: Pda id: BrigmedicIDCard state: pda-corpsman diff --git a/Resources/Prototypes/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Entities/Objects/Devices/pda.yml index 706cbd5dbbf..7155be68d74 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/pda.yml @@ -173,12 +173,13 @@ accentVColor: "#A32D26" - type: Icon state: pda-interncadet - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge + - SecWatchCartridge - type: entity parent: BasePDA @@ -430,12 +431,13 @@ borderColor: "#6f6192" - type: Icon state: pda-lawyer - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge + - SecWatchCartridge - type: entity parent: BasePDA @@ -643,12 +645,13 @@ accentHColor: "#447987" - type: Icon state: pda-hos - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge + - SecWatchCartridge - type: entity parent: BasePDA @@ -664,12 +667,13 @@ accentVColor: "#949137" - type: Icon state: pda-warden - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge + - SecWatchCartridge - type: entity parent: BasePDA @@ -684,12 +688,13 @@ borderColor: "#A32D26" - type: Icon state: pda-security - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge + - SecWatchCartridge - type: entity parent: BasePDA @@ -979,12 +984,13 @@ borderColor: "#774705" - type: Icon state: pda-detective - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge + - SecWatchCartridge - type: entity parent: BaseMedicalPDA @@ -1001,12 +1007,13 @@ accentVColor: "#d7d7d0" - type: Icon state: pda-brigmedic - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge + - SecWatchCartridge - type: entity parent: ClownPDA @@ -1092,12 +1099,13 @@ accentVColor: "#DFDFDF" - type: Icon state: pda-seniorofficer - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge + - SecWatchCartridge - type: entity parent: SyndiPDA diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/pda.yml index c2fd8786aff..4e6115ba339 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/pda.yml @@ -32,12 +32,13 @@ accentVColor: "#DFDFDF" - type: Icon state: pda-security - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge + - SecWatchCartridge - type: entity parent: BasePDA From 2dcab4d57f74e25f4a1aafa23f48463ad6251516 Mon Sep 17 00:00:00 2001 From: SimpleStation Changelogs Date: Tue, 2 Jul 2024 08:01:57 +0000 Subject: [PATCH 77/82] Automatic Changelog Update (#502) --- Resources/Changelog/Changelog.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index e4e812edeb4..cd2ca0c929f 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -4271,3 +4271,11 @@ Entries: message: Fixed loadouts becoming uneditable after spending all your points id: 6134 time: '2024-07-02T07:18:27.0000000+00:00' +- author: deltanedas + changes: + - type: Add + message: >- + Security can find the new SecWatch™ app in their PDAs to see current + suspects and wanted criminals. + id: 6135 + time: '2024-07-02T08:01:36.0000000+00:00' From 2e8e56f763a5cda63511a1aaae0d649ff64eedad Mon Sep 17 00:00:00 2001 From: Mnemotechnican <69920617+Mnemotechnician@users.noreply.github.com> Date: Wed, 3 Jul 2024 22:48:28 +0300 Subject: [PATCH 78/82] Fix Clothing Quick-Equip (#507) # Description For some reason, ClothingSystem.TryEquip would return false if there's a do-after to equip the clothing. This had caused all quick-equip attempts on SMALL ITEMS to fail and ended up with every SMALL clothing item being equipped into one of the pocket slots (which have no equip delays). Also fixes quick swap - see the comments below. # Changelog :cl: - fix: Equipping clothing using the Z key works correctly again. --- Content.Shared/Clothing/EntitySystems/ClothingSystem.cs | 5 +++++ Content.Shared/Inventory/InventorySystem.Equip.cs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs b/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs index f189db005bc..976682c9903 100644 --- a/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs +++ b/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs @@ -62,6 +62,11 @@ private void QuickEquip( { foreach (var slotDef in userEnt.Comp1.Slots) { + // Do not attempt to quick-equip clothing in pocket slots. + // We should probably add a special flag to SlotDefinition to skip quick equip if more similar slots get added. + if (slotDef.SlotFlags.HasFlag(SlotFlags.POCKET)) + continue; + if (!_invSystem.CanEquip(userEnt, toEquipEnt, slotDef.Name, out _, slotDef, userEnt, toEquipEnt)) continue; diff --git a/Content.Shared/Inventory/InventorySystem.Equip.cs b/Content.Shared/Inventory/InventorySystem.Equip.cs index 24006b0c9f9..7bdd17ee6fa 100644 --- a/Content.Shared/Inventory/InventorySystem.Equip.cs +++ b/Content.Shared/Inventory/InventorySystem.Equip.cs @@ -176,7 +176,7 @@ public bool TryEquip(EntityUid actor, EntityUid target, EntityUid itemUid, strin }; _doAfter.TryStartDoAfter(args); - return false; + return true; // Changed to return true even if the item wasn't equipped instantly } if (!_containerSystem.Insert(itemUid, slotContainer)) From 6aaf4664ad1b9d150da9af30c27bfc31858de8d6 Mon Sep 17 00:00:00 2001 From: SimpleStation Changelogs Date: Wed, 3 Jul 2024 19:48:50 +0000 Subject: [PATCH 79/82] Automatic Changelog Update (#507) --- Resources/Changelog/Changelog.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index cd2ca0c929f..c4056561c9c 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -4279,3 +4279,9 @@ Entries: suspects and wanted criminals. id: 6135 time: '2024-07-02T08:01:36.0000000+00:00' +- author: Mnemotechnician + changes: + - type: Fix + message: Equipping clothing using the Z key works correctly again. + id: 6136 + time: '2024-07-03T19:48:29.0000000+00:00' From 8897a4b4732e16baee30be42dd9925419f4cdd0a Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Thu, 4 Jul 2024 00:16:17 -0400 Subject: [PATCH 80/82] Revert "Don't look at this please." This reverts commit d461f4fe176ab24b8278d17b500424c840a6348d. --- Content.Client/Entry/EntryPoint.cs | 1 - .../TypingIndicator/TypingIndicatorSystem.cs | 2 +- .../Components/NPCConversationComponent.cs | 152 ----- .../NPC/Events/NPCConversationEvents.cs | 63 -- .../NPCConversationTreePrototype.cs | 154 ----- .../NPC/Systems/NPCConversationSystem.cs | 558 ------------------ .../SophicScribe/SophicScribeSystem.cs | 36 -- .../Locale/en-US/npc/conversation/sophia.ftl | 82 --- .../Structures/Research/sophicscribe.yml | 194 +----- 9 files changed, 2 insertions(+), 1240 deletions(-) delete mode 100644 Content.Server/NPC/Components/NPCConversationComponent.cs delete mode 100644 Content.Server/NPC/Events/NPCConversationEvents.cs delete mode 100644 Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs delete mode 100644 Content.Server/NPC/Systems/NPCConversationSystem.cs delete mode 100644 Resources/Locale/en-US/npc/conversation/sophia.ftl diff --git a/Content.Client/Entry/EntryPoint.cs b/Content.Client/Entry/EntryPoint.cs index 8636e0eb6aa..a1fc68bbd2f 100644 --- a/Content.Client/Entry/EntryPoint.cs +++ b/Content.Client/Entry/EntryPoint.cs @@ -125,7 +125,6 @@ public override void Init() _prototypeManager.RegisterIgnore("alertLevels"); _prototypeManager.RegisterIgnore("nukeopsRole"); _prototypeManager.RegisterIgnore("stationGoal"); - _prototypeManager.RegisterIgnore("npcConversationTree"); _componentFactory.GenerateNetIds(); _adminManager.Initialize(); diff --git a/Content.Server/Chat/TypingIndicator/TypingIndicatorSystem.cs b/Content.Server/Chat/TypingIndicator/TypingIndicatorSystem.cs index 443923f675c..c923738930a 100644 --- a/Content.Server/Chat/TypingIndicator/TypingIndicatorSystem.cs +++ b/Content.Server/Chat/TypingIndicator/TypingIndicatorSystem.cs @@ -54,7 +54,7 @@ private void OnClientTypingChanged(TypingChangedEvent ev, EntitySessionEventArgs SetTypingIndicatorEnabled(uid.Value, ev.IsTyping); } - public void SetTypingIndicatorEnabled(EntityUid uid, bool isEnabled, AppearanceComponent? appearance = null) + private void SetTypingIndicatorEnabled(EntityUid uid, bool isEnabled, AppearanceComponent? appearance = null) { if (!Resolve(uid, ref appearance, false)) return; diff --git a/Content.Server/NPC/Components/NPCConversationComponent.cs b/Content.Server/NPC/Components/NPCConversationComponent.cs deleted file mode 100644 index c2a8ca31d7d..00000000000 --- a/Content.Server/NPC/Components/NPCConversationComponent.cs +++ /dev/null @@ -1,152 +0,0 @@ -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Content.Server.NPC.Events; -using Content.Server.NPC.Prototypes; -using Content.Server.NPC.Systems; - -namespace Content.Server.NPC.Components; - -[RegisterComponent] -[Access(typeof(NPCConversationSystem))] -public sealed partial class NPCConversationComponent : Component -{ - /// - /// Whether or not the listening logic is turned on. - /// - /// - /// Queued responses will still play through, but no new attempts to listen will be made. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("enabled")] - public bool Enabled = true; - - /* NYI: - /// - /// The NPC will pay attention when one of these words are said. - /// - [ViewVariables] - [DataField("aliases")] - public List Aliases = new(); - */ - - [ViewVariables] - [DataField("tree", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] - public string? ConversationTreeId; - - /// - /// This is the cached prototype. - /// - [ViewVariables] - public NPCConversationTreePrototype ConversationTree = default!; - - /// - /// Topics that are unlocked in the NPC's conversation tree. - /// - [ViewVariables] - public HashSet UnlockedTopics = new(); - - /// - /// How long until we stop paying attention to someone for a prompt. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("attentionSpan")] - public TimeSpan AttentionSpan = TimeSpan.FromSeconds(20); - - /// - /// This is the minimum delay before the NPC makes a response. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("delayBeforeResponse")] - public TimeSpan DelayBeforeResponse = TimeSpan.FromSeconds(0.3); - - /// - /// This is the approximate delay per letter typed in text. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("typingDelay")] - public TimeSpan TypingDelay = TimeSpan.FromSeconds(0.05); - - [ViewVariables] - public Stack ResponseQueue = new(); - - /// - /// This is when the NPC will respond with its top response. - /// - [ViewVariables] - [DataField("nextResponse", customTypeSerializer: typeof(TimeOffsetSerializer))] - public TimeSpan NextResponse; - - /// - /// This is the direction the NPC was facing before looking towards a conversation partner. - /// - [ViewVariables] - public Angle OriginalFacing; - - /// - /// This is who the NPC is paying attention to for conversation. - /// - [ViewVariables] - public EntityUid? AttendingTo; - - /// - /// This is when the NPC will stop paying attention to a specific person. - /// - [ViewVariables] - [DataField("nextAttentionLoss", customTypeSerializer: typeof(TimeOffsetSerializer))] - public TimeSpan NextAttentionLoss; - - /// - /// This event is fired the next time the NPC hears something from the - /// person they're speaking with and it takes control of the response. - /// - [ViewVariables] - public NPCConversationListenEvent? ListeningEvent; - -#region Idle Chatter - - /// - /// Whether or not the NPC will say things unprompted. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("idleEnabled")] - public bool IdleEnabled = true; - - /// - /// This is the approximate delay between idle chats. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("idleChatDelay")] - public TimeSpan IdleChatDelay = TimeSpan.FromMinutes(3); - - /// - /// This is the order in which idle chat lines are given. - /// - /// - /// This is randomized both on init and when the lines have been exhausted - /// to prevent repeating lines twice in a row and to avoid predictable patterns. - /// - /// It technically reduces randomness, with the benefit of less repetition. - /// - [ViewVariables(VVAccess.ReadWrite)] - public List IdleChatOrder = new(); - - /// - /// This is the next idle chat line that will be used. - /// - [ViewVariables(VVAccess.ReadWrite)] - public int IdleChatIndex = 0; - - /// - /// This is when the NPC will say something out of its list of idle lines. - /// - /// - /// This is reset every time the NPC speaks. - /// - [ViewVariables] - [DataField("nextIdleChat", customTypeSerializer: typeof(TimeOffsetSerializer))] - public TimeSpan NextIdleChat; - -#endregion - -} - diff --git a/Content.Server/NPC/Events/NPCConversationEvents.cs b/Content.Server/NPC/Events/NPCConversationEvents.cs deleted file mode 100644 index eb04f59bdd5..00000000000 --- a/Content.Server/NPC/Events/NPCConversationEvents.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Robust.Shared.Audio; -using Content.Server.NPC.Systems; - -namespace Content.Server.NPC.Events; - -/// -/// This is used for dynamic responses and post-response events. -/// -[ImplicitDataDefinitionForInheritors] -[Access(typeof(NPCConversationSystem))] -public abstract partial class NPCConversationEvent : EntityEventArgs -{ - /// - /// This is the entity that the NPC is speaking to. - /// - public EntityUid? TalkingTo; -} - -/// -/// This event type is raised when an NPC hears a response when it was set to listen for one. -/// -/// -/// Set Handled to true when you want the NPC to stop listening. -/// The NPC will otherwise keep listening and block any attempt to find a prompt in the speaker's words. -/// -[ImplicitDataDefinitionForInheritors] -[Access(typeof(NPCConversationSystem))] -public abstract partial class NPCConversationListenEvent : HandledEntityEventArgs -{ - /// - /// This is the entity that said the message. - /// - public EntityUid? Speaker; - - /// - /// This is the original message that the NPC heard. - /// - public string Message = default!; - - /// - /// This is the message, parsed into separate words. - /// - public List Words = default!; -} - -public sealed partial class NPCConversationHelpEvent : NPCConversationEvent -{ - [DataField("text")] - public string? Text; - - [DataField("audio")] - public SoundSpecifier? Audio; -} - -/// -/// This event can be raised after a response to cause an NPC to stop paying attention to someone. -/// -public sealed partial class NPCConversationByeEvent : NPCConversationEvent { } - -// The following classes help demonstrate some of the features of the system. -// They may be separated out at some point. -public sealed partial class NPCConversationToldNameEvent : NPCConversationListenEvent { } - diff --git a/Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs b/Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs deleted file mode 100644 index 20a616d8308..00000000000 --- a/Content.Server/NPC/Prototypes/NPCConversationTreePrototype.cs +++ /dev/null @@ -1,154 +0,0 @@ -using Robust.Shared.Audio; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization; -using Content.Server.NPC.Events; - -namespace Content.Server.NPC.Prototypes; - -[Prototype("npcConversationTree")] -public sealed class NPCConversationTreePrototype : IPrototype, ISerializationHooks -{ - [ViewVariables] - [IdDataField] - public string ID { get; } = default!; - - /// - /// Dialogue contains all the topics to which an NPC can discuss. - /// - [ViewVariables] - [DataField("dialogue", required: true)] - public readonly NPCTopic[] Dialogue = default!; - - /// - /// Attention responses are what the NPC says when they start paying - /// attention to you without a specific question or prompt to respond to. - /// - [ViewVariables] - [DataField("attention", required: true)] - public readonly NPCResponse[] Attention = default!; - - /// - /// Idle responses are just things the NPC will say when nothing else is - /// going on, after some time. - /// - [ViewVariables] - [DataField("idle", required: true)] - public readonly NPCResponse[] Idle = default!; - - /// - /// Unknown responses are what the NPC says when they can't respond to a - /// particular question or prompt. - /// - [ViewVariables] - [DataField("unknown", required: true)] - public readonly NPCResponse[] Unknown = default!; - - /// - /// Custom responses are available to use in extensions to the NPC - /// Conversation system. - /// - // NOTE: This may be removed in favor of storing NPCResponses on custom - // components, i.e. an NPCShopkeeperComponent, but for now, it lives here - // to help demonstrate some features. - [ViewVariables] - [DataField("custom")] - public readonly Dictionary Custom = default!; - - /// - /// This exists as a quick way to map a prompt to a topic. - /// - public readonly Dictionary PromptToTopic = new(); - - // ISerializationHooks _is_ obsolete, but ConstructionGraphPrototype is using it as of this commit, - // and I'm not quite sure how to otherwise do this. - // - // I will look at that prototype when ISerializationHooks is phased out. - void ISerializationHooks.AfterDeserialization() - { - // Cache the strings mapping to prompts. - foreach (var topic in Dialogue) - { - foreach (var prompt in topic.Prompts) - { - PromptToTopic[prompt] = topic; - } - } - } -} - -[DataDefinition] -public sealed partial class NPCTopic -{ - [DataField] - public string[] Prompts = default!; - - /// - /// This determines the likelihood of this topic being selected over any - /// other, given the existence of multiple candidates. - /// - [DataField] - public float Weight = 1.0f; - - /// - /// Locked topics will not be accessible through dialogue until unlocked. - /// - [DataField] - public bool Locked; - - /// - /// Hidden topics won't show up in any form of "help" question. - /// - [DataField] - public bool Hidden; - - [DataField("responses", required: true)] - public NPCResponse[] Responses = default!; -} - -[DataDefinition] -public sealed partial class NPCResponse -{ - public NPCResponse() { } - - public NPCResponse(string? text, SoundSpecifier? audio = null, NPCConversationEvent? ev = null) - { - Text = text; - Audio = audio; - Event = ev; - } - - public override string ToString() - { - return $"NPCResponse({Text})"; - } - - [DataField] - public string? Text; - - [DataField] - public SoundSpecifier? Audio; - - /* [DataField("emote")] */ - /* public string? Emote; */ - - /// - /// This event is raised when the response is queued, - /// for the purpose of dynamic responses. - /// - [DataField] - public NPCConversationEvent? Is; - - /// - /// This event is raised after the response is made. - /// - [DataField] - public NPCConversationEvent? Event; - - /// - /// This event is raised when the NPC next hears a response, - /// allowing the response to be processed by other systems. - /// - [DataField] - public NPCConversationListenEvent? ListenEvent; -} - diff --git a/Content.Server/NPC/Systems/NPCConversationSystem.cs b/Content.Server/NPC/Systems/NPCConversationSystem.cs deleted file mode 100644 index 015adb19de5..00000000000 --- a/Content.Server/NPC/Systems/NPCConversationSystem.cs +++ /dev/null @@ -1,558 +0,0 @@ -using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text.RegularExpressions; -using Robust.Server.GameObjects; -using Robust.Shared.Audio; -using Robust.Shared.Audio.Systems; -using Robust.Shared.Prototypes; -using Robust.Shared.Random; -using Robust.Shared.Timing; -using Content.Server.Chat.Systems; -using Content.Server.Chat.TypingIndicator; -using Content.Server.NPC.HTN; -using Content.Server.NPC.Components; -using Content.Server.NPC.Events; -using Content.Server.NPC.Prototypes; -using Content.Server.Speech; -using Content.Shared.Interaction; -using Content.Server.Radio.Components; - -namespace Content.Server.NPC.Systems; - -public sealed class NPCConversationSystem : EntitySystem -{ - [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly IPrototypeManager _prototype = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly SharedAudioSystem _audioSystem = default!; - [Dependency] private readonly ChatSystem _chatSystem = default!; - [Dependency] private readonly NPCSystem _npcSystem = default!; - [Dependency] private readonly RotateToFaceSystem _rotateToFaceSystem = default!; - [Dependency] private readonly TransformSystem _transformSystem = default!; - [Dependency] private readonly TypingIndicatorSystem _typingIndicatorSystem = default!; - - private ISawmill _sawmill = default!; - - // TODO: attention attenuation. distance, facing, visible - // TODO: attending to multiple people, multiple streams of conversation - // TODO: multi-word prompts - // TODO: nameless prompting (pointing is good) - // TODO: aliases - - public static readonly string[] QuestionWords = { "who", "what", "when", "why", "where", "how" }; - public static readonly string[] Copulae = { "is", "are" }; - - public override void Initialize() - { - base.Initialize(); - - _sawmill = Logger.GetSawmill("npc.conversation"); - - SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnUnpaused); - SubscribeLocalEvent(OnListenAttempt); - SubscribeLocalEvent(OnListen); - - SubscribeLocalEvent(OnBye); - SubscribeLocalEvent(OnHelp); - - SubscribeLocalEvent(OnToldName); - } - -#region API - - /// - /// Toggle the ability of an NPC to listen for topics. - /// - public void EnableConversation(EntityUid uid, bool enable = true, NPCConversationComponent? component = null) - { - if (!Resolve(uid, ref component)) - return; - - component.Enabled = enable; - } - - /// - /// Toggle the NPC's willingness to make idle comments. - /// - public void EnableIdleChat(EntityUid uid, bool enable = true, NPCConversationComponent? component = null) - { - if (!Resolve(uid, ref component)) - return; - - component.IdleEnabled = enable; - } - - /// - /// Return locked status of a dialogue topic. - /// - public bool IsDialogueLocked(EntityUid uid, string option, NPCConversationComponent? component = null) - { - if (!Resolve(uid, ref component)) - return true; - - if (!component.ConversationTree.PromptToTopic.TryGetValue(option, out var topic)) - { - _sawmill.Warning($"Tried to check locked status of missing dialogue option `{option}` on {ToPrettyString(uid)}"); - return true; - } - - if (component.UnlockedTopics.Contains(topic)) - return false; - - return topic.Locked; - } - - /// - /// Unlock dialogue options normally locked in an NPC's conversation tree. - /// - public void UnlockDialogue(EntityUid uid, string option, NPCConversationComponent? component = null) - { - if (!Resolve(uid, ref component)) - return; - - if (component.ConversationTree.PromptToTopic.TryGetValue(option, out var topic)) - component.UnlockedTopics.Add(topic); - else - _sawmill.Warning($"Tried to unlock missing dialogue option `{option}` on {ToPrettyString(uid)}"); - } - - /// - public void UnlockDialogue(EntityUid uid, HashSet options, NPCConversationComponent? component = null) - { - if (!Resolve(uid, ref component)) - return; - - foreach (var option in options) - UnlockDialogue(uid, option, component); - } - - /// - /// Queue a response for an NPC with a visible typing indicator and delay between messages. - /// - /// - /// This can be used as opposed to the typical method. - /// - public void QueueResponse(EntityUid uid, NPCResponse response, NPCConversationComponent? component = null) - { - if (!Resolve(uid, ref component)) - return; - - if (response.Is is {} ev) - { - // This is a dynamic response which will call QueueResponse with static responses of its own. - ev.TalkingTo = component.AttendingTo; - RaiseLocalEvent(uid, (object) ev); - return; - } - - if (component.ResponseQueue.Count == 0) - { - DelayResponse(uid, component, response); - _typingIndicatorSystem.SetTypingIndicatorEnabled(uid, true); - } - - component.ResponseQueue.Push(response); - } - - /// - /// Make an NPC stop paying attention to someone. - /// - public void LoseAttention(EntityUid uid, NPCConversationComponent? component = null) - { - if (!Resolve(uid, ref component)) - return; - - component.AttendingTo = null; - component.ListeningEvent = null; - _rotateToFaceSystem.TryFaceAngle(uid, component.OriginalFacing); - } - -#endregion - - private void DelayResponse(EntityUid uid, NPCConversationComponent component, NPCResponse response) - { - if (response.Text == null) - return; - - component.NextResponse = _gameTiming.CurTime + - component.DelayBeforeResponse + - component.TypingDelay.TotalSeconds * TimeSpan.FromSeconds(response.Text.Length) * - _random.NextDouble(0.9, 1.1); - } - - private IEnumerable GetAvailableTopics(EntityUid uid, NPCConversationComponent component) - { - HashSet availableTopics = new(); - - foreach (var topic in component.ConversationTree.Dialogue) - { - if (!topic.Locked || component.UnlockedTopics.Contains(topic)) - availableTopics.Add(topic); - } - - return availableTopics; - } - - private IEnumerable GetVisibleTopics(EntityUid uid, NPCConversationComponent component) - { - HashSet visibleTopics = new(); - - foreach (var topic in component.ConversationTree.Dialogue) - { - if (!topic.Hidden && (!topic.Locked || component.UnlockedTopics.Contains(topic))) - visibleTopics.Add(topic); - } - - return visibleTopics; - } - - private void OnInit(EntityUid uid, NPCConversationComponent component, ComponentInit args) - { - if (component.ConversationTreeId == null) - return; - - component.ConversationTree = _prototype.Index(component.ConversationTreeId); - component.NextIdleChat = _gameTiming.CurTime + component.IdleChatDelay; - - for (var i = 0; i < component.ConversationTree.Idle.Length; ++i) - component.IdleChatOrder.Add(i); - - _random.Shuffle(component.IdleChatOrder); - } - - private void OnUnpaused(EntityUid uid, NPCConversationComponent component, ref EntityUnpausedEvent args) - { - component.NextResponse += args.PausedTime; - component.NextAttentionLoss += args.PausedTime; - component.NextIdleChat += args.PausedTime; - } - - private bool TryGetIdleChatLine(EntityUid uid, NPCConversationComponent component, [NotNullWhen(true)] out NPCResponse? line) - { - line = null; - - if (component.IdleChatOrder.Count() == 0) - return false; - - if (++component.IdleChatIndex == component.IdleChatOrder.Count()) - { - // Exhausted all lines in the pre-shuffled order. - // Reset the index and shuffle again. - component.IdleChatIndex = 0; - _random.Shuffle(component.IdleChatOrder); - } - - var index = component.IdleChatOrder[component.IdleChatIndex]; - - line = component.ConversationTree.Idle[index]; - - return true; - } - - public override void Update(float frameTime) - { - base.Update(frameTime); - - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var component)) - { - var curTime = _gameTiming.CurTime; - - if (curTime >= component.NextResponse && component.ResponseQueue.Count > 0) - { - // Make a response. - Respond(uid, component, component.ResponseQueue.Pop()); - } - - if (curTime >= component.NextAttentionLoss && component.AttendingTo != null) - { - // Forget who we were talking to. - LoseAttention(uid, component); - } - - if (component.IdleEnabled && - curTime >= component.NextIdleChat && - TryGetIdleChatLine(uid, component, out var line)) - { - Respond(uid, component, line); - } - } - } - - private void OnListenAttempt(EntityUid uid, NPCConversationComponent component, ListenAttemptEvent args) - { - if (!component.Enabled || - // Don't listen to myself... - uid == args.Source || - // Don't bother listening to other NPCs. For now. - HasComp(args.Source) || - // We're already "typing" a response, so do that first. - component.ResponseQueue.Count > 0) - { - args.Cancel(); - } - } - - private void PayAttentionTo(EntityUid uid, NPCConversationComponent component, EntityUid speaker) - { - component.AttendingTo = speaker; - component.NextAttentionLoss = _gameTiming.CurTime + component.AttentionSpan; - component.OriginalFacing = _transformSystem.GetWorldRotation(uid); - } - - private void Respond(EntityUid uid, NPCConversationComponent component, NPCResponse response) - { - if (component.ResponseQueue.Count == 0) - _typingIndicatorSystem.SetTypingIndicatorEnabled(uid, false); - else - DelayResponse(uid, component, component.ResponseQueue.Peek()); - - if (component.AttendingTo != null) - { - // TODO: This line is a mouthful. Maybe write a public API that supports EntityCoordinates later? - var speakerCoords = Transform(component.AttendingTo.Value).Coordinates.ToMap(EntityManager, _transformSystem).Position; - _rotateToFaceSystem.TryFaceCoordinates(uid, speakerCoords); - } - - if (response.Event is {} ev) - { - ev.TalkingTo = component.AttendingTo; - RaiseLocalEvent(uid, (object) ev); - } - - if (response.ListenEvent != null) - component.ListeningEvent = response.ListenEvent; - - if (response.Text != null) - _chatSystem.TrySendInGameICMessage(uid, Loc.GetString(response.Text), InGameICChatType.Speak, false); - - if (response.Audio != null) - _audioSystem.PlayPvs(response.Audio, uid, - // TODO: Allow this to be configured per NPC/response. - AudioParams.Default - .WithVolume(8f) - .WithMaxDistance(9f) - .WithRolloffFactor(0.5f)); - - // Refresh our attention. - component.NextAttentionLoss = _gameTiming.CurTime + component.AttentionSpan; - component.NextIdleChat = component.NextAttentionLoss + component.IdleChatDelay; - } - - private List ParseMessageIntoWords(string message) - { - return Regex.Replace(message.Trim().ToLower(), @"(\p{P})", "") - .Split() - .ToList(); - } - - private bool FindResponse(EntityUid uid, NPCConversationComponent component, List words, [NotNullWhen(true)] out NPCResponse? response) - { - response = null; - - var availableTopics = GetAvailableTopics(uid, component); - - // Some topics are more interesting than others. - var greatestWeight = 0f; - NPCTopic? candidate = null; - - foreach (var word in words) - { - if (component.ConversationTree.PromptToTopic.TryGetValue(word, out var topic) && - availableTopics.Contains(topic) && - topic.Weight > greatestWeight) - { - greatestWeight = topic.Weight; - candidate = topic; - } - } - - if (candidate != null) - { - response = _random.Pick(candidate.Responses); - return true; - } - - return false; - } - - private bool JudgeQuestionLikelihood(EntityUid uid, NPCConversationComponent component, List words, string message) - { - if (message.Length > 0 && message[^1] == '?') - // A question mark is an absolute mark of a question. - return true; - - if (words.Count == 1) - // The usefulness of this is dubious, but it's definitely a question. - return QuestionWords.Contains(words[0]); - - if (words.Count >= 2) - return QuestionWords.Contains(words[0]) && Copulae.Contains(words[1]); - - return false; - } - - private void OnBye(EntityUid uid, NPCConversationComponent component, NPCConversationByeEvent args) - { - LoseAttention(uid, component); - } - - private void OnHelp(EntityUid uid, NPCConversationComponent component, NPCConversationHelpEvent args) - { - if (args.Text == null) - { - _sawmill.Error($"{ToPrettyString(uid)} heard a Help prompt but has no text for it."); - return; - } - - var availableTopics = GetVisibleTopics(uid, component); - var availablePrompts = availableTopics.Select(topic => topic.Prompts.FirstOrDefault()).ToArray(); - - string availablePromptsText; - if (availablePrompts.Count() <= 2) - { - availablePromptsText = Loc.GetString(args.Text, - ("availablePrompts", string.Join(" or ", availablePrompts)) - ); - } - else - { - availablePrompts[^1] = $"or {availablePrompts[^1]}"; - availablePromptsText = Loc.GetString(args.Text, - ("availablePrompts", string.Join(", ", availablePrompts)) - ); - } - - // Unlikely we'll be able to do audio that isn't hard-coded, - // so best to keep it general. - var response = new NPCResponse(availablePromptsText, args.Audio); - QueueResponse(uid, response, component); - } - - private void OnToldName(EntityUid uid, NPCConversationComponent component, NPCConversationListenEvent args) - { - if (!component.ConversationTree.Custom.TryGetValue("toldName", out var responses)) - return; - - var response = _random.Pick(responses); - if (response.Text == null) - { - _sawmill.Error($"{ToPrettyString(uid)} was told a name but had no text response."); - return; - } - - // The world's simplest heuristic for names: - if (args.Words.Count > 3) - { - // It didn't seem like a name, so wait for something that does. - return; - } - - var cleanedName = string.Join(" ", args.Words); - cleanedName = char.ToUpper(cleanedName[0]) + cleanedName.Remove(0, 1); - - var formattedResponse = new NPCResponse(Loc.GetString(response.Text, - ("name", cleanedName)), - response.Audio); - - QueueResponse(uid, formattedResponse, component); - args.Handled = true; - } - - private void OnListen(EntityUid uid, NPCConversationComponent component, ListenEvent args) - { - if (HasComp(args.Source)) - return; - - if (component.AttendingTo != null && component.AttendingTo != args.Source) - // Ignore someone speaking to us if we're already paying attention to someone else. - return; - - var words = ParseMessageIntoWords(args.Message); - if (words.Count == 0) - return; - - if (component.AttendingTo == args.Source) - { - // The person we're talking to said something to us. - - if (component.ListeningEvent is {} ev) - { - // We were waiting on this person to say something, and they've said something. - ev.Handled = false; - ev.Speaker = component.AttendingTo; - ev.Message = args.Message; - ev.Words = words; - RaiseLocalEvent(uid, (object) ev); - - if (ev.Handled) - component.ListeningEvent = null; - - return; - } - - // We're already paying attention to this person, - // so try to figure out if they said something we can talk about. - if (FindResponse(uid, component, words, out var response)) - { - // A response was found so go ahead with it. - QueueResponse(uid, response, component); - } - else if(JudgeQuestionLikelihood(uid, component, words, args.Message)) - { - // The message didn't match any of the prompts, but it seemed like a question. - var unknownResponse = _random.Pick(component.ConversationTree.Unknown); - QueueResponse(uid, unknownResponse, component); - } - - // If the message didn't seem like a question, - // and it didn't raise any of our topics, - // then politely ignore who we're talking with. - // - // It's better than spamming them with "I don't understand." - return; - } - - // See if someone said our name. - var myName = MetaData(uid).EntityName.ToLower(); - - // So this is a rough heuristic, but if our name occurs within the first three words, - // or is the very last one, someone might be trying to talk to us. - var payAttention = words[0] == myName || words[^1] == myName; - if (!payAttention) - { - for (int i = 1; i < Math.Min(2, words.Count); ++i) - { - if (words[i] == myName) - { - payAttention = true; - break; - } - } - } - - if (payAttention) - { - PayAttentionTo(uid, component, args.Source); - - if (!FindResponse(uid, component, words, out var response)) - { - if(JudgeQuestionLikelihood(uid, component, words, args.Message) && - // This subcondition exists to block our name being interpreted as a question in its own right. - words.Count > 1) - { - response = _random.Pick(component.ConversationTree.Unknown); - } - else - { - response = _random.Pick(component.ConversationTree.Attention); - } - } - - QueueResponse(uid, response, component); - } - } -} - diff --git a/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs b/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs index ba5ff0a056d..b1a6c1e9de1 100644 --- a/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs +++ b/Content.Server/Nyanotrasen/Research/SophicScribe/SophicScribeSystem.cs @@ -1,8 +1,5 @@ using Content.Server.Psionics.Abilities; using Content.Server.Chat.Systems; -using Content.Server.NPC.Events; -using Content.Server.NPC.Systems; -using Content.Server.NPC.Prototypes; using Content.Server.Radio.Components; using Content.Server.Radio.EntitySystems; using Content.Server.StationEvents.Events; @@ -21,8 +18,6 @@ public sealed partial class SophicScribeSystem : EntitySystem [Dependency] private readonly RadioSystem _radioSystem = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly NPCConversationSystem _conversationSystem = default!; - protected ISawmill Sawmill = default!; public override void Update(float frameTime) { @@ -56,32 +51,6 @@ public override void Initialize() SubscribeLocalEvent(OnInteractHand); SubscribeLocalEvent(OnGlimmerEventEnded); - SubscribeLocalEvent(OnGetGlimmer); - } - - private void OnGetGlimmer(EntityUid uid, SophicScribeComponent component, NPCConversationGetGlimmerEvent args) - { - if (args.Text == null) - { - Sawmill.Error($"{uid} heard a glimmer reading prompt but has no text for it"); - return; - } - - var tier = _glimmerSystem.GetGlimmerTier() switch - { - GlimmerTier.Minimal => Loc.GetString("glimmer-reading-minimal"), - GlimmerTier.Low => Loc.GetString("glimmer-reading-low"), - GlimmerTier.Moderate => Loc.GetString("glimmer-reading-moderate"), - GlimmerTier.High => Loc.GetString("glimmer-reading-high"), - GlimmerTier.Dangerous => Loc.GetString("glimmer-reading-dangerous"), - _ => Loc.GetString("glimmer-reading-critical"), - }; - - var glimmerReadingText = Loc.GetString(args.Text, - ("glimmer", (int) Math.Round(_glimmerSystem.GlimmerOutput)), ("tier", tier)); - - var response = new NPCResponse(glimmerReadingText); - _conversationSystem.QueueResponse(uid, response); } private void OnInteractHand(EntityUid uid, SophicScribeComponent component, InteractHandEvent args) @@ -114,9 +83,4 @@ private void OnGlimmerEventEnded(GlimmerEventEndedEvent args) _radioSystem.SendRadioMessage(speaker, message, channel, speaker); } } - public sealed partial class NPCConversationGetGlimmerEvent : NPCConversationEvent - { - [DataField] - public string? Text; - } } diff --git a/Resources/Locale/en-US/npc/conversation/sophia.ftl b/Resources/Locale/en-US/npc/conversation/sophia.ftl deleted file mode 100644 index c832d9fc17f..00000000000 --- a/Resources/Locale/en-US/npc/conversation/sophia.ftl +++ /dev/null @@ -1,82 +0,0 @@ -sophia-response-name = You may call me Sophia. -sophia-response-help = You may inquire about one of the following topics: {$availablePrompts}. - -sophia-response-hello-1 = Greetings. -sophia-response-hello-2 = Salutations. - -sophia-response-bye-1 = Fare thee well. -sophia-response-bye-2 = Gods be with you. -sophia-response-bye-3 = Come back wiser. - -sophia-idle-phrase-1 = Mmmm, another portent. -sophia-idle-phrase-2 = The noösphere is quite beautiful today. However, I don't think I could describe it in a way you could understand. -sophia-idle-phrase-3 = I've been here before. You have, too. - -sophia-response-attention-1 = What is it? -sophia-response-attention-2 = What do you seek? -sophia-response-attention-3 = Out with it. - -sophia-response-sorry-1 = That's not a question for me. -sophia-response-sorry-2 = Ask someone else. -sophia-response-sorry-3 = Maybe I know the answer, maybe I do not. Either way, I will not be answering that question. - -sophia-response-nature = My nature doesn't really matter, does it? I'm fulfilling my purpose. Can you say the same, or are you just wasting time? - -sophia-response-epi = 'Epistemics' is a word. Aspiring Hellenes they are, they wished to displace the Latin 'science.' However, in English, epistemics has undesired connotations as a study of knowledge itself, even though the Greek word is a literal replacement for 'science.' - -sophia-response-mantis = 'Mantis' means seer, soothsayer, or prophet. They must be so named because they seek to uncover the truth. And, fittingly with their psionic aptitude, 'mantis' and 'mind' both descend, to the best of our knowledge, from an absolutely ancient word that sounded something like 'mentis.' - -sophia-response-mystagogue = 'Mystagogue' literally means 'leader of the mystics.' You may know the suffix -gogue from 'demogogue.' - -sophia-response-oracle = Oracle? I don't know much about her, and she isn't keen to share her secrets with me. - -sophia-response-psionics = Psionics are extraordinary abilities originating from one's mind. There doesn't seem to be any dominant word to refer to someone with the ability to practice these, although I prefer 'psion' or 'psychic.' - -sophia-response-noosphere = The noösphere is a field connecting all of consciousness. It's the medium through which psionics works. Its strength and effects on the illusory world of the material are based on its pressure. Colloquially, noöspheric pressure is called 'glimmer.' - -sophia-response-god = 'God' is such a vague term. There are so many entities out there that have defeated mortality. How you choose to regard them is your business. - -sophia-response-morphotype = In the first century PCC, several entities reshaped men into their image. I had done the same, if you would believe it. I can offer no evidence of their existence, other than faint memories. Any specific morphotype you want to know about? - -sophia-response-calendar = It's currently 417 PCC. The casuality crisis neccesitated a new year to count from. Due to the nature of the crisis, it can only be said with certainty that 1 PCC is between 2400 and 2700 CE. - -sophia-response-crisis = The first FTL travel was incompatible with the old ways. Fortunately, its resolution made more apparent the inherent futility in trying to give one history, one narrative, one account. Truth cannot be found in the material world, only higher ones. - -sophia-response-metempsychosis = You've died thousands of times, and you'll die thousands more. Some of those lives you may dedicate to trying to stop the cycle. We all carry at least some memory of past lives, usually temporally recent ones. One of the great mysteries of the persistence of fragments is the high concentration of memories from the early 21st century CE, which, inverse to other periods, seem to be more common among the ignorant. - -sophia-response-truth = If you seek the truth, you're in the wrong place. From a perspective tainted by material reality, the best you can hope is to try and divine higher truths that are not dependent on it. - -sophia-response-job = I observe the glimmer here, and record it. - -sophia-response-human = Humans were the base for all the others. But they, too, were shaped. Long, long before the others. - -sophia-response-felinid = Felinids were the first, and the most willing. In true feline nature, they shaped themselves. - -sophia-response-oni = Oni, it is said, originated in Sirius. The brightest star in the night sky from Earth may have attracted some chromatically inclined entities, explaining their vivid coloring. But, that's just speculation. - -sophia-response-arachne = Arachne are the strangest of them. They're not fully mortal. They took the form of humans, but not their genes. Their creator wrote his name in their stead. - -sophia-response-moth = Moths scarecely look human, but, strangely, their genes confirm they are. Their creator shares his name with a genus of moths, and was responsible for the other outlier. - -sophia-response-lamiae = So, you remember? You must be remembering their mythological namesake. If you've really retained that fleeting memory over so many metempsychoses... Perhaps I've said too much. - -sophia-response-cyno = Were those... no... So faint. Ignorance! You cannot remember them! It's impossible! - -sophia-response-harpy = Harpies, it is said, were once men and women, sculpted by greed for a purpose long gone. They were abandoned by their creators on a world named Valerian 4b. - -sophia-response-valerian = The Harpy homeworld? Magestic mountains gleaming in white, forests of brilliant scarlet, oceans wine dark, yet no light to be seen by mortal eyes. The Harpies were made to thrive there. To them, their world was bathed in beautiful silver light. - -sophia-response-grue = You do not know of those. You cannot. I had so hoped to live a few cycles under normal causality. - -sophia-response-abraxas = That's a name of power, and I avoid speaking of him. He's the least content to rest, and the most infatuated with creating things from ignorance. - -sophia-response-zork = You wander into the slavering fangs of a hungry grue. There, did you enjoy this game? - -sophia-response-glimmer = The current glimmer reading is {$glimmer}. {$tier} - -glimmer-reading-minimal = That is extremely low. Nothing bad will happen, but I hope this is not at the cost of progression in your understanding of the universe. -glimmer-reading-low = That is quite low. Just barely enough to register any psionic activity here. -glimmer-reading-moderate = That is about the expected level on a psionically active station. You may notice manageable, minor effects. -glimmer-reading-high = That is sure to start attracting attention, although still quite manageable. -glimmer-reading-dangerous = That's a bit concerning. You may want to redirect efforts to reducing it. -glimmer-reading-critical = That's apocalyptic, in the original sense of the word. That is, to say, revealing. This is the sort of time and place to acquire secret knowledge. diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml index 5213608d95e..8e34a07ea5e 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml @@ -1,7 +1,7 @@ - type: entity parent: BaseStructure id: SophicScribe - name: Sophie + name: sophie description: Latest reports on the Noösphere! components: - type: Sprite @@ -27,10 +27,6 @@ channels: - Common - Science - - type: ActiveListener - - type: TypingIndicator - - type: NPCConversation - tree: SophiaTree - type: PotentialPsionic #this makes her easier to access for glimmer events, dw about it - type: Psionic psychicFeedback: @@ -43,191 +39,3 @@ - type: GuideHelp guides: - Psionics - -- type: npcConversationTree - id: SophiaTree - dialogue: - - prompts: [glimmer, reading] - responses: - - is: !type:NPCConversationGetGlimmerEvent - text: sophia-response-glimmer - - - prompts: [purpose, job, occupation, profession] - weight: 0.5 - responses: - - text: sophia-response-job - - - prompts: [help, topics] - weight: 0.5 - hidden: true - responses: - - is: !type:NPCConversationHelpEvent - text: sophia-response-help - - - prompts: [nature, statue, snake, being] - weight: 0.3 - responses: - - text: sophia-response-nature - - - prompts: [epistemics, epi] - weight: 0.2 - responses: - - text: sophia-response-epi - - - prompts: [mantis] - weight: 0.2 - responses: - - text: sophia-response-mantis - - - prompts: [mystagogue, mysta] - weight: 0.2 - responses: - - text: sophia-response-mystagogue - - - prompts: [psionics, psychic] - weight: 0.2 - responses: - - text: sophia-response-psionics - - - prompts: [noösphere, noosphere] - weight: 0.2 - responses: - - text: sophia-response-noosphere - - - prompts: [metempsychosis, metempsychoses, reincarnation, death, dying, afterlife] - weight: 0.2 - responses: - - text: sophia-response-metempsychosis - - - prompts: [calendar] - weight: 0.2 - responses: - - text: sophia-response-calendar - - - prompts: [morphotypes, morphotype, species] - weight: 0.2 - responses: - - text: sophia-response-morphotype - - - prompts: [gods, god] - weight: 0.1 - hidden: true - responses: - - text: sophia-response-god - - - prompts: [truth, "true", "false", falsity, falsehood] - weight: 0.1 - hidden: true - responses: - - text: sophia-response-truth - - - prompts: [human, humans, humanoid, unmutated] - weight: 0.1 - hidden: true - responses: - - text: sophia-response-human - - - prompts: [felinid, felinids, felid, felids, catperson, catpeople] - weight: 0.1 - hidden: true - responses: - - text: sophia-response-felinid - - - prompts: [oni, onis] - weight: 0.1 - hidden: true - responses: - - text: sophia-response-oni - - - prompts: [arachne, arachnid, arachnids, spiderperson, spiderpeople] - weight: 0.1 - hidden: true - responses: - - text: sophia-response-arachne - - - prompts: [moth, moths, moff, moths] - weight: 0.1 - hidden: true - responses: - - text: sophia-response-moth - - - prompts: [lamiae, lamia, lamias] - weight: 0.1 - hidden: true - responses: - - text: sophia-response-lamiae - - - prompts: [grue, grues, batperson, batpeople] - weight: 0.1 - hidden: true - responses: - - text: sophia-response-grue - - - prompts: [cynocephalus, cynocephali, cyno, cynos] - weight: 0.1 - hidden: true - responses: - - text: sophia-response-cyno - - - prompts: [harpy, harpies] - weight: 0.1 - hidden: true - responses: - - text: sophia-response-harpy - - - prompts: [valerian, Valerian, 4b] - weight: 0.1 - hidden: true - responses: - - text: sophia-response-valerian - - - prompts: [crisis, causality] - weight: 0.1 - hidden: true - responses: - - text: sophia-response-crisis - - - prompts: [oracle] - weight: 0.1 - hidden: true - responses: - - text: sophia-response-oracle - - - prompts: [abraxas] - weight: 0.1 - hidden: true - responses: - - text: sophia-response-abraxas - - - prompts: [hi, hello, hey, greetings, salutations] - weight: 0.1 - hidden: true - responses: - - text: sophia-response-hello-1 - - text: sophia-response-hello-2 - - - prompts: [bye, goodbye, done, farewell, later, seeya] - weight: 0.1 - hidden: true - responses: - - text: sophia-response-bye-1 - event: !type:NPCConversationByeEvent - - text: sophia-response-bye-2 - event: !type:NPCConversationByeEvent - - text: sophia-response-bye-3 - event: !type:NPCConversationByeEvent - - attention: - - text: sophia-response-attention-1 - - text: sophia-response-attention-2 - - text: sophia-response-attention-3 - - idle: - - text: sophia-idle-phrase-1 - - text: sophia-idle-phrase-2 - - text: sophia-idle-phrase-3 - - unknown: - - text: sophia-response-sorry-1 - - text: sophia-response-sorry-2 - - text: sophia-response-sorry-3 From 2f3ee29ec0b1f0b1c51d04c467c7396f1f3df463 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Thu, 4 Jul 2024 00:25:54 -0400 Subject: [PATCH 81/82] Revert "Merge branch 'Simple-Station:master' into Psionic-Power-Refactor" This reverts commit 8a0ee5672643c0137f3ed423d1042feb1e0930cc, reversing changes made to 8897a4b4732e16baee30be42dd9925419f4cdd0a. --- .../Cartridges/CrimeAssistUi.cs | 9 + .../Cartridges/CrimeAssistUiFragment.xaml.cs | 3 + .../Cartridges/SecWatchEntryControl.xaml | 19 - .../Cartridges/SecWatchEntryControl.xaml.cs | 21 - .../CartridgeLoader/Cartridges/SecWatchUi.cs | 27 - .../Cartridges/SecWatchUiFragment.xaml | 13 - .../Cartridges/SecWatchUiFragment.xaml.cs | 25 - .../UI/HumanoidProfileEditor.xaml.cs | 2 +- .../Cartridges/SecWatchCartridgeComponent.cs | 23 - .../Cartridges/SecWatchCartridgeSystem.cs | 73 -- .../CrimeAssistCartridgeComponent.cs | 5 + .../CrimeAssistCartridgeSystem.cs | 16 + Content.Server/Strip/StrippableSystem.cs | 680 +++++++----------- .../Clothing/EntitySystems/ClothingSystem.cs | 5 - .../EntitySystems/ToggleableClothingSystem.cs | 2 +- .../Cartridges/CrimeAssistUiState.cs | 18 + .../Cartridges/SecWatchUiState.cs | 24 - .../Inventory/InventorySystem.Equip.cs | 2 +- .../Inventory/InventoryTemplatePrototype.cs | 2 +- .../Strip/Components/StrippableComponent.cs | 79 +- .../Strip/Components/ThievingComponent.cs | 2 +- .../Strip/SharedStrippableSystem.cs | 6 +- Content.Shared/Strip/ThievingSystem.cs | 1 - .../Weapons/Ranged/Systems/SharedGunSystem.cs | 2 +- Resources/Changelog/Changelog.yml | 34 - Resources/Credits/GitHub.txt | 2 +- .../deltav/cartridge-loader/secwatch.ftl | 5 - .../Locale/en-US/store/uplink-catalog.ftl | 3 - .../Catalog/Fills/Boxes/syndicate.yml | 37 +- .../Prototypes/Catalog/uplink_catalog.yml | 11 - .../DeltaV/Body/Prototypes/harpy.yml | 5 +- .../DeltaV/Body/Prototypes/vulpkanin.yml | 6 +- .../Entities/Objects/Devices/cartridges.yml | 22 +- .../DeltaV/Entities/Objects/Devices/pda.yml | 3 +- .../OuterClothing/base_clothingouter.yml | 6 - .../Entities/Clothing/base_clothing.yml | 3 - .../Entities/Objects/Devices/pda.yml | 24 +- .../Ammunition/Cartridges/base_cartridge.yml | 9 +- .../Entities/Objects/Weapons/Melee/knife.yml | 29 - .../Entities/Body/Prototypes/felinid.yml | 4 +- .../Entities/Clothing/Head/hats.yml | 2 - .../Entities/Objects/Devices/pda.yml | 3 +- .../Entities/Objects/Devices/shock_collar.yml | 2 - .../Objects/Storage/boxes.rsi/meta.json | 17 +- .../Storage/boxes.rsi/throwing_knives.png | Bin 1141 -> 0 bytes .../Objects/Storage/boxicons.rsi/meta.json | 5 +- .../Storage/boxicons.rsi/throwing_knives.png | Bin 1392 -> 0 bytes .../throwing_knife.rsi/equipped-BELT.png | Bin 1289 -> 0 bytes .../Weapons/Melee/throwing_knife.rsi/icon.png | Bin 1593 -> 0 bytes .../Melee/throwing_knife.rsi/inhand-left.png | Bin 1296 -> 0 bytes .../Melee/throwing_knife.rsi/inhand-right.png | Bin 1298 -> 0 bytes .../Melee/throwing_knife.rsi/meta.json | 26 - 52 files changed, 397 insertions(+), 920 deletions(-) delete mode 100644 Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml delete mode 100644 Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml.cs delete mode 100644 Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUi.cs delete mode 100644 Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml delete mode 100644 Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml.cs delete mode 100644 Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeComponent.cs delete mode 100644 Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeSystem.cs create mode 100644 Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeComponent.cs create mode 100644 Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeSystem.cs create mode 100644 Content.Shared/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiState.cs delete mode 100644 Content.Shared/DeltaV/CartridgeLoader/Cartridges/SecWatchUiState.cs delete mode 100644 Resources/Locale/en-US/deltav/cartridge-loader/secwatch.ftl delete mode 100644 Resources/Textures/Objects/Storage/boxes.rsi/throwing_knives.png delete mode 100644 Resources/Textures/Objects/Storage/boxicons.rsi/throwing_knives.png delete mode 100644 Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/equipped-BELT.png delete mode 100644 Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/icon.png delete mode 100644 Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/inhand-left.png delete mode 100644 Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/inhand-right.png delete mode 100644 Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/meta.json diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUi.cs b/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUi.cs index 2dbe923b2a6..ea5aa3cf256 100644 --- a/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUi.cs +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUi.cs @@ -18,6 +18,15 @@ public override Control GetUIFragmentRoot() public override void Setup(BoundUserInterface userInterface, EntityUid? fragmentOwner) { _fragment = new CrimeAssistUiFragment(); + + _fragment.OnSync += _ => SendSyncMessage(userInterface); + } + + private void SendSyncMessage(BoundUserInterface userInterface) + { + var syncMessage = new CrimeAssistSyncMessageEvent(); + var message = new CartridgeUiMessage(syncMessage); + userInterface.SendMessage(message); } public override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiFragment.xaml.cs b/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiFragment.xaml.cs index fb085a8a799..e3163975d12 100644 --- a/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiFragment.xaml.cs +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiFragment.xaml.cs @@ -1,6 +1,7 @@ using Content.Client.Message; using Content.Shared.DeltaV.CartridgeLoader.Cartridges; using Robust.Client.AutoGenerated; +using Robust.Client.ResourceManagement; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; using Robust.Shared.Prototypes; @@ -12,7 +13,9 @@ namespace Content.Client.DeltaV.CartridgeLoader.Cartridges; public sealed partial class CrimeAssistUiFragment : BoxContainer { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IResourceCache _resourceCache = default!; + public event Action? OnSync; private CrimeAssistPage _currentPage; private List? _pages; diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml deleted file mode 100644 index 2de8a37ff77..00000000000 --- a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml.cs b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml.cs deleted file mode 100644 index e8dd4eea446..00000000000 --- a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Content.Shared.CartridgeLoader.Cartridges; -using Robust.Client.AutoGenerated; -using Robust.Client.UserInterface; -using Robust.Client.UserInterface.Controls; -using Robust.Client.UserInterface.XAML; - -namespace Content.Client.DeltaV.CartridgeLoader.Cartridges; - -[GenerateTypedNameReferences] -public sealed partial class SecWatchEntryControl : BoxContainer -{ - public SecWatchEntryControl(SecWatchEntry entry) - { - RobustXamlLoader.Load(this); - - Status.Text = Loc.GetString($"criminal-records-status-{entry.Status.ToString().ToLower()}"); - Title.Text = Loc.GetString("sec-watch-entry", ("name", entry.Name), ("job", entry.Job)); - - Reason.Text = entry.Reason ?? Loc.GetString("sec-watch-no-reason"); - } -} diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUi.cs b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUi.cs deleted file mode 100644 index da5ff825b91..00000000000 --- a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUi.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Content.Client.UserInterface.Fragments; -using Content.Shared.CartridgeLoader; -using Content.Shared.CartridgeLoader.Cartridges; -using Robust.Client.UserInterface; - -namespace Content.Client.DeltaV.CartridgeLoader.Cartridges; - -public sealed partial class SecWatchUi : UIFragment -{ - private SecWatchUiFragment? _fragment; - - public override Control GetUIFragmentRoot() - { - return _fragment!; - } - - public override void Setup(BoundUserInterface ui, EntityUid? owner) - { - _fragment = new SecWatchUiFragment(); - } - - public override void UpdateState(BoundUserInterfaceState state) - { - if (state is SecWatchUiState cast) - _fragment?.UpdateState(cast); - } -} diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml deleted file mode 100644 index 7fb2c42debc..00000000000 --- a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml +++ /dev/null @@ -1,13 +0,0 @@ - - - - diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml.cs b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml.cs deleted file mode 100644 index ad152840529..00000000000 --- a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Content.Shared.CartridgeLoader.Cartridges; -using Robust.Client.AutoGenerated; -using Robust.Client.UserInterface.Controls; -using Robust.Client.UserInterface.XAML; - -namespace Content.Client.DeltaV.CartridgeLoader.Cartridges; - -[GenerateTypedNameReferences] -public sealed partial class SecWatchUiFragment : BoxContainer -{ - public SecWatchUiFragment() - { - RobustXamlLoader.Load(this); - } - - public void UpdateState(SecWatchUiState state) - { - NoEntries.Visible = state.Entries.Count == 0; - Entries.RemoveAllChildren(); - foreach (var entry in state.Entries) - { - Entries.AddChild(new SecWatchEntryControl(entry)); - } - } -} diff --git a/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs b/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs index 04810b07719..c797f02a754 100644 --- a/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs +++ b/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs @@ -2086,7 +2086,7 @@ void AddSelector(LoadoutPreferenceSelector selector, int points, string id) selector.PreferenceChanged += preference => { // Make sure they have enough loadout points - preference = preference ? CheckPoints(-points, preference) : CheckPoints(points, preference); + preference = preference ? CheckPoints(points, preference) : CheckPoints(-points, preference); // Update Preferences Profile = Profile?.WithLoadoutPreference(id, preference); diff --git a/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeComponent.cs b/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeComponent.cs deleted file mode 100644 index 7ccc90ef797..00000000000 --- a/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeComponent.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Content.Shared.Security; - -namespace Content.Server.CartridgeLoader.Cartridges; - -[RegisterComponent, Access(typeof(SecWatchCartridgeSystem))] -public sealed partial class SecWatchCartridgeComponent : Component -{ - /// - /// Only show people with these statuses. - /// - [DataField] - public List Statuses = new() - { - SecurityStatus.Suspected, - SecurityStatus.Wanted - }; - - /// - /// Station entity thats getting its records checked. - /// - [DataField] - public EntityUid? Station; -} diff --git a/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeSystem.cs b/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeSystem.cs deleted file mode 100644 index 16da24514cb..00000000000 --- a/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeSystem.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Content.Server.Station.Systems; -using Content.Server.StationRecords; -using Content.Server.StationRecords.Systems; -using Content.Shared.CartridgeLoader; -using Content.Shared.CartridgeLoader.Cartridges; -using Content.Shared.CriminalRecords; -using Content.Shared.StationRecords; - -namespace Content.Server.CartridgeLoader.Cartridges; - -public sealed class SecWatchCartridgeSystem : EntitySystem -{ - [Dependency] private readonly CartridgeLoaderSystem _cartridgeLoader = default!; - [Dependency] private readonly StationRecordsSystem _records = default!; - [Dependency] private readonly StationSystem _station = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnRecordModified); - - SubscribeLocalEvent(OnUiReady); - } - - private void OnRecordModified(RecordModifiedEvent args) - { - // when a record is modified update the ui of every loaded cartridge tuned to the same station - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var comp, out var cartridge)) - { - if (cartridge.LoaderUid is not {} loader || comp.Station != args.Station) - continue; - - UpdateUI((uid, comp), loader); - } - } - - private void OnUiReady(Entity ent, ref CartridgeUiReadyEvent args) - { - UpdateUI(ent, args.Loader); - } - - private void UpdateUI(Entity ent, EntityUid loader) - { - // if the loader is on a grid, update the station - // if it is off grid use the cached station - if (_station.GetOwningStation(loader) is {} station) - ent.Comp.Station = station; - - if (!TryComp(ent.Comp.Station, out var records)) - return; - - station = ent.Comp.Station.Value; - - var entries = new List(); - foreach (var (id, criminal) in _records.GetRecordsOfType(station, records)) - { - if (!ent.Comp.Statuses.Contains(criminal.Status)) - continue; - - var key = new StationRecordKey(id, station); - if (!_records.TryGetRecord(key, out var general, records)) - continue; - - var status = criminal.Status; - entries.Add(new SecWatchEntry(general.Name, general.JobTitle, criminal.Status, criminal.Reason)); - } - - var state = new SecWatchUiState(entries); - _cartridgeLoader.UpdateCartridgeUiState(loader, state); - } -} diff --git a/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeComponent.cs b/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeComponent.cs new file mode 100644 index 00000000000..741a6134580 --- /dev/null +++ b/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeComponent.cs @@ -0,0 +1,5 @@ +namespace Content.Server.DeltaV.CartridgeLoader.Cartridges; + +[RegisterComponent] +public sealed partial class CrimeAssistCartridgeComponent : Component +{ } diff --git a/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeSystem.cs b/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeSystem.cs new file mode 100644 index 00000000000..06732c2c534 --- /dev/null +++ b/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeSystem.cs @@ -0,0 +1,16 @@ +using Content.Shared.CartridgeLoader; +using Content.Server.DeltaV.CartridgeLoader; +using Content.Server.CartridgeLoader.Cartridges; +using Content.Server.CartridgeLoader; + +namespace Content.Server.DeltaV.CartridgeLoader.Cartridges; + +public sealed class CrimeAssistCartridgeSystem : EntitySystem +{ + [Dependency] private readonly CartridgeLoaderSystem? _cartridgeLoaderSystem = default!; + + public override void Initialize() + { + base.Initialize(); + } +} diff --git a/Content.Server/Strip/StrippableSystem.cs b/Content.Server/Strip/StrippableSystem.cs index 3b38b65a19d..96b2ecc00c6 100644 --- a/Content.Server/Strip/StrippableSystem.cs +++ b/Content.Server/Strip/StrippableSystem.cs @@ -1,3 +1,4 @@ +using System.Linq; using Content.Server.Administration.Logs; using Content.Server.Ensnaring; using Content.Shared.CombatMode; @@ -20,21 +21,18 @@ using Robust.Server.GameObjects; using Robust.Shared.Player; using Robust.Shared.Utility; -using System.Linq; namespace Content.Server.Strip { public sealed class StrippableSystem : SharedStrippableSystem { + [Dependency] private readonly SharedCuffableSystem _cuffable = default!; + [Dependency] private readonly SharedHandsSystem _handsSystem = default!; [Dependency] private readonly InventorySystem _inventorySystem = default!; - [Dependency] private readonly EnsnareableSystem _ensnaringSystem = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly EnsnareableSystem _ensnaring = default!; [Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!; - - [Dependency] private readonly SharedCuffableSystem _cuffableSystem = default!; - [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; - [Dependency] private readonly SharedHandsSystem _handsSystem = default!; - [Dependency] private readonly SharedPopupSystem _popupSystem = default!; - [Dependency] private readonly IAdminLogManager _adminLogger = default!; // TODO: ECS popups. Not all of these have ECS equivalents yet. @@ -50,58 +48,64 @@ public override void Initialize() // BUI SubscribeLocalEvent(OnStripButtonPressed); SubscribeLocalEvent(OnStripEnsnareMessage); - - // DoAfters - SubscribeLocalEvent>(OnStrippableDoAfterRunning); - SubscribeLocalEvent(OnStrippableDoAfterFinished); } - private void AddStripVerb(EntityUid uid, StrippableComponent component, GetVerbsEvent args) + private void OnStripEnsnareMessage(EntityUid uid, EnsnareableComponent component, StrippingEnsnareButtonPressed args) { - if (args.Hands == null || !args.CanAccess || !args.CanInteract || args.Target == args.User) - return; - - if (!HasComp(args.User)) + if (args.Session.AttachedEntity is not {Valid: true} user) return; - Verb verb = new() + foreach (var entity in component.Container.ContainedEntities) { - Text = Loc.GetString("strip-verb-get-data-text"), - Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/outfit.svg.192dpi.png")), - Act = () => StartOpeningStripper(args.User, (uid, component), true), - }; + if (!TryComp(entity, out var ensnaring)) + continue; - args.Verbs.Add(verb); + _ensnaring.TryFree(uid, user, entity, ensnaring); + return; + } } - private void AddStripExamineVerb(EntityUid uid, StrippableComponent component, GetVerbsEvent args) + private void OnStripButtonPressed(Entity strippable, ref StrippingSlotButtonPressed args) { - if (args.Hands == null || !args.CanAccess || !args.CanInteract || args.Target == args.User) + if (args.Session.AttachedEntity is not {Valid: true} user || + !TryComp(user, out var userHands)) return; - if (!HasComp(args.User)) + if (args.IsHand) + { + StripHand(user, args.Slot, strippable, userHands); return; + } - ExamineVerb verb = new() - { - Text = Loc.GetString("strip-verb-get-data-text"), - Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/outfit.svg.192dpi.png")), - Act = () => StartOpeningStripper(args.User, (uid, component), true), - Category = VerbCategory.Examine, - }; + if (!TryComp(strippable, out var inventory)) + return; - args.Verbs.Add(verb); + var hasEnt = _inventorySystem.TryGetSlotEntity(strippable, args.Slot, out var held, inventory); + + if (userHands.ActiveHandEntity != null && !hasEnt) + PlaceActiveHandItemInInventory(user, strippable, userHands.ActiveHandEntity.Value, args.Slot, strippable); + else if (userHands.ActiveHandEntity == null && hasEnt) + TakeItemFromInventory(user, strippable, held!.Value, args.Slot, strippable); } - private void OnActivateInWorld(EntityUid uid, StrippableComponent component, ActivateInWorldEvent args) + private void StripHand(EntityUid user, string handId, Entity target, HandsComponent userHands) { - if (args.Target == args.User) + if (!_handsSystem.TryGetHand(target, handId, out var hand)) return; - if (!HasComp(args.User)) + // is the target a handcuff? + if (TryComp(hand.HeldEntity, out VirtualItemComponent? virt) + && TryComp(target, out CuffableComponent? cuff) + && _cuffable.GetAllCuffs(cuff).Contains(virt.BlockingEntity)) + { + _cuffable.TryUncuff(target, user, virt.BlockingEntity, cuffable: cuff); return; + } - StartOpeningStripper(args.User, (uid, component)); + if (userHands.ActiveHandEntity != null && hand.HeldEntity == null) + PlaceActiveHandItemInHands(user, target, userHands.ActiveHandEntity.Value, handId, target); + else if (userHands.ActiveHandEntity == null && hand.HeldEntity != null) + TakeItemFromHands(user, target, hand.HeldEntity.Value, handId, target); } public override void StartOpeningStripper(EntityUid user, Entity strippable, bool openInCombat = false) @@ -119,520 +123,352 @@ public override void StartOpeningStripper(EntityUid user, Entity strippable, ref StrippingSlotButtonPressed args) + private void AddStripVerb(EntityUid uid, StrippableComponent component, GetVerbsEvent args) { - if (args.Session.AttachedEntity is not { Valid: true } user || - !TryComp(user, out var userHands)) - return; - - if (args.IsHand) - { - StripHand((user, userHands), (strippable.Owner, null), args.Slot, strippable); + if (args.Hands == null || !args.CanAccess || !args.CanInteract || args.Target == args.User) return; - } - if (!TryComp(strippable, out var inventory)) + if (!HasComp(args.User)) return; - var hasEnt = _inventorySystem.TryGetSlotEntity(strippable, args.Slot, out var held, inventory); - - if (userHands.ActiveHandEntity != null && !hasEnt) - StartStripInsertInventory((user, userHands), strippable.Owner, userHands.ActiveHandEntity.Value, args.Slot); - else if (userHands.ActiveHandEntity == null && hasEnt) - StartStripRemoveInventory(user, strippable.Owner, held!.Value, args.Slot); + Verb verb = new() + { + Text = Loc.GetString("strip-verb-get-data-text"), + Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/outfit.svg.192dpi.png")), + Act = () => StartOpeningStripper(args.User, (uid, component), true), + }; + args.Verbs.Add(verb); } - private void StripHand( - Entity user, - Entity target, - string handId, - StrippableComponent? targetStrippable) + private void AddStripExamineVerb(EntityUid uid, StrippableComponent component, GetVerbsEvent args) { - if (!Resolve(user, ref user.Comp) || - !Resolve(target, ref target.Comp) || - !Resolve(target, ref targetStrippable)) + if (args.Hands == null || !args.CanAccess || !args.CanInteract || args.Target == args.User) return; - if (!_handsSystem.TryGetHand(target.Owner, handId, out var handSlot)) + if (!HasComp(args.User)) return; - // Is the target a handcuff? - if (TryComp(handSlot.HeldEntity, out var virtualItem) && - TryComp(target.Owner, out var cuffable) && - _cuffableSystem.GetAllCuffs(cuffable).Contains(virtualItem.BlockingEntity)) + ExamineVerb verb = new() { - _cuffableSystem.TryUncuff(target.Owner, user, virtualItem.BlockingEntity, cuffable); - return; - } + Text = Loc.GetString("strip-verb-get-data-text"), + Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/outfit.svg.192dpi.png")), + Act = () => StartOpeningStripper(args.User, (uid, component), true), + Category = VerbCategory.Examine, + }; - if (user.Comp.ActiveHandEntity != null && handSlot.HeldEntity == null) - StartStripInsertHand(user, target, user.Comp.ActiveHandEntity.Value, handId, targetStrippable); - else if (user.Comp.ActiveHandEntity == null && handSlot.HeldEntity != null) - StartStripRemoveHand(user, target, handSlot.HeldEntity.Value, handId, targetStrippable); + args.Verbs.Add(verb); } - private void OnStripEnsnareMessage(EntityUid uid, EnsnareableComponent component, StrippingEnsnareButtonPressed args) + private void OnActivateInWorld(EntityUid uid, StrippableComponent component, ActivateInWorldEvent args) { - if (args.Session.AttachedEntity is not { Valid: true } user) + if (args.Target == args.User) return; - foreach (var entity in component.Container.ContainedEntities) - { - if (!TryComp(entity, out var ensnaring)) - continue; - - _ensnaringSystem.TryFree(uid, user, entity, ensnaring); + if (!HasComp(args.User)) return; - } + + StartOpeningStripper(args.User, (uid, component)); } /// - /// Checks whether the item is in a user's active hand and whether it can be inserted into the inventory slot. + /// Places item in user's active hand to an inventory slot. /// - private bool CanStripInsertInventory( - Entity user, + private async void PlaceActiveHandItemInInventory( + EntityUid user, EntityUid target, EntityUid held, - string slot) + string slot, + StrippableComponent component) { - if (!Resolve(user, ref user.Comp)) - return false; - - if (user.Comp.ActiveHand == null) - return false; - - if (user.Comp.ActiveHandEntity == null) - return false; - - if (user.Comp.ActiveHandEntity != held) - return false; - - if (!_handsSystem.CanDropHeld(user, user.Comp.ActiveHand)) - { - _popupSystem.PopupCursor(Loc.GetString("strippable-component-cannot-drop"), user); - return false; - } - - if (_inventorySystem.TryGetSlotEntity(target, slot, out _)) - { - _popupSystem.PopupCursor(Loc.GetString("strippable-component-item-slot-occupied", ("owner", target)), user); - return false; - } + var userHands = Comp(user); - if (!_inventorySystem.CanEquip(user, target, held, slot, out _)) + bool Check() { - _popupSystem.PopupCursor(Loc.GetString("strippable-component-cannot-equip-message", ("owner", target)), user); - return false; + if (userHands.ActiveHandEntity != held) + return false; + + if (!_handsSystem.CanDropHeld(user, userHands.ActiveHand!)) + { + _popup.PopupCursor(Loc.GetString("strippable-component-cannot-drop"), user); + return false; + } + + if (_inventorySystem.TryGetSlotEntity(target, slot, out _)) + { + _popup.PopupCursor(Loc.GetString("strippable-component-item-slot-occupied",("owner", target)), user); + return false; + } + + if (!_inventorySystem.CanEquip(user, target, held, slot, out _)) + { + _popup.PopupCursor(Loc.GetString("strippable-component-cannot-equip-message",("owner", target)), user); + return false; + } + + return true; } - return true; - } - - /// - /// Begins a DoAfter to insert the item in the user's active hand into the inventory slot. - /// - private void StartStripInsertInventory( - Entity user, - EntityUid target, - EntityUid held, - string slot) - { - if (!Resolve(user, ref user.Comp)) - return; - - if (!CanStripInsertInventory(user, target, held, slot)) - return; - if (!_inventorySystem.TryGetSlot(target, slot, out var slotDef)) { Log.Error($"{ToPrettyString(user)} attempted to place an item in a non-existent inventory slot ({slot}) on {ToPrettyString(target)}"); return; } - var (time, stealth) = GetStripTimeModifiers(user, target, slotDef.StripTime); - - if (!stealth) - _popupSystem.PopupEntity(Loc.GetString("strippable-component-alert-owner-insert", ("user", Identity.Entity(user, EntityManager)), ("item", user.Comp.ActiveHandEntity!.Value)), target, target, PopupType.Large); - - var prefix = stealth ? "stealthily " : ""; - _adminLogger.Add(LogType.Stripping, LogImpact.Low, $"{ToPrettyString(user):actor} is trying to {prefix}place the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s {slot} slot"); + var userEv = new BeforeStripEvent(slotDef.StripTime); + RaiseLocalEvent(user, userEv); + var ev = new BeforeGettingStrippedEvent(userEv.Time, userEv.Stealth); + RaiseLocalEvent(target, ev); - var doAfterArgs = new DoAfterArgs(EntityManager, user, time, new StrippableDoAfterEvent(true, true, slot), user, target, held) + var doAfterArgs = new DoAfterArgs(EntityManager, user, ev.Time, new AwaitedDoAfterEvent(), null, target: target, used: held) { - Hidden = stealth, + ExtraCheck = Check, + Hidden = ev.Stealth, AttemptFrequency = AttemptFrequency.EveryTick, BreakOnDamage = true, BreakOnTargetMove = true, BreakOnUserMove = true, NeedHand = true, - DuplicateCondition = DuplicateConditions.SameTool + DuplicateCondition = DuplicateConditions.SameTool // Block any other DoAfters featuring this same entity. }; - _doAfterSystem.TryStartDoAfter(doAfterArgs); - } - - /// - /// Inserts the item in the user's active hand into the inventory slot. - /// - private void StripInsertInventory( - Entity user, - EntityUid target, - EntityUid held, - string slot) - { - if (!Resolve(user, ref user.Comp)) - return; + if (!ev.Stealth && Check() && userHands.ActiveHandEntity != null) + { + var message = Loc.GetString("strippable-component-alert-owner-insert", + ("user", Identity.Entity(user, EntityManager)), ("item", userHands.ActiveHandEntity)); + _popup.PopupEntity(message, target, target, PopupType.Large); + } - if (!CanStripInsertInventory(user, target, held, slot)) - return; + var prefix = ev.Stealth ? "stealthily " : ""; + _adminLogger.Add(LogType.Stripping, LogImpact.Low, $"{ToPrettyString(user):actor} is trying to {prefix}place the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s {slot} slot"); - if (!_handsSystem.TryDrop(user, handsComp: user.Comp)) + var result = await _doAfter.WaitDoAfter(doAfterArgs); + if (result != DoAfterStatus.Finished) return; - _inventorySystem.TryEquip(user, target, held, slot); - _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has placed the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s {slot} slot"); - } + DebugTools.Assert(userHands.ActiveHand?.HeldEntity == held); - /// - /// Checks whether the item can be removed from the target's inventory. - /// - private bool CanStripRemoveInventory( - EntityUid user, - EntityUid target, - EntityUid item, - string slot) - { - if (!_inventorySystem.TryGetSlotEntity(target, slot, out var slotItem)) + if (_handsSystem.TryDrop(user, handsComp: userHands)) { - _popupSystem.PopupCursor(Loc.GetString("strippable-component-item-slot-free-message", ("owner", target)), user); - return false; - } + _inventorySystem.TryEquip(user, target, held, slot); - if (slotItem != item) - return false; - - if (!_inventorySystem.CanUnequip(user, target, slot, out var reason)) - { - _popupSystem.PopupCursor(Loc.GetString(reason), user); - return false; + _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has placed the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s {slot} slot"); } - - return true; } /// - /// Begins a DoAfter to remove the item from the target's inventory and insert it in the user's active hand. + /// Places item in user's active hand in one of the entity's hands. /// - private void StartStripRemoveInventory( + private async void PlaceActiveHandItemInHands( EntityUid user, EntityUid target, - EntityUid item, - string slot) + EntityUid held, + string handName, + StrippableComponent component) { - if (!CanStripRemoveInventory(user, target, item, slot)) - return; - - if (!_inventorySystem.TryGetSlot(target, slot, out var slotDef)) - { - Log.Error($"{ToPrettyString(user)} attempted to take an item from a non-existent inventory slot ({slot}) on {ToPrettyString(target)}"); - return; - } - - var (time, stealth) = GetStripTimeModifiers(user, target, slotDef.StripTime); + var hands = Comp(target); + var userHands = Comp(user); - if (!stealth) + bool Check() { - if (slotDef.StripHidden) - _popupSystem.PopupEntity(Loc.GetString("strippable-component-alert-owner-hidden", ("slot", slot)), target, target, PopupType.Large); - else - _popupSystem.PopupEntity(Loc.GetString("strippable-component-alert-owner", ("user", Identity.Entity(user, EntityManager)), ("item", item)), target, target, PopupType.Large); + if (userHands.ActiveHandEntity != held) + return false; + + if (!_handsSystem.CanDropHeld(user, userHands.ActiveHand!)) + { + _popup.PopupCursor(Loc.GetString("strippable-component-cannot-drop"), user); + return false; + } + + if (!_handsSystem.TryGetHand(target, handName, out var hand, hands) + || !_handsSystem.CanPickupToHand(target, userHands.ActiveHandEntity.Value, hand, checkActionBlocker: false, hands)) + { + _popup.PopupCursor(Loc.GetString("strippable-component-cannot-put-message",("owner", target)), user); + return false; + } + + return true; } - var prefix = stealth ? "stealthily " : ""; - _adminLogger.Add(LogType.Stripping, LogImpact.Low, $"{ToPrettyString(user):actor} is trying to {prefix}strip the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s {slot} slot"); + var userEv = new BeforeStripEvent(component.HandStripDelay); + RaiseLocalEvent(user, userEv); + var ev = new BeforeGettingStrippedEvent(userEv.Time, userEv.Stealth); + RaiseLocalEvent(target, ev); - var doAfterArgs = new DoAfterArgs(EntityManager, user, time, new StrippableDoAfterEvent(false, true, slot), user, target, item) + var doAfterArgs = new DoAfterArgs(EntityManager, user, ev.Time, new AwaitedDoAfterEvent(), null, target: target, used: held) { - Hidden = stealth, + ExtraCheck = Check, + Hidden = ev.Stealth, AttemptFrequency = AttemptFrequency.EveryTick, BreakOnDamage = true, BreakOnTargetMove = true, BreakOnUserMove = true, NeedHand = true, - BreakOnHandChange = false, // Allow simultaneously removing multiple items. DuplicateCondition = DuplicateConditions.SameTool }; - _doAfterSystem.TryStartDoAfter(doAfterArgs); + var prefix = ev.Stealth ? "stealthily " : ""; + _adminLogger.Add(LogType.Stripping, LogImpact.Low, $"{ToPrettyString(user):actor} is trying to {prefix}place the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s hands"); + + var result = await _doAfter.WaitDoAfter(doAfterArgs); + if (result != DoAfterStatus.Finished) return; + + _handsSystem.TryDrop(user, checkActionBlocker: false, handsComp: userHands); + _handsSystem.TryPickup(target, held, handName, checkActionBlocker: false, animateUser: !ev.Stealth, animate: !ev.Stealth, handsComp: hands); + _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has placed the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s hands"); + // hand update will trigger strippable update } /// - /// Removes the item from the target's inventory and inserts it in the user's active hand. + /// Takes an item from the inventory and places it in the user's active hand. /// - private void StripRemoveInventory( + private async void TakeItemFromInventory( EntityUid user, EntityUid target, EntityUid item, string slot, - bool stealth) - { - if (!CanStripRemoveInventory(user, target, item, slot)) - return; - - if (!_inventorySystem.TryUnequip(user, target, slot)) - return; - - RaiseLocalEvent(item, new DroppedEvent(user), true); // Gas tank internals etc. - - _handsSystem.PickupOrDrop(user, item, animateUser: stealth, animate: stealth); - _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has stripped the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s {slot} slot"); - } - - /// - /// Checks whether the item in the user's active hand can be inserted into one of the target's hands. - /// - private bool CanStripInsertHand( - Entity user, - Entity target, - EntityUid held, - string handName) + Entity strippable) { - if (!Resolve(user, ref user.Comp) || - !Resolve(target, ref target.Comp)) - return false; - - if (user.Comp.ActiveHand == null) - return false; - - if (user.Comp.ActiveHandEntity == null) - return false; - - if (user.Comp.ActiveHandEntity != held) - return false; - - if (!_handsSystem.CanDropHeld(user, user.Comp.ActiveHand)) + bool Check() { - _popupSystem.PopupCursor(Loc.GetString("strippable-component-cannot-drop"), user); - return false; + if (!_inventorySystem.TryGetSlotEntity(target, slot, out var ent) && ent == item) + { + _popup.PopupCursor(Loc.GetString("strippable-component-item-slot-free-message", ("owner", target)), user); + return false; + } + + if (!_inventorySystem.CanUnequip(user, target, slot, out var reason)) + { + _popup.PopupCursor(Loc.GetString(reason), user); + return false; + } + + return true; } - if (!_handsSystem.TryGetHand(target, handName, out var handSlot, target.Comp) || - !_handsSystem.CanPickupToHand(target, user.Comp.ActiveHandEntity.Value, handSlot, checkActionBlocker: false, target.Comp)) + if (!_inventorySystem.TryGetSlot(target, slot, out var slotDef)) { - _popupSystem.PopupCursor(Loc.GetString("strippable-component-cannot-put-message", ("owner", target)), user); - return false; - } - - return true; - } - - /// - /// Begins a DoAfter to insert the item in the user's active hand into one of the target's hands. - /// - private void StartStripInsertHand( - Entity user, - Entity target, - EntityUid held, - string handName, - StrippableComponent? targetStrippable = null) - { - if (!Resolve(user, ref user.Comp) || - !Resolve(target, ref target.Comp) || - !Resolve(target, ref targetStrippable)) - return; - - if (!CanStripInsertHand(user, target, held, handName)) + Log.Error($"{ToPrettyString(user)} attempted to take an item from a non-existent inventory slot ({slot}) on {ToPrettyString(target)}"); return; + } - var (time, stealth) = GetStripTimeModifiers(user, target, targetStrippable.HandStripDelay); - - var prefix = stealth ? "stealthily " : ""; - _adminLogger.Add(LogType.Stripping, LogImpact.Low, $"{ToPrettyString(user):actor} is trying to {prefix}place the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s hands"); + var userEv = new BeforeStripEvent(slotDef.StripTime); + RaiseLocalEvent(user, userEv); + var ev = new BeforeGettingStrippedEvent(userEv.Time, userEv.Stealth); + RaiseLocalEvent(target, ev); - var doAfterArgs = new DoAfterArgs(EntityManager, user, time, new StrippableDoAfterEvent(true, false, handName), user, target, held) + var doAfterArgs = new DoAfterArgs(EntityManager, user, ev.Time, new AwaitedDoAfterEvent(), null, target: target, used: item) { - Hidden = stealth, + ExtraCheck = Check, + Hidden = ev.Stealth, AttemptFrequency = AttemptFrequency.EveryTick, BreakOnDamage = true, BreakOnTargetMove = true, BreakOnUserMove = true, NeedHand = true, + BreakOnHandChange = false, // allow simultaneously removing multiple items. DuplicateCondition = DuplicateConditions.SameTool }; - _doAfterSystem.TryStartDoAfter(doAfterArgs); - } + if (!ev.Stealth && Check()) + { + if (slotDef.StripHidden) + { + _popup.PopupEntity(Loc.GetString("strippable-component-alert-owner-hidden", ("slot", slot)), target, + target, PopupType.Large); + } + else if (_inventorySystem.TryGetSlotEntity(strippable, slot, out var slotItem)) + { + _popup.PopupEntity(Loc.GetString("strippable-component-alert-owner", ("user", Identity.Entity(user, EntityManager)), ("item", slotItem)), target, + target, PopupType.Large); + } + } - /// - /// Places the item in the user's active hand into one of the target's hands. - /// - private void StripInsertHand( - Entity user, - Entity target, - EntityUid held, - string handName, - bool stealth) - { - if (!Resolve(user, ref user.Comp) || - !Resolve(target, ref target.Comp)) + var prefix = ev.Stealth ? "stealthily " : ""; + _adminLogger.Add(LogType.Stripping, LogImpact.Low, $"{ToPrettyString(user):actor} is trying to {prefix}strip the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s {slot} slot"); + + var result = await _doAfter.WaitDoAfter(doAfterArgs); + if (result != DoAfterStatus.Finished) return; - if (!CanStripInsertHand(user, target, held, handName)) + if (!_inventorySystem.TryUnequip(user, strippable, slot)) return; - _handsSystem.TryDrop(user, checkActionBlocker: false, handsComp: user.Comp); - _handsSystem.TryPickup(target, held, handName, checkActionBlocker: false, animateUser: stealth, animate: stealth, handsComp: target.Comp); - _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has placed the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s hands"); + // Raise a dropped event, so that things like gas tank internals properly deactivate when stripping + RaiseLocalEvent(item, new DroppedEvent(user), true); + + _handsSystem.PickupOrDrop(user, item, animateUser: !ev.Stealth, animate: !ev.Stealth); + _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has stripped the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s {slot} slot"); - // Hand update will trigger strippable update. } /// - /// Checks whether the item is in the target's hand and whether it can be dropped. + /// Takes an item from a hand and places it in the user's active hand. /// - private bool CanStripRemoveHand( - EntityUid user, - Entity target, - EntityUid item, - string handName) + private async void TakeItemFromHands(EntityUid user, EntityUid target, EntityUid item, string handName, Entity strippable) { - if (!Resolve(target, ref target.Comp)) - return false; + var hands = Comp(target); + var userHands = Comp(user); - if (!_handsSystem.TryGetHand(target, handName, out var handSlot, target.Comp)) + bool Check() { - _popupSystem.PopupCursor(Loc.GetString("strippable-component-item-slot-free-message", ("owner", target)), user); - return false; + if (!_handsSystem.TryGetHand(target, handName, out var hand, hands) || hand.HeldEntity != item) + { + _popup.PopupCursor(Loc.GetString("strippable-component-item-slot-free-message",("owner", target)), user); + return false; + } + + if (HasComp(hand.HeldEntity)) + return false; + + if (!_handsSystem.CanDropHeld(target, hand, false)) + { + _popup.PopupCursor(Loc.GetString("strippable-component-cannot-drop-message",("owner", target)), user); + return false; + } + + return true; } - if (HasComp(handSlot.HeldEntity)) - return false; - - if (handSlot.HeldEntity == null) - return false; + var userEv = new BeforeStripEvent(strippable.Comp.HandStripDelay); + RaiseLocalEvent(user, userEv); + var ev = new BeforeGettingStrippedEvent(userEv.Time, userEv.Stealth); + RaiseLocalEvent(target, ev); - if (handSlot.HeldEntity != item) - return false; - - if (!_handsSystem.CanDropHeld(target, handSlot, false)) + var doAfterArgs = new DoAfterArgs(EntityManager, user, ev.Time, new AwaitedDoAfterEvent(), null, target: target, used: item) { - _popupSystem.PopupCursor(Loc.GetString("strippable-component-cannot-drop-message", ("owner", target)), user); - return false; - } - - return true; - } - - /// - /// Begins a DoAfter to remove the item from the target's hand and insert it in the user's active hand. - /// - private void StartStripRemoveHand( - Entity user, - Entity target, - EntityUid item, - string handName, - StrippableComponent? targetStrippable = null) - { - if (!Resolve(user, ref user.Comp) || - !Resolve(target, ref target.Comp) || - !Resolve(target, ref targetStrippable)) - return; - - if (!CanStripRemoveHand(user, target, item, handName)) - return; - - var (time, stealth) = GetStripTimeModifiers(user, target, targetStrippable.HandStripDelay); - - if (!stealth) - _popupSystem.PopupEntity(Loc.GetString("strippable-component-alert-owner", ("user", Identity.Entity(user, EntityManager)), ("item", item)), target, target); - - var prefix = stealth ? "stealthily " : ""; - _adminLogger.Add(LogType.Stripping, LogImpact.Low, $"{ToPrettyString(user):actor} is trying to {prefix}strip the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s hands"); - - var doAfterArgs = new DoAfterArgs(EntityManager, user, time, new StrippableDoAfterEvent(false, false, handName), user, target, item) - { - Hidden = stealth, + ExtraCheck = Check, + Hidden = ev.Stealth, AttemptFrequency = AttemptFrequency.EveryTick, BreakOnDamage = true, BreakOnTargetMove = true, BreakOnUserMove = true, NeedHand = true, - BreakOnHandChange = false, // Allow simultaneously removing multiple items. + BreakOnHandChange = false, // allow simultaneously removing multiple items. DuplicateCondition = DuplicateConditions.SameTool }; - _doAfterSystem.TryStartDoAfter(doAfterArgs); - } - - /// - /// Takes the item from the target's hand and inserts it in the user's active hand. - /// - private void StripRemoveHand( - Entity user, - Entity target, - EntityUid item, - string handName, - bool stealth) - { - if (!Resolve(user, ref user.Comp) || - !Resolve(target, ref target.Comp)) - return; - - if (!CanStripRemoveHand(user, target, item, handName)) - return; - - _handsSystem.TryDrop(target, item, checkActionBlocker: false, handsComp: target.Comp); - _handsSystem.PickupOrDrop(user, item, animateUser: stealth, animate: stealth, handsComp: user.Comp); - _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has stripped the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s hands"); - - // Hand update will trigger strippable update. - } - - private void OnStrippableDoAfterRunning(Entity entity, ref DoAfterAttemptEvent ev) - { - var args = ev.DoAfter.Args; - - DebugTools.Assert(entity.Owner == args.User); - DebugTools.Assert(args.Target != null); - DebugTools.Assert(args.Used != null); - DebugTools.Assert(ev.Event.SlotOrHandName != null); - - if (ev.Event.InventoryOrHand) - { - if ( ev.Event.InsertOrRemove && !CanStripInsertInventory((entity.Owner, entity.Comp), args.Target.Value, args.Used.Value, ev.Event.SlotOrHandName) || - !ev.Event.InsertOrRemove && !CanStripRemoveInventory(entity.Owner, args.Target.Value, args.Used.Value, ev.Event.SlotOrHandName)) - ev.Cancel(); - } - else + if (!ev.Stealth && Check() && _handsSystem.TryGetHand(target, handName, out var handSlot, hands) && handSlot.HeldEntity != null) { - if ( ev.Event.InsertOrRemove && !CanStripInsertHand((entity.Owner, entity.Comp), args.Target.Value, args.Used.Value, ev.Event.SlotOrHandName) || - !ev.Event.InsertOrRemove && !CanStripRemoveHand(entity.Owner, args.Target.Value, args.Used.Value, ev.Event.SlotOrHandName)) - ev.Cancel(); + _popup.PopupEntity( + Loc.GetString("strippable-component-alert-owner", + ("user", Identity.Entity(user, EntityManager)), ("item", item)), + strippable.Owner, + strippable.Owner); } - } - private void OnStrippableDoAfterFinished(Entity entity, ref StrippableDoAfterEvent ev) - { - if (ev.Cancelled) - return; + var prefix = ev.Stealth ? "stealthily " : ""; + _adminLogger.Add(LogType.Stripping, LogImpact.Low, + $"{ToPrettyString(user):actor} is trying to {prefix}strip the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s hands"); - DebugTools.Assert(entity.Owner == ev.User); - DebugTools.Assert(ev.Target != null); - DebugTools.Assert(ev.Used != null); - DebugTools.Assert(ev.SlotOrHandName != null); + var result = await _doAfter.WaitDoAfter(doAfterArgs); + if (result != DoAfterStatus.Finished) + return; - if (ev.InventoryOrHand) - { - if (ev.InsertOrRemove) - StripInsertInventory((entity.Owner, entity.Comp), ev.Target.Value, ev.Used.Value, ev.SlotOrHandName); - else StripRemoveInventory(entity.Owner, ev.Target.Value, ev.Used.Value, ev.SlotOrHandName, ev.Args.Hidden); - } - else - { - if (ev.InsertOrRemove) - StripInsertHand((entity.Owner, entity.Comp), ev.Target.Value, ev.Used.Value, ev.SlotOrHandName, ev.Args.Hidden); - else StripRemoveHand((entity.Owner, entity.Comp), ev.Target.Value, ev.Used.Value, ev.SlotOrHandName, ev.Args.Hidden); - } + _handsSystem.TryDrop(target, item, checkActionBlocker: false, handsComp: hands); + _handsSystem.PickupOrDrop(user, item, animateUser: !ev.Stealth, animate: !ev.Stealth, handsComp: userHands); + // hand update will trigger strippable update + _adminLogger.Add(LogType.Stripping, LogImpact.Medium, + $"{ToPrettyString(user):actor} has stripped the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s hands"); } } } diff --git a/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs b/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs index 976682c9903..f189db005bc 100644 --- a/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs +++ b/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs @@ -62,11 +62,6 @@ private void QuickEquip( { foreach (var slotDef in userEnt.Comp1.Slots) { - // Do not attempt to quick-equip clothing in pocket slots. - // We should probably add a special flag to SlotDefinition to skip quick equip if more similar slots get added. - if (slotDef.SlotFlags.HasFlag(SlotFlags.POCKET)) - continue; - if (!_invSystem.CanEquip(userEnt, toEquipEnt, slotDef.Name, out _, slotDef, userEnt, toEquipEnt)) continue; diff --git a/Content.Shared/Clothing/EntitySystems/ToggleableClothingSystem.cs b/Content.Shared/Clothing/EntitySystems/ToggleableClothingSystem.cs index 22a1d1a8f52..0138de7a98f 100644 --- a/Content.Shared/Clothing/EntitySystems/ToggleableClothingSystem.cs +++ b/Content.Shared/Clothing/EntitySystems/ToggleableClothingSystem.cs @@ -95,7 +95,7 @@ private void StartDoAfter(EntityUid user, EntityUid item, EntityUid wearer, Togg if (component.StripDelay == null) return; - var (time, stealth) = _strippable.GetStripTimeModifiers(user, wearer, component.StripDelay.Value); + var (time, stealth) = _strippable.GetStripTimeModifiers(user, wearer, (float) component.StripDelay.Value.TotalSeconds); var args = new DoAfterArgs(EntityManager, user, time, new ToggleClothingDoAfterEvent(), item, wearer, item) { diff --git a/Content.Shared/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiState.cs b/Content.Shared/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiState.cs new file mode 100644 index 00000000000..dd820f1a0b3 --- /dev/null +++ b/Content.Shared/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiState.cs @@ -0,0 +1,18 @@ +using Content.Shared.CartridgeLoader; +using Robust.Shared.Serialization; + +namespace Content.Shared.DeltaV.CartridgeLoader.Cartridges; + +[Serializable, NetSerializable] +public sealed class CrimeAssistUiState : BoundUserInterfaceState +{ + public CrimeAssistUiState() + { } +} + +[Serializable, NetSerializable] +public sealed class CrimeAssistSyncMessageEvent : CartridgeMessageEvent +{ + public CrimeAssistSyncMessageEvent() + { } +} diff --git a/Content.Shared/DeltaV/CartridgeLoader/Cartridges/SecWatchUiState.cs b/Content.Shared/DeltaV/CartridgeLoader/Cartridges/SecWatchUiState.cs deleted file mode 100644 index 068b54a6ffb..00000000000 --- a/Content.Shared/DeltaV/CartridgeLoader/Cartridges/SecWatchUiState.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Content.Shared.Security; -using Robust.Shared.Serialization; - -namespace Content.Shared.CartridgeLoader.Cartridges; - -/// -/// Show a list of wanted and suspected people from criminal records. -/// -[Serializable, NetSerializable] -public sealed class SecWatchUiState : BoundUserInterfaceState -{ - public readonly List Entries; - - public SecWatchUiState(List entries) - { - Entries = entries; - } -} - -/// -/// Entry for a person who is wanted or suspected. -/// -[Serializable, NetSerializable] -public record struct SecWatchEntry(string Name, string Job, SecurityStatus Status, string? Reason); diff --git a/Content.Shared/Inventory/InventorySystem.Equip.cs b/Content.Shared/Inventory/InventorySystem.Equip.cs index 7bdd17ee6fa..24006b0c9f9 100644 --- a/Content.Shared/Inventory/InventorySystem.Equip.cs +++ b/Content.Shared/Inventory/InventorySystem.Equip.cs @@ -176,7 +176,7 @@ public bool TryEquip(EntityUid actor, EntityUid target, EntityUid itemUid, strin }; _doAfter.TryStartDoAfter(args); - return true; // Changed to return true even if the item wasn't equipped instantly + return false; } if (!_containerSystem.Insert(itemUid, slotContainer)) diff --git a/Content.Shared/Inventory/InventoryTemplatePrototype.cs b/Content.Shared/Inventory/InventoryTemplatePrototype.cs index 585f80d4ce9..a4779699629 100644 --- a/Content.Shared/Inventory/InventoryTemplatePrototype.cs +++ b/Content.Shared/Inventory/InventoryTemplatePrototype.cs @@ -20,7 +20,7 @@ public sealed partial class SlotDefinition [DataField("slotFlags")] public SlotFlags SlotFlags { get; private set; } = SlotFlags.PREVENTEQUIP; [DataField("showInWindow")] public bool ShowInWindow { get; private set; } = true; [DataField("slotGroup")] public string SlotGroup { get; private set; } = "Default"; - [DataField("stripTime")] public TimeSpan StripTime { get; private set; } = TimeSpan.FromSeconds(4f); + [DataField("stripTime")] public float StripTime { get; private set; } = 4f; [DataField("uiWindowPos", required: true)] public Vector2i UIWindowPosition { get; private set; } diff --git a/Content.Shared/Strip/Components/StrippableComponent.cs b/Content.Shared/Strip/Components/StrippableComponent.cs index 4faca4d8f21..fbf99992e3c 100644 --- a/Content.Shared/Strip/Components/StrippableComponent.cs +++ b/Content.Shared/Strip/Components/StrippableComponent.cs @@ -1,4 +1,3 @@ -using Content.Shared.DoAfter; using Content.Shared.Inventory; using Robust.Shared.GameStates; using Robust.Shared.Serialization; @@ -9,10 +8,10 @@ namespace Content.Shared.Strip.Components public sealed partial class StrippableComponent : Component { /// - /// The strip delay for hands. + /// The strip delay for hands. /// [ViewVariables(VVAccess.ReadWrite), DataField("handDelay")] - public TimeSpan HandStripDelay = TimeSpan.FromSeconds(4f); + public float HandStripDelay = 4f; } [NetSerializable, Serializable] @@ -22,63 +21,63 @@ public enum StrippingUiKey : byte } [NetSerializable, Serializable] - public sealed class StrippingSlotButtonPressed(string slot, bool isHand) : BoundUserInterfaceMessage + public sealed class StrippingSlotButtonPressed : BoundUserInterfaceMessage { - public readonly string Slot = slot; - public readonly bool IsHand = isHand; + public readonly string Slot; + + public readonly bool IsHand; + + public StrippingSlotButtonPressed(string slot, bool isHand) + { + Slot = slot; + IsHand = isHand; + } } [NetSerializable, Serializable] - public sealed class StrippingEnsnareButtonPressed : BoundUserInterfaceMessage; + public sealed class StrippingEnsnareButtonPressed : BoundUserInterfaceMessage + { + public StrippingEnsnareButtonPressed() + { + } + } - [ByRefEvent] - public abstract class BaseBeforeStripEvent(TimeSpan initialTime, bool stealth = false) : EntityEventArgs, IInventoryRelayEvent + public abstract class BaseBeforeStripEvent : EntityEventArgs, IInventoryRelayEvent { - public readonly TimeSpan InitialTime = initialTime; + public readonly float InitialTime; + public float Time => MathF.Max(InitialTime * Multiplier + Additive, 0f); + public float Additive = 0; public float Multiplier = 1f; - public TimeSpan Additive = TimeSpan.Zero; - public bool Stealth = stealth; - - public TimeSpan Time => TimeSpan.FromSeconds(MathF.Max(InitialTime.Seconds * Multiplier + Additive.Seconds, 0f)); + public bool Stealth; public SlotFlags TargetSlots { get; } = SlotFlags.GLOVES; + + public BaseBeforeStripEvent(float initialTime, bool stealth = false) + { + InitialTime = initialTime; + Stealth = stealth; + } } /// - /// Used to modify strip times. Raised directed at the user. + /// Used to modify strip times. Raised directed at the user. /// /// - /// This is also used by some stripping related interactions, i.e., interactions with items that are currently equipped by another player. + /// This is also used by some stripping related interactions, i.e., interactions with items that are currently equipped by another player. /// - [ByRefEvent] - public sealed class BeforeStripEvent(TimeSpan initialTime, bool stealth = false) : BaseBeforeStripEvent(initialTime, stealth); + public sealed class BeforeStripEvent : BaseBeforeStripEvent + { + public BeforeStripEvent(float initialTime, bool stealth = false) : base(initialTime, stealth) { } + } /// - /// Used to modify strip times. Raised directed at the target. + /// Used to modify strip times. Raised directed at the target. /// /// - /// This is also used by some stripping related interactions, i.e., interactions with items that are currently equipped by another player. + /// This is also used by some stripping related interactions, i.e., interactions with items that are currently equipped by another player. /// - [ByRefEvent] - public sealed class BeforeGettingStrippedEvent(TimeSpan initialTime, bool stealth = false) : BaseBeforeStripEvent(initialTime, stealth); - - /// - /// Organizes the behavior of DoAfters for . - /// - [Serializable, NetSerializable] - public sealed partial class StrippableDoAfterEvent : DoAfterEvent + public sealed class BeforeGettingStrippedEvent : BaseBeforeStripEvent { - public readonly bool InsertOrRemove; - public readonly bool InventoryOrHand; - public readonly string SlotOrHandName; - - public StrippableDoAfterEvent(bool insertOrRemove, bool inventoryOrHand, string slotOrHandName) - { - InsertOrRemove = insertOrRemove; - InventoryOrHand = inventoryOrHand; - SlotOrHandName = slotOrHandName; - } - - public override DoAfterEvent Clone() => this; + public BeforeGettingStrippedEvent(float initialTime, bool stealth = false) : base(initialTime, stealth) { } } } diff --git a/Content.Shared/Strip/Components/ThievingComponent.cs b/Content.Shared/Strip/Components/ThievingComponent.cs index a851dd5ef63..83679f132c4 100644 --- a/Content.Shared/Strip/Components/ThievingComponent.cs +++ b/Content.Shared/Strip/Components/ThievingComponent.cs @@ -11,7 +11,7 @@ public sealed partial class ThievingComponent : Component /// [ViewVariables(VVAccess.ReadWrite)] [DataField("stripTimeReduction")] - public TimeSpan StripTimeReduction = TimeSpan.FromSeconds(0.5f); + public float StripTimeReduction = 0.5f; /// /// Should it notify the user if they're stripping a pocket? diff --git a/Content.Shared/Strip/SharedStrippableSystem.cs b/Content.Shared/Strip/SharedStrippableSystem.cs index 7afd4f245a1..a698ae5035a 100644 --- a/Content.Shared/Strip/SharedStrippableSystem.cs +++ b/Content.Shared/Strip/SharedStrippableSystem.cs @@ -14,12 +14,12 @@ public override void Initialize() SubscribeLocalEvent(OnDragDrop); } - public (TimeSpan Time, bool Stealth) GetStripTimeModifiers(EntityUid user, EntityUid target, TimeSpan initialTime) + public (float Time, bool Stealth) GetStripTimeModifiers(EntityUid user, EntityUid target, float initialTime) { var userEv = new BeforeStripEvent(initialTime); - RaiseLocalEvent(user, ref userEv); + RaiseLocalEvent(user, userEv); var ev = new BeforeGettingStrippedEvent(userEv.Time, userEv.Stealth); - RaiseLocalEvent(target, ref ev); + RaiseLocalEvent(target, ev); return (ev.Time, ev.Stealth); } diff --git a/Content.Shared/Strip/ThievingSystem.cs b/Content.Shared/Strip/ThievingSystem.cs index 2b3d3b38a00..0ef4b66571f 100644 --- a/Content.Shared/Strip/ThievingSystem.cs +++ b/Content.Shared/Strip/ThievingSystem.cs @@ -1,5 +1,4 @@ using Content.Shared.Inventory; -using Content.Shared.Strip; using Content.Shared.Strip.Components; namespace Content.Shared.Strip; diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs index ff8b102bb57..cadb0a4b215 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs @@ -443,7 +443,7 @@ protected void EjectCartridge( { Angle ejectAngle = angle.Value; ejectAngle += 3.7f; // 212 degrees; casings should eject slightly to the right and behind of a gun - ThrowingSystem.TryThrow(entity, ejectAngle.ToVec(), 625f); + ThrowingSystem.TryThrow(entity, ejectAngle.ToVec().Normalized() / 100, 5f); } if (playSound && TryComp(entity, out var cartridge)) { diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index c4056561c9c..3aea1324fe4 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -4251,37 +4251,3 @@ Entries: message: 'Height and Width sliders have been added to character creation. ' id: 6131 time: '2024-06-27T17:46:51.0000000+00:00' -- author: Mnemotechnician - changes: - - type: Add - message: Most items now take time to equip and unequip, especially space suits. - id: 6132 - time: '2024-06-30T18:22:28.0000000+00:00' -- author: VMSolidus - changes: - - type: Fix - message: >- - Spent bullet casings now fly away from a shooter in a cinematic manner, - rather than fall at their feet. - id: 6133 - time: '2024-07-01T22:37:29.0000000+00:00' -- author: WarMechanic - changes: - - type: Fix - message: Fixed loadouts becoming uneditable after spending all your points - id: 6134 - time: '2024-07-02T07:18:27.0000000+00:00' -- author: deltanedas - changes: - - type: Add - message: >- - Security can find the new SecWatch™ app in their PDAs to see current - suspects and wanted criminals. - id: 6135 - time: '2024-07-02T08:01:36.0000000+00:00' -- author: Mnemotechnician - changes: - - type: Fix - message: Equipping clothing using the Z key works correctly again. - id: 6136 - time: '2024-07-03T19:48:29.0000000+00:00' diff --git a/Resources/Credits/GitHub.txt b/Resources/Credits/GitHub.txt index 84796a94662..b5381a4ce29 100644 --- a/Resources/Credits/GitHub.txt +++ b/Resources/Credits/GitHub.txt @@ -1 +1 @@ -0x6273, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 4dplanner, 612git, 778b, Ablankmann, Acruid, actioninja, adamsong, Admiral-Obvious-001, Adrian16199, Aerocrux, Aexxie, africalimedrop, Agoichi, Ahion, AJCM-git, AjexRose, Alekshhh, AlexMorgan3817, AlmondFlour, AlphaQwerty, Altoids1, amylizzle, ancientpower, ArchPigeon, Arendian, arimah, Arteben, AruMoon, as334, AsikKEsel, asperger-sind, aspiringLich, avghdev, AzzyIsNotHere, BananaFlambe, BasedUser, BGare, BingoJohnson-zz, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, Boaz1111, BobdaBiscuit, brainfood1183, Brandon-Huu, Bribrooo, Bright0, brndd, BubblegumBlue, BYONDFuckery, c4llv07e, CaasGit, CakeQ, CaptainSqrBeard, Carbonhell, Carolyn3114, casperr04, CatTheSystem, Centronias, chairbender, Charlese2, Cheackraze, cheesePizza2, Chief-Engineer, chromiumboy, Chronophylos, clement-or, Clyybber, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, coolmankid12345, corentt, crazybrain23, creadth, CrigCrag, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, Daemon, daerSeebaer, dahnte, dakamakat, dakimasu, DamianX, DangerRevolution, daniel-cr, Darkenson, DawBla, dch-GH, Deahaka, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, deepdarkdepths, Delete69, deltanedas, DeltaV-Bot, DerbyX, DoctorBeard, DogZeroX, dontbetank, Doru991, DoubleRiceEddiedd, DrMelon, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, Dutch-VanDerLinde, Easypoller, eclips_e, EdenTheLiznerd, EEASAS, Efruit, ElectroSR, elthundercloud, Emisse, EmoGarbage404, Endecc, enumerate0, eoineoineoin, ERORR404V1, Errant-4, estacaoespacialpirata, exincore, exp111, Fahasor, FairlySadPanda, ficcialfaint, Fildrance, FillerVK, Fishfish458, Flareguy, FluffiestFloof, FluidRock, FoLoKe, fooberticus, Fortune117, FoxxoTrystan, freeman2651, Fromoriss, FungiFellow, GalacticChimp, gbasood, Geekyhobo, Genkail, geraeumig, Git-Nivrak, github-actions[bot], gituhabu, GNF54, Golinth, GoodWheatley, Gotimanga, graevy, GreyMario, Guess-My-Name, gusxyz, h3half, Hanzdegloker, Hardly3D, harikattar, Hebiman, Henry12116, HerCoyote23, Hmeister-real, HoofedEar, hord-brayden, hubismal, Hugal31, Hyenh, iacore, IamVelcroboy, icekot8, igorsaux, ike709, Illiux, Ilya246, IlyaElDunaev, Injazz, Insineer, IntegerTempest, Interrobang01, IProduceWidgets, ItsMeThom, j-giebel, Jackal298, Jackrost, jamessimo, janekvap, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JoeHammad1844, joelhed, JohnGinnane, johnku1, joshepvodka, jproads, Jrpl, juliangiebel, JustArt1m, JustCone14, JustinTether, JustinTrotter, KaiShibaa, kalane15, kalanosh, KEEYNy, Keikiru, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, KingFroozy, kira-er, Kit0vras, KittenColony, Kmc2000, Ko4ergaPunk, komunre, koteq, Krunklehorn, Kukutis96513, kxvvv, Lamrr, LankLTE, lapatison, Leander-0, leonardo-dabepis, LetterN, Level10Cybermancer, lever1209, LightVillet, liltenhead, LittleBuilderJane, Lomcastar, LordCarve, LordEclipse, LovelyLophi, LudwigVonChesterfield, Lukasz825700516, lunarcomets, luringens, lvvova1, lzimann, lzk228, M3739, MACMAN2003, Macoron, MagnusCrowe, ManelNavola, matthst, Matz05, MehimoNemo, MeltedPixel, MemeProof, Menshin, Mervill, metalgearsloth, mhamsterr, MilenVolf, Minty642, Mirino97, mirrorcult, misandrie, MishaUnity, MisterMecky, Mith-randalf, Moneyl, Moomoobeef, moony, Morb0, Mr0maks, musicmanvr, Myakot, Myctai, N3X15, Nairodian, Naive817, namespace-Memory, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, nmajask, nok-ko, Nopey, notafet, notquitehadouken, noudoit, noverd, nuke-haus, NULL882, OCOtheOmega, OctoRocket, OldDanceJacket, onoira, Owai-Seek, pali6, Pangogie, patrikturi, PaulRitter, Peptide90, peptron1, Phantom-Lily, PHCodes, PixelTheKermit, PJB3005, Plykiya, pofitlo, pointer-to-null, PolterTzi, PoorMansDreams, potato1234x, ProfanedBane, PrPleGoo, ps3moira, Psychpsyo, psykzz, PuroSlavKing, quatre, QuietlyWhisper, qwerltaz, Radosvik, Radrark, Rainbeon, Rainfey, Rane, ravage123321, rbertoche, Redict, RedlineTriad, RednoWCirabrab, RemberBM, RemieRichards, RemTim, rene-descartes2021, RiceMar1244, RieBi, Rinkashikachi, Rockdtben, rolfero, rosieposieeee, Saakra, Samsterious, SaphireLattice, ScalyChimp, scrato, Scribbles0, Serkket, SethLafuente, ShadowCommander, Shadowtheprotogen546, SignalWalker, SimpleStation14, Simyon264, SirDragooon, Sirionaut, siyengar04, Skarletto, Skrauz, Skyedra, SlamBamActionman, slarticodefast, Slava0135, Snowni, snowsignal, SonicHDC, SoulSloth, SpaceManiac, SpeltIncorrectyl, spoogemonster, ssdaniel24, Stealthbomber16, stellar-novas, StrawberryMoses, SweptWasTaken, Szunti, TadJohnson00, takemysoult, TaralGit, Tayrtahn, tday93, TekuNut, TemporalOroboros, tentekal, tgrkzus, thatrandomcanadianguy, TheArturZh, theashtronaut, thedraccx, themias, Theomund, theOperand, TheShuEd, TimrodDX, Titian3, tkdrg, tmtmtl30, tom-leys, tomasalves8, Tomeno, Tornado-Technology, tosatur, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, Tyler-IN, Tyzemol, UbaserB, UKNOWH, UnicornOnLSD, Uriende, UristMcDorf, Vaaankas, Varen, VasilisThePikachu, veliebm, Veritius, Verslebas, VigersRay, Visne, VMSolidus, volundr-, Voomra, Vordenburg, vulppine, waylon531, weaversam8, Willhelm53, wixoaGit, WlarusFromDaSpace, wrexbe, xRiriq, yathxyz, Ygg01, YotaXP, YuriyKiss, zach-hill, Zandario, Zap527, ZelteHonor, zerorulez, zionnBE, zlodo, ZNixian, ZoldorfTheWizard, Zumorica, Zymem +0x6273, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 4dplanner, 612git, 778b, Ablankmann, Acruid, actioninja, adamsong, Admiral-Obvious-001, Adrian16199, Aerocrux, Aexxie, africalimedrop, Agoichi, Ahion, AJCM-git, AjexRose, Alekshhh, AlexMorgan3817, AlmondFlour, AlphaQwerty, Altoids1, amylizzle, ancientpower, ArchPigeon, Arendian, arimah, Arteben, AruMoon, as334, AsikKEsel, asperger-sind, aspiringLich, avghdev, AzzyIsNotHere, BananaFlambe, BasedUser, BGare, BingoJohnson-zz, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, Boaz1111, BobdaBiscuit, brainfood1183, Brandon-Huu, Bribrooo, Bright0, brndd, BubblegumBlue, BYONDFuckery, c4llv07e, CaasGit, CakeQ, CaptainSqrBeard, Carbonhell, Carolyn3114, casperr04, CatTheSystem, Centronias, chairbender, Charlese2, Cheackraze, cheesePizza2, Chief-Engineer, chromiumboy, Chronophylos, clement-or, Clyybber, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, coolmankid12345, corentt, crazybrain23, creadth, CrigCrag, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, Daemon, daerSeebaer, dahnte, dakamakat, dakimasu, DamianX, DangerRevolution, daniel-cr, Darkenson, DawBla, dch-GH, Deahaka, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, deepdarkdepths, Delete69, deltanedas, DeltaV-Bot, DerbyX, DoctorBeard, DogZeroX, dontbetank, Doru991, DoubleRiceEddiedd, DrMelon, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, Dutch-VanDerLinde, Easypoller, eclips_e, EdenTheLiznerd, EEASAS, Efruit, ElectroSR, elthundercloud, Emisse, EmoGarbage404, Endecc, enumerate0, eoineoineoin, ERORR404V1, Errant-4, estacaoespacialpirata, exincore, exp111, Fahasor, FairlySadPanda, ficcialfaint, Fildrance, FillerVK, Fishfish458, Flareguy, FluffiestFloof, FluidRock, FoLoKe, fooberticus, Fortune117, FoxxoTrystan, freeman2651, Fromoriss, FungiFellow, GalacticChimp, gbasood, Geekyhobo, Genkail, Git-Nivrak, github-actions[bot], gituhabu, GNF54, Golinth, GoodWheatley, Gotimanga, graevy, GreyMario, Guess-My-Name, gusxyz, h3half, Hanzdegloker, Hardly3D, harikattar, Hebiman, Henry12116, HerCoyote23, Hmeister-real, HoofedEar, hord-brayden, hubismal, Hugal31, Hyenh, iacore, IamVelcroboy, icekot8, igorsaux, ike709, Illiux, Ilya246, IlyaElDunaev, Injazz, Insineer, IntegerTempest, Interrobang01, IProduceWidgets, ItsMeThom, j-giebel, Jackal298, Jackrost, jamessimo, janekvap, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JoeHammad1844, joelhed, JohnGinnane, johnku1, joshepvodka, jproads, Jrpl, juliangiebel, JustArt1m, JustCone14, JustinTether, JustinTrotter, KaiShibaa, kalane15, kalanosh, KEEYNy, Keikiru, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, KingFroozy, kira-er, Kit0vras, KittenColony, Kmc2000, Ko4ergaPunk, komunre, koteq, Krunklehorn, Kukutis96513, kxvvv, Lamrr, LankLTE, lapatison, Leander-0, leonardo-dabepis, LetterN, Level10Cybermancer, lever1209, LightVillet, liltenhead, LittleBuilderJane, Lomcastar, LordCarve, LordEclipse, LovelyLophi, LudwigVonChesterfield, Lukasz825700516, lunarcomets, luringens, lvvova1, lzimann, lzk228, M3739, MACMAN2003, Macoron, MagnusCrowe, ManelNavola, matthst, Matz05, MehimoNemo, MeltedPixel, MemeProof, Menshin, Mervill, metalgearsloth, mhamsterr, MilenVolf, Minty642, Mirino97, mirrorcult, misandrie, MishaUnity, MisterMecky, Mith-randalf, Moneyl, Moomoobeef, moony, Morb0, Mr0maks, musicmanvr, Myakot, Myctai, N3X15, Nairodian, Naive817, namespace-Memory, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, nmajask, nok-ko, Nopey, notafet, notquitehadouken, noudoit, noverd, nuke-haus, NULL882, OCOtheOmega, OctoRocket, OldDanceJacket, onoira, Owai-Seek, pali6, Pangogie, patrikturi, PaulRitter, Peptide90, peptron1, Phantom-Lily, PHCodes, PixelTheKermit, PJB3005, Plykiya, pofitlo, pointer-to-null, PolterTzi, PoorMansDreams, potato1234x, ProfanedBane, PrPleGoo, ps3moira, Psychpsyo, psykzz, PuroSlavKing, quatre, QuietlyWhisper, qwerltaz, Radosvik, Radrark, Rainbeon, Rainfey, Rane, ravage123321, rbertoche, Redict, RedlineTriad, RednoWCirabrab, RemberBM, RemieRichards, RemTim, rene-descartes2021, RiceMar1244, RieBi, Rinkashikachi, Rockdtben, rolfero, rosieposieeee, Saakra, Samsterious, SaphireLattice, ScalyChimp, scrato, Scribbles0, Serkket, SethLafuente, ShadowCommander, Shadowtheprotogen546, SignalWalker, SimpleStation14, Simyon264, SirDragooon, Sirionaut, siyengar04, Skarletto, Skrauz, Skyedra, SlamBamActionman, slarticodefast, Slava0135, Snowni, snowsignal, SonicHDC, SoulSloth, SpaceManiac, SpeltIncorrectyl, spoogemonster, ssdaniel24, Stealthbomber16, stellar-novas, StrawberryMoses, SweptWasTaken, Szunti, TadJohnson00, takemysoult, TaralGit, Tayrtahn, tday93, TekuNut, TemporalOroboros, tentekal, tgrkzus, thatrandomcanadianguy, TheArturZh, theashtronaut, thedraccx, themias, Theomund, theOperand, TheShuEd, TimrodDX, Titian3, tkdrg, tmtmtl30, tom-leys, tomasalves8, Tomeno, Tornado-Technology, tosatur, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, Tyler-IN, Tyzemol, UbaserB, UKNOWH, UnicornOnLSD, Uriende, UristMcDorf, Vaaankas, Varen, VasilisThePikachu, veliebm, Veritius, Verslebas, VigersRay, Visne, VMSolidus, volundr-, Voomra, Vordenburg, vulppine, waylon531, weaversam8, Willhelm53, wixoaGit, WlarusFromDaSpace, wrexbe, xRiriq, yathxyz, Ygg01, YotaXP, YuriyKiss, zach-hill, Zandario, Zap527, ZelteHonor, zerorulez, zionnBE, zlodo, ZNixian, ZoldorfTheWizard, Zumorica, Zymem diff --git a/Resources/Locale/en-US/deltav/cartridge-loader/secwatch.ftl b/Resources/Locale/en-US/deltav/cartridge-loader/secwatch.ftl deleted file mode 100644 index a5b96eab08f..00000000000 --- a/Resources/Locale/en-US/deltav/cartridge-loader/secwatch.ftl +++ /dev/null @@ -1,5 +0,0 @@ -sec-watch-program-name = SecWatch -sec-watch-title = SecWatch 1.0 -sec-watch-no-entries = Everything's calm. Why not enjoy a Monkin Donut? -sec-watch-entry = {$name}, {$job} -sec-watch-no-reason = None given??? diff --git a/Resources/Locale/en-US/store/uplink-catalog.ftl b/Resources/Locale/en-US/store/uplink-catalog.ftl index 4836a57d6b1..70eb998bb40 100644 --- a/Resources/Locale/en-US/store/uplink-catalog.ftl +++ b/Resources/Locale/en-US/store/uplink-catalog.ftl @@ -201,9 +201,6 @@ uplink-decoy-kit-desc = State-of-the-art distraction technology straight from RN uplink-chemistry-kit-name = Chemical Synthesis Kit uplink-chemistry-kit-desc = A starter kit for the aspiring chemist, includes toxin and vestine for all your criminal needs! -uplink-knives-kit-name = Throwing Knives Kit -uplink-knives-kit-desc = A set of 4 syndicate branded throwing knives, perfect for embedding into the body of your victims. - uplink-meds-bundle-name = Medical Bundle uplink-meds-bundle-desc = All you need to get your comrades back in the fight: mainly a combat medkit, a defibrillator and three combat medipens. diff --git a/Resources/Prototypes/Catalog/Fills/Boxes/syndicate.yml b/Resources/Prototypes/Catalog/Fills/Boxes/syndicate.yml index 7b5b05a49a5..53c526f0339 100644 --- a/Resources/Prototypes/Catalog/Fills/Boxes/syndicate.yml +++ b/Resources/Prototypes/Catalog/Fills/Boxes/syndicate.yml @@ -38,31 +38,14 @@ name: observations kit suffix: Filled components: - - type: StorageFill - contents: - - id: SyndiCrewMonitorEmpty - amount: 1 - - id: PowerCellHigh - amount: 1 - - id: ClothingEyesGlassesHiddenSecurity - amount: 1 - - id: SurveillanceCameraMonitorCircuitboard - amount: 1 + - type: StorageFill + contents: + - id: SyndiCrewMonitorEmpty + amount: 1 + - id: PowerCellHigh + amount: 1 + - id: ClothingEyesGlassesHiddenSecurity + amount: 1 + - id: SurveillanceCameraMonitorCircuitboard + amount: 1 -- type: entity - parent: BoxCardboard - id: ThrowingKnivesKit - name: throwing knives kit - description: A set of 4 syndicate branded throwing knives, perfect for embedding into the body of your victims. - components: - - type: Storage - grid: - - 0,0,3,1 - - type: StorageFill - contents: - - id: ThrowingKnife - amount: 4 - - type: Sprite - layers: - - state: box_of_doom - - state: throwing_knives diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml index 328ace7ba15..1e81cdf2dd1 100644 --- a/Resources/Prototypes/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/Catalog/uplink_catalog.yml @@ -65,17 +65,6 @@ categories: - UplinkWeapons -- type: listing - id: UplinkThrowingKnivesKit - name: uplink-knives-kit-name - description: uplink-knives-kit-desc - icon: { sprite: /Textures/Objects/Storage/boxicons.rsi, state: throwing_knives } - productEntity: ThrowingKnivesKit - cost: - Telecrystal: 6 - categories: - - UplinkWeapons - - type: listing id: UplinkGlovesNorthStar name: uplink-gloves-north-star-name diff --git a/Resources/Prototypes/DeltaV/Body/Prototypes/harpy.yml b/Resources/Prototypes/DeltaV/Body/Prototypes/harpy.yml index 25988f4a3a8..5b3615c55d8 100644 --- a/Resources/Prototypes/DeltaV/Body/Prototypes/harpy.yml +++ b/Resources/Prototypes/DeltaV/Body/Prototypes/harpy.yml @@ -13,10 +13,10 @@ torso: part: TorsoHarpy connections: - - right arm - left arm - - right leg + - right arm - left leg + - right leg organs: heart: OrganHumanHeart lungs: OrganHarpyLungs @@ -47,3 +47,4 @@ part: RightFootHarpy left foot: part: LeftFootHarpy + diff --git a/Resources/Prototypes/DeltaV/Body/Prototypes/vulpkanin.yml b/Resources/Prototypes/DeltaV/Body/Prototypes/vulpkanin.yml index cdf787e4736..3d1552ac81f 100644 --- a/Resources/Prototypes/DeltaV/Body/Prototypes/vulpkanin.yml +++ b/Resources/Prototypes/DeltaV/Body/Prototypes/vulpkanin.yml @@ -1,4 +1,4 @@ -- type: body +- type: body name: "vulpkanin" id: Vulpkanin root: torso @@ -19,10 +19,10 @@ liver: OrganAnimalLiver kidneys: OrganHumanKidneys connections: - - right arm - left arm - - right leg + - right arm - left leg + - right leg right arm: part: RightArmVulpkanin connections: diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Devices/cartridges.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Devices/cartridges.yml index def215cee43..e3d5e9d2138 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Devices/cartridges.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Devices/cartridges.yml @@ -17,24 +17,4 @@ icon: sprite: DeltaV/Icons/cri.rsi state: cri - -- type: entity - parent: BaseItem - id: SecWatchCartridge - name: sec watch cartridge - description: A cartridge that tracks the status of currently wanted individuals. - components: - - type: Sprite - sprite: DeltaV/Objects/Devices/cartridge.rsi - state: cart-cri - - type: Icon - sprite: DeltaV/Objects/Devices/cartridge.rsi - state: cart-cri - - type: UIFragment - ui: !type:SecWatchUi - - type: Cartridge - programName: sec-watch-program-name - icon: - sprite: Objects/Weapons/Melee/stunbaton.rsi - state: stunbaton_on - - type: SecWatchCartridge + - type: CrimeAssistCartridge diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Devices/pda.yml index d9607390cd7..6ee3a7543f7 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Devices/pda.yml @@ -20,13 +20,12 @@ map: [ "enum.PdaVisualLayers.IdLight" ] shader: "unshaded" visible: false - - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch + - type: CartridgeLoader # DeltaV - Crime Assist preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge - - SecWatchCartridge - type: Pda id: BrigmedicIDCard state: pda-corpsman diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml index 902c57418e4..13524efa9e6 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml @@ -93,9 +93,6 @@ - Hardsuit - WhitelistChameleon - HidesHarpyWings #DeltaV: Used by harpies to help render their hardsuit sprites - - type: Clothing - equipDelay: 2.5 # Hardsuits are heavy and take a while to put on/off. - unequipDelay: 2.5 - type: entity abstract: true @@ -117,9 +114,6 @@ - type: Tag tags: - HidesHarpyWings #DeltaV: Used by harpies to help render their hardsuit sprites - - type: Clothing - equipDelay: 1.25 # Softsuits are easier to put on and off - unequipDelay: 1 - type: entity parent: ClothingOuterBase diff --git a/Resources/Prototypes/Entities/Clothing/base_clothing.yml b/Resources/Prototypes/Entities/Clothing/base_clothing.yml index 810ada5429d..92a698dd301 100644 --- a/Resources/Prototypes/Entities/Clothing/base_clothing.yml +++ b/Resources/Prototypes/Entities/Clothing/base_clothing.yml @@ -11,9 +11,6 @@ - WhitelistChameleon - type: StaticPrice price: 15 - - type: Clothing - equipDelay: 0.5 - unequipDelay: 0.5 - type: entity abstract: true diff --git a/Resources/Prototypes/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Entities/Objects/Devices/pda.yml index 7155be68d74..706cbd5dbbf 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/pda.yml @@ -173,13 +173,12 @@ accentVColor: "#A32D26" - type: Icon state: pda-interncadet - - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch + - type: CartridgeLoader # DeltaV - Crime Assist preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge - - SecWatchCartridge - type: entity parent: BasePDA @@ -431,13 +430,12 @@ borderColor: "#6f6192" - type: Icon state: pda-lawyer - - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch + - type: CartridgeLoader # DeltaV - Crime Assist preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge - - SecWatchCartridge - type: entity parent: BasePDA @@ -645,13 +643,12 @@ accentHColor: "#447987" - type: Icon state: pda-hos - - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch + - type: CartridgeLoader # DeltaV - Crime Assist preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge - - SecWatchCartridge - type: entity parent: BasePDA @@ -667,13 +664,12 @@ accentVColor: "#949137" - type: Icon state: pda-warden - - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch + - type: CartridgeLoader # DeltaV - Crime Assist preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge - - SecWatchCartridge - type: entity parent: BasePDA @@ -688,13 +684,12 @@ borderColor: "#A32D26" - type: Icon state: pda-security - - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch + - type: CartridgeLoader # DeltaV - Crime Assist preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge - - SecWatchCartridge - type: entity parent: BasePDA @@ -984,13 +979,12 @@ borderColor: "#774705" - type: Icon state: pda-detective - - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch + - type: CartridgeLoader # DeltaV - Crime Assist preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge - - SecWatchCartridge - type: entity parent: BaseMedicalPDA @@ -1007,13 +1001,12 @@ accentVColor: "#d7d7d0" - type: Icon state: pda-brigmedic - - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch + - type: CartridgeLoader # DeltaV - Crime Assist preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge - - SecWatchCartridge - type: entity parent: ClownPDA @@ -1099,13 +1092,12 @@ accentVColor: "#DFDFDF" - type: Icon state: pda-seniorofficer - - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch + - type: CartridgeLoader # DeltaV - Crime Assist preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge - - SecWatchCartridge - type: entity parent: SyndiPDA diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/base_cartridge.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/base_cartridge.yml index 3bef413dffa..e188ee8c658 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/base_cartridge.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/base_cartridge.yml @@ -11,10 +11,10 @@ shape: !type:PhysShapeAabb bounds: "-0.10,-0.05,0.10,0.05" - density: 0.5 + density: 20 mask: - ItemMask - restitution: 0.7 # Small and bouncy + restitution: 0.3 # fite me friction: 0.2 - type: Tag tags: @@ -23,11 +23,6 @@ size: Tiny - type: SpaceGarbage - type: EmitSoundOnLand - sound: - path: /Audio/Weapons/Guns/Casings/casing_fall_1.ogg - params: - volume: -1 - - type: EmitSoundOnCollide sound: path: /Audio/Weapons/Guns/Casings/casing_fall_2.ogg params: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml index 03654061ced..b5d597715aa 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml @@ -252,32 +252,3 @@ sprite: Objects/Weapons/Melee/uranium_shiv.rsi - type: Sprite sprite: Objects/Weapons/Melee/uranium_shiv.rsi - -- type: entity - name: throwing knife - parent: BaseKnife - id: ThrowingKnife - description: This bloodred knife is very aerodynamic and easy to throw, but good luck trying to fight someone hand-to-hand. - components: - - type: Tag - tags: - - CombatKnife - - Knife - - type: Sprite - sprite: Objects/Weapons/Melee/throwing_knife.rsi - state: icon - - type: MeleeWeapon - wideAnimationRotation: -135 - attackRate: 2 - damage: - types: - Slash: 5 - - type: EmbeddableProjectile - sound: /Audio/Weapons/star_hit.ogg - - type: DamageOtherOnHit - damage: - types: - Slash: 10 - Piercing: 15 - - type: Item - sprite: Objects/Weapons/Melee/throwing_knife.rsi diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Body/Prototypes/felinid.yml b/Resources/Prototypes/Nyanotrasen/Entities/Body/Prototypes/felinid.yml index a09f3b6ab7f..6dd2a89e5a8 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Body/Prototypes/felinid.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Body/Prototypes/felinid.yml @@ -13,10 +13,10 @@ torso: part: TorsoHuman connections: - - right arm - left arm - - right leg + - right arm - left leg + - right leg organs: heart: OrganAnimalHeart lungs: OrganHumanLungs diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Head/hats.yml b/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Head/hats.yml index 83e3756c0f2..0a30756d724 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Head/hats.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Head/hats.yml @@ -99,8 +99,6 @@ sprite: Nyanotrasen/Clothing/Head/Hats/cage.rsi - type: Clothing sprite: Nyanotrasen/Clothing/Head/Hats/cage.rsi - equipDelay: 0.5 - unequipDelay: 6 - type: HeadCage - type: entity diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/pda.yml index 4e6115ba339..c2fd8786aff 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/pda.yml @@ -32,13 +32,12 @@ accentVColor: "#DFDFDF" - type: Icon state: pda-security - - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch + - type: CartridgeLoader # DeltaV - Crime Assist preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge - - SecWatchCartridge - type: entity parent: BasePDA diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/shock_collar.yml b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/shock_collar.yml index 1266a721fe2..35cdcae6589 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/shock_collar.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/shock_collar.yml @@ -8,8 +8,6 @@ sprite: Nyanotrasen/Clothing/Neck/Misc/shock.rsi - type: Clothing sprite: Nyanotrasen/Clothing/Neck/Misc/shock.rsi - equipDelay: 1 - unequipDelay: 10 # It's a collar meant to be used on prisoners (or not), so it probably has some sort of safety. - type: ShockCollar - type: UseDelay delay: 3 # DeltaV: prevent clocks instakilling people diff --git a/Resources/Textures/Objects/Storage/boxes.rsi/meta.json b/Resources/Textures/Objects/Storage/boxes.rsi/meta.json index 53ac39b639b..23868a906f4 100644 --- a/Resources/Textures/Objects/Storage/boxes.rsi/meta.json +++ b/Resources/Textures/Objects/Storage/boxes.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/cc65477c04f7403ca8a457bd5bae69a01abadbf0, encryptokey was taken from Baystation12 at https://github.com/infinitystation/Baystation12/blob/073f678cdce92edb8fcd55f9ffc9f0523bf31506/icons/obj/radio.dmi and modified by lapatison. boxwidetoy, shelltoy, swab, flare, inflatable, trashbag, magazine, holo and forensic created by potato1234x (github) for ss14 based on toys.rsi, mouth_swab.rsi, flare.rsi, inflatable_wall.rsi, trashbag.rsi, caseless_pistol_mag.rsi, guardians.rsi and bureaucracy.rsi respectively, candle and darts created by TheShuEd for ss14, throwing_knives and vials was drawn by Ubaser, evidence_markers by moomoobeef.", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/cc65477c04f7403ca8a457bd5bae69a01abadbf0, encryptokey was taken from Baystation12 at https://github.com/infinitystation/Baystation12/blob/073f678cdce92edb8fcd55f9ffc9f0523bf31506/icons/obj/radio.dmi and modified by lapatison. boxwidetoy, shelltoy, swab, flare, inflatable, trashbag, magazine, holo and forensic created by potato1234x (github) for ss14 based on toys.rsi, mouth_swab.rsi, flare.rsi, inflatable_wall.rsi, trashbag.rsi, caseless_pistol_mag.rsi, guardians.rsi and bureaucracy.rsi respectively, candle and darts created by TheShuEd for ss14, vials was drawn by Ubaser, evidence_markers by moomoobeef.", "size": { "x": 32, "y": 32 @@ -35,7 +35,7 @@ "name": "sechud" }, { - "name": "bottle" + "name": "bottle" }, { "name": "box" @@ -142,9 +142,6 @@ { "name": "syringe" }, - { - "name": "throwing_knives" - }, { "name": "trashbag" }, @@ -155,12 +152,12 @@ "name": "writing_of_doom" }, { - "name": "headset" - }, + "name": "headset" + }, { - "name": "encryptokey" - }, - { + "name": "encryptokey" + }, + { "name": "inhand-left", "directions": 4 }, diff --git a/Resources/Textures/Objects/Storage/boxes.rsi/throwing_knives.png b/Resources/Textures/Objects/Storage/boxes.rsi/throwing_knives.png deleted file mode 100644 index 834410a43ef64bd0f3dbfd9d852247d464cbd5f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1141 zcmZ`&O=#0#7*2JTtvC;YZit60f{2)WZB~X2X<#$^3EEL=g=`16Hc7XzG+#)*+BgSJ z4^u%!9HT)<=$0%*`di&DU%@%;&UsW-gtBTI$qnX zp%I554$ONq(!q5-B8aU>&&x>89OD#NW(q1SYK&X9d=&3;_*m9Zfpp7;>2PkE@-;Yo z_QZf9eHAp7rsPbPJOXWv>|x?eoDyOrN%FQ@;&S3Z2*h~Qs5XK)Ri);~s@R6_ zMOA=iXl2br4oENw&8P z^E>(cRx~-Ey}kOY>*2{yt7|vq_uqb=K@7Mycl6Mok8_dE*+}P;Zi~1#+Hs@h!h`!> N%S-*k;zHl}`F|_-V#WXf diff --git a/Resources/Textures/Objects/Storage/boxicons.rsi/meta.json b/Resources/Textures/Objects/Storage/boxicons.rsi/meta.json index 935b0b9f8b3..858fc7c4e54 100644 --- a/Resources/Textures/Objects/Storage/boxicons.rsi/meta.json +++ b/Resources/Textures/Objects/Storage/boxicons.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from baystation at https://github.com/Baystation12/Baystation12/commit/bc9fbb1722530596e3aa7522ee407280b323ad43, throwing_knives and vials are drawn by Ubaser, tracks made by Fazansen(https://github.com/Fazansen).", + "copyright": "Taken from baystation at https://github.com/Baystation12/Baystation12/commit/bc9fbb1722530596e3aa7522ee407280b323ad43, vials drawn by Ubaser, tracks made by Fazansen(https://github.com/Fazansen).", "size": { "x": 32, "y": 32 @@ -76,9 +76,6 @@ { "name": "syringe" }, - { - "name": "throwing_knives" - }, { "name": "ziptie" }, diff --git a/Resources/Textures/Objects/Storage/boxicons.rsi/throwing_knives.png b/Resources/Textures/Objects/Storage/boxicons.rsi/throwing_knives.png deleted file mode 100644 index b2af7bce88436ed9b060cec8bd6f97019537caa9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1392 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}e5nzhX}-P; zT0k}j5QD&_;K@Lev%n*=n1MlK76>znTPbd0U|=rE42dX-@b$4u&d=3LOvz75)vL%Y z0PC`;umUo3Q%e#RDspr3imfVamB1>jfNYSkzLEl1NlCV?QiN}Sf^&XRs)CuGfu4bq z9hZWFf=y9MnpKdC8&o@xXRDM^Qc_^0uU}qXu2*iXmtT~wZ)j<0sc&GUZ)BtkRH0j3 znOBlnp_^B%3^4>|j!SBBa#3bMNoIbY0?6FNr2NtnTO}osMQ{LdXG${Mo`TY%9I!1Z z$@-}|sky0nCB^!NdWQPg^p#|$AzYYO3=Ixo!03ZyfZ7bOYV#~8Nj3q7lxqdhJy8Dv z9hwZbx40xlA4!3}k%57Qu7Q!Rk)=M|e?aHkq$FFFWR~Qlf&&ijA8-gd=9Hj{g4Bb8 zASV+PvQ{~XdFi%F6}l;@X^EvdB}#Tl`4#c`Y4Iuf`MEaw5QV4)Ktxf^wb94o1RIdY zts;X`i}Q0zK|yb4WM*Om4h|GiL?l3TL}1l{EQ+opAS1sdADF0$GLt>?N>Ymoihv0W zVk6W(+$zw`LRcP}msw(G1T_Fn7)cjW1X(#2m6YcfWru(x10^JJs)CvX300(Y3dscE z7y#x1J1!f2c#g8;T5vFZ7clEqd%8G=L~y$v&<~>y})k!b$Ij_*Boec?7c@H{qFghl3r*G!+?2O}8vz5m}+81h%=^c1PKS83O{n;1@QN}0Z7^Xpv`mc7*YUNB{2a+8@u z6VE;{x%R3Bx1%7%JU02a%^lN%F zE%jh-`3kPxCsNfyV%|*TT~Hz7n*90eUlmUe899+_S!k}&6*}S*Quc$Du?mypn?RQoOuZK{=k6;xQ!K#XyN7Ju|PyZWn zMDN`Biup!2tQbXXfBj=p>r*o7QRYk6np)zppMvt=Rf6n1)cS_o?!bBEpWVW zzxWC@_m8>zq*a)GFBhEM{dHDh?X&sHg;q@=(~U%$M(T(8_%FTW^V-_X+1Qs2Nx-^fT8s6w~6 zGOr}DLN~8i8Da>`9GBGM~RsBTId_|A5Z7NlCUU$t=l91qU45Kj08_%qc+?1*r!G zK~5$pWUX=%^U`gVDs)p)(-KQ_N|fv}^D+|iQgn+l(=$qJ^dTxyO@N4^8f>GF#SJzf zpIb!+r55Msl!C(E&dAKf1{@wJqKH_4=!n3o16dSZM?gk?Nj@-D6=f!S=9Q!t6%+we z7{o@XeYjPin}x7EG%vHn&IoD%nlO?sq!_YtEGj9_FUk%9#|COp;#3AT3KFbHDHW0p zz)=9q2XMaQ|Ei{ z!xO@M-(SD!`>3)=h^2Je2J^D5F{d?VMa9-GwO_78j!x3y?Z zAj4G~+4hAyrlqc*dNa%HszigAoqha~oP8H+mOXafayE9a!9u>WGK-y+(MulJo4!

{Sco1*{# diff --git a/Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/icon.png b/Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/icon.png deleted file mode 100644 index 2c61755b52c35b9138c5aa7f93ec6e71bffa7871..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1593 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}e5nzhX}-P; zT0k}j5QD&_;K@Lev%n*=7^vU~2s2LA=96Y%V9v=5i71Ki^|4CM&(%vz$xlkvtH>$0h^0y1+`OA-|-a&z*EttxDlz$&bOY>=?Nk^)#sNw%$0gl~X?bAC~(f|;Iyo`I4b zmx6+VO;JjkRgjAtR6CGotCUevQedU8UtV6WS8lAAUzDzIXlZGwZ(yWvWTXpJp<7&; zSCUwvn^&w1F$89gOKNd)QD#9&W`3Rm$lS!F{L&IzB_)tWZ~$>9$H0x+$q?iKRIuN_L*U?(xRP#^yHq5LKwUA)=^;+UR4k-v;DstH_|# z;{2RaP`KM!n%RJZ0!0uJ0T2xl*fbyuqH74q$S=tUrl+FJWY4^k)S`kSVA=xPX9Tql zw+eK#5O#;=WtP~%3_ue`(uEW^R*pp_<@rU~A>epG1R_o)P-7qgij+Pfi60#Jz|?QY zWup(zNp@V%mxb~$FfjRex;TbJaJ~)o_78Rx`Ind7Qc!9C=1{nZp6(V`<|%VS?rwO| zv`YFX^9e4~PsSA-Axxj#MNAkEdHI&OX76G=)GMZ}=rs8q-}j!mL07V^3U2f6J^AI# zoq03g8>T;Fdis2i^@6E~7#7=l^gJ%xJ+Y%+lXKaHqX+i&-QKcutMlpi*H_-Xt=jRV zd*1~6f=%ZSTsAiTP#JCb>kaF>`@6Xp?f)>h#U}3b>)o#T)52Oly*PYaWOlU5PTu2@ z`>WU4$ImIf^YZ<&n>TcNwn&$7C%_^!e&PWtFDOYqF~P)RrY}dv#vx z+mV|31?|)Bt-W|{n`iU1w>;<0W?wzjc_fLaDOPdysp~DDCN*y^+BSEpyF4%F)yewt zqVAQxxweIq_1K#BTHaROvFh!q{eFz zK3OI`antZn#mM^|`vUTx9X{?q)pV<`M@~&xT=!J%TJAry)DFy+mU5`JKlnhdpM7PB z*G*T;g$Ycu3|n7Vm0iv>{N65lwq#bQ@Z<*>?{c(v2M9F!WqQbu$Pe0yk&>D6*Hq-gd*mBP7>5; hNwHl1#vxGFf@x_avz=0K&TUY!?dj_0vd$@?2>>-FL7@Nu diff --git a/Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/inhand-left.png deleted file mode 100644 index 5988d571dc12ca1c485efc87735bbba3ce635640..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1296 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|_);T0(|mmy zw18|5AO?X;!IOa`XMsm#F$06fED&ZCw^H21z`$IV84^(v;p=0SoS&h?X&sHg;q@=(~U%$M(T(8_%FTW^V-_X+1Qs2Nx-^fT8s6w~6 zGOr}DLN~8i8Da>`9GBGM~RsBTId_|A5Z7NlCUU$t=l91qU45Kj08_%qc+?1*r!G zK~5$pWUX=%^U`gVDs)p)(-KQ_N|fv}^D+|iQgn+l(=$qJ^dTxyO@N4^8f>GF#SJzf zpIb!+r55Msl!C(E&dAKf1{@wJqKH_4=!n3o16dSZM?gk?Nj@-D6=f!S=9Q!t6%+we z7{o@XeYjPin}x7EG%vHn&IoD%nlO?sq!_YtEGj9_FUk%9#|COp;#3AT3KFbHDHW0p zz)=9q2X*mm#I&6k+g^W`6|5prbv@a}`Hz?!tn&ug}I zy!5S_wCuBHzq<U{MO(OH#J#lhTTXtx$E#ub`D;1*mDf3?|1NQ# p_;-Kx%DB?a9Dh3C-ua-+#BaJLkNt{4Ehnfn@^tlcS?83{1OP7tpo#zh diff --git a/Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/inhand-right.png deleted file mode 100644 index 09c015efac56e7935ff49a7488bea47ee21f706a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1298 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|_);T0(|mmy zw18|5AO?X;!IOa`XMsm#F$06fED&ZCw^H21z`$IV84^(v;p=0SoS&h?X&sHg;q@=(~U%$M(T(8_%FTW^V-_X+1Qs2Nx-^fT8s6w~6 zGOr}DLN~8i8Da>`9GBGM~RsBTId_|A5Z7NlCUU$t=l91qU45Kj08_%qc+?1*r!G zK~5$pWUX=%^U`gVDs)p)(-KQ_N|fv}^D+|iQgn+l(=$qJ^dTxyO@N4^8f>GF#SJzf zpIb!+r55Msl!C(E&dAKf1{@wJqKH_4=!n3o16dSZM?gk?Nj@-D6=f!S=9Q!t6%+we z7{o@XeYjPin}x7EG%vHn&IoD%nlO?sq!_YtEGj9_FUk%9#|COp;#3AT3KFbHDHW0p zz)=9q2X1D--Z+E{R|F`Dg_uaXhW6tcgx!1%pi>paAZW9~hvW5@d6(?_2pParSE_c-* z{|Wn+{=e67Ep6>X)9_3GCW~F>Grp7k(%8AgO9|B?RC`-lOEe^_b5>b}$HEbI&63Re#m1*}He%`O5qM s!?yrm-qO5?#!wak2L?tE(OAW5$7GzxZoH}C0;oLlboFyt=akR{01HQ^j{pDw diff --git a/Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/meta.json b/Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/meta.json deleted file mode 100644 index 373d2d77701..00000000000 --- a/Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/meta.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Drawn by Ubaser.", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "equipped-BELT", - "directions": 4 - } - ] -} From 23059a860d317feebae3e0696da5e7596a084ca5 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Thu, 4 Jul 2024 00:27:02 -0400 Subject: [PATCH 82/82] Reapply "Merge branch 'Simple-Station:master' into Psionic-Power-Refactor" This reverts commit 2f3ee29ec0b1f0b1c51d04c467c7396f1f3df463. --- .../Cartridges/CrimeAssistUi.cs | 9 - .../Cartridges/CrimeAssistUiFragment.xaml.cs | 3 - .../Cartridges/SecWatchEntryControl.xaml | 19 + .../Cartridges/SecWatchEntryControl.xaml.cs | 21 + .../CartridgeLoader/Cartridges/SecWatchUi.cs | 27 + .../Cartridges/SecWatchUiFragment.xaml | 13 + .../Cartridges/SecWatchUiFragment.xaml.cs | 25 + .../UI/HumanoidProfileEditor.xaml.cs | 2 +- .../Cartridges/SecWatchCartridgeComponent.cs | 23 + .../Cartridges/SecWatchCartridgeSystem.cs | 73 ++ .../CrimeAssistCartridgeComponent.cs | 5 - .../CrimeAssistCartridgeSystem.cs | 16 - Content.Server/Strip/StrippableSystem.cs | 680 +++++++++++------- .../Clothing/EntitySystems/ClothingSystem.cs | 5 + .../EntitySystems/ToggleableClothingSystem.cs | 2 +- .../Cartridges/CrimeAssistUiState.cs | 18 - .../Cartridges/SecWatchUiState.cs | 24 + .../Inventory/InventorySystem.Equip.cs | 2 +- .../Inventory/InventoryTemplatePrototype.cs | 2 +- .../Strip/Components/StrippableComponent.cs | 79 +- .../Strip/Components/ThievingComponent.cs | 2 +- .../Strip/SharedStrippableSystem.cs | 6 +- Content.Shared/Strip/ThievingSystem.cs | 1 + .../Weapons/Ranged/Systems/SharedGunSystem.cs | 2 +- Resources/Changelog/Changelog.yml | 34 + Resources/Credits/GitHub.txt | 2 +- .../deltav/cartridge-loader/secwatch.ftl | 5 + .../Locale/en-US/store/uplink-catalog.ftl | 3 + .../Catalog/Fills/Boxes/syndicate.yml | 37 +- .../Prototypes/Catalog/uplink_catalog.yml | 11 + .../DeltaV/Body/Prototypes/harpy.yml | 5 +- .../DeltaV/Body/Prototypes/vulpkanin.yml | 6 +- .../Entities/Objects/Devices/cartridges.yml | 22 +- .../DeltaV/Entities/Objects/Devices/pda.yml | 3 +- .../OuterClothing/base_clothingouter.yml | 6 + .../Entities/Clothing/base_clothing.yml | 3 + .../Entities/Objects/Devices/pda.yml | 24 +- .../Ammunition/Cartridges/base_cartridge.yml | 9 +- .../Entities/Objects/Weapons/Melee/knife.yml | 29 + .../Entities/Body/Prototypes/felinid.yml | 4 +- .../Entities/Clothing/Head/hats.yml | 2 + .../Entities/Objects/Devices/pda.yml | 3 +- .../Entities/Objects/Devices/shock_collar.yml | 2 + .../Objects/Storage/boxes.rsi/meta.json | 17 +- .../Storage/boxes.rsi/throwing_knives.png | Bin 0 -> 1141 bytes .../Objects/Storage/boxicons.rsi/meta.json | 5 +- .../Storage/boxicons.rsi/throwing_knives.png | Bin 0 -> 1392 bytes .../throwing_knife.rsi/equipped-BELT.png | Bin 0 -> 1289 bytes .../Weapons/Melee/throwing_knife.rsi/icon.png | Bin 0 -> 1593 bytes .../Melee/throwing_knife.rsi/inhand-left.png | Bin 0 -> 1296 bytes .../Melee/throwing_knife.rsi/inhand-right.png | Bin 0 -> 1298 bytes .../Melee/throwing_knife.rsi/meta.json | 26 + 52 files changed, 920 insertions(+), 397 deletions(-) create mode 100644 Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml create mode 100644 Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml.cs create mode 100644 Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUi.cs create mode 100644 Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml create mode 100644 Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml.cs create mode 100644 Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeComponent.cs create mode 100644 Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeSystem.cs delete mode 100644 Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeComponent.cs delete mode 100644 Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeSystem.cs delete mode 100644 Content.Shared/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiState.cs create mode 100644 Content.Shared/DeltaV/CartridgeLoader/Cartridges/SecWatchUiState.cs create mode 100644 Resources/Locale/en-US/deltav/cartridge-loader/secwatch.ftl create mode 100644 Resources/Textures/Objects/Storage/boxes.rsi/throwing_knives.png create mode 100644 Resources/Textures/Objects/Storage/boxicons.rsi/throwing_knives.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/equipped-BELT.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/icon.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/meta.json diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUi.cs b/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUi.cs index ea5aa3cf256..2dbe923b2a6 100644 --- a/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUi.cs +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUi.cs @@ -18,15 +18,6 @@ public override Control GetUIFragmentRoot() public override void Setup(BoundUserInterface userInterface, EntityUid? fragmentOwner) { _fragment = new CrimeAssistUiFragment(); - - _fragment.OnSync += _ => SendSyncMessage(userInterface); - } - - private void SendSyncMessage(BoundUserInterface userInterface) - { - var syncMessage = new CrimeAssistSyncMessageEvent(); - var message = new CartridgeUiMessage(syncMessage); - userInterface.SendMessage(message); } public override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiFragment.xaml.cs b/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiFragment.xaml.cs index e3163975d12..fb085a8a799 100644 --- a/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiFragment.xaml.cs +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiFragment.xaml.cs @@ -1,7 +1,6 @@ using Content.Client.Message; using Content.Shared.DeltaV.CartridgeLoader.Cartridges; using Robust.Client.AutoGenerated; -using Robust.Client.ResourceManagement; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; using Robust.Shared.Prototypes; @@ -13,9 +12,7 @@ namespace Content.Client.DeltaV.CartridgeLoader.Cartridges; public sealed partial class CrimeAssistUiFragment : BoxContainer { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly IResourceCache _resourceCache = default!; - public event Action? OnSync; private CrimeAssistPage _currentPage; private List? _pages; diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml new file mode 100644 index 00000000000..2de8a37ff77 --- /dev/null +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml @@ -0,0 +1,19 @@ + + + + + + + + + + diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml.cs b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml.cs new file mode 100644 index 00000000000..e8dd4eea446 --- /dev/null +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml.cs @@ -0,0 +1,21 @@ +using Content.Shared.CartridgeLoader.Cartridges; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.DeltaV.CartridgeLoader.Cartridges; + +[GenerateTypedNameReferences] +public sealed partial class SecWatchEntryControl : BoxContainer +{ + public SecWatchEntryControl(SecWatchEntry entry) + { + RobustXamlLoader.Load(this); + + Status.Text = Loc.GetString($"criminal-records-status-{entry.Status.ToString().ToLower()}"); + Title.Text = Loc.GetString("sec-watch-entry", ("name", entry.Name), ("job", entry.Job)); + + Reason.Text = entry.Reason ?? Loc.GetString("sec-watch-no-reason"); + } +} diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUi.cs b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUi.cs new file mode 100644 index 00000000000..da5ff825b91 --- /dev/null +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUi.cs @@ -0,0 +1,27 @@ +using Content.Client.UserInterface.Fragments; +using Content.Shared.CartridgeLoader; +using Content.Shared.CartridgeLoader.Cartridges; +using Robust.Client.UserInterface; + +namespace Content.Client.DeltaV.CartridgeLoader.Cartridges; + +public sealed partial class SecWatchUi : UIFragment +{ + private SecWatchUiFragment? _fragment; + + public override Control GetUIFragmentRoot() + { + return _fragment!; + } + + public override void Setup(BoundUserInterface ui, EntityUid? owner) + { + _fragment = new SecWatchUiFragment(); + } + + public override void UpdateState(BoundUserInterfaceState state) + { + if (state is SecWatchUiState cast) + _fragment?.UpdateState(cast); + } +} diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml new file mode 100644 index 00000000000..7fb2c42debc --- /dev/null +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml @@ -0,0 +1,13 @@ + + + + diff --git a/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml.cs b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml.cs new file mode 100644 index 00000000000..ad152840529 --- /dev/null +++ b/Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml.cs @@ -0,0 +1,25 @@ +using Content.Shared.CartridgeLoader.Cartridges; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.DeltaV.CartridgeLoader.Cartridges; + +[GenerateTypedNameReferences] +public sealed partial class SecWatchUiFragment : BoxContainer +{ + public SecWatchUiFragment() + { + RobustXamlLoader.Load(this); + } + + public void UpdateState(SecWatchUiState state) + { + NoEntries.Visible = state.Entries.Count == 0; + Entries.RemoveAllChildren(); + foreach (var entry in state.Entries) + { + Entries.AddChild(new SecWatchEntryControl(entry)); + } + } +} diff --git a/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs b/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs index c797f02a754..04810b07719 100644 --- a/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs +++ b/Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs @@ -2086,7 +2086,7 @@ void AddSelector(LoadoutPreferenceSelector selector, int points, string id) selector.PreferenceChanged += preference => { // Make sure they have enough loadout points - preference = preference ? CheckPoints(points, preference) : CheckPoints(-points, preference); + preference = preference ? CheckPoints(-points, preference) : CheckPoints(points, preference); // Update Preferences Profile = Profile?.WithLoadoutPreference(id, preference); diff --git a/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeComponent.cs b/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeComponent.cs new file mode 100644 index 00000000000..7ccc90ef797 --- /dev/null +++ b/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeComponent.cs @@ -0,0 +1,23 @@ +using Content.Shared.Security; + +namespace Content.Server.CartridgeLoader.Cartridges; + +[RegisterComponent, Access(typeof(SecWatchCartridgeSystem))] +public sealed partial class SecWatchCartridgeComponent : Component +{ + ///

+ /// Only show people with these statuses. + /// + [DataField] + public List Statuses = new() + { + SecurityStatus.Suspected, + SecurityStatus.Wanted + }; + + /// + /// Station entity thats getting its records checked. + /// + [DataField] + public EntityUid? Station; +} diff --git a/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeSystem.cs b/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeSystem.cs new file mode 100644 index 00000000000..16da24514cb --- /dev/null +++ b/Content.Server/DeltaV/CartridgeLoader/Cartridges/SecWatchCartridgeSystem.cs @@ -0,0 +1,73 @@ +using Content.Server.Station.Systems; +using Content.Server.StationRecords; +using Content.Server.StationRecords.Systems; +using Content.Shared.CartridgeLoader; +using Content.Shared.CartridgeLoader.Cartridges; +using Content.Shared.CriminalRecords; +using Content.Shared.StationRecords; + +namespace Content.Server.CartridgeLoader.Cartridges; + +public sealed class SecWatchCartridgeSystem : EntitySystem +{ + [Dependency] private readonly CartridgeLoaderSystem _cartridgeLoader = default!; + [Dependency] private readonly StationRecordsSystem _records = default!; + [Dependency] private readonly StationSystem _station = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnRecordModified); + + SubscribeLocalEvent(OnUiReady); + } + + private void OnRecordModified(RecordModifiedEvent args) + { + // when a record is modified update the ui of every loaded cartridge tuned to the same station + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var comp, out var cartridge)) + { + if (cartridge.LoaderUid is not {} loader || comp.Station != args.Station) + continue; + + UpdateUI((uid, comp), loader); + } + } + + private void OnUiReady(Entity ent, ref CartridgeUiReadyEvent args) + { + UpdateUI(ent, args.Loader); + } + + private void UpdateUI(Entity ent, EntityUid loader) + { + // if the loader is on a grid, update the station + // if it is off grid use the cached station + if (_station.GetOwningStation(loader) is {} station) + ent.Comp.Station = station; + + if (!TryComp(ent.Comp.Station, out var records)) + return; + + station = ent.Comp.Station.Value; + + var entries = new List(); + foreach (var (id, criminal) in _records.GetRecordsOfType(station, records)) + { + if (!ent.Comp.Statuses.Contains(criminal.Status)) + continue; + + var key = new StationRecordKey(id, station); + if (!_records.TryGetRecord(key, out var general, records)) + continue; + + var status = criminal.Status; + entries.Add(new SecWatchEntry(general.Name, general.JobTitle, criminal.Status, criminal.Reason)); + } + + var state = new SecWatchUiState(entries); + _cartridgeLoader.UpdateCartridgeUiState(loader, state); + } +} diff --git a/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeComponent.cs b/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeComponent.cs deleted file mode 100644 index 741a6134580..00000000000 --- a/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeComponent.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Content.Server.DeltaV.CartridgeLoader.Cartridges; - -[RegisterComponent] -public sealed partial class CrimeAssistCartridgeComponent : Component -{ } diff --git a/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeSystem.cs b/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeSystem.cs deleted file mode 100644 index 06732c2c534..00000000000 --- a/Content.Server/DeltaV/CartridgeLoader/CrimeAssistCartridgeSystem.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Content.Shared.CartridgeLoader; -using Content.Server.DeltaV.CartridgeLoader; -using Content.Server.CartridgeLoader.Cartridges; -using Content.Server.CartridgeLoader; - -namespace Content.Server.DeltaV.CartridgeLoader.Cartridges; - -public sealed class CrimeAssistCartridgeSystem : EntitySystem -{ - [Dependency] private readonly CartridgeLoaderSystem? _cartridgeLoaderSystem = default!; - - public override void Initialize() - { - base.Initialize(); - } -} diff --git a/Content.Server/Strip/StrippableSystem.cs b/Content.Server/Strip/StrippableSystem.cs index 96b2ecc00c6..3b38b65a19d 100644 --- a/Content.Server/Strip/StrippableSystem.cs +++ b/Content.Server/Strip/StrippableSystem.cs @@ -1,4 +1,3 @@ -using System.Linq; using Content.Server.Administration.Logs; using Content.Server.Ensnaring; using Content.Shared.CombatMode; @@ -21,18 +20,21 @@ using Robust.Server.GameObjects; using Robust.Shared.Player; using Robust.Shared.Utility; +using System.Linq; namespace Content.Server.Strip { public sealed class StrippableSystem : SharedStrippableSystem { - [Dependency] private readonly SharedCuffableSystem _cuffable = default!; - [Dependency] private readonly SharedHandsSystem _handsSystem = default!; [Dependency] private readonly InventorySystem _inventorySystem = default!; - [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; - [Dependency] private readonly SharedPopupSystem _popup = default!; - [Dependency] private readonly EnsnareableSystem _ensnaring = default!; + [Dependency] private readonly EnsnareableSystem _ensnaringSystem = default!; [Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!; + + [Dependency] private readonly SharedCuffableSystem _cuffableSystem = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly SharedHandsSystem _handsSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly IAdminLogManager _adminLogger = default!; // TODO: ECS popups. Not all of these have ECS equivalents yet. @@ -48,64 +50,58 @@ public override void Initialize() // BUI SubscribeLocalEvent(OnStripButtonPressed); SubscribeLocalEvent(OnStripEnsnareMessage); + + // DoAfters + SubscribeLocalEvent>(OnStrippableDoAfterRunning); + SubscribeLocalEvent(OnStrippableDoAfterFinished); } - private void OnStripEnsnareMessage(EntityUid uid, EnsnareableComponent component, StrippingEnsnareButtonPressed args) + private void AddStripVerb(EntityUid uid, StrippableComponent component, GetVerbsEvent args) { - if (args.Session.AttachedEntity is not {Valid: true} user) + if (args.Hands == null || !args.CanAccess || !args.CanInteract || args.Target == args.User) return; - foreach (var entity in component.Container.ContainedEntities) + if (!HasComp(args.User)) + return; + + Verb verb = new() { - if (!TryComp(entity, out var ensnaring)) - continue; + Text = Loc.GetString("strip-verb-get-data-text"), + Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/outfit.svg.192dpi.png")), + Act = () => StartOpeningStripper(args.User, (uid, component), true), + }; - _ensnaring.TryFree(uid, user, entity, ensnaring); - return; - } + args.Verbs.Add(verb); } - private void OnStripButtonPressed(Entity strippable, ref StrippingSlotButtonPressed args) + private void AddStripExamineVerb(EntityUid uid, StrippableComponent component, GetVerbsEvent args) { - if (args.Session.AttachedEntity is not {Valid: true} user || - !TryComp(user, out var userHands)) - return; - - if (args.IsHand) - { - StripHand(user, args.Slot, strippable, userHands); + if (args.Hands == null || !args.CanAccess || !args.CanInteract || args.Target == args.User) return; - } - if (!TryComp(strippable, out var inventory)) + if (!HasComp(args.User)) return; - var hasEnt = _inventorySystem.TryGetSlotEntity(strippable, args.Slot, out var held, inventory); + ExamineVerb verb = new() + { + Text = Loc.GetString("strip-verb-get-data-text"), + Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/outfit.svg.192dpi.png")), + Act = () => StartOpeningStripper(args.User, (uid, component), true), + Category = VerbCategory.Examine, + }; - if (userHands.ActiveHandEntity != null && !hasEnt) - PlaceActiveHandItemInInventory(user, strippable, userHands.ActiveHandEntity.Value, args.Slot, strippable); - else if (userHands.ActiveHandEntity == null && hasEnt) - TakeItemFromInventory(user, strippable, held!.Value, args.Slot, strippable); + args.Verbs.Add(verb); } - private void StripHand(EntityUid user, string handId, Entity target, HandsComponent userHands) + private void OnActivateInWorld(EntityUid uid, StrippableComponent component, ActivateInWorldEvent args) { - if (!_handsSystem.TryGetHand(target, handId, out var hand)) + if (args.Target == args.User) return; - // is the target a handcuff? - if (TryComp(hand.HeldEntity, out VirtualItemComponent? virt) - && TryComp(target, out CuffableComponent? cuff) - && _cuffable.GetAllCuffs(cuff).Contains(virt.BlockingEntity)) - { - _cuffable.TryUncuff(target, user, virt.BlockingEntity, cuffable: cuff); + if (!HasComp(args.User)) return; - } - if (userHands.ActiveHandEntity != null && hand.HeldEntity == null) - PlaceActiveHandItemInHands(user, target, userHands.ActiveHandEntity.Value, handId, target); - else if (userHands.ActiveHandEntity == null && hand.HeldEntity != null) - TakeItemFromHands(user, target, hand.HeldEntity.Value, handId, target); + StartOpeningStripper(args.User, (uid, component)); } public override void StartOpeningStripper(EntityUid user, Entity strippable, bool openInCombat = false) @@ -123,352 +119,520 @@ public override void StartOpeningStripper(EntityUid user, Entity args) + private void OnStripButtonPressed(Entity strippable, ref StrippingSlotButtonPressed args) { - if (args.Hands == null || !args.CanAccess || !args.CanInteract || args.Target == args.User) + if (args.Session.AttachedEntity is not { Valid: true } user || + !TryComp(user, out var userHands)) return; - if (!HasComp(args.User)) + if (args.IsHand) + { + StripHand((user, userHands), (strippable.Owner, null), args.Slot, strippable); return; + } - Verb verb = new() - { - Text = Loc.GetString("strip-verb-get-data-text"), - Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/outfit.svg.192dpi.png")), - Act = () => StartOpeningStripper(args.User, (uid, component), true), - }; - args.Verbs.Add(verb); + if (!TryComp(strippable, out var inventory)) + return; + + var hasEnt = _inventorySystem.TryGetSlotEntity(strippable, args.Slot, out var held, inventory); + + if (userHands.ActiveHandEntity != null && !hasEnt) + StartStripInsertInventory((user, userHands), strippable.Owner, userHands.ActiveHandEntity.Value, args.Slot); + else if (userHands.ActiveHandEntity == null && hasEnt) + StartStripRemoveInventory(user, strippable.Owner, held!.Value, args.Slot); } - private void AddStripExamineVerb(EntityUid uid, StrippableComponent component, GetVerbsEvent args) + private void StripHand( + Entity user, + Entity target, + string handId, + StrippableComponent? targetStrippable) { - if (args.Hands == null || !args.CanAccess || !args.CanInteract || args.Target == args.User) + if (!Resolve(user, ref user.Comp) || + !Resolve(target, ref target.Comp) || + !Resolve(target, ref targetStrippable)) return; - if (!HasComp(args.User)) + if (!_handsSystem.TryGetHand(target.Owner, handId, out var handSlot)) return; - ExamineVerb verb = new() + // Is the target a handcuff? + if (TryComp(handSlot.HeldEntity, out var virtualItem) && + TryComp(target.Owner, out var cuffable) && + _cuffableSystem.GetAllCuffs(cuffable).Contains(virtualItem.BlockingEntity)) { - Text = Loc.GetString("strip-verb-get-data-text"), - Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/outfit.svg.192dpi.png")), - Act = () => StartOpeningStripper(args.User, (uid, component), true), - Category = VerbCategory.Examine, - }; + _cuffableSystem.TryUncuff(target.Owner, user, virtualItem.BlockingEntity, cuffable); + return; + } - args.Verbs.Add(verb); + if (user.Comp.ActiveHandEntity != null && handSlot.HeldEntity == null) + StartStripInsertHand(user, target, user.Comp.ActiveHandEntity.Value, handId, targetStrippable); + else if (user.Comp.ActiveHandEntity == null && handSlot.HeldEntity != null) + StartStripRemoveHand(user, target, handSlot.HeldEntity.Value, handId, targetStrippable); } - private void OnActivateInWorld(EntityUid uid, StrippableComponent component, ActivateInWorldEvent args) + private void OnStripEnsnareMessage(EntityUid uid, EnsnareableComponent component, StrippingEnsnareButtonPressed args) { - if (args.Target == args.User) + if (args.Session.AttachedEntity is not { Valid: true } user) return; - if (!HasComp(args.User)) - return; + foreach (var entity in component.Container.ContainedEntities) + { + if (!TryComp(entity, out var ensnaring)) + continue; - StartOpeningStripper(args.User, (uid, component)); + _ensnaringSystem.TryFree(uid, user, entity, ensnaring); + return; + } } /// - /// Places item in user's active hand to an inventory slot. + /// Checks whether the item is in a user's active hand and whether it can be inserted into the inventory slot. /// - private async void PlaceActiveHandItemInInventory( - EntityUid user, + private bool CanStripInsertInventory( + Entity user, EntityUid target, EntityUid held, - string slot, - StrippableComponent component) + string slot) { - var userHands = Comp(user); + if (!Resolve(user, ref user.Comp)) + return false; + + if (user.Comp.ActiveHand == null) + return false; + + if (user.Comp.ActiveHandEntity == null) + return false; + + if (user.Comp.ActiveHandEntity != held) + return false; + + if (!_handsSystem.CanDropHeld(user, user.Comp.ActiveHand)) + { + _popupSystem.PopupCursor(Loc.GetString("strippable-component-cannot-drop"), user); + return false; + } + + if (_inventorySystem.TryGetSlotEntity(target, slot, out _)) + { + _popupSystem.PopupCursor(Loc.GetString("strippable-component-item-slot-occupied", ("owner", target)), user); + return false; + } - bool Check() + if (!_inventorySystem.CanEquip(user, target, held, slot, out _)) { - if (userHands.ActiveHandEntity != held) - return false; - - if (!_handsSystem.CanDropHeld(user, userHands.ActiveHand!)) - { - _popup.PopupCursor(Loc.GetString("strippable-component-cannot-drop"), user); - return false; - } - - if (_inventorySystem.TryGetSlotEntity(target, slot, out _)) - { - _popup.PopupCursor(Loc.GetString("strippable-component-item-slot-occupied",("owner", target)), user); - return false; - } - - if (!_inventorySystem.CanEquip(user, target, held, slot, out _)) - { - _popup.PopupCursor(Loc.GetString("strippable-component-cannot-equip-message",("owner", target)), user); - return false; - } - - return true; + _popupSystem.PopupCursor(Loc.GetString("strippable-component-cannot-equip-message", ("owner", target)), user); + return false; } + return true; + } + + /// + /// Begins a DoAfter to insert the item in the user's active hand into the inventory slot. + /// + private void StartStripInsertInventory( + Entity user, + EntityUid target, + EntityUid held, + string slot) + { + if (!Resolve(user, ref user.Comp)) + return; + + if (!CanStripInsertInventory(user, target, held, slot)) + return; + if (!_inventorySystem.TryGetSlot(target, slot, out var slotDef)) { Log.Error($"{ToPrettyString(user)} attempted to place an item in a non-existent inventory slot ({slot}) on {ToPrettyString(target)}"); return; } - var userEv = new BeforeStripEvent(slotDef.StripTime); - RaiseLocalEvent(user, userEv); - var ev = new BeforeGettingStrippedEvent(userEv.Time, userEv.Stealth); - RaiseLocalEvent(target, ev); + var (time, stealth) = GetStripTimeModifiers(user, target, slotDef.StripTime); + + if (!stealth) + _popupSystem.PopupEntity(Loc.GetString("strippable-component-alert-owner-insert", ("user", Identity.Entity(user, EntityManager)), ("item", user.Comp.ActiveHandEntity!.Value)), target, target, PopupType.Large); + + var prefix = stealth ? "stealthily " : ""; + _adminLogger.Add(LogType.Stripping, LogImpact.Low, $"{ToPrettyString(user):actor} is trying to {prefix}place the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s {slot} slot"); - var doAfterArgs = new DoAfterArgs(EntityManager, user, ev.Time, new AwaitedDoAfterEvent(), null, target: target, used: held) + var doAfterArgs = new DoAfterArgs(EntityManager, user, time, new StrippableDoAfterEvent(true, true, slot), user, target, held) { - ExtraCheck = Check, - Hidden = ev.Stealth, + Hidden = stealth, AttemptFrequency = AttemptFrequency.EveryTick, BreakOnDamage = true, BreakOnTargetMove = true, BreakOnUserMove = true, NeedHand = true, - DuplicateCondition = DuplicateConditions.SameTool // Block any other DoAfters featuring this same entity. + DuplicateCondition = DuplicateConditions.SameTool }; - if (!ev.Stealth && Check() && userHands.ActiveHandEntity != null) - { - var message = Loc.GetString("strippable-component-alert-owner-insert", - ("user", Identity.Entity(user, EntityManager)), ("item", userHands.ActiveHandEntity)); - _popup.PopupEntity(message, target, target, PopupType.Large); - } + _doAfterSystem.TryStartDoAfter(doAfterArgs); + } - var prefix = ev.Stealth ? "stealthily " : ""; - _adminLogger.Add(LogType.Stripping, LogImpact.Low, $"{ToPrettyString(user):actor} is trying to {prefix}place the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s {slot} slot"); + /// + /// Inserts the item in the user's active hand into the inventory slot. + /// + private void StripInsertInventory( + Entity user, + EntityUid target, + EntityUid held, + string slot) + { + if (!Resolve(user, ref user.Comp)) + return; - var result = await _doAfter.WaitDoAfter(doAfterArgs); - if (result != DoAfterStatus.Finished) + if (!CanStripInsertInventory(user, target, held, slot)) return; - DebugTools.Assert(userHands.ActiveHand?.HeldEntity == held); + if (!_handsSystem.TryDrop(user, handsComp: user.Comp)) + return; + + _inventorySystem.TryEquip(user, target, held, slot); + _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has placed the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s {slot} slot"); + } - if (_handsSystem.TryDrop(user, handsComp: userHands)) + /// + /// Checks whether the item can be removed from the target's inventory. + /// + private bool CanStripRemoveInventory( + EntityUid user, + EntityUid target, + EntityUid item, + string slot) + { + if (!_inventorySystem.TryGetSlotEntity(target, slot, out var slotItem)) { - _inventorySystem.TryEquip(user, target, held, slot); + _popupSystem.PopupCursor(Loc.GetString("strippable-component-item-slot-free-message", ("owner", target)), user); + return false; + } - _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has placed the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s {slot} slot"); + if (slotItem != item) + return false; + + if (!_inventorySystem.CanUnequip(user, target, slot, out var reason)) + { + _popupSystem.PopupCursor(Loc.GetString(reason), user); + return false; } + + return true; } /// - /// Places item in user's active hand in one of the entity's hands. + /// Begins a DoAfter to remove the item from the target's inventory and insert it in the user's active hand. /// - private async void PlaceActiveHandItemInHands( + private void StartStripRemoveInventory( EntityUid user, EntityUid target, - EntityUid held, - string handName, - StrippableComponent component) + EntityUid item, + string slot) { - var hands = Comp(target); - var userHands = Comp(user); + if (!CanStripRemoveInventory(user, target, item, slot)) + return; + + if (!_inventorySystem.TryGetSlot(target, slot, out var slotDef)) + { + Log.Error($"{ToPrettyString(user)} attempted to take an item from a non-existent inventory slot ({slot}) on {ToPrettyString(target)}"); + return; + } + + var (time, stealth) = GetStripTimeModifiers(user, target, slotDef.StripTime); - bool Check() + if (!stealth) { - if (userHands.ActiveHandEntity != held) - return false; - - if (!_handsSystem.CanDropHeld(user, userHands.ActiveHand!)) - { - _popup.PopupCursor(Loc.GetString("strippable-component-cannot-drop"), user); - return false; - } - - if (!_handsSystem.TryGetHand(target, handName, out var hand, hands) - || !_handsSystem.CanPickupToHand(target, userHands.ActiveHandEntity.Value, hand, checkActionBlocker: false, hands)) - { - _popup.PopupCursor(Loc.GetString("strippable-component-cannot-put-message",("owner", target)), user); - return false; - } - - return true; + if (slotDef.StripHidden) + _popupSystem.PopupEntity(Loc.GetString("strippable-component-alert-owner-hidden", ("slot", slot)), target, target, PopupType.Large); + else + _popupSystem.PopupEntity(Loc.GetString("strippable-component-alert-owner", ("user", Identity.Entity(user, EntityManager)), ("item", item)), target, target, PopupType.Large); } - var userEv = new BeforeStripEvent(component.HandStripDelay); - RaiseLocalEvent(user, userEv); - var ev = new BeforeGettingStrippedEvent(userEv.Time, userEv.Stealth); - RaiseLocalEvent(target, ev); + var prefix = stealth ? "stealthily " : ""; + _adminLogger.Add(LogType.Stripping, LogImpact.Low, $"{ToPrettyString(user):actor} is trying to {prefix}strip the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s {slot} slot"); - var doAfterArgs = new DoAfterArgs(EntityManager, user, ev.Time, new AwaitedDoAfterEvent(), null, target: target, used: held) + var doAfterArgs = new DoAfterArgs(EntityManager, user, time, new StrippableDoAfterEvent(false, true, slot), user, target, item) { - ExtraCheck = Check, - Hidden = ev.Stealth, + Hidden = stealth, AttemptFrequency = AttemptFrequency.EveryTick, BreakOnDamage = true, BreakOnTargetMove = true, BreakOnUserMove = true, NeedHand = true, + BreakOnHandChange = false, // Allow simultaneously removing multiple items. DuplicateCondition = DuplicateConditions.SameTool }; - var prefix = ev.Stealth ? "stealthily " : ""; - _adminLogger.Add(LogType.Stripping, LogImpact.Low, $"{ToPrettyString(user):actor} is trying to {prefix}place the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s hands"); - - var result = await _doAfter.WaitDoAfter(doAfterArgs); - if (result != DoAfterStatus.Finished) return; - - _handsSystem.TryDrop(user, checkActionBlocker: false, handsComp: userHands); - _handsSystem.TryPickup(target, held, handName, checkActionBlocker: false, animateUser: !ev.Stealth, animate: !ev.Stealth, handsComp: hands); - _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has placed the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s hands"); - // hand update will trigger strippable update + _doAfterSystem.TryStartDoAfter(doAfterArgs); } /// - /// Takes an item from the inventory and places it in the user's active hand. + /// Removes the item from the target's inventory and inserts it in the user's active hand. /// - private async void TakeItemFromInventory( + private void StripRemoveInventory( EntityUid user, EntityUid target, EntityUid item, string slot, - Entity strippable) + bool stealth) + { + if (!CanStripRemoveInventory(user, target, item, slot)) + return; + + if (!_inventorySystem.TryUnequip(user, target, slot)) + return; + + RaiseLocalEvent(item, new DroppedEvent(user), true); // Gas tank internals etc. + + _handsSystem.PickupOrDrop(user, item, animateUser: stealth, animate: stealth); + _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has stripped the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s {slot} slot"); + } + + /// + /// Checks whether the item in the user's active hand can be inserted into one of the target's hands. + /// + private bool CanStripInsertHand( + Entity user, + Entity target, + EntityUid held, + string handName) { - bool Check() + if (!Resolve(user, ref user.Comp) || + !Resolve(target, ref target.Comp)) + return false; + + if (user.Comp.ActiveHand == null) + return false; + + if (user.Comp.ActiveHandEntity == null) + return false; + + if (user.Comp.ActiveHandEntity != held) + return false; + + if (!_handsSystem.CanDropHeld(user, user.Comp.ActiveHand)) { - if (!_inventorySystem.TryGetSlotEntity(target, slot, out var ent) && ent == item) - { - _popup.PopupCursor(Loc.GetString("strippable-component-item-slot-free-message", ("owner", target)), user); - return false; - } - - if (!_inventorySystem.CanUnequip(user, target, slot, out var reason)) - { - _popup.PopupCursor(Loc.GetString(reason), user); - return false; - } - - return true; + _popupSystem.PopupCursor(Loc.GetString("strippable-component-cannot-drop"), user); + return false; } - if (!_inventorySystem.TryGetSlot(target, slot, out var slotDef)) + if (!_handsSystem.TryGetHand(target, handName, out var handSlot, target.Comp) || + !_handsSystem.CanPickupToHand(target, user.Comp.ActiveHandEntity.Value, handSlot, checkActionBlocker: false, target.Comp)) { - Log.Error($"{ToPrettyString(user)} attempted to take an item from a non-existent inventory slot ({slot}) on {ToPrettyString(target)}"); - return; + _popupSystem.PopupCursor(Loc.GetString("strippable-component-cannot-put-message", ("owner", target)), user); + return false; } - var userEv = new BeforeStripEvent(slotDef.StripTime); - RaiseLocalEvent(user, userEv); - var ev = new BeforeGettingStrippedEvent(userEv.Time, userEv.Stealth); - RaiseLocalEvent(target, ev); + return true; + } + + /// + /// Begins a DoAfter to insert the item in the user's active hand into one of the target's hands. + /// + private void StartStripInsertHand( + Entity user, + Entity target, + EntityUid held, + string handName, + StrippableComponent? targetStrippable = null) + { + if (!Resolve(user, ref user.Comp) || + !Resolve(target, ref target.Comp) || + !Resolve(target, ref targetStrippable)) + return; + + if (!CanStripInsertHand(user, target, held, handName)) + return; + + var (time, stealth) = GetStripTimeModifiers(user, target, targetStrippable.HandStripDelay); - var doAfterArgs = new DoAfterArgs(EntityManager, user, ev.Time, new AwaitedDoAfterEvent(), null, target: target, used: item) + var prefix = stealth ? "stealthily " : ""; + _adminLogger.Add(LogType.Stripping, LogImpact.Low, $"{ToPrettyString(user):actor} is trying to {prefix}place the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s hands"); + + var doAfterArgs = new DoAfterArgs(EntityManager, user, time, new StrippableDoAfterEvent(true, false, handName), user, target, held) { - ExtraCheck = Check, - Hidden = ev.Stealth, + Hidden = stealth, AttemptFrequency = AttemptFrequency.EveryTick, BreakOnDamage = true, BreakOnTargetMove = true, BreakOnUserMove = true, NeedHand = true, - BreakOnHandChange = false, // allow simultaneously removing multiple items. DuplicateCondition = DuplicateConditions.SameTool }; - if (!ev.Stealth && Check()) - { - if (slotDef.StripHidden) - { - _popup.PopupEntity(Loc.GetString("strippable-component-alert-owner-hidden", ("slot", slot)), target, - target, PopupType.Large); - } - else if (_inventorySystem.TryGetSlotEntity(strippable, slot, out var slotItem)) - { - _popup.PopupEntity(Loc.GetString("strippable-component-alert-owner", ("user", Identity.Entity(user, EntityManager)), ("item", slotItem)), target, - target, PopupType.Large); - } - } - - var prefix = ev.Stealth ? "stealthily " : ""; - _adminLogger.Add(LogType.Stripping, LogImpact.Low, $"{ToPrettyString(user):actor} is trying to {prefix}strip the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s {slot} slot"); + _doAfterSystem.TryStartDoAfter(doAfterArgs); + } - var result = await _doAfter.WaitDoAfter(doAfterArgs); - if (result != DoAfterStatus.Finished) + /// + /// Places the item in the user's active hand into one of the target's hands. + /// + private void StripInsertHand( + Entity user, + Entity target, + EntityUid held, + string handName, + bool stealth) + { + if (!Resolve(user, ref user.Comp) || + !Resolve(target, ref target.Comp)) return; - if (!_inventorySystem.TryUnequip(user, strippable, slot)) + if (!CanStripInsertHand(user, target, held, handName)) return; - // Raise a dropped event, so that things like gas tank internals properly deactivate when stripping - RaiseLocalEvent(item, new DroppedEvent(user), true); - - _handsSystem.PickupOrDrop(user, item, animateUser: !ev.Stealth, animate: !ev.Stealth); - _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has stripped the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s {slot} slot"); + _handsSystem.TryDrop(user, checkActionBlocker: false, handsComp: user.Comp); + _handsSystem.TryPickup(target, held, handName, checkActionBlocker: false, animateUser: stealth, animate: stealth, handsComp: target.Comp); + _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has placed the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s hands"); + // Hand update will trigger strippable update. } /// - /// Takes an item from a hand and places it in the user's active hand. + /// Checks whether the item is in the target's hand and whether it can be dropped. /// - private async void TakeItemFromHands(EntityUid user, EntityUid target, EntityUid item, string handName, Entity strippable) + private bool CanStripRemoveHand( + EntityUid user, + Entity target, + EntityUid item, + string handName) { - var hands = Comp(target); - var userHands = Comp(user); + if (!Resolve(target, ref target.Comp)) + return false; - bool Check() + if (!_handsSystem.TryGetHand(target, handName, out var handSlot, target.Comp)) { - if (!_handsSystem.TryGetHand(target, handName, out var hand, hands) || hand.HeldEntity != item) - { - _popup.PopupCursor(Loc.GetString("strippable-component-item-slot-free-message",("owner", target)), user); - return false; - } - - if (HasComp(hand.HeldEntity)) - return false; - - if (!_handsSystem.CanDropHeld(target, hand, false)) - { - _popup.PopupCursor(Loc.GetString("strippable-component-cannot-drop-message",("owner", target)), user); - return false; - } - - return true; + _popupSystem.PopupCursor(Loc.GetString("strippable-component-item-slot-free-message", ("owner", target)), user); + return false; } - var userEv = new BeforeStripEvent(strippable.Comp.HandStripDelay); - RaiseLocalEvent(user, userEv); - var ev = new BeforeGettingStrippedEvent(userEv.Time, userEv.Stealth); - RaiseLocalEvent(target, ev); + if (HasComp(handSlot.HeldEntity)) + return false; + + if (handSlot.HeldEntity == null) + return false; - var doAfterArgs = new DoAfterArgs(EntityManager, user, ev.Time, new AwaitedDoAfterEvent(), null, target: target, used: item) + if (handSlot.HeldEntity != item) + return false; + + if (!_handsSystem.CanDropHeld(target, handSlot, false)) { - ExtraCheck = Check, - Hidden = ev.Stealth, + _popupSystem.PopupCursor(Loc.GetString("strippable-component-cannot-drop-message", ("owner", target)), user); + return false; + } + + return true; + } + + /// + /// Begins a DoAfter to remove the item from the target's hand and insert it in the user's active hand. + /// + private void StartStripRemoveHand( + Entity user, + Entity target, + EntityUid item, + string handName, + StrippableComponent? targetStrippable = null) + { + if (!Resolve(user, ref user.Comp) || + !Resolve(target, ref target.Comp) || + !Resolve(target, ref targetStrippable)) + return; + + if (!CanStripRemoveHand(user, target, item, handName)) + return; + + var (time, stealth) = GetStripTimeModifiers(user, target, targetStrippable.HandStripDelay); + + if (!stealth) + _popupSystem.PopupEntity(Loc.GetString("strippable-component-alert-owner", ("user", Identity.Entity(user, EntityManager)), ("item", item)), target, target); + + var prefix = stealth ? "stealthily " : ""; + _adminLogger.Add(LogType.Stripping, LogImpact.Low, $"{ToPrettyString(user):actor} is trying to {prefix}strip the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s hands"); + + var doAfterArgs = new DoAfterArgs(EntityManager, user, time, new StrippableDoAfterEvent(false, false, handName), user, target, item) + { + Hidden = stealth, AttemptFrequency = AttemptFrequency.EveryTick, BreakOnDamage = true, BreakOnTargetMove = true, BreakOnUserMove = true, NeedHand = true, - BreakOnHandChange = false, // allow simultaneously removing multiple items. + BreakOnHandChange = false, // Allow simultaneously removing multiple items. DuplicateCondition = DuplicateConditions.SameTool }; - if (!ev.Stealth && Check() && _handsSystem.TryGetHand(target, handName, out var handSlot, hands) && handSlot.HeldEntity != null) + _doAfterSystem.TryStartDoAfter(doAfterArgs); + } + + /// + /// Takes the item from the target's hand and inserts it in the user's active hand. + /// + private void StripRemoveHand( + Entity user, + Entity target, + EntityUid item, + string handName, + bool stealth) + { + if (!Resolve(user, ref user.Comp) || + !Resolve(target, ref target.Comp)) + return; + + if (!CanStripRemoveHand(user, target, item, handName)) + return; + + _handsSystem.TryDrop(target, item, checkActionBlocker: false, handsComp: target.Comp); + _handsSystem.PickupOrDrop(user, item, animateUser: stealth, animate: stealth, handsComp: user.Comp); + _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has stripped the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s hands"); + + // Hand update will trigger strippable update. + } + + private void OnStrippableDoAfterRunning(Entity entity, ref DoAfterAttemptEvent ev) + { + var args = ev.DoAfter.Args; + + DebugTools.Assert(entity.Owner == args.User); + DebugTools.Assert(args.Target != null); + DebugTools.Assert(args.Used != null); + DebugTools.Assert(ev.Event.SlotOrHandName != null); + + if (ev.Event.InventoryOrHand) { - _popup.PopupEntity( - Loc.GetString("strippable-component-alert-owner", - ("user", Identity.Entity(user, EntityManager)), ("item", item)), - strippable.Owner, - strippable.Owner); + if ( ev.Event.InsertOrRemove && !CanStripInsertInventory((entity.Owner, entity.Comp), args.Target.Value, args.Used.Value, ev.Event.SlotOrHandName) || + !ev.Event.InsertOrRemove && !CanStripRemoveInventory(entity.Owner, args.Target.Value, args.Used.Value, ev.Event.SlotOrHandName)) + ev.Cancel(); } + else + { + if ( ev.Event.InsertOrRemove && !CanStripInsertHand((entity.Owner, entity.Comp), args.Target.Value, args.Used.Value, ev.Event.SlotOrHandName) || + !ev.Event.InsertOrRemove && !CanStripRemoveHand(entity.Owner, args.Target.Value, args.Used.Value, ev.Event.SlotOrHandName)) + ev.Cancel(); + } + } - var prefix = ev.Stealth ? "stealthily " : ""; - _adminLogger.Add(LogType.Stripping, LogImpact.Low, - $"{ToPrettyString(user):actor} is trying to {prefix}strip the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s hands"); - - var result = await _doAfter.WaitDoAfter(doAfterArgs); - if (result != DoAfterStatus.Finished) + private void OnStrippableDoAfterFinished(Entity entity, ref StrippableDoAfterEvent ev) + { + if (ev.Cancelled) return; - _handsSystem.TryDrop(target, item, checkActionBlocker: false, handsComp: hands); - _handsSystem.PickupOrDrop(user, item, animateUser: !ev.Stealth, animate: !ev.Stealth, handsComp: userHands); - // hand update will trigger strippable update - _adminLogger.Add(LogType.Stripping, LogImpact.Medium, - $"{ToPrettyString(user):actor} has stripped the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s hands"); + DebugTools.Assert(entity.Owner == ev.User); + DebugTools.Assert(ev.Target != null); + DebugTools.Assert(ev.Used != null); + DebugTools.Assert(ev.SlotOrHandName != null); + + if (ev.InventoryOrHand) + { + if (ev.InsertOrRemove) + StripInsertInventory((entity.Owner, entity.Comp), ev.Target.Value, ev.Used.Value, ev.SlotOrHandName); + else StripRemoveInventory(entity.Owner, ev.Target.Value, ev.Used.Value, ev.SlotOrHandName, ev.Args.Hidden); + } + else + { + if (ev.InsertOrRemove) + StripInsertHand((entity.Owner, entity.Comp), ev.Target.Value, ev.Used.Value, ev.SlotOrHandName, ev.Args.Hidden); + else StripRemoveHand((entity.Owner, entity.Comp), ev.Target.Value, ev.Used.Value, ev.SlotOrHandName, ev.Args.Hidden); + } } } } diff --git a/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs b/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs index f189db005bc..976682c9903 100644 --- a/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs +++ b/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs @@ -62,6 +62,11 @@ private void QuickEquip( { foreach (var slotDef in userEnt.Comp1.Slots) { + // Do not attempt to quick-equip clothing in pocket slots. + // We should probably add a special flag to SlotDefinition to skip quick equip if more similar slots get added. + if (slotDef.SlotFlags.HasFlag(SlotFlags.POCKET)) + continue; + if (!_invSystem.CanEquip(userEnt, toEquipEnt, slotDef.Name, out _, slotDef, userEnt, toEquipEnt)) continue; diff --git a/Content.Shared/Clothing/EntitySystems/ToggleableClothingSystem.cs b/Content.Shared/Clothing/EntitySystems/ToggleableClothingSystem.cs index 0138de7a98f..22a1d1a8f52 100644 --- a/Content.Shared/Clothing/EntitySystems/ToggleableClothingSystem.cs +++ b/Content.Shared/Clothing/EntitySystems/ToggleableClothingSystem.cs @@ -95,7 +95,7 @@ private void StartDoAfter(EntityUid user, EntityUid item, EntityUid wearer, Togg if (component.StripDelay == null) return; - var (time, stealth) = _strippable.GetStripTimeModifiers(user, wearer, (float) component.StripDelay.Value.TotalSeconds); + var (time, stealth) = _strippable.GetStripTimeModifiers(user, wearer, component.StripDelay.Value); var args = new DoAfterArgs(EntityManager, user, time, new ToggleClothingDoAfterEvent(), item, wearer, item) { diff --git a/Content.Shared/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiState.cs b/Content.Shared/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiState.cs deleted file mode 100644 index dd820f1a0b3..00000000000 --- a/Content.Shared/DeltaV/CartridgeLoader/Cartridges/CrimeAssistUiState.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Content.Shared.CartridgeLoader; -using Robust.Shared.Serialization; - -namespace Content.Shared.DeltaV.CartridgeLoader.Cartridges; - -[Serializable, NetSerializable] -public sealed class CrimeAssistUiState : BoundUserInterfaceState -{ - public CrimeAssistUiState() - { } -} - -[Serializable, NetSerializable] -public sealed class CrimeAssistSyncMessageEvent : CartridgeMessageEvent -{ - public CrimeAssistSyncMessageEvent() - { } -} diff --git a/Content.Shared/DeltaV/CartridgeLoader/Cartridges/SecWatchUiState.cs b/Content.Shared/DeltaV/CartridgeLoader/Cartridges/SecWatchUiState.cs new file mode 100644 index 00000000000..068b54a6ffb --- /dev/null +++ b/Content.Shared/DeltaV/CartridgeLoader/Cartridges/SecWatchUiState.cs @@ -0,0 +1,24 @@ +using Content.Shared.Security; +using Robust.Shared.Serialization; + +namespace Content.Shared.CartridgeLoader.Cartridges; + +/// +/// Show a list of wanted and suspected people from criminal records. +/// +[Serializable, NetSerializable] +public sealed class SecWatchUiState : BoundUserInterfaceState +{ + public readonly List Entries; + + public SecWatchUiState(List entries) + { + Entries = entries; + } +} + +/// +/// Entry for a person who is wanted or suspected. +/// +[Serializable, NetSerializable] +public record struct SecWatchEntry(string Name, string Job, SecurityStatus Status, string? Reason); diff --git a/Content.Shared/Inventory/InventorySystem.Equip.cs b/Content.Shared/Inventory/InventorySystem.Equip.cs index 24006b0c9f9..7bdd17ee6fa 100644 --- a/Content.Shared/Inventory/InventorySystem.Equip.cs +++ b/Content.Shared/Inventory/InventorySystem.Equip.cs @@ -176,7 +176,7 @@ public bool TryEquip(EntityUid actor, EntityUid target, EntityUid itemUid, strin }; _doAfter.TryStartDoAfter(args); - return false; + return true; // Changed to return true even if the item wasn't equipped instantly } if (!_containerSystem.Insert(itemUid, slotContainer)) diff --git a/Content.Shared/Inventory/InventoryTemplatePrototype.cs b/Content.Shared/Inventory/InventoryTemplatePrototype.cs index a4779699629..585f80d4ce9 100644 --- a/Content.Shared/Inventory/InventoryTemplatePrototype.cs +++ b/Content.Shared/Inventory/InventoryTemplatePrototype.cs @@ -20,7 +20,7 @@ public sealed partial class SlotDefinition [DataField("slotFlags")] public SlotFlags SlotFlags { get; private set; } = SlotFlags.PREVENTEQUIP; [DataField("showInWindow")] public bool ShowInWindow { get; private set; } = true; [DataField("slotGroup")] public string SlotGroup { get; private set; } = "Default"; - [DataField("stripTime")] public float StripTime { get; private set; } = 4f; + [DataField("stripTime")] public TimeSpan StripTime { get; private set; } = TimeSpan.FromSeconds(4f); [DataField("uiWindowPos", required: true)] public Vector2i UIWindowPosition { get; private set; } diff --git a/Content.Shared/Strip/Components/StrippableComponent.cs b/Content.Shared/Strip/Components/StrippableComponent.cs index fbf99992e3c..4faca4d8f21 100644 --- a/Content.Shared/Strip/Components/StrippableComponent.cs +++ b/Content.Shared/Strip/Components/StrippableComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared.DoAfter; using Content.Shared.Inventory; using Robust.Shared.GameStates; using Robust.Shared.Serialization; @@ -8,10 +9,10 @@ namespace Content.Shared.Strip.Components public sealed partial class StrippableComponent : Component { /// - /// The strip delay for hands. + /// The strip delay for hands. /// [ViewVariables(VVAccess.ReadWrite), DataField("handDelay")] - public float HandStripDelay = 4f; + public TimeSpan HandStripDelay = TimeSpan.FromSeconds(4f); } [NetSerializable, Serializable] @@ -21,63 +22,63 @@ public enum StrippingUiKey : byte } [NetSerializable, Serializable] - public sealed class StrippingSlotButtonPressed : BoundUserInterfaceMessage + public sealed class StrippingSlotButtonPressed(string slot, bool isHand) : BoundUserInterfaceMessage { - public readonly string Slot; - - public readonly bool IsHand; - - public StrippingSlotButtonPressed(string slot, bool isHand) - { - Slot = slot; - IsHand = isHand; - } + public readonly string Slot = slot; + public readonly bool IsHand = isHand; } [NetSerializable, Serializable] - public sealed class StrippingEnsnareButtonPressed : BoundUserInterfaceMessage - { - public StrippingEnsnareButtonPressed() - { - } - } + public sealed class StrippingEnsnareButtonPressed : BoundUserInterfaceMessage; - public abstract class BaseBeforeStripEvent : EntityEventArgs, IInventoryRelayEvent + [ByRefEvent] + public abstract class BaseBeforeStripEvent(TimeSpan initialTime, bool stealth = false) : EntityEventArgs, IInventoryRelayEvent { - public readonly float InitialTime; - public float Time => MathF.Max(InitialTime * Multiplier + Additive, 0f); - public float Additive = 0; + public readonly TimeSpan InitialTime = initialTime; public float Multiplier = 1f; - public bool Stealth; + public TimeSpan Additive = TimeSpan.Zero; + public bool Stealth = stealth; - public SlotFlags TargetSlots { get; } = SlotFlags.GLOVES; + public TimeSpan Time => TimeSpan.FromSeconds(MathF.Max(InitialTime.Seconds * Multiplier + Additive.Seconds, 0f)); - public BaseBeforeStripEvent(float initialTime, bool stealth = false) - { - InitialTime = initialTime; - Stealth = stealth; - } + public SlotFlags TargetSlots { get; } = SlotFlags.GLOVES; } /// - /// Used to modify strip times. Raised directed at the user. + /// Used to modify strip times. Raised directed at the user. /// /// - /// This is also used by some stripping related interactions, i.e., interactions with items that are currently equipped by another player. + /// This is also used by some stripping related interactions, i.e., interactions with items that are currently equipped by another player. /// - public sealed class BeforeStripEvent : BaseBeforeStripEvent - { - public BeforeStripEvent(float initialTime, bool stealth = false) : base(initialTime, stealth) { } - } + [ByRefEvent] + public sealed class BeforeStripEvent(TimeSpan initialTime, bool stealth = false) : BaseBeforeStripEvent(initialTime, stealth); /// - /// Used to modify strip times. Raised directed at the target. + /// Used to modify strip times. Raised directed at the target. /// /// - /// This is also used by some stripping related interactions, i.e., interactions with items that are currently equipped by another player. + /// This is also used by some stripping related interactions, i.e., interactions with items that are currently equipped by another player. /// - public sealed class BeforeGettingStrippedEvent : BaseBeforeStripEvent + [ByRefEvent] + public sealed class BeforeGettingStrippedEvent(TimeSpan initialTime, bool stealth = false) : BaseBeforeStripEvent(initialTime, stealth); + + /// + /// Organizes the behavior of DoAfters for . + /// + [Serializable, NetSerializable] + public sealed partial class StrippableDoAfterEvent : DoAfterEvent { - public BeforeGettingStrippedEvent(float initialTime, bool stealth = false) : base(initialTime, stealth) { } + public readonly bool InsertOrRemove; + public readonly bool InventoryOrHand; + public readonly string SlotOrHandName; + + public StrippableDoAfterEvent(bool insertOrRemove, bool inventoryOrHand, string slotOrHandName) + { + InsertOrRemove = insertOrRemove; + InventoryOrHand = inventoryOrHand; + SlotOrHandName = slotOrHandName; + } + + public override DoAfterEvent Clone() => this; } } diff --git a/Content.Shared/Strip/Components/ThievingComponent.cs b/Content.Shared/Strip/Components/ThievingComponent.cs index 83679f132c4..a851dd5ef63 100644 --- a/Content.Shared/Strip/Components/ThievingComponent.cs +++ b/Content.Shared/Strip/Components/ThievingComponent.cs @@ -11,7 +11,7 @@ public sealed partial class ThievingComponent : Component ///
[ViewVariables(VVAccess.ReadWrite)] [DataField("stripTimeReduction")] - public float StripTimeReduction = 0.5f; + public TimeSpan StripTimeReduction = TimeSpan.FromSeconds(0.5f); /// /// Should it notify the user if they're stripping a pocket? diff --git a/Content.Shared/Strip/SharedStrippableSystem.cs b/Content.Shared/Strip/SharedStrippableSystem.cs index a698ae5035a..7afd4f245a1 100644 --- a/Content.Shared/Strip/SharedStrippableSystem.cs +++ b/Content.Shared/Strip/SharedStrippableSystem.cs @@ -14,12 +14,12 @@ public override void Initialize() SubscribeLocalEvent(OnDragDrop); } - public (float Time, bool Stealth) GetStripTimeModifiers(EntityUid user, EntityUid target, float initialTime) + public (TimeSpan Time, bool Stealth) GetStripTimeModifiers(EntityUid user, EntityUid target, TimeSpan initialTime) { var userEv = new BeforeStripEvent(initialTime); - RaiseLocalEvent(user, userEv); + RaiseLocalEvent(user, ref userEv); var ev = new BeforeGettingStrippedEvent(userEv.Time, userEv.Stealth); - RaiseLocalEvent(target, ev); + RaiseLocalEvent(target, ref ev); return (ev.Time, ev.Stealth); } diff --git a/Content.Shared/Strip/ThievingSystem.cs b/Content.Shared/Strip/ThievingSystem.cs index 0ef4b66571f..2b3d3b38a00 100644 --- a/Content.Shared/Strip/ThievingSystem.cs +++ b/Content.Shared/Strip/ThievingSystem.cs @@ -1,4 +1,5 @@ using Content.Shared.Inventory; +using Content.Shared.Strip; using Content.Shared.Strip.Components; namespace Content.Shared.Strip; diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs index cadb0a4b215..ff8b102bb57 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs @@ -443,7 +443,7 @@ protected void EjectCartridge( { Angle ejectAngle = angle.Value; ejectAngle += 3.7f; // 212 degrees; casings should eject slightly to the right and behind of a gun - ThrowingSystem.TryThrow(entity, ejectAngle.ToVec().Normalized() / 100, 5f); + ThrowingSystem.TryThrow(entity, ejectAngle.ToVec(), 625f); } if (playSound && TryComp(entity, out var cartridge)) { diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 3aea1324fe4..c4056561c9c 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -4251,3 +4251,37 @@ Entries: message: 'Height and Width sliders have been added to character creation. ' id: 6131 time: '2024-06-27T17:46:51.0000000+00:00' +- author: Mnemotechnician + changes: + - type: Add + message: Most items now take time to equip and unequip, especially space suits. + id: 6132 + time: '2024-06-30T18:22:28.0000000+00:00' +- author: VMSolidus + changes: + - type: Fix + message: >- + Spent bullet casings now fly away from a shooter in a cinematic manner, + rather than fall at their feet. + id: 6133 + time: '2024-07-01T22:37:29.0000000+00:00' +- author: WarMechanic + changes: + - type: Fix + message: Fixed loadouts becoming uneditable after spending all your points + id: 6134 + time: '2024-07-02T07:18:27.0000000+00:00' +- author: deltanedas + changes: + - type: Add + message: >- + Security can find the new SecWatch™ app in their PDAs to see current + suspects and wanted criminals. + id: 6135 + time: '2024-07-02T08:01:36.0000000+00:00' +- author: Mnemotechnician + changes: + - type: Fix + message: Equipping clothing using the Z key works correctly again. + id: 6136 + time: '2024-07-03T19:48:29.0000000+00:00' diff --git a/Resources/Credits/GitHub.txt b/Resources/Credits/GitHub.txt index b5381a4ce29..84796a94662 100644 --- a/Resources/Credits/GitHub.txt +++ b/Resources/Credits/GitHub.txt @@ -1 +1 @@ -0x6273, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 4dplanner, 612git, 778b, Ablankmann, Acruid, actioninja, adamsong, Admiral-Obvious-001, Adrian16199, Aerocrux, Aexxie, africalimedrop, Agoichi, Ahion, AJCM-git, AjexRose, Alekshhh, AlexMorgan3817, AlmondFlour, AlphaQwerty, Altoids1, amylizzle, ancientpower, ArchPigeon, Arendian, arimah, Arteben, AruMoon, as334, AsikKEsel, asperger-sind, aspiringLich, avghdev, AzzyIsNotHere, BananaFlambe, BasedUser, BGare, BingoJohnson-zz, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, Boaz1111, BobdaBiscuit, brainfood1183, Brandon-Huu, Bribrooo, Bright0, brndd, BubblegumBlue, BYONDFuckery, c4llv07e, CaasGit, CakeQ, CaptainSqrBeard, Carbonhell, Carolyn3114, casperr04, CatTheSystem, Centronias, chairbender, Charlese2, Cheackraze, cheesePizza2, Chief-Engineer, chromiumboy, Chronophylos, clement-or, Clyybber, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, coolmankid12345, corentt, crazybrain23, creadth, CrigCrag, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, Daemon, daerSeebaer, dahnte, dakamakat, dakimasu, DamianX, DangerRevolution, daniel-cr, Darkenson, DawBla, dch-GH, Deahaka, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, deepdarkdepths, Delete69, deltanedas, DeltaV-Bot, DerbyX, DoctorBeard, DogZeroX, dontbetank, Doru991, DoubleRiceEddiedd, DrMelon, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, Dutch-VanDerLinde, Easypoller, eclips_e, EdenTheLiznerd, EEASAS, Efruit, ElectroSR, elthundercloud, Emisse, EmoGarbage404, Endecc, enumerate0, eoineoineoin, ERORR404V1, Errant-4, estacaoespacialpirata, exincore, exp111, Fahasor, FairlySadPanda, ficcialfaint, Fildrance, FillerVK, Fishfish458, Flareguy, FluffiestFloof, FluidRock, FoLoKe, fooberticus, Fortune117, FoxxoTrystan, freeman2651, Fromoriss, FungiFellow, GalacticChimp, gbasood, Geekyhobo, Genkail, Git-Nivrak, github-actions[bot], gituhabu, GNF54, Golinth, GoodWheatley, Gotimanga, graevy, GreyMario, Guess-My-Name, gusxyz, h3half, Hanzdegloker, Hardly3D, harikattar, Hebiman, Henry12116, HerCoyote23, Hmeister-real, HoofedEar, hord-brayden, hubismal, Hugal31, Hyenh, iacore, IamVelcroboy, icekot8, igorsaux, ike709, Illiux, Ilya246, IlyaElDunaev, Injazz, Insineer, IntegerTempest, Interrobang01, IProduceWidgets, ItsMeThom, j-giebel, Jackal298, Jackrost, jamessimo, janekvap, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JoeHammad1844, joelhed, JohnGinnane, johnku1, joshepvodka, jproads, Jrpl, juliangiebel, JustArt1m, JustCone14, JustinTether, JustinTrotter, KaiShibaa, kalane15, kalanosh, KEEYNy, Keikiru, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, KingFroozy, kira-er, Kit0vras, KittenColony, Kmc2000, Ko4ergaPunk, komunre, koteq, Krunklehorn, Kukutis96513, kxvvv, Lamrr, LankLTE, lapatison, Leander-0, leonardo-dabepis, LetterN, Level10Cybermancer, lever1209, LightVillet, liltenhead, LittleBuilderJane, Lomcastar, LordCarve, LordEclipse, LovelyLophi, LudwigVonChesterfield, Lukasz825700516, lunarcomets, luringens, lvvova1, lzimann, lzk228, M3739, MACMAN2003, Macoron, MagnusCrowe, ManelNavola, matthst, Matz05, MehimoNemo, MeltedPixel, MemeProof, Menshin, Mervill, metalgearsloth, mhamsterr, MilenVolf, Minty642, Mirino97, mirrorcult, misandrie, MishaUnity, MisterMecky, Mith-randalf, Moneyl, Moomoobeef, moony, Morb0, Mr0maks, musicmanvr, Myakot, Myctai, N3X15, Nairodian, Naive817, namespace-Memory, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, nmajask, nok-ko, Nopey, notafet, notquitehadouken, noudoit, noverd, nuke-haus, NULL882, OCOtheOmega, OctoRocket, OldDanceJacket, onoira, Owai-Seek, pali6, Pangogie, patrikturi, PaulRitter, Peptide90, peptron1, Phantom-Lily, PHCodes, PixelTheKermit, PJB3005, Plykiya, pofitlo, pointer-to-null, PolterTzi, PoorMansDreams, potato1234x, ProfanedBane, PrPleGoo, ps3moira, Psychpsyo, psykzz, PuroSlavKing, quatre, QuietlyWhisper, qwerltaz, Radosvik, Radrark, Rainbeon, Rainfey, Rane, ravage123321, rbertoche, Redict, RedlineTriad, RednoWCirabrab, RemberBM, RemieRichards, RemTim, rene-descartes2021, RiceMar1244, RieBi, Rinkashikachi, Rockdtben, rolfero, rosieposieeee, Saakra, Samsterious, SaphireLattice, ScalyChimp, scrato, Scribbles0, Serkket, SethLafuente, ShadowCommander, Shadowtheprotogen546, SignalWalker, SimpleStation14, Simyon264, SirDragooon, Sirionaut, siyengar04, Skarletto, Skrauz, Skyedra, SlamBamActionman, slarticodefast, Slava0135, Snowni, snowsignal, SonicHDC, SoulSloth, SpaceManiac, SpeltIncorrectyl, spoogemonster, ssdaniel24, Stealthbomber16, stellar-novas, StrawberryMoses, SweptWasTaken, Szunti, TadJohnson00, takemysoult, TaralGit, Tayrtahn, tday93, TekuNut, TemporalOroboros, tentekal, tgrkzus, thatrandomcanadianguy, TheArturZh, theashtronaut, thedraccx, themias, Theomund, theOperand, TheShuEd, TimrodDX, Titian3, tkdrg, tmtmtl30, tom-leys, tomasalves8, Tomeno, Tornado-Technology, tosatur, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, Tyler-IN, Tyzemol, UbaserB, UKNOWH, UnicornOnLSD, Uriende, UristMcDorf, Vaaankas, Varen, VasilisThePikachu, veliebm, Veritius, Verslebas, VigersRay, Visne, VMSolidus, volundr-, Voomra, Vordenburg, vulppine, waylon531, weaversam8, Willhelm53, wixoaGit, WlarusFromDaSpace, wrexbe, xRiriq, yathxyz, Ygg01, YotaXP, YuriyKiss, zach-hill, Zandario, Zap527, ZelteHonor, zerorulez, zionnBE, zlodo, ZNixian, ZoldorfTheWizard, Zumorica, Zymem +0x6273, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 4dplanner, 612git, 778b, Ablankmann, Acruid, actioninja, adamsong, Admiral-Obvious-001, Adrian16199, Aerocrux, Aexxie, africalimedrop, Agoichi, Ahion, AJCM-git, AjexRose, Alekshhh, AlexMorgan3817, AlmondFlour, AlphaQwerty, Altoids1, amylizzle, ancientpower, ArchPigeon, Arendian, arimah, Arteben, AruMoon, as334, AsikKEsel, asperger-sind, aspiringLich, avghdev, AzzyIsNotHere, BananaFlambe, BasedUser, BGare, BingoJohnson-zz, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, Boaz1111, BobdaBiscuit, brainfood1183, Brandon-Huu, Bribrooo, Bright0, brndd, BubblegumBlue, BYONDFuckery, c4llv07e, CaasGit, CakeQ, CaptainSqrBeard, Carbonhell, Carolyn3114, casperr04, CatTheSystem, Centronias, chairbender, Charlese2, Cheackraze, cheesePizza2, Chief-Engineer, chromiumboy, Chronophylos, clement-or, Clyybber, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, coolmankid12345, corentt, crazybrain23, creadth, CrigCrag, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, Daemon, daerSeebaer, dahnte, dakamakat, dakimasu, DamianX, DangerRevolution, daniel-cr, Darkenson, DawBla, dch-GH, Deahaka, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, deepdarkdepths, Delete69, deltanedas, DeltaV-Bot, DerbyX, DoctorBeard, DogZeroX, dontbetank, Doru991, DoubleRiceEddiedd, DrMelon, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, Dutch-VanDerLinde, Easypoller, eclips_e, EdenTheLiznerd, EEASAS, Efruit, ElectroSR, elthundercloud, Emisse, EmoGarbage404, Endecc, enumerate0, eoineoineoin, ERORR404V1, Errant-4, estacaoespacialpirata, exincore, exp111, Fahasor, FairlySadPanda, ficcialfaint, Fildrance, FillerVK, Fishfish458, Flareguy, FluffiestFloof, FluidRock, FoLoKe, fooberticus, Fortune117, FoxxoTrystan, freeman2651, Fromoriss, FungiFellow, GalacticChimp, gbasood, Geekyhobo, Genkail, geraeumig, Git-Nivrak, github-actions[bot], gituhabu, GNF54, Golinth, GoodWheatley, Gotimanga, graevy, GreyMario, Guess-My-Name, gusxyz, h3half, Hanzdegloker, Hardly3D, harikattar, Hebiman, Henry12116, HerCoyote23, Hmeister-real, HoofedEar, hord-brayden, hubismal, Hugal31, Hyenh, iacore, IamVelcroboy, icekot8, igorsaux, ike709, Illiux, Ilya246, IlyaElDunaev, Injazz, Insineer, IntegerTempest, Interrobang01, IProduceWidgets, ItsMeThom, j-giebel, Jackal298, Jackrost, jamessimo, janekvap, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JoeHammad1844, joelhed, JohnGinnane, johnku1, joshepvodka, jproads, Jrpl, juliangiebel, JustArt1m, JustCone14, JustinTether, JustinTrotter, KaiShibaa, kalane15, kalanosh, KEEYNy, Keikiru, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, KingFroozy, kira-er, Kit0vras, KittenColony, Kmc2000, Ko4ergaPunk, komunre, koteq, Krunklehorn, Kukutis96513, kxvvv, Lamrr, LankLTE, lapatison, Leander-0, leonardo-dabepis, LetterN, Level10Cybermancer, lever1209, LightVillet, liltenhead, LittleBuilderJane, Lomcastar, LordCarve, LordEclipse, LovelyLophi, LudwigVonChesterfield, Lukasz825700516, lunarcomets, luringens, lvvova1, lzimann, lzk228, M3739, MACMAN2003, Macoron, MagnusCrowe, ManelNavola, matthst, Matz05, MehimoNemo, MeltedPixel, MemeProof, Menshin, Mervill, metalgearsloth, mhamsterr, MilenVolf, Minty642, Mirino97, mirrorcult, misandrie, MishaUnity, MisterMecky, Mith-randalf, Moneyl, Moomoobeef, moony, Morb0, Mr0maks, musicmanvr, Myakot, Myctai, N3X15, Nairodian, Naive817, namespace-Memory, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, nmajask, nok-ko, Nopey, notafet, notquitehadouken, noudoit, noverd, nuke-haus, NULL882, OCOtheOmega, OctoRocket, OldDanceJacket, onoira, Owai-Seek, pali6, Pangogie, patrikturi, PaulRitter, Peptide90, peptron1, Phantom-Lily, PHCodes, PixelTheKermit, PJB3005, Plykiya, pofitlo, pointer-to-null, PolterTzi, PoorMansDreams, potato1234x, ProfanedBane, PrPleGoo, ps3moira, Psychpsyo, psykzz, PuroSlavKing, quatre, QuietlyWhisper, qwerltaz, Radosvik, Radrark, Rainbeon, Rainfey, Rane, ravage123321, rbertoche, Redict, RedlineTriad, RednoWCirabrab, RemberBM, RemieRichards, RemTim, rene-descartes2021, RiceMar1244, RieBi, Rinkashikachi, Rockdtben, rolfero, rosieposieeee, Saakra, Samsterious, SaphireLattice, ScalyChimp, scrato, Scribbles0, Serkket, SethLafuente, ShadowCommander, Shadowtheprotogen546, SignalWalker, SimpleStation14, Simyon264, SirDragooon, Sirionaut, siyengar04, Skarletto, Skrauz, Skyedra, SlamBamActionman, slarticodefast, Slava0135, Snowni, snowsignal, SonicHDC, SoulSloth, SpaceManiac, SpeltIncorrectyl, spoogemonster, ssdaniel24, Stealthbomber16, stellar-novas, StrawberryMoses, SweptWasTaken, Szunti, TadJohnson00, takemysoult, TaralGit, Tayrtahn, tday93, TekuNut, TemporalOroboros, tentekal, tgrkzus, thatrandomcanadianguy, TheArturZh, theashtronaut, thedraccx, themias, Theomund, theOperand, TheShuEd, TimrodDX, Titian3, tkdrg, tmtmtl30, tom-leys, tomasalves8, Tomeno, Tornado-Technology, tosatur, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, Tyler-IN, Tyzemol, UbaserB, UKNOWH, UnicornOnLSD, Uriende, UristMcDorf, Vaaankas, Varen, VasilisThePikachu, veliebm, Veritius, Verslebas, VigersRay, Visne, VMSolidus, volundr-, Voomra, Vordenburg, vulppine, waylon531, weaversam8, Willhelm53, wixoaGit, WlarusFromDaSpace, wrexbe, xRiriq, yathxyz, Ygg01, YotaXP, YuriyKiss, zach-hill, Zandario, Zap527, ZelteHonor, zerorulez, zionnBE, zlodo, ZNixian, ZoldorfTheWizard, Zumorica, Zymem diff --git a/Resources/Locale/en-US/deltav/cartridge-loader/secwatch.ftl b/Resources/Locale/en-US/deltav/cartridge-loader/secwatch.ftl new file mode 100644 index 00000000000..a5b96eab08f --- /dev/null +++ b/Resources/Locale/en-US/deltav/cartridge-loader/secwatch.ftl @@ -0,0 +1,5 @@ +sec-watch-program-name = SecWatch +sec-watch-title = SecWatch 1.0 +sec-watch-no-entries = Everything's calm. Why not enjoy a Monkin Donut? +sec-watch-entry = {$name}, {$job} +sec-watch-no-reason = None given??? diff --git a/Resources/Locale/en-US/store/uplink-catalog.ftl b/Resources/Locale/en-US/store/uplink-catalog.ftl index 70eb998bb40..4836a57d6b1 100644 --- a/Resources/Locale/en-US/store/uplink-catalog.ftl +++ b/Resources/Locale/en-US/store/uplink-catalog.ftl @@ -201,6 +201,9 @@ uplink-decoy-kit-desc = State-of-the-art distraction technology straight from RN uplink-chemistry-kit-name = Chemical Synthesis Kit uplink-chemistry-kit-desc = A starter kit for the aspiring chemist, includes toxin and vestine for all your criminal needs! +uplink-knives-kit-name = Throwing Knives Kit +uplink-knives-kit-desc = A set of 4 syndicate branded throwing knives, perfect for embedding into the body of your victims. + uplink-meds-bundle-name = Medical Bundle uplink-meds-bundle-desc = All you need to get your comrades back in the fight: mainly a combat medkit, a defibrillator and three combat medipens. diff --git a/Resources/Prototypes/Catalog/Fills/Boxes/syndicate.yml b/Resources/Prototypes/Catalog/Fills/Boxes/syndicate.yml index 53c526f0339..7b5b05a49a5 100644 --- a/Resources/Prototypes/Catalog/Fills/Boxes/syndicate.yml +++ b/Resources/Prototypes/Catalog/Fills/Boxes/syndicate.yml @@ -38,14 +38,31 @@ name: observations kit suffix: Filled components: - - type: StorageFill - contents: - - id: SyndiCrewMonitorEmpty - amount: 1 - - id: PowerCellHigh - amount: 1 - - id: ClothingEyesGlassesHiddenSecurity - amount: 1 - - id: SurveillanceCameraMonitorCircuitboard - amount: 1 + - type: StorageFill + contents: + - id: SyndiCrewMonitorEmpty + amount: 1 + - id: PowerCellHigh + amount: 1 + - id: ClothingEyesGlassesHiddenSecurity + amount: 1 + - id: SurveillanceCameraMonitorCircuitboard + amount: 1 +- type: entity + parent: BoxCardboard + id: ThrowingKnivesKit + name: throwing knives kit + description: A set of 4 syndicate branded throwing knives, perfect for embedding into the body of your victims. + components: + - type: Storage + grid: + - 0,0,3,1 + - type: StorageFill + contents: + - id: ThrowingKnife + amount: 4 + - type: Sprite + layers: + - state: box_of_doom + - state: throwing_knives diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml index 1e81cdf2dd1..328ace7ba15 100644 --- a/Resources/Prototypes/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/Catalog/uplink_catalog.yml @@ -65,6 +65,17 @@ categories: - UplinkWeapons +- type: listing + id: UplinkThrowingKnivesKit + name: uplink-knives-kit-name + description: uplink-knives-kit-desc + icon: { sprite: /Textures/Objects/Storage/boxicons.rsi, state: throwing_knives } + productEntity: ThrowingKnivesKit + cost: + Telecrystal: 6 + categories: + - UplinkWeapons + - type: listing id: UplinkGlovesNorthStar name: uplink-gloves-north-star-name diff --git a/Resources/Prototypes/DeltaV/Body/Prototypes/harpy.yml b/Resources/Prototypes/DeltaV/Body/Prototypes/harpy.yml index 5b3615c55d8..25988f4a3a8 100644 --- a/Resources/Prototypes/DeltaV/Body/Prototypes/harpy.yml +++ b/Resources/Prototypes/DeltaV/Body/Prototypes/harpy.yml @@ -13,10 +13,10 @@ torso: part: TorsoHarpy connections: - - left arm - right arm - - left leg + - left arm - right leg + - left leg organs: heart: OrganHumanHeart lungs: OrganHarpyLungs @@ -47,4 +47,3 @@ part: RightFootHarpy left foot: part: LeftFootHarpy - diff --git a/Resources/Prototypes/DeltaV/Body/Prototypes/vulpkanin.yml b/Resources/Prototypes/DeltaV/Body/Prototypes/vulpkanin.yml index 3d1552ac81f..cdf787e4736 100644 --- a/Resources/Prototypes/DeltaV/Body/Prototypes/vulpkanin.yml +++ b/Resources/Prototypes/DeltaV/Body/Prototypes/vulpkanin.yml @@ -1,4 +1,4 @@ -- type: body +- type: body name: "vulpkanin" id: Vulpkanin root: torso @@ -19,10 +19,10 @@ liver: OrganAnimalLiver kidneys: OrganHumanKidneys connections: - - left arm - right arm - - left leg + - left arm - right leg + - left leg right arm: part: RightArmVulpkanin connections: diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Devices/cartridges.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Devices/cartridges.yml index e3d5e9d2138..def215cee43 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Devices/cartridges.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Devices/cartridges.yml @@ -17,4 +17,24 @@ icon: sprite: DeltaV/Icons/cri.rsi state: cri - - type: CrimeAssistCartridge + +- type: entity + parent: BaseItem + id: SecWatchCartridge + name: sec watch cartridge + description: A cartridge that tracks the status of currently wanted individuals. + components: + - type: Sprite + sprite: DeltaV/Objects/Devices/cartridge.rsi + state: cart-cri + - type: Icon + sprite: DeltaV/Objects/Devices/cartridge.rsi + state: cart-cri + - type: UIFragment + ui: !type:SecWatchUi + - type: Cartridge + programName: sec-watch-program-name + icon: + sprite: Objects/Weapons/Melee/stunbaton.rsi + state: stunbaton_on + - type: SecWatchCartridge diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Devices/pda.yml index 6ee3a7543f7..d9607390cd7 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Devices/pda.yml @@ -20,12 +20,13 @@ map: [ "enum.PdaVisualLayers.IdLight" ] shader: "unshaded" visible: false - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge + - SecWatchCartridge - type: Pda id: BrigmedicIDCard state: pda-corpsman diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml index 13524efa9e6..902c57418e4 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml @@ -93,6 +93,9 @@ - Hardsuit - WhitelistChameleon - HidesHarpyWings #DeltaV: Used by harpies to help render their hardsuit sprites + - type: Clothing + equipDelay: 2.5 # Hardsuits are heavy and take a while to put on/off. + unequipDelay: 2.5 - type: entity abstract: true @@ -114,6 +117,9 @@ - type: Tag tags: - HidesHarpyWings #DeltaV: Used by harpies to help render their hardsuit sprites + - type: Clothing + equipDelay: 1.25 # Softsuits are easier to put on and off + unequipDelay: 1 - type: entity parent: ClothingOuterBase diff --git a/Resources/Prototypes/Entities/Clothing/base_clothing.yml b/Resources/Prototypes/Entities/Clothing/base_clothing.yml index 92a698dd301..810ada5429d 100644 --- a/Resources/Prototypes/Entities/Clothing/base_clothing.yml +++ b/Resources/Prototypes/Entities/Clothing/base_clothing.yml @@ -11,6 +11,9 @@ - WhitelistChameleon - type: StaticPrice price: 15 + - type: Clothing + equipDelay: 0.5 + unequipDelay: 0.5 - type: entity abstract: true diff --git a/Resources/Prototypes/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Entities/Objects/Devices/pda.yml index 706cbd5dbbf..7155be68d74 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/pda.yml @@ -173,12 +173,13 @@ accentVColor: "#A32D26" - type: Icon state: pda-interncadet - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge + - SecWatchCartridge - type: entity parent: BasePDA @@ -430,12 +431,13 @@ borderColor: "#6f6192" - type: Icon state: pda-lawyer - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge + - SecWatchCartridge - type: entity parent: BasePDA @@ -643,12 +645,13 @@ accentHColor: "#447987" - type: Icon state: pda-hos - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge + - SecWatchCartridge - type: entity parent: BasePDA @@ -664,12 +667,13 @@ accentVColor: "#949137" - type: Icon state: pda-warden - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge + - SecWatchCartridge - type: entity parent: BasePDA @@ -684,12 +688,13 @@ borderColor: "#A32D26" - type: Icon state: pda-security - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge + - SecWatchCartridge - type: entity parent: BasePDA @@ -979,12 +984,13 @@ borderColor: "#774705" - type: Icon state: pda-detective - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge + - SecWatchCartridge - type: entity parent: BaseMedicalPDA @@ -1001,12 +1007,13 @@ accentVColor: "#d7d7d0" - type: Icon state: pda-brigmedic - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge + - SecWatchCartridge - type: entity parent: ClownPDA @@ -1092,12 +1099,13 @@ accentVColor: "#DFDFDF" - type: Icon state: pda-seniorofficer - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge + - SecWatchCartridge - type: entity parent: SyndiPDA diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/base_cartridge.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/base_cartridge.yml index e188ee8c658..3bef413dffa 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/base_cartridge.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/base_cartridge.yml @@ -11,10 +11,10 @@ shape: !type:PhysShapeAabb bounds: "-0.10,-0.05,0.10,0.05" - density: 20 + density: 0.5 mask: - ItemMask - restitution: 0.3 # fite me + restitution: 0.7 # Small and bouncy friction: 0.2 - type: Tag tags: @@ -23,6 +23,11 @@ size: Tiny - type: SpaceGarbage - type: EmitSoundOnLand + sound: + path: /Audio/Weapons/Guns/Casings/casing_fall_1.ogg + params: + volume: -1 + - type: EmitSoundOnCollide sound: path: /Audio/Weapons/Guns/Casings/casing_fall_2.ogg params: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml index b5d597715aa..03654061ced 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml @@ -252,3 +252,32 @@ sprite: Objects/Weapons/Melee/uranium_shiv.rsi - type: Sprite sprite: Objects/Weapons/Melee/uranium_shiv.rsi + +- type: entity + name: throwing knife + parent: BaseKnife + id: ThrowingKnife + description: This bloodred knife is very aerodynamic and easy to throw, but good luck trying to fight someone hand-to-hand. + components: + - type: Tag + tags: + - CombatKnife + - Knife + - type: Sprite + sprite: Objects/Weapons/Melee/throwing_knife.rsi + state: icon + - type: MeleeWeapon + wideAnimationRotation: -135 + attackRate: 2 + damage: + types: + Slash: 5 + - type: EmbeddableProjectile + sound: /Audio/Weapons/star_hit.ogg + - type: DamageOtherOnHit + damage: + types: + Slash: 10 + Piercing: 15 + - type: Item + sprite: Objects/Weapons/Melee/throwing_knife.rsi diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Body/Prototypes/felinid.yml b/Resources/Prototypes/Nyanotrasen/Entities/Body/Prototypes/felinid.yml index 6dd2a89e5a8..a09f3b6ab7f 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Body/Prototypes/felinid.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Body/Prototypes/felinid.yml @@ -13,10 +13,10 @@ torso: part: TorsoHuman connections: - - left arm - right arm - - left leg + - left arm - right leg + - left leg organs: heart: OrganAnimalHeart lungs: OrganHumanLungs diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Head/hats.yml b/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Head/hats.yml index 0a30756d724..83e3756c0f2 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Head/hats.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Head/hats.yml @@ -99,6 +99,8 @@ sprite: Nyanotrasen/Clothing/Head/Hats/cage.rsi - type: Clothing sprite: Nyanotrasen/Clothing/Head/Hats/cage.rsi + equipDelay: 0.5 + unequipDelay: 6 - type: HeadCage - type: entity diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/pda.yml index c2fd8786aff..4e6115ba339 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/pda.yml @@ -32,12 +32,13 @@ accentVColor: "#DFDFDF" - type: Icon state: pda-security - - type: CartridgeLoader # DeltaV - Crime Assist + - type: CartridgeLoader # DeltaV - Crime Assist + SecWatch preinstalled: - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge - CrimeAssistCartridge + - SecWatchCartridge - type: entity parent: BasePDA diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/shock_collar.yml b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/shock_collar.yml index 35cdcae6589..1266a721fe2 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/shock_collar.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/shock_collar.yml @@ -8,6 +8,8 @@ sprite: Nyanotrasen/Clothing/Neck/Misc/shock.rsi - type: Clothing sprite: Nyanotrasen/Clothing/Neck/Misc/shock.rsi + equipDelay: 1 + unequipDelay: 10 # It's a collar meant to be used on prisoners (or not), so it probably has some sort of safety. - type: ShockCollar - type: UseDelay delay: 3 # DeltaV: prevent clocks instakilling people diff --git a/Resources/Textures/Objects/Storage/boxes.rsi/meta.json b/Resources/Textures/Objects/Storage/boxes.rsi/meta.json index 23868a906f4..53ac39b639b 100644 --- a/Resources/Textures/Objects/Storage/boxes.rsi/meta.json +++ b/Resources/Textures/Objects/Storage/boxes.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/cc65477c04f7403ca8a457bd5bae69a01abadbf0, encryptokey was taken from Baystation12 at https://github.com/infinitystation/Baystation12/blob/073f678cdce92edb8fcd55f9ffc9f0523bf31506/icons/obj/radio.dmi and modified by lapatison. boxwidetoy, shelltoy, swab, flare, inflatable, trashbag, magazine, holo and forensic created by potato1234x (github) for ss14 based on toys.rsi, mouth_swab.rsi, flare.rsi, inflatable_wall.rsi, trashbag.rsi, caseless_pistol_mag.rsi, guardians.rsi and bureaucracy.rsi respectively, candle and darts created by TheShuEd for ss14, vials was drawn by Ubaser, evidence_markers by moomoobeef.", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/cc65477c04f7403ca8a457bd5bae69a01abadbf0, encryptokey was taken from Baystation12 at https://github.com/infinitystation/Baystation12/blob/073f678cdce92edb8fcd55f9ffc9f0523bf31506/icons/obj/radio.dmi and modified by lapatison. boxwidetoy, shelltoy, swab, flare, inflatable, trashbag, magazine, holo and forensic created by potato1234x (github) for ss14 based on toys.rsi, mouth_swab.rsi, flare.rsi, inflatable_wall.rsi, trashbag.rsi, caseless_pistol_mag.rsi, guardians.rsi and bureaucracy.rsi respectively, candle and darts created by TheShuEd for ss14, throwing_knives and vials was drawn by Ubaser, evidence_markers by moomoobeef.", "size": { "x": 32, "y": 32 @@ -35,7 +35,7 @@ "name": "sechud" }, { - "name": "bottle" + "name": "bottle" }, { "name": "box" @@ -142,6 +142,9 @@ { "name": "syringe" }, + { + "name": "throwing_knives" + }, { "name": "trashbag" }, @@ -152,12 +155,12 @@ "name": "writing_of_doom" }, { - "name": "headset" - }, + "name": "headset" + }, { - "name": "encryptokey" - }, - { + "name": "encryptokey" + }, + { "name": "inhand-left", "directions": 4 }, diff --git a/Resources/Textures/Objects/Storage/boxes.rsi/throwing_knives.png b/Resources/Textures/Objects/Storage/boxes.rsi/throwing_knives.png new file mode 100644 index 0000000000000000000000000000000000000000..834410a43ef64bd0f3dbfd9d852247d464cbd5f0 GIT binary patch literal 1141 zcmZ`&O=#0#7*2JTtvC;YZit60f{2)WZB~X2X<#$^3EEL=g=`16Hc7XzG+#)*+BgSJ z4^u%!9HT)<=$0%*`di&DU%@%;&UsW-gtBTI$qnX zp%I554$ONq(!q5-B8aU>&&x>89OD#NW(q1SYK&X9d=&3;_*m9Zfpp7;>2PkE@-;Yo z_QZf9eHAp7rsPbPJOXWv>|x?eoDyOrN%FQ@;&S3Z2*h~Qs5XK)Ri);~s@R6_ zMOA=iXl2br4oENw&8P z^E>(cRx~-Ey}kOY>*2{yt7|vq_uqb=K@7Mycl6Mok8_dE*+}P;Zi~1#+Hs@h!h`!> N%S-*k;zHl}`F|_-V#WXf literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Storage/boxicons.rsi/meta.json b/Resources/Textures/Objects/Storage/boxicons.rsi/meta.json index 858fc7c4e54..935b0b9f8b3 100644 --- a/Resources/Textures/Objects/Storage/boxicons.rsi/meta.json +++ b/Resources/Textures/Objects/Storage/boxicons.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from baystation at https://github.com/Baystation12/Baystation12/commit/bc9fbb1722530596e3aa7522ee407280b323ad43, vials drawn by Ubaser, tracks made by Fazansen(https://github.com/Fazansen).", + "copyright": "Taken from baystation at https://github.com/Baystation12/Baystation12/commit/bc9fbb1722530596e3aa7522ee407280b323ad43, throwing_knives and vials are drawn by Ubaser, tracks made by Fazansen(https://github.com/Fazansen).", "size": { "x": 32, "y": 32 @@ -76,6 +76,9 @@ { "name": "syringe" }, + { + "name": "throwing_knives" + }, { "name": "ziptie" }, diff --git a/Resources/Textures/Objects/Storage/boxicons.rsi/throwing_knives.png b/Resources/Textures/Objects/Storage/boxicons.rsi/throwing_knives.png new file mode 100644 index 0000000000000000000000000000000000000000..b2af7bce88436ed9b060cec8bd6f97019537caa9 GIT binary patch literal 1392 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}e5nzhX}-P; zT0k}j5QD&_;K@Lev%n*=n1MlK76>znTPbd0U|=rE42dX-@b$4u&d=3LOvz75)vL%Y z0PC`;umUo3Q%e#RDspr3imfVamB1>jfNYSkzLEl1NlCV?QiN}Sf^&XRs)CuGfu4bq z9hZWFf=y9MnpKdC8&o@xXRDM^Qc_^0uU}qXu2*iXmtT~wZ)j<0sc&GUZ)BtkRH0j3 znOBlnp_^B%3^4>|j!SBBa#3bMNoIbY0?6FNr2NtnTO}osMQ{LdXG${Mo`TY%9I!1Z z$@-}|sky0nCB^!NdWQPg^p#|$AzYYO3=Ixo!03ZyfZ7bOYV#~8Nj3q7lxqdhJy8Dv z9hwZbx40xlA4!3}k%57Qu7Q!Rk)=M|e?aHkq$FFFWR~Qlf&&ijA8-gd=9Hj{g4Bb8 zASV+PvQ{~XdFi%F6}l;@X^EvdB}#Tl`4#c`Y4Iuf`MEaw5QV4)Ktxf^wb94o1RIdY zts;X`i}Q0zK|yb4WM*Om4h|GiL?l3TL}1l{EQ+opAS1sdADF0$GLt>?N>Ymoihv0W zVk6W(+$zw`LRcP}msw(G1T_Fn7)cjW1X(#2m6YcfWru(x10^JJs)CvX300(Y3dscE z7y#x1J1!f2c#g8;T5vFZ7clEqd%8G=L~y$v&<~>y})k!b$Ij_*Boec?7c@H{qFghl3r*G!+?2O}8vz5m}+81h%=^c1PKS83O{n;1@QN}0Z7^Xpv`mc7*YUNB{2a+8@u z6VE;{x%R3Bx1%7%JU02a%^lN%F zE%jh-`3kPxCsNfyV%|*TT~Hz7n*90eUlmUe899+_S!k}&6*}S*Quc$Du?mypn?RQoOuZK{=k6;xQ!K#XyN7Ju|PyZWn zMDN`Biup!2tQbXXfBj=p>r*o7QRYk6np)zppMvt=Rf6n1)cS_o?!bBEpWVW zzxWC@_m8>zq*a)GFBhEM{dHDh?X&sHg;q@=(~U%$M(T(8_%FTW^V-_X+1Qs2Nx-^fT8s6w~6 zGOr}DLN~8i8Da>`9GBGM~RsBTId_|A5Z7NlCUU$t=l91qU45Kj08_%qc+?1*r!G zK~5$pWUX=%^U`gVDs)p)(-KQ_N|fv}^D+|iQgn+l(=$qJ^dTxyO@N4^8f>GF#SJzf zpIb!+r55Msl!C(E&dAKf1{@wJqKH_4=!n3o16dSZM?gk?Nj@-D6=f!S=9Q!t6%+we z7{o@XeYjPin}x7EG%vHn&IoD%nlO?sq!_YtEGj9_FUk%9#|COp;#3AT3KFbHDHW0p zz)=9q2XMaQ|Ei{ z!xO@M-(SD!`>3)=h^2Je2J^D5F{d?VMa9-GwO_78j!x3y?Z zAj4G~+4hAyrlqc*dNa%HszigAoqha~oP8H+mOXafayE9a!9u>WGK-y+(MulJo4!

{Sco1*{# literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/icon.png b/Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2c61755b52c35b9138c5aa7f93ec6e71bffa7871 GIT binary patch literal 1593 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}e5nzhX}-P; zT0k}j5QD&_;K@Lev%n*=7^vU~2s2LA=96Y%V9v=5i71Ki^|4CM&(%vz$xlkvtH>$0h^0y1+`OA-|-a&z*EttxDlz$&bOY>=?Nk^)#sNw%$0gl~X?bAC~(f|;Iyo`I4b zmx6+VO;JjkRgjAtR6CGotCUevQedU8UtV6WS8lAAUzDzIXlZGwZ(yWvWTXpJp<7&; zSCUwvn^&w1F$89gOKNd)QD#9&W`3Rm$lS!F{L&IzB_)tWZ~$>9$H0x+$q?iKRIuN_L*U?(xRP#^yHq5LKwUA)=^;+UR4k-v;DstH_|# z;{2RaP`KM!n%RJZ0!0uJ0T2xl*fbyuqH74q$S=tUrl+FJWY4^k)S`kSVA=xPX9Tql zw+eK#5O#;=WtP~%3_ue`(uEW^R*pp_<@rU~A>epG1R_o)P-7qgij+Pfi60#Jz|?QY zWup(zNp@V%mxb~$FfjRex;TbJaJ~)o_78Rx`Ind7Qc!9C=1{nZp6(V`<|%VS?rwO| zv`YFX^9e4~PsSA-Axxj#MNAkEdHI&OX76G=)GMZ}=rs8q-}j!mL07V^3U2f6J^AI# zoq03g8>T;Fdis2i^@6E~7#7=l^gJ%xJ+Y%+lXKaHqX+i&-QKcutMlpi*H_-Xt=jRV zd*1~6f=%ZSTsAiTP#JCb>kaF>`@6Xp?f)>h#U}3b>)o#T)52Oly*PYaWOlU5PTu2@ z`>WU4$ImIf^YZ<&n>TcNwn&$7C%_^!e&PWtFDOYqF~P)RrY}dv#vx z+mV|31?|)Bt-W|{n`iU1w>;<0W?wzjc_fLaDOPdysp~DDCN*y^+BSEpyF4%F)yewt zqVAQxxweIq_1K#BTHaROvFh!q{eFz zK3OI`antZn#mM^|`vUTx9X{?q)pV<`M@~&xT=!J%TJAry)DFy+mU5`JKlnhdpM7PB z*G*T;g$Ycu3|n7Vm0iv>{N65lwq#bQ@Z<*>?{c(v2M9F!WqQbu$Pe0yk&>D6*Hq-gd*mBP7>5; hNwHl1#vxGFf@x_avz=0K&TUY!?dj_0vd$@?2>>-FL7@Nu literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..5988d571dc12ca1c485efc87735bbba3ce635640 GIT binary patch literal 1296 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|_);T0(|mmy zw18|5AO?X;!IOa`XMsm#F$06fED&ZCw^H21z`$IV84^(v;p=0SoS&h?X&sHg;q@=(~U%$M(T(8_%FTW^V-_X+1Qs2Nx-^fT8s6w~6 zGOr}DLN~8i8Da>`9GBGM~RsBTId_|A5Z7NlCUU$t=l91qU45Kj08_%qc+?1*r!G zK~5$pWUX=%^U`gVDs)p)(-KQ_N|fv}^D+|iQgn+l(=$qJ^dTxyO@N4^8f>GF#SJzf zpIb!+r55Msl!C(E&dAKf1{@wJqKH_4=!n3o16dSZM?gk?Nj@-D6=f!S=9Q!t6%+we z7{o@XeYjPin}x7EG%vHn&IoD%nlO?sq!_YtEGj9_FUk%9#|COp;#3AT3KFbHDHW0p zz)=9q2X*mm#I&6k+g^W`6|5prbv@a}`Hz?!tn&ug}I zy!5S_wCuBHzq<U{MO(OH#J#lhTTXtx$E#ub`D;1*mDf3?|1NQ# p_;-Kx%DB?a9Dh3C-ua-+#BaJLkNt{4Ehnfn@^tlcS?83{1OP7tpo#zh literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..09c015efac56e7935ff49a7488bea47ee21f706a GIT binary patch literal 1298 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|_);T0(|mmy zw18|5AO?X;!IOa`XMsm#F$06fED&ZCw^H21z`$IV84^(v;p=0SoS&h?X&sHg;q@=(~U%$M(T(8_%FTW^V-_X+1Qs2Nx-^fT8s6w~6 zGOr}DLN~8i8Da>`9GBGM~RsBTId_|A5Z7NlCUU$t=l91qU45Kj08_%qc+?1*r!G zK~5$pWUX=%^U`gVDs)p)(-KQ_N|fv}^D+|iQgn+l(=$qJ^dTxyO@N4^8f>GF#SJzf zpIb!+r55Msl!C(E&dAKf1{@wJqKH_4=!n3o16dSZM?gk?Nj@-D6=f!S=9Q!t6%+we z7{o@XeYjPin}x7EG%vHn&IoD%nlO?sq!_YtEGj9_FUk%9#|COp;#3AT3KFbHDHW0p zz)=9q2X1D--Z+E{R|F`Dg_uaXhW6tcgx!1%pi>paAZW9~hvW5@d6(?_2pParSE_c-* z{|Wn+{=e67Ep6>X)9_3GCW~F>Grp7k(%8AgO9|B?RC`-lOEe^_b5>b}$HEbI&63Re#m1*}He%`O5qM s!?yrm-qO5?#!wak2L?tE(OAW5$7GzxZoH}C0;oLlboFyt=akR{01HQ^j{pDw literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/meta.json b/Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/meta.json new file mode 100644 index 00000000000..373d2d77701 --- /dev/null +++ b/Resources/Textures/Objects/Weapons/Melee/throwing_knife.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Drawn by Ubaser.", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "equipped-BELT", + "directions": 4 + } + ] +}