Add PDA Ringtones (#5842)

Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
TheDarkElites
2022-02-08 04:39:23 -05:00
committed by GitHub
parent b499ef61b0
commit 8c47d6103f
29 changed files with 590 additions and 2 deletions

View File

@@ -134,6 +134,7 @@ namespace Content.Client.Entry
"Airtight",
"MovedByPressure",
"Spray",
"Ringer",
"Vapor",
"AddAccentClothing",
"DamageOnHighSpeedImpact",

View File

@@ -48,6 +48,11 @@ namespace Content.Client.PDA
SendMessage(new PDAShowUplinkMessage());
};
_menu.AccessRingtoneButton.OnPressed += _ =>
{
SendMessage(new PDAShowRingtoneMessage());
};
}
protected override void UpdateState(BoundUserInterfaceState state)

View File

@@ -1,7 +1,7 @@
<DefaultWindow xmlns="https://spacestation14.io"
Title="{Loc 'comp-pda-ui-menu-title'}"
MinSize="512 256"
SetSize="512 256">
MinSize="576 256"
SetSize="576 256">
<TabContainer Name="MasterTabContainer">
<BoxContainer Orientation="Vertical"
VerticalExpand="True"
@@ -23,6 +23,11 @@
Text="{Loc 'comp-pda-ui-eject-pen-button'}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<Button Name="AccessRingtoneButton"
Access="Public"
Text="{Loc 'comp-pda-ui-ringtone-button'}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</BoxContainer>
</PanelContainer>
<Button Name="FlashLightToggleButton"

View File

@@ -0,0 +1,111 @@
using System;
using Content.Client.Message;
using Content.Shared.PDA;
using Content.Shared.PDA.Ringer;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Localization;
namespace Content.Client.PDA.Ringer
{
[UsedImplicitly]
public sealed class RingerBoundUserInterface : BoundUserInterface
{
private RingtoneMenu? _menu;
public RingerBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
_menu = new RingtoneMenu();
_menu.OpenToLeft();
_menu.OnClose += Close;
_menu.TestRingerButton.OnPressed += _ =>
{
SendMessage(new RingerPlayRingtoneMessage());
};
_menu.SetRingerButton.OnPressed += _ =>
{
if (!TryGetRingtone(out var ringtone)) return;
SendMessage(new RingerSetRingtoneMessage(ringtone));
};
}
private bool TryGetRingtone(out Note[] ringtone)
{
if (_menu == null)
{
ringtone = Array.Empty<Note>();
return false;
}
ringtone = new Note[4];
if (!Enum.TryParse<Note>(_menu.RingerNoteOneInput.Text.Replace("#", "sharp"), false, out var one)) return false;
ringtone[0] = one;
if (!Enum.TryParse<Note>(_menu.RingerNoteTwoInput.Text.Replace("#", "sharp"), false, out var two)) return false;
ringtone[1] = two;
if (!Enum.TryParse<Note>(_menu.RingerNoteThreeInput.Text.Replace("#", "sharp"), false, out var three)) return false;
ringtone[2] = three;
if (!Enum.TryParse<Note>(_menu.RingerNoteFourInput.Text.Replace("#", "sharp"), false, out var four)) return false;
ringtone[3] = four;
return true;
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
if (_menu == null)
{
return;
}
switch (state)
{
case RingerUpdateState msg:
{
var noteOne = msg.Ringtone[0].ToString();
var noteTwo = msg.Ringtone[1].ToString();
var noteThree = msg.Ringtone[2].ToString();
var noteFour = msg.Ringtone[3].ToString();
if (RingtoneMenu.IsNote(noteOne))
_menu.RingerNoteOneInput.Text = noteOne.Replace("sharp", "#");
if (RingtoneMenu.IsNote(noteTwo))
_menu.RingerNoteTwoInput.Text = noteTwo.Replace("sharp", "#");
if (RingtoneMenu.IsNote(noteThree))
_menu.RingerNoteThreeInput.Text = noteThree.Replace("sharp", "#");
if (RingtoneMenu.IsNote(noteFour))
_menu.RingerNoteFourInput.Text = noteFour.Replace("sharp", "#");
_menu.TestRingerButton.Visible = !msg.IsPlaying;
break;
}
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_menu?.Dispose();
}
}
}

View File

@@ -0,0 +1,73 @@
<SS14Window xmlns="https://spacestation14.io"
Title="{Loc 'comp-ringer-ui-menu-title'}"
MinSize="256 128"
SetSize="256 128">
<BoxContainer Orientation="Vertical"
VerticalExpand="True"
HorizontalExpand="True"
HorizontalAlignment="Center"
MinSize="50 50">
<PanelContainer>
<BoxContainer Orientation="Horizontal"
VerticalExpand="True"
HorizontalExpand="True"
HorizontalAlignment="Center"
MinSize="120 0">
<Label Name = "Indent_0Label"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="♪" />
<LineEdit Name ="RingerNoteOneInput"
Access="Public"
MinSize="40 0"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<Label Name = "Indent_1Label"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="-" />
<LineEdit Name ="RingerNoteTwoInput"
Access="Public"
MinSize="40 0"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<Label Name = "Indent_2Label"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="-" />
<LineEdit Name ="RingerNoteThreeInput"
Access="Public"
MinSize="40 0"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<Label Name = "Indent_3Label"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="-" />
<LineEdit Name ="RingerNoteFourInput"
Access="Public"
MinSize="40 0"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</BoxContainer>
</PanelContainer>
<PanelContainer>
<BoxContainer Orientation="Horizontal"
VerticalExpand="True"
HorizontalExpand="True"
HorizontalAlignment="Center"
MinSize="120 50">
<Button Name = "TestRingerButton"
Access="Public"
Text="{Loc 'comp-ringer-ui-test-ringtone-button'}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<Button Name = "SetRingerButton"
Access="Public"
Text="{Loc 'comp-ringer-ui-set-ringtone-button'}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</BoxContainer>
</PanelContainer>
</BoxContainer>
</SS14Window>

View File

@@ -0,0 +1,105 @@
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Maths;
using System;
using Content.Client;
using Content.Shared.PDA;
namespace Content.Client.PDA.Ringer
{
[GenerateTypedNameReferences]
public sealed partial class RingtoneMenu : SS14Window
{
private string[] _previousNoteInputs = new string[4];
public RingtoneMenu()
{
RobustXamlLoader.Load(this);
//RingerNoteOneInput
RingerNoteOneInput.OnTextChanged += _ => //Prevents unauthorized characters from being entered into the LineEdit
{
RingerNoteOneInput.Text = RingerNoteOneInput.Text.ToUpper();
if(!IsNote(RingerNoteOneInput.Text))
{
RingerNoteOneInput.Text = _previousNoteInputs[0];
}
else
{
_previousNoteInputs[0] = RingerNoteOneInput.Text;
}
RingerNoteOneInput.CursorPosition = RingerNoteOneInput.Text.Length; //Resets caret position to the end of the typed input
};
//RingerNoteTwoInput
RingerNoteTwoInput.OnTextChanged += _ => //Prevents unauthorized characters from being entered into the LineEdit
{
RingerNoteTwoInput.Text = RingerNoteTwoInput.Text.ToUpper();
if(!IsNote(RingerNoteTwoInput.Text))
{
RingerNoteTwoInput.Text = _previousNoteInputs[1];
}
else
{
_previousNoteInputs[1] = RingerNoteTwoInput.Text;
}
RingerNoteTwoInput.CursorPosition = RingerNoteTwoInput.Text.Length; //Resets caret position to the end of the typed input
};
//RingerNoteThreeInput
RingerNoteThreeInput.OnTextChanged += _ => //Prevents unauthorized characters from being entered into the LineEdit
{
RingerNoteThreeInput.Text = RingerNoteThreeInput.Text.ToUpper();
if(!IsNote(RingerNoteThreeInput.Text))
{
RingerNoteThreeInput.Text = _previousNoteInputs[2];
}
else
{
_previousNoteInputs[2] = RingerNoteThreeInput.Text;
}
RingerNoteThreeInput.CursorPosition = RingerNoteThreeInput.Text.Length; //Resets caret position to the end of the typed input
};
//RingerNoteFourInput
RingerNoteFourInput.OnTextChanged += _ => //Prevents unauthorized characters from being entered into the LineEdit
{
RingerNoteFourInput.Text = RingerNoteFourInput.Text.ToUpper();
if(!IsNote(RingerNoteFourInput.Text))
{
RingerNoteFourInput.Text = _previousNoteInputs[3];
}
else
{
_previousNoteInputs[3] = RingerNoteFourInput.Text;
}
RingerNoteFourInput.CursorPosition = RingerNoteFourInput.Text.Length; //Resets caret position to the end of the typed input
};
}
protected override DragMode GetDragModeFor(Vector2 relativeMousePos)
{
//Prevents the ringtone window from being resized
return DragMode.Move;
}
/// <summary>
/// Determines whether or not the characters inputed are authorized
/// </summary>
public static bool IsNote(string input)
{
input = input.Replace("#", "sharp");
return Enum.TryParse(input, true, out Note _);
}
}
}

View File

@@ -4,6 +4,7 @@ using Content.Server.Light.Events;
using Content.Server.Traitor.Uplink;
using Content.Server.Traitor.Uplink.Account;
using Content.Server.Traitor.Uplink.Components;
using Content.Server.PDA.Ringer;
using Content.Server.UserInterface;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Interaction;
@@ -20,6 +21,7 @@ namespace Content.Server.PDA
[Dependency] private readonly UplinkSystem _uplinkSystem = default!;
[Dependency] private readonly UplinkAccountsSystem _uplinkAccounts = default!;
[Dependency] private readonly UnpoweredFlashlightSystem _unpoweredFlashlight = default!;
[Dependency] private readonly RingerSystem _ringerSystem = default!;
public override void Initialize()
{
@@ -38,6 +40,13 @@ namespace Content.Server.PDA
ui.OnReceiveMessage += (msg) => OnUIMessage(pda, msg);
}
private void OnUse(EntityUid uid, PDAComponent pda, UseInHandEvent args)
{
if (args.Handled)
return;
args.Handled = OpenUI(pda, args.User);
}
private void OnActivateInWorld(EntityUid uid, PDAComponent pda, ActivateInWorldEvent args)
{
if (args.Handled)
@@ -175,6 +184,12 @@ namespace Content.Server.PDA
_uplinkSystem.ToggleUplinkUI(uplink, msg.Session);
break;
}
case PDAShowRingtoneMessage _:
{
if (EntityManager.TryGetComponent(pda.Owner, out RingerComponent? ringer))
_ringerSystem.ToggleRingerUI(ringer, msg.Session);
break;
}
}
}
}

View File

@@ -0,0 +1,27 @@
using Content.Shared.PDA;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Content.Server.PDA.Ringer
{
[RegisterComponent, ComponentProtoName("Ringer")]
public sealed class RingerComponent : Component
{
[ViewVariables]
[DataField("ringtone")]
public Note[] Ringtone = new Note[SharedRingerSystem.RingtoneLength];
[DataField("timeElapsed")]
public float TimeElapsed = 0;
/// <summary>
/// Keeps track of how many notes have elapsed if the ringer component is playing.
/// </summary>
[DataField("noteCount")]
public int NoteCount = 0;
[DataField("isPlaying")]
public bool IsPlaying = false;
}
}

View File

@@ -0,0 +1,136 @@
using Content.Server.UserInterface;
using Content.Shared.PDA.Ringer;
using Robust.Shared.GameObjects;
using Robust.Shared.Audio;
using Robust.Server.Player;
using Robust.Shared.Player;
using System;
using System.Collections.Generic;
using Content.Shared.Audio;
using Content.Shared.PDA;
using Content.Shared.Sound;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Utility;
namespace Content.Server.PDA.Ringer
{
public sealed class RingerSystem : SharedRingerSystem
{
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly IRobustRandom _random = default!;
public override void Initialize()
{
base.Initialize();
// General Event Subscriptions
SubscribeLocalEvent<RingerComponent, ComponentInit>(RandomizeRingtone);
// RingerBoundUserInterface Subscriptions
SubscribeLocalEvent<RingerComponent, RingerSetRingtoneMessage>(OnSetRingtone);
SubscribeLocalEvent<RingerComponent, RingerPlayRingtoneMessage>(RingerPlayRingtone);
SubscribeLocalEvent<RingerComponent, RingerRequestUpdateInterfaceMessage>(UpdateRingerUserInterfaceDriver);
}
//Event Functions
private void RingerPlayRingtone(EntityUid uid, RingerComponent ringer, RingerPlayRingtoneMessage args)
{
ringer.IsPlaying = true;
UpdateRingerUserInterface(ringer);
}
private void UpdateRingerUserInterfaceDriver(EntityUid uid, RingerComponent ringer, RingerRequestUpdateInterfaceMessage args)
{
UpdateRingerUserInterface(ringer);
}
private void OnSetRingtone(EntityUid uid, RingerComponent ringer, RingerSetRingtoneMessage args)
{
// Client sent us an updated ringtone so set it to that.
if (args.Ringtone.Length != RingtoneLength) return;
UpdateRingerRingtone(ringer, args.Ringtone);
}
public void RandomizeRingtone(EntityUid uid, RingerComponent ringer, ComponentInit args)
{
// Default to using C pentatonic so it at least sounds not terrible.
var notes = new[]
{
Note.C,
Note.D,
Note.E,
Note.G,
Note.A,
};
var ringtone = new Note[RingtoneLength];
for (var i = 0; i < 4; i++)
{
ringtone[i] = _random.Pick(notes);
}
UpdateRingerRingtone(ringer, ringtone);
}
//Non Event Functions
private bool UpdateRingerRingtone(RingerComponent ringer, Note[] ringtone)
{
// Assume validation has already happened.
ringer.Ringtone = ringtone;
UpdateRingerUserInterface(ringer);
return true;
}
private void UpdateRingerUserInterface(RingerComponent ringer)
{
var ui = ringer.Owner.GetUIOrNull(RingerUiKey.Key);
ui?.SetState(new RingerUpdateState(ringer.IsPlaying, ringer.Ringtone));
}
public bool ToggleRingerUI(RingerComponent ringer, IPlayerSession session)
{
var ui = ringer.Owner.GetUIOrNull(RingerUiKey.Key);
ui?.Toggle(session);
return true;
}
public override void Update(float frameTime) //Responsible for actually playing the ringtone
{
foreach(var ringer in EntityManager.EntityQuery<RingerComponent>())
{
// If this is perf problem then something something custom tracking via hashset.
if (!ringer.IsPlaying)
continue;
ringer.TimeElapsed += frameTime;
if (ringer.TimeElapsed < NoteDelay) continue;
ringer.TimeElapsed -= NoteDelay;
SoundSystem.Play(Filter.Pvs(ringer.Owner, entityManager: EntityManager), GetSound(ringer.Ringtone[ringer.NoteCount]));
ringer.NoteCount++;
if (ringer.NoteCount > 3)
{
ringer.IsPlaying = false;
UpdateRingerUserInterface(ringer);
ringer.TimeElapsed = 0;
ringer.NoteCount = 0;
break;
}
}
}
private string GetSound(Note note)
{
return new ResourcePath("/Audio/Effects/RingtoneNotes/" + note.ToString().ToLower()) + ".ogg";
}
}
}

View File

@@ -30,6 +30,14 @@ namespace Content.Shared.PDA
}
}
[Serializable, NetSerializable]
public sealed class PDAShowRingtoneMessage : BoundUserInterfaceMessage
{
public PDAShowRingtoneMessage()
{
}
}
[Serializable, NetSerializable]
public sealed class PDAShowUplinkMessage : BoundUserInterfaceMessage

View File

@@ -0,0 +1,24 @@
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;
using System;
namespace Content.Shared.PDA.Ringer
{
[Serializable, NetSerializable]
public sealed class RingerRequestUpdateInterfaceMessage : BoundUserInterfaceMessage {}
[Serializable, NetSerializable]
public sealed class RingerPlayRingtoneMessage : BoundUserInterfaceMessage {}
[Serializable, NetSerializable]
public sealed class RingerSetRingtoneMessage : BoundUserInterfaceMessage
{
public Note[] Ringtone {get;}
public RingerSetRingtoneMessage(Note[] ringTone)
{
Ringtone = ringTone;
}
}
}

View File

@@ -0,0 +1,20 @@
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;
using System;
namespace Content.Shared.PDA.Ringer
{
[Serializable, NetSerializable]
public sealed class RingerUpdateState : BoundUserInterfaceState
{
public bool IsPlaying;
public Note[] Ringtone;
public RingerUpdateState(bool isPlay, Note[] ringtone)
{
IsPlaying = isPlay;
Ringtone = ringtone;
}
}
}

View File

@@ -0,0 +1,12 @@
using System;
using Robust.Shared.Serialization;
namespace Content.Shared.PDA.Ringer
{
[Serializable, NetSerializable]
public enum RingerUiKey
{
Key
}
}

View File

@@ -0,0 +1,29 @@
using System;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;
namespace Content.Shared.PDA;
public abstract class SharedRingerSystem : EntitySystem
{
public const int RingtoneLength = 4;
public const int NoteTempo = 300;
public const float NoteDelay = 60f / NoteTempo;
}
[Serializable, NetSerializable]
public enum Note : byte
{
A,
Asharp,
B,
C,
Csharp,
D,
Dsharp,
E,
F,
Fsharp,
G,
Gsharp
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,12 @@
### UI
# For the PDA Ringer screen
comp-ringer-ui-menu-title = Ringtone
comp-ringer-ui-test-ringtone-button = Test
comp-ringer-ui-set-ringtone-button = Set
comp-ringer-ui = [color=yellow]♪{$RingtoneOne}-{$RingtoneTwo}-{$RingtoneThree}-{$RingtoneFour}[/color]

View File

@@ -18,4 +18,6 @@ comp-pda-ui-eject-id-button = Eject ID
comp-pda-ui-eject-pen-button = Eject Pen
comp-pda-ui-ringtone-button = Ringtone
comp-pda-ui-toggle-flashlight-button = Toggle Flashlight

View File

@@ -28,12 +28,15 @@
softness: 5
mask: /Textures/Effects/LightMasks/cone.png
autoRot: true
- type: Ringer
- type: UserInterface
interfaces:
- key: enum.PDAUiKey.Key
type: PDABoundUserInterface
- key: enum.UplinkUiKey.Key
type: UplinkBoundUserInterface
- key: enum.RingerUiKey.Key
type: RingerBoundUserInterface
- type: PDA
penSlot:
startingItem: Pen