Adding a random gate (#41627)

* Added random gate

* minor edit

* cleaning up my shit after trying to do something faster

* new lines

* some changes

* joke

* UI

* Long Division

* Dont use ctrl + x in 3 am

* I hope these are the final touches

* One thing, I don't know why

* noname commit

* no way, 1kk of code lines edit

* sudo rm -rf ... and something there...

* update

* sometimes its sad
This commit is contained in:
Borsh
2025-12-14 22:15:22 +03:00
committed by GitHub
parent c5148750d5
commit 6fc13a5875
16 changed files with 283 additions and 1 deletions

View File

@@ -0,0 +1,5 @@
using Content.Shared.DeviceLinking.Systems;
namespace Content.Client.DeviceLinking.Systems;
public sealed class RandomGateSystem : SharedRandomGateSystem;

View File

@@ -0,0 +1,37 @@
using Content.Shared.DeviceLinking;
using JetBrains.Annotations;
using Robust.Client.UserInterface;
namespace Content.Client.DeviceLinking.UI;
[UsedImplicitly]
public sealed class RandomGateBoundUserInterface : BoundUserInterface
{
private RandomGateSetupWindow? _window;
public RandomGateBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { }
protected override void Open()
{
base.Open();
_window = this.CreateWindow<RandomGateSetupWindow>();
_window.OnApplyPressed += OnProbabilityChanged;
}
private void OnProbabilityChanged(string value)
{
if (!float.TryParse(value, out var probability))
return;
SendPredictedMessage(new RandomGateProbabilityChangedMessage(probability));
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
if (state is not RandomGateBoundUserInterfaceState castState || _window == null)
return;
_window.SetProbability(castState.SuccessProbability * 100);
}
}

View File

@@ -0,0 +1,19 @@
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Title="{Loc 'random-gate-menu-setup'}"
MinSize="260 115">
<BoxContainer Orientation="Vertical" Margin="5" SeparationOverride="10">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<Label Text="{Loc 'random-gate-menu-settings'}" VerticalAlignment="Center" />
<Control HorizontalExpand="True" />
<LineEdit Name="ProbabilityInput" MinSize="70 0" />
</BoxContainer>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<Control HorizontalExpand="True" />
<Button Name="ApplyButton"
Text="{Loc 'random-gate-menu-apply'}"
HorizontalAlignment="Right" />
</BoxContainer>
</BoxContainer>
</controls:FancyWindow>

View File

@@ -0,0 +1,28 @@
using Content.Client.UserInterface.Controls;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.DeviceLinking.UI;
/// <summary>
/// Window for setting up the random gate probability.
/// </summary>
[GenerateTypedNameReferences]
public sealed partial class RandomGateSetupWindow : FancyWindow
{
/// <summary>
/// Event triggered when the "Apply" button is pressed.
/// </summary>
public event Action<string>? OnApplyPressed;
public RandomGateSetupWindow()
{
RobustXamlLoader.Load(this);
ApplyButton.OnPressed += _ => OnApplyPressed?.Invoke(ProbabilityInput.Text);
}
public void SetProbability(float probability)
{
ProbabilityInput.Text = probability.ToString("0.00");
}
}

View File

@@ -0,0 +1,32 @@
using Content.Shared.DeviceLinking.Components;
using Content.Shared.DeviceLinking.Events;
using Content.Shared.DeviceLinking.Systems;
using Robust.Shared.Random;
namespace Content.Server.DeviceLinking.Systems;
public sealed class RandomGateSystem : SharedRandomGateSystem
{
[Dependency] private readonly DeviceLinkSystem _deviceLink = default!;
[Dependency] private readonly IRobustRandom _random = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<RandomGateComponent, SignalReceivedEvent>(OnSignalReceived);
}
private void OnSignalReceived(Entity<RandomGateComponent> ent, ref SignalReceivedEvent args)
{
if (args.Port != ent.Comp.InputPort)
return;
var output = _random.Prob(ent.Comp.SuccessProbability);
if (output != ent.Comp.LastOutput)
{
ent.Comp.LastOutput = output;
Dirty(ent);
_deviceLink.SendSignal(ent.Owner, ent.Comp.OutputPort, output);
}
}
}

View File

@@ -0,0 +1,35 @@
using Robust.Shared.Prototypes;
using Robust.Shared.GameStates;
namespace Content.Shared.DeviceLinking.Components;
/// <summary>
/// A component for a random gate, which outputs a signal with a given probability.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class RandomGateComponent : Component
{
/// <summary>
/// The input port for receiving signals.
/// </summary>
[DataField]
public ProtoId<SinkPortPrototype> InputPort = "RandomGateInput";
/// <summary>
/// The output port for sending signals.
/// </summary>
[DataField]
public ProtoId<SourcePortPrototype> OutputPort = "Output";
/// <summary>
/// The last output state of the gate.
/// </summary>
[DataField, AutoNetworkedField]
public bool LastOutput;
/// <summary>
/// The probability (0.0 to 1.0) that the gate will output a signal.
/// </summary>
[DataField, AutoNetworkedField]
public float SuccessProbability = 0.5f;
}

View File

@@ -0,0 +1,21 @@
using Robust.Shared.Serialization;
namespace Content.Shared.DeviceLinking;
[Serializable, NetSerializable]
public sealed class RandomGateBoundUserInterfaceState(float successProbability) : BoundUserInterfaceState
{
public float SuccessProbability = successProbability;
}
[Serializable, NetSerializable]
public sealed class RandomGateProbabilityChangedMessage(float probability) : BoundUserInterfaceMessage
{
public float Probability = probability;
}
[Serializable, NetSerializable]
public enum RandomGateUiKey : byte
{
Key
}

View File

@@ -0,0 +1,35 @@
using Content.Shared.DeviceLinking.Components;
using Content.Shared.UserInterface;
namespace Content.Shared.DeviceLinking.Systems;
public abstract class SharedRandomGateSystem : EntitySystem
{
[Dependency] private readonly SharedUserInterfaceSystem _ui = default!;
public override void Initialize()
{
SubscribeLocalEvent<RandomGateComponent, AfterActivatableUIOpenEvent>(OnAfterActivatableUIOpen);
SubscribeLocalEvent<RandomGateComponent, RandomGateProbabilityChangedMessage>(OnProbabilityChanged);
}
private void OnAfterActivatableUIOpen(Entity<RandomGateComponent> ent, ref AfterActivatableUIOpenEvent args)
{
UpdateUI(ent);
}
private void OnProbabilityChanged(Entity<RandomGateComponent> ent, ref RandomGateProbabilityChangedMessage args)
{
ent.Comp.SuccessProbability = Math.Clamp(args.Probability, 0f, 100f) / 100f;
Dirty(ent);
UpdateUI(ent);
}
private void UpdateUI(Entity<RandomGateComponent> ent)
{
if (!_ui.HasUi(ent.Owner, RandomGateUiKey.Key))
return;
_ui.SetUiState(ent.Owner, RandomGateUiKey.Key, new RandomGateBoundUserInterfaceState(ent.Comp.SuccessProbability));
}
}

View File

@@ -0,0 +1,3 @@
random-gate-menu-settings = Success Probability (%):
random-gate-menu-setup = Random Gate Setup
random-gate-menu-apply = Apply

View File

@@ -86,3 +86,6 @@ signal-port-description-logic-memory-input = Signal to load into the memory cell
signal-port-name-logic-enable = Enable
signal-port-description-logic-enable = Only loads the input signal into the memory cell when HIGH.
signal-port-name-logic-random-input = Input Signal
signal-port-description-logic-random-input = Receives any signal to trigger a random output.

View File

@@ -108,6 +108,11 @@
name: signal-port-name-logic-enable
description: signal-port-description-logic-enable
- type: sinkPort
id: RandomGateInput
name: signal-port-name-logic-random-input
description: signal-port-description-logic-random-input
- type: sinkPort
id: SetParticleDelta
name: signal-port-name-set-particle-delta

View File

@@ -291,3 +291,29 @@
- Output
- type: Construction
node: memory_cell
- type: entity
parent: BaseLogicItem
id: RandomGate
name: random gate
description: A logic gate that outputs a random signal when input changes.
components:
- type: Sprite
layers:
- state: base
- state: random_gate
- type: RandomGate
- type: DeviceLinkSink
ports:
- RandomGateInput
- type: DeviceLinkSource
ports:
- Output
- type: UserInterface
interfaces:
enum.RandomGateUiKey.Key:
type: RandomGateBoundUserInterface
- type: ActivatableUI
key: enum.RandomGateUiKey.Key
- type: Construction
node: random_gate

View File

@@ -51,6 +51,14 @@
- material: Cable
amount: 2
doAfter: 1
- to: random_gate
steps:
- material: MetalRod
amount: 1
doAfter: 1
- material: Cable
amount: 1
doAfter: 1
- node: logic_gate
entity: LogicGateOr
edges:
@@ -102,3 +110,17 @@
- !type:SpawnPrototype
prototype: CableApcStack1
amount: 2
- node: random_gate
entity: RandomGate
edges:
- to: empty
steps:
- tool: Prying
doAfter: 2
completed:
- !type:SpawnPrototype
prototype: CableApcStack1
amount: 1
- !type:SpawnPrototype
prototype: PartRodMetal1
amount: 1

View File

@@ -37,3 +37,11 @@
targetNode: memory_cell
category: construction-category-tools
objectType: Item
- type: construction
id: RandomGate
graph: LogicGate
startNode: start
targetNode: random_gate
category: construction-category-tools
objectType: Item

View File

@@ -1,7 +1,7 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "or.png originally created by Kevin Zheng, 2022. All are modified by deltanedas (github) for SS14, 2024. Sprites logic_a logic_b logic_o were made by 0tito (github) for SS14",
"copyright": "or.png originally created by Kevin Zheng, 2022. All are modified by deltanedas (github) for SS14, 2024. Sprites logic_a logic_b logic_o were made by 0tito (github) for SS14. 2025, added random_gate.png by borsh.",
"size": {
"x": 32,
"y": 32
@@ -51,6 +51,9 @@
},
{
"name": "memory_cell"
},
{
"name": "random_gate"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B