mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-10-09 10:21:18 +03:00
golobby for vanilla (#3715)
This commit is contained in:
parent
96be7c48c8
commit
eacc62bbaf
16 changed files with 270 additions and 4 deletions
15
Content.Client/Corvax/Ghost/GhostGoLobbyConfirmWindow.xaml
Normal file
15
Content.Client/Corvax/Ghost/GhostGoLobbyConfirmWindow.xaml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<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 'ghost-go-lobby-confirm-title'}"
|
||||
Resizable="False">
|
||||
<BoxContainer Orientation="Vertical" VerticalExpand="True" SetWidth="420">
|
||||
<RichTextLabel Name="WarningLabel" Margin="20 10 20 10"/>
|
||||
<BoxContainer HorizontalExpand="True" HorizontalAlignment="Center">
|
||||
<Button Name="ContinueButton"
|
||||
Text="{Loc 'ghost-go-lobby-confirm-continue'}"
|
||||
SetWidth="150"
|
||||
Margin="0 10 0 10"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</controls:FancyWindow>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
using Content.Client.UserInterface.Controls;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Corvax.Ghost;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class GhostGoLobbyConfirmWindow : FancyWindow
|
||||
{
|
||||
public event Action? ContinuePressed;
|
||||
|
||||
public GhostGoLobbyConfirmWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
WarningLabel.SetMessage(FormattedMessage.FromMarkupPermissive(Loc.GetString("ghost-go-lobby-confirm")));
|
||||
|
||||
ContinueButton.OnPressed += _ =>
|
||||
{
|
||||
ContinuePressed?.Invoke();
|
||||
Close();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using Content.Client.Movement.Systems;
|
||||
using Content.Shared.Corvax.Events;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Ghost.Components;
|
||||
using Content.Shared.Ghost.Systems;
|
||||
|
|
@ -187,6 +188,11 @@ namespace Content.Client.Ghost
|
|||
RaiseNetworkEvent(new GhostWarpsRequestEvent());
|
||||
}
|
||||
|
||||
public void GhostGoLobby() // Corvax-GoLobby
|
||||
{
|
||||
RaiseNetworkEvent(new GhostGoLobbyEvent());
|
||||
}
|
||||
|
||||
public void ReturnToBody()
|
||||
{
|
||||
var msg = new GhostReturnToBodyRequest();
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
using Content.Client.Corvax.Ghost;
|
||||
using Content.Client.Gameplay;
|
||||
using Content.Client.Ghost;
|
||||
using Content.Client.UserInterface.Systems.Gameplay;
|
||||
using Content.Client.UserInterface.Systems.Ghost.Widgets;
|
||||
using Content.Shared.Corvax.CCCVars;
|
||||
using Content.Shared.Ghost.Components;
|
||||
using Content.Shared.Ghost.Systems;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controllers;
|
||||
using Robust.Shared.Configuration;
|
||||
|
||||
namespace Content.Client.UserInterface.Systems.Ghost;
|
||||
|
||||
|
|
@ -13,11 +16,15 @@ namespace Content.Client.UserInterface.Systems.Ghost;
|
|||
public sealed partial class GhostUIController : UIController, IOnSystemChanged<GhostSystem>
|
||||
{
|
||||
[Dependency] private IEntityNetworkManager _net = default!;
|
||||
[Dependency] private IConfigurationManager _cfg = default!; // Corvax-GoLobby
|
||||
|
||||
[UISystemDependency] private readonly GhostSystem? _system = default;
|
||||
|
||||
private GhostGui? Gui => UIManager.GetActiveUIWidgetOrNull<GhostGui>();
|
||||
|
||||
private GhostGoLobbyConfirmWindow? _goLobbyConfirmWindow; // Corvax-GoLobby
|
||||
private bool _goLobbyEnabled = true; // Corvax-GoLobby
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
|
@ -25,6 +32,15 @@ public sealed partial class GhostUIController : UIController, IOnSystemChanged<G
|
|||
var gameplayStateLoad = UIManager.GetUIController<GameplayStateLoadController>();
|
||||
gameplayStateLoad.OnScreenLoad += OnScreenLoad;
|
||||
gameplayStateLoad.OnScreenUnload += OnScreenUnload;
|
||||
|
||||
// Corvax-GoLobby
|
||||
_cfg.OnValueChanged(CCCVars.GhostGoLobbyEnabled, OnGoLobbyEnabledChanged, true);
|
||||
}
|
||||
|
||||
private void OnGoLobbyEnabledChanged(bool enabled) // Corvax-GoLobby
|
||||
{
|
||||
_goLobbyEnabled = enabled;
|
||||
UpdateGui();
|
||||
}
|
||||
|
||||
private void OnScreenLoad()
|
||||
|
|
@ -65,7 +81,7 @@ public sealed partial class GhostUIController : UIController, IOnSystemChanged<G
|
|||
}
|
||||
|
||||
Gui.Visible = _system?.IsGhost ?? false;
|
||||
Gui.Update(_system?.AvailableGhostRoleCount, _system?.Player?.CanReturnToBody);
|
||||
Gui.Update(_system?.AvailableGhostRoleCount, _system?.Player?.CanReturnToBody, _goLobbyEnabled); // Corvax-GoLobby edit
|
||||
}
|
||||
|
||||
private void OnPlayerRemoved(GhostComponent component)
|
||||
|
|
@ -142,6 +158,7 @@ public sealed partial class GhostUIController : UIController, IOnSystemChanged<G
|
|||
Gui.TargetWindow.OnGhostnadoClicked += OnGhostnadoClicked;
|
||||
Gui.TargetWindow.OnWarpToRandomFollowedClicked += OnWarpToRandomFollowedClicked;
|
||||
Gui.TargetWindow.OnWarpToRandomClicked += OnWarpToRandomClicked;
|
||||
Gui.GhostGoLobbyPressed += GhostGoLobby; // Corvax-GoLobby
|
||||
|
||||
UpdateGui();
|
||||
}
|
||||
|
|
@ -155,6 +172,7 @@ public sealed partial class GhostUIController : UIController, IOnSystemChanged<G
|
|||
Gui.ReturnToBodyPressed -= ReturnToBody;
|
||||
Gui.GhostRolesPressed -= GhostRolesPressed;
|
||||
Gui.TargetWindow.WarpClicked -= OnWarpClicked;
|
||||
Gui.GhostGoLobbyPressed -= GhostGoLobby; // Corvax-GoLobby
|
||||
|
||||
Gui.Hide();
|
||||
}
|
||||
|
|
@ -164,6 +182,22 @@ public sealed partial class GhostUIController : UIController, IOnSystemChanged<G
|
|||
_system?.ReturnToBody();
|
||||
}
|
||||
|
||||
// Corvax-Changes-Start
|
||||
private void GhostGoLobby()
|
||||
{
|
||||
if (_goLobbyConfirmWindow is { Disposed: false })
|
||||
{
|
||||
_goLobbyConfirmWindow.MoveToFront();
|
||||
return;
|
||||
}
|
||||
|
||||
_goLobbyConfirmWindow = new GhostGoLobbyConfirmWindow();
|
||||
_goLobbyConfirmWindow.ContinuePressed += () => _system?.GhostGoLobby();
|
||||
_goLobbyConfirmWindow.OnClose += () => _goLobbyConfirmWindow = null;
|
||||
_goLobbyConfirmWindow.OpenCentered();
|
||||
}
|
||||
// Corvax-Changes-End
|
||||
|
||||
private void RequestWarps()
|
||||
{
|
||||
_system?.RequestWarps();
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
<widgets:GhostGui xmlns="https://spacestation14.io"
|
||||
<widgets:GhostGui xmlns="https://spacestation14.io"
|
||||
xmlns:widgets="clr-namespace:Content.Client.UserInterface.Systems.Ghost.Widgets"
|
||||
HorizontalAlignment="Center">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Button Name="ReturnToBodyButton" Text="{Loc ghost-gui-return-to-body-button}" />
|
||||
<Button Name="GhostWarpButton" Text="{Loc ghost-gui-ghost-warp-button}" />
|
||||
<Button Name="GhostRolesButton" />
|
||||
<!-- Corvax-Changes: Added GhostGoLobbyButton -->
|
||||
<Button Name="GhostGoLobbyButton" Text="{Loc ghost-go-lobby-button}" />
|
||||
</BoxContainer>
|
||||
</widgets:GhostGui>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ public sealed partial class GhostGui : UIWidget
|
|||
public event Action? RequestWarpsPressed;
|
||||
public event Action? ReturnToBodyPressed;
|
||||
public event Action? GhostRolesPressed;
|
||||
public event Action? GhostGoLobbyPressed; // Corvax-GoLobby
|
||||
private int _prevNumberRoles;
|
||||
|
||||
public GhostGui()
|
||||
|
|
@ -28,6 +29,7 @@ public sealed partial class GhostGui : UIWidget
|
|||
ReturnToBodyButton.OnPressed += _ => ReturnToBodyPressed?.Invoke();
|
||||
GhostRolesButton.OnPressed += _ => GhostRolesPressed?.Invoke();
|
||||
GhostRolesButton.OnPressed += _ => GhostRolesButton.StyleClasses.Remove(StyleClass.Negative);
|
||||
GhostGoLobbyButton.OnPressed += _ => GhostGoLobbyPressed?.Invoke(); // Corvax-GoLobby
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
|
|
@ -36,9 +38,10 @@ public sealed partial class GhostGui : UIWidget
|
|||
Visible = false;
|
||||
}
|
||||
|
||||
public void Update(int? roles, bool? canReturnToBody)
|
||||
public void Update(int? roles, bool? canReturnToBody, bool? canGoLobby = true) // Corvax-GoLobby edit
|
||||
{
|
||||
ReturnToBodyButton.Disabled = !canReturnToBody ?? true;
|
||||
GhostGoLobbyButton.Visible = canGoLobby ?? true; // Corvax-GoLobby
|
||||
|
||||
if (roles != null)
|
||||
{
|
||||
|
|
|
|||
13
Content.Server/Corvax/Events/GhostJoinLobbyRequestEvent.cs
Normal file
13
Content.Server/Corvax/Events/GhostJoinLobbyRequestEvent.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server._Corvax.Events;
|
||||
|
||||
public sealed class GhostJoinLobbyRequestEvent : EntityEventArgs
|
||||
{
|
||||
public readonly ICommonSession Session;
|
||||
|
||||
public GhostJoinLobbyRequestEvent(ICommonSession session)
|
||||
{
|
||||
Session = session;
|
||||
}
|
||||
}
|
||||
105
Content.Server/Corvax/Ghost/GhostGoLobbySystem.cs
Normal file
105
Content.Server/Corvax/Ghost/GhostGoLobbySystem.cs
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
using Content.Server._Corvax.Events;
|
||||
using Content.Server.Chat.Managers;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.Mind;
|
||||
using Content.Server.Players.PlayTimeTracking;
|
||||
using Content.Server.Preferences.Managers;
|
||||
using Content.Shared.Corvax.CCCVars;
|
||||
using Content.Shared.Corvax.Events;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Ghost.Components;
|
||||
using Content.Shared.Players.PlayTimeTracking;
|
||||
using Content.Shared.Popups;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Corvax.Ghost;
|
||||
|
||||
public sealed partial class GhostGoLobbySystem : EntitySystem
|
||||
{
|
||||
[Dependency] private IConfigurationManager _cfg = default!;
|
||||
[Dependency] private IGameTiming _timing = default!;
|
||||
[Dependency] private MindSystem _mind = default!;
|
||||
[Dependency] private PlayTimeTrackingManager _playTime = default!;
|
||||
[Dependency] private SharedPopupSystem _popup = default!;
|
||||
[Dependency] private IChatManager _chatManager = default!;
|
||||
[Dependency] private IServerPreferencesManager _prefsManager = default!;
|
||||
|
||||
private bool _enabled;
|
||||
private TimeSpan _requiredPlaytime;
|
||||
private TimeSpan _deathTime;
|
||||
|
||||
private readonly Dictionary<NetUserId, HashSet<int>> _usedCharacterSlots = new();
|
||||
|
||||
public int GetSelectedSlot(NetUserId userId)
|
||||
{
|
||||
return _prefsManager.GetPreferences(userId).SelectedCharacterIndex;
|
||||
}
|
||||
|
||||
public bool CanUseCharacter(NetUserId userId, int characterSlot)
|
||||
{
|
||||
return !_usedCharacterSlots.TryGetValue(userId, out var slots) || !slots.Contains(characterSlot);
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeNetworkEvent<GhostGoLobbyEvent>(OnGhostGoLobby);
|
||||
SubscribeLocalEvent<GameRunLevelChangedEvent>(OnRunLevelChanged);
|
||||
|
||||
Subs.CVar(_cfg, CCCVars.GhostGoLobbyEnabled, value => _enabled = value, true);
|
||||
Subs.CVar(_cfg, CCCVars.GhostGoLobbyTimeHours, value => _requiredPlaytime = TimeSpan.FromHours(value), true);
|
||||
Subs.CVar(_cfg, CCCVars.GhostGoLobbyDeathTimeMinutes, value => _deathTime = TimeSpan.FromMinutes(value), true);
|
||||
}
|
||||
|
||||
private void OnRunLevelChanged(GameRunLevelChangedEvent ev)
|
||||
{
|
||||
if (ev.New == GameRunLevel.PreRoundLobby)
|
||||
_usedCharacterSlots.Clear();
|
||||
}
|
||||
|
||||
private void OnGhostGoLobby(GhostGoLobbyEvent msg, EntitySessionEventArgs args)
|
||||
{
|
||||
if (args.SenderSession.AttachedEntity is not { Valid: true } attached)
|
||||
return;
|
||||
|
||||
TryGhostGoLobby(attached, args.SenderSession);
|
||||
}
|
||||
|
||||
private void TryGhostGoLobby(EntityUid uid, ICommonSession session)
|
||||
{
|
||||
if (!_enabled)
|
||||
return;
|
||||
|
||||
var all = _playTime.GetOverallPlaytime(session);
|
||||
if (all < _requiredPlaytime)
|
||||
{
|
||||
var remaining = (int) Math.Ceiling((_requiredPlaytime - all).TotalHours);
|
||||
_popup.PopupEntity(Loc.GetString("ghost-go-lobby-playtime", ("hours", remaining)), uid, uid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryComp<GhostComponent>(uid, out var ghost))
|
||||
return;
|
||||
|
||||
var timeSinceDeath = _timing.RealTime - ghost.TimeOfDeath;
|
||||
if (_deathTime > TimeSpan.Zero && timeSinceDeath < _deathTime)
|
||||
{
|
||||
var remaining = (int) ((_deathTime - timeSinceDeath).TotalMinutes);
|
||||
_popup.PopupEntity(Loc.GetString("ghost-go-lobby-deathtime", ("minutes", remaining)), uid, uid);
|
||||
return;
|
||||
}
|
||||
|
||||
var slot = GetSelectedSlot(session.UserId);
|
||||
if (!_usedCharacterSlots.TryGetValue(session.UserId, out var slots))
|
||||
_usedCharacterSlots[session.UserId] = slots = new HashSet<int>();
|
||||
|
||||
slots.Add(slot);
|
||||
|
||||
_mind.WipeMind(session);
|
||||
|
||||
RaiseLocalEvent(new GhostJoinLobbyRequestEvent(session));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
using Content.Server._Corvax.Events;
|
||||
using Content.Corvax.Interfaces.Server;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.CCVar;
|
||||
|
|
@ -24,6 +25,7 @@ namespace Content.Server.GameTicking
|
|||
private void InitializePlayer()
|
||||
{
|
||||
_playerManager.PlayerStatusChanged += PlayerStatusChanged;
|
||||
SubscribeLocalEvent<GhostJoinLobbyRequestEvent>(OnGhostJoinLobbyRequest); // CorvaxGoob-GoLobby
|
||||
}
|
||||
|
||||
private async void PlayerStatusChanged(object? sender, SessionStatusEventArgs args)
|
||||
|
|
@ -227,6 +229,13 @@ namespace Content.Server.GameTicking
|
|||
RaiseLocalEvent(new PlayerJoinedLobbyEvent(session));
|
||||
}
|
||||
|
||||
// Corvax-Changes-Start
|
||||
private void OnGhostJoinLobbyRequest(GhostJoinLobbyRequestEvent ev)
|
||||
{
|
||||
PlayerJoinLobby(ev.Session);
|
||||
}
|
||||
// Corvax-Changes-End
|
||||
|
||||
private void ReqWindowAttentionAll()
|
||||
{
|
||||
RaiseNetworkEvent(new RequestWindowAttentionEvent());
|
||||
|
|
|
|||
|
|
@ -165,6 +165,15 @@ namespace Content.Server.GameTicking
|
|||
if (DummyTicker)
|
||||
return;
|
||||
|
||||
// Corvax-GoLobby-start
|
||||
var selectedSlot = _ghostGoLobby.GetSelectedSlot(player.UserId);
|
||||
if (!_ghostGoLobby.CanUseCharacter(player.UserId, selectedSlot))
|
||||
{
|
||||
_chatManager.DispatchServerMessage(player, Loc.GetString("ghost-go-lobby-used"));
|
||||
return;
|
||||
}
|
||||
// Corvax-GoLobby-end
|
||||
|
||||
if (station == EntityUid.Invalid)
|
||||
{
|
||||
var stations = GetSpawnableStations();
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using Content.Server.Chat.Managers;
|
|||
using Content.Server.Chat.Systems;
|
||||
using Content.Server.Database;
|
||||
using Content.Server.Ghost;
|
||||
using Content.Server.Corvax.Ghost; // Corvax-GoLobby
|
||||
using Content.Server.Maps;
|
||||
using Content.Server.Players.PlayTimeTracking;
|
||||
using Content.Server.Preferences.Managers;
|
||||
|
|
@ -50,6 +51,7 @@ namespace Content.Server.GameTicking
|
|||
[Dependency] private MapLoaderSystem _loader = default!;
|
||||
[Dependency] private SharedMapSystem _map = default!;
|
||||
[Dependency] private GhostSystem _ghost = default!;
|
||||
[Dependency] private GhostGoLobbySystem _ghostGoLobby = default!; // Corvax-GoLobby
|
||||
[Dependency] private SharedMindSystem _mind = default!;
|
||||
[Dependency] private PlayTimeTrackingSystem _playTimeTrackings = default!;
|
||||
[Dependency] private PvsOverrideSystem _pvsOverride = default!;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using Content.Shared.Corvax.TTS;
|
||||
using Content.Shared.Corvax.TTS;
|
||||
using Robust.Shared.Configuration;
|
||||
|
||||
namespace Content.Shared.Corvax.CCCVars;
|
||||
|
|
@ -134,4 +134,14 @@ public sealed class CCCVars
|
|||
/// </summary>
|
||||
public static readonly CVarDef<bool> StationGoal =
|
||||
CVarDef.Create("game.station_goal", true, CVar.SERVERONLY);
|
||||
|
||||
public static readonly CVarDef<bool> GhostGoLobbyEnabled =
|
||||
CVarDef.Create("ghost.go_lobby.enabled", false, CVar.SERVER | CVar.REPLICATED);
|
||||
|
||||
public static readonly CVarDef<float> GhostGoLobbyTimeHours =
|
||||
CVarDef.Create("ghost.go_lobby.require_time", 25f, CVar.SERVERONLY);
|
||||
|
||||
public static readonly CVarDef<float> GhostGoLobbyDeathTimeMinutes =
|
||||
CVarDef.Create("ghost.go_lobby.death_time", 15f, CVar.SERVERONLY);
|
||||
|
||||
}
|
||||
|
|
|
|||
6
Content.Shared/Corvax/Events/GhostGoLobbyEvent.cs
Normal file
6
Content.Shared/Corvax/Events/GhostGoLobbyEvent.cs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Corvax.Events;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class GhostGoLobbyEvent : EntityEventArgs;
|
||||
|
|
@ -27,3 +27,6 @@ same_type_timeout = 300.0
|
|||
timerrestart = 30
|
||||
preset_enabled = false
|
||||
restart_enabled = false
|
||||
|
||||
[ghost.go_lobby]
|
||||
enabled = true
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
ghost-go-lobby-button = Return to lobby
|
||||
|
||||
ghost-go-lobby-deathtime = You can return to the lobby in {$minutes} minutes.
|
||||
ghost-go-lobby-playtime = You need to play for another {$hours} hours.
|
||||
ghost-go-lobby-used = Please choose a different character.
|
||||
|
||||
ghost-go-lobby-confirm-title = Returning to the Lobby
|
||||
ghost-go-lobby-confirm = Are you sure you want to return to the lobby?
|
||||
You have forgotten everything about your current character and do not remember anything you learned while you were a ghost.
|
||||
You are allowed to remember general knowledge about the game e.g., how to cook, use items, etc.
|
||||
You are [color=red]NOT[/color] allowed to remember or mention the name, appearance, etc., of your previous character.
|
||||
ghost-go-lobby-confirm-continue = Continue
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
ghost-go-lobby-button = Вернуться в лобби
|
||||
|
||||
ghost-go-lobby-deathtime = Вернуться в лобби можно через {$minutes} мин.
|
||||
ghost-go-lobby-playtime = Вам нужно наиграть еще {$hours} ч.
|
||||
ghost-go-lobby-used = Выберите другого персонажа.
|
||||
|
||||
ghost-go-lobby-confirm-title = Возвращение в лобби
|
||||
ghost-go-lobby-confirm = Вы уверены, что хотите вернуться в лобби?
|
||||
Вы забыли всё о своём текущем персонаже и ничего не помните из того, что узнали, будучи призраком.
|
||||
Вам разрешается помнить общие знания об игре: например, как готовить, использовать предметы и т.д.
|
||||
Вам [color=red]НЕ[/color] разрешается помнить или говорить имя, внешность и т.д. вашего предыдущего персонажа.
|
||||
ghost-go-lobby-confirm-continue = Продолжить
|
||||
Loading…
Add table
Reference in a new issue