diff --git a/Content.Client/SS220/DialogWindowDescUI/DialogWindowDesc.xaml b/Content.Client/SS220/DialogWindowDescUI/DialogWindowDesc.xaml
new file mode 100644
index 00000000000000..e60873ef950d35
--- /dev/null
+++ b/Content.Client/SS220/DialogWindowDescUI/DialogWindowDesc.xaml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/SS220/DialogWindowDescUI/DialogWindowDesc.xaml.cs b/Content.Client/SS220/DialogWindowDescUI/DialogWindowDesc.xaml.cs
new file mode 100644
index 00000000000000..05f29b4a1e39a1
--- /dev/null
+++ b/Content.Client/SS220/DialogWindowDescUI/DialogWindowDesc.xaml.cs
@@ -0,0 +1,84 @@
+// © SS220, An EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt
+using Content.Shared.Administration;
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+using Content.Client.UserInterface.Controls;
+
+namespace Content.Client.SS220.DialogWindowDescUI;
+
+///
+/// A modified window in which you can send an additional description to explain a particular action being performed
+///
+[GenerateTypedNameReferences]
+public sealed partial class DialogWindowDesc : FancyWindow
+{
+ private List<(string, LineEdit)> _promptLines;
+
+ private bool _finished;
+
+ public Action>? OnConfirmed;
+
+ public Action? OnCancelled;
+
+ public DialogWindowDesc(string title, string dsscEntty, List entries, bool ok = true)
+ {
+ RobustXamlLoader.Load(this);
+
+ Title = title;
+
+ OkButton.Visible = ok;
+
+ _promptLines = new(entries.Count);
+
+ for (int i = 0; i < entries.Count; i++)
+ {
+ var entry = entries[i];
+
+ var box = new BoxContainer();
+ box.AddChild(new Label() { Text = entry.Prompt, Align = Label.AlignMode.Center, HorizontalExpand = true});
+ Prompts.AddChild(box);
+
+ var boxDesc = new BoxContainer();
+ boxDesc.AddChild(new Label() { Text = dsscEntty, Align = Label.AlignMode.Center, FontColorOverride = Color.Gray, HorizontalExpand = true });
+ Prompts.AddChild(boxDesc);
+
+ var boxEmpty = new BoxContainer();
+ boxEmpty.AddChild(new BoxContainer() {MinHeight=20});
+ Prompts.AddChild(boxEmpty);
+
+ var boxEdit = new BoxContainer();
+ var edit = new LineEdit() { HorizontalExpand = true };
+ boxEdit.AddChild(edit);
+
+ _promptLines.Add((entry.FieldId, edit));
+ Prompts.AddChild(boxEdit);
+ }
+
+ OkButton.OnPressed += _ => Confirm();
+
+ OnClose += () =>
+ {
+ if (!_finished)
+ OnCancelled?.Invoke();
+ };
+
+ _promptLines[0].Item2.GrabKeyboardFocus();
+
+ OpenCentered();
+ }
+
+ private void Confirm()
+ {
+ var results = new Dictionary();
+ foreach (var (field, edit) in _promptLines)
+ {
+ results[field] = edit.Text;
+ }
+
+ _finished = true;
+ OnConfirmed?.Invoke(results);
+ Close();
+ }
+}
+
diff --git a/Content.Client/SS220/QuickDialog/QuickDialogSystem.cs b/Content.Client/SS220/QuickDialog/QuickDialogSystem.cs
new file mode 100644
index 00000000000000..44d9a3e3898033
--- /dev/null
+++ b/Content.Client/SS220/QuickDialog/QuickDialogSystem.cs
@@ -0,0 +1,35 @@
+// © SS220, An EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt
+using Content.Client.SS220.DialogWindowDescUI;
+using Content.Shared.Administration;
+
+namespace Content.Client.SS220.QuickDialog;
+
+public sealed class QuickDialogSystem : EntitySystem
+{
+ ///
+ public override void Initialize()
+ {
+ SubscribeNetworkEvent(OpenDialog);
+ }
+
+ private void OpenDialog(QuickDialogDescOpenEvent ev)
+ {
+ var ok = (ev.Buttons & QuickDialogButtonFlag.OkButton) != 0;
+ var window = new DialogWindowDesc(ev.Title, ev.Description, ev.Prompts, ok: ok);
+
+ window.OnConfirmed += responses =>
+ {
+ RaiseNetworkEvent(new QuickDialogResponseEvent(ev.DialogId,
+ responses,
+ QuickDialogButtonFlag.OkButton));
+ };
+
+ window.OnCancelled += () =>
+ {
+ RaiseNetworkEvent(new QuickDialogResponseEvent(ev.DialogId,
+ new(),
+ QuickDialogButtonFlag.CancelButton));
+ };
+ }
+}
+
diff --git a/Content.Server/Administration/QuickDialogSystem.OpenDialog.cs b/Content.Server/Administration/QuickDialogSystem.OpenDialog.cs
index 1bbc8a6c9e8710..399a937a9bb20d 100644
--- a/Content.Server/Administration/QuickDialogSystem.OpenDialog.cs
+++ b/Content.Server/Administration/QuickDialogSystem.OpenDialog.cs
@@ -173,4 +173,33 @@ public void OpenDialog(ICommonSession session, string title, str
cancelAction ?? (() => { })
);
}
+
+ //SS220-RenameStart - start
+ [PublicAPI]
+ public void OpenDialog(ICommonSession session, string title, string description, string prompt, Action okAction,
+ Action? cancelAction = null)
+ {
+ OpenDialogInternal(
+ session,
+ title,
+ description,
+ new List
+ {
+ new("1", TypeToEntryType(typeof(T1)), prompt)
+ },
+ QuickDialogButtonFlag.OkButton | QuickDialogButtonFlag.CancelButton,
+ (ev =>
+ {
+ if (TryParseQuickDialog(TypeToEntryType(typeof(T1)), ev.Responses["1"], out var v1))
+ okAction.Invoke(v1);
+ else
+ {
+ session.Channel.Disconnect("Replied with invalid quick dialog data.");
+ cancelAction?.Invoke();
+ }
+ }),
+ cancelAction ?? (() => { })
+ );
+ }
+ //SS220-RenameStart - end
}
diff --git a/Content.Server/Administration/QuickDialogSystem.cs b/Content.Server/Administration/QuickDialogSystem.cs
index df2953f98d19b0..d149e7e9b22b4d 100644
--- a/Content.Server/Administration/QuickDialogSystem.cs
+++ b/Content.Server/Administration/QuickDialogSystem.cs
@@ -103,6 +103,28 @@ private void OpenDialogInternal(ICommonSession session, string title, List entries, QuickDialogButtonFlag buttons, Action okAction, Action cancelAction)
+ {
+ var did = GetDialogId();
+ RaiseNetworkEvent(
+ new QuickDialogDescOpenEvent(
+ title,
+ description,
+ entries,
+ did,
+ buttons),
+ session
+ );
+
+ _openDialogs.Add(did, (okAction, cancelAction));
+ if (!_openDialogsByUser.ContainsKey(session.UserId))
+ _openDialogsByUser.Add(session.UserId, new List());
+
+ _openDialogsByUser[session.UserId].Add(did);
+ }
+ //SS220-RenameStart - end
+
private bool TryParseQuickDialog(QuickDialogEntryType entryType, string input, [NotNullWhen(true)] out T? output)
{
switch (entryType)
diff --git a/Content.Server/SS220/RenameStart/RenameStartComponent.cs b/Content.Server/SS220/RenameStart/RenameStartComponent.cs
new file mode 100644
index 00000000000000..b94ce6e94927f5
--- /dev/null
+++ b/Content.Server/SS220/RenameStart/RenameStartComponent.cs
@@ -0,0 +1,17 @@
+// © SS220, An EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt
+using Content.Shared.Preferences;
+
+namespace Content.Server.SS220.RenameStart;
+
+///
+/// This is used for change the entity name once the player starts controlling
+///
+[RegisterComponent]
+public sealed partial class RenameStartComponent : Component
+{
+ [DataField]
+ public int MinChar = 2;
+
+ [DataField]
+ public int MaxChar = HumanoidCharacterProfile.MaxNameLength;
+}
diff --git a/Content.Server/SS220/RenameStart/RenameStartSystem.cs b/Content.Server/SS220/RenameStart/RenameStartSystem.cs
new file mode 100644
index 00000000000000..b09f76a0bef94a
--- /dev/null
+++ b/Content.Server/SS220/RenameStart/RenameStartSystem.cs
@@ -0,0 +1,90 @@
+// © SS220, An EULA/CLA with a hosting restriction, full text: https://raw.githubusercontent.com/SerbiaStrong-220/space-station-14/master/CLA.txt
+using System.Text.RegularExpressions;
+using Content.Server.Administration;
+using Content.Server.Administration.Systems;
+using Content.Shared.Administration;
+using Content.Shared.Mind;
+using Content.Shared.Mind.Components;
+using Robust.Shared.Player;
+
+namespace Content.Server.SS220.RenameStart;
+
+///
+/// This handles opens the ui to change your name at the beginning of the game. Renaming is necessary for such roles as a clown with a “custom” name
+///
+public sealed class RenameStartSystem : EntitySystem
+{
+ [Dependency] private readonly QuickDialogSystem _quickDialog = default!;
+ [Dependency] private readonly MetaDataSystem _meta = default!;
+ [Dependency] private readonly AdminFrozenSystem _frozen = default!;
+ private static readonly Regex Expressions = new("[^А-Яа-яёЁ0-9' \\-?!,.]");
+ ///
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnPlayerAttached);
+ SubscribeLocalEvent(OnRemoveComponent);
+ }
+
+ private void OnPlayerAttached(Entity ent, ref PlayerAttachedEvent args)
+ {
+ _frozen.FreezeAndMute(ent.Owner); //prevent players from changing their name after showing up with their initial name
+
+ ChangeName(ent.Owner);
+ }
+
+ private void ChangeName(EntityUid entOwner)
+ {
+ if(!TryComp(entOwner, out var actorComp))
+ {
+ RemComp(entOwner);
+ return;
+ }
+
+ if(!TryComp(entOwner, out var renameComp))
+ {
+ RemComp(entOwner);
+ return;
+ }
+
+ _quickDialog.OpenDialog(actorComp.PlayerSession,
+ Loc.GetString("rename-window-title"),
+ description: Loc.GetString("rename-window-desc"),
+ Loc.GetString("rename-window-promt"),
+ (LongString newName) =>
+ {
+ if (newName.String.Length < renameComp.MinChar ||
+ newName.String.Length > renameComp.MaxChar ||
+ Expressions.IsMatch(newName.String))
+ {
+ ChangeName(entOwner);
+ return;
+ }
+
+ if(!TryComp(entOwner, out var mindContComp))
+ {
+ RemComp(entOwner);
+ return;
+ }
+
+ if (!TryComp(mindContComp.Mind, out var mindComp))
+ {
+ RemComp(entOwner);
+ return;
+ }
+
+ mindComp.CharacterName = newName.String;
+
+ _meta.SetEntityName(entOwner, newName);
+
+ RemComp(entOwner);
+ }, () =>
+ {
+ RemComp(entOwner);
+ });
+ }
+
+ private void OnRemoveComponent(Entity ent, ref ComponentShutdown args)
+ {
+ RemComp(ent.Owner);
+ }
+}
diff --git a/Content.Shared/Administration/QuickDialogOpenEvent.cs b/Content.Shared/Administration/QuickDialogOpenEvent.cs
index f4e77ab9990adb..01388e41bcff87 100644
--- a/Content.Shared/Administration/QuickDialogOpenEvent.cs
+++ b/Content.Shared/Administration/QuickDialogOpenEvent.cs
@@ -37,6 +37,46 @@ public QuickDialogOpenEvent(string title, List prompts, int di
}
}
+//SS220-RenameStart - start
+[Serializable, NetSerializable]
+public sealed class QuickDialogDescOpenEvent : EntityEventArgs
+{
+ ///
+ /// The title of the dialog.
+ ///
+ public string Title;
+
+ ///
+ /// The title of the dialog.
+ ///
+ public string Description;
+
+ ///
+ /// The internal dialog ID.
+ ///
+ public int DialogId;
+
+ ///
+ /// The prompts to show the user.
+ ///
+ public List Prompts;
+
+ ///
+ /// The buttons presented for the user.
+ ///
+ public QuickDialogButtonFlag Buttons = QuickDialogButtonFlag.OkButton | QuickDialogButtonFlag.CancelButton;
+
+ public QuickDialogDescOpenEvent(string title, string description, List prompts, int dialogId, QuickDialogButtonFlag buttons)
+ {
+ Title = title;
+ Description = description;
+ Prompts = prompts;
+ Buttons = buttons;
+ DialogId = dialogId;
+ }
+}
+//SS220-RenameStart - end
+
///
/// A networked event raised when the client replies to a quick dialog.
///
diff --git a/Resources/Locale/ru-RU/ss220/quick-dialog/quick-dialog.ftl b/Resources/Locale/ru-RU/ss220/quick-dialog/quick-dialog.ftl
new file mode 100644
index 00000000000000..094b56626380d2
--- /dev/null
+++ b/Resources/Locale/ru-RU/ss220/quick-dialog/quick-dialog.ftl
@@ -0,0 +1 @@
+quick-dialog-ui-confirm = Подтвердить
\ No newline at end of file
diff --git a/Resources/Locale/ru-RU/ss220/rename-start-window/rename-start-window.ftl b/Resources/Locale/ru-RU/ss220/rename-start-window/rename-start-window.ftl
new file mode 100644
index 00000000000000..f81c09034112f6
--- /dev/null
+++ b/Resources/Locale/ru-RU/ss220/rename-start-window/rename-start-window.ftl
@@ -0,0 +1,7 @@
+rename-window-title = Переименование
+rename-window-promt = Выберите свое новое имя
+rename-window-desc =
+ Ваше имя не должно нарушать 4 пункт правил:
+ Ваш персонаж - находится на передовой космической станции.
+ Клоуну и миму предоставляется более широкое поле для мемных имён
+ Имена синтетиков так же имеют свою специфику. Ознакомьтесь с ними на вики.
\ No newline at end of file
diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml b/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml
index c84f9079e566e9..2b05a04f3b93b6 100644
--- a/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml
+++ b/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml
@@ -18,6 +18,7 @@
special:
- !type:AddComponentSpecial
components:
+ - type: RenameStart #SS220-RenameStart
- type: Clumsy
clumsyDamage:
types: #literally just picked semi random valus. i tested this once and tweaked it.
diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml b/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml
index 4eb4e8151ce258..03b7cf756dba23 100644
--- a/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml
+++ b/Resources/Prototypes/Roles/Jobs/Civilian/mime.yml
@@ -20,6 +20,7 @@
components:
- type: MimePowers
- type: FrenchAccent
+ - type: RenameStart #SS220-RenameStart
- type: startingGear
id: MimeGear
diff --git a/Resources/Prototypes/Roles/Jobs/Science/borg.yml b/Resources/Prototypes/Roles/Jobs/Science/borg.yml
index f3b3b6dff5ddf2..01f30536b7105a 100644
--- a/Resources/Prototypes/Roles/Jobs/Science/borg.yml
+++ b/Resources/Prototypes/Roles/Jobs/Science/borg.yml
@@ -18,6 +18,10 @@
supervisors: job-supervisors-rd
jobEntity: StationAiBrain
applyTraits: false
+ special: #SS220-RenameStart - start
+ - !type:AddComponentSpecial
+ components:
+ - type: RenameStart #SS220-RenameStart - end
- type: job
id: Borg
@@ -32,3 +36,7 @@
supervisors: job-supervisors-rd
jobEntity: PlayerBorgGeneric
applyTraits: false
+ special: #SS220-RenameStart - start
+ - !type:AddComponentSpecial
+ components:
+ - type: RenameStart #SS220-RenameStart - end
\ No newline at end of file