Compare commits
5 Commits
LocalHelpe
...
ed-29-09-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb0f7c9632 | ||
|
|
4d8d5d5c82 | ||
|
|
60ca78ed9b | ||
|
|
beb681ce7b | ||
|
|
752d9b8ff4 |
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@@ -19,7 +19,7 @@
|
|||||||
/Resources/engineCommandPerms.yml @moonheart08 @Chief-Engineer
|
/Resources/engineCommandPerms.yml @moonheart08 @Chief-Engineer
|
||||||
/Resources/clientCommandPerms.yml @moonheart08 @Chief-Engineer
|
/Resources/clientCommandPerms.yml @moonheart08 @Chief-Engineer
|
||||||
|
|
||||||
/Resources/Prototypes/Maps/** @Emisse
|
/Resources/Prototypes/Maps/ @Emisse
|
||||||
|
|
||||||
/Resources/Prototypes/Body/ @DrSmugleaf # suffering
|
/Resources/Prototypes/Body/ @DrSmugleaf # suffering
|
||||||
/Resources/Prototypes/Entities/Mobs/Player/ @DrSmugleaf
|
/Resources/Prototypes/Entities/Mobs/Player/ @DrSmugleaf
|
||||||
|
|||||||
4
.github/workflows/publish.yml
vendored
4
.github/workflows/publish.yml
vendored
@@ -5,8 +5,8 @@ concurrency:
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
# schedule:
|
schedule:
|
||||||
# - cron: '0 10 * * *'
|
- cron: '0 10 * * *'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
|
|||||||
{
|
{
|
||||||
private readonly IEntityManager _entManager;
|
private readonly IEntityManager _entManager;
|
||||||
private readonly SpriteSystem _spriteSystem;
|
private readonly SpriteSystem _spriteSystem;
|
||||||
private readonly SharedNavMapSystem _navMapSystem;
|
|
||||||
|
|
||||||
private EntityUid? _owner;
|
private EntityUid? _owner;
|
||||||
private NetEntity? _trackedEntity;
|
private NetEntity? _trackedEntity;
|
||||||
@@ -43,32 +42,19 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
|
|||||||
|
|
||||||
private const float SilencingDuration = 2.5f;
|
private const float SilencingDuration = 2.5f;
|
||||||
|
|
||||||
// Colors
|
|
||||||
private Color _wallColor = new Color(64, 64, 64);
|
|
||||||
private Color _tileColor = new Color(28, 28, 28);
|
|
||||||
private Color _monitorBlipColor = Color.Cyan;
|
|
||||||
private Color _untrackedEntColor = Color.DimGray;
|
|
||||||
private Color _regionBaseColor = new Color(154, 154, 154);
|
|
||||||
private Color _inactiveColor = StyleNano.DisabledFore;
|
|
||||||
private Color _statusTextColor = StyleNano.GoodGreenFore;
|
|
||||||
private Color _goodColor = Color.LimeGreen;
|
|
||||||
private Color _warningColor = new Color(255, 182, 72);
|
|
||||||
private Color _dangerColor = new Color(255, 67, 67);
|
|
||||||
|
|
||||||
public AtmosAlertsComputerWindow(AtmosAlertsComputerBoundUserInterface userInterface, EntityUid? owner)
|
public AtmosAlertsComputerWindow(AtmosAlertsComputerBoundUserInterface userInterface, EntityUid? owner)
|
||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
_entManager = IoCManager.Resolve<IEntityManager>();
|
_entManager = IoCManager.Resolve<IEntityManager>();
|
||||||
_spriteSystem = _entManager.System<SpriteSystem>();
|
_spriteSystem = _entManager.System<SpriteSystem>();
|
||||||
_navMapSystem = _entManager.System<SharedNavMapSystem>();
|
|
||||||
|
|
||||||
// Pass the owner to nav map
|
// Pass the owner to nav map
|
||||||
_owner = owner;
|
_owner = owner;
|
||||||
NavMap.Owner = _owner;
|
NavMap.Owner = _owner;
|
||||||
|
|
||||||
// Set nav map colors
|
// Set nav map colors
|
||||||
NavMap.WallColor = _wallColor;
|
NavMap.WallColor = new Color(64, 64, 64);
|
||||||
NavMap.TileColor = _tileColor;
|
NavMap.TileColor = Color.DimGray * NavMap.WallColor;
|
||||||
|
|
||||||
// Set nav map grid uid
|
// Set nav map grid uid
|
||||||
var stationName = Loc.GetString("atmos-alerts-window-unknown-location");
|
var stationName = Loc.GetString("atmos-alerts-window-unknown-location");
|
||||||
@@ -193,9 +179,6 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
|
|||||||
// Add tracked entities to the nav map
|
// Add tracked entities to the nav map
|
||||||
foreach (var device in console.AtmosDevices)
|
foreach (var device in console.AtmosDevices)
|
||||||
{
|
{
|
||||||
if (!device.NetEntity.Valid)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!NavMap.Visible)
|
if (!NavMap.Visible)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -226,7 +209,7 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
|
|||||||
if (consoleCoords != null && consoleUid != null)
|
if (consoleCoords != null && consoleUid != null)
|
||||||
{
|
{
|
||||||
var texture = _spriteSystem.Frame0(new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")));
|
var texture = _spriteSystem.Frame0(new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")));
|
||||||
var blip = new NavMapBlip(consoleCoords.Value, texture, _monitorBlipColor, true, false);
|
var blip = new NavMapBlip(consoleCoords.Value, texture, Color.Cyan, true, false);
|
||||||
NavMap.TrackedEntities[consoleUid.Value] = blip;
|
NavMap.TrackedEntities[consoleUid.Value] = blip;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,7 +258,7 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
|
|||||||
VerticalAlignment = VAlignment.Center,
|
VerticalAlignment = VAlignment.Center,
|
||||||
};
|
};
|
||||||
|
|
||||||
label.SetMarkup(Loc.GetString("atmos-alerts-window-no-active-alerts", ("color", _statusTextColor.ToHexNoAlpha())));
|
label.SetMarkup(Loc.GetString("atmos-alerts-window-no-active-alerts", ("color", StyleNano.GoodGreenFore.ToHexNoAlpha())));
|
||||||
|
|
||||||
AlertsTable.AddChild(label);
|
AlertsTable.AddChild(label);
|
||||||
}
|
}
|
||||||
@@ -287,34 +270,6 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
|
|||||||
else
|
else
|
||||||
MasterTabContainer.SetTabTitle(0, Loc.GetString("atmos-alerts-window-tab-alerts", ("value", activeAlarmCount)));
|
MasterTabContainer.SetTabTitle(0, Loc.GetString("atmos-alerts-window-tab-alerts", ("value", activeAlarmCount)));
|
||||||
|
|
||||||
// Update sensor regions
|
|
||||||
NavMap.RegionOverlays.Clear();
|
|
||||||
var prioritizedRegionOverlays = new Dictionary<NavMapRegionOverlay, int>();
|
|
||||||
|
|
||||||
if (_owner != null &&
|
|
||||||
_entManager.TryGetComponent<TransformComponent>(_owner, out var xform) &&
|
|
||||||
_entManager.TryGetComponent<NavMapComponent>(xform.GridUid, out var navMap))
|
|
||||||
{
|
|
||||||
var regionOverlays = _navMapSystem.GetNavMapRegionOverlays(_owner.Value, navMap, AtmosAlertsComputerUiKey.Key);
|
|
||||||
|
|
||||||
foreach (var (regionOwner, regionOverlay) in regionOverlays)
|
|
||||||
{
|
|
||||||
var alarmState = GetAlarmState(regionOwner);
|
|
||||||
|
|
||||||
if (!TryGetSensorRegionColor(regionOwner, alarmState, out var regionColor))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
regionOverlay.Color = regionColor;
|
|
||||||
|
|
||||||
var priority = (_trackedEntity == regionOwner) ? 999 : (int)alarmState;
|
|
||||||
prioritizedRegionOverlays.Add(regionOverlay, priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort overlays according to their priority
|
|
||||||
var sortedOverlays = prioritizedRegionOverlays.OrderBy(x => x.Value).Select(x => x.Key).ToList();
|
|
||||||
NavMap.RegionOverlays = sortedOverlays;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auto-scroll re-enable
|
// Auto-scroll re-enable
|
||||||
if (_autoScrollAwaitsUpdate)
|
if (_autoScrollAwaitsUpdate)
|
||||||
{
|
{
|
||||||
@@ -335,7 +290,7 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
|
|||||||
var coords = _entManager.GetCoordinates(metaData.NetCoordinates);
|
var coords = _entManager.GetCoordinates(metaData.NetCoordinates);
|
||||||
|
|
||||||
if (_trackedEntity != null && _trackedEntity != metaData.NetEntity)
|
if (_trackedEntity != null && _trackedEntity != metaData.NetEntity)
|
||||||
color *= _untrackedEntColor;
|
color *= Color.DimGray;
|
||||||
|
|
||||||
var selectable = true;
|
var selectable = true;
|
||||||
var blip = new NavMapBlip(coords, _spriteSystem.Frame0(texture), color, _trackedEntity == metaData.NetEntity, selectable);
|
var blip = new NavMapBlip(coords, _spriteSystem.Frame0(texture), color, _trackedEntity == metaData.NetEntity, selectable);
|
||||||
@@ -343,24 +298,6 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
|
|||||||
NavMap.TrackedEntities[metaData.NetEntity] = blip;
|
NavMap.TrackedEntities[metaData.NetEntity] = blip;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryGetSensorRegionColor(NetEntity regionOwner, AtmosAlarmType alarmState, out Color color)
|
|
||||||
{
|
|
||||||
color = Color.White;
|
|
||||||
|
|
||||||
var blip = GetBlipTexture(alarmState);
|
|
||||||
|
|
||||||
if (blip == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Color the region based on alarm state and entity tracking
|
|
||||||
color = blip.Value.Item2 * _regionBaseColor;
|
|
||||||
|
|
||||||
if (_trackedEntity != null && _trackedEntity != regionOwner)
|
|
||||||
color *= _untrackedEntColor;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateUIEntry(AtmosAlertsComputerEntry entry, int index, Control table, AtmosAlertsComputerComponent console, AtmosAlertsFocusDeviceData? focusData = null)
|
private void UpdateUIEntry(AtmosAlertsComputerEntry entry, int index, Control table, AtmosAlertsComputerComponent console, AtmosAlertsFocusDeviceData? focusData = null)
|
||||||
{
|
{
|
||||||
// Make new UI entry if required
|
// Make new UI entry if required
|
||||||
@@ -597,13 +534,13 @@ public sealed partial class AtmosAlertsComputerWindow : FancyWindow
|
|||||||
switch (alarmState)
|
switch (alarmState)
|
||||||
{
|
{
|
||||||
case AtmosAlarmType.Invalid:
|
case AtmosAlarmType.Invalid:
|
||||||
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")), _inactiveColor); break;
|
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")), StyleNano.DisabledFore); break;
|
||||||
case AtmosAlarmType.Normal:
|
case AtmosAlarmType.Normal:
|
||||||
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")), _goodColor); break;
|
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")), Color.LimeGreen); break;
|
||||||
case AtmosAlarmType.Warning:
|
case AtmosAlarmType.Warning:
|
||||||
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_triangle.png")), _warningColor); break;
|
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_triangle.png")), new Color(255, 182, 72)); break;
|
||||||
case AtmosAlarmType.Danger:
|
case AtmosAlarmType.Danger:
|
||||||
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_square.png")), _dangerColor); break;
|
output = (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_square.png")), new Color(255, 67, 67)); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
|||||||
@@ -43,8 +43,6 @@ public sealed partial class ContentAudioSystem
|
|||||||
|
|
||||||
private void CP14UpdateAmbientLoops()
|
private void CP14UpdateAmbientLoops()
|
||||||
{
|
{
|
||||||
return; //DISABLED UNTIL CLIENT ERROR SPAM FIXED
|
|
||||||
|
|
||||||
if (_timing.CurTime <= _nextUpdateTime)
|
if (_timing.CurTime <= _nextUpdateTime)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ public sealed partial class ContentAudioSystem
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly IBaseClient _client = default!;
|
[Dependency] private readonly IBaseClient _client = default!;
|
||||||
[Dependency] private readonly ClientGameTicker _gameTicker = default!;
|
[Dependency] private readonly ClientGameTicker _gameTicker = default!;
|
||||||
|
[Dependency] private readonly IStateManager _stateManager = default!;
|
||||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||||
|
|
||||||
private readonly AudioParams _lobbySoundtrackParams = new(-5f, 1, 0, 0, 0, false, 0f);
|
private readonly AudioParams _lobbySoundtrackParams = new(-5f, 1, 0, 0, 0, false, 0f);
|
||||||
@@ -70,7 +71,7 @@ public sealed partial class ContentAudioSystem
|
|||||||
Subs.CVar(_configManager, CCVars.LobbyMusicEnabled, LobbyMusicCVarChanged);
|
Subs.CVar(_configManager, CCVars.LobbyMusicEnabled, LobbyMusicCVarChanged);
|
||||||
Subs.CVar(_configManager, CCVars.LobbyMusicVolume, LobbyMusicVolumeCVarChanged);
|
Subs.CVar(_configManager, CCVars.LobbyMusicVolume, LobbyMusicVolumeCVarChanged);
|
||||||
|
|
||||||
_state.OnStateChanged += StateManagerOnStateChanged;
|
_stateManager.OnStateChanged += StateManagerOnStateChanged;
|
||||||
|
|
||||||
_client.PlayerLeaveServer += OnLeave;
|
_client.PlayerLeaveServer += OnLeave;
|
||||||
|
|
||||||
@@ -114,7 +115,7 @@ public sealed partial class ContentAudioSystem
|
|||||||
|
|
||||||
private void LobbyMusicCVarChanged(bool musicEnabled)
|
private void LobbyMusicCVarChanged(bool musicEnabled)
|
||||||
{
|
{
|
||||||
if (musicEnabled && _state.CurrentState is LobbyState)
|
if (musicEnabled && _stateManager.CurrentState is LobbyState)
|
||||||
{
|
{
|
||||||
StartLobbyMusic();
|
StartLobbyMusic();
|
||||||
}
|
}
|
||||||
@@ -233,7 +234,7 @@ public sealed partial class ContentAudioSystem
|
|||||||
|
|
||||||
private void ShutdownLobbyMusic()
|
private void ShutdownLobbyMusic()
|
||||||
{
|
{
|
||||||
_state.OnStateChanged -= StateManagerOnStateChanged;
|
_stateManager.OnStateChanged -= StateManagerOnStateChanged;
|
||||||
|
|
||||||
_client.PlayerLeaveServer -= OnLeave;
|
_client.PlayerLeaveServer -= OnLeave;
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
using Content.Shared.Timing;
|
|
||||||
using Content.Shared.Cargo.Systems;
|
|
||||||
|
|
||||||
namespace Content.Client.Cargo.Systems;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This handles...
|
|
||||||
/// </summary>
|
|
||||||
public sealed class ClientPriceGunSystem : SharedPriceGunSystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly UseDelaySystem _useDelay = default!;
|
|
||||||
|
|
||||||
protected override bool GetPriceOrBounty(EntityUid priceGunUid, EntityUid target, EntityUid user)
|
|
||||||
{
|
|
||||||
if (!TryComp(priceGunUid, out UseDelayComponent? useDelay) || _useDelay.IsDelayed((priceGunUid, useDelay)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// It feels worse if the cooldown is predicted but the popup isn't! So only do the cooldown reset on the server.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -21,16 +21,6 @@ internal sealed class ChatManager : IChatManager
|
|||||||
_sawmill.Level = LogLevel.Info;
|
_sawmill.Level = LogLevel.Info;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendAdminAlert(string message)
|
|
||||||
{
|
|
||||||
// See server-side manager. This just exists for shared code.
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendAdminAlert(EntityUid player, string message)
|
|
||||||
{
|
|
||||||
// See server-side manager. This just exists for shared code.
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendMessage(string text, ChatSelectChannel channel)
|
public void SendMessage(string text, ChatSelectChannel channel)
|
||||||
{
|
{
|
||||||
var str = text.ToString();
|
var str = text.ToString();
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ using Content.Shared.Chat;
|
|||||||
|
|
||||||
namespace Content.Client.Chat.Managers
|
namespace Content.Client.Chat.Managers
|
||||||
{
|
{
|
||||||
public interface IChatManager : ISharedChatManager
|
public interface IChatManager
|
||||||
{
|
{
|
||||||
|
void Initialize();
|
||||||
|
|
||||||
public void SendMessage(string text, ChatSelectChannel channel);
|
public void SendMessage(string text, ChatSelectChannel channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -327,8 +327,7 @@ public sealed class ClientClothingSystem : ClothingSystem
|
|||||||
if (layerData.State is not null && inventory.SpeciesId is not null && layerData.State.EndsWith(inventory.SpeciesId))
|
if (layerData.State is not null && inventory.SpeciesId is not null && layerData.State.EndsWith(inventory.SpeciesId))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (_displacement.TryAddDisplacement(displacementData, sprite, index, key, revealedLayers))
|
_displacement.TryAddDisplacement(displacementData, sprite, index, key, revealedLayers);
|
||||||
index++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
using Content.Shared.Damage.Prototypes;
|
|
||||||
using Content.Shared.Overlays;
|
using Content.Shared.Overlays;
|
||||||
using Robust.Client.Player;
|
using Robust.Client.Player;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Content.Client.Commands;
|
namespace Content.Client.Commands;
|
||||||
@@ -36,7 +34,7 @@ public sealed class ShowHealthBarsCommand : LocalizedCommands
|
|||||||
{
|
{
|
||||||
var showHealthBarsComponent = new ShowHealthBarsComponent
|
var showHealthBarsComponent = new ShowHealthBarsComponent
|
||||||
{
|
{
|
||||||
DamageContainers = args.Select(arg => new ProtoId<DamageContainerPrototype>(arg)).ToList(),
|
DamageContainers = args.ToList(),
|
||||||
HealthStatusIcon = null,
|
HealthStatusIcon = null,
|
||||||
NetSyncEnabled = false
|
NetSyncEnabled = false
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using Content.Client.Chat.Managers;
|
|||||||
using Content.Client.DebugMon;
|
using Content.Client.DebugMon;
|
||||||
using Content.Client.Eui;
|
using Content.Client.Eui;
|
||||||
using Content.Client.Fullscreen;
|
using Content.Client.Fullscreen;
|
||||||
using Content.Client.GameTicking.Managers;
|
|
||||||
using Content.Client.GhostKick;
|
using Content.Client.GhostKick;
|
||||||
using Content.Client.Guidebook;
|
using Content.Client.Guidebook;
|
||||||
using Content.Client.Input;
|
using Content.Client.Input;
|
||||||
@@ -71,8 +70,8 @@ namespace Content.Client.Entry
|
|||||||
[Dependency] private readonly IResourceManager _resourceManager = default!;
|
[Dependency] private readonly IResourceManager _resourceManager = default!;
|
||||||
[Dependency] private readonly IReplayLoadManager _replayLoad = default!;
|
[Dependency] private readonly IReplayLoadManager _replayLoad = default!;
|
||||||
[Dependency] private readonly ILogManager _logManager = default!;
|
[Dependency] private readonly ILogManager _logManager = default!;
|
||||||
|
[Dependency] private readonly ContentReplayPlaybackManager _replayMan = default!;
|
||||||
[Dependency] private readonly DebugMonitorManager _debugMonitorManager = default!;
|
[Dependency] private readonly DebugMonitorManager _debugMonitorManager = default!;
|
||||||
[Dependency] private readonly TitleWindowManager _titleWindowManager = default!;
|
|
||||||
|
|
||||||
public override void Init()
|
public override void Init()
|
||||||
{
|
{
|
||||||
@@ -142,12 +141,6 @@ namespace Content.Client.Entry
|
|||||||
_configManager.SetCVar("interface.resolutionAutoScaleMinimum", 0.5f);
|
_configManager.SetCVar("interface.resolutionAutoScaleMinimum", 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Shutdown()
|
|
||||||
{
|
|
||||||
base.Shutdown();
|
|
||||||
_titleWindowManager.Shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void PostInit()
|
public override void PostInit()
|
||||||
{
|
{
|
||||||
base.PostInit();
|
base.PostInit();
|
||||||
@@ -168,7 +161,6 @@ namespace Content.Client.Entry
|
|||||||
_userInterfaceManager.SetDefaultTheme(_configManager.GetCVar(CCVars.UIDefaultInterfaceTheme));
|
_userInterfaceManager.SetDefaultTheme(_configManager.GetCVar(CCVars.UIDefaultInterfaceTheme));
|
||||||
_userInterfaceManager.SetActiveTheme(_configManager.GetCVar(CVars.InterfaceTheme));
|
_userInterfaceManager.SetActiveTheme(_configManager.GetCVar(CVars.InterfaceTheme));
|
||||||
_documentParsingManager.Initialize();
|
_documentParsingManager.Initialize();
|
||||||
_titleWindowManager.Initialize();
|
|
||||||
|
|
||||||
_baseClient.RunLevelChanged += (_, args) =>
|
_baseClient.RunLevelChanged += (_, args) =>
|
||||||
{
|
{
|
||||||
@@ -200,7 +192,7 @@ namespace Content.Client.Entry
|
|||||||
_resourceManager,
|
_resourceManager,
|
||||||
ReplayConstants.ReplayZipFolder.ToRootedPath());
|
ReplayConstants.ReplayZipFolder.ToRootedPath());
|
||||||
|
|
||||||
_playbackMan.LastLoad = (null, ReplayConstants.ReplayZipFolder.ToRootedPath());
|
_replayMan.LastLoad = (null, ReplayConstants.ReplayZipFolder.ToRootedPath());
|
||||||
_replayLoad.LoadAndStartReplay(reader);
|
_replayLoad.LoadAndStartReplay(reader);
|
||||||
}
|
}
|
||||||
else if (_gameController.LaunchState.FromLauncher)
|
else if (_gameController.LaunchState.FromLauncher)
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
using Content.Shared.CCVar;
|
|
||||||
using Robust.Client;
|
|
||||||
using Robust.Client.Graphics;
|
|
||||||
using Robust.Shared;
|
|
||||||
using Robust.Shared.Configuration;
|
|
||||||
|
|
||||||
namespace Content.Client.GameTicking.Managers;
|
|
||||||
|
|
||||||
public sealed class TitleWindowManager
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IBaseClient _client = default!;
|
|
||||||
[Dependency] private readonly IClyde _clyde = default!;
|
|
||||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
|
||||||
[Dependency] private readonly IGameController _gameController = default!;
|
|
||||||
|
|
||||||
public void Initialize()
|
|
||||||
{
|
|
||||||
_cfg.OnValueChanged(CVars.GameHostName, OnHostnameChange, true);
|
|
||||||
_cfg.OnValueChanged(CCVars.GameHostnameInTitlebar, OnHostnameTitleChange, true);
|
|
||||||
|
|
||||||
_client.RunLevelChanged += OnRunLevelChangedChange;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Shutdown()
|
|
||||||
{
|
|
||||||
_cfg.UnsubValueChanged(CVars.GameHostName, OnHostnameChange);
|
|
||||||
_cfg.UnsubValueChanged(CCVars.GameHostnameInTitlebar, OnHostnameTitleChange);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnHostnameChange(string hostname)
|
|
||||||
{
|
|
||||||
var defaultWindowTitle = _gameController.GameTitle();
|
|
||||||
|
|
||||||
// Since the game assumes the server name is MyServer and that GameHostnameInTitlebar CCVar is true by default
|
|
||||||
// Lets just... not show anything. This also is used to revert back to just the game title on disconnect.
|
|
||||||
if (_client.RunLevel == ClientRunLevel.Initialize)
|
|
||||||
{
|
|
||||||
_clyde.SetWindowTitle(defaultWindowTitle);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_cfg.GetCVar(CCVars.GameHostnameInTitlebar))
|
|
||||||
// If you really dislike the dash I guess change it here
|
|
||||||
_clyde.SetWindowTitle(hostname + " - " + defaultWindowTitle);
|
|
||||||
else
|
|
||||||
_clyde.SetWindowTitle(defaultWindowTitle);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clients by default assume game.hostname_in_titlebar is true
|
|
||||||
// but we need to clear it as soon as we join and actually receive the servers preference on this.
|
|
||||||
// This will ensure we rerun OnHostnameChange and set the correct title bar name.
|
|
||||||
private void OnHostnameTitleChange(bool colonthree)
|
|
||||||
{
|
|
||||||
OnHostnameChange(_cfg.GetCVar(CVars.GameHostName));
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is just used we can rerun the hostname change function when we disconnect to revert back to just the games title.
|
|
||||||
private void OnRunLevelChangedChange(object? sender, RunLevelChangedEventArgs runLevelChangedEventArgs)
|
|
||||||
{
|
|
||||||
OnHostnameChange(_cfg.GetCVar(CVars.GameHostName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -130,9 +130,9 @@ namespace Content.Client.Hands.Systems
|
|||||||
OnPlayerHandsAdded?.Invoke(hands);
|
OnPlayerHandsAdded?.Invoke(hands);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DoDrop(EntityUid uid, Hand hand, bool doDropInteraction = true, HandsComponent? hands = null, bool log = true)
|
public override void DoDrop(EntityUid uid, Hand hand, bool doDropInteraction = true, HandsComponent? hands = null)
|
||||||
{
|
{
|
||||||
base.DoDrop(uid, hand, doDropInteraction, hands, log);
|
base.DoDrop(uid, hand, doDropInteraction, hands);
|
||||||
|
|
||||||
if (TryComp(hand.HeldEntity, out SpriteComponent? sprite))
|
if (TryComp(hand.HeldEntity, out SpriteComponent? sprite))
|
||||||
sprite.RenderOrder = EntityManager.CurrentTick.Value;
|
sprite.RenderOrder = EntityManager.CurrentTick.Value;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using Content.Shared.Localizations;
|
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
@@ -17,10 +16,19 @@ public sealed partial class PlaytimeStatsEntry : ContainerButton
|
|||||||
|
|
||||||
RoleLabel.Text = role;
|
RoleLabel.Text = role;
|
||||||
Playtime = playtime; // store the TimeSpan value directly
|
Playtime = playtime; // store the TimeSpan value directly
|
||||||
PlaytimeLabel.Text = ContentLocalizationManager.FormatPlaytime(playtime); // convert to string for display
|
PlaytimeLabel.Text = ConvertTimeSpanToHoursMinutes(playtime); // convert to string for display
|
||||||
BackgroundColorPanel.PanelOverride = styleBox;
|
BackgroundColorPanel.PanelOverride = styleBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string ConvertTimeSpanToHoursMinutes(TimeSpan timeSpan)
|
||||||
|
{
|
||||||
|
var hours = (int)timeSpan.TotalHours;
|
||||||
|
var minutes = timeSpan.Minutes;
|
||||||
|
|
||||||
|
var formattedTimeLoc = Loc.GetString("ui-playtime-time-format", ("hours", hours), ("minutes", minutes));
|
||||||
|
return formattedTimeLoc;
|
||||||
|
}
|
||||||
|
|
||||||
public void UpdateShading(StyleBoxFlat styleBox)
|
public void UpdateShading(StyleBoxFlat styleBox)
|
||||||
{
|
{
|
||||||
BackgroundColorPanel.PanelOverride = styleBox;
|
BackgroundColorPanel.PanelOverride = styleBox;
|
||||||
|
|||||||
@@ -104,7 +104,8 @@ public sealed partial class PlaytimeStatsWindow : FancyWindow
|
|||||||
{
|
{
|
||||||
var overallPlaytime = _jobRequirementsManager.FetchOverallPlaytime();
|
var overallPlaytime = _jobRequirementsManager.FetchOverallPlaytime();
|
||||||
|
|
||||||
OverallPlaytimeLabel.Text = Loc.GetString("ui-playtime-overall", ("time", overallPlaytime));
|
var formattedPlaytime = ConvertTimeSpanToHoursMinutes(overallPlaytime);
|
||||||
|
OverallPlaytimeLabel.Text = Loc.GetString("ui-playtime-overall", ("time", formattedPlaytime));
|
||||||
|
|
||||||
var rolePlaytimes = _jobRequirementsManager.FetchPlaytimeByRoles();
|
var rolePlaytimes = _jobRequirementsManager.FetchPlaytimeByRoles();
|
||||||
|
|
||||||
@@ -133,4 +134,13 @@ public sealed partial class PlaytimeStatsWindow : FancyWindow
|
|||||||
_sawmill.Error($"The provided playtime string '{playtimeString}' is not in the correct format.");
|
_sawmill.Error($"The provided playtime string '{playtimeString}' is not in the correct format.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string ConvertTimeSpanToHoursMinutes(TimeSpan timeSpan)
|
||||||
|
{
|
||||||
|
var hours = (int) timeSpan.TotalHours;
|
||||||
|
var minutes = timeSpan.Minutes;
|
||||||
|
|
||||||
|
var formattedTimeLoc = Loc.GetString("ui-playtime-time-format", ("hours", hours), ("minutes", minutes));
|
||||||
|
return formattedTimeLoc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ namespace Content.Client.Inventory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EntMan.TryGetComponent<HandsComponent>(Owner, out var handsComp) && handsComp.CanBeStripped)
|
if (EntMan.TryGetComponent<HandsComponent>(Owner, out var handsComp))
|
||||||
{
|
{
|
||||||
// good ol hands shit code. there is a GuiHands comparer that does the same thing... but these are hands
|
// good ol hands shit code. there is a GuiHands comparer that does the same thing... but these are hands
|
||||||
// and not gui hands... which are different...
|
// and not gui hands... which are different...
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ using Content.Client.Clickable;
|
|||||||
using Content.Client.DebugMon;
|
using Content.Client.DebugMon;
|
||||||
using Content.Client.Eui;
|
using Content.Client.Eui;
|
||||||
using Content.Client.Fullscreen;
|
using Content.Client.Fullscreen;
|
||||||
using Content.Client.GameTicking.Managers;
|
|
||||||
using Content.Client.GhostKick;
|
using Content.Client.GhostKick;
|
||||||
using Content.Client.Guidebook;
|
using Content.Client.Guidebook;
|
||||||
using Content.Client.Launcher;
|
using Content.Client.Launcher;
|
||||||
@@ -19,11 +18,8 @@ using Content.Client.Viewport;
|
|||||||
using Content.Client.Voting;
|
using Content.Client.Voting;
|
||||||
using Content.Shared.Administration.Logs;
|
using Content.Shared.Administration.Logs;
|
||||||
using Content.Client.Lobby;
|
using Content.Client.Lobby;
|
||||||
using Content.Client.Players.RateLimiting;
|
|
||||||
using Content.Shared.Administration.Managers;
|
using Content.Shared.Administration.Managers;
|
||||||
using Content.Shared.Chat;
|
|
||||||
using Content.Shared.Players.PlayTimeTracking;
|
using Content.Shared.Players.PlayTimeTracking;
|
||||||
using Content.Shared.Players.RateLimiting;
|
|
||||||
|
|
||||||
namespace Content.Client.IoC
|
namespace Content.Client.IoC
|
||||||
{
|
{
|
||||||
@@ -35,7 +31,6 @@ namespace Content.Client.IoC
|
|||||||
|
|
||||||
collection.Register<IParallaxManager, ParallaxManager>();
|
collection.Register<IParallaxManager, ParallaxManager>();
|
||||||
collection.Register<IChatManager, ChatManager>();
|
collection.Register<IChatManager, ChatManager>();
|
||||||
collection.Register<ISharedChatManager, ChatManager>();
|
|
||||||
collection.Register<IClientPreferencesManager, ClientPreferencesManager>();
|
collection.Register<IClientPreferencesManager, ClientPreferencesManager>();
|
||||||
collection.Register<IStylesheetManager, StylesheetManager>();
|
collection.Register<IStylesheetManager, StylesheetManager>();
|
||||||
collection.Register<IScreenshotHook, ScreenshotHook>();
|
collection.Register<IScreenshotHook, ScreenshotHook>();
|
||||||
@@ -52,13 +47,10 @@ namespace Content.Client.IoC
|
|||||||
collection.Register<ExtendedDisconnectInformationManager>();
|
collection.Register<ExtendedDisconnectInformationManager>();
|
||||||
collection.Register<JobRequirementsManager>();
|
collection.Register<JobRequirementsManager>();
|
||||||
collection.Register<DocumentParsingManager>();
|
collection.Register<DocumentParsingManager>();
|
||||||
collection.Register<ContentReplayPlaybackManager>();
|
collection.Register<ContentReplayPlaybackManager, ContentReplayPlaybackManager>();
|
||||||
collection.Register<ISharedPlaytimeManager, JobRequirementsManager>();
|
collection.Register<ISharedPlaytimeManager, JobRequirementsManager>();
|
||||||
collection.Register<MappingManager>();
|
collection.Register<MappingManager>();
|
||||||
collection.Register<DebugMonitorManager>();
|
collection.Register<DebugMonitorManager>();
|
||||||
collection.Register<PlayerRateLimitManager>();
|
|
||||||
collection.Register<SharedPlayerRateLimitManager, PlayerRateLimitManager>();
|
|
||||||
collection.Register<TitleWindowManager>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
149
Content.Client/Movement/Systems/WaddleAnimationSystem.cs
Normal file
149
Content.Client/Movement/Systems/WaddleAnimationSystem.cs
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using Content.Client.Buckle;
|
||||||
|
using Content.Client.Gravity;
|
||||||
|
using Content.Shared.ActionBlocker;
|
||||||
|
using Content.Shared.Mobs.Systems;
|
||||||
|
using Content.Shared.Movement.Components;
|
||||||
|
using Content.Shared.Movement.Systems;
|
||||||
|
using Robust.Client.Animations;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Shared.Animations;
|
||||||
|
|
||||||
|
namespace Content.Client.Movement.Systems;
|
||||||
|
|
||||||
|
public sealed class WaddleAnimationSystem : SharedWaddleAnimationSystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly AnimationPlayerSystem _animation = default!;
|
||||||
|
[Dependency] private readonly GravitySystem _gravity = default!;
|
||||||
|
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
|
||||||
|
[Dependency] private readonly BuckleSystem _buckle = default!;
|
||||||
|
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeAllEvent<StartedWaddlingEvent>(OnStartWaddling);
|
||||||
|
SubscribeLocalEvent<WaddleAnimationComponent, AnimationCompletedEvent>(OnAnimationCompleted);
|
||||||
|
SubscribeAllEvent<StoppedWaddlingEvent>(OnStopWaddling);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnStartWaddling(StartedWaddlingEvent msg, EntitySessionEventArgs args)
|
||||||
|
{
|
||||||
|
if (TryComp<WaddleAnimationComponent>(GetEntity(msg.Entity), out var comp))
|
||||||
|
StartWaddling((GetEntity(msg.Entity), comp));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnStopWaddling(StoppedWaddlingEvent msg, EntitySessionEventArgs args)
|
||||||
|
{
|
||||||
|
if (TryComp<WaddleAnimationComponent>(GetEntity(msg.Entity), out var comp))
|
||||||
|
StopWaddling((GetEntity(msg.Entity), comp));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartWaddling(Entity<WaddleAnimationComponent> entity)
|
||||||
|
{
|
||||||
|
if (_animation.HasRunningAnimation(entity.Owner, entity.Comp.KeyName))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp<InputMoverComponent>(entity.Owner, out var mover))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_gravity.IsWeightless(entity.Owner))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_actionBlocker.CanMove(entity.Owner, mover))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Do nothing if buckled in
|
||||||
|
if (_buckle.IsBuckled(entity.Owner))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Do nothing if crit or dead (for obvious reasons)
|
||||||
|
if (_mobState.IsIncapacitated(entity.Owner))
|
||||||
|
return;
|
||||||
|
|
||||||
|
PlayWaddleAnimationUsing(
|
||||||
|
(entity.Owner, entity.Comp),
|
||||||
|
CalculateAnimationLength(entity.Comp, mover),
|
||||||
|
CalculateTumbleIntensity(entity.Comp)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float CalculateTumbleIntensity(WaddleAnimationComponent component)
|
||||||
|
{
|
||||||
|
return component.LastStep ? 360 - component.TumbleIntensity : component.TumbleIntensity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float CalculateAnimationLength(WaddleAnimationComponent component, InputMoverComponent mover)
|
||||||
|
{
|
||||||
|
return mover.Sprinting ? component.AnimationLength * component.RunAnimationLengthMultiplier : component.AnimationLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAnimationCompleted(Entity<WaddleAnimationComponent> entity, ref AnimationCompletedEvent args)
|
||||||
|
{
|
||||||
|
if (args.Key != entity.Comp.KeyName)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp<InputMoverComponent>(entity.Owner, out var mover))
|
||||||
|
return;
|
||||||
|
|
||||||
|
PlayWaddleAnimationUsing(
|
||||||
|
(entity.Owner, entity.Comp),
|
||||||
|
CalculateAnimationLength(entity.Comp, mover),
|
||||||
|
CalculateTumbleIntensity(entity.Comp)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StopWaddling(Entity<WaddleAnimationComponent> entity)
|
||||||
|
{
|
||||||
|
if (!_animation.HasRunningAnimation(entity.Owner, entity.Comp.KeyName))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_animation.Stop(entity.Owner, entity.Comp.KeyName);
|
||||||
|
|
||||||
|
if (!TryComp<SpriteComponent>(entity.Owner, out var sprite))
|
||||||
|
return;
|
||||||
|
|
||||||
|
sprite.Offset = new Vector2();
|
||||||
|
sprite.Rotation = Angle.FromDegrees(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlayWaddleAnimationUsing(Entity<WaddleAnimationComponent> entity, float len, float tumbleIntensity)
|
||||||
|
{
|
||||||
|
entity.Comp.LastStep = !entity.Comp.LastStep;
|
||||||
|
|
||||||
|
var anim = new Animation()
|
||||||
|
{
|
||||||
|
Length = TimeSpan.FromSeconds(len),
|
||||||
|
AnimationTracks =
|
||||||
|
{
|
||||||
|
new AnimationTrackComponentProperty()
|
||||||
|
{
|
||||||
|
ComponentType = typeof(SpriteComponent),
|
||||||
|
Property = nameof(SpriteComponent.Rotation),
|
||||||
|
InterpolationMode = AnimationInterpolationMode.Linear,
|
||||||
|
KeyFrames =
|
||||||
|
{
|
||||||
|
new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(0), 0),
|
||||||
|
new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(tumbleIntensity), len/2),
|
||||||
|
new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(0), len/2),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new AnimationTrackComponentProperty()
|
||||||
|
{
|
||||||
|
ComponentType = typeof(SpriteComponent),
|
||||||
|
Property = nameof(SpriteComponent.Offset),
|
||||||
|
InterpolationMode = AnimationInterpolationMode.Linear,
|
||||||
|
KeyFrames =
|
||||||
|
{
|
||||||
|
new AnimationTrackProperty.KeyFrame(new Vector2(), 0),
|
||||||
|
new AnimationTrackProperty.KeyFrame(entity.Comp.HopIntensity, len/2),
|
||||||
|
new AnimationTrackProperty.KeyFrame(new Vector2(), len/2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_animation.Play(entity.Owner, anim, entity.Comp.KeyName);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,6 @@ public sealed class ShowThirstIconsSystem : EquipmentHudSystem<ShowThirstIconsCo
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (_thirst.TryGetStatusIconPrototype(component, out var iconPrototype))
|
if (_thirst.TryGetStatusIconPrototype(component, out var iconPrototype))
|
||||||
ev.StatusIcons.Add(iconPrototype);
|
ev.StatusIcons.Add(iconPrototype!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,16 +76,16 @@ public sealed partial class StencilOverlay : Overlay
|
|||||||
|
|
||||||
|
|
||||||
//CP14 Overlays
|
//CP14 Overlays
|
||||||
if (_entManager.TryGetComponent<CP14CloudShadowsComponent>(mapUid, out var shadows))
|
if (_entManager.TryGetComponent<CP14WorldEdgeComponent>(mapUid, out var worldEdge))
|
||||||
{
|
{
|
||||||
DrawCloudShadows(args, shadows, invMatrix);
|
DrawWorldEdge(args, worldEdge, invMatrix);
|
||||||
}
|
}
|
||||||
//CP14 Overlays end
|
//CP14 Overlays end
|
||||||
|
|
||||||
//CP14 Overlays
|
//CP14 Overlays
|
||||||
if (_entManager.TryGetComponent<CP14WorldEdgeComponent>(mapUid, out var worldEdge))
|
if (_entManager.TryGetComponent<CP14CloudShadowsComponent>(mapUid, out var shadows))
|
||||||
{
|
{
|
||||||
DrawWorldEdge(args, worldEdge, invMatrix);
|
DrawCloudShadows(args, shadows, invMatrix);
|
||||||
}
|
}
|
||||||
//CP14 Overlays end
|
//CP14 Overlays end
|
||||||
|
|
||||||
|
|||||||
@@ -319,8 +319,6 @@ namespace Content.Client.Paper.UI
|
|||||||
|
|
||||||
private void RunOnSaved()
|
private void RunOnSaved()
|
||||||
{
|
{
|
||||||
// Prevent further saving while text processing still in
|
|
||||||
SaveButton.Disabled = true;
|
|
||||||
OnSaved?.Invoke(Rope.Collapse(Input.TextRope));
|
OnSaved?.Invoke(Rope.Collapse(Input.TextRope));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,303 +0,0 @@
|
|||||||
using Content.Shared.Atmos;
|
|
||||||
using Content.Shared.Pinpointer;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Content.Client.Pinpointer;
|
|
||||||
|
|
||||||
public sealed partial class NavMapSystem
|
|
||||||
{
|
|
||||||
private (AtmosDirection, Vector2i, AtmosDirection)[] _regionPropagationTable =
|
|
||||||
{
|
|
||||||
(AtmosDirection.East, new Vector2i(1, 0), AtmosDirection.West),
|
|
||||||
(AtmosDirection.West, new Vector2i(-1, 0), AtmosDirection.East),
|
|
||||||
(AtmosDirection.North, new Vector2i(0, 1), AtmosDirection.South),
|
|
||||||
(AtmosDirection.South, new Vector2i(0, -1), AtmosDirection.North),
|
|
||||||
};
|
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
|
||||||
{
|
|
||||||
// To prevent compute spikes, only one region is flood filled per frame
|
|
||||||
var query = AllEntityQuery<NavMapComponent>();
|
|
||||||
|
|
||||||
while (query.MoveNext(out var ent, out var entNavMapRegions))
|
|
||||||
FloodFillNextEnqueuedRegion(ent, entNavMapRegions);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FloodFillNextEnqueuedRegion(EntityUid uid, NavMapComponent component)
|
|
||||||
{
|
|
||||||
if (!component.QueuedRegionsToFlood.Any())
|
|
||||||
return;
|
|
||||||
|
|
||||||
var regionOwner = component.QueuedRegionsToFlood.Dequeue();
|
|
||||||
|
|
||||||
// If the region is no longer valid, flood the next one in the queue
|
|
||||||
if (!component.RegionProperties.TryGetValue(regionOwner, out var regionProperties) ||
|
|
||||||
!regionProperties.Seeds.Any())
|
|
||||||
{
|
|
||||||
FloodFillNextEnqueuedRegion(uid, component);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flood fill the region, using the region seeds as starting points
|
|
||||||
var (floodedTiles, floodedChunks) = FloodFillRegion(uid, component, regionProperties);
|
|
||||||
|
|
||||||
// Combine the flooded tiles into larger rectangles
|
|
||||||
var gridCoords = GetMergedRegionTiles(floodedTiles);
|
|
||||||
|
|
||||||
// Create and assign the new region overlay
|
|
||||||
var regionOverlay = new NavMapRegionOverlay(regionProperties.UiKey, gridCoords)
|
|
||||||
{
|
|
||||||
Color = regionProperties.Color
|
|
||||||
};
|
|
||||||
|
|
||||||
component.RegionOverlays[regionOwner] = regionOverlay;
|
|
||||||
|
|
||||||
// To reduce unnecessary future flood fills, we will track which chunks have been flooded by a region owner
|
|
||||||
|
|
||||||
// First remove an old assignments
|
|
||||||
if (component.RegionOwnerToChunkTable.TryGetValue(regionOwner, out var oldChunks))
|
|
||||||
{
|
|
||||||
foreach (var chunk in oldChunks)
|
|
||||||
{
|
|
||||||
if (component.ChunkToRegionOwnerTable.TryGetValue(chunk, out var oldOwners))
|
|
||||||
{
|
|
||||||
oldOwners.Remove(regionOwner);
|
|
||||||
component.ChunkToRegionOwnerTable[chunk] = oldOwners;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now update with the new assignments
|
|
||||||
component.RegionOwnerToChunkTable[regionOwner] = floodedChunks;
|
|
||||||
|
|
||||||
foreach (var chunk in floodedChunks)
|
|
||||||
{
|
|
||||||
if (!component.ChunkToRegionOwnerTable.TryGetValue(chunk, out var owners))
|
|
||||||
owners = new();
|
|
||||||
|
|
||||||
owners.Add(regionOwner);
|
|
||||||
component.ChunkToRegionOwnerTable[chunk] = owners;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private (HashSet<Vector2i>, HashSet<Vector2i>) FloodFillRegion(EntityUid uid, NavMapComponent component, NavMapRegionProperties regionProperties)
|
|
||||||
{
|
|
||||||
if (!regionProperties.Seeds.Any())
|
|
||||||
return (new(), new());
|
|
||||||
|
|
||||||
var visitedChunks = new HashSet<Vector2i>();
|
|
||||||
var visitedTiles = new HashSet<Vector2i>();
|
|
||||||
var tilesToVisit = new Stack<Vector2i>();
|
|
||||||
|
|
||||||
foreach (var regionSeed in regionProperties.Seeds)
|
|
||||||
{
|
|
||||||
tilesToVisit.Push(regionSeed);
|
|
||||||
|
|
||||||
while (tilesToVisit.Count > 0)
|
|
||||||
{
|
|
||||||
// If the max region area is hit, exit
|
|
||||||
if (visitedTiles.Count > regionProperties.MaxArea)
|
|
||||||
return (new(), new());
|
|
||||||
|
|
||||||
// Pop the top tile from the stack
|
|
||||||
var current = tilesToVisit.Pop();
|
|
||||||
|
|
||||||
// If the current tile position has already been visited,
|
|
||||||
// or is too far away from the seed, continue
|
|
||||||
if ((regionSeed - current).Length > regionProperties.MaxRadius)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (visitedTiles.Contains(current))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Determine the tile's chunk index
|
|
||||||
var chunkOrigin = SharedMapSystem.GetChunkIndices(current, ChunkSize);
|
|
||||||
var relative = SharedMapSystem.GetChunkRelative(current, ChunkSize);
|
|
||||||
var idx = GetTileIndex(relative);
|
|
||||||
|
|
||||||
// Extract the tile data
|
|
||||||
if (!component.Chunks.TryGetValue(chunkOrigin, out var chunk))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var flag = chunk.TileData[idx];
|
|
||||||
|
|
||||||
// If the current tile is entirely occupied, continue
|
|
||||||
if ((FloorMask & flag) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ((WallMask & flag) == WallMask)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ((AirlockMask & flag) == AirlockMask)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Otherwise the tile can be added to this region
|
|
||||||
visitedTiles.Add(current);
|
|
||||||
visitedChunks.Add(chunkOrigin);
|
|
||||||
|
|
||||||
// Determine if we can propagate the region into its cardinally adjacent neighbors
|
|
||||||
// To propagate to a neighbor, movement into the neighbors closest edge must not be
|
|
||||||
// blocked, and vice versa
|
|
||||||
|
|
||||||
foreach (var (direction, tileOffset, reverseDirection) in _regionPropagationTable)
|
|
||||||
{
|
|
||||||
if (!RegionCanPropagateInDirection(chunk, current, direction))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var neighbor = current + tileOffset;
|
|
||||||
var neighborOrigin = SharedMapSystem.GetChunkIndices(neighbor, ChunkSize);
|
|
||||||
|
|
||||||
if (!component.Chunks.TryGetValue(neighborOrigin, out var neighborChunk))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
visitedChunks.Add(neighborOrigin);
|
|
||||||
|
|
||||||
if (!RegionCanPropagateInDirection(neighborChunk, neighbor, reverseDirection))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
tilesToVisit.Push(neighbor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (visitedTiles, visitedChunks);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool RegionCanPropagateInDirection(NavMapChunk chunk, Vector2i tile, AtmosDirection direction)
|
|
||||||
{
|
|
||||||
var relative = SharedMapSystem.GetChunkRelative(tile, ChunkSize);
|
|
||||||
var idx = GetTileIndex(relative);
|
|
||||||
var flag = chunk.TileData[idx];
|
|
||||||
|
|
||||||
if ((FloorMask & flag) == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var directionMask = 1 << (int)direction;
|
|
||||||
var wallMask = (int)direction << (int)NavMapChunkType.Wall;
|
|
||||||
var airlockMask = (int)direction << (int)NavMapChunkType.Airlock;
|
|
||||||
|
|
||||||
if ((wallMask & flag) > 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ((airlockMask & flag) > 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<(Vector2i, Vector2i)> GetMergedRegionTiles(HashSet<Vector2i> tiles)
|
|
||||||
{
|
|
||||||
if (!tiles.Any())
|
|
||||||
return new();
|
|
||||||
|
|
||||||
var x = tiles.Select(t => t.X);
|
|
||||||
var minX = x.Min();
|
|
||||||
var maxX = x.Max();
|
|
||||||
|
|
||||||
var y = tiles.Select(t => t.Y);
|
|
||||||
var minY = y.Min();
|
|
||||||
var maxY = y.Max();
|
|
||||||
|
|
||||||
var matrix = new int[maxX - minX + 1, maxY - minY + 1];
|
|
||||||
|
|
||||||
foreach (var tile in tiles)
|
|
||||||
{
|
|
||||||
var a = tile.X - minX;
|
|
||||||
var b = tile.Y - minY;
|
|
||||||
|
|
||||||
matrix[a, b] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return GetMergedRegionTiles(matrix, new Vector2i(minX, minY));
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<(Vector2i, Vector2i)> GetMergedRegionTiles(int[,] matrix, Vector2i offset)
|
|
||||||
{
|
|
||||||
var output = new List<(Vector2i, Vector2i)>();
|
|
||||||
|
|
||||||
var rows = matrix.GetLength(0);
|
|
||||||
var cols = matrix.GetLength(1);
|
|
||||||
|
|
||||||
var dp = new int[rows, cols];
|
|
||||||
var coords = (new Vector2i(), new Vector2i());
|
|
||||||
var maxArea = 0;
|
|
||||||
|
|
||||||
var count = 0;
|
|
||||||
|
|
||||||
while (!IsArrayEmpty(matrix))
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
|
|
||||||
if (count > rows * cols)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Clear old values
|
|
||||||
dp = new int[rows, cols];
|
|
||||||
coords = (new Vector2i(), new Vector2i());
|
|
||||||
maxArea = 0;
|
|
||||||
|
|
||||||
// Initialize the first row of dp
|
|
||||||
for (int j = 0; j < cols; j++)
|
|
||||||
{
|
|
||||||
dp[0, j] = matrix[0, j];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate dp values for remaining rows
|
|
||||||
for (int i = 1; i < rows; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < cols; j++)
|
|
||||||
dp[i, j] = matrix[i, j] == 1 ? dp[i - 1, j] + 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the largest rectangular area seeded for each position in the matrix
|
|
||||||
for (int i = 0; i < rows; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < cols; j++)
|
|
||||||
{
|
|
||||||
int minWidth = dp[i, j];
|
|
||||||
|
|
||||||
for (int k = j; k >= 0; k--)
|
|
||||||
{
|
|
||||||
if (dp[i, k] <= 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
minWidth = Math.Min(minWidth, dp[i, k]);
|
|
||||||
var currArea = Math.Max(maxArea, minWidth * (j - k + 1));
|
|
||||||
|
|
||||||
if (currArea > maxArea)
|
|
||||||
{
|
|
||||||
maxArea = currArea;
|
|
||||||
coords = (new Vector2i(i - minWidth + 1, k), new Vector2i(i, j));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the recorded rectangle vertices
|
|
||||||
output.Add((coords.Item1 + offset, coords.Item2 + offset));
|
|
||||||
|
|
||||||
// Removed the tiles covered by the rectangle from matrix
|
|
||||||
for (int i = coords.Item1.X; i <= coords.Item2.X; i++)
|
|
||||||
{
|
|
||||||
for (int j = coords.Item1.Y; j <= coords.Item2.Y; j++)
|
|
||||||
matrix[i, j] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsArrayEmpty(int[,] matrix)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < matrix.GetLength(0); i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < matrix.GetLength(1); j++)
|
|
||||||
{
|
|
||||||
if (matrix[i, j] == 1)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
using System.Linq;
|
|
||||||
using Content.Shared.Pinpointer;
|
using Content.Shared.Pinpointer;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
@@ -17,7 +16,6 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
|
|||||||
{
|
{
|
||||||
Dictionary<Vector2i, int[]> modifiedChunks;
|
Dictionary<Vector2i, int[]> modifiedChunks;
|
||||||
Dictionary<NetEntity, NavMapBeacon> beacons;
|
Dictionary<NetEntity, NavMapBeacon> beacons;
|
||||||
Dictionary<NetEntity, NavMapRegionProperties> regions;
|
|
||||||
|
|
||||||
switch (args.Current)
|
switch (args.Current)
|
||||||
{
|
{
|
||||||
@@ -25,8 +23,6 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
|
|||||||
{
|
{
|
||||||
modifiedChunks = delta.ModifiedChunks;
|
modifiedChunks = delta.ModifiedChunks;
|
||||||
beacons = delta.Beacons;
|
beacons = delta.Beacons;
|
||||||
regions = delta.Regions;
|
|
||||||
|
|
||||||
foreach (var index in component.Chunks.Keys)
|
foreach (var index in component.Chunks.Keys)
|
||||||
{
|
{
|
||||||
if (!delta.AllChunks!.Contains(index))
|
if (!delta.AllChunks!.Contains(index))
|
||||||
@@ -39,8 +35,6 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
|
|||||||
{
|
{
|
||||||
modifiedChunks = state.Chunks;
|
modifiedChunks = state.Chunks;
|
||||||
beacons = state.Beacons;
|
beacons = state.Beacons;
|
||||||
regions = state.Regions;
|
|
||||||
|
|
||||||
foreach (var index in component.Chunks.Keys)
|
foreach (var index in component.Chunks.Keys)
|
||||||
{
|
{
|
||||||
if (!state.Chunks.ContainsKey(index))
|
if (!state.Chunks.ContainsKey(index))
|
||||||
@@ -53,54 +47,13 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update region data and queue new regions for flooding
|
|
||||||
var prevRegionOwners = component.RegionProperties.Keys.ToList();
|
|
||||||
var validRegionOwners = new List<NetEntity>();
|
|
||||||
|
|
||||||
component.RegionProperties.Clear();
|
|
||||||
|
|
||||||
foreach (var (regionOwner, regionData) in regions)
|
|
||||||
{
|
|
||||||
if (!regionData.Seeds.Any())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
component.RegionProperties[regionOwner] = regionData;
|
|
||||||
validRegionOwners.Add(regionOwner);
|
|
||||||
|
|
||||||
if (component.RegionOverlays.ContainsKey(regionOwner))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (component.QueuedRegionsToFlood.Contains(regionOwner))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
component.QueuedRegionsToFlood.Enqueue(regionOwner);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove stale region owners
|
|
||||||
var regionOwnersToRemove = prevRegionOwners.Except(validRegionOwners);
|
|
||||||
|
|
||||||
foreach (var regionOwnerRemoved in regionOwnersToRemove)
|
|
||||||
RemoveNavMapRegion(uid, component, regionOwnerRemoved);
|
|
||||||
|
|
||||||
// Modify chunks
|
|
||||||
foreach (var (origin, chunk) in modifiedChunks)
|
foreach (var (origin, chunk) in modifiedChunks)
|
||||||
{
|
{
|
||||||
var newChunk = new NavMapChunk(origin);
|
var newChunk = new NavMapChunk(origin);
|
||||||
Array.Copy(chunk, newChunk.TileData, chunk.Length);
|
Array.Copy(chunk, newChunk.TileData, chunk.Length);
|
||||||
component.Chunks[origin] = newChunk;
|
component.Chunks[origin] = newChunk;
|
||||||
|
|
||||||
// If the affected chunk intersects one or more regions, re-flood them
|
|
||||||
if (!component.ChunkToRegionOwnerTable.TryGetValue(origin, out var affectedOwners))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
foreach (var affectedOwner in affectedOwners)
|
|
||||||
{
|
|
||||||
if (!component.QueuedRegionsToFlood.Contains(affectedOwner))
|
|
||||||
component.QueuedRegionsToFlood.Enqueue(affectedOwner);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh beacons
|
|
||||||
component.Beacons.Clear();
|
component.Beacons.Clear();
|
||||||
foreach (var (nuid, beacon) in beacons)
|
foreach (var (nuid, beacon) in beacons)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ public partial class NavMapControl : MapGridControl
|
|||||||
public List<(Vector2, Vector2)> TileLines = new();
|
public List<(Vector2, Vector2)> TileLines = new();
|
||||||
public List<(Vector2, Vector2)> TileRects = new();
|
public List<(Vector2, Vector2)> TileRects = new();
|
||||||
public List<(Vector2[], Color)> TilePolygons = new();
|
public List<(Vector2[], Color)> TilePolygons = new();
|
||||||
public List<NavMapRegionOverlay> RegionOverlays = new();
|
|
||||||
|
|
||||||
// Default colors
|
// Default colors
|
||||||
public Color WallColor = new(102, 217, 102);
|
public Color WallColor = new(102, 217, 102);
|
||||||
@@ -320,22 +319,6 @@ public partial class NavMapControl : MapGridControl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw region overlays
|
|
||||||
if (_grid != null)
|
|
||||||
{
|
|
||||||
foreach (var regionOverlay in RegionOverlays)
|
|
||||||
{
|
|
||||||
foreach (var gridCoords in regionOverlay.GridCoords)
|
|
||||||
{
|
|
||||||
var positionTopLeft = ScalePosition(new Vector2(gridCoords.Item1.X, -gridCoords.Item1.Y) - new Vector2(offset.X, -offset.Y));
|
|
||||||
var positionBottomRight = ScalePosition(new Vector2(gridCoords.Item2.X + _grid.TileSize, -gridCoords.Item2.Y - _grid.TileSize) - new Vector2(offset.X, -offset.Y));
|
|
||||||
|
|
||||||
var box = new UIBox2(positionTopLeft, positionBottomRight);
|
|
||||||
handle.DrawRect(box, regionOverlay.Color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw map lines
|
// Draw map lines
|
||||||
if (TileLines.Any())
|
if (TileLines.Any())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -51,8 +51,6 @@ public sealed class JobRequirementsManager : ISharedPlaytimeManager
|
|||||||
{
|
{
|
||||||
// Reset on disconnect, just in case.
|
// Reset on disconnect, just in case.
|
||||||
_roles.Clear();
|
_roles.Clear();
|
||||||
_jobWhitelists.Clear();
|
|
||||||
_roleBans.Clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,6 +58,9 @@ public sealed class JobRequirementsManager : ISharedPlaytimeManager
|
|||||||
{
|
{
|
||||||
_sawmill.Debug($"Received roleban info containing {message.Bans.Count} entries.");
|
_sawmill.Debug($"Received roleban info containing {message.Bans.Count} entries.");
|
||||||
|
|
||||||
|
if (_roleBans.Equals(message.Bans))
|
||||||
|
return;
|
||||||
|
|
||||||
_roleBans.Clear();
|
_roleBans.Clear();
|
||||||
_roleBans.AddRange(message.Bans);
|
_roleBans.AddRange(message.Bans);
|
||||||
Updated?.Invoke();
|
Updated?.Invoke();
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
using Content.Shared.Players.RateLimiting;
|
|
||||||
using Robust.Shared.Player;
|
|
||||||
|
|
||||||
namespace Content.Client.Players.RateLimiting;
|
|
||||||
|
|
||||||
public sealed class PlayerRateLimitManager : SharedPlayerRateLimitManager
|
|
||||||
{
|
|
||||||
public override RateLimitStatus CountAction(ICommonSession player, string key)
|
|
||||||
{
|
|
||||||
// TODO Rate-Limit
|
|
||||||
// Add support for rate limit prediction
|
|
||||||
// I.e., dont mis-predict just because somebody is clicking too quickly.
|
|
||||||
return RateLimitStatus.Allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Register(string key, RateLimitRegistration registration)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
using Content.Client.Power.APC.UI;
|
using Content.Client.Power.APC.UI;
|
||||||
using Content.Shared.Access.Systems;
|
|
||||||
using Content.Shared.APC;
|
using Content.Shared.APC;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.UserInterface;
|
using Robust.Client.UserInterface;
|
||||||
using Robust.Shared.Player;
|
|
||||||
|
|
||||||
namespace Content.Client.Power.APC
|
namespace Content.Client.Power.APC
|
||||||
{
|
{
|
||||||
@@ -23,14 +22,6 @@ namespace Content.Client.Power.APC
|
|||||||
_menu = this.CreateWindow<ApcMenu>();
|
_menu = this.CreateWindow<ApcMenu>();
|
||||||
_menu.SetEntity(Owner);
|
_menu.SetEntity(Owner);
|
||||||
_menu.OnBreaker += BreakerPressed;
|
_menu.OnBreaker += BreakerPressed;
|
||||||
|
|
||||||
var hasAccess = false;
|
|
||||||
if (PlayerManager.LocalEntity != null)
|
|
||||||
{
|
|
||||||
var accessReader = EntMan.System<AccessReaderSystem>();
|
|
||||||
hasAccess = accessReader.IsAllowed((EntityUid)PlayerManager.LocalEntity, Owner);
|
|
||||||
}
|
|
||||||
_menu?.SetAccessEnabled(hasAccess);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateState(BoundUserInterfaceState state)
|
protected override void UpdateState(BoundUserInterfaceState state)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
@@ -36,9 +36,19 @@ namespace Content.Client.Power.APC.UI
|
|||||||
{
|
{
|
||||||
var castState = (ApcBoundInterfaceState) state;
|
var castState = (ApcBoundInterfaceState) state;
|
||||||
|
|
||||||
if (!BreakerButton.Disabled)
|
if (BreakerButton != null)
|
||||||
{
|
{
|
||||||
BreakerButton.Pressed = castState.MainBreaker;
|
if(castState.HasAccess == false)
|
||||||
|
{
|
||||||
|
BreakerButton.Disabled = true;
|
||||||
|
BreakerButton.ToolTip = Loc.GetString("apc-component-insufficient-access");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BreakerButton.Disabled = false;
|
||||||
|
BreakerButton.ToolTip = null;
|
||||||
|
BreakerButton.Pressed = castState.MainBreaker;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PowerLabel != null)
|
if (PowerLabel != null)
|
||||||
@@ -76,20 +86,6 @@ namespace Content.Client.Power.APC.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetAccessEnabled(bool hasAccess)
|
|
||||||
{
|
|
||||||
if(hasAccess)
|
|
||||||
{
|
|
||||||
BreakerButton.Disabled = false;
|
|
||||||
BreakerButton.ToolTip = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BreakerButton.Disabled = true;
|
|
||||||
BreakerButton.ToolTip = Loc.GetString("apc-component-insufficient-access");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateChargeBarColor(float charge)
|
private void UpdateChargeBarColor(float charge)
|
||||||
{
|
{
|
||||||
if (ChargeBar == null)
|
if (ChargeBar == null)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Content.Shared.Doors.Components;
|
using Content.Shared.Doors.Components;
|
||||||
using Content.Shared.Electrocution;
|
|
||||||
using Content.Shared.Silicons.StationAi;
|
using Content.Shared.Silicons.StationAi;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
@@ -7,69 +6,25 @@ namespace Content.Client.Silicons.StationAi;
|
|||||||
|
|
||||||
public sealed partial class StationAiSystem
|
public sealed partial class StationAiSystem
|
||||||
{
|
{
|
||||||
private readonly ResPath _aiActionsRsi = new ResPath("/Textures/Interface/Actions/actions_ai.rsi");
|
|
||||||
|
|
||||||
private void InitializeAirlock()
|
private void InitializeAirlock()
|
||||||
{
|
{
|
||||||
SubscribeLocalEvent<DoorBoltComponent, GetStationAiRadialEvent>(OnDoorBoltGetRadial);
|
SubscribeLocalEvent<DoorBoltComponent, GetStationAiRadialEvent>(OnDoorBoltGetRadial);
|
||||||
SubscribeLocalEvent<AirlockComponent, GetStationAiRadialEvent>(OnEmergencyAccessGetRadial);
|
|
||||||
SubscribeLocalEvent<ElectrifiedComponent, GetStationAiRadialEvent>(OnDoorElectrifiedGetRadial);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDoorBoltGetRadial(Entity<DoorBoltComponent> ent, ref GetStationAiRadialEvent args)
|
private void OnDoorBoltGetRadial(Entity<DoorBoltComponent> ent, ref GetStationAiRadialEvent args)
|
||||||
{
|
{
|
||||||
args.Actions.Add(
|
args.Actions.Add(new StationAiRadial()
|
||||||
new StationAiRadial
|
{
|
||||||
|
Sprite = ent.Comp.BoltsDown ?
|
||||||
|
new SpriteSpecifier.Rsi(
|
||||||
|
new ResPath("/Textures/Structures/Doors/Airlocks/Standard/basic.rsi"), "open") :
|
||||||
|
new SpriteSpecifier.Rsi(
|
||||||
|
new ResPath("/Textures/Structures/Doors/Airlocks/Standard/basic.rsi"), "closed"),
|
||||||
|
Tooltip = ent.Comp.BoltsDown ? Loc.GetString("bolt-open") : Loc.GetString("bolt-close"),
|
||||||
|
Event = new StationAiBoltEvent()
|
||||||
{
|
{
|
||||||
Sprite = ent.Comp.BoltsDown
|
Bolted = !ent.Comp.BoltsDown,
|
||||||
? new SpriteSpecifier.Rsi(_aiActionsRsi, "unbolt_door")
|
|
||||||
: new SpriteSpecifier.Rsi(_aiActionsRsi, "bolt_door"),
|
|
||||||
Tooltip = ent.Comp.BoltsDown
|
|
||||||
? Loc.GetString("bolt-open")
|
|
||||||
: Loc.GetString("bolt-close"),
|
|
||||||
Event = new StationAiBoltEvent
|
|
||||||
{
|
|
||||||
Bolted = !ent.Comp.BoltsDown,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
}
|
|
||||||
|
|
||||||
private void OnEmergencyAccessGetRadial(Entity<AirlockComponent> ent, ref GetStationAiRadialEvent args)
|
|
||||||
{
|
|
||||||
args.Actions.Add(
|
|
||||||
new StationAiRadial
|
|
||||||
{
|
|
||||||
Sprite = ent.Comp.EmergencyAccess
|
|
||||||
? new SpriteSpecifier.Rsi(_aiActionsRsi, "emergency_off")
|
|
||||||
: new SpriteSpecifier.Rsi(_aiActionsRsi, "emergency_on"),
|
|
||||||
Tooltip = ent.Comp.EmergencyAccess
|
|
||||||
? Loc.GetString("emergency-access-off")
|
|
||||||
: Loc.GetString("emergency-access-on"),
|
|
||||||
Event = new StationAiEmergencyAccessEvent
|
|
||||||
{
|
|
||||||
EmergencyAccess = !ent.Comp.EmergencyAccess,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDoorElectrifiedGetRadial(Entity<ElectrifiedComponent> ent, ref GetStationAiRadialEvent args)
|
|
||||||
{
|
|
||||||
args.Actions.Add(
|
|
||||||
new StationAiRadial
|
|
||||||
{
|
|
||||||
Sprite = ent.Comp.Enabled
|
|
||||||
? new SpriteSpecifier.Rsi(_aiActionsRsi, "door_overcharge_off")
|
|
||||||
: new SpriteSpecifier.Rsi(_aiActionsRsi, "door_overcharge_on"),
|
|
||||||
Tooltip = ent.Comp.Enabled
|
|
||||||
? Loc.GetString("electrify-door-off")
|
|
||||||
: Loc.GetString("electrify-door-on"),
|
|
||||||
Event = new StationAiElectrifiedEvent
|
|
||||||
{
|
|
||||||
Electrified = !ent.Comp.Enabled,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ namespace Content.Client.Stylesheets
|
|||||||
public static readonly Color ButtonColorDefaultRed = Color.FromHex("#D43B3B");
|
public static readonly Color ButtonColorDefaultRed = Color.FromHex("#D43B3B");
|
||||||
public static readonly Color ButtonColorHovered = Color.FromHex("#7f6357");
|
public static readonly Color ButtonColorHovered = Color.FromHex("#7f6357");
|
||||||
public static readonly Color ButtonColorHoveredRed = Color.FromHex("#DF6B6B");
|
public static readonly Color ButtonColorHoveredRed = Color.FromHex("#DF6B6B");
|
||||||
public static readonly Color ButtonColorPressed = Color.FromHex("#4a332b");
|
public static readonly Color ButtonColorPressed = Color.FromHex("#6c4a3e");
|
||||||
public static readonly Color ButtonColorDisabled = Color.FromHex("#3c3330");
|
public static readonly Color ButtonColorDisabled = Color.FromHex("#3c3330");
|
||||||
|
|
||||||
public static readonly Color ButtonColorCautionDefault = Color.FromHex("#ab3232");
|
public static readonly Color ButtonColorCautionDefault = Color.FromHex("#ab3232");
|
||||||
|
|||||||
@@ -398,6 +398,10 @@ public sealed class ActionUIController : UIController, IOnStateChanged<GameplayS
|
|||||||
{
|
{
|
||||||
QueueWindowUpdate();
|
QueueWindowUpdate();
|
||||||
|
|
||||||
|
// TODO ACTIONS allow buttons to persist across state applications
|
||||||
|
// Then we don't have to interrupt drags any time the buttons get rebuilt.
|
||||||
|
_menuDragHelper.EndDrag();
|
||||||
|
|
||||||
if (_actionsSystem != null)
|
if (_actionsSystem != null)
|
||||||
_container?.SetActionData(_actionsSystem, _actions.ToArray());
|
_container?.SetActionData(_actionsSystem, _actions.ToArray());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,26 +28,14 @@ public class ActionButtonContainer : GridContainer
|
|||||||
get => (ActionButton) GetChild(index);
|
get => (ActionButton) GetChild(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetActionData(ActionsSystem system, params EntityUid?[] actionTypes)
|
private void BuildActionButtons(int count)
|
||||||
{
|
{
|
||||||
var uniqueCount = Math.Min(system.GetClientActions().Count(), actionTypes.Length + 1);
|
|
||||||
var keys = ContentKeyFunctions.GetHotbarBoundKeys();
|
var keys = ContentKeyFunctions.GetHotbarBoundKeys();
|
||||||
|
|
||||||
for (var i = 0; i < uniqueCount; i++)
|
Children.Clear();
|
||||||
|
for (var index = 0; index < count; index++)
|
||||||
{
|
{
|
||||||
if (i >= ChildCount)
|
Children.Add(MakeButton(index));
|
||||||
{
|
|
||||||
AddChild(MakeButton(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!actionTypes.TryGetValue(i, out var action))
|
|
||||||
action = null;
|
|
||||||
((ActionButton) GetChild(i)).UpdateData(action, system);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = ChildCount - 1; i >= uniqueCount; i--)
|
|
||||||
{
|
|
||||||
RemoveChild(GetChild(i));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ActionButton MakeButton(int index)
|
ActionButton MakeButton(int index)
|
||||||
@@ -67,6 +55,20 @@ public class ActionButtonContainer : GridContainer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetActionData(ActionsSystem system, params EntityUid?[] actionTypes)
|
||||||
|
{
|
||||||
|
var uniqueCount = Math.Min(system.GetClientActions().Count(), actionTypes.Length + 1);
|
||||||
|
if (ChildCount != uniqueCount)
|
||||||
|
BuildActionButtons(uniqueCount);
|
||||||
|
|
||||||
|
for (var i = 0; i < uniqueCount; i++)
|
||||||
|
{
|
||||||
|
if (!actionTypes.TryGetValue(i, out var action))
|
||||||
|
action = null;
|
||||||
|
((ActionButton) GetChild(i)).UpdateData(action, system);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void ClearActionData()
|
public void ClearActionData()
|
||||||
{
|
{
|
||||||
foreach (var button in Children)
|
foreach (var button in Children)
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
<BoxContainer xmlns="https://spacestation14.io"
|
|
||||||
Orientation="Vertical"
|
|
||||||
Margin="8 0 8 0">
|
|
||||||
<BoxContainer Name="Buttons"
|
|
||||||
Orientation="Vertical"
|
|
||||||
SeparationOverride="5">
|
|
||||||
<!-- Buttons are added here by code -->
|
|
||||||
</BoxContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
<BoxContainer xmlns="https://spacestation14.io"
|
<BoxContainer xmlns="https://spacestation14.io"
|
||||||
Orientation="Horizontal"
|
Orientation="Horizontal">
|
||||||
HorizontalAlignment="Stretch">
|
|
||||||
<Button Name="RequestButton"
|
<Button Name="RequestButton"
|
||||||
Access="Public"
|
Access="Public"
|
||||||
Text="{Loc 'ghost-roles-window-request-role-button'}"
|
Text="{Loc 'ghost-roles-window-request-role-button'}"
|
||||||
StyleClasses="OpenRight"
|
StyleClasses="OpenRight"
|
||||||
HorizontalExpand="True"
|
HorizontalAlignment="Left"
|
||||||
SizeFlagsStretchRatio="3"/>
|
SetWidth="300"/>
|
||||||
<Button Name="FollowButton"
|
<Button Name="FollowButton"
|
||||||
Access="Public"
|
Access="Public"
|
||||||
Text="{Loc 'ghost-roles-window-follow-role-button'}"
|
Text="{Loc 'ghost-roles-window-follow-role-button'}"
|
||||||
StyleClasses="OpenLeft"
|
StyleClasses="OpenLeft"
|
||||||
HorizontalExpand="True"/>
|
HorizontalAlignment="Right"
|
||||||
|
SetWidth="150"/>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
<BoxContainer xmlns="https://spacestation14.io"
|
|
||||||
Orientation="Vertical">
|
|
||||||
<Label Name="Title"
|
|
||||||
StyleClasses="LabelKeyText"/>
|
|
||||||
<PanelContainer StyleClasses="HighDivider" />
|
|
||||||
<RichTextLabel Name="Description"
|
|
||||||
Margin="0 4"/>
|
|
||||||
</BoxContainer>
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
using Robust.Client.AutoGenerated;
|
|
||||||
using Robust.Client.UserInterface.Controls;
|
|
||||||
using Robust.Client.UserInterface.XAML;
|
|
||||||
|
|
||||||
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
|
||||||
{
|
|
||||||
[GenerateTypedNameReferences]
|
|
||||||
public sealed partial class GhostRoleInfoBox : BoxContainer
|
|
||||||
{
|
|
||||||
public GhostRoleInfoBox(string name, string description)
|
|
||||||
{
|
|
||||||
RobustXamlLoader.Load(this);
|
|
||||||
|
|
||||||
Title.Text = name;
|
|
||||||
Description.SetMessage(description);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<BoxContainer xmlns="https://spacestation14.io"
|
||||||
|
Orientation="Vertical"
|
||||||
|
HorizontalExpand="True"
|
||||||
|
Margin="0 0 8 8">
|
||||||
|
<Label Name="Title"
|
||||||
|
StyleClasses="LabelKeyText"/>
|
||||||
|
<PanelContainer StyleClasses="HighDivider" />
|
||||||
|
<RichTextLabel Name="Description"
|
||||||
|
Margin="0 4"/>
|
||||||
|
<BoxContainer Name="Buttons"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Orientation="Vertical"
|
||||||
|
SeparationOverride="5">
|
||||||
|
<!-- Buttons are added here by code -->
|
||||||
|
</BoxContainer>
|
||||||
|
</BoxContainer>
|
||||||
@@ -10,17 +10,20 @@ using Robust.Shared.Utility;
|
|||||||
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
||||||
{
|
{
|
||||||
[GenerateTypedNameReferences]
|
[GenerateTypedNameReferences]
|
||||||
public sealed partial class GhostRoleButtonsBox : BoxContainer
|
public sealed partial class GhostRolesEntry : BoxContainer
|
||||||
{
|
{
|
||||||
private SpriteSystem _spriteSystem;
|
private SpriteSystem _spriteSystem;
|
||||||
public event Action<GhostRoleInfo>? OnRoleSelected;
|
public event Action<GhostRoleInfo>? OnRoleSelected;
|
||||||
public event Action<GhostRoleInfo>? OnRoleFollow;
|
public event Action<GhostRoleInfo>? OnRoleFollow;
|
||||||
|
|
||||||
public GhostRoleButtonsBox(bool hasAccess, FormattedMessage? reason, IEnumerable<GhostRoleInfo> roles, SpriteSystem spriteSystem)
|
public GhostRolesEntry(string name, string description, bool hasAccess, FormattedMessage? reason, IEnumerable<GhostRoleInfo> roles, SpriteSystem spriteSystem)
|
||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
_spriteSystem = spriteSystem;
|
_spriteSystem = spriteSystem;
|
||||||
|
|
||||||
|
Title.Text = name;
|
||||||
|
Description.SetMessage(description);
|
||||||
|
|
||||||
foreach (var role in roles)
|
foreach (var role in roles)
|
||||||
{
|
{
|
||||||
var button = new GhostRoleEntryButtons(role);
|
var button = new GhostRoleEntryButtons(role);
|
||||||
@@ -5,6 +5,7 @@ using Content.Shared.Eui;
|
|||||||
using Content.Shared.Ghost.Roles;
|
using Content.Shared.Ghost.Roles;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
||||||
{
|
{
|
||||||
@@ -76,13 +77,6 @@ namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
|||||||
|
|
||||||
if (state is not GhostRolesEuiState ghostState)
|
if (state is not GhostRolesEuiState ghostState)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// We must save BodyVisible state, so all Collapsible boxes will not close
|
|
||||||
// on adding new ghost role.
|
|
||||||
// Save the current state of each Collapsible box being visible or not
|
|
||||||
_window.SaveCollapsibleBoxesStates();
|
|
||||||
|
|
||||||
// Clearing the container before adding new roles
|
|
||||||
_window.ClearEntries();
|
_window.ClearEntries();
|
||||||
|
|
||||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||||
@@ -90,32 +84,28 @@ namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
|||||||
var spriteSystem = sysManager.GetEntitySystem<SpriteSystem>();
|
var spriteSystem = sysManager.GetEntitySystem<SpriteSystem>();
|
||||||
var requirementsManager = IoCManager.Resolve<JobRequirementsManager>();
|
var requirementsManager = IoCManager.Resolve<JobRequirementsManager>();
|
||||||
|
|
||||||
// TODO: role.Requirements value doesn't work at all as an equality key, this must be fixed
|
|
||||||
// Grouping roles
|
|
||||||
var groupedRoles = ghostState.GhostRoles.GroupBy(
|
var groupedRoles = ghostState.GhostRoles.GroupBy(
|
||||||
role => (role.Name, role.Description, role.Requirements));
|
role => (role.Name, role.Description, role.Requirements));
|
||||||
|
|
||||||
// Add a new entry for each role group
|
|
||||||
foreach (var group in groupedRoles)
|
foreach (var group in groupedRoles)
|
||||||
{
|
{
|
||||||
var name = group.Key.Name;
|
var name = group.Key.Name;
|
||||||
var description = group.Key.Description;
|
var description = group.Key.Description;
|
||||||
var hasAccess = requirementsManager.CheckRoleRequirements(
|
bool hasAccess = true;
|
||||||
group.Key.Requirements,
|
FormattedMessage? reason;
|
||||||
null,
|
|
||||||
out var reason);
|
if (!requirementsManager.CheckRoleRequirements(group.Key.Requirements, null, out reason))
|
||||||
|
{
|
||||||
|
hasAccess = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Adding a new role
|
|
||||||
_window.AddEntry(name, description, hasAccess, reason, group, spriteSystem);
|
_window.AddEntry(name, description, hasAccess, reason, group, spriteSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore the Collapsible box state if it is saved
|
|
||||||
_window.RestoreCollapsibleBoxesStates();
|
|
||||||
|
|
||||||
// Close the rules window if it is no longer needed
|
|
||||||
var closeRulesWindow = ghostState.GhostRoles.All(role => role.Identifier != _windowRulesId);
|
var closeRulesWindow = ghostState.GhostRoles.All(role => role.Identifier != _windowRulesId);
|
||||||
if (closeRulesWindow)
|
if (closeRulesWindow)
|
||||||
|
{
|
||||||
_windowRules?.Close();
|
_windowRules?.Close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
using System.Linq;
|
|
||||||
using Content.Shared.Ghost.Roles;
|
using Content.Shared.Ghost.Roles;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.UserInterface.Controls;
|
|
||||||
using Robust.Client.UserInterface.CustomControls;
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
using Robust.Client.UserInterface.XAML;
|
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
||||||
@@ -15,86 +12,20 @@ namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
|||||||
public event Action<GhostRoleInfo>? OnRoleRequestButtonClicked;
|
public event Action<GhostRoleInfo>? OnRoleRequestButtonClicked;
|
||||||
public event Action<GhostRoleInfo>? OnRoleFollow;
|
public event Action<GhostRoleInfo>? OnRoleFollow;
|
||||||
|
|
||||||
private Dictionary<(string name, string description), Collapsible> _collapsibleBoxes = new();
|
|
||||||
private HashSet<(string name, string description)> _uncollapsedStates = new();
|
|
||||||
|
|
||||||
public GhostRolesWindow()
|
|
||||||
{
|
|
||||||
RobustXamlLoader.Load(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearEntries()
|
public void ClearEntries()
|
||||||
{
|
{
|
||||||
NoRolesMessage.Visible = true;
|
NoRolesMessage.Visible = true;
|
||||||
EntryContainer.DisposeAllChildren();
|
EntryContainer.DisposeAllChildren();
|
||||||
_collapsibleBoxes.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SaveCollapsibleBoxesStates()
|
|
||||||
{
|
|
||||||
_uncollapsedStates.Clear();
|
|
||||||
foreach (var (key, collapsible) in _collapsibleBoxes)
|
|
||||||
{
|
|
||||||
if (collapsible.BodyVisible)
|
|
||||||
{
|
|
||||||
_uncollapsedStates.Add(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RestoreCollapsibleBoxesStates()
|
|
||||||
{
|
|
||||||
foreach (var (key, collapsible) in _collapsibleBoxes)
|
|
||||||
{
|
|
||||||
collapsible.BodyVisible = _uncollapsedStates.Contains(key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddEntry(string name, string description, bool hasAccess, FormattedMessage? reason, IEnumerable<GhostRoleInfo> roles, SpriteSystem spriteSystem)
|
public void AddEntry(string name, string description, bool hasAccess, FormattedMessage? reason, IEnumerable<GhostRoleInfo> roles, SpriteSystem spriteSystem)
|
||||||
{
|
{
|
||||||
NoRolesMessage.Visible = false;
|
NoRolesMessage.Visible = false;
|
||||||
|
|
||||||
var ghostRoleInfos = roles.ToList();
|
var entry = new GhostRolesEntry(name, description, hasAccess, reason, roles, spriteSystem);
|
||||||
var rolesCount = ghostRoleInfos.Count;
|
entry.OnRoleSelected += OnRoleRequestButtonClicked;
|
||||||
|
entry.OnRoleFollow += OnRoleFollow;
|
||||||
var info = new GhostRoleInfoBox(name, description);
|
EntryContainer.AddChild(entry);
|
||||||
var buttons = new GhostRoleButtonsBox(hasAccess, reason, ghostRoleInfos, spriteSystem);
|
|
||||||
buttons.OnRoleSelected += OnRoleRequestButtonClicked;
|
|
||||||
buttons.OnRoleFollow += OnRoleFollow;
|
|
||||||
|
|
||||||
EntryContainer.AddChild(info);
|
|
||||||
|
|
||||||
if (rolesCount > 1)
|
|
||||||
{
|
|
||||||
var buttonHeading = new CollapsibleHeading(Loc.GetString("ghost-roles-window-available-button", ("rolesCount", rolesCount)));
|
|
||||||
|
|
||||||
buttonHeading.AddStyleClass(ContainerButton.StyleClassButton);
|
|
||||||
buttonHeading.Label.HorizontalAlignment = HAlignment.Center;
|
|
||||||
buttonHeading.Label.HorizontalExpand = true;
|
|
||||||
|
|
||||||
var body = new CollapsibleBody
|
|
||||||
{
|
|
||||||
Margin = new Thickness(0, 5, 0, 0),
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Add Requirements to this key when it'll be fixed and work as an equality key in GhostRolesEui
|
|
||||||
var key = (name, description);
|
|
||||||
|
|
||||||
var collapsible = new Collapsible(buttonHeading, body)
|
|
||||||
{
|
|
||||||
Orientation = BoxContainer.LayoutOrientation.Vertical,
|
|
||||||
Margin = new Thickness(0, 0, 0, 8),
|
|
||||||
};
|
|
||||||
|
|
||||||
body.AddChild(buttons);
|
|
||||||
|
|
||||||
EntryContainer.AddChild(collapsible);
|
|
||||||
_collapsibleBoxes.Add(key, collapsible);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EntryContainer.AddChild(buttons);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,7 @@
|
|||||||
xmlns="https://spacestation14.io"
|
xmlns="https://spacestation14.io"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||||
xmlns:co="clr-namespace:Content.Client.UserInterface.Controls"
|
xmlns:co="clr-namespace:Content.Client.UserInterface.Controls">
|
||||||
MinHeight="210">
|
|
||||||
<BoxContainer Name="MainContainer" Orientation="Vertical">
|
<BoxContainer Name="MainContainer" Orientation="Vertical">
|
||||||
<LineEdit Name="SearchBar" PlaceHolder="{Loc 'vending-machine-component-search-filter'}" HorizontalExpand="True" Margin ="4 4"/>
|
<LineEdit Name="SearchBar" PlaceHolder="{Loc 'vending-machine-component-search-filter'}" HorizontalExpand="True" Margin ="4 4"/>
|
||||||
<co:SearchListContainer Name="VendingContents" VerticalExpand="True" Margin="4 4"/>
|
<co:SearchListContainer Name="VendingContents" VerticalExpand="True" Margin="4 4"/>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Content.Client.Gameplay;
|
|
||||||
using Content.Client.Stylesheets;
|
using Content.Client.Stylesheets;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
@@ -9,7 +8,6 @@ using Content.Shared.Voting;
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.Console;
|
using Robust.Client.Console;
|
||||||
using Robust.Client.State;
|
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
using Robust.Client.UserInterface.CustomControls;
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
@@ -30,7 +28,6 @@ namespace Content.Client.Voting.UI
|
|||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
[Dependency] private readonly IEntityNetworkManager _entNetManager = default!;
|
[Dependency] private readonly IEntityNetworkManager _entNetManager = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
[Dependency] private readonly IStateManager _state = default!;
|
|
||||||
|
|
||||||
private VotingSystem _votingSystem;
|
private VotingSystem _votingSystem;
|
||||||
|
|
||||||
@@ -65,7 +62,7 @@ namespace Content.Client.Voting.UI
|
|||||||
|
|
||||||
Stylesheet = IoCManager.Resolve<IStylesheetManager>().SheetSpace;
|
Stylesheet = IoCManager.Resolve<IStylesheetManager>().SheetSpace;
|
||||||
CloseButton.OnPressed += _ => Close();
|
CloseButton.OnPressed += _ => Close();
|
||||||
VoteNotTrustedLabel.Text = Loc.GetString("ui-vote-trusted-users-notice", ("timeReq", _cfg.GetCVar(CCVars.VotekickEligibleVoterDeathtime)));
|
VoteNotTrustedLabel.Text = Loc.GetString("ui-vote-trusted-users-notice", ("timeReq", _cfg.GetCVar(CCVars.VotekickEligibleVoterDeathtime) / 60));
|
||||||
|
|
||||||
foreach (StandardVoteType voteType in Enum.GetValues<StandardVoteType>())
|
foreach (StandardVoteType voteType in Enum.GetValues<StandardVoteType>())
|
||||||
{
|
{
|
||||||
@@ -73,7 +70,6 @@ namespace Content.Client.Voting.UI
|
|||||||
VoteTypeButton.AddItem(Loc.GetString(option.Name), (int)voteType);
|
VoteTypeButton.AddItem(Loc.GetString(option.Name), (int)voteType);
|
||||||
}
|
}
|
||||||
|
|
||||||
_state.OnStateChanged += OnStateChanged;
|
|
||||||
VoteTypeButton.OnItemSelected += VoteTypeSelected;
|
VoteTypeButton.OnItemSelected += VoteTypeSelected;
|
||||||
CreateButton.OnPressed += CreatePressed;
|
CreateButton.OnPressed += CreatePressed;
|
||||||
FollowButton.OnPressed += FollowSelected;
|
FollowButton.OnPressed += FollowSelected;
|
||||||
@@ -105,14 +101,6 @@ namespace Content.Client.Voting.UI
|
|||||||
UpdateVoteTimeout();
|
UpdateVoteTimeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStateChanged(StateChangedEventArgs obj)
|
|
||||||
{
|
|
||||||
if (obj.NewState is not GameplayState)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CanCallVoteChanged(bool obj)
|
private void CanCallVoteChanged(bool obj)
|
||||||
{
|
{
|
||||||
if (!obj)
|
if (!obj)
|
||||||
|
|||||||
@@ -19,6 +19,11 @@ public sealed class VotingSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnVotePlayerListResponseEvent(VotePlayerListResponseEvent msg)
|
private void OnVotePlayerListResponseEvent(VotePlayerListResponseEvent msg)
|
||||||
{
|
{
|
||||||
|
if (!_ghostSystem.IsGhost)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
VotePlayerListResponse?.Invoke(msg);
|
VotePlayerListResponse?.Invoke(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem
|
|||||||
[Dependency] private readonly AnimationPlayerSystem _animation = default!;
|
[Dependency] private readonly AnimationPlayerSystem _animation = default!;
|
||||||
[Dependency] private readonly InputSystem _inputSystem = default!;
|
[Dependency] private readonly InputSystem _inputSystem = default!;
|
||||||
[Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
|
[Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
|
||||||
[Dependency] private readonly MapSystem _map = default!;
|
|
||||||
|
|
||||||
private EntityQuery<TransformComponent> _xformQuery;
|
private EntityQuery<TransformComponent> _xformQuery;
|
||||||
|
|
||||||
@@ -110,11 +109,11 @@ public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem
|
|||||||
|
|
||||||
if (MapManager.TryFindGridAt(mousePos, out var gridUid, out _))
|
if (MapManager.TryFindGridAt(mousePos, out var gridUid, out _))
|
||||||
{
|
{
|
||||||
coordinates = TransformSystem.ToCoordinates(gridUid, mousePos);
|
coordinates = EntityCoordinates.FromMap(gridUid, mousePos, TransformSystem, EntityManager);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
coordinates = TransformSystem.ToCoordinates(_map.GetMap(mousePos.MapId), mousePos);
|
coordinates = EntityCoordinates.FromMap(MapManager.GetMapEntityId(mousePos.MapId), mousePos, TransformSystem, EntityManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Heavy attack.
|
// Heavy attack.
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
namespace Content.Client._CP14.Localization;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Controls the visual of the sprite, depending on the localization. Useful for drawn lettering
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class CP14LocalizationVisualsComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// map(map,(lang, state))
|
|
||||||
/// in yml:
|
|
||||||
///
|
|
||||||
/// - type: Sprite
|
|
||||||
/// layers:
|
|
||||||
/// - state: stateName0
|
|
||||||
/// map: ["map1"]
|
|
||||||
/// - state: stateName0
|
|
||||||
/// map: ["map2"]
|
|
||||||
/// - type: CP14LocalizationVisuals
|
|
||||||
/// mapStates:
|
|
||||||
/// map1:
|
|
||||||
/// ru-RU: stateName1
|
|
||||||
/// en-US: stateName2
|
|
||||||
/// map2:
|
|
||||||
/// ru-RU: stateName3
|
|
||||||
/// en-US: stateName4
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public Dictionary<string, Dictionary<string, string>> MapStates;
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
using Content.Shared.Localizations;
|
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
|
|
||||||
namespace Content.Client._CP14.Localization;
|
|
||||||
|
|
||||||
public sealed class CP14LocalizationVisualsSystem : EntitySystem
|
|
||||||
{
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<CP14LocalizationVisualsComponent, ComponentInit>(OnCompInit);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnCompInit(Entity<CP14LocalizationVisualsComponent> visuals, ref ComponentInit args)
|
|
||||||
{
|
|
||||||
if (!TryComp<SpriteComponent>(visuals, out var sprite))
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var (map, pDictionary) in visuals.Comp.MapStates)
|
|
||||||
{
|
|
||||||
if (!pDictionary.TryGetValue(ContentLocalizationManager.Culture, out var state))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (sprite.LayerMapTryGet(map, out _))
|
|
||||||
sprite.LayerSetState(map, state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
using Content.Shared._CP14.MagicRitual;
|
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
|
|
||||||
namespace Content.Server._CP14.MagicRituals;
|
|
||||||
|
|
||||||
public partial class CP14ClientRitualSystem : CP14SharedRitualSystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<CP14MagicRitualComponent, AppearanceChangeEvent>(OnAppearanceChange);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnAppearanceChange(Entity<CP14MagicRitualComponent> ent, ref AppearanceChangeEvent args)
|
|
||||||
{
|
|
||||||
if (args.Sprite == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!args.Sprite.LayerMapTryGet(ent.Comp.RitualLayerMap, out var ritualLayer))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_appearance.TryGetData<Color>(ent, RitualVisuals.Color, out var ritualColor, args.Component))
|
|
||||||
{
|
|
||||||
args.Sprite.LayerSetColor(ritualLayer, ritualColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_appearance.TryGetData<bool>(ent, RitualVisuals.Enabled, out var enabled, args.Component))
|
|
||||||
{
|
|
||||||
args.Sprite.LayerSetVisible(ritualLayer, enabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
using Content.Shared._CP14.MagicSpell;
|
|
||||||
|
|
||||||
namespace Content.Client._CP14.MagicSpell;
|
|
||||||
|
|
||||||
public sealed partial class CP14ClientMagicSystem : CP14SharedMagicSystem
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
using Robust.Shared;
|
|
||||||
using Robust.Shared.Configuration;
|
|
||||||
|
|
||||||
namespace Content.Client._CP14.Shitcode;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Эта система - сборник разного мелкого барахла, который слишком мелкий чтобы иметь свои собственные системы. В идеале в будущем разнести по отдельным файлам.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class CP14EdSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
_cfg.SetCVar(CVars.EntitiesCategoryFilter, "ForkFiltered");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
<Control xmlns="https://spacestation14.io">
|
|
||||||
<GridContainer Columns="6">
|
|
||||||
|
|
||||||
<TextureRect Name="GoldView"
|
|
||||||
MinSize="10 10"
|
|
||||||
Stretch="KeepAspectCentered"/>
|
|
||||||
<Label Name="GoldText"
|
|
||||||
Margin="0,0,5,0"/>
|
|
||||||
|
|
||||||
<TextureRect Name="SilverView"
|
|
||||||
MinSize="10 10"
|
|
||||||
Stretch="KeepAspectCentered"/>
|
|
||||||
<Label Name="SilverText"
|
|
||||||
Margin="0,0,5,0"/>
|
|
||||||
|
|
||||||
<TextureRect Name="CopperView"
|
|
||||||
MinSize="10 10"
|
|
||||||
Stretch="KeepAspectCentered"/>
|
|
||||||
<Label Name="CopperText"
|
|
||||||
Margin="0,0,5,0"/>
|
|
||||||
</GridContainer>
|
|
||||||
</Control>
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
using Robust.Client.AutoGenerated;
|
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
using Robust.Client.UserInterface;
|
|
||||||
using Robust.Client.UserInterface.XAML;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.Shared.Utility;
|
|
||||||
|
|
||||||
namespace Content.Client._CP14.TravelingStoreShip;
|
|
||||||
|
|
||||||
[GenerateTypedNameReferences]
|
|
||||||
public sealed partial class CP14PriceControl : Control
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IEntityManager _entity = default!;
|
|
||||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
|
||||||
|
|
||||||
private readonly SpriteSystem _sprite;
|
|
||||||
|
|
||||||
public CP14PriceControl(int price)
|
|
||||||
{
|
|
||||||
RobustXamlLoader.Load(this);
|
|
||||||
IoCManager.InjectDependencies(this);
|
|
||||||
|
|
||||||
_sprite = _entity.System<SpriteSystem>();
|
|
||||||
|
|
||||||
var rsiPath = new ResPath("_CP14/Interface/Misc/coins.rsi");
|
|
||||||
|
|
||||||
var total = price;
|
|
||||||
|
|
||||||
var gp = total / 100;
|
|
||||||
total %= 100;
|
|
||||||
|
|
||||||
var sp = total / 10;
|
|
||||||
total %= 10;
|
|
||||||
|
|
||||||
var cp = total;
|
|
||||||
|
|
||||||
CopperView.Texture = _sprite.Frame0(new SpriteSpecifier.Rsi(rsiPath, "c"));
|
|
||||||
CopperText.Text = cp.ToString();
|
|
||||||
|
|
||||||
SilverView.Texture = _sprite.Frame0(new SpriteSpecifier.Rsi(rsiPath, "s"));
|
|
||||||
SilverText.Text = sp.ToString();
|
|
||||||
|
|
||||||
GoldView.Texture = _sprite.Frame0(new SpriteSpecifier.Rsi(rsiPath, "g"));
|
|
||||||
GoldText.Text = gp.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
using Content.Shared._CP14.Cargo;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Client.UserInterface;
|
|
||||||
|
|
||||||
namespace Content.Client._CP14.TravelingStoreShip;
|
|
||||||
|
|
||||||
public sealed class CP14StoreBoundUserInterface : BoundUserInterface
|
|
||||||
{
|
|
||||||
private CP14StoreWindow? _window;
|
|
||||||
|
|
||||||
public CP14StoreBoundUserInterface(EntityUid owner, [NotNull] Enum uiKey) : base(owner, uiKey)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Open()
|
|
||||||
{
|
|
||||||
base.Open();
|
|
||||||
|
|
||||||
_window = this.CreateWindow<CP14StoreWindow>();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected override void UpdateState(BoundUserInterfaceState state)
|
|
||||||
{
|
|
||||||
base.UpdateState(state);
|
|
||||||
|
|
||||||
switch (state)
|
|
||||||
{
|
|
||||||
case CP14StoreUiState storeState:
|
|
||||||
_window?.UpdateUI(storeState);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
<Control xmlns="https://spacestation14.io">
|
|
||||||
<Button Name="ProductButton" Access="Public">
|
|
||||||
<BoxContainer Orientation="Vertical">
|
|
||||||
<BoxContainer Orientation="Horizontal">
|
|
||||||
<TextureRect Name="View"
|
|
||||||
MinSize="48 48"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
VerticalAlignment="Top"
|
|
||||||
Stretch="KeepAspectCentered"/>
|
|
||||||
<RichTextLabel Name="ProductName" VerticalAlignment="Center" Access="Public"/>
|
|
||||||
<BoxContainer Name="PriceHolder" VerticalAlignment="Center" HorizontalExpand="True" HorizontalAlignment="Right"/>
|
|
||||||
</BoxContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
</Button>
|
|
||||||
</Control>
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
using Content.Shared._CP14.Cargo;
|
|
||||||
using Robust.Client.AutoGenerated;
|
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
using Robust.Client.UserInterface;
|
|
||||||
using Robust.Client.UserInterface.XAML;
|
|
||||||
using Robust.Shared.Utility;
|
|
||||||
|
|
||||||
namespace Content.Client._CP14.TravelingStoreShip;
|
|
||||||
|
|
||||||
[GenerateTypedNameReferences]
|
|
||||||
public sealed partial class CP14StoreProductControl : Control
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IEntityManager _entity = default!;
|
|
||||||
|
|
||||||
private readonly SpriteSystem _sprite;
|
|
||||||
|
|
||||||
public CP14StoreProductControl(CP14StoreUiProductEntry entry)
|
|
||||||
{
|
|
||||||
RobustXamlLoader.Load(this);
|
|
||||||
IoCManager.InjectDependencies(this);
|
|
||||||
|
|
||||||
_sprite = _entity.System<SpriteSystem>();
|
|
||||||
|
|
||||||
UpdateName(entry.Name);
|
|
||||||
UpdateView(entry.Icon);
|
|
||||||
UpdatePrice(entry.Price);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdatePrice(int price)
|
|
||||||
{
|
|
||||||
PriceHolder.RemoveAllChildren();
|
|
||||||
PriceHolder.AddChild(new CP14PriceControl(price));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateName(string name)
|
|
||||||
{
|
|
||||||
ProductName.Text = $"[bold]{name}[/bold]";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateView(SpriteSpecifier spriteSpecifier)
|
|
||||||
{
|
|
||||||
View.Texture = _sprite.Frame0(spriteSpecifier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
<DefaultWindow xmlns="https://spacestation14.io"
|
|
||||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
|
||||||
Title="{Loc 'cp14-store-ui-title'}"
|
|
||||||
MinSize="800 600"
|
|
||||||
SetSize="800 600">
|
|
||||||
<BoxContainer Orientation="Horizontal">
|
|
||||||
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Horizontal">
|
|
||||||
<!-- Product list (left side UI) -->
|
|
||||||
<TabContainer SizeFlagsStretchRatio="0.5" Name="Tabs" HorizontalExpand="True" VerticalExpand="True" MinSize="0 200">
|
|
||||||
<ScrollContainer HorizontalExpand="True" VerticalExpand="True" MinSize="0 200">
|
|
||||||
<BoxContainer Name="BuyProductsContainer" Orientation="Vertical" HorizontalExpand="True"/>
|
|
||||||
</ScrollContainer>
|
|
||||||
<ScrollContainer HorizontalExpand="True" VerticalExpand="True" MinSize="0 200">
|
|
||||||
<BoxContainer Name="SellProductsContainer" Orientation="Vertical" HorizontalExpand="True"/>
|
|
||||||
</ScrollContainer>
|
|
||||||
</TabContainer>
|
|
||||||
<!-- Station trading data (right side UI) -->
|
|
||||||
<BoxContainer SizeFlagsStretchRatio="0.5" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" Margin="0 0 10 0">
|
|
||||||
<controls:StripeBack>
|
|
||||||
<PanelContainer>
|
|
||||||
<Label Text="{Loc 'cp14-store-ui-order'}" Align="Center" Margin="0 5 0 3"/>
|
|
||||||
</PanelContainer>
|
|
||||||
</controls:StripeBack>
|
|
||||||
<Label Name="TravelTimeLabel" Text="00:00" HorizontalAlignment="Center" HorizontalExpand="True" Margin="0 15 0 0"/>
|
|
||||||
<controls:HLine Color="#404040" Thickness="2" Margin="0 5"/>
|
|
||||||
<RichTextLabel Name="SelectedName" HorizontalExpand="True" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="5"/>
|
|
||||||
<RichTextLabel Name="SelectedDesc" HorizontalExpand="True" VerticalExpand="True" VerticalAlignment="Top" Margin="5"/>
|
|
||||||
</BoxContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
</DefaultWindow>
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
using Content.Shared._CP14.Cargo;
|
|
||||||
using Robust.Client.AutoGenerated;
|
|
||||||
using Robust.Client.UserInterface.CustomControls;
|
|
||||||
using Robust.Client.UserInterface.XAML;
|
|
||||||
using Robust.Shared.Timing;
|
|
||||||
|
|
||||||
namespace Content.Client._CP14.TravelingStoreShip;
|
|
||||||
|
|
||||||
[GenerateTypedNameReferences]
|
|
||||||
public sealed partial class CP14StoreWindow : DefaultWindow
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
|
||||||
|
|
||||||
private TimeSpan? _nextTravelTime;
|
|
||||||
private bool _onStation;
|
|
||||||
|
|
||||||
public CP14StoreWindow()
|
|
||||||
{
|
|
||||||
RobustXamlLoader.Load(this);
|
|
||||||
IoCManager.InjectDependencies(this);
|
|
||||||
|
|
||||||
Tabs.SetTabTitle(0, Loc.GetString("cp14-store-ui-tab-buy"));
|
|
||||||
Tabs.SetTabTitle(1, Loc.GetString("cp14-store-ui-tab-sell"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateUI(CP14StoreUiState state)
|
|
||||||
{
|
|
||||||
UpdateProducts(state);
|
|
||||||
|
|
||||||
_nextTravelTime = state.NextTravelTime;
|
|
||||||
_onStation = state.OnStation;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void FrameUpdate(FrameEventArgs args)
|
|
||||||
{
|
|
||||||
base.FrameUpdate(args);
|
|
||||||
|
|
||||||
//Updating time
|
|
||||||
if (_nextTravelTime is not null)
|
|
||||||
{
|
|
||||||
var time = _nextTravelTime.Value - _timing.CurTime;
|
|
||||||
|
|
||||||
TravelTimeLabel.Text =
|
|
||||||
$"{Loc.GetString(_onStation ? "cp14-store-ui-next-travel-out" : "cp14-store-ui-next-travel-in")} {Math.Max(time.Minutes, 0):00}:{Math.Max(time.Seconds, 0):00}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateProducts(CP14StoreUiState state)
|
|
||||||
{
|
|
||||||
BuyProductsContainer.RemoveAllChildren();
|
|
||||||
SellProductsContainer.RemoveAllChildren();
|
|
||||||
|
|
||||||
foreach (var product in state.ProductsBuy)
|
|
||||||
{
|
|
||||||
var control = new CP14StoreProductControl(product);
|
|
||||||
control.ProductButton.OnPressed += _ =>
|
|
||||||
{
|
|
||||||
SelectProduct(product);
|
|
||||||
};
|
|
||||||
BuyProductsContainer.AddChild(control);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var product in state.ProductsSell)
|
|
||||||
{
|
|
||||||
var control = new CP14StoreProductControl(product);
|
|
||||||
control.ProductButton.OnPressed += _ =>
|
|
||||||
{
|
|
||||||
SelectProduct(product);
|
|
||||||
};
|
|
||||||
SellProductsContainer.AddChild(control);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SelectProduct(CP14StoreUiProductEntry? entry)
|
|
||||||
{
|
|
||||||
SelectedName.Text = entry is null ? string.Empty : $"[bold]{entry.Value.Name}[/bold]";
|
|
||||||
SelectedDesc.Text = entry is null ? string.Empty : entry.Value.Desc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -35,9 +35,9 @@ public sealed partial class TestPair
|
|||||||
mapData.GridCoords = new EntityCoordinates(mapData.Grid, 0, 0);
|
mapData.GridCoords = new EntityCoordinates(mapData.Grid, 0, 0);
|
||||||
var plating = tileDefinitionManager[tile];
|
var plating = tileDefinitionManager[tile];
|
||||||
var platingTile = new Tile(plating.TileId);
|
var platingTile = new Tile(plating.TileId);
|
||||||
Server.System<SharedMapSystem>().SetTile(mapData.Grid.Owner, mapData.Grid.Comp, mapData.GridCoords, platingTile);
|
mapData.Grid.Comp.SetTile(mapData.GridCoords, platingTile);
|
||||||
mapData.MapCoords = new MapCoordinates(0, 0, mapData.MapId);
|
mapData.MapCoords = new MapCoordinates(0, 0, mapData.MapId);
|
||||||
mapData.Tile = Server.System<SharedMapSystem>().GetAllTiles(mapData.Grid.Owner, mapData.Grid.Comp).First();
|
mapData.Tile = mapData.Grid.Comp.GetAllTiles().First();
|
||||||
});
|
});
|
||||||
|
|
||||||
TestMap = mapData;
|
TestMap = mapData;
|
||||||
@@ -107,41 +107,13 @@ public sealed partial class TestPair
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieve all entity prototypes that have some component.
|
/// Retrieve all entity prototypes that have some component.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<(EntityPrototype, T)> GetPrototypesWithComponent<T>(
|
public List<EntityPrototype> GetPrototypesWithComponent<T>(
|
||||||
HashSet<string>? ignored = null,
|
HashSet<string>? ignored = null,
|
||||||
bool ignoreAbstract = true,
|
bool ignoreAbstract = true,
|
||||||
bool ignoreTestPrototypes = true)
|
bool ignoreTestPrototypes = true)
|
||||||
where T : IComponent
|
where T : IComponent
|
||||||
{
|
{
|
||||||
var id = Server.ResolveDependency<IComponentFactory>().GetComponentName(typeof(T));
|
var id = Server.ResolveDependency<IComponentFactory>().GetComponentName(typeof(T));
|
||||||
var list = new List<(EntityPrototype, T)>();
|
|
||||||
foreach (var proto in Server.ProtoMan.EnumeratePrototypes<EntityPrototype>())
|
|
||||||
{
|
|
||||||
if (ignored != null && ignored.Contains(proto.ID))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ignoreAbstract && proto.Abstract)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ignoreTestPrototypes && IsTestPrototype(proto))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (proto.Components.TryGetComponent(id, out var cmp))
|
|
||||||
list.Add((proto, (T)cmp));
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieve all entity prototypes that have some component.
|
|
||||||
/// </summary>
|
|
||||||
public List<EntityPrototype> GetPrototypesWithComponent(Type type,
|
|
||||||
HashSet<string>? ignored = null,
|
|
||||||
bool ignoreAbstract = true,
|
|
||||||
bool ignoreTestPrototypes = true)
|
|
||||||
{
|
|
||||||
var id = Server.ResolveDependency<IComponentFactory>().GetComponentName(type);
|
|
||||||
var list = new List<EntityPrototype>();
|
var list = new List<EntityPrototype>();
|
||||||
foreach (var proto in Server.ProtoMan.EnumeratePrototypes<EntityPrototype>())
|
foreach (var proto in Server.ProtoMan.EnumeratePrototypes<EntityPrototype>())
|
||||||
{
|
{
|
||||||
@@ -155,7 +127,7 @@ public sealed partial class TestPair
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (proto.Components.ContainsKey(id))
|
if (proto.Components.ContainsKey(id))
|
||||||
list.Add((proto));
|
list.Add(proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
|
|||||||
@@ -36,9 +36,7 @@ public static partial class PoolManager
|
|||||||
(CCVars.ConfigPresetDevelopment.Name, "false"),
|
(CCVars.ConfigPresetDevelopment.Name, "false"),
|
||||||
(CCVars.AdminLogsEnabled.Name, "false"),
|
(CCVars.AdminLogsEnabled.Name, "false"),
|
||||||
(CCVars.AutosaveEnabled.Name, "false"),
|
(CCVars.AutosaveEnabled.Name, "false"),
|
||||||
(CVars.NetBufferSize.Name, "0"),
|
(CVars.NetBufferSize.Name, "0")
|
||||||
(CCVars.InteractionRateLimitCount.Name, "9999999"),
|
|
||||||
(CCVars.InteractionRateLimitPeriod.Name, "0.1"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public static async Task SetupCVars(RobustIntegrationTest.IntegrationInstance instance, PoolSettings settings)
|
public static async Task SetupCVars(RobustIntegrationTest.IntegrationInstance instance, PoolSettings settings)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Content.IntegrationTests.Tests.GameRules;
|
|||||||
// Lets not let that happen again.
|
// Lets not let that happen again.
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public sealed class AntagPreferenceTest
|
public sealed class AntagPreferenceTest
|
||||||
{/* CP14 disabled
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public async Task TestLobbyPlayersValid()
|
public async Task TestLobbyPlayersValid()
|
||||||
{
|
{
|
||||||
@@ -72,5 +72,5 @@ public sealed class AntagPreferenceTest
|
|||||||
|
|
||||||
await server.WaitPost(() => server.EntMan.DeleteEntity(uid));
|
await server.WaitPost(() => server.EntMan.DeleteEntity(uid));
|
||||||
await pair.CleanReturnAsync();
|
await pair.CleanReturnAsync();
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Body.Components;
|
using Content.Server.Body.Components;
|
||||||
using Content.Server.GameTicking;
|
using Content.Server.GameTicking;
|
||||||
@@ -121,8 +120,8 @@ public sealed class NukeOpsTest
|
|||||||
Assert.That(roleSys.MindHasRole<NukeopsRoleComponent>(mind));
|
Assert.That(roleSys.MindHasRole<NukeopsRoleComponent>(mind));
|
||||||
Assert.That(factionSys.IsMember(player, "Syndicate"), Is.True);
|
Assert.That(factionSys.IsMember(player, "Syndicate"), Is.True);
|
||||||
Assert.That(factionSys.IsMember(player, "NanoTrasen"), Is.False);
|
Assert.That(factionSys.IsMember(player, "NanoTrasen"), Is.False);
|
||||||
var roles = roleSys.MindGetAllRoleInfo(mind);
|
var roles = roleSys.MindGetAllRoles(mind);
|
||||||
var cmdRoles = roles.Where(x => x.Prototype == "NukeopsCommander");
|
var cmdRoles = roles.Where(x => x.Prototype == "NukeopsCommander" && x.Component is NukeopsRoleComponent);
|
||||||
Assert.That(cmdRoles.Count(), Is.EqualTo(1));
|
Assert.That(cmdRoles.Count(), Is.EqualTo(1));
|
||||||
|
|
||||||
// The second dummy player should be a medic
|
// The second dummy player should be a medic
|
||||||
@@ -132,8 +131,8 @@ public sealed class NukeOpsTest
|
|||||||
Assert.That(roleSys.MindHasRole<NukeopsRoleComponent>(dummyMind));
|
Assert.That(roleSys.MindHasRole<NukeopsRoleComponent>(dummyMind));
|
||||||
Assert.That(factionSys.IsMember(dummyEnts[1], "Syndicate"), Is.True);
|
Assert.That(factionSys.IsMember(dummyEnts[1], "Syndicate"), Is.True);
|
||||||
Assert.That(factionSys.IsMember(dummyEnts[1], "NanoTrasen"), Is.False);
|
Assert.That(factionSys.IsMember(dummyEnts[1], "NanoTrasen"), Is.False);
|
||||||
roles = roleSys.MindGetAllRoleInfo(dummyMind);
|
roles = roleSys.MindGetAllRoles(dummyMind);
|
||||||
cmdRoles = roles.Where(x => x.Prototype == "NukeopsMedic");
|
cmdRoles = roles.Where(x => x.Prototype == "NukeopsMedic" && x.Component is NukeopsRoleComponent);
|
||||||
Assert.That(cmdRoles.Count(), Is.EqualTo(1));
|
Assert.That(cmdRoles.Count(), Is.EqualTo(1));
|
||||||
|
|
||||||
// The other two players should have just spawned in as normal.
|
// The other two players should have just spawned in as normal.
|
||||||
@@ -142,14 +141,13 @@ public sealed class NukeOpsTest
|
|||||||
void CheckDummy(int i)
|
void CheckDummy(int i)
|
||||||
{
|
{
|
||||||
var ent = dummyEnts[i];
|
var ent = dummyEnts[i];
|
||||||
var mindCrew = mindSys.GetMind(ent)!.Value;
|
var mind = mindSys.GetMind(ent)!.Value;
|
||||||
Assert.That(entMan.HasComponent<NukeOperativeComponent>(ent), Is.False);
|
Assert.That(entMan.HasComponent<NukeOperativeComponent>(ent), Is.False);
|
||||||
Assert.That(roleSys.MindIsAntagonist(mindCrew), Is.False);
|
Assert.That(roleSys.MindIsAntagonist(mind), Is.False);
|
||||||
Assert.That(roleSys.MindHasRole<NukeopsRoleComponent>(mindCrew), Is.False);
|
Assert.That(roleSys.MindHasRole<NukeopsRoleComponent>(mind), Is.False);
|
||||||
Assert.That(factionSys.IsMember(ent, "Syndicate"), Is.False);
|
Assert.That(factionSys.IsMember(ent, "Syndicate"), Is.False);
|
||||||
Assert.That(factionSys.IsMember(ent, "NanoTrasen"), Is.True);
|
Assert.That(factionSys.IsMember(ent, "NanoTrasen"), Is.True);
|
||||||
var nukeroles = new List<string>() { "Nukeops", "NukeopsMedic", "NukeopsCommander" };
|
Assert.That(roleSys.MindGetAllRoles(mind).Any(x => x.Component is NukeopsRoleComponent), Is.False);
|
||||||
Assert.That(roleSys.MindGetAllRoleInfo(mindCrew).Any(x => nukeroles.Contains(x.Prototype)), Is.False);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The game rule exists, and all the stations/shuttles/maps are properly initialized
|
// The game rule exists, and all the stations/shuttles/maps are properly initialized
|
||||||
@@ -240,8 +238,7 @@ public sealed class NukeOpsTest
|
|||||||
for (var i = 0; i < nukies.Length - 1; i++)
|
for (var i = 0; i < nukies.Length - 1; i++)
|
||||||
{
|
{
|
||||||
entMan.DeleteEntity(nukies[i]);
|
entMan.DeleteEntity(nukies[i]);
|
||||||
Assert.That(roundEndSys.IsRoundEndRequested,
|
Assert.That(roundEndSys.IsRoundEndRequested, Is.False,
|
||||||
Is.False,
|
|
||||||
$"The round ended, but {nukies.Length - i - 1} nukies are still alive!");
|
$"The round ended, but {nukies.Length - i - 1} nukies are still alive!");
|
||||||
}
|
}
|
||||||
// Delete the last nukie and make sure the round ends.
|
// Delete the last nukie and make sure the round ends.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using Content.Server.Atmos.EntitySystems;
|
|||||||
using Content.Server.Body.Systems;
|
using Content.Server.Body.Systems;
|
||||||
using Content.Server.Station.Systems;
|
using Content.Server.Station.Systems;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
|
using Content.Shared.Roles.Jobs;
|
||||||
|
|
||||||
namespace Content.IntegrationTests.Tests.Internals;
|
namespace Content.IntegrationTests.Tests.Internals;
|
||||||
|
|
||||||
@@ -24,7 +25,10 @@ public sealed class AutoInternalsTests
|
|||||||
await server.WaitAssertion(() =>
|
await server.WaitAssertion(() =>
|
||||||
{
|
{
|
||||||
var profile = new HumanoidCharacterProfile();
|
var profile = new HumanoidCharacterProfile();
|
||||||
var dummy = stationSpawning.SpawnPlayerMob(testMap.GridCoords, "TestInternalsDummy", profile, station: null);
|
var dummy = stationSpawning.SpawnPlayerMob(testMap.GridCoords, new JobComponent()
|
||||||
|
{
|
||||||
|
Prototype = "TestInternalsDummy"
|
||||||
|
}, profile, station: null);
|
||||||
|
|
||||||
Assert.That(atmos.HasAtmosphere(testMap.Grid), Is.False, "Test map has atmosphere - test needs adjustment!");
|
Assert.That(atmos.HasAtmosphere(testMap.Grid), Is.False, "Test map has atmosphere - test needs adjustment!");
|
||||||
Assert.That(internals.AreInternalsWorking(dummy), "Internals did not automatically connect!");
|
Assert.That(internals.AreInternalsWorking(dummy), "Internals did not automatically connect!");
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Content.Server.Ghost;
|
||||||
using Content.Server.Ghost.Roles;
|
using Content.Server.Ghost.Roles;
|
||||||
using Content.Server.Ghost.Roles.Components;
|
using Content.Server.Ghost.Roles.Components;
|
||||||
using Content.Server.Mind.Commands;
|
using Content.Server.Mind.Commands;
|
||||||
|
using Content.Server.Players;
|
||||||
using Content.Server.Roles;
|
using Content.Server.Roles;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Damage.Prototypes;
|
using Content.Shared.Damage.Prototypes;
|
||||||
@@ -16,6 +18,7 @@ using Robust.Server.Console;
|
|||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
@@ -284,27 +287,27 @@ public sealed partial class MindTests
|
|||||||
Assert.Multiple(() =>
|
Assert.Multiple(() =>
|
||||||
{
|
{
|
||||||
Assert.That(roleSystem.MindHasRole<TraitorRoleComponent>(mindId), Is.False);
|
Assert.That(roleSystem.MindHasRole<TraitorRoleComponent>(mindId), Is.False);
|
||||||
Assert.That(roleSystem.MindHasRole<JobRoleComponent>(mindId), Is.False);
|
Assert.That(roleSystem.MindHasRole<JobComponent>(mindId), Is.False);
|
||||||
});
|
});
|
||||||
|
|
||||||
var traitorRole = "MindRoleTraitor";
|
var traitorRole = new TraitorRoleComponent();
|
||||||
|
|
||||||
roleSystem.MindAddRole(mindId, traitorRole);
|
roleSystem.MindAddRole(mindId, traitorRole);
|
||||||
|
|
||||||
Assert.Multiple(() =>
|
Assert.Multiple(() =>
|
||||||
{
|
{
|
||||||
Assert.That(roleSystem.MindHasRole<TraitorRoleComponent>(mindId));
|
Assert.That(roleSystem.MindHasRole<TraitorRoleComponent>(mindId));
|
||||||
Assert.That(roleSystem.MindHasRole<JobRoleComponent>(mindId), Is.False);
|
Assert.That(roleSystem.MindHasRole<JobComponent>(mindId), Is.False);
|
||||||
});
|
});
|
||||||
|
|
||||||
var jobRole = "";
|
var jobRole = new JobComponent();
|
||||||
|
|
||||||
roleSystem.MindAddJobRole(mindId, jobPrototype:jobRole);
|
roleSystem.MindAddRole(mindId, jobRole);
|
||||||
|
|
||||||
Assert.Multiple(() =>
|
Assert.Multiple(() =>
|
||||||
{
|
{
|
||||||
Assert.That(roleSystem.MindHasRole<TraitorRoleComponent>(mindId));
|
Assert.That(roleSystem.MindHasRole<TraitorRoleComponent>(mindId));
|
||||||
Assert.That(roleSystem.MindHasRole<JobRoleComponent>(mindId));
|
Assert.That(roleSystem.MindHasRole<JobComponent>(mindId));
|
||||||
});
|
});
|
||||||
|
|
||||||
roleSystem.MindRemoveRole<TraitorRoleComponent>(mindId);
|
roleSystem.MindRemoveRole<TraitorRoleComponent>(mindId);
|
||||||
@@ -312,15 +315,15 @@ public sealed partial class MindTests
|
|||||||
Assert.Multiple(() =>
|
Assert.Multiple(() =>
|
||||||
{
|
{
|
||||||
Assert.That(roleSystem.MindHasRole<TraitorRoleComponent>(mindId), Is.False);
|
Assert.That(roleSystem.MindHasRole<TraitorRoleComponent>(mindId), Is.False);
|
||||||
Assert.That(roleSystem.MindHasRole<JobRoleComponent>(mindId));
|
Assert.That(roleSystem.MindHasRole<JobComponent>(mindId));
|
||||||
});
|
});
|
||||||
|
|
||||||
roleSystem.MindRemoveRole<JobRoleComponent>(mindId);
|
roleSystem.MindRemoveRole<JobComponent>(mindId);
|
||||||
|
|
||||||
Assert.Multiple(() =>
|
Assert.Multiple(() =>
|
||||||
{
|
{
|
||||||
Assert.That(roleSystem.MindHasRole<TraitorRoleComponent>(mindId), Is.False);
|
Assert.That(roleSystem.MindHasRole<TraitorRoleComponent>(mindId), Is.False);
|
||||||
Assert.That(roleSystem.MindHasRole<JobRoleComponent>(mindId), Is.False);
|
Assert.That(roleSystem.MindHasRole<JobComponent>(mindId), Is.False);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,95 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
using Content.Server.Roles;
|
|
||||||
using Content.Shared.Roles;
|
|
||||||
using Content.Shared.Roles.Jobs;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Reflection;
|
|
||||||
|
|
||||||
namespace Content.IntegrationTests.Tests.Minds;
|
|
||||||
|
|
||||||
[TestFixture]
|
|
||||||
public sealed class RoleTests
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Check that any prototype with a <see cref="MindRoleComponent"/> is properly configured
|
|
||||||
/// </summary>
|
|
||||||
[Test]
|
|
||||||
public async Task ValidateRolePrototypes()
|
|
||||||
{
|
|
||||||
await using var pair = await PoolManager.GetServerClient();
|
|
||||||
|
|
||||||
var jobComp = pair.Server.ResolveDependency<IComponentFactory>().GetComponentName(typeof(JobRoleComponent));
|
|
||||||
|
|
||||||
Assert.Multiple(() =>
|
|
||||||
{
|
|
||||||
foreach (var (proto, comp) in pair.GetPrototypesWithComponent<MindRoleComponent>())
|
|
||||||
{
|
|
||||||
Assert.That(comp.AntagPrototype == null || comp.JobPrototype == null, $"Role {proto.ID} has both a job and antag prototype.");
|
|
||||||
Assert.That(!comp.ExclusiveAntag || comp.Antag, $"Role {proto.ID} is marked as an exclusive antag, despite not being an antag.");
|
|
||||||
Assert.That(comp.Antag || comp.AntagPrototype == null, $"Role {proto.ID} has an antag prototype, despite not being an antag.");
|
|
||||||
|
|
||||||
if (comp.JobPrototype != null)
|
|
||||||
Assert.That(proto.Components.ContainsKey(jobComp), $"Role {proto.ID} is a job, despite not having a job prototype.");
|
|
||||||
|
|
||||||
// It is possible that this is meant to be supported? Though I would assume that it would be for
|
|
||||||
// admin / prototype uploads, and that pre-defined roles should still check this.
|
|
||||||
Assert.That(!comp.Antag || comp.AntagPrototype != null , $"Role {proto.ID} is an antag, despite not having a antag prototype.");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await pair.CleanReturnAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Check that any prototype with a <see cref="JobRoleComponent"/> also has a properly configured
|
|
||||||
/// <see cref="MindRoleComponent"/>
|
|
||||||
/// </summary>
|
|
||||||
[Test]
|
|
||||||
public async Task ValidateJobPrototypes()
|
|
||||||
{
|
|
||||||
await using var pair = await PoolManager.GetServerClient();
|
|
||||||
|
|
||||||
var mindCompId = pair.Server.ResolveDependency<IComponentFactory>().GetComponentName(typeof(MindRoleComponent));
|
|
||||||
|
|
||||||
Assert.Multiple(() =>
|
|
||||||
{
|
|
||||||
foreach (var (proto, comp) in pair.GetPrototypesWithComponent<JobRoleComponent>())
|
|
||||||
{
|
|
||||||
if (proto.Components.TryGetComponent(mindCompId, out var mindComp))
|
|
||||||
Assert.That(((MindRoleComponent)mindComp).JobPrototype, Is.Not.Null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await pair.CleanReturnAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Check that any prototype with a component that inherits from <see cref="BaseMindRoleComponent"/> also has a
|
|
||||||
/// <see cref="MindRoleComponent"/>
|
|
||||||
/// </summary>
|
|
||||||
[Test]
|
|
||||||
public async Task ValidateRolesHaveMindRoleComp()
|
|
||||||
{
|
|
||||||
await using var pair = await PoolManager.GetServerClient();
|
|
||||||
|
|
||||||
var refMan = pair.Server.ResolveDependency<IReflectionManager>();
|
|
||||||
var mindCompId = pair.Server.ResolveDependency<IComponentFactory>().GetComponentName(typeof(MindRoleComponent));
|
|
||||||
|
|
||||||
var compTypes = refMan.GetAllChildren(typeof(BaseMindRoleComponent))
|
|
||||||
.Append(typeof(RoleBriefingComponent))
|
|
||||||
.Where(x => !x.IsAbstract);
|
|
||||||
|
|
||||||
Assert.Multiple(() =>
|
|
||||||
{
|
|
||||||
foreach (var comp in compTypes)
|
|
||||||
{
|
|
||||||
foreach (var proto in pair.GetPrototypesWithComponent(comp))
|
|
||||||
{
|
|
||||||
Assert.That(proto.Components.ContainsKey(mindCompId), $"Role {proto.ID} does not have a {nameof(MindRoleComponent)} despite having a {comp.Name}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await pair.CleanReturnAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -50,8 +50,9 @@ namespace Content.IntegrationTests.Tests
|
|||||||
"MeteorArena",
|
"MeteorArena",
|
||||||
|
|
||||||
//CrystallPunk maps
|
//CrystallPunk maps
|
||||||
"Village",
|
"AlchemyTest",
|
||||||
"Island",
|
"BattleRoyale",
|
||||||
|
"ExpeditionTest",
|
||||||
//CrystallPunk Map replacement end
|
//CrystallPunk Map replacement end
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -235,6 +236,7 @@ namespace Content.IntegrationTests.Tests
|
|||||||
|
|
||||||
// Test all availableJobs have spawnPoints
|
// Test all availableJobs have spawnPoints
|
||||||
// This is done inside gamemap test because loading the map takes ages and we already have it.
|
// This is done inside gamemap test because loading the map takes ages and we already have it.
|
||||||
|
/*
|
||||||
var comp = entManager.GetComponent<StationJobsComponent>(station);
|
var comp = entManager.GetComponent<StationJobsComponent>(station);
|
||||||
var jobs = new HashSet<ProtoId<JobPrototype>>(comp.SetupAvailableJobs.Keys);
|
var jobs = new HashSet<ProtoId<JobPrototype>>(comp.SetupAvailableJobs.Keys);
|
||||||
|
|
||||||
@@ -251,6 +253,7 @@ namespace Content.IntegrationTests.Tests
|
|||||||
jobs.ExceptWith(spawnPoints);
|
jobs.ExceptWith(spawnPoints);
|
||||||
|
|
||||||
Assert.That(jobs, Is.Empty, $"There is no spawnpoints for {string.Join(", ", jobs)} on {mapProto}.");
|
Assert.That(jobs, Is.Empty, $"There is no spawnpoints for {string.Join(", ", jobs)} on {mapProto}.");
|
||||||
|
*/ //CP14 disable job spawners test
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Content.Server.Station.Systems;
|
|||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
using Content.Shared.Preferences.Loadouts;
|
using Content.Shared.Preferences.Loadouts;
|
||||||
|
using Content.Shared.Roles.Jobs;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
@@ -67,7 +68,10 @@ public sealed class LoadoutTests
|
|||||||
|
|
||||||
profile.SetLoadout(new RoleLoadout("LoadoutTester"));
|
profile.SetLoadout(new RoleLoadout("LoadoutTester"));
|
||||||
|
|
||||||
var tester = stationSystem.SpawnPlayerMob(testMap.GridCoords, job: "LoadoutTester", profile, station: null);
|
var tester = stationSystem.SpawnPlayerMob(testMap.GridCoords, job: new JobComponent()
|
||||||
|
{
|
||||||
|
Prototype = "LoadoutTester"
|
||||||
|
}, profile, station: null);
|
||||||
|
|
||||||
var slotQuery = inventorySystem.GetSlotEnumerator(tester);
|
var slotQuery = inventorySystem.GetSlotEnumerator(tester);
|
||||||
var checkedCount = 0;
|
var checkedCount = 0;
|
||||||
|
|||||||
@@ -35,16 +35,15 @@ public sealed class StartingGearPrototypeStorageTest
|
|||||||
{
|
{
|
||||||
foreach (var gearProto in protos)
|
foreach (var gearProto in protos)
|
||||||
{
|
{
|
||||||
|
var backpackProto = ((IEquipmentLoadout) gearProto).GetGear("back");
|
||||||
|
if (backpackProto == string.Empty)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var bag = server.EntMan.SpawnEntity(backpackProto, coords);
|
||||||
var ents = new ValueList<EntityUid>();
|
var ents = new ValueList<EntityUid>();
|
||||||
|
|
||||||
foreach (var (slot, entProtos) in gearProto.Storage)
|
foreach (var (slot, entProtos) in gearProto.Storage)
|
||||||
{
|
{
|
||||||
ents.Clear();
|
|
||||||
var storageProto = ((IEquipmentLoadout)gearProto).GetGear(slot);
|
|
||||||
if (storageProto == string.Empty)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var bag = server.EntMan.SpawnEntity(storageProto, coords);
|
|
||||||
if (entProtos.Count == 0)
|
if (entProtos.Count == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -60,8 +59,9 @@ public sealed class StartingGearPrototypeStorageTest
|
|||||||
|
|
||||||
server.EntMan.DeleteEntity(ent);
|
server.EntMan.DeleteEntity(ent);
|
||||||
}
|
}
|
||||||
server.EntMan.DeleteEntity(bag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
server.EntMan.DeleteEntity(bag);
|
||||||
}
|
}
|
||||||
|
|
||||||
mapManager.DeleteMap(testMap.MapId);
|
mapManager.DeleteMap(testMap.MapId);
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public sealed class PrototypeSaveTest
|
|||||||
|
|
||||||
await pair.Client.WaitPost(() =>
|
await pair.Client.WaitPost(() =>
|
||||||
{
|
{
|
||||||
foreach (var (proto, _) in pair.GetPrototypesWithComponent<ItemComponent>(Ignored))
|
foreach (var proto in pair.GetPrototypesWithComponent<ItemComponent>(Ignored))
|
||||||
{
|
{
|
||||||
var dummy = pair.Client.EntMan.Spawn(proto.ID);
|
var dummy = pair.Client.EntMan.Spawn(proto.ID);
|
||||||
pair.Client.EntMan.RunMapInit(dummy, pair.Client.MetaData(dummy));
|
pair.Client.EntMan.RunMapInit(dummy, pair.Client.MetaData(dummy));
|
||||||
|
|||||||
@@ -94,13 +94,14 @@ namespace Content.IntegrationTests.Tests
|
|||||||
|
|
||||||
await Assert.MultipleAsync(async () =>
|
await Assert.MultipleAsync(async () =>
|
||||||
{
|
{
|
||||||
foreach (var (proto, fill) in pair.GetPrototypesWithComponent<StorageFillComponent>())
|
foreach (var proto in pair.GetPrototypesWithComponent<StorageFillComponent>())
|
||||||
{
|
{
|
||||||
if (proto.HasComponent<EntityStorageComponent>(compFact))
|
if (proto.HasComponent<EntityStorageComponent>(compFact))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
StorageComponent? storage = null;
|
StorageComponent? storage = null;
|
||||||
ItemComponent? item = null;
|
ItemComponent? item = null;
|
||||||
|
StorageFillComponent fill = default!;
|
||||||
var size = 0;
|
var size = 0;
|
||||||
await server.WaitAssertion(() =>
|
await server.WaitAssertion(() =>
|
||||||
{
|
{
|
||||||
@@ -111,6 +112,7 @@ namespace Content.IntegrationTests.Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
proto.TryGetComponent("Item", out item);
|
proto.TryGetComponent("Item", out item);
|
||||||
|
fill = (StorageFillComponent) proto.Components[id].Component;
|
||||||
size = GetFillSize(fill, false, protoMan, itemSys);
|
size = GetFillSize(fill, false, protoMan, itemSys);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -177,7 +179,7 @@ namespace Content.IntegrationTests.Tests
|
|||||||
|
|
||||||
var itemSys = entMan.System<SharedItemSystem>();
|
var itemSys = entMan.System<SharedItemSystem>();
|
||||||
|
|
||||||
foreach (var (proto, fill) in pair.GetPrototypesWithComponent<StorageFillComponent>())
|
foreach (var proto in pair.GetPrototypesWithComponent<StorageFillComponent>())
|
||||||
{
|
{
|
||||||
if (proto.HasComponent<StorageComponent>(compFact))
|
if (proto.HasComponent<StorageComponent>(compFact))
|
||||||
continue;
|
continue;
|
||||||
@@ -190,6 +192,7 @@ namespace Content.IntegrationTests.Tests
|
|||||||
if (entStorage == null)
|
if (entStorage == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var fill = (StorageFillComponent) proto.Components[id].Component;
|
||||||
var size = GetFillSize(fill, true, protoMan, itemSys);
|
var size = GetFillSize(fill, true, protoMan, itemSys);
|
||||||
Assert.That(size, Is.LessThanOrEqualTo(entStorage.Capacity),
|
Assert.That(size, Is.LessThanOrEqualTo(entStorage.Capacity),
|
||||||
$"{proto.ID} storage fill is too large.");
|
$"{proto.ID} storage fill is too large.");
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using Content.Shared._CP14.Cargo.Prototype;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.IntegrationTests.Tests._CP14;
|
|
||||||
|
|
||||||
#nullable enable
|
|
||||||
|
|
||||||
[TestFixture]
|
|
||||||
public sealed class CP14CargoTest
|
|
||||||
{
|
|
||||||
[Test]
|
|
||||||
public async Task CheckAllBuyPositionsUniqueCode()
|
|
||||||
{
|
|
||||||
await using var pair = await PoolManager.GetServerClient();
|
|
||||||
var server = pair.Server;
|
|
||||||
|
|
||||||
var compFactory = server.ResolveDependency<IComponentFactory>();
|
|
||||||
var protoManager = server.ResolveDependency<IPrototypeManager>();
|
|
||||||
|
|
||||||
await server.WaitAssertion(() =>
|
|
||||||
{
|
|
||||||
Assert.Multiple(() =>
|
|
||||||
{
|
|
||||||
HashSet<string> existedCodes = new();
|
|
||||||
|
|
||||||
foreach (var proto in protoManager.EnumeratePrototypes<CP14StoreBuyPositionPrototype>())
|
|
||||||
{
|
|
||||||
Assert.That(!existedCodes.Contains(proto.Code), $"Repeated purchasing code {proto.Code} of the {proto}");
|
|
||||||
existedCodes.Add(proto.Code);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
await pair.CleanReturnAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.IntegrationTests.Tests._CP14;
|
|
||||||
|
|
||||||
#nullable enable
|
|
||||||
|
|
||||||
[TestFixture]
|
|
||||||
public sealed class CP14EntityTest
|
|
||||||
{
|
|
||||||
[Test]
|
|
||||||
public async Task CheckAllCP14EntityHasForkFilteredCategory()
|
|
||||||
{
|
|
||||||
await using var pair = await PoolManager.GetServerClient();
|
|
||||||
var server = pair.Server;
|
|
||||||
|
|
||||||
var compFactory = server.ResolveDependency<IComponentFactory>();
|
|
||||||
var protoManager = server.ResolveDependency<IPrototypeManager>();
|
|
||||||
|
|
||||||
await server.WaitAssertion(() =>
|
|
||||||
{
|
|
||||||
Assert.Multiple(() =>
|
|
||||||
{
|
|
||||||
if (!protoManager.TryIndex<EntityCategoryPrototype>("ForkFiltered", out var indexedFilter))
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var proto in protoManager.EnumeratePrototypes<EntityPrototype>())
|
|
||||||
{
|
|
||||||
if (!proto.ID.StartsWith("CP14"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (proto.Abstract || proto.HideSpawnMenu)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Assert.That(proto.Categories.Contains(indexedFilter), $"CP14 fork proto: {proto} does not marked abstract, or have a HideSpawnMenu or ForkFiltered category");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
await pair.CleanReturnAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
using Content.Shared._CP14.MagicRitual;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.IntegrationTests.Tests._CP14;
|
|
||||||
|
|
||||||
#nullable enable
|
|
||||||
|
|
||||||
[TestFixture]
|
|
||||||
public sealed class CP14RitualTest
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// States that all edges of the ritual phase have triggers.
|
|
||||||
/// </summary>
|
|
||||||
[Test]
|
|
||||||
public async Task RitualHasAllTriggersTest()
|
|
||||||
{
|
|
||||||
await using var pair = await PoolManager.GetServerClient();
|
|
||||||
var server = pair.Server;
|
|
||||||
|
|
||||||
var compFactory = server.ResolveDependency<IComponentFactory>();
|
|
||||||
var protoManager = server.ResolveDependency<IPrototypeManager>();
|
|
||||||
|
|
||||||
await server.WaitAssertion(() =>
|
|
||||||
{
|
|
||||||
Assert.Multiple(() =>
|
|
||||||
{
|
|
||||||
foreach (var proto in protoManager.EnumeratePrototypes<EntityPrototype>())
|
|
||||||
{
|
|
||||||
if (!proto.TryGetComponent(out CP14MagicRitualPhaseComponent? phase, compFactory))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (phase.DeadEnd)
|
|
||||||
{
|
|
||||||
Assert.That(phase.Edges.Count == 0, $"{proto} is a ritual node, but has no paths to other nodes. Either add deadEnd = true, or add paths to other nodes.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Assert.That(phase.Edges.Count > 0, $"{proto} is a deadEnd ritual node, but has {phase.Edges.Count} edges! Remove all edges, or make it a non dead-end node");
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var edge in phase.Edges)
|
|
||||||
{
|
|
||||||
Assert.That(edge.Triggers.Count > 0, $"{proto} is ritual node, but edge to {edge.Target} has no triggers and cannot be activated.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
await pair.CleanReturnAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -67,7 +67,7 @@ namespace Content.Server.Access.Systems
|
|||||||
if (!TryComp<IdCardComponent>(uid, out var idCard))
|
if (!TryComp<IdCardComponent>(uid, out var idCard))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var state = new AgentIDCardBoundUserInterfaceState(idCard.FullName ?? "", idCard.LocalizedJobTitle ?? "", idCard.JobIcon);
|
var state = new AgentIDCardBoundUserInterfaceState(idCard.FullName ?? "", idCard.JobTitle ?? "", idCard.JobIcon);
|
||||||
_uiSystem.SetUiState(uid, AgentIDCardUiKey.Key, state);
|
_uiSystem.SetUiState(uid, AgentIDCardUiKey.Key, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ public sealed class IdCardConsoleSystem : SharedIdCardConsoleSystem
|
|||||||
PrivilegedIdIsAuthorized(uid, component),
|
PrivilegedIdIsAuthorized(uid, component),
|
||||||
true,
|
true,
|
||||||
targetIdComponent.FullName,
|
targetIdComponent.FullName,
|
||||||
targetIdComponent.LocalizedJobTitle,
|
targetIdComponent.JobTitle,
|
||||||
targetAccessComponent.Tags.ToList(),
|
targetAccessComponent.Tags.ToList(),
|
||||||
possibleAccess,
|
possibleAccess,
|
||||||
jobProto,
|
jobProto,
|
||||||
|
|||||||
@@ -14,13 +14,13 @@ using Content.Shared.Players.PlayTimeTracking;
|
|||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Asynchronous;
|
using Robust.Shared.Asynchronous;
|
||||||
using Robust.Shared.Collections;
|
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Server.Administration.Managers;
|
namespace Content.Server.Administration.Managers;
|
||||||
|
|
||||||
@@ -45,12 +45,14 @@ public sealed partial class BanManager : IBanManager, IPostInjectInit
|
|||||||
public const string SawmillId = "admin.bans";
|
public const string SawmillId = "admin.bans";
|
||||||
public const string JobPrefix = "Job:";
|
public const string JobPrefix = "Job:";
|
||||||
|
|
||||||
private readonly Dictionary<ICommonSession, List<ServerRoleBanDef>> _cachedRoleBans = new();
|
private readonly Dictionary<NetUserId, HashSet<ServerRoleBanDef>> _cachedRoleBans = new();
|
||||||
// Cached ban exemption flags are used to handle
|
// Cached ban exemption flags are used to handle
|
||||||
private readonly Dictionary<ICommonSession, ServerBanExemptFlags> _cachedBanExemptions = new();
|
private readonly Dictionary<ICommonSession, ServerBanExemptFlags> _cachedBanExemptions = new();
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
|
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
|
||||||
|
|
||||||
_netManager.RegisterNetMessage<MsgRoleBans>();
|
_netManager.RegisterNetMessage<MsgRoleBans>();
|
||||||
|
|
||||||
_db.SubscribeToNotifications(OnDatabaseNotification);
|
_db.SubscribeToNotifications(OnDatabaseNotification);
|
||||||
@@ -61,23 +63,12 @@ public sealed partial class BanManager : IBanManager, IPostInjectInit
|
|||||||
|
|
||||||
private async Task CachePlayerData(ICommonSession player, CancellationToken cancel)
|
private async Task CachePlayerData(ICommonSession player, CancellationToken cancel)
|
||||||
{
|
{
|
||||||
|
// Yeah so role ban loading code isn't integrated with exempt flag loading code.
|
||||||
|
// Have you seen how garbage role ban code code is? I don't feel like refactoring it right now.
|
||||||
|
|
||||||
var flags = await _db.GetBanExemption(player.UserId, cancel);
|
var flags = await _db.GetBanExemption(player.UserId, cancel);
|
||||||
|
|
||||||
var netChannel = player.Channel;
|
|
||||||
ImmutableArray<byte>? hwId = netChannel.UserData.HWId.Length == 0 ? null : netChannel.UserData.HWId;
|
|
||||||
var roleBans = await _db.GetServerRoleBansAsync(netChannel.RemoteEndPoint.Address, player.UserId, hwId, false);
|
|
||||||
|
|
||||||
var userRoleBans = new List<ServerRoleBanDef>();
|
|
||||||
foreach (var ban in roleBans)
|
|
||||||
{
|
|
||||||
userRoleBans.Add(ban);
|
|
||||||
}
|
|
||||||
|
|
||||||
cancel.ThrowIfCancellationRequested();
|
cancel.ThrowIfCancellationRequested();
|
||||||
_cachedBanExemptions[player] = flags;
|
_cachedBanExemptions[player] = flags;
|
||||||
_cachedRoleBans[player] = userRoleBans;
|
|
||||||
|
|
||||||
SendRoleBans(player);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClearPlayerData(ICommonSession player)
|
private void ClearPlayerData(ICommonSession player)
|
||||||
@@ -85,15 +76,25 @@ public sealed partial class BanManager : IBanManager, IPostInjectInit
|
|||||||
_cachedBanExemptions.Remove(player);
|
_cachedBanExemptions.Remove(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.NewStatus != SessionStatus.Connected || _cachedRoleBans.ContainsKey(e.Session.UserId))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var netChannel = e.Session.Channel;
|
||||||
|
ImmutableArray<byte>? hwId = netChannel.UserData.HWId.Length == 0 ? null : netChannel.UserData.HWId;
|
||||||
|
await CacheDbRoleBans(e.Session.UserId, netChannel.RemoteEndPoint.Address, hwId);
|
||||||
|
|
||||||
|
SendRoleBans(e.Session);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<bool> AddRoleBan(ServerRoleBanDef banDef)
|
private async Task<bool> AddRoleBan(ServerRoleBanDef banDef)
|
||||||
{
|
{
|
||||||
banDef = await _db.AddServerRoleBanAsync(banDef);
|
banDef = await _db.AddServerRoleBanAsync(banDef);
|
||||||
|
|
||||||
if (banDef.UserId != null
|
if (banDef.UserId != null)
|
||||||
&& _playerManager.TryGetSessionById(banDef.UserId, out var player)
|
|
||||||
&& _cachedRoleBans.TryGetValue(player, out var cachedBans))
|
|
||||||
{
|
{
|
||||||
cachedBans.Add(banDef);
|
_cachedRoleBans.GetOrNew(banDef.UserId.Value).Add(banDef);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -101,21 +102,31 @@ public sealed partial class BanManager : IBanManager, IPostInjectInit
|
|||||||
|
|
||||||
public HashSet<string>? GetRoleBans(NetUserId playerUserId)
|
public HashSet<string>? GetRoleBans(NetUserId playerUserId)
|
||||||
{
|
{
|
||||||
if (!_playerManager.TryGetSessionById(playerUserId, out var session))
|
return _cachedRoleBans.TryGetValue(playerUserId, out var roleBans)
|
||||||
return null;
|
|
||||||
|
|
||||||
return _cachedRoleBans.TryGetValue(session, out var roleBans)
|
|
||||||
? roleBans.Select(banDef => banDef.Role).ToHashSet()
|
? roleBans.Select(banDef => banDef.Role).ToHashSet()
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task CacheDbRoleBans(NetUserId userId, IPAddress? address = null, ImmutableArray<byte>? hwId = null)
|
||||||
|
{
|
||||||
|
var roleBans = await _db.GetServerRoleBansAsync(address, userId, hwId, false);
|
||||||
|
|
||||||
|
var userRoleBans = new HashSet<ServerRoleBanDef>();
|
||||||
|
foreach (var ban in roleBans)
|
||||||
|
{
|
||||||
|
userRoleBans.Add(ban);
|
||||||
|
}
|
||||||
|
|
||||||
|
_cachedRoleBans[userId] = userRoleBans;
|
||||||
|
}
|
||||||
|
|
||||||
public void Restart()
|
public void Restart()
|
||||||
{
|
{
|
||||||
// Clear out players that have disconnected.
|
// Clear out players that have disconnected.
|
||||||
var toRemove = new ValueList<ICommonSession>();
|
var toRemove = new List<NetUserId>();
|
||||||
foreach (var player in _cachedRoleBans.Keys)
|
foreach (var player in _cachedRoleBans.Keys)
|
||||||
{
|
{
|
||||||
if (player.Status == SessionStatus.Disconnected)
|
if (!_playerManager.TryGetSessionById(player, out _))
|
||||||
toRemove.Add(player);
|
toRemove.Add(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +138,7 @@ public sealed partial class BanManager : IBanManager, IPostInjectInit
|
|||||||
// Check for expired bans
|
// Check for expired bans
|
||||||
foreach (var roleBans in _cachedRoleBans.Values)
|
foreach (var roleBans in _cachedRoleBans.Values)
|
||||||
{
|
{
|
||||||
roleBans.RemoveAll(ban => DateTimeOffset.Now > ban.ExpirationTime);
|
roleBans.RemoveWhere(ban => DateTimeOffset.Now > ban.ExpirationTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,9 +281,9 @@ public sealed partial class BanManager : IBanManager, IPostInjectInit
|
|||||||
var length = expires == null ? Loc.GetString("cmd-roleban-inf") : Loc.GetString("cmd-roleban-until", ("expires", expires));
|
var length = expires == null ? Loc.GetString("cmd-roleban-inf") : Loc.GetString("cmd-roleban-until", ("expires", expires));
|
||||||
_chat.SendAdminAlert(Loc.GetString("cmd-roleban-success", ("target", targetUsername ?? "null"), ("role", role), ("reason", reason), ("length", length)));
|
_chat.SendAdminAlert(Loc.GetString("cmd-roleban-success", ("target", targetUsername ?? "null"), ("role", role), ("reason", reason), ("length", length)));
|
||||||
|
|
||||||
if (target != null && _playerManager.TryGetSessionById(target.Value, out var session))
|
if (target != null)
|
||||||
{
|
{
|
||||||
SendRoleBans(session);
|
SendRoleBans(target.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,12 +311,10 @@ public sealed partial class BanManager : IBanManager, IPostInjectInit
|
|||||||
|
|
||||||
await _db.AddServerRoleUnbanAsync(new ServerRoleUnbanDef(banId, unbanningAdmin, DateTimeOffset.Now));
|
await _db.AddServerRoleUnbanAsync(new ServerRoleUnbanDef(banId, unbanningAdmin, DateTimeOffset.Now));
|
||||||
|
|
||||||
if (ban.UserId is { } player
|
if (ban.UserId is { } player && _cachedRoleBans.TryGetValue(player, out var roleBans))
|
||||||
&& _playerManager.TryGetSessionById(player, out var session)
|
|
||||||
&& _cachedRoleBans.TryGetValue(session, out var roleBans))
|
|
||||||
{
|
{
|
||||||
roleBans.RemoveAll(roleBan => roleBan.Id == ban.Id);
|
roleBans.RemoveWhere(roleBan => roleBan.Id == ban.Id);
|
||||||
SendRoleBans(session);
|
SendRoleBans(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $"Pardoned ban with id {banId}";
|
return $"Pardoned ban with id {banId}";
|
||||||
@@ -313,12 +322,8 @@ public sealed partial class BanManager : IBanManager, IPostInjectInit
|
|||||||
|
|
||||||
public HashSet<ProtoId<JobPrototype>>? GetJobBans(NetUserId playerUserId)
|
public HashSet<ProtoId<JobPrototype>>? GetJobBans(NetUserId playerUserId)
|
||||||
{
|
{
|
||||||
if (!_playerManager.TryGetSessionById(playerUserId, out var session))
|
if (!_cachedRoleBans.TryGetValue(playerUserId, out var roleBans))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (!_cachedRoleBans.TryGetValue(session, out var roleBans))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return roleBans
|
return roleBans
|
||||||
.Where(ban => ban.Role.StartsWith(JobPrefix, StringComparison.Ordinal))
|
.Where(ban => ban.Role.StartsWith(JobPrefix, StringComparison.Ordinal))
|
||||||
.Select(ban => new ProtoId<JobPrototype>(ban.Role[JobPrefix.Length..]))
|
.Select(ban => new ProtoId<JobPrototype>(ban.Role[JobPrefix.Length..]))
|
||||||
@@ -326,9 +331,19 @@ public sealed partial class BanManager : IBanManager, IPostInjectInit
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
public void SendRoleBans(NetUserId userId)
|
||||||
|
{
|
||||||
|
if (!_playerManager.TryGetSessionById(userId, out var player))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SendRoleBans(player);
|
||||||
|
}
|
||||||
|
|
||||||
public void SendRoleBans(ICommonSession pSession)
|
public void SendRoleBans(ICommonSession pSession)
|
||||||
{
|
{
|
||||||
var roleBans = _cachedRoleBans.GetValueOrDefault(pSession) ?? new List<ServerRoleBanDef>();
|
var roleBans = _cachedRoleBans.GetValueOrDefault(pSession.UserId) ?? new HashSet<ServerRoleBanDef>();
|
||||||
var bans = new MsgRoleBans()
|
var bans = new MsgRoleBans()
|
||||||
{
|
{
|
||||||
Bans = roleBans.Select(o => o.Role).ToList()
|
Bans = roleBans.Select(o => o.Role).ToList()
|
||||||
|
|||||||
@@ -47,6 +47,12 @@ public interface IBanManager
|
|||||||
/// <param name="unbanTime">The time at which this role ban was pardoned.</param>
|
/// <param name="unbanTime">The time at which this role ban was pardoned.</param>
|
||||||
public Task<string> PardonRoleBan(int banId, NetUserId? unbanningAdmin, DateTimeOffset unbanTime);
|
public Task<string> PardonRoleBan(int banId, NetUserId? unbanningAdmin, DateTimeOffset unbanTime);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends role bans to the target
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pSession">Player's user ID</param>
|
||||||
|
public void SendRoleBans(NetUserId userId);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends role bans to the target
|
/// Sends role bans to the target
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using Content.Server._CP14.Roles;
|
|
||||||
using Content.Server.Administration.Commands;
|
using Content.Server.Administration.Commands;
|
||||||
using Content.Server.Antag;
|
using Content.Server.Antag;
|
||||||
using Content.Server.GameTicking.Rules.Components;
|
using Content.Server.GameTicking.Rules.Components;
|
||||||
@@ -53,23 +52,6 @@ public sealed partial class AdminVerbSystem
|
|||||||
|
|
||||||
var targetPlayer = targetActor.PlayerSession;
|
var targetPlayer = targetActor.PlayerSession;
|
||||||
|
|
||||||
|
|
||||||
Verb CP14Sociopath = new()
|
|
||||||
{
|
|
||||||
Text = Loc.GetString("cp14-admin-verb-text-make-sociopath"),
|
|
||||||
Category = VerbCategory.Antag,
|
|
||||||
Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/Clothing/Hands/Gloves/Color/black.rsi"),
|
|
||||||
"icon"), //TODO
|
|
||||||
Act = () =>
|
|
||||||
{
|
|
||||||
//_antag.ForceMakeAntag<CP14BanditRoleComponent>(targetPlayer, "CP14Bandit"); //TODO
|
|
||||||
},
|
|
||||||
Impact = LogImpact.High,
|
|
||||||
Message = Loc.GetString("cp14-admin-verb-make-sociopath"),
|
|
||||||
};
|
|
||||||
args.Verbs.Add(CP14Sociopath);
|
|
||||||
|
|
||||||
/* CP14 disable default antags
|
|
||||||
Verb traitor = new()
|
Verb traitor = new()
|
||||||
{
|
{
|
||||||
Text = Loc.GetString("admin-verb-text-make-traitor"),
|
Text = Loc.GetString("admin-verb-text-make-traitor"),
|
||||||
@@ -169,6 +151,5 @@ public sealed partial class AdminVerbSystem
|
|||||||
Message = Loc.GetString("admin-verb-make-thief"),
|
Message = Loc.GetString("admin-verb-make-thief"),
|
||||||
};
|
};
|
||||||
args.Verbs.Add(thief);
|
args.Verbs.Add(thief);
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,10 +95,9 @@ public sealed partial class AdminVerbSystem
|
|||||||
if (HasComp<MapComponent>(args.Target) || HasComp<MapGridComponent>(args.Target))
|
if (HasComp<MapComponent>(args.Target) || HasComp<MapGridComponent>(args.Target))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var explodeName = Loc.GetString("admin-smite-explode-name").ToLowerInvariant();
|
|
||||||
Verb explode = new()
|
Verb explode = new()
|
||||||
{
|
{
|
||||||
Text = explodeName,
|
Text = "admin-smite-explode-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/smite.svg.192dpi.png")),
|
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/smite.svg.192dpi.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -112,14 +111,13 @@ public sealed partial class AdminVerbSystem
|
|||||||
_bodySystem.GibBody(args.Target);
|
_bodySystem.GibBody(args.Target);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", explodeName, Loc.GetString("admin-smite-explode-description")) // we do this so the description tells admins the Text to run it via console.
|
Message = Loc.GetString("admin-smite-explode-description")
|
||||||
};
|
};
|
||||||
args.Verbs.Add(explode);
|
args.Verbs.Add(explode);
|
||||||
|
|
||||||
var chessName = Loc.GetString("admin-smite-chess-dimension-name").ToLowerInvariant();
|
|
||||||
Verb chess = new()
|
Verb chess = new()
|
||||||
{
|
{
|
||||||
Text = chessName,
|
Text = "admin-smite-chess-dimension-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Fun/Tabletop/chessboard.rsi"), "chessboard"),
|
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Fun/Tabletop/chessboard.rsi"), "chessboard"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -139,13 +137,12 @@ public sealed partial class AdminVerbSystem
|
|||||||
xform.WorldRotation = Angle.Zero;
|
xform.WorldRotation = Angle.Zero;
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", chessName, Loc.GetString("admin-smite-chess-dimension-description"))
|
Message = Loc.GetString("admin-smite-chess-dimension-description")
|
||||||
};
|
};
|
||||||
args.Verbs.Add(chess);
|
args.Verbs.Add(chess);
|
||||||
|
|
||||||
if (TryComp<FlammableComponent>(args.Target, out var flammable))
|
if (TryComp<FlammableComponent>(args.Target, out var flammable))
|
||||||
{
|
{
|
||||||
var flamesName = Loc.GetString("admin-smite-set-alight-name").ToLowerInvariant();
|
|
||||||
Verb flames = new()
|
Verb flames = new()
|
||||||
{
|
{
|
||||||
Text = "admin-smite-set-alight-name",
|
Text = "admin-smite-set-alight-name",
|
||||||
@@ -163,15 +160,14 @@ public sealed partial class AdminVerbSystem
|
|||||||
Filter.PvsExcept(args.Target), true, PopupType.MediumCaution);
|
Filter.PvsExcept(args.Target), true, PopupType.MediumCaution);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", flamesName, Loc.GetString("admin-smite-set-alight-description"))
|
Message = Loc.GetString("admin-smite-set-alight-description")
|
||||||
};
|
};
|
||||||
args.Verbs.Add(flames);
|
args.Verbs.Add(flames);
|
||||||
}
|
}
|
||||||
|
|
||||||
var monkeyName = Loc.GetString("admin-smite-monkeyify-name").ToLowerInvariant();
|
|
||||||
Verb monkey = new()
|
Verb monkey = new()
|
||||||
{
|
{
|
||||||
Text = monkeyName,
|
Text = "admin-smite-monkeyify-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Mobs/Animals/monkey.rsi"), "monkey"),
|
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Mobs/Animals/monkey.rsi"), "monkey"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -179,14 +175,13 @@ public sealed partial class AdminVerbSystem
|
|||||||
_polymorphSystem.PolymorphEntity(args.Target, "AdminMonkeySmite");
|
_polymorphSystem.PolymorphEntity(args.Target, "AdminMonkeySmite");
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", monkeyName, Loc.GetString("admin-smite-monkeyify-description"))
|
Message = Loc.GetString("admin-smite-monkeyify-description")
|
||||||
};
|
};
|
||||||
args.Verbs.Add(monkey);
|
args.Verbs.Add(monkey);
|
||||||
|
|
||||||
var disposalBinName = Loc.GetString("admin-smite-garbage-can-name").ToLowerInvariant();
|
|
||||||
Verb disposalBin = new()
|
Verb disposalBin = new()
|
||||||
{
|
{
|
||||||
Text = disposalBinName,
|
Text = "admin-smite-electrocute-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Structures/Piping/disposal.rsi"), "disposal"),
|
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Structures/Piping/disposal.rsi"), "disposal"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -194,17 +189,16 @@ public sealed partial class AdminVerbSystem
|
|||||||
_polymorphSystem.PolymorphEntity(args.Target, "AdminDisposalsSmite");
|
_polymorphSystem.PolymorphEntity(args.Target, "AdminDisposalsSmite");
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", disposalBinName, Loc.GetString("admin-smite-garbage-can-description"))
|
Message = Loc.GetString("admin-smite-garbage-can-description")
|
||||||
};
|
};
|
||||||
args.Verbs.Add(disposalBin);
|
args.Verbs.Add(disposalBin);
|
||||||
|
|
||||||
if (TryComp<DamageableComponent>(args.Target, out var damageable) &&
|
if (TryComp<DamageableComponent>(args.Target, out var damageable) &&
|
||||||
HasComp<MobStateComponent>(args.Target))
|
HasComp<MobStateComponent>(args.Target))
|
||||||
{
|
{
|
||||||
var hardElectrocuteName = Loc.GetString("admin-smite-electrocute-name").ToLowerInvariant();
|
|
||||||
Verb hardElectrocute = new()
|
Verb hardElectrocute = new()
|
||||||
{
|
{
|
||||||
Text = hardElectrocuteName,
|
Text = "admin-smite-creampie-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Clothing/Hands/Gloves/Color/yellow.rsi"), "icon"),
|
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Clothing/Hands/Gloves/Color/yellow.rsi"), "icon"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -240,17 +234,16 @@ public sealed partial class AdminVerbSystem
|
|||||||
TimeSpan.FromSeconds(30), refresh: true, ignoreInsulation: true);
|
TimeSpan.FromSeconds(30), refresh: true, ignoreInsulation: true);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", hardElectrocuteName, Loc.GetString("admin-smite-electrocute-description"))
|
Message = Loc.GetString("admin-smite-electrocute-description")
|
||||||
};
|
};
|
||||||
args.Verbs.Add(hardElectrocute);
|
args.Verbs.Add(hardElectrocute);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryComp<CreamPiedComponent>(args.Target, out var creamPied))
|
if (TryComp<CreamPiedComponent>(args.Target, out var creamPied))
|
||||||
{
|
{
|
||||||
var creamPieName = Loc.GetString("admin-smite-creampie-name").ToLowerInvariant();
|
|
||||||
Verb creamPie = new()
|
Verb creamPie = new()
|
||||||
{
|
{
|
||||||
Text = creamPieName,
|
Text = "admin-smite-remove-blood-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Consumable/Food/Baked/pie.rsi"), "plain-slice"),
|
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Consumable/Food/Baked/pie.rsi"), "plain-slice"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -258,17 +251,16 @@ public sealed partial class AdminVerbSystem
|
|||||||
_creamPieSystem.SetCreamPied(args.Target, creamPied, true);
|
_creamPieSystem.SetCreamPied(args.Target, creamPied, true);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", creamPieName, Loc.GetString("admin-smite-creampie-description"))
|
Message = Loc.GetString("admin-smite-creampie-description")
|
||||||
};
|
};
|
||||||
args.Verbs.Add(creamPie);
|
args.Verbs.Add(creamPie);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryComp<BloodstreamComponent>(args.Target, out var bloodstream))
|
if (TryComp<BloodstreamComponent>(args.Target, out var bloodstream))
|
||||||
{
|
{
|
||||||
var bloodRemovalName = Loc.GetString("admin-smite-remove-blood-name").ToLowerInvariant();
|
|
||||||
Verb bloodRemoval = new()
|
Verb bloodRemoval = new()
|
||||||
{
|
{
|
||||||
Text = bloodRemovalName,
|
Text = "admin-smite-vomit-organs-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Fluids/tomato_splat.rsi"), "puddle-1"),
|
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Fluids/tomato_splat.rsi"), "puddle-1"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -281,7 +273,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
Filter.PvsExcept(args.Target), true, PopupType.MediumCaution);
|
Filter.PvsExcept(args.Target), true, PopupType.MediumCaution);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", bloodRemovalName, Loc.GetString("admin-smite-remove-blood-description"))
|
Message = Loc.GetString("admin-smite-remove-blood-description")
|
||||||
};
|
};
|
||||||
args.Verbs.Add(bloodRemoval);
|
args.Verbs.Add(bloodRemoval);
|
||||||
}
|
}
|
||||||
@@ -289,10 +281,9 @@ public sealed partial class AdminVerbSystem
|
|||||||
// bobby...
|
// bobby...
|
||||||
if (TryComp<BodyComponent>(args.Target, out var body))
|
if (TryComp<BodyComponent>(args.Target, out var body))
|
||||||
{
|
{
|
||||||
var vomitOrgansName = Loc.GetString("admin-smite-vomit-organs-name").ToLowerInvariant();
|
|
||||||
Verb vomitOrgans = new()
|
Verb vomitOrgans = new()
|
||||||
{
|
{
|
||||||
Text = vomitOrgansName,
|
Text = "admin-smite-remove-hands-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Fluids/vomit_toxin.rsi"), "vomit_toxin-1"),
|
Icon = new SpriteSpecifier.Rsi(new("/Textures/Fluids/vomit_toxin.rsi"), "vomit_toxin-1"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -314,14 +305,13 @@ public sealed partial class AdminVerbSystem
|
|||||||
Filter.PvsExcept(args.Target), true, PopupType.MediumCaution);
|
Filter.PvsExcept(args.Target), true, PopupType.MediumCaution);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", vomitOrgansName, Loc.GetString("admin-smite-vomit-organs-description"))
|
Message = Loc.GetString("admin-smite-vomit-organs-description")
|
||||||
};
|
};
|
||||||
args.Verbs.Add(vomitOrgans);
|
args.Verbs.Add(vomitOrgans);
|
||||||
|
|
||||||
var handsRemovalName = Loc.GetString("admin-smite-remove-hands-name").ToLowerInvariant();
|
|
||||||
Verb handsRemoval = new()
|
Verb handsRemoval = new()
|
||||||
{
|
{
|
||||||
Text = handsRemovalName,
|
Text = "admin-smite-remove-hand-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/remove-hands.png")),
|
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/remove-hands.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -337,14 +327,13 @@ public sealed partial class AdminVerbSystem
|
|||||||
Filter.PvsExcept(args.Target), true, PopupType.Medium);
|
Filter.PvsExcept(args.Target), true, PopupType.Medium);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", handsRemovalName, Loc.GetString("admin-smite-remove-hands-description"))
|
Message = Loc.GetString("admin-smite-remove-hands-description")
|
||||||
};
|
};
|
||||||
args.Verbs.Add(handsRemoval);
|
args.Verbs.Add(handsRemoval);
|
||||||
|
|
||||||
var handRemovalName = Loc.GetString("admin-smite-remove-hand-name").ToLowerInvariant();
|
|
||||||
Verb handRemoval = new()
|
Verb handRemoval = new()
|
||||||
{
|
{
|
||||||
Text = handRemovalName,
|
Text = "admin-smite-pinball-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/remove-hand.png")),
|
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/remove-hand.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -361,14 +350,13 @@ public sealed partial class AdminVerbSystem
|
|||||||
Filter.PvsExcept(args.Target), true, PopupType.Medium);
|
Filter.PvsExcept(args.Target), true, PopupType.Medium);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", handRemovalName, Loc.GetString("admin-smite-remove-hand-description"))
|
Message = Loc.GetString("admin-smite-remove-hand-description")
|
||||||
};
|
};
|
||||||
args.Verbs.Add(handRemoval);
|
args.Verbs.Add(handRemoval);
|
||||||
|
|
||||||
var stomachRemovalName = Loc.GetString("admin-smite-stomach-removal-name").ToLowerInvariant();
|
|
||||||
Verb stomachRemoval = new()
|
Verb stomachRemoval = new()
|
||||||
{
|
{
|
||||||
Text = stomachRemovalName,
|
Text = "admin-smite-yeet-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Mobs/Species/Human/organs.rsi"), "stomach"),
|
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Mobs/Species/Human/organs.rsi"), "stomach"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -382,14 +370,13 @@ public sealed partial class AdminVerbSystem
|
|||||||
args.Target, PopupType.LargeCaution);
|
args.Target, PopupType.LargeCaution);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", stomachRemovalName, Loc.GetString("admin-smite-stomach-removal-description"))
|
Message = Loc.GetString("admin-smite-stomach-removal-description"),
|
||||||
};
|
};
|
||||||
args.Verbs.Add(stomachRemoval);
|
args.Verbs.Add(stomachRemoval);
|
||||||
|
|
||||||
var lungRemovalName = Loc.GetString("admin-smite-lung-removal-name").ToLowerInvariant();
|
|
||||||
Verb lungRemoval = new()
|
Verb lungRemoval = new()
|
||||||
{
|
{
|
||||||
Text = lungRemovalName,
|
Text = "admin-smite-become-bread-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Mobs/Species/Human/organs.rsi"), "lung-r"),
|
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Mobs/Species/Human/organs.rsi"), "lung-r"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -403,17 +390,16 @@ public sealed partial class AdminVerbSystem
|
|||||||
args.Target, PopupType.LargeCaution);
|
args.Target, PopupType.LargeCaution);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", lungRemovalName, Loc.GetString("admin-smite-lung-removal-description"))
|
Message = Loc.GetString("admin-smite-lung-removal-description"),
|
||||||
};
|
};
|
||||||
args.Verbs.Add(lungRemoval);
|
args.Verbs.Add(lungRemoval);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryComp<PhysicsComponent>(args.Target, out var physics))
|
if (TryComp<PhysicsComponent>(args.Target, out var physics))
|
||||||
{
|
{
|
||||||
var pinballName = Loc.GetString("admin-smite-pinball-name").ToLowerInvariant();
|
|
||||||
Verb pinball = new()
|
Verb pinball = new()
|
||||||
{
|
{
|
||||||
Text = pinballName,
|
Text = "admin-smite-ghostkick-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Fun/toys.rsi"), "basketball"),
|
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Fun/toys.rsi"), "basketball"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -441,14 +427,13 @@ public sealed partial class AdminVerbSystem
|
|||||||
_physics.SetAngularDamping(args.Target, physics, 0f);
|
_physics.SetAngularDamping(args.Target, physics, 0f);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", pinballName, Loc.GetString("admin-smite-pinball-description"))
|
Message = Loc.GetString("admin-smite-pinball-description")
|
||||||
};
|
};
|
||||||
args.Verbs.Add(pinball);
|
args.Verbs.Add(pinball);
|
||||||
|
|
||||||
var yeetName = Loc.GetString("admin-smite-yeet-name").ToLowerInvariant();
|
|
||||||
Verb yeet = new()
|
Verb yeet = new()
|
||||||
{
|
{
|
||||||
Text = yeetName,
|
Text = "admin-smite-nyanify-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/eject.svg.192dpi.png")),
|
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/eject.svg.192dpi.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -472,12 +457,11 @@ public sealed partial class AdminVerbSystem
|
|||||||
_physics.SetAngularDamping(args.Target, physics, 0f);
|
_physics.SetAngularDamping(args.Target, physics, 0f);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", yeetName, Loc.GetString("admin-smite-yeet-description"))
|
Message = Loc.GetString("admin-smite-yeet-description")
|
||||||
};
|
};
|
||||||
args.Verbs.Add(yeet);
|
args.Verbs.Add(yeet);
|
||||||
}
|
}
|
||||||
|
|
||||||
var breadName = Loc.GetString("admin-smite-become-bread-name").ToLowerInvariant(); // Will I get cancelled for breadName-ing you?
|
|
||||||
Verb bread = new()
|
Verb bread = new()
|
||||||
{
|
{
|
||||||
Text = "admin-smite-kill-sign-name",
|
Text = "admin-smite-kill-sign-name",
|
||||||
@@ -488,11 +472,10 @@ public sealed partial class AdminVerbSystem
|
|||||||
_polymorphSystem.PolymorphEntity(args.Target, "AdminBreadSmite");
|
_polymorphSystem.PolymorphEntity(args.Target, "AdminBreadSmite");
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", breadName, Loc.GetString("admin-smite-become-bread-description"))
|
Message = Loc.GetString("admin-smite-become-bread-description")
|
||||||
};
|
};
|
||||||
args.Verbs.Add(bread);
|
args.Verbs.Add(bread);
|
||||||
|
|
||||||
var mouseName = Loc.GetString("admin-smite-become-mouse-name").ToLowerInvariant();
|
|
||||||
Verb mouse = new()
|
Verb mouse = new()
|
||||||
{
|
{
|
||||||
Text = "admin-smite-cluwne-name",
|
Text = "admin-smite-cluwne-name",
|
||||||
@@ -503,16 +486,15 @@ public sealed partial class AdminVerbSystem
|
|||||||
_polymorphSystem.PolymorphEntity(args.Target, "AdminMouseSmite");
|
_polymorphSystem.PolymorphEntity(args.Target, "AdminMouseSmite");
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", mouseName, Loc.GetString("admin-smite-become-mouse-description"))
|
Message = Loc.GetString("admin-smite-become-mouse-description")
|
||||||
};
|
};
|
||||||
args.Verbs.Add(mouse);
|
args.Verbs.Add(mouse);
|
||||||
|
|
||||||
if (TryComp<ActorComponent>(args.Target, out var actorComponent))
|
if (TryComp<ActorComponent>(args.Target, out var actorComponent))
|
||||||
{
|
{
|
||||||
var ghostKickName = Loc.GetString("admin-smite-ghostkick-name").ToLowerInvariant();
|
|
||||||
Verb ghostKick = new()
|
Verb ghostKick = new()
|
||||||
{
|
{
|
||||||
Text = ghostKickName,
|
Text = "admin-smite-anger-pointing-arrows-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/gavel.svg.192dpi.png")),
|
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/gavel.svg.192dpi.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -520,18 +502,15 @@ public sealed partial class AdminVerbSystem
|
|||||||
_ghostKickManager.DoDisconnect(actorComponent.PlayerSession.Channel, "Smitten.");
|
_ghostKickManager.DoDisconnect(actorComponent.PlayerSession.Channel, "Smitten.");
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", ghostKickName, Loc.GetString("admin-smite-ghostkick-description"))
|
Message = Loc.GetString("admin-smite-ghostkick-description")
|
||||||
|
|
||||||
};
|
};
|
||||||
args.Verbs.Add(ghostKick);
|
args.Verbs.Add(ghostKick);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryComp<InventoryComponent>(args.Target, out var inventory))
|
if (TryComp<InventoryComponent>(args.Target, out var inventory)) {
|
||||||
{
|
|
||||||
var nyanifyName = Loc.GetString("admin-smite-nyanify-name").ToLowerInvariant();
|
|
||||||
Verb nyanify = new()
|
Verb nyanify = new()
|
||||||
{
|
{
|
||||||
Text = nyanifyName,
|
Text = "admin-smite-dust-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Clothing/Head/Hats/catears.rsi"), "icon"),
|
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Clothing/Head/Hats/catears.rsi"), "icon"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -542,14 +521,13 @@ public sealed partial class AdminVerbSystem
|
|||||||
_inventorySystem.TryEquip(args.Target, ears, "head", true, true, false, inventory);
|
_inventorySystem.TryEquip(args.Target, ears, "head", true, true, false, inventory);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", nyanifyName, Loc.GetString("admin-smite-nyanify-description"))
|
Message = Loc.GetString("admin-smite-nyanify-description")
|
||||||
};
|
};
|
||||||
args.Verbs.Add(nyanify);
|
args.Verbs.Add(nyanify);
|
||||||
|
|
||||||
var killSignName = Loc.GetString("admin-smite-kill-sign-name").ToLowerInvariant();
|
|
||||||
Verb killSign = new()
|
Verb killSign = new()
|
||||||
{
|
{
|
||||||
Text = killSignName,
|
Text = "admin-smite-buffering-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Misc/killsign.rsi"), "icon"),
|
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Misc/killsign.rsi"), "icon"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -557,14 +535,13 @@ public sealed partial class AdminVerbSystem
|
|||||||
EnsureComp<KillSignComponent>(args.Target);
|
EnsureComp<KillSignComponent>(args.Target);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", killSignName, Loc.GetString("admin-smite-kill-sign-description"))
|
Message = Loc.GetString("admin-smite-kill-sign-description")
|
||||||
};
|
};
|
||||||
args.Verbs.Add(killSign);
|
args.Verbs.Add(killSign);
|
||||||
|
|
||||||
var cluwneName = Loc.GetString("admin-smite-cluwne-name").ToLowerInvariant();
|
|
||||||
Verb cluwne = new()
|
Verb cluwne = new()
|
||||||
{
|
{
|
||||||
Text = cluwneName,
|
Text = "admin-smite-become-instrument-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
|
|
||||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Clothing/Mask/cluwne.rsi"), "icon"),
|
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Clothing/Mask/cluwne.rsi"), "icon"),
|
||||||
@@ -574,14 +551,13 @@ public sealed partial class AdminVerbSystem
|
|||||||
EnsureComp<CluwneComponent>(args.Target);
|
EnsureComp<CluwneComponent>(args.Target);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", cluwneName, Loc.GetString("admin-smite-cluwne-description"))
|
Message = Loc.GetString("admin-smite-cluwne-description")
|
||||||
};
|
};
|
||||||
args.Verbs.Add(cluwne);
|
args.Verbs.Add(cluwne);
|
||||||
|
|
||||||
var maidenName = Loc.GetString("admin-smite-maid-name").ToLowerInvariant();
|
|
||||||
Verb maiden = new()
|
Verb maiden = new()
|
||||||
{
|
{
|
||||||
Text = maidenName,
|
Text = "admin-smite-remove-gravity-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Clothing/Uniforms/Jumpskirt/janimaid.rsi"), "icon"),
|
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Clothing/Uniforms/Jumpskirt/janimaid.rsi"), "icon"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -594,15 +570,14 @@ public sealed partial class AdminVerbSystem
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", maidenName, Loc.GetString("admin-smite-maid-description"))
|
Message = Loc.GetString("admin-smite-maid-description")
|
||||||
};
|
};
|
||||||
args.Verbs.Add(maiden);
|
args.Verbs.Add(maiden);
|
||||||
}
|
}
|
||||||
|
|
||||||
var angerPointingArrowsName = Loc.GetString("admin-smite-anger-pointing-arrows-name").ToLowerInvariant();
|
|
||||||
Verb angerPointingArrows = new()
|
Verb angerPointingArrows = new()
|
||||||
{
|
{
|
||||||
Text = angerPointingArrowsName,
|
Text = "admin-smite-reptilian-species-swap-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Interface/Misc/pointing.rsi"), "pointing"),
|
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Interface/Misc/pointing.rsi"), "pointing"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -610,14 +585,13 @@ public sealed partial class AdminVerbSystem
|
|||||||
EnsureComp<PointingArrowAngeringComponent>(args.Target);
|
EnsureComp<PointingArrowAngeringComponent>(args.Target);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", angerPointingArrowsName, Loc.GetString("admin-smite-anger-pointing-arrows-description"))
|
Message = Loc.GetString("admin-smite-anger-pointing-arrows-description")
|
||||||
};
|
};
|
||||||
args.Verbs.Add(angerPointingArrows);
|
args.Verbs.Add(angerPointingArrows);
|
||||||
|
|
||||||
var dustName = Loc.GetString("admin-smite-dust-name").ToLowerInvariant();
|
|
||||||
Verb dust = new()
|
Verb dust = new()
|
||||||
{
|
{
|
||||||
Text = dustName,
|
Text = "admin-smite-locker-stuff-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Materials/materials.rsi"), "ash"),
|
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Materials/materials.rsi"), "ash"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -627,14 +601,13 @@ public sealed partial class AdminVerbSystem
|
|||||||
_popupSystem.PopupEntity(Loc.GetString("admin-smite-turned-ash-other", ("name", args.Target)), args.Target, PopupType.LargeCaution);
|
_popupSystem.PopupEntity(Loc.GetString("admin-smite-turned-ash-other", ("name", args.Target)), args.Target, PopupType.LargeCaution);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", dustName, Loc.GetString("admin-smite-dust-description"))
|
Message = Loc.GetString("admin-smite-dust-description"),
|
||||||
};
|
};
|
||||||
args.Verbs.Add(dust);
|
args.Verbs.Add(dust);
|
||||||
|
|
||||||
var youtubeVideoSimulationName = Loc.GetString("admin-smite-buffering-name").ToLowerInvariant();
|
|
||||||
Verb youtubeVideoSimulation = new()
|
Verb youtubeVideoSimulation = new()
|
||||||
{
|
{
|
||||||
Text = youtubeVideoSimulationName,
|
Text = "admin-smite-headstand-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/Misc/buffering_smite_icon.png")),
|
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/Misc/buffering_smite_icon.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -642,11 +615,10 @@ public sealed partial class AdminVerbSystem
|
|||||||
EnsureComp<BufferingComponent>(args.Target);
|
EnsureComp<BufferingComponent>(args.Target);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", youtubeVideoSimulationName, Loc.GetString("admin-smite-buffering-description"))
|
Message = Loc.GetString("admin-smite-buffering-description"),
|
||||||
};
|
};
|
||||||
args.Verbs.Add(youtubeVideoSimulation);
|
args.Verbs.Add(youtubeVideoSimulation);
|
||||||
|
|
||||||
var instrumentationName = Loc.GetString("admin-smite-become-instrument-name").ToLowerInvariant();
|
|
||||||
Verb instrumentation = new()
|
Verb instrumentation = new()
|
||||||
{
|
{
|
||||||
Text = "admin-smite-become-mouse-name",
|
Text = "admin-smite-become-mouse-name",
|
||||||
@@ -657,14 +629,13 @@ public sealed partial class AdminVerbSystem
|
|||||||
_polymorphSystem.PolymorphEntity(args.Target, "AdminInstrumentSmite");
|
_polymorphSystem.PolymorphEntity(args.Target, "AdminInstrumentSmite");
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", instrumentationName, Loc.GetString("admin-smite-become-instrument-description"))
|
Message = Loc.GetString("admin-smite-become-instrument-description"),
|
||||||
};
|
};
|
||||||
args.Verbs.Add(instrumentation);
|
args.Verbs.Add(instrumentation);
|
||||||
|
|
||||||
var noGravityName = Loc.GetString("admin-smite-remove-gravity-name").ToLowerInvariant();
|
|
||||||
Verb noGravity = new()
|
Verb noGravity = new()
|
||||||
{
|
{
|
||||||
Text = noGravityName,
|
Text = "admin-smite-maid-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Structures/Machines/gravity_generator.rsi"), "off"),
|
Icon = new SpriteSpecifier.Rsi(new("/Textures/Structures/Machines/gravity_generator.rsi"), "off"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -675,14 +646,13 @@ public sealed partial class AdminVerbSystem
|
|||||||
Dirty(args.Target, grav);
|
Dirty(args.Target, grav);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", noGravityName, Loc.GetString("admin-smite-remove-gravity-description"))
|
Message = Loc.GetString("admin-smite-remove-gravity-description"),
|
||||||
};
|
};
|
||||||
args.Verbs.Add(noGravity);
|
args.Verbs.Add(noGravity);
|
||||||
|
|
||||||
var reptilianName = Loc.GetString("admin-smite-reptilian-species-swap-name").ToLowerInvariant();
|
|
||||||
Verb reptilian = new()
|
Verb reptilian = new()
|
||||||
{
|
{
|
||||||
Text = reptilianName,
|
Text = "admin-smite-zoom-in-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Fun/toys.rsi"), "plushie_lizard"),
|
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Fun/toys.rsi"), "plushie_lizard"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -690,14 +660,13 @@ public sealed partial class AdminVerbSystem
|
|||||||
_polymorphSystem.PolymorphEntity(args.Target, "AdminLizardSmite");
|
_polymorphSystem.PolymorphEntity(args.Target, "AdminLizardSmite");
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", reptilianName, Loc.GetString("admin-smite-reptilian-species-swap-description"))
|
Message = Loc.GetString("admin-smite-reptilian-species-swap-description"),
|
||||||
};
|
};
|
||||||
args.Verbs.Add(reptilian);
|
args.Verbs.Add(reptilian);
|
||||||
|
|
||||||
var lockerName = Loc.GetString("admin-smite-locker-stuff-name").ToLowerInvariant();
|
|
||||||
Verb locker = new()
|
Verb locker = new()
|
||||||
{
|
{
|
||||||
Text = lockerName,
|
Text = "admin-smite-flip-eye-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Structures/Storage/closet.rsi"), "generic"),
|
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Structures/Storage/closet.rsi"), "generic"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -713,11 +682,10 @@ public sealed partial class AdminVerbSystem
|
|||||||
_weldableSystem.SetWeldedState(locker, true);
|
_weldableSystem.SetWeldedState(locker, true);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", lockerName, Loc.GetString("admin-smite-locker-stuff-description"))
|
Message = Loc.GetString("admin-smite-locker-stuff-description"),
|
||||||
};
|
};
|
||||||
args.Verbs.Add(locker);
|
args.Verbs.Add(locker);
|
||||||
|
|
||||||
var headstandName = Loc.GetString("admin-smite-headstand-name").ToLowerInvariant();
|
|
||||||
Verb headstand = new()
|
Verb headstand = new()
|
||||||
{
|
{
|
||||||
Text = "admin-smite-run-walk-swap-name",
|
Text = "admin-smite-run-walk-swap-name",
|
||||||
@@ -728,14 +696,13 @@ public sealed partial class AdminVerbSystem
|
|||||||
EnsureComp<HeadstandComponent>(args.Target);
|
EnsureComp<HeadstandComponent>(args.Target);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", headstandName, Loc.GetString("admin-smite-headstand-description"))
|
Message = Loc.GetString("admin-smite-headstand-description"),
|
||||||
};
|
};
|
||||||
args.Verbs.Add(headstand);
|
args.Verbs.Add(headstand);
|
||||||
|
|
||||||
var zoomInName = Loc.GetString("admin-smite-zoom-in-name").ToLowerInvariant();
|
|
||||||
Verb zoomIn = new()
|
Verb zoomIn = new()
|
||||||
{
|
{
|
||||||
Text = zoomInName,
|
Text = "admin-smite-super-speed-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/zoom.png")),
|
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/zoom.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -744,14 +711,13 @@ public sealed partial class AdminVerbSystem
|
|||||||
_eyeSystem.SetZoom(args.Target, eye.TargetZoom * 0.2f, ignoreLimits: true);
|
_eyeSystem.SetZoom(args.Target, eye.TargetZoom * 0.2f, ignoreLimits: true);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", zoomInName, Loc.GetString("admin-smite-zoom-in-description"))
|
Message = Loc.GetString("admin-smite-zoom-in-description"),
|
||||||
};
|
};
|
||||||
args.Verbs.Add(zoomIn);
|
args.Verbs.Add(zoomIn);
|
||||||
|
|
||||||
var flipEyeName = Loc.GetString("admin-smite-flip-eye-name").ToLowerInvariant();
|
|
||||||
Verb flipEye = new()
|
Verb flipEye = new()
|
||||||
{
|
{
|
||||||
Text = flipEyeName,
|
Text = "admin-smite-stomach-removal-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/flip.png")),
|
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/flip.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -760,14 +726,13 @@ public sealed partial class AdminVerbSystem
|
|||||||
_eyeSystem.SetZoom(args.Target, eye.TargetZoom * -1, ignoreLimits: true);
|
_eyeSystem.SetZoom(args.Target, eye.TargetZoom * -1, ignoreLimits: true);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", flipEyeName, Loc.GetString("admin-smite-flip-eye-description"))
|
Message = Loc.GetString("admin-smite-flip-eye-description"),
|
||||||
};
|
};
|
||||||
args.Verbs.Add(flipEye);
|
args.Verbs.Add(flipEye);
|
||||||
|
|
||||||
var runWalkSwapName = Loc.GetString("admin-smite-run-walk-swap-name").ToLowerInvariant();
|
|
||||||
Verb runWalkSwap = new()
|
Verb runWalkSwap = new()
|
||||||
{
|
{
|
||||||
Text = runWalkSwapName,
|
Text = "admin-smite-speak-backwards-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/run-walk-swap.png")),
|
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/run-walk-swap.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -781,14 +746,13 @@ public sealed partial class AdminVerbSystem
|
|||||||
args.Target, PopupType.LargeCaution);
|
args.Target, PopupType.LargeCaution);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", runWalkSwapName, Loc.GetString("admin-smite-run-walk-swap-description"))
|
Message = Loc.GetString("admin-smite-run-walk-swap-description"),
|
||||||
};
|
};
|
||||||
args.Verbs.Add(runWalkSwap);
|
args.Verbs.Add(runWalkSwap);
|
||||||
|
|
||||||
var backwardsAccentName = Loc.GetString("admin-smite-speak-backwards-name").ToLowerInvariant();
|
|
||||||
Verb backwardsAccent = new()
|
Verb backwardsAccent = new()
|
||||||
{
|
{
|
||||||
Text = backwardsAccentName,
|
Text = "admin-smite-lung-removal-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/help-backwards.png")),
|
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/help-backwards.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -796,14 +760,13 @@ public sealed partial class AdminVerbSystem
|
|||||||
EnsureComp<BackwardsAccentComponent>(args.Target);
|
EnsureComp<BackwardsAccentComponent>(args.Target);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", backwardsAccentName, Loc.GetString("admin-smite-speak-backwards-description"))
|
Message = Loc.GetString("admin-smite-speak-backwards-description"),
|
||||||
};
|
};
|
||||||
args.Verbs.Add(backwardsAccent);
|
args.Verbs.Add(backwardsAccent);
|
||||||
|
|
||||||
var disarmProneName = Loc.GetString("admin-smite-disarm-prone-name").ToLowerInvariant();
|
|
||||||
Verb disarmProne = new()
|
Verb disarmProne = new()
|
||||||
{
|
{
|
||||||
Text = disarmProneName,
|
Text = "admin-smite-disarm-prone-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/Actions/disarm.png")),
|
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/Actions/disarm.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -811,11 +774,10 @@ public sealed partial class AdminVerbSystem
|
|||||||
EnsureComp<DisarmProneComponent>(args.Target);
|
EnsureComp<DisarmProneComponent>(args.Target);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", disarmProneName, Loc.GetString("admin-smite-disarm-prone-description"))
|
Message = Loc.GetString("admin-smite-disarm-prone-description"),
|
||||||
};
|
};
|
||||||
args.Verbs.Add(disarmProne);
|
args.Verbs.Add(disarmProne);
|
||||||
|
|
||||||
var superSpeedName = Loc.GetString("admin-smite-super-speed-name").ToLowerInvariant();
|
|
||||||
Verb superSpeed = new()
|
Verb superSpeed = new()
|
||||||
{
|
{
|
||||||
Text = "admin-smite-garbage-can-name",
|
Text = "admin-smite-garbage-can-name",
|
||||||
@@ -830,45 +792,41 @@ public sealed partial class AdminVerbSystem
|
|||||||
args.Target, PopupType.LargeCaution);
|
args.Target, PopupType.LargeCaution);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", superSpeedName, Loc.GetString("admin-smite-super-speed-description"))
|
Message = Loc.GetString("admin-smite-super-speed-description"),
|
||||||
};
|
};
|
||||||
args.Verbs.Add(superSpeed);
|
args.Verbs.Add(superSpeed);
|
||||||
|
|
||||||
//Bonk
|
//Bonk
|
||||||
var superBonkLiteName = Loc.GetString("admin-smite-super-bonk-lite-name").ToLowerInvariant();
|
|
||||||
Verb superBonkLite = new()
|
Verb superBonkLite = new()
|
||||||
{
|
{
|
||||||
Text = superBonkLiteName,
|
Text = "admin-smite-super-bonk-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Rsi(new("Structures/Furniture/Tables/glass.rsi"), "full"),
|
Icon = new SpriteSpecifier.Rsi(new("Structures/Furniture/Tables/glass.rsi"), "full"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
{
|
{
|
||||||
_superBonkSystem.StartSuperBonk(args.Target, stopWhenDead: true);
|
_superBonkSystem.StartSuperBonk(args.Target, stopWhenDead: true);
|
||||||
},
|
},
|
||||||
|
Message = Loc.GetString("admin-smite-super-bonk-lite-description"),
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", superBonkLiteName, Loc.GetString("admin-smite-super-bonk-lite-description"))
|
|
||||||
};
|
};
|
||||||
args.Verbs.Add(superBonkLite);
|
args.Verbs.Add(superBonkLite);
|
||||||
|
|
||||||
var superBonkName = Loc.GetString("admin-smite-super-bonk-name").ToLowerInvariant();
|
|
||||||
Verb superBonk= new()
|
Verb superBonk= new()
|
||||||
{
|
{
|
||||||
Text = superBonkName,
|
Text = "admin-smite-super-bonk-lite-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Rsi(new("Structures/Furniture/Tables/generic.rsi"), "full"),
|
Icon = new SpriteSpecifier.Rsi(new("Structures/Furniture/Tables/generic.rsi"), "full"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
{
|
{
|
||||||
_superBonkSystem.StartSuperBonk(args.Target);
|
_superBonkSystem.StartSuperBonk(args.Target);
|
||||||
},
|
},
|
||||||
|
Message = Loc.GetString("admin-smite-super-bonk-description"),
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", superBonkName, Loc.GetString("admin-smite-super-bonk-description"))
|
|
||||||
};
|
};
|
||||||
args.Verbs.Add(superBonk);
|
args.Verbs.Add(superBonk);
|
||||||
|
|
||||||
var superslipName = Loc.GetString("admin-smite-super-slip-name").ToLowerInvariant();
|
|
||||||
Verb superslip = new()
|
Verb superslip = new()
|
||||||
{
|
{
|
||||||
Text = superslipName,
|
Text = "admin-smite-super-slip-name",
|
||||||
Category = VerbCategory.Smite,
|
Category = VerbCategory.Smite,
|
||||||
Icon = new SpriteSpecifier.Rsi(new("Objects/Specific/Janitorial/soap.rsi"), "omega-4"),
|
Icon = new SpriteSpecifier.Rsi(new("Objects/Specific/Janitorial/soap.rsi"), "omega-4"),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
@@ -888,7 +846,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Extreme,
|
Impact = LogImpact.Extreme,
|
||||||
Message = string.Join(": ", superslipName, Loc.GetString("admin-smite-super-slip-description"))
|
Message = Loc.GetString("admin-smite-super-slip-description")
|
||||||
};
|
};
|
||||||
args.Verbs.Add(superslip);
|
args.Verbs.Add(superslip);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
[Dependency] private readonly StationJobsSystem _stationJobsSystem = default!;
|
[Dependency] private readonly StationJobsSystem _stationJobsSystem = default!;
|
||||||
[Dependency] private readonly JointSystem _jointSystem = default!;
|
[Dependency] private readonly JointSystem _jointSystem = default!;
|
||||||
[Dependency] private readonly BatterySystem _batterySystem = default!;
|
[Dependency] private readonly BatterySystem _batterySystem = default!;
|
||||||
|
[Dependency] private readonly SharedTransformSystem _xformSystem = default!;
|
||||||
[Dependency] private readonly MetaDataSystem _metaSystem = default!;
|
[Dependency] private readonly MetaDataSystem _metaSystem = default!;
|
||||||
[Dependency] private readonly GunSystem _gun = default!;
|
[Dependency] private readonly GunSystem _gun = default!;
|
||||||
|
|
||||||
@@ -89,22 +90,22 @@ public sealed partial class AdminVerbSystem
|
|||||||
args.Verbs.Add(bolt);
|
args.Verbs.Add(bolt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryComp<AirlockComponent>(args.Target, out var airlockComp))
|
if (TryComp<AirlockComponent>(args.Target, out var airlock))
|
||||||
{
|
{
|
||||||
Verb emergencyAccess = new()
|
Verb emergencyAccess = new()
|
||||||
{
|
{
|
||||||
Text = airlockComp.EmergencyAccess ? "Emergency Access Off" : "Emergency Access On",
|
Text = airlock.EmergencyAccess ? "Emergency Access Off" : "Emergency Access On",
|
||||||
Category = VerbCategory.Tricks,
|
Category = VerbCategory.Tricks,
|
||||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/emergency_access.png")),
|
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/emergency_access.png")),
|
||||||
Act = () =>
|
Act = () =>
|
||||||
{
|
{
|
||||||
_airlockSystem.SetEmergencyAccess((args.Target, airlockComp), !airlockComp.EmergencyAccess);
|
_airlockSystem.ToggleEmergencyAccess(args.Target, airlock);
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Medium,
|
Impact = LogImpact.Medium,
|
||||||
Message = Loc.GetString(airlockComp.EmergencyAccess
|
Message = Loc.GetString(airlock.EmergencyAccess
|
||||||
? "admin-trick-emergency-access-off-description"
|
? "admin-trick-emergency-access-off-description"
|
||||||
: "admin-trick-emergency-access-on-description"),
|
: "admin-trick-emergency-access-on-description"),
|
||||||
Priority = (int) (airlockComp.EmergencyAccess ? TricksVerbPriorities.EmergencyAccessOff : TricksVerbPriorities.EmergencyAccessOn),
|
Priority = (int) (airlock.EmergencyAccess ? TricksVerbPriorities.EmergencyAccessOff : TricksVerbPriorities.EmergencyAccessOn),
|
||||||
};
|
};
|
||||||
args.Verbs.Add(emergencyAccess);
|
args.Verbs.Add(emergencyAccess);
|
||||||
}
|
}
|
||||||
@@ -326,7 +327,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
Act = () =>
|
Act = () =>
|
||||||
{
|
{
|
||||||
var (mapUid, gridUid) = _adminTestArenaSystem.AssertArenaLoaded(player);
|
var (mapUid, gridUid) = _adminTestArenaSystem.AssertArenaLoaded(player);
|
||||||
_transformSystem.SetCoordinates(args.Target, new EntityCoordinates(gridUid ?? mapUid, Vector2.One));
|
_xformSystem.SetCoordinates(args.Target, new EntityCoordinates(gridUid ?? mapUid, Vector2.One));
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Medium,
|
Impact = LogImpact.Medium,
|
||||||
Message = Loc.GetString("admin-trick-send-to-test-arena-description"),
|
Message = Loc.GetString("admin-trick-send-to-test-arena-description"),
|
||||||
@@ -532,7 +533,7 @@ public sealed partial class AdminVerbSystem
|
|||||||
if (shuttle is null)
|
if (shuttle is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_transformSystem.SetCoordinates(args.User, new EntityCoordinates(shuttle.Value, Vector2.Zero));
|
_xformSystem.SetCoordinates(args.User, new EntityCoordinates(shuttle.Value, Vector2.Zero));
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Low,
|
Impact = LogImpact.Low,
|
||||||
Message = Loc.GetString("admin-trick-locate-cargo-shuttle-description"),
|
Message = Loc.GetString("admin-trick-locate-cargo-shuttle-description"),
|
||||||
|
|||||||
@@ -35,10 +35,10 @@ using Robust.Shared.Toolshed;
|
|||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Silicons.Laws;
|
using Content.Server.Silicons.Laws;
|
||||||
using Content.Shared.Movement.Components;
|
using Content.Shared.Silicons.Laws;
|
||||||
using Content.Shared.Silicons.Laws.Components;
|
using Content.Shared.Silicons.Laws.Components;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Content.Shared.Silicons.StationAi;
|
using Content.Shared.Mind;
|
||||||
using Robust.Shared.Physics.Components;
|
using Robust.Shared.Physics.Components;
|
||||||
using static Content.Shared.Configurable.ConfigurationComponent;
|
using static Content.Shared.Configurable.ConfigurationComponent;
|
||||||
|
|
||||||
@@ -63,6 +63,7 @@ namespace Content.Server.Administration.Systems
|
|||||||
[Dependency] private readonly ArtifactSystem _artifactSystem = default!;
|
[Dependency] private readonly ArtifactSystem _artifactSystem = default!;
|
||||||
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
|
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
|
||||||
[Dependency] private readonly PrayerSystem _prayerSystem = default!;
|
[Dependency] private readonly PrayerSystem _prayerSystem = default!;
|
||||||
|
[Dependency] private readonly EuiManager _eui = default!;
|
||||||
[Dependency] private readonly MindSystem _mindSystem = default!;
|
[Dependency] private readonly MindSystem _mindSystem = default!;
|
||||||
[Dependency] private readonly ToolshedManager _toolshed = default!;
|
[Dependency] private readonly ToolshedManager _toolshed = default!;
|
||||||
[Dependency] private readonly RejuvenateSystem _rejuvenate = default!;
|
[Dependency] private readonly RejuvenateSystem _rejuvenate = default!;
|
||||||
@@ -293,7 +294,7 @@ namespace Content.Server.Administration.Systems
|
|||||||
Act = () =>
|
Act = () =>
|
||||||
{
|
{
|
||||||
var ui = new AdminLogsEui();
|
var ui = new AdminLogsEui();
|
||||||
_euiManager.OpenEui(ui, player);
|
_eui.OpenEui(ui, player);
|
||||||
ui.SetLogFilter(search:args.Target.Id.ToString());
|
ui.SetLogFilter(search:args.Target.Id.ToString());
|
||||||
},
|
},
|
||||||
Impact = LogImpact.Low
|
Impact = LogImpact.Low
|
||||||
@@ -347,30 +348,7 @@ namespace Content.Server.Administration.Systems
|
|||||||
Impact = LogImpact.Low
|
Impact = LogImpact.Low
|
||||||
});
|
});
|
||||||
|
|
||||||
// This logic is needed to be able to modify the AI's laws through its core and eye.
|
if (TryComp<SiliconLawBoundComponent>(args.Target, out var lawBoundComponent))
|
||||||
EntityUid? target = null;
|
|
||||||
SiliconLawBoundComponent? lawBoundComponent = null;
|
|
||||||
|
|
||||||
if (TryComp(args.Target, out lawBoundComponent))
|
|
||||||
{
|
|
||||||
target = args.Target;
|
|
||||||
}
|
|
||||||
// When inspecting the core we can find the entity with its laws by looking at the AiHolderComponent.
|
|
||||||
else if (TryComp<StationAiHolderComponent>(args.Target, out var holder) && holder.Slot.Item != null
|
|
||||||
&& TryComp(holder.Slot.Item, out lawBoundComponent))
|
|
||||||
{
|
|
||||||
target = holder.Slot.Item.Value;
|
|
||||||
// For the eye we can find the entity with its laws as the source of the movement relay since the eye
|
|
||||||
// is just a proxy for it to move around and look around the station.
|
|
||||||
}
|
|
||||||
else if (TryComp<MovementRelayTargetComponent>(args.Target, out var relay)
|
|
||||||
&& TryComp(relay.Source, out lawBoundComponent))
|
|
||||||
{
|
|
||||||
target = relay.Source;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lawBoundComponent != null && target != null)
|
|
||||||
{
|
{
|
||||||
args.Verbs.Add(new Verb()
|
args.Verbs.Add(new Verb()
|
||||||
{
|
{
|
||||||
@@ -384,7 +362,7 @@ namespace Content.Server.Administration.Systems
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_euiManager.OpenEui(ui, session);
|
_euiManager.OpenEui(ui, session);
|
||||||
ui.UpdateLaws(lawBoundComponent, target.Value);
|
ui.UpdateLaws(lawBoundComponent, args.Target);
|
||||||
},
|
},
|
||||||
Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/Interface/Actions/actions_borg.rsi"), "state-laws"),
|
Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/Interface/Actions/actions_borg.rsi"), "state-laws"),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ using Content.Shared.Administration;
|
|||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
using Content.Shared.Mind;
|
using Content.Shared.Mind;
|
||||||
using Content.Shared.Players.RateLimiting;
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared;
|
using Robust.Shared;
|
||||||
@@ -47,23 +46,20 @@ namespace Content.Server.Administration.Systems
|
|||||||
[GeneratedRegex(@"^https://discord\.com/api/webhooks/(\d+)/((?!.*/).*)$")]
|
[GeneratedRegex(@"^https://discord\.com/api/webhooks/(\d+)/((?!.*/).*)$")]
|
||||||
private static partial Regex DiscordRegex();
|
private static partial Regex DiscordRegex();
|
||||||
|
|
||||||
private string _webhookUrl = string.Empty;
|
|
||||||
private WebhookData? _webhookData;
|
|
||||||
|
|
||||||
private string _onCallUrl = string.Empty;
|
|
||||||
private WebhookData? _onCallData;
|
|
||||||
|
|
||||||
private ISawmill _sawmill = default!;
|
private ISawmill _sawmill = default!;
|
||||||
private readonly HttpClient _httpClient = new();
|
private readonly HttpClient _httpClient = new();
|
||||||
|
private string _webhookUrl = string.Empty;
|
||||||
|
private WebhookData? _webhookData;
|
||||||
private string _footerIconUrl = string.Empty;
|
private string _footerIconUrl = string.Empty;
|
||||||
private string _avatarUrl = string.Empty;
|
private string _avatarUrl = string.Empty;
|
||||||
private string _serverName = string.Empty;
|
private string _serverName = string.Empty;
|
||||||
|
|
||||||
private readonly Dictionary<NetUserId, DiscordRelayInteraction> _relayMessages = new();
|
private readonly
|
||||||
|
Dictionary<NetUserId, (string? id, string username, string description, string? characterName, GameRunLevel
|
||||||
|
lastRunLevel)> _relayMessages = new();
|
||||||
|
|
||||||
private Dictionary<NetUserId, string> _oldMessageIds = new();
|
private Dictionary<NetUserId, string> _oldMessageIds = new();
|
||||||
private readonly Dictionary<NetUserId, Queue<DiscordRelayedData>> _messageQueues = new();
|
private readonly Dictionary<NetUserId, Queue<string>> _messageQueues = new();
|
||||||
private readonly HashSet<NetUserId> _processingChannels = new();
|
private readonly HashSet<NetUserId> _processingChannels = new();
|
||||||
private readonly Dictionary<NetUserId, (TimeSpan Timestamp, bool Typing)> _typingUpdateTimestamps = new();
|
private readonly Dictionary<NetUserId, (TimeSpan Timestamp, bool Typing)> _typingUpdateTimestamps = new();
|
||||||
private string _overrideClientName = string.Empty;
|
private string _overrideClientName = string.Empty;
|
||||||
@@ -85,16 +81,12 @@ namespace Content.Server.Administration.Systems
|
|||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
Subs.CVar(_config, CCVars.DiscordOnCallWebhook, OnCallChanged, true);
|
|
||||||
|
|
||||||
Subs.CVar(_config, CCVars.DiscordAHelpWebhook, OnWebhookChanged, true);
|
Subs.CVar(_config, CCVars.DiscordAHelpWebhook, OnWebhookChanged, true);
|
||||||
Subs.CVar(_config, CCVars.DiscordAHelpFooterIcon, OnFooterIconChanged, true);
|
Subs.CVar(_config, CCVars.DiscordAHelpFooterIcon, OnFooterIconChanged, true);
|
||||||
Subs.CVar(_config, CCVars.DiscordAHelpAvatar, OnAvatarChanged, true);
|
Subs.CVar(_config, CCVars.DiscordAHelpAvatar, OnAvatarChanged, true);
|
||||||
Subs.CVar(_config, CVars.GameHostName, OnServerNameChanged, true);
|
Subs.CVar(_config, CVars.GameHostName, OnServerNameChanged, true);
|
||||||
Subs.CVar(_config, CCVars.AdminAhelpOverrideClientName, OnOverrideChanged, true);
|
Subs.CVar(_config, CCVars.AdminAhelpOverrideClientName, OnOverrideChanged, true);
|
||||||
_sawmill = IoCManager.Resolve<ILogManager>().GetSawmill("AHELP");
|
_sawmill = IoCManager.Resolve<ILogManager>().GetSawmill("AHELP");
|
||||||
|
|
||||||
var defaultParams = new AHelpMessageParams(
|
var defaultParams = new AHelpMessageParams(
|
||||||
string.Empty,
|
string.Empty,
|
||||||
string.Empty,
|
string.Empty,
|
||||||
@@ -103,7 +95,7 @@ namespace Content.Server.Administration.Systems
|
|||||||
_gameTicker.RunLevel,
|
_gameTicker.RunLevel,
|
||||||
playedSound: false
|
playedSound: false
|
||||||
);
|
);
|
||||||
_maxAdditionalChars = GenerateAHelpMessage(defaultParams).Message.Length;
|
_maxAdditionalChars = GenerateAHelpMessage(defaultParams).Length;
|
||||||
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
|
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
|
||||||
|
|
||||||
SubscribeLocalEvent<GameRunLevelChangedEvent>(OnGameRunLevelChanged);
|
SubscribeLocalEvent<GameRunLevelChangedEvent>(OnGameRunLevelChanged);
|
||||||
@@ -112,37 +104,12 @@ namespace Content.Server.Administration.Systems
|
|||||||
|
|
||||||
_rateLimit.Register(
|
_rateLimit.Register(
|
||||||
RateLimitKey,
|
RateLimitKey,
|
||||||
new RateLimitRegistration(CCVars.AhelpRateLimitPeriod,
|
new RateLimitRegistration
|
||||||
CCVars.AhelpRateLimitCount,
|
{
|
||||||
PlayerRateLimitedAction)
|
CVarLimitPeriodLength = CCVars.AhelpRateLimitPeriod,
|
||||||
);
|
CVarLimitCount = CCVars.AhelpRateLimitCount,
|
||||||
}
|
PlayerLimitedAction = PlayerRateLimitedAction
|
||||||
|
});
|
||||||
private async void OnCallChanged(string url)
|
|
||||||
{
|
|
||||||
_onCallUrl = url;
|
|
||||||
|
|
||||||
if (url == string.Empty)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var match = DiscordRegex().Match(url);
|
|
||||||
|
|
||||||
if (!match.Success)
|
|
||||||
{
|
|
||||||
Log.Error("On call URL does not appear to be valid.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (match.Groups.Count <= 2)
|
|
||||||
{
|
|
||||||
Log.Error("Could not get webhook ID or token for on call URL.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var webhookId = match.Groups[1].Value;
|
|
||||||
var webhookToken = match.Groups[2].Value;
|
|
||||||
|
|
||||||
_onCallData = await GetWebhookData(webhookId, webhookToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PlayerRateLimitedAction(ICommonSession obj)
|
private void PlayerRateLimitedAction(ICommonSession obj)
|
||||||
@@ -293,13 +260,13 @@ namespace Content.Server.Administration.Systems
|
|||||||
|
|
||||||
// Store the Discord message IDs of the previous round
|
// Store the Discord message IDs of the previous round
|
||||||
_oldMessageIds = new Dictionary<NetUserId, string>();
|
_oldMessageIds = new Dictionary<NetUserId, string>();
|
||||||
foreach (var (user, interaction) in _relayMessages)
|
foreach (var message in _relayMessages)
|
||||||
{
|
{
|
||||||
var id = interaction.Id;
|
var id = message.Value.id;
|
||||||
if (id == null)
|
if (id == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_oldMessageIds[user] = id;
|
_oldMessageIds[message.Key] = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
_relayMessages.Clear();
|
_relayMessages.Clear();
|
||||||
@@ -364,10 +331,10 @@ namespace Content.Server.Administration.Systems
|
|||||||
var webhookToken = match.Groups[2].Value;
|
var webhookToken = match.Groups[2].Value;
|
||||||
|
|
||||||
// Fire and forget
|
// Fire and forget
|
||||||
_webhookData = await GetWebhookData(webhookId, webhookToken);
|
await SetWebhookData(webhookId, webhookToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<WebhookData?> GetWebhookData(string id, string token)
|
private async Task SetWebhookData(string id, string token)
|
||||||
{
|
{
|
||||||
var response = await _httpClient.GetAsync($"https://discord.com/api/v10/webhooks/{id}/{token}");
|
var response = await _httpClient.GetAsync($"https://discord.com/api/v10/webhooks/{id}/{token}");
|
||||||
|
|
||||||
@@ -376,10 +343,10 @@ namespace Content.Server.Administration.Systems
|
|||||||
{
|
{
|
||||||
_sawmill.Log(LogLevel.Error,
|
_sawmill.Log(LogLevel.Error,
|
||||||
$"Discord returned bad status code when trying to get webhook data (perhaps the webhook URL is invalid?): {response.StatusCode}\nResponse: {content}");
|
$"Discord returned bad status code when trying to get webhook data (perhaps the webhook URL is invalid?): {response.StatusCode}\nResponse: {content}");
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return JsonSerializer.Deserialize<WebhookData>(content);
|
_webhookData = JsonSerializer.Deserialize<WebhookData>(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnFooterIconChanged(string url)
|
private void OnFooterIconChanged(string url)
|
||||||
@@ -392,14 +359,14 @@ namespace Content.Server.Administration.Systems
|
|||||||
_avatarUrl = url;
|
_avatarUrl = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void ProcessQueue(NetUserId userId, Queue<DiscordRelayedData> messages)
|
private async void ProcessQueue(NetUserId userId, Queue<string> messages)
|
||||||
{
|
{
|
||||||
// Whether an embed already exists for this player
|
// Whether an embed already exists for this player
|
||||||
var exists = _relayMessages.TryGetValue(userId, out var existingEmbed);
|
var exists = _relayMessages.TryGetValue(userId, out var existingEmbed);
|
||||||
|
|
||||||
// Whether the message will become too long after adding these new messages
|
// Whether the message will become too long after adding these new messages
|
||||||
var tooLong = exists && messages.Sum(msg => Math.Min(msg.Message.Length, MessageLengthCap) + "\n".Length)
|
var tooLong = exists && messages.Sum(msg => Math.Min(msg.Length, MessageLengthCap) + "\n".Length)
|
||||||
+ existingEmbed?.Description.Length > DescriptionMax;
|
+ existingEmbed.description.Length > DescriptionMax;
|
||||||
|
|
||||||
// If there is no existing embed, or it is getting too long, we create a new embed
|
// If there is no existing embed, or it is getting too long, we create a new embed
|
||||||
if (!exists || tooLong)
|
if (!exists || tooLong)
|
||||||
@@ -419,10 +386,10 @@ namespace Content.Server.Administration.Systems
|
|||||||
// If we have all the data required, we can link to the embed of the previous round or embed that was too long
|
// If we have all the data required, we can link to the embed of the previous round or embed that was too long
|
||||||
if (_webhookData is { GuildId: { } guildId, ChannelId: { } channelId })
|
if (_webhookData is { GuildId: { } guildId, ChannelId: { } channelId })
|
||||||
{
|
{
|
||||||
if (tooLong && existingEmbed?.Id != null)
|
if (tooLong && existingEmbed.id != null)
|
||||||
{
|
{
|
||||||
linkToPrevious =
|
linkToPrevious =
|
||||||
$"**[Go to previous embed of this round](https://discord.com/channels/{guildId}/{channelId}/{existingEmbed.Id})**\n";
|
$"**[Go to previous embed of this round](https://discord.com/channels/{guildId}/{channelId}/{existingEmbed.id})**\n";
|
||||||
}
|
}
|
||||||
else if (_oldMessageIds.TryGetValue(userId, out var id) && !string.IsNullOrEmpty(id))
|
else if (_oldMessageIds.TryGetValue(userId, out var id) && !string.IsNullOrEmpty(id))
|
||||||
{
|
{
|
||||||
@@ -432,22 +399,13 @@ namespace Content.Server.Administration.Systems
|
|||||||
}
|
}
|
||||||
|
|
||||||
var characterName = _minds.GetCharacterName(userId);
|
var characterName = _minds.GetCharacterName(userId);
|
||||||
existingEmbed = new DiscordRelayInteraction()
|
existingEmbed = (null, lookup.Username, linkToPrevious, characterName, _gameTicker.RunLevel);
|
||||||
{
|
|
||||||
Id = null,
|
|
||||||
CharacterName = characterName,
|
|
||||||
Description = linkToPrevious,
|
|
||||||
Username = lookup.Username,
|
|
||||||
LastRunLevel = _gameTicker.RunLevel,
|
|
||||||
};
|
|
||||||
|
|
||||||
_relayMessages[userId] = existingEmbed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Previous message was in another RunLevel, so show that in the embed
|
// Previous message was in another RunLevel, so show that in the embed
|
||||||
if (existingEmbed!.LastRunLevel != _gameTicker.RunLevel)
|
if (existingEmbed.lastRunLevel != _gameTicker.RunLevel)
|
||||||
{
|
{
|
||||||
existingEmbed.Description += _gameTicker.RunLevel switch
|
existingEmbed.description += _gameTicker.RunLevel switch
|
||||||
{
|
{
|
||||||
GameRunLevel.PreRoundLobby => "\n\n:arrow_forward: _**Pre-round lobby started**_\n",
|
GameRunLevel.PreRoundLobby => "\n\n:arrow_forward: _**Pre-round lobby started**_\n",
|
||||||
GameRunLevel.InRound => "\n\n:arrow_forward: _**Round started**_\n",
|
GameRunLevel.InRound => "\n\n:arrow_forward: _**Round started**_\n",
|
||||||
@@ -456,35 +414,26 @@ namespace Content.Server.Administration.Systems
|
|||||||
$"{_gameTicker.RunLevel} was not matched."),
|
$"{_gameTicker.RunLevel} was not matched."),
|
||||||
};
|
};
|
||||||
|
|
||||||
existingEmbed.LastRunLevel = _gameTicker.RunLevel;
|
existingEmbed.lastRunLevel = _gameTicker.RunLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If last message of the new batch is SOS then relay it to on-call.
|
|
||||||
// ... as long as it hasn't been relayed already.
|
|
||||||
var discordMention = messages.Last();
|
|
||||||
var onCallRelay = !discordMention.Receivers && !existingEmbed.OnCall;
|
|
||||||
|
|
||||||
// Add available messages to the embed description
|
// Add available messages to the embed description
|
||||||
while (messages.TryDequeue(out var message))
|
while (messages.TryDequeue(out var message))
|
||||||
{
|
{
|
||||||
string text;
|
|
||||||
|
|
||||||
// In case someone thinks they're funny
|
// In case someone thinks they're funny
|
||||||
if (message.Message.Length > MessageLengthCap)
|
if (message.Length > MessageLengthCap)
|
||||||
text = message.Message[..(MessageLengthCap - TooLongText.Length)] + TooLongText;
|
message = message[..(MessageLengthCap - TooLongText.Length)] + TooLongText;
|
||||||
else
|
|
||||||
text = message.Message;
|
|
||||||
|
|
||||||
existingEmbed.Description += $"\n{text}";
|
existingEmbed.description += $"\n{message}";
|
||||||
}
|
}
|
||||||
|
|
||||||
var payload = GeneratePayload(existingEmbed.Description,
|
var payload = GeneratePayload(existingEmbed.description,
|
||||||
existingEmbed.Username,
|
existingEmbed.username,
|
||||||
existingEmbed.CharacterName);
|
existingEmbed.characterName);
|
||||||
|
|
||||||
// If there is no existing embed, create a new one
|
// If there is no existing embed, create a new one
|
||||||
// Otherwise patch (edit) it
|
// Otherwise patch (edit) it
|
||||||
if (existingEmbed.Id == null)
|
if (existingEmbed.id == null)
|
||||||
{
|
{
|
||||||
var request = await _httpClient.PostAsync($"{_webhookUrl}?wait=true",
|
var request = await _httpClient.PostAsync($"{_webhookUrl}?wait=true",
|
||||||
new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json"));
|
new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json"));
|
||||||
@@ -507,11 +456,11 @@ namespace Content.Server.Administration.Systems
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
existingEmbed.Id = id.ToString();
|
existingEmbed.id = id.ToString();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var request = await _httpClient.PatchAsync($"{_webhookUrl}/messages/{existingEmbed.Id}",
|
var request = await _httpClient.PatchAsync($"{_webhookUrl}/messages/{existingEmbed.id}",
|
||||||
new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json"));
|
new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json"));
|
||||||
|
|
||||||
if (!request.IsSuccessStatusCode)
|
if (!request.IsSuccessStatusCode)
|
||||||
@@ -526,43 +475,6 @@ namespace Content.Server.Administration.Systems
|
|||||||
|
|
||||||
_relayMessages[userId] = existingEmbed;
|
_relayMessages[userId] = existingEmbed;
|
||||||
|
|
||||||
// Actually do the on call relay last, we just need to grab it before we dequeue every message above.
|
|
||||||
if (onCallRelay &&
|
|
||||||
_onCallData != null)
|
|
||||||
{
|
|
||||||
existingEmbed.OnCall = true;
|
|
||||||
var roleMention = _config.GetCVar(CCVars.DiscordAhelpMention);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(roleMention))
|
|
||||||
{
|
|
||||||
var message = new StringBuilder();
|
|
||||||
message.AppendLine($"<@&{roleMention}>");
|
|
||||||
message.AppendLine("Unanswered SOS");
|
|
||||||
|
|
||||||
// Need webhook data to get the correct link for that channel rather than on-call data.
|
|
||||||
if (_webhookData is { GuildId: { } guildId, ChannelId: { } channelId })
|
|
||||||
{
|
|
||||||
message.AppendLine(
|
|
||||||
$"**[Go to ahelp](https://discord.com/channels/{guildId}/{channelId}/{existingEmbed.Id})**");
|
|
||||||
}
|
|
||||||
|
|
||||||
payload = GeneratePayload(message.ToString(), existingEmbed.Username, existingEmbed.CharacterName);
|
|
||||||
|
|
||||||
var request = await _httpClient.PostAsync($"{_onCallUrl}?wait=true",
|
|
||||||
new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json"));
|
|
||||||
|
|
||||||
var content = await request.Content.ReadAsStringAsync();
|
|
||||||
if (!request.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
_sawmill.Log(LogLevel.Error, $"Discord returned bad status code when posting relay message (perhaps the message is too long?): {request.StatusCode}\nResponse: {content}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
existingEmbed.OnCall = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_processingChannels.Remove(userId);
|
_processingChannels.Remove(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -741,7 +653,7 @@ namespace Content.Server.Administration.Systems
|
|||||||
if (sendsWebhook)
|
if (sendsWebhook)
|
||||||
{
|
{
|
||||||
if (!_messageQueues.ContainsKey(msg.UserId))
|
if (!_messageQueues.ContainsKey(msg.UserId))
|
||||||
_messageQueues[msg.UserId] = new Queue<DiscordRelayedData>();
|
_messageQueues[msg.UserId] = new Queue<string>();
|
||||||
|
|
||||||
var str = message.Text;
|
var str = message.Text;
|
||||||
var unameLength = senderSession.Name.Length;
|
var unameLength = senderSession.Name.Length;
|
||||||
@@ -790,7 +702,7 @@ namespace Content.Server.Administration.Systems
|
|||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DiscordRelayedData GenerateAHelpMessage(AHelpMessageParams parameters)
|
private static string GenerateAHelpMessage(AHelpMessageParams parameters)
|
||||||
{
|
{
|
||||||
var stringbuilder = new StringBuilder();
|
var stringbuilder = new StringBuilder();
|
||||||
|
|
||||||
@@ -807,57 +719,13 @@ namespace Content.Server.Administration.Systems
|
|||||||
stringbuilder.Append($" **{parameters.RoundTime}**");
|
stringbuilder.Append($" **{parameters.RoundTime}**");
|
||||||
if (!parameters.PlayedSound)
|
if (!parameters.PlayedSound)
|
||||||
stringbuilder.Append(" **(S)**");
|
stringbuilder.Append(" **(S)**");
|
||||||
|
|
||||||
if (parameters.Icon == null)
|
if (parameters.Icon == null)
|
||||||
stringbuilder.Append($" **{parameters.Username}:** ");
|
stringbuilder.Append($" **{parameters.Username}:** ");
|
||||||
else
|
else
|
||||||
stringbuilder.Append($" **{parameters.Username}** ");
|
stringbuilder.Append($" **{parameters.Username}** ");
|
||||||
stringbuilder.Append(parameters.Message);
|
stringbuilder.Append(parameters.Message);
|
||||||
|
return stringbuilder.ToString();
|
||||||
return new DiscordRelayedData()
|
|
||||||
{
|
|
||||||
Receivers = !parameters.NoReceivers,
|
|
||||||
Message = stringbuilder.ToString(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private record struct DiscordRelayedData
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Was anyone online to receive it.
|
|
||||||
/// </summary>
|
|
||||||
public bool Receivers;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// What's the payload to send to discord.
|
|
||||||
/// </summary>
|
|
||||||
public string Message;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Class specifically for holding information regarding existing Discord embeds
|
|
||||||
/// </summary>
|
|
||||||
private sealed class DiscordRelayInteraction
|
|
||||||
{
|
|
||||||
public string? Id;
|
|
||||||
|
|
||||||
public string Username = String.Empty;
|
|
||||||
|
|
||||||
public string? CharacterName;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Contents for the discord message.
|
|
||||||
/// </summary>
|
|
||||||
public string Description = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Run level of the last interaction. If different we'll link to the last Id.
|
|
||||||
/// </summary>
|
|
||||||
public GameRunLevel LastRunLevel;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Did we relay this interaction to OnCall previously.
|
|
||||||
/// </summary>
|
|
||||||
public bool OnCall;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ public sealed partial class AmeControllerComponent : SharedAmeControllerComponen
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("injectSound")]
|
[DataField("injectSound")]
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
public SoundSpecifier InjectSound = new SoundPathSpecifier("/Audio/Machines/ame_fuelinjection.ogg");
|
public SoundSpecifier InjectSound = new SoundCollectionSpecifier("MetalThud");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The last time this could have injected fuel into the AME.
|
/// The last time this could have injected fuel into the AME.
|
||||||
|
|||||||
@@ -22,17 +22,11 @@ public sealed class TechAnomalySystem : EntitySystem
|
|||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<TechAnomalyComponent, MapInitEvent>(OnTechMapInit);
|
|
||||||
SubscribeLocalEvent<TechAnomalyComponent, AnomalyPulseEvent>(OnPulse);
|
SubscribeLocalEvent<TechAnomalyComponent, AnomalyPulseEvent>(OnPulse);
|
||||||
SubscribeLocalEvent<TechAnomalyComponent, AnomalySupercriticalEvent>(OnSupercritical);
|
SubscribeLocalEvent<TechAnomalyComponent, AnomalySupercriticalEvent>(OnSupercritical);
|
||||||
SubscribeLocalEvent<TechAnomalyComponent, AnomalyStabilityChangedEvent>(OnStabilityChanged);
|
SubscribeLocalEvent<TechAnomalyComponent, AnomalyStabilityChangedEvent>(OnStabilityChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTechMapInit(Entity<TechAnomalyComponent> ent, ref MapInitEvent args)
|
|
||||||
{
|
|
||||||
ent.Comp.NextTimer = _timing.CurTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
public override void Update(float frameTime)
|
||||||
{
|
{
|
||||||
base.Update(frameTime);
|
base.Update(frameTime);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ using Content.Server.Preferences.Managers;
|
|||||||
using Content.Server.Roles;
|
using Content.Server.Roles;
|
||||||
using Content.Server.Roles.Jobs;
|
using Content.Server.Roles.Jobs;
|
||||||
using Content.Server.Shuttles.Components;
|
using Content.Server.Shuttles.Components;
|
||||||
|
using Content.Server.Station.Systems;
|
||||||
using Content.Shared.Antag;
|
using Content.Shared.Antag;
|
||||||
using Content.Shared.Clothing;
|
using Content.Shared.Clothing;
|
||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
@@ -19,6 +20,7 @@ using Content.Shared.Ghost;
|
|||||||
using Content.Shared.Humanoid;
|
using Content.Shared.Humanoid;
|
||||||
using Content.Shared.Mind;
|
using Content.Shared.Mind;
|
||||||
using Content.Shared.Players;
|
using Content.Shared.Players;
|
||||||
|
using Content.Shared.Preferences.Loadouts;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using Content.Shared.Whitelist;
|
using Content.Shared.Whitelist;
|
||||||
using Robust.Server.Audio;
|
using Robust.Server.Audio;
|
||||||
@@ -35,14 +37,14 @@ namespace Content.Server.Antag;
|
|||||||
|
|
||||||
public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelectionComponent>
|
public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelectionComponent>
|
||||||
{
|
{
|
||||||
[Dependency] private readonly AudioSystem _audio = default!;
|
|
||||||
[Dependency] private readonly IChatManager _chat = default!;
|
[Dependency] private readonly IChatManager _chat = default!;
|
||||||
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
|
[Dependency] private readonly IServerPreferencesManager _pref = default!;
|
||||||
|
[Dependency] private readonly AudioSystem _audio = default!;
|
||||||
[Dependency] private readonly GhostRoleSystem _ghostRole = default!;
|
[Dependency] private readonly GhostRoleSystem _ghostRole = default!;
|
||||||
[Dependency] private readonly JobSystem _jobs = default!;
|
[Dependency] private readonly JobSystem _jobs = default!;
|
||||||
[Dependency] private readonly LoadoutSystem _loadout = default!;
|
[Dependency] private readonly LoadoutSystem _loadout = default!;
|
||||||
[Dependency] private readonly MindSystem _mind = default!;
|
[Dependency] private readonly MindSystem _mind = default!;
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
|
||||||
[Dependency] private readonly IServerPreferencesManager _pref = default!;
|
|
||||||
[Dependency] private readonly RoleSystem _role = default!;
|
[Dependency] private readonly RoleSystem _role = default!;
|
||||||
[Dependency] private readonly TransformSystem _transform = default!;
|
[Dependency] private readonly TransformSystem _transform = default!;
|
||||||
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
|
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
|
||||||
@@ -191,9 +193,6 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Chooses antagonists from the given selection of players
|
/// Chooses antagonists from the given selection of players
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ent">The antagonist rule entity</param>
|
|
||||||
/// <param name="pool">The players to choose from</param>
|
|
||||||
/// <param name="midround">Disable picking players for pre-spawn antags in the middle of a round</param>
|
|
||||||
public void ChooseAntags(Entity<AntagSelectionComponent> ent, IList<ICommonSession> pool, bool midround = false)
|
public void ChooseAntags(Entity<AntagSelectionComponent> ent, IList<ICommonSession> pool, bool midround = false)
|
||||||
{
|
{
|
||||||
if (ent.Comp.SelectionsComplete)
|
if (ent.Comp.SelectionsComplete)
|
||||||
@@ -210,14 +209,8 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Chooses antagonists from the given selection of players for the given antag definition.
|
/// Chooses antagonists from the given selection of players for the given antag definition.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ent">The antagonist rule entity</param>
|
|
||||||
/// <param name="pool">The players to choose from</param>
|
|
||||||
/// <param name="def">The antagonist selection parameters and criteria</param>
|
|
||||||
/// <param name="midround">Disable picking players for pre-spawn antags in the middle of a round</param>
|
/// <param name="midround">Disable picking players for pre-spawn antags in the middle of a round</param>
|
||||||
public void ChooseAntags(Entity<AntagSelectionComponent> ent,
|
public void ChooseAntags(Entity<AntagSelectionComponent> ent, IList<ICommonSession> pool, AntagSelectionDefinition def, bool midround = false)
|
||||||
IList<ICommonSession> pool,
|
|
||||||
AntagSelectionDefinition def,
|
|
||||||
bool midround = false)
|
|
||||||
{
|
{
|
||||||
var playerPool = GetPlayerPool(ent, pool, def);
|
var playerPool = GetPlayerPool(ent, pool, def);
|
||||||
var count = GetTargetAntagCount(ent, GetTotalPlayerCount(pool), def);
|
var count = GetTargetAntagCount(ent, GetTotalPlayerCount(pool), def);
|
||||||
@@ -338,7 +331,7 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
|
|||||||
EntityManager.AddComponents(player, def.Components);
|
EntityManager.AddComponents(player, def.Components);
|
||||||
|
|
||||||
// Equip the entity's RoleLoadout and LoadoutGroup
|
// Equip the entity's RoleLoadout and LoadoutGroup
|
||||||
List<ProtoId<StartingGearPrototype>> gear = new();
|
List<ProtoId<StartingGearPrototype>>? gear = new();
|
||||||
if (def.StartingGear is not null)
|
if (def.StartingGear is not null)
|
||||||
gear.Add(def.StartingGear.Value);
|
gear.Add(def.StartingGear.Value);
|
||||||
|
|
||||||
@@ -357,7 +350,7 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
|
|||||||
}
|
}
|
||||||
|
|
||||||
_mind.TransferTo(curMind.Value, antagEnt, ghostCheckOverride: true);
|
_mind.TransferTo(curMind.Value, antagEnt, ghostCheckOverride: true);
|
||||||
_role.MindAddRoles(curMind.Value, def.MindRoles, null, true);
|
_role.MindAddRoles(curMind.Value, def.MindComponents, null, true);
|
||||||
ent.Comp.SelectedMinds.Add((curMind.Value, Name(player)));
|
ent.Comp.SelectedMinds.Add((curMind.Value, Name(player)));
|
||||||
SendBriefing(session, def.Briefing);
|
SendBriefing(session, def.Briefing);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Content.Shared.Antag;
|
|||||||
using Content.Shared.Destructible.Thresholds;
|
using Content.Shared.Destructible.Thresholds;
|
||||||
using Content.Shared.Preferences.Loadouts;
|
using Content.Shared.Preferences.Loadouts;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
|
using Content.Shared.Storage;
|
||||||
using Content.Shared.Whitelist;
|
using Content.Shared.Whitelist;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
@@ -144,17 +145,10 @@ public partial struct AntagSelectionDefinition()
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Components added to the player's mind.
|
/// Components added to the player's mind.
|
||||||
/// Do NOT use this to add role-type components. Add those as MindRoles instead
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField]
|
||||||
public ComponentRegistry MindComponents = new();
|
public ComponentRegistry MindComponents = new();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// List of Mind Role Prototypes to be added to the player's mind.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public List<ProtoId<EntityPrototype>>? MindRoles;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A set of starting gear that's equipped to the player.
|
/// A set of starting gear that's equipped to the player.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Server.Atmos.Components
|
namespace Content.Server.Atmos.Components
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used by FixGridAtmos. Entities with this may get magically auto-deleted on map initialization in future.
|
/// Used by FixGridAtmos. Entities with this may get magically auto-deleted on map initialization in future.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent, EntityCategory("Mapping")]
|
[RegisterComponent]
|
||||||
public sealed partial class AtmosFixMarkerComponent : Component
|
public sealed partial class AtmosFixMarkerComponent : Component
|
||||||
{
|
{
|
||||||
// See FixGridAtmos for more details
|
// See FixGridAtmos for more details
|
||||||
|
|||||||
@@ -1,19 +1,15 @@
|
|||||||
using Content.Server.Atmos.Monitor.Components;
|
using Content.Server.Atmos.Monitor.Components;
|
||||||
using Content.Server.DeviceNetwork.Components;
|
using Content.Server.DeviceNetwork.Components;
|
||||||
using Content.Server.DeviceNetwork.Systems;
|
|
||||||
using Content.Server.Pinpointer;
|
|
||||||
using Content.Server.Power.Components;
|
using Content.Server.Power.Components;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
using Content.Shared.Atmos.Components;
|
using Content.Shared.Atmos.Components;
|
||||||
using Content.Shared.Atmos.Consoles;
|
using Content.Shared.Atmos.Consoles;
|
||||||
using Content.Shared.Atmos.Monitor;
|
using Content.Shared.Atmos.Monitor;
|
||||||
using Content.Shared.Atmos.Monitor.Components;
|
using Content.Shared.Atmos.Monitor.Components;
|
||||||
using Content.Shared.DeviceNetwork.Components;
|
|
||||||
using Content.Shared.Pinpointer;
|
using Content.Shared.Pinpointer;
|
||||||
using Content.Shared.Tag;
|
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Map.Components;
|
using Robust.Shared.Map.Components;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Player;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
@@ -25,12 +21,6 @@ public sealed class AtmosAlertsComputerSystem : SharedAtmosAlertsComputerSystem
|
|||||||
[Dependency] private readonly AirAlarmSystem _airAlarmSystem = default!;
|
[Dependency] private readonly AirAlarmSystem _airAlarmSystem = default!;
|
||||||
[Dependency] private readonly AtmosDeviceNetworkSystem _atmosDevNet = default!;
|
[Dependency] private readonly AtmosDeviceNetworkSystem _atmosDevNet = default!;
|
||||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||||
[Dependency] private readonly TagSystem _tagSystem = default!;
|
|
||||||
[Dependency] private readonly MapSystem _mapSystem = default!;
|
|
||||||
[Dependency] private readonly TransformSystem _transformSystem = default!;
|
|
||||||
[Dependency] private readonly NavMapSystem _navMapSystem = default!;
|
|
||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
|
||||||
[Dependency] private readonly DeviceListSystem _deviceListSystem = default!;
|
|
||||||
|
|
||||||
private const float UpdateTime = 1.0f;
|
private const float UpdateTime = 1.0f;
|
||||||
|
|
||||||
@@ -48,9 +38,6 @@ public sealed class AtmosAlertsComputerSystem : SharedAtmosAlertsComputerSystem
|
|||||||
|
|
||||||
// Grid events
|
// Grid events
|
||||||
SubscribeLocalEvent<GridSplitEvent>(OnGridSplit);
|
SubscribeLocalEvent<GridSplitEvent>(OnGridSplit);
|
||||||
|
|
||||||
// Alarm events
|
|
||||||
SubscribeLocalEvent<AtmosAlertsDeviceComponent, EntityTerminatingEvent>(OnDeviceTerminatingEvent);
|
|
||||||
SubscribeLocalEvent<AtmosAlertsDeviceComponent, AnchorStateChangedEvent>(OnDeviceAnchorChanged);
|
SubscribeLocalEvent<AtmosAlertsDeviceComponent, AnchorStateChangedEvent>(OnDeviceAnchorChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,16 +81,6 @@ public sealed class AtmosAlertsComputerSystem : SharedAtmosAlertsComputerSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void OnDeviceAnchorChanged(EntityUid uid, AtmosAlertsDeviceComponent component, AnchorStateChangedEvent args)
|
private void OnDeviceAnchorChanged(EntityUid uid, AtmosAlertsDeviceComponent component, AnchorStateChangedEvent args)
|
||||||
{
|
|
||||||
OnDeviceAdditionOrRemoval(uid, component, args.Anchored);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDeviceTerminatingEvent(EntityUid uid, AtmosAlertsDeviceComponent component, ref EntityTerminatingEvent args)
|
|
||||||
{
|
|
||||||
OnDeviceAdditionOrRemoval(uid, component, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDeviceAdditionOrRemoval(EntityUid uid, AtmosAlertsDeviceComponent component, bool isAdding)
|
|
||||||
{
|
{
|
||||||
var xform = Transform(uid);
|
var xform = Transform(uid);
|
||||||
var gridUid = xform.GridUid;
|
var gridUid = xform.GridUid;
|
||||||
@@ -111,13 +88,10 @@ public sealed class AtmosAlertsComputerSystem : SharedAtmosAlertsComputerSystem
|
|||||||
if (gridUid == null)
|
if (gridUid == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!TryComp<NavMapComponent>(xform.GridUid, out var navMap))
|
if (!TryGetAtmosDeviceNavMapData(uid, component, xform, gridUid.Value, out var data))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!TryGetAtmosDeviceNavMapData(uid, component, xform, out var data))
|
var netEntity = EntityManager.GetNetEntity(uid);
|
||||||
return;
|
|
||||||
|
|
||||||
var netEntity = GetNetEntity(uid);
|
|
||||||
|
|
||||||
var query = AllEntityQuery<AtmosAlertsComputerComponent, TransformComponent>();
|
var query = AllEntityQuery<AtmosAlertsComputerComponent, TransformComponent>();
|
||||||
while (query.MoveNext(out var ent, out var entConsole, out var entXform))
|
while (query.MoveNext(out var ent, out var entConsole, out var entXform))
|
||||||
@@ -125,18 +99,11 @@ public sealed class AtmosAlertsComputerSystem : SharedAtmosAlertsComputerSystem
|
|||||||
if (gridUid != entXform.GridUid)
|
if (gridUid != entXform.GridUid)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (isAdding)
|
if (args.Anchored)
|
||||||
{
|
|
||||||
entConsole.AtmosDevices.Add(data.Value);
|
entConsole.AtmosDevices.Add(data.Value);
|
||||||
}
|
|
||||||
|
|
||||||
else
|
else if (!args.Anchored)
|
||||||
{
|
|
||||||
entConsole.AtmosDevices.RemoveWhere(x => x.NetEntity == netEntity);
|
entConsole.AtmosDevices.RemoveWhere(x => x.NetEntity == netEntity);
|
||||||
_navMapSystem.RemoveNavMapRegion(gridUid.Value, navMap, netEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
Dirty(ent, entConsole);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,12 +209,6 @@ public sealed class AtmosAlertsComputerSystem : SharedAtmosAlertsComputerSystem
|
|||||||
if (entDevice.Group != group)
|
if (entDevice.Group != group)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!TryComp<MapGridComponent>(entXform.GridUid, out var mapGrid))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!TryComp<NavMapComponent>(entXform.GridUid, out var navMap))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// If emagged, change the alarm type to normal
|
// If emagged, change the alarm type to normal
|
||||||
var alarmState = (entAtmosAlarmable.LastAlarmState == AtmosAlarmType.Emagged) ? AtmosAlarmType.Normal : entAtmosAlarmable.LastAlarmState;
|
var alarmState = (entAtmosAlarmable.LastAlarmState == AtmosAlarmType.Emagged) ? AtmosAlarmType.Normal : entAtmosAlarmable.LastAlarmState;
|
||||||
|
|
||||||
@@ -255,45 +216,14 @@ public sealed class AtmosAlertsComputerSystem : SharedAtmosAlertsComputerSystem
|
|||||||
if (TryComp<ApcPowerReceiverComponent>(ent, out var entAPCPower) && !entAPCPower.Powered)
|
if (TryComp<ApcPowerReceiverComponent>(ent, out var entAPCPower) && !entAPCPower.Powered)
|
||||||
alarmState = AtmosAlarmType.Invalid;
|
alarmState = AtmosAlarmType.Invalid;
|
||||||
|
|
||||||
// Create entry
|
|
||||||
var netEnt = GetNetEntity(ent);
|
|
||||||
|
|
||||||
var entry = new AtmosAlertsComputerEntry
|
var entry = new AtmosAlertsComputerEntry
|
||||||
(netEnt,
|
(GetNetEntity(ent),
|
||||||
GetNetCoordinates(entXform.Coordinates),
|
GetNetCoordinates(entXform.Coordinates),
|
||||||
entDevice.Group,
|
entDevice.Group,
|
||||||
alarmState,
|
alarmState,
|
||||||
MetaData(ent).EntityName,
|
MetaData(ent).EntityName,
|
||||||
entDeviceNetwork.Address);
|
entDeviceNetwork.Address);
|
||||||
|
|
||||||
// Get the list of sensors attached to the alarm
|
|
||||||
var sensorList = TryComp<DeviceListComponent>(ent, out var entDeviceList) ? _deviceListSystem.GetDeviceList(ent, entDeviceList) : null;
|
|
||||||
|
|
||||||
if (sensorList?.Any() == true)
|
|
||||||
{
|
|
||||||
var alarmRegionSeeds = new HashSet<Vector2i>();
|
|
||||||
|
|
||||||
// If valid and anchored, use the position of sensors as seeds for the region
|
|
||||||
foreach (var (address, sensorEnt) in sensorList)
|
|
||||||
{
|
|
||||||
if (!sensorEnt.IsValid() || !HasComp<AtmosMonitorComponent>(sensorEnt))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var sensorXform = Transform(sensorEnt);
|
|
||||||
|
|
||||||
if (sensorXform.Anchored && sensorXform.GridUid == entXform.GridUid)
|
|
||||||
alarmRegionSeeds.Add(_mapSystem.CoordinatesToTile(entXform.GridUid.Value, mapGrid, _transformSystem.GetMapCoordinates(sensorEnt, sensorXform)));
|
|
||||||
}
|
|
||||||
|
|
||||||
var regionProperties = new SharedNavMapSystem.NavMapRegionProperties(netEnt, AtmosAlertsComputerUiKey.Key, alarmRegionSeeds);
|
|
||||||
_navMapSystem.AddOrUpdateNavMapRegion(gridUid, navMap, netEnt, regionProperties);
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_navMapSystem.RemoveNavMapRegion(entXform.GridUid.Value, navMap, netEnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
alarmStateData.Add(entry);
|
alarmStateData.Add(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,10 +306,7 @@ public sealed class AtmosAlertsComputerSystem : SharedAtmosAlertsComputerSystem
|
|||||||
var query = AllEntityQuery<AtmosAlertsDeviceComponent, TransformComponent>();
|
var query = AllEntityQuery<AtmosAlertsDeviceComponent, TransformComponent>();
|
||||||
while (query.MoveNext(out var ent, out var entComponent, out var entXform))
|
while (query.MoveNext(out var ent, out var entComponent, out var entXform))
|
||||||
{
|
{
|
||||||
if (entXform.GridUid != gridUid)
|
if (TryGetAtmosDeviceNavMapData(ent, entComponent, entXform, gridUid, out var data))
|
||||||
continue;
|
|
||||||
|
|
||||||
if (TryGetAtmosDeviceNavMapData(ent, entComponent, entXform, out var data))
|
|
||||||
atmosDeviceNavMapData.Add(data.Value);
|
atmosDeviceNavMapData.Add(data.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,10 +317,14 @@ public sealed class AtmosAlertsComputerSystem : SharedAtmosAlertsComputerSystem
|
|||||||
(EntityUid uid,
|
(EntityUid uid,
|
||||||
AtmosAlertsDeviceComponent component,
|
AtmosAlertsDeviceComponent component,
|
||||||
TransformComponent xform,
|
TransformComponent xform,
|
||||||
|
EntityUid gridUid,
|
||||||
[NotNullWhen(true)] out AtmosAlertsDeviceNavMapData? output)
|
[NotNullWhen(true)] out AtmosAlertsDeviceNavMapData? output)
|
||||||
{
|
{
|
||||||
output = null;
|
output = null;
|
||||||
|
|
||||||
|
if (xform.GridUid != gridUid)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!xform.Anchored)
|
if (!xform.Anchored)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|||||||
@@ -281,17 +281,6 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Compares two TileAtmospheres to see if they are within acceptable ranges for group processing to be enabled.
|
|
||||||
/// </summary>
|
|
||||||
public GasCompareResult CompareExchange(TileAtmosphere sample, TileAtmosphere otherSample)
|
|
||||||
{
|
|
||||||
if (sample.AirArchived == null || otherSample.AirArchived == null)
|
|
||||||
return GasCompareResult.NoExchange;
|
|
||||||
|
|
||||||
return CompareExchange(sample.AirArchived, otherSample.AirArchived);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compares two gas mixtures to see if they are within acceptable ranges for group processing to be enabled.
|
/// Compares two gas mixtures to see if they are within acceptable ranges for group processing to be enabled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -270,7 +270,7 @@ public sealed partial class AtmosphereSystem
|
|||||||
{
|
{
|
||||||
DebugTools.AssertNotNull(tile.Air);
|
DebugTools.AssertNotNull(tile.Air);
|
||||||
DebugTools.Assert(tile.Air?.Immutable == false);
|
DebugTools.Assert(tile.Air?.Immutable == false);
|
||||||
tile.AirArchived = null;
|
Array.Clear(tile.MolesArchived);
|
||||||
tile.ArchivedCycle = 0;
|
tile.ArchivedCycle = 0;
|
||||||
|
|
||||||
var count = 0;
|
var count = 0;
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
MovedByPressureComponent.ProbabilityOffset);
|
MovedByPressureComponent.ProbabilityOffset);
|
||||||
|
|
||||||
// Can we yeet the thing (due to probability, strength, etc.)
|
// Can we yeet the thing (due to probability, strength, etc.)
|
||||||
if (moveProb > MovedByPressureComponent.ProbabilityOffset && _random.Prob(MathF.Min(moveProb / 100f, 1f))
|
if (moveProb > MovedByPressureComponent.ProbabilityOffset && _robustRandom.Prob(MathF.Min(moveProb / 100f, 1f))
|
||||||
&& !float.IsPositiveInfinity(component.MoveResist)
|
&& !float.IsPositiveInfinity(component.MoveResist)
|
||||||
&& (physics.BodyType != BodyType.Static
|
&& (physics.BodyType != BodyType.Static
|
||||||
&& (maxForce >= (component.MoveResist * MovedByPressureComponent.MoveForcePushRatio)))
|
&& (maxForce >= (component.MoveResist * MovedByPressureComponent.MoveForcePushRatio)))
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
}
|
}
|
||||||
|
|
||||||
shouldShareAir = true;
|
shouldShareAir = true;
|
||||||
} else if (CompareExchange(tile, enemyTile) != GasCompareResult.NoExchange)
|
} else if (CompareExchange(tile.Air, enemyTile.Air) != GasCompareResult.NoExchange)
|
||||||
{
|
{
|
||||||
AddActiveTile(gridAtmosphere, enemyTile);
|
AddActiveTile(gridAtmosphere, enemyTile);
|
||||||
if (ExcitedGroups)
|
if (ExcitedGroups)
|
||||||
@@ -117,8 +117,9 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
private void Archive(TileAtmosphere tile, int fireCount)
|
private void Archive(TileAtmosphere tile, int fireCount)
|
||||||
{
|
{
|
||||||
if (tile.Air != null)
|
if (tile.Air != null)
|
||||||
tile.AirArchived = new GasMixture(tile.Air);
|
tile.Air.Moles.AsSpan().CopyTo(tile.MolesArchived.AsSpan());
|
||||||
|
|
||||||
|
tile.TemperatureArchived = tile.Temperature;
|
||||||
tile.ArchivedCycle = fireCount;
|
tile.ArchivedCycle = fireCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,10 +184,10 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public float GetHeatCapacityArchived(TileAtmosphere tile)
|
public float GetHeatCapacityArchived(TileAtmosphere tile)
|
||||||
{
|
{
|
||||||
if (tile.AirArchived == null)
|
if (tile.Air == null)
|
||||||
return tile.HeatCapacity;
|
return tile.HeatCapacity;
|
||||||
|
|
||||||
return GetHeatCapacity(tile.AirArchived);
|
return GetHeatCapacityCalculation(tile.MolesArchived!, tile.Space);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -194,11 +195,10 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public float Share(TileAtmosphere tileReceiver, TileAtmosphere tileSharer, int atmosAdjacentTurfs)
|
public float Share(TileAtmosphere tileReceiver, TileAtmosphere tileSharer, int atmosAdjacentTurfs)
|
||||||
{
|
{
|
||||||
if (tileReceiver.Air is not {} receiver || tileSharer.Air is not {} sharer ||
|
if (tileReceiver.Air is not {} receiver || tileSharer.Air is not {} sharer)
|
||||||
tileReceiver.AirArchived == null || tileSharer.AirArchived == null)
|
|
||||||
return 0f;
|
return 0f;
|
||||||
|
|
||||||
var temperatureDelta = tileReceiver.AirArchived.Temperature - tileSharer.AirArchived.Temperature;
|
var temperatureDelta = tileReceiver.TemperatureArchived - tileSharer.TemperatureArchived;
|
||||||
var absTemperatureDelta = Math.Abs(temperatureDelta);
|
var absTemperatureDelta = Math.Abs(temperatureDelta);
|
||||||
var oldHeatCapacity = 0f;
|
var oldHeatCapacity = 0f;
|
||||||
var oldSharerHeatCapacity = 0f;
|
var oldSharerHeatCapacity = 0f;
|
||||||
@@ -249,12 +249,12 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
// Transfer of thermal energy (via changed heat capacity) between self and sharer.
|
// Transfer of thermal energy (via changed heat capacity) between self and sharer.
|
||||||
if (!receiver.Immutable && newHeatCapacity > Atmospherics.MinimumHeatCapacity)
|
if (!receiver.Immutable && newHeatCapacity > Atmospherics.MinimumHeatCapacity)
|
||||||
{
|
{
|
||||||
receiver.Temperature = ((oldHeatCapacity * receiver.Temperature) - (heatCapacityToSharer * tileReceiver.AirArchived.Temperature) + (heatCapacitySharerToThis * tileSharer.AirArchived.Temperature)) / newHeatCapacity;
|
receiver.Temperature = ((oldHeatCapacity * receiver.Temperature) - (heatCapacityToSharer * tileReceiver.TemperatureArchived) + (heatCapacitySharerToThis * tileSharer.TemperatureArchived)) / newHeatCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sharer.Immutable && newSharerHeatCapacity > Atmospherics.MinimumHeatCapacity)
|
if (!sharer.Immutable && newSharerHeatCapacity > Atmospherics.MinimumHeatCapacity)
|
||||||
{
|
{
|
||||||
sharer.Temperature = ((oldSharerHeatCapacity * sharer.Temperature) - (heatCapacitySharerToThis * tileSharer.AirArchived.Temperature) + (heatCapacityToSharer * tileReceiver.AirArchived.Temperature)) / newSharerHeatCapacity;
|
sharer.Temperature = ((oldSharerHeatCapacity * sharer.Temperature) - (heatCapacitySharerToThis * tileSharer.TemperatureArchived) + (heatCapacityToSharer * tileReceiver.TemperatureArchived)) / newSharerHeatCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Thermal energy of the system (self and sharer) is unchanged.
|
// Thermal energy of the system (self and sharer) is unchanged.
|
||||||
@@ -273,7 +273,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
var moles = receiver.TotalMoles;
|
var moles = receiver.TotalMoles;
|
||||||
var theirMoles = sharer.TotalMoles;
|
var theirMoles = sharer.TotalMoles;
|
||||||
|
|
||||||
return (tileReceiver.AirArchived.Temperature * (moles + movedMoles)) - (tileSharer.AirArchived.Temperature * (theirMoles - movedMoles)) * Atmospherics.R / receiver.Volume;
|
return (tileReceiver.TemperatureArchived * (moles + movedMoles)) - (tileSharer.TemperatureArchived * (theirMoles - movedMoles)) * Atmospherics.R / receiver.Volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -281,11 +281,10 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public float TemperatureShare(TileAtmosphere tileReceiver, TileAtmosphere tileSharer, float conductionCoefficient)
|
public float TemperatureShare(TileAtmosphere tileReceiver, TileAtmosphere tileSharer, float conductionCoefficient)
|
||||||
{
|
{
|
||||||
if (tileReceiver.Air is not { } receiver || tileSharer.Air is not { } sharer ||
|
if (tileReceiver.Air is not { } receiver || tileSharer.Air is not { } sharer)
|
||||||
tileReceiver.AirArchived == null || tileSharer.AirArchived == null)
|
|
||||||
return 0f;
|
return 0f;
|
||||||
|
|
||||||
var temperatureDelta = tileReceiver.AirArchived.Temperature - tileSharer.AirArchived.Temperature;
|
var temperatureDelta = tileReceiver.TemperatureArchived - tileSharer.TemperatureArchived;
|
||||||
if (MathF.Abs(temperatureDelta) > Atmospherics.MinimumTemperatureDeltaToConsider)
|
if (MathF.Abs(temperatureDelta) > Atmospherics.MinimumTemperatureDeltaToConsider)
|
||||||
{
|
{
|
||||||
var heatCapacity = GetHeatCapacityArchived(tileReceiver);
|
var heatCapacity = GetHeatCapacityArchived(tileReceiver);
|
||||||
@@ -311,10 +310,10 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public float TemperatureShare(TileAtmosphere tileReceiver, float conductionCoefficient, float sharerTemperature, float sharerHeatCapacity)
|
public float TemperatureShare(TileAtmosphere tileReceiver, float conductionCoefficient, float sharerTemperature, float sharerHeatCapacity)
|
||||||
{
|
{
|
||||||
if (tileReceiver.Air is not {} receiver || tileReceiver.AirArchived == null)
|
if (tileReceiver.Air is not {} receiver)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
var temperatureDelta = tileReceiver.AirArchived.Temperature - sharerTemperature;
|
var temperatureDelta = tileReceiver.TemperatureArchived - sharerTemperature;
|
||||||
if (MathF.Abs(temperatureDelta) > Atmospherics.MinimumTemperatureDeltaToConsider)
|
if (MathF.Abs(temperatureDelta) > Atmospherics.MinimumTemperatureDeltaToConsider)
|
||||||
{
|
{
|
||||||
var heatCapacity = GetHeatCapacityArchived(tileReceiver);
|
var heatCapacity = GetHeatCapacityArchived(tileReceiver);
|
||||||
|
|||||||
@@ -355,7 +355,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
DebugTools.Assert(otherTile2.AdjacentBits.IsFlagSet(direction.GetOpposite()));
|
DebugTools.Assert(otherTile2.AdjacentBits.IsFlagSet(direction.GetOpposite()));
|
||||||
if (otherTile2.Air != null && CompareExchange(otherTile2, tile) == GasCompareResult.NoExchange)
|
if (otherTile2.Air != null && CompareExchange(otherTile2.Air, tile.Air) == GasCompareResult.NoExchange)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
AddActiveTile(gridAtmosphere, otherTile2);
|
AddActiveTile(gridAtmosphere, otherTile2);
|
||||||
@@ -689,7 +689,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
|
|
||||||
var chance = MathHelper.Clamp(0.01f + (sum / SpacingMaxWind) * 0.3f, 0.003f, 0.3f);
|
var chance = MathHelper.Clamp(0.01f + (sum / SpacingMaxWind) * 0.3f, 0.003f, 0.3f);
|
||||||
|
|
||||||
if (sum > 20 && _random.Prob(chance))
|
if (sum > 20 && _robustRandom.Prob(chance))
|
||||||
PryTile(mapGrid, tile.GridIndices);
|
PryTile(mapGrid, tile.GridIndices);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
tile.MapAtmosphere = false;
|
tile.MapAtmosphere = false;
|
||||||
atmos.MapTiles.Remove(tile);
|
atmos.MapTiles.Remove(tile);
|
||||||
tile.Air = null;
|
tile.Air = null;
|
||||||
tile.AirArchived = null;
|
Array.Clear(tile.MolesArchived);
|
||||||
tile.ArchivedCycle = 0;
|
tile.ArchivedCycle = 0;
|
||||||
tile.LastShare = 0f;
|
tile.LastShare = 0f;
|
||||||
tile.Space = false;
|
tile.Space = false;
|
||||||
@@ -261,7 +261,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
tile.Air = null;
|
tile.Air = null;
|
||||||
tile.AirArchived = null;
|
Array.Clear(tile.MolesArchived);
|
||||||
tile.ArchivedCycle = 0;
|
tile.ArchivedCycle = 0;
|
||||||
tile.LastShare = 0f;
|
tile.LastShare = 0f;
|
||||||
tile.Hotspot = new Hotspot();
|
tile.Hotspot = new Hotspot();
|
||||||
|
|||||||
@@ -131,10 +131,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
|
|
||||||
private void TemperatureShareMutualSolid(TileAtmosphere tile, TileAtmosphere other, float conductionCoefficient)
|
private void TemperatureShareMutualSolid(TileAtmosphere tile, TileAtmosphere other, float conductionCoefficient)
|
||||||
{
|
{
|
||||||
if (tile.AirArchived == null || other.AirArchived == null)
|
var deltaTemperature = (tile.TemperatureArchived - other.TemperatureArchived);
|
||||||
return;
|
|
||||||
|
|
||||||
var deltaTemperature = (tile.AirArchived.Temperature - other.AirArchived.Temperature);
|
|
||||||
if (MathF.Abs(deltaTemperature) > Atmospherics.MinimumTemperatureDeltaToConsider
|
if (MathF.Abs(deltaTemperature) > Atmospherics.MinimumTemperatureDeltaToConsider
|
||||||
&& tile.HeatCapacity != 0f && other.HeatCapacity != 0f)
|
&& tile.HeatCapacity != 0f && other.HeatCapacity != 0f)
|
||||||
{
|
{
|
||||||
@@ -148,14 +145,11 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
|
|
||||||
public void RadiateToSpace(TileAtmosphere tile)
|
public void RadiateToSpace(TileAtmosphere tile)
|
||||||
{
|
{
|
||||||
if (tile.AirArchived == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Considering 0ºC as the break even point for radiation in and out.
|
// Considering 0ºC as the break even point for radiation in and out.
|
||||||
if (tile.Temperature > Atmospherics.T0C)
|
if (tile.Temperature > Atmospherics.T0C)
|
||||||
{
|
{
|
||||||
// Hardcoded space temperature.
|
// Hardcoded space temperature.
|
||||||
var deltaTemperature = (tile.AirArchived.Temperature - Atmospherics.TCMB);
|
var deltaTemperature = (tile.TemperatureArchived - Atmospherics.TCMB);
|
||||||
if ((tile.HeatCapacity > 0) && (MathF.Abs(deltaTemperature) > Atmospherics.MinimumTemperatureDeltaToConsider))
|
if ((tile.HeatCapacity > 0) && (MathF.Abs(deltaTemperature) > Atmospherics.MinimumTemperatureDeltaToConsider))
|
||||||
{
|
{
|
||||||
var heat = tile.ThermalConductivity * deltaTemperature * (tile.HeatCapacity *
|
var heat = tile.ThermalConductivity * deltaTemperature * (tile.HeatCapacity *
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ using Robust.Shared.Containers;
|
|||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Physics.Systems;
|
using Robust.Shared.Physics.Systems;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Random;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Content.Server.Atmos.EntitySystems;
|
namespace Content.Server.Atmos.EntitySystems;
|
||||||
@@ -26,6 +27,7 @@ public sealed partial class AtmosphereSystem : SharedAtmosphereSystem
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
[Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!;
|
[Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!;
|
||||||
|
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
||||||
[Dependency] private readonly IAdminLogManager _adminLog = default!;
|
[Dependency] private readonly IAdminLogManager _adminLog = default!;
|
||||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||||
[Dependency] private readonly InternalsSystem _internals = default!;
|
[Dependency] private readonly InternalsSystem _internals = default!;
|
||||||
@@ -37,6 +39,7 @@ public sealed partial class AtmosphereSystem : SharedAtmosphereSystem
|
|||||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||||
[Dependency] private readonly TileSystem _tile = default!;
|
[Dependency] private readonly TileSystem _tile = default!;
|
||||||
[Dependency] private readonly MapSystem _map = default!;
|
[Dependency] private readonly MapSystem _map = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] public readonly PuddleSystem Puddle = default!;
|
[Dependency] public readonly PuddleSystem Puddle = default!;
|
||||||
|
|
||||||
private const float ExposedUpdateDelay = 1f;
|
private const float ExposedUpdateDelay = 1f;
|
||||||
@@ -121,6 +124,6 @@ public sealed partial class AtmosphereSystem : SharedAtmosphereSystem
|
|||||||
|
|
||||||
private void CacheDecals()
|
private void CacheDecals()
|
||||||
{
|
{
|
||||||
_burntDecals = _protoMan.EnumeratePrototypes<DecalPrototype>().Where(x => x.Tags.Contains("burnt")).Select(x => x.ID).ToArray();
|
_burntDecals = _prototypeManager.EnumeratePrototypes<DecalPrototype>().Where(x => x.Tags.Contains("burnt")).Select(x => x.ID).ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ namespace Content.Server.Atmos
|
|||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public float Temperature { get; set; } = Atmospherics.T20C;
|
public float Temperature { get; set; } = Atmospherics.T20C;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public float TemperatureArchived { get; set; } = Atmospherics.T20C;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public TileAtmosphere? PressureSpecificTarget { get; set; }
|
public TileAtmosphere? PressureSpecificTarget { get; set; }
|
||||||
|
|
||||||
@@ -90,16 +93,12 @@ namespace Content.Server.Atmos
|
|||||||
[Access(typeof(AtmosphereSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
|
[Access(typeof(AtmosphereSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
|
||||||
public GasMixture? Air { get; set; }
|
public GasMixture? Air { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Like Air, but a copy stored each atmos tick before tile processing takes place. This lets us update Air
|
|
||||||
/// in-place without affecting the results based on update order.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public GasMixture? AirArchived;
|
|
||||||
|
|
||||||
[DataField("lastShare")]
|
[DataField("lastShare")]
|
||||||
public float LastShare;
|
public float LastShare;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public readonly float[] MolesArchived = new float[Atmospherics.AdjustedNumberOfGases];
|
||||||
|
|
||||||
GasMixture IGasMixtureHolder.Air
|
GasMixture IGasMixtureHolder.Air
|
||||||
{
|
{
|
||||||
get => Air ?? new GasMixture(Atmospherics.CellVolume){ Temperature = Temperature };
|
get => Air ?? new GasMixture(Atmospherics.CellVolume){ Temperature = Temperature };
|
||||||
@@ -140,7 +139,6 @@ namespace Content.Server.Atmos
|
|||||||
GridIndex = gridIndex;
|
GridIndex = gridIndex;
|
||||||
GridIndices = gridIndices;
|
GridIndices = gridIndices;
|
||||||
Air = mixture;
|
Air = mixture;
|
||||||
AirArchived = Air != null ? Air.Clone() : null;
|
|
||||||
Space = space;
|
Space = space;
|
||||||
|
|
||||||
if(immutable)
|
if(immutable)
|
||||||
@@ -155,7 +153,7 @@ namespace Content.Server.Atmos
|
|||||||
NoGridTile = other.NoGridTile;
|
NoGridTile = other.NoGridTile;
|
||||||
MapAtmosphere = other.MapAtmosphere;
|
MapAtmosphere = other.MapAtmosphere;
|
||||||
Air = other.Air?.Clone();
|
Air = other.Air?.Clone();
|
||||||
AirArchived = Air != null ? Air.Clone() : null;
|
Array.Copy(other.MolesArchived, MolesArchived, MolesArchived.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TileAtmosphere()
|
public TileAtmosphere()
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ public sealed class CryostorageSystem : SharedCryostorageSystem
|
|||||||
Loc.GetString(
|
Loc.GetString(
|
||||||
"earlyleave-cryo-announcement",
|
"earlyleave-cryo-announcement",
|
||||||
("character", name),
|
("character", name),
|
||||||
("entity", ent.Owner), // gender things for supporting downstreams with other languages
|
("entity", ent.Owner),
|
||||||
("job", CultureInfo.CurrentCulture.TextInfo.ToTitleCase(jobName))
|
("job", CultureInfo.CurrentCulture.TextInfo.ToTitleCase(jobName))
|
||||||
), Loc.GetString("earlyleave-cryo-sender"),
|
), Loc.GetString("earlyleave-cryo-sender"),
|
||||||
playDefaultSound: false
|
playDefaultSound: false
|
||||||
|
|||||||
@@ -472,7 +472,7 @@ public sealed class BloodstreamSystem : EntitySystem
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentVolume = bloodSolution.RemoveReagent(component.BloodReagent, bloodSolution.Volume, ignoreReagentData: true);
|
var currentVolume = bloodSolution.RemoveReagent(component.BloodReagent, bloodSolution.Volume);
|
||||||
|
|
||||||
component.BloodReagent = reagent;
|
component.BloodReagent = reagent;
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ public sealed class LungSystem : EntitySystem
|
|||||||
[Dependency] private readonly AtmosphereSystem _atmos = default!;
|
[Dependency] private readonly AtmosphereSystem _atmos = default!;
|
||||||
[Dependency] private readonly InternalsSystem _internals = default!;
|
[Dependency] private readonly InternalsSystem _internals = default!;
|
||||||
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
|
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
|
||||||
|
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
||||||
|
|
||||||
public static string LungSolutionName = "Lung";
|
public static string LungSolutionName = "Lung";
|
||||||
|
|
||||||
@@ -28,7 +29,7 @@ public sealed class LungSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnGotUnequipped(Entity<BreathToolComponent> ent, ref GotUnequippedEvent args)
|
private void OnGotUnequipped(Entity<BreathToolComponent> ent, ref GotUnequippedEvent args)
|
||||||
{
|
{
|
||||||
_atmos.DisconnectInternals(ent);
|
_atmosphereSystem.DisconnectInternals(ent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnGotEquipped(Entity<BreathToolComponent> ent, ref GotEquippedEvent args)
|
private void OnGotEquipped(Entity<BreathToolComponent> ent, ref GotEquippedEvent args)
|
||||||
@@ -92,7 +93,7 @@ public sealed class LungSystem : EntitySystem
|
|||||||
if (moles <= 0)
|
if (moles <= 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var reagent = _atmos.GasReagents[i];
|
var reagent = _atmosphereSystem.GasReagents[i];
|
||||||
if (reagent is null)
|
if (reagent is null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using Content.Shared.Chemistry.Components;
|
using Content.Shared.Chemistry.Components;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||||
using Robust.Shared.Audio;
|
|
||||||
|
|
||||||
namespace Content.Server.Botany.Components;
|
namespace Content.Server.Botany.Components;
|
||||||
|
|
||||||
@@ -24,9 +23,6 @@ public sealed partial class PlantHolderComponent : Component
|
|||||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
|
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
|
||||||
public TimeSpan LastCycle = TimeSpan.Zero;
|
public TimeSpan LastCycle = TimeSpan.Zero;
|
||||||
|
|
||||||
[DataField]
|
|
||||||
public SoundSpecifier? WateringSound;
|
|
||||||
|
|
||||||
[DataField]
|
[DataField]
|
||||||
public bool UpdateSpriteAfterUpdate;
|
public bool UpdateSpriteAfterUpdate;
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public sealed class MutationSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
foreach (var mutation in _randomMutations.mutations)
|
foreach (var mutation in _randomMutations.mutations)
|
||||||
{
|
{
|
||||||
if (Random(Math.Min(mutation.BaseOdds * severity, 1.0f)))
|
if (Random(mutation.BaseOdds * severity))
|
||||||
{
|
{
|
||||||
if (mutation.AppliesToPlant)
|
if (mutation.AppliesToPlant)
|
||||||
{
|
{
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user