Stable merge (#37050)

This commit is contained in:
Myra
2025-04-29 21:54:43 +01:00
committed by GitHub
16 changed files with 159 additions and 53 deletions

View File

@@ -1,3 +1,4 @@
using System.Linq;
using System.Numerics; using System.Numerics;
using Content.Client.UserInterface.Controls; using Content.Client.UserInterface.Controls;
using Robust.Client.AutoGenerated; using Robust.Client.AutoGenerated;
@@ -29,48 +30,47 @@ namespace Content.Client.PDA.Ringer
{ {
var input = RingerNoteInputs[i]; var input = RingerNoteInputs[i];
var index = 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 => input.OnTextChanged += args =>
{ {
// Convert to uppercase if (input.Text.Length <= 0)
var upperText = args.Text.ToUpper(); return;
// Filter to only valid notes input.Text = args.Text.ToUpper();
var newText = upperText;
if (!IsNote(newText)) var isValid = IsNote(input.Text);
if (!isValid)
{ {
newText = PreviousNoteInputs[index]; input.Text = PreviousNoteInputs[index];
input.AddStyleClass("Caution"); input.AddStyleClass("Caution");
} }
else else
{ {
PreviousNoteInputs[index] = newText; PreviousNoteInputs[index] = input.Text;
input.RemoveStyleClass("Caution"); input.RemoveStyleClass("Caution");
} }
// Only update if there's a change input.CursorPosition = input.Text.Length;
if (newText != input.Text) };
input.Text = newText;
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
/// </summary> /// </summary>
public static bool IsNote(string input) public static bool IsNote(string input)
{ {
if (input.Any(char.IsDigit))
return false;
input = input.Replace("#", "sharp"); input = input.Replace("#", "sharp");
return Enum.TryParse(input, true, out Note _); return Enum.TryParse(input, true, out Note _);

View File

@@ -1,6 +1,5 @@
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
namespace Content.Server.Actions; namespace Content.Server.Actions;
@@ -24,4 +23,6 @@ public sealed partial class ActionOnInteractComponent : Component
public List<EntProtoId>? Actions; public List<EntProtoId>? Actions;
[DataField] public List<EntityUid>? ActionEntities; [DataField] public List<EntityUid>? ActionEntities;
[DataField] public bool RequiresCharge;
} }

View File

@@ -1,5 +1,7 @@
using System.Linq; using System.Linq;
using Content.Shared.Actions; using Content.Shared.Actions;
using Content.Shared.Charges.Components;
using Content.Shared.Charges.Systems;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.Timing; using Robust.Shared.Timing;
@@ -15,6 +17,7 @@ public sealed class ActionOnInteractSystem : EntitySystem
[Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly SharedActionsSystem _actions = default!;
[Dependency] private readonly ActionContainerSystem _actionContainer = default!; [Dependency] private readonly ActionContainerSystem _actionContainer = default!;
[Dependency] private readonly SharedChargesSystem _charges = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -54,6 +57,9 @@ public sealed class ActionOnInteractSystem : EntitySystem
if (options.Count == 0) if (options.Count == 0)
return; return;
if (!TryUseCharge((uid, component)))
return;
var (actId, act) = _random.Pick(options); var (actId, act) = _random.Pick(options);
_actions.PerformAction(args.User, null, actId, act, act.Event, _timing.CurTime, false); _actions.PerformAction(args.User, null, actId, act, act.Event, _timing.CurTime, false);
args.Handled = true; args.Handled = true;
@@ -85,6 +91,9 @@ public sealed class ActionOnInteractSystem : EntitySystem
if (entOptions.Count > 0) if (entOptions.Count > 0)
{ {
if (!TryUseCharge((uid, component)))
return;
var (entActId, entAct) = _random.Pick(entOptions); var (entActId, entAct) = _random.Pick(entOptions);
if (entAct.Event != null) if (entAct.Event != null)
{ {
@@ -108,6 +117,9 @@ public sealed class ActionOnInteractSystem : EntitySystem
if (entWorldOptions.Count > 0) if (entWorldOptions.Count > 0)
{ {
if (!TryUseCharge((uid, component)))
return;
var (entActId, entAct) = _random.Pick(entWorldOptions); var (entActId, entAct) = _random.Pick(entWorldOptions);
if (entAct.Event != null) if (entAct.Event != null)
{ {
@@ -132,6 +144,9 @@ public sealed class ActionOnInteractSystem : EntitySystem
if (options.Count == 0) if (options.Count == 0)
return; return;
if (!TryUseCharge((uid, component)))
return;
var (actId, act) = _random.Pick(options); var (actId, act) = _random.Pick(options);
if (act.Event != null) if (act.Event != null)
{ {
@@ -163,4 +178,17 @@ public sealed class ActionOnInteractSystem : EntitySystem
return valid; return valid;
} }
private bool TryUseCharge(Entity<ActionOnInteractComponent> ent)
{
if (!ent.Comp.RequiresCharge)
return true;
Entity<LimitedChargesComponent?> charges = ent.Owner;
if (_charges.IsEmpty(charges))
return false;
_charges.TryUseCharge(charges);
return true;
}
} }

View File

@@ -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<ReagentData>? data)
{
var spillSystem = entityManager.System<PuddleSystem>();
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;
}
}
}

View File

@@ -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<ReagentData>? data)
{
var spillSystem = entityManager.System<PuddleSystem>();
return spillSystem.TrySpillAt(tile, new Solution(reagent.ID, reactVolume, data), out _, sound: false, tileReact: false)
? reactVolume
: FixedPoint2.Zero;
}
}
}

View File

@@ -232,6 +232,9 @@ public sealed class NPCUtilitySystem : EntitySystem
{ {
if (_container.TryGetContainingContainer(targetUid, out var container)) if (_container.TryGetContainingContainer(targetUid, out var container))
{ {
if (container.Owner == owner)
return 0f;
if (TryComp<EntityStorageComponent>(container.Owner, out var storageComponent)) if (TryComp<EntityStorageComponent>(container.Owner, out var storageComponent))
{ {
if (storageComponent is { Open: false } && _weldable.IsWelded(container.Owner)) if (storageComponent is { Open: false } && _weldable.IsWelded(container.Owner))

View File

@@ -55,7 +55,6 @@ public sealed class RingerSystem : SharedRingerSystem
/// </summary> /// </summary>
private void OnGenerateUplinkCode(Entity<RingerUplinkComponent> ent, ref GenerateUplinkCodeEvent ev) private void OnGenerateUplinkCode(Entity<RingerUplinkComponent> ent, ref GenerateUplinkCodeEvent ev)
{ {
// Generate a new uplink code
var code = GenerateRingtone(); var code = GenerateRingtone();
// Set the code on the component // Set the code on the component
@@ -74,6 +73,10 @@ public sealed class RingerSystem : SharedRingerSystem
if (!HasComp<StoreComponent>(uid)) if (!HasComp<StoreComponent>(uid))
return false; return false;
// Wasn't generated yet
if (uplink.Code is null)
return false;
// On the server, we always check if the code matches // On the server, we always check if the code matches
if (!uplink.Code.SequenceEqual(ringtone)) if (!uplink.Code.SequenceEqual(ringtone))
return false; return false;

View File

@@ -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 _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(); var ev = new AnimateSpellEvent();
RaiseLocalEvent(ref ev); RaiseLocalEvent(ent, ref ev);
} }
} }

View File

@@ -14,7 +14,7 @@ public sealed partial class RingerUplinkComponent : Component
/// Set via GenerateUplinkCodeEvent. /// Set via GenerateUplinkCodeEvent.
/// </summary> /// </summary>
[DataField] [DataField]
public Note[] Code = new Note[SharedRingerSystem.RingtoneLength]; public Note[]? Code;
/// <summary> /// <summary>
/// Whether to show the toggle uplink button in PDA settings. /// Whether to show the toggle uplink button in PDA settings.

View File

@@ -45,8 +45,8 @@ public abstract class SharedRingerSystem : EntitySystem
/// <inheritdoc/> /// <inheritdoc/>
public override void Update(float frameTime) public override void Update(float frameTime)
{ {
var ringerQuery = EntityQueryEnumerator<RingerComponent>(); var ringerQuery = EntityQueryEnumerator<RingerComponent, TransformComponent>();
while (ringerQuery.MoveNext(out var uid, out var ringer)) while (ringerQuery.MoveNext(out var uid, out var ringer, out var xform))
{ {
if (!ringer.Active || !ringer.NextNoteTime.HasValue) if (!ringer.Active || !ringer.NextNoteTime.HasValue)
continue; continue;
@@ -63,10 +63,9 @@ public abstract class SharedRingerSystem : EntitySystem
// and play it separately with PlayLocal, so that it's actually predicted // and play it separately with PlayLocal, so that it's actually predicted
if (_net.IsServer) if (_net.IsServer)
{ {
var ringerXform = Transform(uid);
_audio.PlayEntity( _audio.PlayEntity(
GetSound(ringer.Ringtone[ringer.NoteCount]), GetSound(ringer.Ringtone[ringer.NoteCount]),
Filter.Empty().AddInRange(_xform.GetMapCoordinates(uid, ringerXform), ringer.Range), Filter.Empty().AddInRange(_xform.GetMapCoordinates(uid, xform), ringer.Range),
uid, uid,
true, true,
AudioParams.Default.WithMaxDistance(ringer.Range).WithVolume(ringer.Volume) AudioParams.Default.WithMaxDistance(ringer.Range).WithVolume(ringer.Volume)
@@ -257,14 +256,6 @@ public abstract class SharedRingerSystem : EntitySystem
return true; return true;
} }
/// <summary>
/// Helper method to determine if the mind is an antagonist.
/// </summary>
protected bool IsAntagonist(EntityUid? user)
{
return user != null && _mind.TryGetMind(user.Value, out var mindId, out _) && _role.MindIsAntagonist(mindId);
}
/// <summary> /// <summary>
/// Gets the sound path for a specific note. /// Gets the sound path for a specific note.
/// </summary> /// </summary>

View File

@@ -3,14 +3,12 @@
name: Animate name: Animate
description: Bring an inanimate object to life! description: Bring an inanimate object to life!
components: components:
- type: LimitedCharges
maxCharges: 5
- type: EntityTargetAction - type: EntityTargetAction
useDelay: 0 useDelay: 0
itemIconStyle: BigAction itemIconStyle: BigAction
whitelist: whitelist:
components: 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: blacklist:
components: components:
- MindContainer - MindContainer
@@ -19,7 +17,7 @@
- AnomalyGenerator - AnomalyGenerator
- TegGenerator - TegGenerator
- TegCirculator - TegCirculator
- Artifact - XenoArtifact
canTargetSelf: false canTargetSelf: false
interactOnMiss: false interactOnMiss: false
sound: !type:SoundPathSpecifier sound: !type:SoundPathSpecifier
@@ -70,9 +68,11 @@
collection: MetalBreak collection: MetalBreak
- type: Hands - type: Hands
- type: CanEscapeInventory - type: CanEscapeInventory
- type: MobCollision
toRemove: toRemove:
- RequireProjectileTarget - RequireProjectileTarget
- BlockMovement - BlockMovement
- Item - Item
- MeleeRequiresWield
speech: action-speech-spell-animate speech: action-speech-spell-animate
doSpeech: false doSpeech: false

View File

@@ -7,6 +7,10 @@
name: RGB staff name: RGB staff
description: Helps fix the underabundance of RGB gear on the station. description: Helps fix the underabundance of RGB gear on the station.
components: components:
- type: LimitedCharges
maxCharges: 25
- type: AutoRecharge
rechargeDuration: 30
- type: Sprite - type: Sprite
sprite: Objects/Weapons/Guns/Basic/staves.rsi sprite: Objects/Weapons/Guns/Basic/staves.rsi
layers: layers:
@@ -14,6 +18,7 @@
- state: nothing-unshaded - state: nothing-unshaded
shader: unshaded shader: unshaded
- type: ActionOnInteract - type: ActionOnInteract
requiresCharge: true
actions: actions:
- ActionRgbLight - ActionRgbLight
- type: Item - type: Item
@@ -38,11 +43,16 @@
name: staff of animation name: staff of animation
description: Brings inanimate objects to life! description: Brings inanimate objects to life!
components: components:
- type: LimitedCharges
maxCharges: 5
- type: AutoRecharge
rechargeDuration: 30
- type: Sprite - type: Sprite
sprite: Objects/Weapons/Guns/Basic/staves.rsi sprite: Objects/Weapons/Guns/Basic/staves.rsi
layers: layers:
- state: animation - state: animation
- type: ActionOnInteract - type: ActionOnInteract
requiresCharge: true
actions: actions:
- ActionAnimateSpell - ActionAnimateSpell
- type: Item - type: Item
@@ -59,8 +69,6 @@
- type: entity - type: entity
id: ActionRgbLight id: ActionRgbLight
components: components:
- type: LimitedCharges
maxCharges: 25
- type: EntityTargetAction - type: EntityTargetAction
whitelist: { components: [ PointLight ] } whitelist: { components: [ PointLight ] }
sound: /Audio/Magic/blink.ogg sound: /Audio/Magic/blink.ogg

View File

@@ -19,6 +19,7 @@
amount: 1 amount: 1
tileReactions: tileReactions:
- !type:ExtinguishTileReaction { } - !type:ExtinguishTileReaction { }
- !type:SpillIfPuddlePresentTileReaction { }
- type: reagent - type: reagent
id: BaseSoda id: BaseSoda

View File

@@ -175,6 +175,8 @@
recognizable: true recognizable: true
physicalDesc: reagent-physical-desc-sticky physicalDesc: reagent-physical-desc-sticky
viscosity: 0.55 #Start using syrup to attach your remote recievers to your microwaves! viscosity: 0.55 #Start using syrup to attach your remote recievers to your microwaves!
tileReactions:
- !type:SpillTileReaction
metabolisms: metabolisms:
Food: Food:
# 12 diona blood for 1 unit of syrup, this stuff better be worthwhile. # 12 diona blood for 1 unit of syrup, this stuff better be worthwhile.

View File

@@ -66,6 +66,8 @@
recognizable: true recognizable: true
physicalDesc: reagent-physical-desc-viscous physicalDesc: reagent-physical-desc-viscous
viscosity: 0.25 viscosity: 0.25
tileReactions:
- !type:SpillTileReaction
metabolisms: metabolisms:
Food: Food:
# Delicious! # Delicious!
@@ -87,6 +89,8 @@
recognizable: true recognizable: true
physicalDesc: reagent-physical-desc-sticky physicalDesc: reagent-physical-desc-sticky
viscosity: 0.10 viscosity: 0.10
tileReactions:
- !type:SpillTileReaction
metabolisms: metabolisms:
Food: Food:
# Sweet! # Sweet!

View File

@@ -77,6 +77,8 @@
recognizable: true recognizable: true
boilingPoint: 290.0 # Glycerin boilingPoint: 290.0 # Glycerin
meltingPoint: 18.2 meltingPoint: 18.2
tileReactions:
- !type:SpillTileReaction
friction: 0.0 friction: 0.0
- type: reagent - type: reagent
@@ -88,6 +90,8 @@
color: "#ffffff" color: "#ffffff"
boilingPoint: 250.0 boilingPoint: 250.0
meltingPoint: 380.0 meltingPoint: 380.0
tileReactions:
- !type:SpillTileReaction
viscosity: 0.5 viscosity: 0.5
reactiveEffects: reactiveEffects:
Acidic: Acidic: