From b9b854e179ccbedc183adfaefc4561dc90cf285a Mon Sep 17 00:00:00 2001 From: Milon Date: Tue, 29 Apr 2025 19:08:23 +0200 Subject: [PATCH 1/3] ringer bugfixes (#36936) AAAAAAAAAA --- .../PDA/Ringer/RingtoneMenu.xaml.cs | 63 ++++++++++--------- Content.Server/PDA/Ringer/RingerSystem.cs | 5 +- .../PDA/Ringer/RingerUplinkComponent.cs | 2 +- Content.Shared/PDA/SharedRingerSystem.cs | 15 +---- 4 files changed, 41 insertions(+), 44 deletions(-) diff --git a/Content.Client/PDA/Ringer/RingtoneMenu.xaml.cs b/Content.Client/PDA/Ringer/RingtoneMenu.xaml.cs index 989fe65843..83024c22fb 100644 --- a/Content.Client/PDA/Ringer/RingtoneMenu.xaml.cs +++ b/Content.Client/PDA/Ringer/RingtoneMenu.xaml.cs @@ -1,3 +1,4 @@ +using System.Linq; using System.Numerics; using Content.Client.UserInterface.Controls; using Robust.Client.AutoGenerated; @@ -29,48 +30,47 @@ namespace Content.Client.PDA.Ringer { var input = RingerNoteInputs[i]; var index = i; - var foo = () => // Prevents unauthorized characters from being entered into the LineEdit - { - input.Text = input.Text.ToUpper(); - - if (!IsNote(input.Text)) - { - input.Text = PreviousNoteInputs[index]; - } - else - PreviousNoteInputs[index] = input.Text; - - input.RemoveStyleClass("Caution"); - }; - - input.OnFocusExit += _ => foo(); - input.OnTextEntered += _ => - { - foo(); - input.CursorPosition = input.Text.Length; // Resets caret position to the end of the typed input - }; input.OnTextChanged += args => { - // Convert to uppercase - var upperText = args.Text.ToUpper(); + if (input.Text.Length <= 0) + return; - // Filter to only valid notes - var newText = upperText; - if (!IsNote(newText)) + input.Text = args.Text.ToUpper(); + + var isValid = IsNote(input.Text); + + if (!isValid) { - newText = PreviousNoteInputs[index]; + input.Text = PreviousNoteInputs[index]; input.AddStyleClass("Caution"); } else { - PreviousNoteInputs[index] = newText; + PreviousNoteInputs[index] = input.Text; input.RemoveStyleClass("Caution"); } - // Only update if there's a change - if (newText != input.Text) - input.Text = newText; + input.CursorPosition = input.Text.Length; + }; + + input.OnFocusExit += _ => + { + if (!IsNote(input.Text)) + { + input.Text = PreviousNoteInputs[index]; + input.RemoveStyleClass("Caution"); + } + }; + + input.OnTextEntered += _ => + { + if (!IsNote(input.Text)) + { + input.Text = PreviousNoteInputs[index]; + input.RemoveStyleClass("Caution"); + } + input.CursorPosition = input.Text.Length; }; } } @@ -86,6 +86,9 @@ namespace Content.Client.PDA.Ringer /// public static bool IsNote(string input) { + if (input.Any(char.IsDigit)) + return false; + input = input.Replace("#", "sharp"); return Enum.TryParse(input, true, out Note _); diff --git a/Content.Server/PDA/Ringer/RingerSystem.cs b/Content.Server/PDA/Ringer/RingerSystem.cs index dbdc5e83f3..b47ca0fde3 100644 --- a/Content.Server/PDA/Ringer/RingerSystem.cs +++ b/Content.Server/PDA/Ringer/RingerSystem.cs @@ -55,7 +55,6 @@ public sealed class RingerSystem : SharedRingerSystem /// private void OnGenerateUplinkCode(Entity ent, ref GenerateUplinkCodeEvent ev) { - // Generate a new uplink code var code = GenerateRingtone(); // Set the code on the component @@ -74,6 +73,10 @@ public sealed class RingerSystem : SharedRingerSystem if (!HasComp(uid)) return false; + // Wasn't generated yet + if (uplink.Code is null) + return false; + // On the server, we always check if the code matches if (!uplink.Code.SequenceEqual(ringtone)) return false; diff --git a/Content.Shared/PDA/Ringer/RingerUplinkComponent.cs b/Content.Shared/PDA/Ringer/RingerUplinkComponent.cs index e3170c84e3..2dbbfb5efc 100644 --- a/Content.Shared/PDA/Ringer/RingerUplinkComponent.cs +++ b/Content.Shared/PDA/Ringer/RingerUplinkComponent.cs @@ -14,7 +14,7 @@ public sealed partial class RingerUplinkComponent : Component /// Set via GenerateUplinkCodeEvent. /// [DataField] - public Note[] Code = new Note[SharedRingerSystem.RingtoneLength]; + public Note[]? Code; /// /// Whether to show the toggle uplink button in PDA settings. diff --git a/Content.Shared/PDA/SharedRingerSystem.cs b/Content.Shared/PDA/SharedRingerSystem.cs index 0fa5a570aa..8a9d8156a3 100644 --- a/Content.Shared/PDA/SharedRingerSystem.cs +++ b/Content.Shared/PDA/SharedRingerSystem.cs @@ -45,8 +45,8 @@ public abstract class SharedRingerSystem : EntitySystem /// public override void Update(float frameTime) { - var ringerQuery = EntityQueryEnumerator(); - while (ringerQuery.MoveNext(out var uid, out var ringer)) + var ringerQuery = EntityQueryEnumerator(); + while (ringerQuery.MoveNext(out var uid, out var ringer, out var xform)) { if (!ringer.Active || !ringer.NextNoteTime.HasValue) continue; @@ -63,10 +63,9 @@ public abstract class SharedRingerSystem : EntitySystem // and play it separately with PlayLocal, so that it's actually predicted if (_net.IsServer) { - var ringerXform = Transform(uid); _audio.PlayEntity( GetSound(ringer.Ringtone[ringer.NoteCount]), - Filter.Empty().AddInRange(_xform.GetMapCoordinates(uid, ringerXform), ringer.Range), + Filter.Empty().AddInRange(_xform.GetMapCoordinates(uid, xform), ringer.Range), uid, true, AudioParams.Default.WithMaxDistance(ringer.Range).WithVolume(ringer.Volume) @@ -257,14 +256,6 @@ public abstract class SharedRingerSystem : EntitySystem return true; } - /// - /// Helper method to determine if the mind is an antagonist. - /// - protected bool IsAntagonist(EntityUid? user) - { - return user != null && _mind.TryGetMind(user.Value, out var mindId, out _) && _role.MindIsAntagonist(mindId); - } - /// /// Gets the sound path for a specific note. /// From a8ff93076311a185d7b96264ae0466ec37847089 Mon Sep 17 00:00:00 2001 From: ActiveMammmoth <140334666+ActiveMammmoth@users.noreply.github.com> Date: Tue, 29 Apr 2025 15:40:49 -0400 Subject: [PATCH 2/3] Staff of Animation Fixes & Recharging (#37021) --- .../Actions/ActionOnInteractComponent.cs | 5 ++-- .../Actions/ActionOnInteractSystem.cs | 28 +++++++++++++++++++ .../NPC/Systems/NPCUtilitySystem.cs | 3 ++ .../Magic/Systems/AnimateSpellSystem.cs | 2 +- Resources/Prototypes/Magic/animate_spell.yml | 8 +++--- Resources/Prototypes/Magic/staves.yml | 12 ++++++-- 6 files changed, 49 insertions(+), 9 deletions(-) diff --git a/Content.Server/Actions/ActionOnInteractComponent.cs b/Content.Server/Actions/ActionOnInteractComponent.cs index 3a7e15649b..4ae3d9e5f7 100644 --- a/Content.Server/Actions/ActionOnInteractComponent.cs +++ b/Content.Server/Actions/ActionOnInteractComponent.cs @@ -1,6 +1,5 @@ using Content.Shared.Interaction; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; namespace Content.Server.Actions; @@ -20,8 +19,10 @@ namespace Content.Server.Actions; [RegisterComponent] public sealed partial class ActionOnInteractComponent : Component { - [DataField(required:true)] + [DataField(required: true)] public List? Actions; [DataField] public List? ActionEntities; + + [DataField] public bool RequiresCharge; } diff --git a/Content.Server/Actions/ActionOnInteractSystem.cs b/Content.Server/Actions/ActionOnInteractSystem.cs index af9b0b1ddb..c658b3f90a 100644 --- a/Content.Server/Actions/ActionOnInteractSystem.cs +++ b/Content.Server/Actions/ActionOnInteractSystem.cs @@ -1,5 +1,7 @@ using System.Linq; using Content.Shared.Actions; +using Content.Shared.Charges.Components; +using Content.Shared.Charges.Systems; using Content.Shared.Interaction; using Robust.Shared.Random; using Robust.Shared.Timing; @@ -15,6 +17,7 @@ public sealed class ActionOnInteractSystem : EntitySystem [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly ActionContainerSystem _actionContainer = default!; + [Dependency] private readonly SharedChargesSystem _charges = default!; public override void Initialize() { @@ -54,6 +57,9 @@ public sealed class ActionOnInteractSystem : EntitySystem if (options.Count == 0) return; + if (!TryUseCharge((uid, component))) + return; + var (actId, act) = _random.Pick(options); _actions.PerformAction(args.User, null, actId, act, act.Event, _timing.CurTime, false); args.Handled = true; @@ -85,6 +91,9 @@ public sealed class ActionOnInteractSystem : EntitySystem if (entOptions.Count > 0) { + if (!TryUseCharge((uid, component))) + return; + var (entActId, entAct) = _random.Pick(entOptions); if (entAct.Event != null) { @@ -108,6 +117,9 @@ public sealed class ActionOnInteractSystem : EntitySystem if (entWorldOptions.Count > 0) { + if (!TryUseCharge((uid, component))) + return; + var (entActId, entAct) = _random.Pick(entWorldOptions); if (entAct.Event != null) { @@ -132,6 +144,9 @@ public sealed class ActionOnInteractSystem : EntitySystem if (options.Count == 0) return; + if (!TryUseCharge((uid, component))) + return; + var (actId, act) = _random.Pick(options); if (act.Event != null) { @@ -163,4 +178,17 @@ public sealed class ActionOnInteractSystem : EntitySystem return valid; } + + private bool TryUseCharge(Entity ent) + { + if (!ent.Comp.RequiresCharge) + return true; + + Entity charges = ent.Owner; + if (_charges.IsEmpty(charges)) + return false; + + _charges.TryUseCharge(charges); + return true; + } } diff --git a/Content.Server/NPC/Systems/NPCUtilitySystem.cs b/Content.Server/NPC/Systems/NPCUtilitySystem.cs index eff4f2772b..7b485eeb96 100644 --- a/Content.Server/NPC/Systems/NPCUtilitySystem.cs +++ b/Content.Server/NPC/Systems/NPCUtilitySystem.cs @@ -232,6 +232,9 @@ public sealed class NPCUtilitySystem : EntitySystem { if (_container.TryGetContainingContainer(targetUid, out var container)) { + if (container.Owner == owner) + return 0f; + if (TryComp(container.Owner, out var storageComponent)) { if (storageComponent is { Open: false } && _weldable.IsWelded(container.Owner)) diff --git a/Content.Shared/Magic/Systems/AnimateSpellSystem.cs b/Content.Shared/Magic/Systems/AnimateSpellSystem.cs index 458336dea1..202605a338 100644 --- a/Content.Shared/Magic/Systems/AnimateSpellSystem.cs +++ b/Content.Shared/Magic/Systems/AnimateSpellSystem.cs @@ -40,7 +40,7 @@ public sealed class AnimateSpellSystem : EntitySystem _container.AttachParentToContainerOrGrid((ent, xform)); // Items animated inside inventory now exit, they can't be picked up and so can't escape otherwise var ev = new AnimateSpellEvent(); - RaiseLocalEvent(ref ev); + RaiseLocalEvent(ent, ref ev); } } diff --git a/Resources/Prototypes/Magic/animate_spell.yml b/Resources/Prototypes/Magic/animate_spell.yml index d36afb49d9..6d1319944b 100644 --- a/Resources/Prototypes/Magic/animate_spell.yml +++ b/Resources/Prototypes/Magic/animate_spell.yml @@ -3,14 +3,12 @@ name: Animate description: Bring an inanimate object to life! components: - - type: LimitedCharges - maxCharges: 5 - type: EntityTargetAction useDelay: 0 itemIconStyle: BigAction whitelist: components: - - Animateable # Currently on: SeatBase, TableBase, ClosetBase, BaseMachine, ConstructibleMachine, BaseComputer, BaseItem, CrateGeneric, StorageTank, GasCanister, BaseTarget + - Animateable # Currently on: SeatBase, TableBase, ClosetBase, BaseMachine, ConstructibleMachine, BaseComputer, BaseItem, CrateGeneric, StorageTank, GasCanister blacklist: components: - MindContainer @@ -19,7 +17,7 @@ - AnomalyGenerator - TegGenerator - TegCirculator - - Artifact + - XenoArtifact canTargetSelf: false interactOnMiss: false sound: !type:SoundPathSpecifier @@ -70,9 +68,11 @@ collection: MetalBreak - type: Hands - type: CanEscapeInventory + - type: MobCollision toRemove: - RequireProjectileTarget - BlockMovement - Item + - MeleeRequiresWield speech: action-speech-spell-animate doSpeech: false diff --git a/Resources/Prototypes/Magic/staves.yml b/Resources/Prototypes/Magic/staves.yml index 8bfb30b887..ff43db866e 100644 --- a/Resources/Prototypes/Magic/staves.yml +++ b/Resources/Prototypes/Magic/staves.yml @@ -7,6 +7,10 @@ name: RGB staff description: Helps fix the underabundance of RGB gear on the station. components: + - type: LimitedCharges + maxCharges: 25 + - type: AutoRecharge + rechargeDuration: 30 - type: Sprite sprite: Objects/Weapons/Guns/Basic/staves.rsi layers: @@ -14,6 +18,7 @@ - state: nothing-unshaded shader: unshaded - type: ActionOnInteract + requiresCharge: true actions: - ActionRgbLight - type: Item @@ -38,11 +43,16 @@ name: staff of animation description: Brings inanimate objects to life! components: + - type: LimitedCharges + maxCharges: 5 + - type: AutoRecharge + rechargeDuration: 30 - type: Sprite sprite: Objects/Weapons/Guns/Basic/staves.rsi layers: - state: animation - type: ActionOnInteract + requiresCharge: true actions: - ActionAnimateSpell - type: Item @@ -59,8 +69,6 @@ - type: entity id: ActionRgbLight components: - - type: LimitedCharges - maxCharges: 25 - type: EntityTargetAction whitelist: { components: [ PointLight ] } sound: /Audio/Magic/blink.ogg From 84178dd5343399305e875c19bdb2a5393bb59905 Mon Sep 17 00:00:00 2001 From: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com> Date: Tue, 29 Apr 2025 13:10:00 -0700 Subject: [PATCH 3/3] Puddle code hotfix 2 (#37046) --- .../SpillIfPuddlePresentTileReaction.cs | 30 +++++++++++++++++++ .../TileReactions/SpillTileReaction.cs | 28 +++++++++++++++++ .../Reagents/Consumable/Drink/base_drink.yml | 1 + .../Reagents/Consumable/Food/condiments.yml | 2 ++ Resources/Prototypes/Reagents/biological.yml | 4 +++ Resources/Prototypes/Reagents/cleaning.yml | 4 +++ 6 files changed, 69 insertions(+) create mode 100644 Content.Server/Chemistry/TileReactions/SpillIfPuddlePresentTileReaction.cs create mode 100644 Content.Server/Chemistry/TileReactions/SpillTileReaction.cs diff --git a/Content.Server/Chemistry/TileReactions/SpillIfPuddlePresentTileReaction.cs b/Content.Server/Chemistry/TileReactions/SpillIfPuddlePresentTileReaction.cs new file mode 100644 index 0000000000..5acef8d1a8 --- /dev/null +++ b/Content.Server/Chemistry/TileReactions/SpillIfPuddlePresentTileReaction.cs @@ -0,0 +1,30 @@ +using Content.Server.Fluids.EntitySystems; +using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.Reaction; +using Content.Shared.Chemistry.Reagent; +using Content.Shared.FixedPoint; +using JetBrains.Annotations; +using Robust.Shared.Map; + +namespace Content.Server.Chemistry.TileReactions +{ + [UsedImplicitly] + [DataDefinition] + public sealed partial class SpillIfPuddlePresentTileReaction : ITileReaction + { + public FixedPoint2 TileReact(TileRef tile, + ReagentPrototype reagent, + FixedPoint2 reactVolume, + IEntityManager entityManager, + List? data) + { + var spillSystem = entityManager.System(); + if (!spillSystem.TryGetPuddle(tile, out _)) + return FixedPoint2.Zero; + + return spillSystem.TrySpillAt(tile, new Solution(reagent.ID, reactVolume, data), out _, sound: false, tileReact: false) + ? reactVolume + : FixedPoint2.Zero; + } + } +} diff --git a/Content.Server/Chemistry/TileReactions/SpillTileReaction.cs b/Content.Server/Chemistry/TileReactions/SpillTileReaction.cs new file mode 100644 index 0000000000..c371410909 --- /dev/null +++ b/Content.Server/Chemistry/TileReactions/SpillTileReaction.cs @@ -0,0 +1,28 @@ +using Content.Server.Fluids.EntitySystems; +using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.Reaction; +using Content.Shared.Chemistry.Reagent; +using Content.Shared.FixedPoint; +using JetBrains.Annotations; +using Robust.Shared.Map; + +namespace Content.Server.Chemistry.TileReactions +{ + [UsedImplicitly] + [DataDefinition] + public sealed partial class SpillTileReaction : ITileReaction + { + public FixedPoint2 TileReact(TileRef tile, + ReagentPrototype reagent, + FixedPoint2 reactVolume, + IEntityManager entityManager, + List? data) + { + var spillSystem = entityManager.System(); + + return spillSystem.TrySpillAt(tile, new Solution(reagent.ID, reactVolume, data), out _, sound: false, tileReact: false) + ? reactVolume + : FixedPoint2.Zero; + } + } +} diff --git a/Resources/Prototypes/Reagents/Consumable/Drink/base_drink.yml b/Resources/Prototypes/Reagents/Consumable/Drink/base_drink.yml index dac16dcb1c..c5cbaea8d3 100644 --- a/Resources/Prototypes/Reagents/Consumable/Drink/base_drink.yml +++ b/Resources/Prototypes/Reagents/Consumable/Drink/base_drink.yml @@ -19,6 +19,7 @@ amount: 1 tileReactions: - !type:ExtinguishTileReaction { } + - !type:SpillIfPuddlePresentTileReaction { } - type: reagent id: BaseSoda diff --git a/Resources/Prototypes/Reagents/Consumable/Food/condiments.yml b/Resources/Prototypes/Reagents/Consumable/Food/condiments.yml index 1dde464128..addc85096d 100644 --- a/Resources/Prototypes/Reagents/Consumable/Food/condiments.yml +++ b/Resources/Prototypes/Reagents/Consumable/Food/condiments.yml @@ -175,6 +175,8 @@ recognizable: true physicalDesc: reagent-physical-desc-sticky viscosity: 0.55 #Start using syrup to attach your remote recievers to your microwaves! + tileReactions: + - !type:SpillTileReaction metabolisms: Food: # 12 diona blood for 1 unit of syrup, this stuff better be worthwhile. diff --git a/Resources/Prototypes/Reagents/biological.yml b/Resources/Prototypes/Reagents/biological.yml index df5ed51945..7e7c544c12 100644 --- a/Resources/Prototypes/Reagents/biological.yml +++ b/Resources/Prototypes/Reagents/biological.yml @@ -66,6 +66,8 @@ recognizable: true physicalDesc: reagent-physical-desc-viscous viscosity: 0.25 + tileReactions: + - !type:SpillTileReaction metabolisms: Food: # Delicious! @@ -87,6 +89,8 @@ recognizable: true physicalDesc: reagent-physical-desc-sticky viscosity: 0.10 + tileReactions: + - !type:SpillTileReaction metabolisms: Food: # Sweet! diff --git a/Resources/Prototypes/Reagents/cleaning.yml b/Resources/Prototypes/Reagents/cleaning.yml index 1c0f220160..3f289d0486 100644 --- a/Resources/Prototypes/Reagents/cleaning.yml +++ b/Resources/Prototypes/Reagents/cleaning.yml @@ -77,6 +77,8 @@ recognizable: true boilingPoint: 290.0 # Glycerin meltingPoint: 18.2 + tileReactions: + - !type:SpillTileReaction friction: 0.0 - type: reagent @@ -88,6 +90,8 @@ color: "#ffffff" boilingPoint: 250.0 meltingPoint: 380.0 + tileReactions: + - !type:SpillTileReaction viscosity: 0.5 reactiveEffects: Acidic: