merge master

This commit is contained in:
deltanedas 2025-03-02 23:33:56 +00:00
commit c7a83857b4
35 changed files with 37896 additions and 17406 deletions

View File

@ -1,6 +1,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Numerics;
using Content.Client._RMC14.Mentor; // RMC14
using Content.Client.Administration.Managers;
using Content.Client.Administration.Systems;
using Content.Client.Administration.UI.Bwoink;
@ -37,11 +38,12 @@ public sealed class AHelpUIController: UIController, IOnSystemChanged<BwoinkSyst
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IClyde _clyde = default!;
[Dependency] private readonly IUserInterfaceManager _uiManager = default!;
[Dependency] private readonly StaffHelpUIController _staffHelp = default!; // RMC14 - Mentor Help
[UISystemDependency] private readonly AudioSystem _audio = default!;
private BwoinkSystem? _bwoinkSystem;
private MenuButton? GameAHelpButton => UIManager.GetActiveUIWidgetOrNull<GameTopMenuBar>()?.AHelpButton;
private Button? LobbyAHelpButton => (UIManager.ActiveScreen as LobbyGui)?.AHelpButton;
public MenuButton? GameAHelpButton => UIManager.GetActiveUIWidgetOrNull<GameTopMenuBar>()?.AHelpButton; // RMC14 - Mentor help
public Button? LobbyAHelpButton => (UIManager.ActiveScreen as LobbyGui)?.AHelpButton; // RMC14 - Mentor Help
public IAHelpUIHandler? UIHelper;
private bool _discordRelayActive;
private bool _hasUnreadAHelp;
@ -87,8 +89,9 @@ public sealed class AHelpUIController: UIController, IOnSystemChanged<BwoinkSyst
private void AHelpButtonPressed(BaseButton.ButtonEventArgs obj)
{
EnsureUIHelper();
UIHelper!.ToggleWindow();
_staffHelp.ToggleWindow(); // RMC 14 - Mentor Help
// EnsureUIHelper(); RMC 14 - Mentor Help
// UIHelper!.ToggleWindow(); RMC14 Mentor Help
}
public void OnSystemLoaded(BwoinkSystem system)
@ -246,7 +249,7 @@ public sealed class AHelpUIController: UIController, IOnSystemChanged<BwoinkSyst
helper.Control.PopOut.Visible = false;
}
private void UnreadAHelpReceived()
public void UnreadAHelpReceived() // RMC14 - Mentor Help
{
GameAHelpButton?.StyleClasses.Add(MenuButton.StyleClassRedTopButton);
LobbyAHelpButton?.StyleClasses.Add(StyleNano.StyleClassButtonColorRed);

View File

@ -98,9 +98,8 @@
Access="Internal"
Icon="{xe:Tex '/Textures/Interface/info.svg.192dpi.png'}"
BoundKey = "{x:Static is:ContentKeyFunctions.OpenAHelp}"
ToolTip="{Loc 'ui-options-function-open-a-help'}"
MinSize="42 64"
ToolTip="{Loc 'ui-options-function-open-staff-chats-deltav'}" MinSize="42 64"
HorizontalExpand="True"
AppendStyleClass="{x:Static style:StyleBase.ButtonOpenLeft}"
/>
/> <!--DeltaV - Rename to Curator Chat-->
</widgets:GameTopMenuBar>

View File

@ -0,0 +1,15 @@
<controls:MentorHelpWindow
xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client._RMC14.Mentor"
SetSize="500 300"
Title="Curator Chat"> <!--DeltaV - Renamed to Curator Chat-->
<BoxContainer Orientation="Vertical">
<OutputPanel Name="Messages" Access="Public" HorizontalExpand="True"
VerticalExpand="True" />
<BoxContainer Orientation="Horizontal">
<LineEdit Name="Chat" Access="Public" HorizontalExpand="True" />
<!-- DeltaV - Remove de/re-mentor <Button Name="ReMentorButton" Access="Public" Text="Re-mentor" Visible="False"
StyleClasses="OpenBoth" />-->
</BoxContainer>
</BoxContainer>
</controls:MentorHelpWindow>

View File

@ -0,0 +1,14 @@
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client._RMC14.Mentor;
[GenerateTypedNameReferences]
public sealed partial class MentorHelpWindow : DefaultWindow
{
public MentorHelpWindow()
{
RobustXamlLoader.Load(this);
}
}

View File

@ -0,0 +1,30 @@
<controls:MentorWindow
xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client._RMC14.Mentor"
xmlns:graphics="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
SetSize="900 500"
Title="Curator Chat"> <!--DeltaV - Renamed to Curator Chat-->
<BoxContainer Orientation="Horizontal">
<PanelContainer HorizontalExpand="True" VerticalExpand="True">
<PanelContainer.PanelOverride>
<graphics:StyleBoxFlat BackgroundColor="#202028" />
</PanelContainer.PanelOverride>
<ScrollContainer HScrollEnabled="False" VScrollEnabled="True"
HorizontalExpand="True" VerticalExpand="True">
<BoxContainer Orientation="Vertical" HorizontalExpand="True"
VerticalExpand="True">
<BoxContainer Name="Players" Access="Public" Orientation="Vertical"
VerticalExpand="True" />
<!-- DeltaV - Remove de/re-mentor <Button Name="DeMentorButton" Access="Public" Text="De-Mentor"
StyleClasses="OpenBoth" />-->
</BoxContainer>
</ScrollContainer>
</PanelContainer>
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True"
SizeFlagsStretchRatio="3">
<OutputPanel Name="Messages" Access="Public"
VerticalExpand="True" />
<LineEdit Name="Chat" Access="Public" HorizontalExpand="True" Editable="False" />
</BoxContainer>
</BoxContainer>
</controls:MentorWindow>

View File

@ -0,0 +1,19 @@
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Network;
namespace Content.Client._RMC14.Mentor;
[GenerateTypedNameReferences]
public sealed partial class MentorWindow : DefaultWindow
{
public NetUserId SelectedPlayer { get; set; }
public readonly Dictionary<NetUserId, Button> PlayerDict = new();
public MentorWindow()
{
RobustXamlLoader.Load(this);
}
}

View File

@ -0,0 +1,329 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq; // DeltaV
using Content.Client.Administration.Systems;
using Content.Client.Stylesheets;
using Content.Client.UserInterface.Systems.Bwoink;
using Content.Shared._RMC14.CCVar;
using Content.Shared._RMC14.Mentor;
using Content.Shared.Administration; // DeltaV
using Content.Shared.Input;
using Robust.Client.Audio;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controllers;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Configuration;
using Robust.Shared.Input.Binding;
using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Utility;
namespace Content.Client._RMC14.Mentor;
public sealed class StaffHelpUIController : UIController, IOnSystemChanged<BwoinkSystem>
{
[Dependency] private readonly AHelpUIController _aHelp = default!;
[Dependency] private readonly IClyde _clyde = default!;
[Dependency] private readonly IConfigurationManager _config = default!;
[Dependency] private readonly INetManager _net = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[UISystemDependency] private readonly AudioSystem? _audio = default!;
[UISystemDependency] private readonly AdminSystem _admin = default!; // DeltaV
private readonly Dictionary<NetUserId, List<MentorMessage>> _messages = new();
//private readonly Dictionary<NetUserId, string> _destinationNames = new(); DeltaV - All players in chat
private bool _isMentor;
//private bool _canReMentor; DeltaV - Remove de/re-mentor
private StaffHelpWindow? _staffHelpWindow;
private MentorHelpWindow? _mentorHelpWindow;
private MentorWindow? _mentorWindow;
private string? _mHelpSound;
private bool _unread;
public override void Initialize()
{
_net.RegisterNetMessage<MentorStatusMsg>(OnMentorStatus);
_net.RegisterNetMessage<MentorMessagesReceivedMsg>(OnMentorHelpReceived);
_net.RegisterNetMessage<MentorSendMessageMsg>();
_net.RegisterNetMessage<MentorHelpMsg>();
//_net.RegisterNetMessage<DeMentorMsg>(); DeltaV - Remove de/re-mentor
//_net.RegisterNetMessage<ReMentorMsg>(); DeltaV - Remove de/re-mentor
_config.OnValueChanged(RMCCVars.RMCMentorHelpSound, v => _mHelpSound = v, true);
}
private void OnMentorStatus(MentorStatusMsg msg)
{
_isMentor = msg.IsMentor;
//_canReMentor = msg.CanReMentor; DeltaV - Remove de/re-mentor
if (_isMentor)
_mentorHelpWindow?.Close();
else
_mentorWindow?.Close();
}
private void OnMentorHelpReceived(MentorMessagesReceivedMsg msg)
{
var other = false;
foreach (var message in msg.Messages)
{
if (message.Author != _player.LocalUser)
other = true;
if (_isMentor &&
_mentorWindow is not { IsOpen: true })
{
_unread = true;
_aHelp.UnreadAHelpReceived();
}
//_destinationNames.TryAdd(message.Destination, message.DestinationName); DeltaV - All players in chat
_messages.GetOrNew(message.Destination).Add(message);
if (_mentorWindow is { IsOpen: true })
{
//MentorAddPlayerButton(message.Destination); DeltaV - All players in chat
if (_mentorWindow.SelectedPlayer == message.Destination)
{
_mentorWindow.Messages.AddMessage(CreateMessageLabel(message));
_mentorWindow.Messages.ScrollToBottom();
}
continue;
}
if (_mentorHelpWindow is { IsOpen: true } &&
_player.LocalUser == message.Destination)
{
_mentorHelpWindow.Messages.AddMessage(CreateMessageLabel(message));
_mentorHelpWindow.Messages.ScrollToBottom();
}
}
if (other)
{
_audio?.PlayGlobal(_mHelpSound, Filter.Local(), false);
_clyde.RequestWindowAttention();
if (!_isMentor)
{
if (OpenWindow(ref _mentorHelpWindow, CreateMentorHelpWindow, () => _mentorHelpWindow = null))
{
_mentorHelpWindow.OpenCentered();
}
}
}
}
public void OnSystemLoaded(BwoinkSystem system)
{
CommandBinds.Builder
.BindBefore(ContentKeyFunctions.OpenAHelp,
InputCmdHandler.FromDelegate(_ => ToggleWindow()),
typeof(AHelpUIController))
.Register<StaffHelpUIController>();
}
public void OnSystemUnloaded(BwoinkSystem system)
{
CommandBinds.Unregister<StaffHelpUIController>();
}
public void ToggleWindow()
{
if (_staffHelpWindow != null)
{
_staffHelpWindow.Close();
_staffHelpWindow = null;
SetAHelpButtonPressed(false);
return;
}
SetAHelpButtonPressed(true);
_staffHelpWindow = new StaffHelpWindow();
_staffHelpWindow.OnClose += () => _staffHelpWindow = null;
_staffHelpWindow.OpenCentered();
UIManager.ClickSound();
if (_unread)
_staffHelpWindow.MentorHelpButton.StyleClasses.Add(StyleNano.StyleClassButtonColorRed);
_staffHelpWindow.AdminHelpButton.OnPressed += _ =>
{
_aHelp.Open();
_staffHelpWindow.Close();
SetAHelpButtonPressed(false);
};
_staffHelpWindow.MentorHelpButton.OnPressed += _ =>
{
SetAHelpButtonPressed(false);
_unread = false;
if (_isMentor)
{
if (OpenWindow(ref _mentorWindow, CreateMentorWindow, () => _mentorWindow = null))
{
// DeltaV - Start all players in chat sorted
var playerList = _admin.PlayerList.ToList();
playerList.Sort(delegate(PlayerInfo player1, PlayerInfo player2)
{
var time1 = _messages.GetValueOrDefault(player1.SessionId);
var time2 = _messages.GetValueOrDefault(player2.SessionId);
if (time1 == null && time2 == null)
return 0;
if (time1 == null)
return -1;
if (time2 == null)
return 1;
return time1.Last().Time.CompareTo(time2.Last().Time);
});
foreach (var player in playerList)
{
MentorAddPlayerButton(player);
}
// DeltaV - End all players in chat sorted
_mentorWindow.OpenCentered();
}
}
else
{
if (OpenWindow(ref _mentorHelpWindow, CreateMentorHelpWindow, () => _mentorHelpWindow = null))
{
_mentorHelpWindow.OpenCentered();
}
}
_staffHelpWindow.Close();
};
}
private MentorHelpWindow CreateMentorHelpWindow()
{
var window = new MentorHelpWindow();
//window.ReMentorButton.OnPressed += _ => _net.ClientSendMessage(new ReMentorMsg()); DeltaV - Remove de/re-mentor
//window.ReMentorButton.Visible = _canReMentor; DeltaV - Remove de/re-mentor
window.Chat.OnTextEntered += args =>
{
window.Chat.Clear();
if (string.IsNullOrWhiteSpace(args.Text))
return;
var msg = new MentorHelpMsg() { Message = args.Text };
_net.ClientSendMessage(msg);
};
if (_player.LocalUser is { } local && _messages.TryGetValue(local, out var messages))
{
foreach (var message in messages)
{
window.Messages.AddMessage(CreateMessageLabel(message));
window.Messages.ScrollToBottom();
}
}
return window;
}
private MentorWindow CreateMentorWindow()
{
var window = new MentorWindow();
//window.DeMentorButton.OnPressed += _ => _net.ClientSendMessage(new DeMentorMsg()); DeltaV - Remove de/re-mentor
window.Chat.OnTextEntered += args =>
{
var msg = new MentorSendMessageMsg { Message = args.Text, To = window.SelectedPlayer };
_net.ClientSendMessage(msg);
window.Chat.Clear();
};
return window;
}
private void MentorAddPlayerButton(PlayerInfo player)
{
if (_mentorWindow == null)
return;
/* DeltaV - Start show char name and job if possible
if (_mentorWindow.PlayerDict.TryGetValue(player, out var button))
{
button.SetPositionFirst();
return;
}
var playerName = player.ToString();
if (_destinationNames.TryGetValue(player, out var destinationName))
playerName = destinationName;
*/
//Default show player name if they don't have a character
var character = player.Username;
var job = "Spectator";
//Use Character and Job name if they exist.
if (!string.IsNullOrWhiteSpace(player.CharacterName))
character = player.CharacterName;
if (!string.IsNullOrWhiteSpace(player.StartingJob))
job = player.StartingJob;
// DeltaV - End show char name and job if possible
var playerButton = new Button
{
Text = $"{character} ({job})", // DeltaV - Show char name and job if possible
StyleClasses = { "OpenBoth" },
};
playerButton.OnPressed += _ =>
{
if (_mentorWindow is not { IsOpen: true })
return;
_mentorWindow.SelectedPlayer = player.SessionId;
_mentorWindow.Messages.Clear();
_mentorWindow.Chat.Editable = true;
if (!_messages.TryGetValue(player.SessionId, out var authorMessages))
return;
foreach (var message in authorMessages)
{
_mentorWindow.Messages.AddMessage(CreateMessageLabel(message));
_mentorWindow.Messages.ScrollToBottom();
}
};
_mentorWindow.Players.AddChild(playerButton);
playerButton.SetPositionFirst();
_mentorWindow.PlayerDict[player.SessionId] = playerButton;
}
private bool OpenWindow<T>([NotNullWhen(true)] ref T? window, Func<T> create, Action onClose) where T : DefaultWindow
{
if (window != null)
return true;
window = create();
window.OnClose += onClose;
return true;
}
private FormattedMessage CreateMessageLabel(MentorMessage message)
{
var author = message.AuthorName;
if (message.IsMentor)
author = $"[bold][color=red]{_player.GetPlayerData(message.Author).UserName}[/color][/bold]"; // DeltaV - Use usernames for curators
var text = $"{message.Time:HH:mm} {author}: {FormattedMessage.EscapeText(message.Text)}";
return FormattedMessage.FromMarkupPermissive(text);
}
private void SetAHelpButtonPressed(bool pressed)
{
if (_aHelp.GameAHelpButton != null)
_aHelp.GameAHelpButton.Pressed = pressed;
if (_aHelp.GameAHelpButton != null)
_aHelp.GameAHelpButton.Pressed = pressed;
}
}

View File

@ -0,0 +1,11 @@
<controls:StaffHelpWindow
xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client._RMC14.Mentor"
Title="Admin Help and Curator Chat"> <!--DeltaV - Rename to Curator Chat-->
<BoxContainer Orientation="Vertical">
<RichTextLabel Text="For reporting issues with another player to an admin" />
<Button Name="AdminHelpButton" Access="Public" Text="Admin Help" StyleClasses="OpenBoth" />
<RichTextLabel Text="For contacting curators for game help and running special events." Margin="0 20 0 0" /> <!--DeltaV - Rename to Curator Chat-->
<Button Name="MentorHelpButton" Access="Public" Text="Curator Chat" StyleClasses="OpenBoth" /> <!--DeltaV - Rename to Curator Chat-->
</BoxContainer>
</controls:StaffHelpWindow>

View File

@ -0,0 +1,14 @@
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client._RMC14.Mentor;
[GenerateTypedNameReferences]
public sealed partial class StaffHelpWindow : DefaultWindow
{
public StaffHelpWindow()
{
RobustXamlLoader.Load(this);
}
}

View File

@ -1,3 +1,4 @@
using Content.Server._RMC14.Mentor; // RMC14
using Content.Server.Administration;
using Content.Server.Administration.Logs;
using Content.Server.Administration.Managers;
@ -79,6 +80,9 @@ namespace Content.Server.IoC
IoCManager.Register<ConnectionManager>();
IoCManager.Register<MultiServerKickManager>();
IoCManager.Register<CVarControlManager>();
// RMC14
IoCManager.Register<MentorManager>();
}
}
}

View File

@ -0,0 +1,235 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Content.Server.Administration; // DeltaV
using Content.Server.Administration.Managers; // DeltaV
using Content.Server.Database;
using Content.Server.Players.RateLimiting;
using Content.Shared._RMC14.CCVar;
using Content.Shared._RMC14.Mentor;
using Content.Shared.Administration;
using Content.Shared.Mind; // DeltaV
using Content.Shared.Players.RateLimiting;
using Content.Shared.Roles;
using Robust.Server.Player;
using Robust.Shared.Configuration;
using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
namespace Content.Server._RMC14.Mentor;
public sealed class MentorManager : IPostInjectInit
{
[Dependency] private readonly IAdminManager _admin = default!; // DeltaV
[Dependency] private readonly IEntityManager _entity = default!; // DeltaV
[Dependency] private readonly IConfigurationManager _config = default!;
[Dependency] private readonly IServerDbManager _db = default!;
[Dependency] private readonly ILogManager _log = default!;
[Dependency] private readonly INetManager _net = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly PlayerRateLimitManager _rateLimit = default!;
[Dependency] private readonly UserDbDataManager _userDb = default!;
private const string RateLimitKey = "MentorHelp";
// private static readonly ProtoId<JobPrototype> MentorJob = "CMSeniorEnlistedAdvisor"; Remove mentoring jobs
private readonly List<ICommonSession> _activeMentors = new();
private readonly Dictionary<NetUserId, bool> _mentors = new();
/* DeltaV - Update mentor on perm updates
private async Task LoadData(ICommonSession player, CancellationToken cancel)
{
var userId = player.UserId;
var isMentor = await _db.IsJobWhitelisted(player.UserId, MentorJob, cancel);
if (!isMentor)
{
var dbData = await _db.GetAdminDataForAsync(userId, cancel);
var flags = AdminFlags.None;
if (dbData?.AdminRank?.Flags != null)
{
flags |= AdminFlagsHelper.NamesToFlags(dbData.AdminRank.Flags.Select(p => p.Flag));
}
if (dbData?.Flags != null)
{
flags |= AdminFlagsHelper.NamesToFlags(dbData.Flags.Select(p => p.Flag));
}
isMentor = flags.HasFlag(AdminFlags.MentorHelp);
}
_mentors[player.UserId] = isMentor;
if (isMentor)
_activeMentors.Add(player);
}
*/
private void FinishLoad(ICommonSession player)
{
SendMentorStatus(player);
}
private void ClientDisconnected(ICommonSession player)
{
_mentors.Remove(player.UserId);
_activeMentors.Remove(player);
}
private void OnMentorSendMessage(MentorSendMessageMsg message)
{
var destination = new NetUserId(message.To);
if (!_player.TryGetSessionById(destination, out var destinationSession))
return;
var author = message.MsgChannel.UserId;
if (!_player.TryGetSessionById(author, out var authorSession) ||
!_activeMentors.Contains(authorSession))
{
return;
}
SendMentorMessage(
destination,
destinationSession.Name,
author,
authorSession.Name,
message.Message,
destinationSession.Channel
);
}
private void OnMentorHelpMessage(MentorHelpMsg message)
{
if (!_player.TryGetSessionById(message.MsgChannel.UserId, out var author))
return;
var mind = _entity.System<SharedMindSystem>();
SendMentorMessage(author.UserId, author.Name, author.UserId, mind.GetCharacterName(author.UserId) ?? author.Name, message.Message, message.MsgChannel); // DeltaV - Try to use character name
}
// DeltaV - Begin Update mentor on perm updates
private void OnAdminPermsChanged(AdminPermsChangedEventArgs args)
{
if (_admin.HasAdminFlag(args.Player, AdminFlags.CuratorChat) && !_activeMentors.Contains(args.Player)) // DeltaV - Rename to Curator Chat
{
_activeMentors.Add(args.Player);
SendMentorStatus(args.Player);
}
if (!_admin.HasAdminFlag(args.Player, AdminFlags.CuratorChat) && _activeMentors.Contains(args.Player)) // DeltaV - Rename to Curator Chat
{
_activeMentors.Remove(args.Player);
SendMentorStatus(args.Player);
}
}
/*
private void OnDeMentor(DeMentorMsg message)
{
if (!_player.TryGetSessionById(message.MsgChannel.UserId, out var session) ||
!_activeMentors.Contains(session))
{
return;
}
_activeMentors.Remove(session);
SendMentorStatus(session);
}
private void OnReMentor(ReMentorMsg message)
{
if (!_player.TryGetSessionById(message.MsgChannel.UserId, out var session) ||
!_mentors.TryGetValue(session.UserId, out var mentor) ||
!mentor)
{
return;
}
_activeMentors.Add(session);
SendMentorStatus(session);
}
DeltaV - End Update mentor on perm updates */
private void SendMentorStatus(ICommonSession player)
{
var isMentor = _activeMentors.Contains(player);
var canReMentor = _mentors.TryGetValue(player.UserId, out var mentor) && mentor;
var msg = new MentorStatusMsg()
{
IsMentor = isMentor,
CanReMentor = canReMentor,
};
_net.ServerSendMessage(msg, player.Channel);
}
private void SendMentorMessage(NetUserId destination, string destinationName, NetUserId author, string authorName, string message, INetChannel destinationChannel)
{
if (string.IsNullOrWhiteSpace(message))
return;
var recipients = new HashSet<INetChannel> { destinationChannel };
var isMentor = false;
foreach (var active in _activeMentors)
{
if (active.UserId == author)
isMentor = true;
recipients.Add(active.Channel);
}
var mentorMsg = new MentorMessage(
destination,
destinationName,
author,
authorName,
message,
DateTime.Now,
isMentor
);
var messages = new List<MentorMessage> { mentorMsg };
var receive = new MentorMessagesReceivedMsg { Messages = messages };
foreach (var recipient in recipients)
{
try
{
_net.ServerSendMessage(receive, recipient);
}
catch (Exception e)
{
_log.RootSawmill.Error($"Error sending mentor help message:\n{e}");
}
}
}
void IPostInjectInit.PostInject()
{
_net.RegisterNetMessage<MentorStatusMsg>();
_net.RegisterNetMessage<MentorSendMessageMsg>(OnMentorSendMessage);
_net.RegisterNetMessage<MentorHelpMsg>(OnMentorHelpMessage);
_net.RegisterNetMessage<MentorMessagesReceivedMsg>();
//_net.RegisterNetMessage<DeMentorMsg>(OnDeMentor); DeltaV Update mentor on perm updates
//_net.RegisterNetMessage<ReMentorMsg>(OnReMentor); DeltaV Update mentor on perm updates
//_userDb.AddOnLoadPlayer(LoadData); DeltaV Update mentor on perm updates
_userDb.AddOnFinishLoad(FinishLoad);
_userDb.AddOnPlayerDisconnect(ClientDisconnected);
if (_config.IsCVarRegistered(RMCCVars.RMCMentorHelpRateLimitPeriod.Name) &&
_config.IsCVarRegistered(RMCCVars.RMCMentorHelpRateLimitCount.Name))
{
_rateLimit.Register(
RateLimitKey,
new RateLimitRegistration(
RMCCVars.RMCMentorHelpRateLimitPeriod,
RMCCVars.RMCMentorHelpRateLimitCount,
_ => { }
)
);
}
_admin.OnPermsChanged += OnAdminPermsChanged; // DeltaV
}
}

View File

@ -129,6 +129,11 @@
/// </summary>
Whitelist = 1 << 25,
/// <summary>
/// DeltaV - Lets you use the Curator Chat
/// </summary>
CuratorChat = 1 << 30,
/// <summary>
/// Dangerous host permissions like scsi.
/// </summary>

View File

@ -0,0 +1,17 @@
using Robust.Shared;
using Robust.Shared.Configuration;
namespace Content.Shared._RMC14.CCVar;
[CVarDefs]
public sealed class RMCCVars : CVars
{
public static readonly CVarDef<float> RMCMentorHelpRateLimitPeriod =
CVarDef.Create("rmc.mentor_help_rate_limit_period", 2f, CVar.SERVERONLY);
public static readonly CVarDef<int> RMCMentorHelpRateLimitCount =
CVarDef.Create("rmc.mentor_help_rate_limit_count", 10, CVar.SERVERONLY);
public static readonly CVarDef<string> RMCMentorHelpSound =
CVarDef.Create("rmc.mentor_help_sound", "/Audio/_RMC14/Effects/Admin/mhelp.ogg", CVar.ARCHIVE | CVar.CLIENTONLY);
}

View File

@ -0,0 +1,22 @@
using Lidgren.Network;
using Robust.Shared.Network;
using Robust.Shared.Serialization;
namespace Content.Shared._RMC14.Mentor;
public sealed class MentorHelpMsg : NetMessage
{
public override MsgGroups MsgGroup => MsgGroups.Core;
public string Message = string.Empty;
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
{
Message = buffer.ReadString();
}
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
{
buffer.Write(Message);
}
}

View File

@ -0,0 +1,15 @@
using Robust.Shared.Network;
using Robust.Shared.Serialization;
namespace Content.Shared._RMC14.Mentor;
[Serializable, NetSerializable]
public readonly record struct MentorMessage(
NetUserId Destination,
string DestinationName,
NetUserId Author,
string AuthorName,
string Text,
DateTime Time,
bool IsMentor
);

View File

@ -0,0 +1,46 @@
using Lidgren.Network;
using Robust.Shared.Network;
using Robust.Shared.Serialization;
namespace Content.Shared._RMC14.Mentor;
public sealed class MentorMessagesReceivedMsg : NetMessage
{
public override MsgGroups MsgGroup => MsgGroups.Core;
public List<MentorMessage> Messages = new();
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
{
var count = buffer.ReadInt32();
Messages.EnsureCapacity(count);
for (var i = 0; i < count; i++)
{
var destination = new NetUserId(buffer.ReadGuid());
var destinationName = buffer.ReadString();
var author = new NetUserId(buffer.ReadGuid());
var authorName = buffer.ReadString();
var text = buffer.ReadString();
var time = DateTime.FromBinary(buffer.ReadInt64());
var isMentor = buffer.ReadBoolean();
var message = new MentorMessage(destination, destinationName, author, authorName, text, time, isMentor);
Messages.Add(message);
}
}
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
{
buffer.Write(Messages.Count);
foreach (var message in Messages)
{
buffer.Write(message.Destination.UserId);
buffer.Write(message.DestinationName);
buffer.Write(message.Author.UserId);
buffer.Write(message.AuthorName);
buffer.Write(message.Text);
buffer.Write(message.Time.ToBinary());
buffer.Write(message.IsMentor);
}
}
}

View File

@ -0,0 +1,25 @@
using Lidgren.Network;
using Robust.Shared.Network;
using Robust.Shared.Serialization;
namespace Content.Shared._RMC14.Mentor;
public sealed class MentorSendMessageMsg : NetMessage
{
public override MsgGroups MsgGroup => MsgGroups.Core;
public string Message = string.Empty;
public Guid To;
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
{
Message = buffer.ReadString();
To = buffer.ReadGuid();
}
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
{
buffer.Write(Message);
buffer.Write(To);
}
}

View File

@ -0,0 +1,25 @@
using Lidgren.Network;
using Robust.Shared.Network;
using Robust.Shared.Serialization;
namespace Content.Shared._RMC14.Mentor;
public sealed class MentorStatusMsg : NetMessage
{
public override MsgGroups MsgGroup => MsgGroups.Core;
public bool IsMentor;
public bool CanReMentor;
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer)
{
IsMentor = buffer.ReadBoolean();
CanReMentor = buffer.ReadBoolean();
}
public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer)
{
buffer.Write(IsMentor);
buffer.Write(CanReMentor);
}
}

View File

@ -0,0 +1,9 @@
using Robust.Shared.Serialization;
namespace Content.Shared._RMC14.Mentor;
[Serializable, NetSerializable]
public sealed class SendMentorHelpMessageEvent(string message) : EntityEventArgs
{
public readonly string Message = message;
}

View File

@ -0,0 +1,4 @@
- files: [ "mhelp.ogg" ]
license: "CC-BY-SA-3.0"
copyright: "Taken from cmss13"
source: "https://github.com/cmss13-devs/cmss13/blob/f0fb0e64d6e577e2592da29aa4acfe0a89713ce1/sound/effects/mhelp.ogg"

Binary file not shown.

View File

@ -1,56 +1,4 @@
Entries:
- author: deltanedas
changes:
- message: Syndicate duffelbags can be reverse engineered for bags of holding.
type: Add
- message: Hyper-capacity powercells can be made by reverse engineering high-capacity
powercells, which can also be reverse engineered to make microreactor cells.
type: Add
- message: Moonboots can now be reverse engineered for speedboots.
type: Add
- message: Any cloning board that gets reverse engineered unlocks every cloning
board instead of itself (which was useless since you already have it).
type: Tweak
- message: Removed reverse engineering from items that made no sense to reverse
engineer like roundstart equipment or tier 1 techs.
type: Remove
id: 592
time: '2024-10-02T13:04:44.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/1915
- author: Radezolid
changes:
- message: Moved the reverse engineered combat hardsuits to the security techfab.
You can still access them as a traitor with an emag on the exosuit fabricator.
type: Tweak
id: 593
time: '2024-10-02T13:19:50.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/1956
- author: deltanedas
changes:
- message: Merged last ~weeks changes from upstream.
type: Add
- message: Fixed captain requiring global whitelist instead of just the role whitelist.
type: Fix
- message: Frezon nerfed was reverted.
type: Tweak
id: 594
time: '2024-10-02T22:09:14.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/1957
- author: Unkn0wnGh0st333
changes:
- message: Shoukou's Bridge and Command Room have been remodeled, alongside tons
of station pets, and slice of life necessities added! Yay! :3
type: Tweak
id: 595
time: '2024-10-03T01:26:11.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/1920
- author: Avalon-Proto
changes:
- message: Goliaths are far less hardy than they once were
type: Tweak
id: 596
time: '2024-10-03T12:50:47.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/1955
- author: MilonPL
changes:
- message: Reverted the frezon price nerf. Atmosians rejoice!
@ -3921,3 +3869,42 @@
id: 1091
time: '2025-03-01T12:32:45.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/3081
- author: Smugman
changes:
- message: Syndicate listening posts have been SIGNIFICANTLY remodeled, and given
a self destruct device. Validhunt one Today!
type: Tweak
id: 1092
time: '2025-03-01T14:26:38.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/2912
- author: ewokswagger
changes:
- message: Added Curator Chat! Open with F1 to talk with a Curator for game-related
assistance and events.
type: Add
id: 1093
time: '2025-03-02T00:03:28.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/3070
- author: IAmNotGray
changes:
- message: The TEG on Elegance is now accessible by Station Engineers. Read the
paper on station for more information!
type: Tweak
id: 1094
time: '2025-03-02T17:22:21.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/3067
- author: Field Command
changes:
- message: Reworked engineering, bridge and sec. Added perma to now include prisoner
slots and all that entails with that. Soft cap up from 20 to 25.
type: Tweak
id: 1095
time: '2025-03-02T17:30:06.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/2960
- author: deltanedas
changes:
- message: Renamed ammonia back to miasma.
type: Tweak
id: 1096
time: '2025-03-02T18:06:30.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/3083

File diff suppressed because one or more lines are too long

View File

@ -10,3 +10,6 @@ ui-options-function-nano-chat-navigate-up = Navigate up
ui-options-function-nano-chat-navigate-down = Navigate down
ui-options-function-nano-chat-navigate-up-unread = Navigate up to next unread
ui-options-function-nano-chat-navigate-down-unread = Navigate down to next unread
## DeltaV staff chats
ui-options-function-open-staff-chats-deltav = Open admin help and curator chat

View File

@ -0,0 +1 @@
gases-miasma = Miasma

View File

@ -0,0 +1 @@
ent-GasMinerAmmonia = miasma gas miner

View File

@ -0,0 +1,2 @@
ent-AmmoniaCanister = miasma canister
.desc = A canister that can contain any type of gas. This one is supposed to contain miasma. It can be attached to connector ports using a wrench.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -61,7 +61,7 @@
- type: gas
id: 6
name: gases-ammonia
name: gases-miasma # DeltaV
specificHeat: 20
heatCapacityRatio: 1.4
molarMass: 44
@ -69,7 +69,7 @@
gasOverlayState: miasma
gasMolesVisible: 2
gasVisbilityFactor: 3.5
color: 56941E
color: 1E092A # DeltaV - purple instead of green, matches the sprite
reagent: Ammonia
pricePerMole: 0.15

View File

@ -3,7 +3,7 @@
mapName: 'Byōin'
mapPath: /Maps/byoin.yml
minPlayers: 0
maxPlayers: 20
maxPlayers: 25
stations:
Byoin:
stationProto: StandardNanotrasenStation
@ -39,9 +39,10 @@
Mime: [ 1, 1 ]
Librarian: [ 1, 1 ]
ServiceWorker: [ 1, 1 ]
Boxer: [ 2, 2 ]
#engineering
AtmosphericTechnician: [ 1, 1 ]
StationEngineer: [ 1, 2 ]
AtmosphericTechnician: [ 2, 2 ]
StationEngineer: [ 2, 2 ]
TechnicalAssistant: [ 1, 1 ]
#medical
Chemist: [ 1, 1 ]
@ -52,7 +53,7 @@
MedicalIntern: [ 1, 1 ]
#science
Roboticist: [ 1, 1 ]
Scientist: [ 1, 2 ]
Scientist: [ 2, 2 ]
ResearchAssistant: [ 1, 1 ]
ForensicMantis: [ 1, 1 ]
Chaplain: [ 1, 1 ]
@ -62,15 +63,18 @@
#security
Warden: [ 1, 1 ]
Detective: [ 1, 1 ]
SecurityOfficer: [ 1, 2 ]
SecurityOfficer: [ 2, 2 ]
SecurityCadet: [ 1, 1 ]
Brigmedic: [ 1, 1 ]
Prisoner: [ 2, 2 ]
PrisonGuard: [ 1, 1 ]
#justice
Clerk: [ 1, 1 ]
Prosecutor: [ 1, 1 ]
Lawyer: [ 1, 1 ]
#supply
SalvageSpecialist: [ 1, 1 ]
CargoTechnician: [ 1, 2 ]
SalvageSpecialist: [ 2, 2 ]
CargoTechnician: [ 2, 2 ]
Courier: [ 1, 1 ]
CargoAssistant: [ 1, 1 ]
#civilian

View File

@ -475,3 +475,32 @@
id: TapeRecorderTranscript
name: record transcript
# TODO: could have a unique sprite in the future
- type: entity
parent: BoxFolderRed
id: BoxFolderFakeNukeCodes
name: fake nuclear code folder
description: contains a single paper that looks like it would contain a nuke code.
components:
- type: Sprite
sprite: Objects/Misc/bureaucracy.rsi
layers:
- state: folder-colormap
color: "#cc2323"
- state: folder-base
- state: folder-stamp-inverse
color: "#1dff00"
- type: StorageFill
contents:
- id: FakeNukeCodePaper
- type: entity
parent: Paper
id: FakeNukeCodePaper
suffix: Fake
name: nuclear authentication codes
components:
- type: Paper
content: |2
[color=red]TOP SECRET![/color]
nuclear fission explosive (NT-XXXXXX) code: XXXXXX

View File

@ -216,3 +216,38 @@
stateDoorOpen: justice_open
- type: AccessReader
access: [["Justice"]]
- type: entity
parent: ClosetWallBlack
id: StampLockerListeningPost
name: stamp closet
description: A closet packed with forged stamps, CentComm not included.
suffix: DO NOT MAP
components:
- type: StorageFill
contents:
- id: RubberStampApproved
- id: RubberStampDenied
- id: RubberStampAdminAssistant
- id: RubberStampCaptain
- id: RubberStampChaplain
- id: RubberStampCE
- id: RubberStampChiefJustice
- id: RubberStampChaplain
- id: RubberStampCMO
- id: RubberStampClown
- id: RubberStampDetective
- id: RubberStampHop
- id: RubberStampHos
- id: RubberStampLawyer
- id: RubberStampQm
- id: RubberStampMime
- id: RubberStampRd
- id: RubberStampNotary
- id: RubberStampProsec
- id: RubberStampMantis
- id: RubberStampPsychologist
- id: RubberStampSyndicate
- id: RubberStampTrader
- id: RubberStampWarden
- id: RubberStampGreytide # a disturbance in the rising grey water.

View File

@ -6,6 +6,8 @@ You and your fellow crewmates are tasked with working together, surviving, and h
[bold]Make sure to follow all server rules.[/bold] You can ask questions or report rule breaks to the [color=#EB2D3A][bold]admin team[/bold][/color] by using the [bold]admin help menu[/bold]. ([italic]accessible by pressing [/italic][color=yellow][bold][keybind="OpenAHelp"/][/bold][/color])
Curators' goal is to present an interesting and enjoyable game experience. They may do this through influencing the round as a spectator through events. You can contact a curator for an event or need general game help by using the Curator Chat menu. ([italic]accessible by pressing [/italic][color=yellow][bold][keybind="OpenAHelp"/][/bold][/color])
More detailed guides about [italic]specific jobs[/italic] and [italic]mechanics[/italic] can be found [textlink="here." link="SS14"/]
This guide can be reopened at any time using [color=yellow][bold][keybind="OpenGuidebook"][/bold][/color].