@@ -82,7 +82,7 @@ namespace Content.Server.Abilities.Mime
|
||||
// Get the tile in front of the mime
|
||||
var offsetValue = xform.LocalRotation.ToWorldVec();
|
||||
var coords = xform.Coordinates.Offset(offsetValue).SnapToGrid(EntityManager, _mapMan);
|
||||
var tile = _turf.GetTileRef(coords);
|
||||
var tile = coords.GetTileRef(EntityManager, _mapMan);
|
||||
if (tile == null)
|
||||
return;
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ public sealed class AccessOverriderSystem : SharedAccessOverriderSystem
|
||||
|
||||
if (component.TargetAccessReaderId is { Valid: true } accessReader)
|
||||
{
|
||||
targetLabel = Loc.GetString("access-overrider-window-target-label") + " " + Comp<MetaDataComponent>(component.TargetAccessReaderId).EntityName;
|
||||
targetLabel = Loc.GetString("access-overrider-window-target-label") + " " + EntityManager.GetComponent<MetaDataComponent>(component.TargetAccessReaderId).EntityName;
|
||||
targetLabelColor = Color.White;
|
||||
|
||||
if (!_accessReader.GetMainAccessReader(accessReader, out var accessReaderEnt))
|
||||
@@ -125,7 +125,7 @@ public sealed class AccessOverriderSystem : SharedAccessOverriderSystem
|
||||
|
||||
if (component.PrivilegedIdSlot.Item is { Valid: true } idCard)
|
||||
{
|
||||
privilegedIdName = Comp<MetaDataComponent>(idCard).EntityName;
|
||||
privilegedIdName = EntityManager.GetComponent<MetaDataComponent>(idCard).EntityName;
|
||||
|
||||
if (component.TargetAccessReaderId is { Valid: true })
|
||||
{
|
||||
|
||||
@@ -73,7 +73,7 @@ public sealed class IdCardConsoleSystem : SharedIdCardConsoleSystem
|
||||
List<ProtoId<AccessLevelPrototype>>? possibleAccess = null;
|
||||
if (component.PrivilegedIdSlot.Item is { Valid: true } item)
|
||||
{
|
||||
privilegedIdName = Comp<MetaDataComponent>(item).EntityName;
|
||||
privilegedIdName = EntityManager.GetComponent<MetaDataComponent>(item).EntityName;
|
||||
possibleAccess = _accessReader.FindAccessTags(item).ToList();
|
||||
}
|
||||
|
||||
@@ -95,8 +95,8 @@ public sealed class IdCardConsoleSystem : SharedIdCardConsoleSystem
|
||||
}
|
||||
else
|
||||
{
|
||||
var targetIdComponent = Comp<IdCardComponent>(targetId);
|
||||
var targetAccessComponent = Comp<AccessComponent>(targetId);
|
||||
var targetIdComponent = EntityManager.GetComponent<IdCardComponent>(targetId);
|
||||
var targetAccessComponent = EntityManager.GetComponent<AccessComponent>(targetId);
|
||||
|
||||
var jobProto = targetIdComponent.JobPrototype ?? new ProtoId<AccessLevelPrototype>(string.Empty);
|
||||
if (TryComp<StationRecordKeyStorageComponent>(targetId, out var keyStorage)
|
||||
|
||||
@@ -47,12 +47,12 @@ public sealed class IdCardSystem : SharedIdCardSystem
|
||||
{
|
||||
_popupSystem.PopupCoordinates(Loc.GetString("id-card-component-microwave-burnt", ("id", uid)),
|
||||
transformComponent.Coordinates, PopupType.Medium);
|
||||
Spawn("FoodBadRecipe",
|
||||
EntityManager.SpawnEntity("FoodBadRecipe",
|
||||
transformComponent.Coordinates);
|
||||
}
|
||||
_adminLogger.Add(LogType.Action, LogImpact.Medium,
|
||||
$"{ToPrettyString(args.Microwave)} burnt {ToPrettyString(uid):entity}");
|
||||
QueueDel(uid);
|
||||
EntityManager.QueueDeleteEntity(uid);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,41 +3,52 @@ using Content.Shared.Administration;
|
||||
using Content.Shared.Body.Part;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
namespace Content.Server.Administration.Commands;
|
||||
|
||||
[AdminCommand(AdminFlags.Admin)]
|
||||
public sealed class AddBodyPartCommand : LocalizedEntityCommands
|
||||
namespace Content.Server.Administration.Commands
|
||||
{
|
||||
[Dependency] private readonly BodySystem _bodySystem = default!;
|
||||
|
||||
public override string Command => "addbodypart";
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
[AdminCommand(AdminFlags.Admin)]
|
||||
public sealed class AddBodyPartCommand : IConsoleCommand
|
||||
{
|
||||
if (args.Length != 4)
|
||||
{
|
||||
shell.WriteError(Loc.GetString("shell-wrong-arguments-number"));
|
||||
return;
|
||||
}
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
|
||||
if (!NetEntity.TryParse(args[0], out var childNetId) || !EntityManager.TryGetEntity(childNetId, out var childId))
|
||||
{
|
||||
shell.WriteError(Loc.GetString("shell-invalid-entity-uid", ("uid", args[0])));
|
||||
return;
|
||||
}
|
||||
public string Command => "addbodypart";
|
||||
public string Description => "Adds a given entity to a containing body.";
|
||||
public string Help => "Usage: addbodypart <entity uid> <body uid> <part slot> <part type>";
|
||||
|
||||
if (!NetEntity.TryParse(args[1], out var parentNetId) || !EntityManager.TryGetEntity(parentNetId, out var parentId))
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
shell.WriteError(Loc.GetString("shell-invalid-entity-uid", ("uid", args[1])));
|
||||
return;
|
||||
}
|
||||
if (args.Length != 3)
|
||||
{
|
||||
shell.WriteError(Loc.GetString("shell-wrong-arguments-number"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (Enum.TryParse<BodyPartType>(args[3], out var partType) &&
|
||||
_bodySystem.TryCreatePartSlotAndAttach(parentId.Value, args[2], childId.Value, partType))
|
||||
{
|
||||
shell.WriteLine($@"Added {childId} to {parentId}.");
|
||||
if (!NetEntity.TryParse(args[0], out var childNetId))
|
||||
{
|
||||
shell.WriteError(Loc.GetString("shell-entity-uid-must-be-number"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NetEntity.TryParse(args[1], out var parentNetId))
|
||||
{
|
||||
shell.WriteError(Loc.GetString("shell-entity-uid-must-be-number"));
|
||||
return;
|
||||
}
|
||||
|
||||
var childId = _entManager.GetEntity(childNetId);
|
||||
var parentId = _entManager.GetEntity(parentNetId);
|
||||
var bodySystem = _entManager.System<BodySystem>();
|
||||
|
||||
|
||||
|
||||
if (Enum.TryParse<BodyPartType>(args[3], out var partType) &&
|
||||
bodySystem.TryCreatePartSlotAndAttach(parentId, args[2], childId, partType))
|
||||
{
|
||||
shell.WriteLine($@"Added {childId} to {parentId}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
shell.WriteError($@"Could not add {childId} to {parentId}.");
|
||||
}
|
||||
}
|
||||
else
|
||||
shell.WriteError($@"Could not add {childId} to {parentId}.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,10 +14,9 @@ namespace Content.Server.Administration.Commands;
|
||||
[AdminCommand(AdminFlags.Ban)]
|
||||
public sealed class BanListCommand : LocalizedCommands
|
||||
{
|
||||
[Dependency] private readonly IPlayerLocator _locator = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IServerDbManager _dbManager = default!;
|
||||
[Dependency] private readonly EuiManager _eui = default!;
|
||||
[Dependency] private readonly IPlayerLocator _locator = default!;
|
||||
|
||||
public override string Command => "banlist";
|
||||
|
||||
@@ -67,7 +66,8 @@ public sealed class BanListCommand : LocalizedCommands
|
||||
if (args.Length != 1)
|
||||
return CompletionResult.Empty;
|
||||
|
||||
var options = _playerManager.Sessions.Select(c => c.Name).OrderBy(c => c).ToArray();
|
||||
var playerMgr = IoCManager.Resolve<IPlayerManager>();
|
||||
var options = playerMgr.Sessions.Select(c => c.Name).OrderBy(c => c).ToArray();
|
||||
return CompletionResult.FromHintOptions(options, Loc.GetString("cmd-banlist-hint"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,36 +2,39 @@ using Content.Server.Chat.Systems;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
namespace Content.Server.Administration.Commands;
|
||||
|
||||
[AdminCommand(AdminFlags.Moderator)]
|
||||
public sealed class DsayCommand : LocalizedEntityCommands
|
||||
namespace Content.Server.Administration.Commands
|
||||
{
|
||||
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
||||
|
||||
public override string Command => "dsay";
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
[AdminCommand(AdminFlags.Moderator)]
|
||||
sealed class DSay : IConsoleCommand
|
||||
{
|
||||
if (shell.Player is not { } player)
|
||||
[Dependency] private readonly IEntityManager _e = default!;
|
||||
|
||||
public string Command => "dsay";
|
||||
|
||||
public string Description => Loc.GetString("dsay-command-description");
|
||||
|
||||
public string Help => Loc.GetString("dsay-command-help-text", ("command", Command));
|
||||
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
shell.WriteError(Loc.GetString("shell-cannot-run-command-from-server"));
|
||||
return;
|
||||
if (shell.Player is not { } player)
|
||||
{
|
||||
shell.WriteError(Loc.GetString("shell-cannot-run-command-from-server"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.AttachedEntity is not { Valid: true } entity)
|
||||
return;
|
||||
|
||||
if (args.Length < 1)
|
||||
return;
|
||||
|
||||
var message = string.Join(" ", args).Trim();
|
||||
if (string.IsNullOrEmpty(message))
|
||||
return;
|
||||
|
||||
var chat = _e.System<ChatSystem>();
|
||||
chat.TrySendInGameOOCMessage(entity, message, InGameOOCChatType.Dead, false, shell, player);
|
||||
}
|
||||
|
||||
if (player.AttachedEntity is not { Valid: true } entity)
|
||||
{
|
||||
shell.WriteError(Loc.GetString("shell-must-be-attached-to-entity"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Length < 1)
|
||||
return;
|
||||
|
||||
var message = string.Join(" ", args).Trim();
|
||||
if (string.IsNullOrEmpty(message))
|
||||
return;
|
||||
|
||||
_chatSystem.TrySendInGameOOCMessage(entity, message, InGameOOCChatType.Dead, false, shell, player);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,18 +4,22 @@ using Robust.Shared.Console;
|
||||
namespace Content.Server.Administration.Commands;
|
||||
|
||||
[AdminCommand(AdminFlags.Debug)]
|
||||
public sealed class DirtyCommand : LocalizedEntityCommands
|
||||
public sealed class DirtyCommand : IConsoleCommand
|
||||
{
|
||||
public override string Command => "dirty";
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
|
||||
public override async void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
public string Command => "dirty";
|
||||
public string Description => "Marks all components on an entity as dirty, if not specified, dirties everything";
|
||||
public string Help => $"Usage: {Command} [entityUid]";
|
||||
|
||||
public async void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
switch (args.Length)
|
||||
{
|
||||
case 0:
|
||||
foreach (var entity in EntityManager.GetEntities())
|
||||
foreach (var entity in _entManager.GetEntities())
|
||||
{
|
||||
DirtyAll(entity);
|
||||
DirtyAll(_entManager, entity);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
@@ -24,7 +28,7 @@ public sealed class DirtyCommand : LocalizedEntityCommands
|
||||
shell.WriteError(Loc.GetString("shell-entity-uid-must-be-number"));
|
||||
return;
|
||||
}
|
||||
DirtyAll(EntityManager.GetEntity(parsedTarget));
|
||||
DirtyAll(_entManager, _entManager.GetEntity(parsedTarget));
|
||||
break;
|
||||
default:
|
||||
shell.WriteLine(Loc.GetString("shell-wrong-arguments-number"));
|
||||
@@ -32,11 +36,11 @@ public sealed class DirtyCommand : LocalizedEntityCommands
|
||||
}
|
||||
}
|
||||
|
||||
private void DirtyAll(EntityUid entityUid)
|
||||
private static void DirtyAll(IEntityManager manager, EntityUid entityUid)
|
||||
{
|
||||
foreach (var component in EntityManager.GetNetComponents(entityUid))
|
||||
foreach (var component in manager.GetNetComponents(entityUid))
|
||||
{
|
||||
EntityManager.Dirty(entityUid, component.component);
|
||||
manager.Dirty(entityUid, component.component);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,15 @@ using Robust.Shared.Enums;
|
||||
namespace Content.Server.Administration.Commands;
|
||||
|
||||
[AdminCommand(AdminFlags.Admin)]
|
||||
public sealed class FollowCommand : LocalizedEntityCommands
|
||||
public sealed class FollowCommand : IConsoleCommand
|
||||
{
|
||||
[Dependency] private readonly FollowerSystem _followerSystem = default!;
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
|
||||
public override string Command => "follow";
|
||||
public string Command => "follow";
|
||||
public string Description => Loc.GetString("follow-command-description");
|
||||
public string Help => Loc.GetString("follow-command-help");
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (shell.Player is not { } player)
|
||||
{
|
||||
@@ -32,7 +34,10 @@ public sealed class FollowCommand : LocalizedEntityCommands
|
||||
return;
|
||||
}
|
||||
|
||||
if (NetEntity.TryParse(args[0], out var uidNet) && EntityManager.TryGetEntity(uidNet, out var uid))
|
||||
_followerSystem.StartFollowingEntity(playerEntity, uid.Value);
|
||||
var entity = args[0];
|
||||
if (NetEntity.TryParse(entity, out var uidNet) && _entManager.TryGetEntity(uidNet, out var uid))
|
||||
{
|
||||
_entManager.System<FollowerSystem>().StartFollowingEntity(playerEntity, uid.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,6 @@ namespace Content.Server.Administration.Commands;
|
||||
[AdminCommand(AdminFlags.ViewNotes)]
|
||||
public sealed class OpenAdminNotesCommand : LocalizedCommands
|
||||
{
|
||||
[Dependency] private readonly IAdminNotesManager _adminNotes = default!;
|
||||
[Dependency] private readonly IPlayerLocator _locator = default!;
|
||||
|
||||
public const string CommandName = "adminnotes";
|
||||
|
||||
public override string Command => CommandName;
|
||||
@@ -31,7 +28,8 @@ public sealed class OpenAdminNotesCommand : LocalizedCommands
|
||||
case 1 when Guid.TryParse(args[0], out notedPlayer):
|
||||
break;
|
||||
case 1:
|
||||
var dbGuid = await _locator.LookupIdByNameAsync(args[0]);
|
||||
var locator = IoCManager.Resolve<IPlayerLocator>();
|
||||
var dbGuid = await locator.LookupIdByNameAsync(args[0]);
|
||||
|
||||
if (dbGuid == null)
|
||||
{
|
||||
@@ -46,7 +44,7 @@ public sealed class OpenAdminNotesCommand : LocalizedCommands
|
||||
return;
|
||||
}
|
||||
|
||||
await _adminNotes.OpenEui(player, notedPlayer);
|
||||
await IoCManager.Resolve<IAdminNotesManager>().OpenEui(player, notedPlayer);
|
||||
}
|
||||
|
||||
public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
|
||||
|
||||
@@ -14,18 +14,18 @@ public sealed class PanicBunkerCommand : LocalizedCommands
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var toggle = Toggle(CCVars.PanicBunkerEnabled, shell, args, _cfg, LocalizationManager);
|
||||
var toggle = Toggle(CCVars.PanicBunkerEnabled, shell, args, _cfg);
|
||||
if (toggle == null)
|
||||
return;
|
||||
|
||||
shell.WriteLine(Loc.GetString(toggle.Value ? "panicbunker-command-enabled" : "panicbunker-command-disabled"));
|
||||
}
|
||||
|
||||
public static bool? Toggle(CVarDef<bool> cvar, IConsoleShell shell, string[] args, IConfigurationManager config, ILocalizationManager loc)
|
||||
public static bool? Toggle(CVarDef<bool> cvar, IConsoleShell shell, string[] args, IConfigurationManager config)
|
||||
{
|
||||
if (args.Length > 1)
|
||||
{
|
||||
shell.WriteError(loc.GetString("shell-need-between-arguments",("lower", 0), ("upper", 1)));
|
||||
shell.WriteError(Loc.GetString("shell-need-between-arguments",("lower", 0), ("upper", 1)));
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ public sealed class PanicBunkerCommand : LocalizedCommands
|
||||
|
||||
if (args.Length == 1 && !bool.TryParse(args[0], out enabled))
|
||||
{
|
||||
shell.WriteError(loc.GetString("shell-argument-must-be-boolean"));
|
||||
shell.WriteError(Loc.GetString("shell-argument-must-be-boolean"));
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public sealed class PanicBunkerDisableWithAdminsCommand : LocalizedCommands
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var toggle = PanicBunkerCommand.Toggle(CCVars.PanicBunkerDisableWithAdmins, shell, args, _cfg, LocalizationManager);
|
||||
var toggle = PanicBunkerCommand.Toggle(CCVars.PanicBunkerDisableWithAdmins, shell, args, _cfg);
|
||||
if (toggle == null)
|
||||
return;
|
||||
|
||||
@@ -76,7 +76,7 @@ public sealed class PanicBunkerEnableWithoutAdminsCommand : LocalizedCommands
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var toggle = PanicBunkerCommand.Toggle(CCVars.PanicBunkerEnableWithoutAdmins, shell, args, _cfg, LocalizationManager);
|
||||
var toggle = PanicBunkerCommand.Toggle(CCVars.PanicBunkerEnableWithoutAdmins, shell, args, _cfg);
|
||||
if (toggle == null)
|
||||
return;
|
||||
|
||||
@@ -96,7 +96,7 @@ public sealed class PanicBunkerCountDeadminnedCommand : LocalizedCommands
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var toggle = PanicBunkerCommand.Toggle(CCVars.PanicBunkerCountDeadminnedAdmins, shell, args, _cfg, LocalizationManager);
|
||||
var toggle = PanicBunkerCommand.Toggle(CCVars.PanicBunkerCountDeadminnedAdmins, shell, args, _cfg);
|
||||
if (toggle == null)
|
||||
return;
|
||||
|
||||
@@ -116,7 +116,7 @@ public sealed class PanicBunkerShowReasonCommand : LocalizedCommands
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var toggle = PanicBunkerCommand.Toggle(CCVars.PanicBunkerShowReason, shell, args, _cfg, LocalizationManager);
|
||||
var toggle = PanicBunkerCommand.Toggle(CCVars.PanicBunkerShowReason, shell, args, _cfg);
|
||||
if (toggle == null)
|
||||
return;
|
||||
|
||||
|
||||
@@ -1,33 +1,39 @@
|
||||
using Content.Server.Administration.Managers;
|
||||
using Content.Shared.Administration;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Administration.Commands;
|
||||
|
||||
[UsedImplicitly]
|
||||
[AdminCommand(AdminFlags.Stealth)]
|
||||
public sealed class StealthminCommand : LocalizedCommands
|
||||
{
|
||||
[Dependency] private readonly IAdminManager _adminManager = default!;
|
||||
|
||||
public override string Command => "stealthmin";
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
var player = shell.Player;
|
||||
if (player == null)
|
||||
{
|
||||
shell.WriteLine(Loc.GetString("shell-cannot-run-command-from-server"));
|
||||
return;
|
||||
}
|
||||
var player = shell.Player;
|
||||
if (player == null)
|
||||
{
|
||||
shell.WriteLine(Loc.GetString("cmd-stealthmin-no-console"));
|
||||
return;
|
||||
}
|
||||
|
||||
var adminData = _adminManager.GetAdminData(player);
|
||||
var mgr = IoCManager.Resolve<IAdminManager>();
|
||||
|
||||
DebugTools.AssertNotNull(adminData);
|
||||
var adminData = mgr.GetAdminData(player);
|
||||
|
||||
if (!adminData!.Stealth)
|
||||
_adminManager.Stealth(player);
|
||||
else
|
||||
_adminManager.UnStealth(player);
|
||||
DebugTools.AssertNotNull(adminData);
|
||||
|
||||
if (!adminData!.Stealth)
|
||||
{
|
||||
mgr.Stealth(player);
|
||||
}
|
||||
else
|
||||
{
|
||||
mgr.UnStealth(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,12 +42,13 @@ public sealed class StripAllCommand : LocalizedEntityCommands
|
||||
|
||||
if (EntityManager.TryGetComponent<HandsComponent>(targetEntity, out var hands))
|
||||
{
|
||||
foreach (var hand in _handsSystem.EnumerateHands((targetEntity.Value, hands)))
|
||||
foreach (var hand in _handsSystem.EnumerateHands(targetEntity.Value, hands))
|
||||
{
|
||||
_handsSystem.TryDrop((targetEntity.Value, hands),
|
||||
_handsSystem.TryDrop(targetEntity.Value,
|
||||
hand,
|
||||
checkActionBlocker: false,
|
||||
doDropInteraction: false);
|
||||
doDropInteraction: false,
|
||||
handsComp: hands);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace Content.Server.Administration.Commands;
|
||||
public sealed class VariantizeCommand : IConsoleCommand
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
[Dependency] private readonly ITileDefinitionManager _tileDefManager = default!;
|
||||
|
||||
public string Command => "variantize";
|
||||
|
||||
@@ -39,11 +40,10 @@ public sealed class VariantizeCommand : IConsoleCommand
|
||||
|
||||
var mapsSystem = _entManager.System<SharedMapSystem>();
|
||||
var tileSystem = _entManager.System<TileSystem>();
|
||||
var turfSystem = _entManager.System<TurfSystem>();
|
||||
|
||||
foreach (var tile in mapsSystem.GetAllTiles(euid.Value, gridComp))
|
||||
{
|
||||
var def = turfSystem.GetContentTileDefinition(tile);
|
||||
var def = tile.GetContentTileDefinition(_tileDefManager);
|
||||
var newTile = new Tile(tile.Tile.TypeId, tile.Tile.Flags, tileSystem.PickVariant(def));
|
||||
mapsSystem.SetTile(euid.Value, gridComp, tile.GridIndices, newTile);
|
||||
}
|
||||
|
||||
@@ -9,14 +9,12 @@ using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Chat;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Players.PlayTimeTracking;
|
||||
using Prometheus;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Reflection;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
@@ -35,7 +33,6 @@ public sealed partial class AdminLogManager : SharedAdminLogManager, IAdminLogMa
|
||||
[Dependency] private readonly ISharedPlayerManager _player = default!;
|
||||
[Dependency] private readonly ISharedPlaytimeManager _playtime = default!;
|
||||
[Dependency] private readonly ISharedChatManager _chat = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
public const string SawmillId = "admin.logs";
|
||||
|
||||
@@ -333,8 +330,7 @@ public sealed partial class AdminLogManager : SharedAdminLogManager, IAdminLogMa
|
||||
var cachedInfo = adminSys.GetCachedPlayerInfo(new NetUserId(id));
|
||||
if (cachedInfo != null && cachedInfo.Antag)
|
||||
{
|
||||
var proto = cachedInfo.RoleProto == null ? null : _proto.Index(cachedInfo.RoleProto.Value);
|
||||
var subtype = Loc.GetString(cachedInfo.Subtype ?? proto?.Name ?? RoleTypePrototype.FallbackName);
|
||||
var subtype = Loc.GetString(cachedInfo.Subtype ?? cachedInfo.RoleProto.Name);
|
||||
logMessage = Loc.GetString(
|
||||
"admin-alert-antag-label",
|
||||
("message", logMessage),
|
||||
|
||||
@@ -224,14 +224,14 @@ public sealed class AdminSystem : EntitySystem
|
||||
// Visible (identity) name can be different from real name
|
||||
if (session?.AttachedEntity != null)
|
||||
{
|
||||
entityName = Comp<MetaDataComponent>(session.AttachedEntity.Value).EntityName;
|
||||
entityName = EntityManager.GetComponent<MetaDataComponent>(session.AttachedEntity.Value).EntityName;
|
||||
identityName = Identity.Name(session.AttachedEntity.Value, EntityManager);
|
||||
}
|
||||
|
||||
var antag = false;
|
||||
|
||||
// Starting role, antagonist status and role type
|
||||
RoleTypePrototype? roleType = null;
|
||||
RoleTypePrototype roleType = new();
|
||||
var startingRole = string.Empty;
|
||||
LocId? subtype = null;
|
||||
if (_minds.TryGetMind(session, out var mindId, out var mindComp) && mindComp is not null)
|
||||
@@ -244,7 +244,7 @@ public sealed class AdminSystem : EntitySystem
|
||||
subtype = mindComp.Subtype;
|
||||
}
|
||||
else
|
||||
Log.Error($"{ToPrettyString(mindId)} has invalid Role Type '{mindComp.RoleType}'. Displaying '{Loc.GetString(RoleTypePrototype.FallbackName)}' instead");
|
||||
Log.Error($"{ToPrettyString(mindId)} has invalid Role Type '{mindComp.RoleType}'. Displaying '{Loc.GetString(roleType.Name)}' instead");
|
||||
|
||||
antag = _role.MindIsAntagonist(mindId);
|
||||
startingRole = _jobs.MindTryGetJobName(mindId);
|
||||
@@ -270,7 +270,7 @@ public sealed class AdminSystem : EntitySystem
|
||||
identityName,
|
||||
startingRole,
|
||||
antag,
|
||||
roleType?.ID,
|
||||
roleType,
|
||||
subtype,
|
||||
sortWeight,
|
||||
GetNetEntity(session?.AttachedEntity),
|
||||
@@ -433,9 +433,9 @@ public sealed class AdminSystem : EntitySystem
|
||||
|
||||
if (TryComp(entity, out HandsComponent? hands))
|
||||
{
|
||||
foreach (var hand in _hands.EnumerateHands((entity, hands)))
|
||||
foreach (var hand in _hands.EnumerateHands(entity, hands))
|
||||
{
|
||||
_hands.TryDrop((entity, hands), hand, checkActionBlocker: false, doDropInteraction: false);
|
||||
_hands.TryDrop(entity, hand, checkActionBlocker: false, doDropInteraction: false, handsComp: hands);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,11 +79,12 @@ public sealed partial class AdminVerbSystem
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
[Dependency] private readonly SuperBonkSystem _superBonkSystem = default!;
|
||||
[Dependency] private readonly SlipperySystem _slipperySystem = default!;
|
||||
[Dependency] private readonly OutfitSystem _outfitSystem = default!;
|
||||
|
||||
// All smite verbs have names so invokeverb works.
|
||||
private void AddSmiteVerbs(GetVerbsEvent<Verb> args)
|
||||
{
|
||||
if (!TryComp(args.User, out ActorComponent? actor))
|
||||
if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor))
|
||||
return;
|
||||
|
||||
var player = actor.PlayerSession;
|
||||
@@ -273,7 +274,7 @@ public sealed partial class AdminVerbSystem
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Fluids/tomato_splat.rsi"), "puddle-1"),
|
||||
Act = () =>
|
||||
{
|
||||
_bloodstreamSystem.SpillAllSolutions((args.Target, bloodstream));
|
||||
_bloodstreamSystem.SpillAllSolutions(args.Target, bloodstream);
|
||||
var xform = Transform(args.Target);
|
||||
_popupSystem.PopupEntity(Loc.GetString("admin-smite-remove-blood-self"), args.Target,
|
||||
args.Target, PopupType.LargeCaution);
|
||||
@@ -586,7 +587,7 @@ public sealed partial class AdminVerbSystem
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Clothing/Uniforms/Jumpskirt/janimaid.rsi"), "icon"),
|
||||
Act = () =>
|
||||
{
|
||||
_outfit.SetOutfit(args.Target, "JanitorMaidGear", (_, clothing) =>
|
||||
_outfitSystem.SetOutfit(args.Target, "JanitorMaidGear", (_, clothing) =>
|
||||
{
|
||||
if (HasComp<ClothingComponent>(clothing))
|
||||
EnsureComp<UnremoveableComponent>(clothing);
|
||||
@@ -622,7 +623,7 @@ public sealed partial class AdminVerbSystem
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Materials/materials.rsi"), "ash"),
|
||||
Act = () =>
|
||||
{
|
||||
QueueDel(args.Target);
|
||||
EntityManager.QueueDeleteEntity(args.Target);
|
||||
Spawn("Ash", Transform(args.Target).Coordinates);
|
||||
_popupSystem.PopupEntity(Loc.GetString("admin-smite-turned-ash-other", ("name", args.Target)), args.Target, PopupType.LargeCaution);
|
||||
},
|
||||
|
||||
@@ -58,7 +58,7 @@ public sealed partial class AdminVerbSystem
|
||||
|
||||
private void AddTricksVerbs(GetVerbsEvent<Verb> args)
|
||||
{
|
||||
if (!TryComp(args.User, out ActorComponent? actor))
|
||||
if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor))
|
||||
return;
|
||||
|
||||
var player = actor.PlayerSession;
|
||||
@@ -820,7 +820,7 @@ public sealed partial class AdminVerbSystem
|
||||
}
|
||||
else if (TryComp<HandsComponent>(target, out var hands))
|
||||
{
|
||||
foreach (var held in _handsSystem.EnumerateHeld((target, hands)))
|
||||
foreach (var held in _handsSystem.EnumerateHeld(target, hands))
|
||||
{
|
||||
if (HasComp<AccessComponent>(held))
|
||||
{
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace Content.Server.Administration.Systems
|
||||
|
||||
private void AddAdminVerbs(GetVerbsEvent<Verb> args)
|
||||
{
|
||||
if (!TryComp(args.User, out ActorComponent? actor))
|
||||
if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor))
|
||||
return;
|
||||
|
||||
var player = actor.PlayerSession;
|
||||
@@ -395,7 +395,7 @@ namespace Content.Server.Administration.Systems
|
||||
|
||||
private void AddDebugVerbs(GetVerbsEvent<Verb> args)
|
||||
{
|
||||
if (!TryComp(args.User, out ActorComponent? actor))
|
||||
if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor))
|
||||
return;
|
||||
|
||||
var player = actor.PlayerSession;
|
||||
@@ -408,7 +408,7 @@ namespace Content.Server.Administration.Systems
|
||||
Text = Loc.GetString("delete-verb-get-data-text"),
|
||||
Category = VerbCategory.Debug,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/delete_transparent.svg.192dpi.png")),
|
||||
Act = () => Del(args.Target),
|
||||
Act = () => EntityManager.DeleteEntity(args.Target),
|
||||
Impact = LogImpact.Medium,
|
||||
ConfirmationPopup = true
|
||||
};
|
||||
@@ -451,7 +451,7 @@ namespace Content.Server.Administration.Systems
|
||||
// Make Sentient verb
|
||||
if (_groupController.CanCommand(player, "makesentient") &&
|
||||
args.User != args.Target &&
|
||||
!HasComp<MindContainerComponent>(args.Target))
|
||||
!EntityManager.HasComponent<MindContainerComponent>(args.Target))
|
||||
{
|
||||
Verb verb = new()
|
||||
{
|
||||
@@ -517,7 +517,7 @@ namespace Content.Server.Administration.Systems
|
||||
|
||||
// Get Disposal tube direction verb
|
||||
if (_groupController.CanCommand(player, "tubeconnections") &&
|
||||
TryComp(args.Target, out DisposalTubeComponent? tube))
|
||||
EntityManager.TryGetComponent(args.Target, out DisposalTubeComponent? tube))
|
||||
{
|
||||
Verb verb = new()
|
||||
{
|
||||
@@ -544,7 +544,7 @@ namespace Content.Server.Administration.Systems
|
||||
}
|
||||
|
||||
if (_groupController.CanAdminMenu(player) &&
|
||||
TryComp(args.Target, out ConfigurationComponent? config))
|
||||
EntityManager.TryGetComponent(args.Target, out ConfigurationComponent? config))
|
||||
{
|
||||
Verb verb = new()
|
||||
{
|
||||
@@ -558,7 +558,7 @@ namespace Content.Server.Administration.Systems
|
||||
|
||||
// Add verb to open Solution Editor
|
||||
if (_groupController.CanCommand(player, "addreagent") &&
|
||||
HasComp<SolutionContainerManagerComponent>(args.Target))
|
||||
EntityManager.HasComponent<SolutionContainerManagerComponent>(args.Target))
|
||||
{
|
||||
Verb verb = new()
|
||||
{
|
||||
|
||||
@@ -2,15 +2,16 @@
|
||||
using Content.Server.Administration;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Shared.Administration;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
namespace Content.Server.AlertLevel.Commands
|
||||
{
|
||||
[UsedImplicitly]
|
||||
[AdminCommand(AdminFlags.Fun)]
|
||||
public sealed class SetAlertLevelCommand : LocalizedEntityCommands
|
||||
public sealed class SetAlertLevelCommand : LocalizedCommands
|
||||
{
|
||||
[Dependency] private readonly AlertLevelSystem _alertLevelSystem = default!;
|
||||
[Dependency] private readonly StationSystem _stationSystem = default!;
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystems = default!;
|
||||
|
||||
public override string Command => "setalertlevel";
|
||||
|
||||
@@ -20,9 +21,11 @@ namespace Content.Server.AlertLevel.Commands
|
||||
var player = shell.Player;
|
||||
if (player?.AttachedEntity != null)
|
||||
{
|
||||
var stationUid = _stationSystem.GetOwningStation(player.AttachedEntity.Value);
|
||||
var stationUid = _entitySystems.GetEntitySystem<StationSystem>().GetOwningStation(player.AttachedEntity.Value);
|
||||
if (stationUid != null)
|
||||
{
|
||||
levelNames = GetStationLevelNames(stationUid.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return args.Length switch
|
||||
@@ -57,7 +60,7 @@ namespace Content.Server.AlertLevel.Commands
|
||||
return;
|
||||
}
|
||||
|
||||
var stationUid = _stationSystem.GetOwningStation(player.AttachedEntity.Value);
|
||||
var stationUid = _entitySystems.GetEntitySystem<StationSystem>().GetOwningStation(player.AttachedEntity.Value);
|
||||
if (stationUid == null)
|
||||
{
|
||||
shell.WriteLine(LocalizationManager.GetString("cmd-setalertlevel-invalid-grid"));
|
||||
@@ -72,12 +75,13 @@ namespace Content.Server.AlertLevel.Commands
|
||||
return;
|
||||
}
|
||||
|
||||
_alertLevelSystem.SetLevel(stationUid.Value, level, true, true, true, locked);
|
||||
_entitySystems.GetEntitySystem<AlertLevelSystem>().SetLevel(stationUid.Value, level, true, true, true, locked);
|
||||
}
|
||||
|
||||
private string[] GetStationLevelNames(EntityUid station)
|
||||
{
|
||||
if (!EntityManager.TryGetComponent<AlertLevelComponent>(station, out var alertLevelComp))
|
||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||
if (!entityManager.TryGetComponent<AlertLevelComponent>(station, out var alertLevelComp))
|
||||
return new string[]{};
|
||||
|
||||
if (alertLevelComp.AlertLevels == null)
|
||||
|
||||
@@ -246,7 +246,7 @@ public sealed class AmeControllerSystem : EntitySystem
|
||||
return;
|
||||
|
||||
var humanReadableState = value ? "Inject" : "Not inject";
|
||||
_adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(user.Value):player} has set the AME to {humanReadableState}");
|
||||
_adminLogger.Add(LogType.Action, LogImpact.Medium, $"{EntityManager.ToPrettyString(user.Value):player} has set the AME to {humanReadableState}");
|
||||
}
|
||||
|
||||
public void ToggleInjecting(EntityUid uid, EntityUid? user = null, AmeControllerComponent? controller = null)
|
||||
@@ -281,7 +281,7 @@ public sealed class AmeControllerSystem : EntitySystem
|
||||
|
||||
var logImpact = (oldValue <= safeLimit && value > safeLimit) ? LogImpact.Extreme : LogImpact.Medium;
|
||||
|
||||
_adminLogger.Add(LogType.Action, logImpact, $"{ToPrettyString(user.Value):player} has set the AME to inject {controller.InjectionAmount} while set to {humanReadableState}");
|
||||
_adminLogger.Add(LogType.Action, logImpact, $"{EntityManager.ToPrettyString(user.Value):player} has set the AME to inject {controller.InjectionAmount} while set to {humanReadableState}");
|
||||
}
|
||||
|
||||
public void AdjustInjectionAmount(EntityUid uid, int delta, EntityUid? user = null, AmeControllerComponent? controller = null)
|
||||
|
||||
@@ -29,7 +29,7 @@ public sealed class BlockGameArcadeSystem : EntitySystem
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
var query = EntityQueryEnumerator<BlockGameArcadeComponent>();
|
||||
var query = EntityManager.EntityQueryEnumerator<BlockGameArcadeComponent>();
|
||||
while (query.MoveNext(out var _, out var blockGame))
|
||||
{
|
||||
blockGame.Game?.GameTick(frameTime);
|
||||
|
||||
@@ -42,7 +42,7 @@ public sealed partial class SpaceVillainArcadeSystem : EntitySystem
|
||||
if (arcade.RewardAmount <= 0)
|
||||
return;
|
||||
|
||||
Spawn(_random.Pick(arcade.PossibleRewards), xform.Coordinates);
|
||||
EntityManager.SpawnEntity(_random.Pick(arcade.PossibleRewards), xform.Coordinates);
|
||||
arcade.RewardAmount--;
|
||||
}
|
||||
|
||||
|
||||
@@ -497,7 +497,7 @@ public sealed class AtmosMonitoringConsoleSystem : SharedAtmosMonitoringConsoleS
|
||||
if (component.NavMapBlip == null)
|
||||
return;
|
||||
|
||||
var netEntity = GetNetEntity(uid);
|
||||
var netEntity = EntityManager.GetNetEntity(uid);
|
||||
var query = AllEntityQuery<AtmosMonitoringConsoleComponent, TransformComponent>();
|
||||
|
||||
while (query.MoveNext(out var ent, out var entConsole, out var entXform))
|
||||
@@ -531,7 +531,7 @@ public sealed class AtmosMonitoringConsoleSystem : SharedAtmosMonitoringConsoleS
|
||||
if (component.NavMapBlip == null)
|
||||
return;
|
||||
|
||||
var netEntity = GetNetEntity(uid);
|
||||
var netEntity = EntityManager.GetNetEntity(uid);
|
||||
var query = AllEntityQuery<AtmosMonitoringConsoleComponent>();
|
||||
|
||||
while (query.MoveNext(out var ent, out var entConsole))
|
||||
|
||||
@@ -122,7 +122,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
|
||||
public void InvalidatePosition(Entity<MapGridComponent?> grid, Vector2i pos)
|
||||
{
|
||||
var query = GetEntityQuery<AirtightComponent>();
|
||||
var query = EntityManager.GetEntityQuery<AirtightComponent>();
|
||||
_explosionSystem.UpdateAirtightMap(grid, pos, grid, query);
|
||||
_atmosphereSystem.InvalidateTile(grid.Owner, pos);
|
||||
}
|
||||
|
||||
@@ -252,128 +252,6 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
Merge(destination, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the dimensionless fraction of gas required to equalize pressure between two gas mixtures.
|
||||
/// </summary>
|
||||
/// <param name="gasMixture1">The first gas mixture involved in the pressure equalization.
|
||||
/// This mixture should be the one you always expect to be the highest pressure.</param>
|
||||
/// <param name="gasMixture2">The second gas mixture involved in the pressure equalization.</param>
|
||||
/// <returns>A float (from 0 to 1) representing the dimensionless fraction of gas that needs to be transferred from the
|
||||
/// mixture of higher pressure to the mixture of lower pressure.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This properly takes into account the effect
|
||||
/// of gas merging from inlet to outlet affecting the temperature
|
||||
/// (and possibly increasing the pressure) in the outlet.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The gas is assumed to expand freely,
|
||||
/// so the temperature of the gas with the greater pressure is not changing.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// If you want to calculate the moles required to equalize pressure between an inlet and an outlet,
|
||||
/// multiply the fraction returned by the source moles.
|
||||
/// </example>
|
||||
public float FractionToEqualizePressure(GasMixture gasMixture1, GasMixture gasMixture2)
|
||||
{
|
||||
/*
|
||||
Problem: the gas being merged from the inlet to the outlet could affect the
|
||||
temp. of the gas and cause a pressure rise.
|
||||
We want the pressure to be equalized, so we have to account for this.
|
||||
|
||||
For clarity, let's assume that gasMixture1 is the inlet and gasMixture2 is the outlet.
|
||||
|
||||
We require mechanical equilibrium, so \( P_1' = P_2' \)
|
||||
|
||||
Before the transfer, we have:
|
||||
\( P_1 = \frac{n_1 R T_1}{V_1} \)
|
||||
\( P_2 = \frac{n_2 R T_2}{V_2} \)
|
||||
|
||||
After removing fraction \( x \) moles from the inlet, we have:
|
||||
\( P_1' = \frac{(1 - x) n_1 R T_1}{V_1} \)
|
||||
|
||||
The outlet will gain the same \( x n_1 \) moles of gas.
|
||||
So \( n_2' = n_2 + x n_1 \)
|
||||
|
||||
After mixing, the outlet temperature will be changed.
|
||||
Denote the new mixture temperature as \( T_2' \).
|
||||
Volume is constant.
|
||||
So we have:
|
||||
\( P_2' = \frac{(n_2 + x n_1) R T_2}{V_2} \)
|
||||
|
||||
The total energy of the incoming inlet to outlet gas at \( T_1 \) plus the existing energy of the outlet gas at \( T_2 \)
|
||||
will be equal to the energy of the new outlet gas at \( T_2' \).
|
||||
This leads to the following derivation:
|
||||
\( x n_1 C_1 T_1 + n_2 C_2 T_2 = (x n_1 C_1 + n_2 C_2) T_2' \)
|
||||
|
||||
Where \( C_1 \) and \( C_2 \) are the heat capacities of the inlet and outlet gases, respectively.
|
||||
|
||||
Solving for \( T_2' \) gives us:
|
||||
\( T_2' = \frac{x n_1 C_1 T_1 + n_2 C_2 T_2}{x n_1 C_1 + n_2 C_2} \)
|
||||
|
||||
Once again, we require mechanical equilibrium (\( P_1' = P_2' \)),
|
||||
so we can substitute \( T_2' \) into the pressure equation:
|
||||
|
||||
\( \frac{(1 - x) n_1 R T_1}{V_1} =
|
||||
\frac{(n_2 + x n_1) R}{V_2} \cdot
|
||||
\frac{x n_1 C_1 T_1 + n_2 C_2 T_2}
|
||||
{x n_1 C_1 + n_2 C_2} \)
|
||||
|
||||
Now it's a matter of solving for \( x \).
|
||||
Not going to show the full derivation here, just steps.
|
||||
1. Cancel common factor \( R \).
|
||||
2. Multiply both sides by \( x n_1 C_1 + n_2 C_2 \), so that everything
|
||||
becomes a polynomial in terms of \( x \).
|
||||
3. Expand both sides.
|
||||
4. Collect like powers of \( x \).
|
||||
5. After collecting, you should end up with a polynomial of the form:
|
||||
|
||||
\( (-n_1 C_1 T_1 (1 + \frac{V_2}{V_1})) x^2 +
|
||||
(n_1 T_1 \frac{V_2}{V_1} (C_1 - C_2) - n_2 C_1 T_1 - n_1 C_2 T_2) x +
|
||||
(n_1 T_1 \frac{V_2}{V_1} C_2 - n_2 C_2 T_2) = 0 \)
|
||||
|
||||
Divide through by \( n_1 C_1 T_1 \) and replace each ratio with a symbol for clarity:
|
||||
\( k_V = \frac{V_2}{V_1} \)
|
||||
\( k_n = \frac{n_2}{n_1} \)
|
||||
\( k_T = \frac{T_2}{T_1} \)
|
||||
\( k_C = \frac{C_2}{C_1} \)
|
||||
*/
|
||||
|
||||
// Ensure that P_1 > P_2 so the quadratic works out.
|
||||
if (gasMixture1.Pressure < gasMixture2.Pressure)
|
||||
{
|
||||
(gasMixture1, gasMixture2) = (gasMixture2, gasMixture1);
|
||||
}
|
||||
|
||||
// Establish the dimensionless ratios.
|
||||
var volumeRatio = gasMixture2.Volume / gasMixture1.Volume;
|
||||
var molesRatio = gasMixture2.TotalMoles / gasMixture1.TotalMoles;
|
||||
var temperatureRatio = gasMixture2.Temperature / gasMixture1.Temperature;
|
||||
var heatCapacityRatio = GetHeatCapacity(gasMixture2) / GetHeatCapacity(gasMixture1);
|
||||
|
||||
// The quadratic equation is solved for the transfer fraction.
|
||||
var quadraticA = 1 + volumeRatio;
|
||||
var quadraticB = molesRatio - volumeRatio + heatCapacityRatio * (temperatureRatio + volumeRatio);
|
||||
var quadraticC = heatCapacityRatio * (molesRatio * temperatureRatio - volumeRatio);
|
||||
|
||||
return (-quadraticB + MathF.Sqrt(quadraticB * quadraticB - 4 * quadraticA * quadraticC)) / (2 * quadraticA);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the number of moles that need to be removed from a <see cref="GasMixture"/> to reach a target pressure threshold.
|
||||
/// </summary>
|
||||
/// <param name="gasMixture">The gas mixture whose moles and properties will be used in the calculation.</param>
|
||||
/// <param name="targetPressure">The target pressure threshold to calculate against.</param>
|
||||
/// <returns>The difference in moles required to reach the target pressure threshold.</returns>
|
||||
/// <remarks>The temperature of the gas is assumed to be not changing due to a free expansion.</remarks>
|
||||
public static float MolesToPressureThreshold(GasMixture gasMixture, float targetPressure)
|
||||
{
|
||||
// Kid named PV = nRT.
|
||||
return gasMixture.TotalMoles -
|
||||
targetPressure * gasMixture.Volume / (Atmospherics.R * gasMixture.Temperature);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a gas mixture is probably safe.
|
||||
/// This only checks temperature and pressure, not gas composition.
|
||||
|
||||
@@ -390,10 +390,10 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
// Note: This is still processed even if space wind is turned off since this handles playing the sounds.
|
||||
|
||||
var number = 0;
|
||||
var bodies = GetEntityQuery<PhysicsComponent>();
|
||||
var xforms = GetEntityQuery<TransformComponent>();
|
||||
var metas = GetEntityQuery<MetaDataComponent>();
|
||||
var pressureQuery = GetEntityQuery<MovedByPressureComponent>();
|
||||
var bodies = EntityManager.GetEntityQuery<PhysicsComponent>();
|
||||
var xforms = EntityManager.GetEntityQuery<TransformComponent>();
|
||||
var metas = EntityManager.GetEntityQuery<MetaDataComponent>();
|
||||
var pressureQuery = EntityManager.GetEntityQuery<MovedByPressureComponent>();
|
||||
|
||||
while (atmosphere.CurrentRunTiles.TryDequeue(out var tile))
|
||||
{
|
||||
|
||||
@@ -120,7 +120,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
|
||||
var otherEnt = args.OtherEntity;
|
||||
|
||||
if (!TryComp(otherEnt, out FlammableComponent? flammable))
|
||||
if (!EntityManager.TryGetComponent(otherEnt, out FlammableComponent? flammable))
|
||||
return;
|
||||
|
||||
//Only ignite when the colliding fixture is projectile or ignition.
|
||||
|
||||
@@ -82,7 +82,7 @@ public sealed class AtmosAlarmableSystem : EntitySystem
|
||||
{
|
||||
if (component.IgnoreAlarms) return;
|
||||
|
||||
if (!TryComp(uid, out DeviceNetworkComponent? netConn))
|
||||
if (!EntityManager.TryGetComponent(uid, out DeviceNetworkComponent? netConn))
|
||||
return;
|
||||
|
||||
if (!args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? cmd)
|
||||
|
||||
@@ -1,202 +0,0 @@
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.NodeContainer.EntitySystems;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.EntitySystems;
|
||||
using Content.Shared.Atmos.Piping;
|
||||
using Content.Shared.Atmos.Piping.Binary.Components;
|
||||
using Content.Shared.Audio;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Atmos.Piping.Binary.EntitySystems;
|
||||
|
||||
/// <summary>
|
||||
/// Handles serverside logic for pressure regulators. Gas will only flow through the regulator
|
||||
/// if the pressure on the inlet side is over a certain pressure threshold.
|
||||
/// See https://en.wikipedia.org/wiki/Pressure_regulator
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed class GasPressureRegulatorSystem : SharedGasPressureRegulatorSystem
|
||||
{
|
||||
[Dependency] private readonly SharedAmbientSoundSystem _ambientSound = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly AtmosphereSystem _atmosphere = default!;
|
||||
[Dependency] private readonly NodeContainerSystem _nodeContainer = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GasPressureRegulatorComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<GasPressureRegulatorComponent, AtmosDeviceUpdateEvent>(OnPressureRegulatorUpdated);
|
||||
SubscribeLocalEvent<GasPressureRegulatorComponent, MapInitEvent>(OnMapInit);
|
||||
}
|
||||
|
||||
private void OnMapInit(Entity<GasPressureRegulatorComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
ent.Comp.NextUiUpdate = _timing.CurTime + ent.Comp.UpdateInterval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dirties the regulator every second or so, so that the UI can update.
|
||||
/// The UI automatically updates after an AutoHandleStateEvent.
|
||||
/// </summary>
|
||||
/// <param name="frameTime"></param>
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<GasPressureRegulatorComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var comp))
|
||||
{
|
||||
if (comp.NextUiUpdate > _timing.CurTime)
|
||||
continue;
|
||||
|
||||
comp.NextUiUpdate += comp.UpdateInterval;
|
||||
|
||||
DirtyFields(uid,
|
||||
comp,
|
||||
null,
|
||||
nameof(comp.InletPressure),
|
||||
nameof(comp.OutletPressure),
|
||||
nameof(comp.FlowRate));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInit(Entity<GasPressureRegulatorComponent> ent, ref ComponentInit args)
|
||||
{
|
||||
UpdateAppearance(ent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the updating logic for the pressure regulator.
|
||||
/// </summary>
|
||||
/// <param name="ent"> the <see cref="Entity{T}" /> of the pressure regulator</param>
|
||||
/// <param name="args"> Args provided to us via <see cref="AtmosDeviceUpdateEvent" /></param>
|
||||
private void OnPressureRegulatorUpdated(Entity<GasPressureRegulatorComponent> ent,
|
||||
ref AtmosDeviceUpdateEvent args)
|
||||
{
|
||||
if (!_nodeContainer.TryGetNodes(ent.Owner,
|
||||
ent.Comp.InletName,
|
||||
ent.Comp.OutletName,
|
||||
out PipeNode? inletPipeNode,
|
||||
out PipeNode? outletPipeNode))
|
||||
{
|
||||
ChangeStatus(false, ent, inletPipeNode, outletPipeNode, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
It's time for some math! :)
|
||||
|
||||
Gas is simply transferred from the inlet to the outlet, restricted by flow rate and pressure.
|
||||
We want to transfer enough gas to bring the inlet pressure below the threshold,
|
||||
and only as much as our max flow rate allows.
|
||||
|
||||
The equations:
|
||||
PV = nRT
|
||||
P1 = P2
|
||||
|
||||
Can be used to calculate the amount of gas we need to transfer.
|
||||
*/
|
||||
|
||||
var p1 = inletPipeNode.Air.Pressure;
|
||||
var p2 = outletPipeNode.Air.Pressure;
|
||||
|
||||
if (p1 <= ent.Comp.Threshold || p2 >= p1)
|
||||
{
|
||||
ChangeStatus(false, ent, inletPipeNode, outletPipeNode, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
var t1 = inletPipeNode.Air.Temperature;
|
||||
|
||||
// First, calculate the amount of gas we need to transfer to bring us below the threshold.
|
||||
var deltaMolesToPressureThreshold =
|
||||
AtmosphereSystem.MolesToPressureThreshold(inletPipeNode.Air, ent.Comp.Threshold);
|
||||
|
||||
// Second, calculate the moles required to equalize the pressure.
|
||||
// We round here to avoid the valve staying enabled for 0.00001 pressure differences.
|
||||
var deltaMolesToEqualizePressure =
|
||||
float.Round(_atmosphere.FractionToEqualizePressure(inletPipeNode.Air, outletPipeNode.Air) *
|
||||
inletPipeNode.Air.TotalMoles,
|
||||
1,
|
||||
MidpointRounding.ToPositiveInfinity);
|
||||
|
||||
// Third, make sure we only transfer the minimum of the two.
|
||||
// We do this so that we don't accidentally transfer so much gas to the point
|
||||
// where the outlet pressure is higher than the inlet.
|
||||
var deltaMolesToTransfer = Math.Min(deltaMolesToPressureThreshold, deltaMolesToEqualizePressure);
|
||||
|
||||
// Fourth, convert to the desired volume to transfer.
|
||||
var desiredVolumeToTransfer = deltaMolesToTransfer * ((Atmospherics.R * t1) / p1);
|
||||
|
||||
// And finally, limit the transfer volume to the max flow rate of the valve.
|
||||
var actualVolumeToTransfer = Math.Min(desiredVolumeToTransfer,
|
||||
ent.Comp.MaxTransferRate * _atmosphere.PumpSpeedup() * args.dt);
|
||||
|
||||
// We remove the gas from the inlet and merge it into the outlet.
|
||||
var removed = inletPipeNode.Air.RemoveVolume(actualVolumeToTransfer);
|
||||
_atmosphere.Merge(outletPipeNode.Air, removed);
|
||||
|
||||
// Calculate the flow rate in L/s for the UI.
|
||||
var sentFlowRate = MathF.Round(actualVolumeToTransfer / args.dt, 1);
|
||||
|
||||
ChangeStatus(true, ent, inletPipeNode, outletPipeNode, sentFlowRate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the visual appearance of the pressure regulator based on its current state.
|
||||
/// </summary>
|
||||
/// <param name="ent">The <see cref="Entity{GasPressureRegulatorComponent, AppearanceComponent}"/>
|
||||
/// representing the pressure regulator with respective components.</param>
|
||||
private void UpdateAppearance(Entity<GasPressureRegulatorComponent> ent)
|
||||
{
|
||||
_appearance.SetData(ent,
|
||||
PressureRegulatorVisuals.State,
|
||||
ent.Comp.Enabled);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the pressure regulator's appearance and sound based on its current state, while
|
||||
/// also preventing network spamming.
|
||||
/// Also prepares data for dirtying.
|
||||
/// </summary>
|
||||
/// <param name="enabled">The new state to set</param>
|
||||
/// <param name="ent">The pressure regulator to update</param>
|
||||
/// <param name="inletNode">The inlet node of the pressure regulator</param>
|
||||
/// <param name="outletNode">The outlet node of the pressure regulator</param>
|
||||
/// <param name="flowRate">Current flow rate of the pressure regulator</param>
|
||||
private void ChangeStatus(bool enabled,
|
||||
Entity<GasPressureRegulatorComponent> ent,
|
||||
PipeNode? inletNode,
|
||||
PipeNode? outletNode,
|
||||
float flowRate)
|
||||
{
|
||||
// First, set data on the component server-side.
|
||||
ent.Comp.InletPressure = inletNode?.Air.Pressure ?? 0f;
|
||||
ent.Comp.OutletPressure = outletNode?.Air.Pressure ?? 0f;
|
||||
ent.Comp.FlowRate = flowRate;
|
||||
|
||||
// We need to prevent spamming the network with updates, so only check if we've
|
||||
// switched states.
|
||||
if (ent.Comp.Enabled == enabled)
|
||||
return;
|
||||
|
||||
ent.Comp.Enabled = enabled;
|
||||
_ambientSound.SetAmbience(ent, enabled);
|
||||
UpdateAppearance(ent);
|
||||
|
||||
// The regulator has changed state, so we need to dirty all applicable fields *right now* so the UI updates
|
||||
// at the same time as everything else.
|
||||
DirtyFields(ent.AsNullable(),
|
||||
null,
|
||||
nameof(ent.Comp.InletPressure),
|
||||
nameof(ent.Comp.OutletPressure),
|
||||
nameof(ent.Comp.FlowRate));
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
|
||||
private void OnExamined(Entity<GasRecyclerComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
var comp = ent.Comp;
|
||||
if (!Comp<TransformComponent>(ent).Anchored || !args.IsInDetailsRange) // Not anchored? Out of range? No status.
|
||||
if (!EntityManager.GetComponent<TransformComponent>(ent).Anchored || !args.IsInDetailsRange) // Not anchored? Out of range? No status.
|
||||
return;
|
||||
|
||||
if (!_nodeContainer.TryGetNode(ent.Owner, comp.InletName, out PipeNode? inlet))
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Content.Server.Atmos.Piping.EntitySystems
|
||||
|
||||
private void OnStartup(EntityUid uid, AtmosPipeColorComponent component, ComponentStartup args)
|
||||
{
|
||||
if (!TryComp(uid, out AppearanceComponent? appearance))
|
||||
if (!EntityManager.TryGetComponent(uid, out AppearanceComponent? appearance))
|
||||
return;
|
||||
|
||||
_appearance.SetData(uid, PipeColorVisuals.Color, component.Color, appearance);
|
||||
@@ -26,7 +26,7 @@ namespace Content.Server.Atmos.Piping.EntitySystems
|
||||
|
||||
private void OnShutdown(EntityUid uid, AtmosPipeColorComponent component, ComponentShutdown args)
|
||||
{
|
||||
if (!TryComp(uid, out AppearanceComponent? appearance))
|
||||
if (!EntityManager.TryGetComponent(uid, out AppearanceComponent? appearance))
|
||||
return;
|
||||
|
||||
_appearance.SetData(uid, PipeColorVisuals.Color, Color.White, appearance);
|
||||
@@ -36,7 +36,7 @@ namespace Content.Server.Atmos.Piping.EntitySystems
|
||||
{
|
||||
component.Color = color;
|
||||
|
||||
if (!TryComp(uid, out AppearanceComponent? appearance))
|
||||
if (!EntityManager.TryGetComponent(uid, out AppearanceComponent? appearance))
|
||||
return;
|
||||
|
||||
_appearance.SetData(uid, PipeColorVisuals.Color, color, appearance);
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Content.Server.Atmos.Piping.EntitySystems
|
||||
|
||||
private void OnUnanchorAttempt(EntityUid uid, AtmosUnsafeUnanchorComponent component, UnanchorAttemptEvent args)
|
||||
{
|
||||
if (!component.Enabled || !TryComp(uid, out NodeContainerComponent? nodes))
|
||||
if (!component.Enabled || !EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodes))
|
||||
return;
|
||||
|
||||
if (_atmosphere.GetContainingMixture(uid, true) is not {} environment)
|
||||
@@ -78,7 +78,7 @@ namespace Content.Server.Atmos.Piping.EntitySystems
|
||||
/// </summary>
|
||||
public void LeakGas(EntityUid uid, bool removeFromPipe = true)
|
||||
{
|
||||
if (!TryComp(uid, out NodeContainerComponent? nodes))
|
||||
if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodes))
|
||||
return;
|
||||
|
||||
if (_atmosphere.GetContainingMixture(uid, true, true) is not { } environment)
|
||||
|
||||
@@ -103,10 +103,10 @@ namespace Content.Server.Atmos.Piping.Trinary.EntitySystems
|
||||
if (args.Handled || !args.Complex)
|
||||
return;
|
||||
|
||||
if (!TryComp(args.User, out ActorComponent? actor))
|
||||
if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor))
|
||||
return;
|
||||
|
||||
if (Comp<TransformComponent>(uid).Anchored)
|
||||
if (EntityManager.GetComponent<TransformComponent>(uid).Anchored)
|
||||
{
|
||||
_userInterfaceSystem.OpenUi(uid, GasFilterUiKey.Key, actor.PlayerSession);
|
||||
DirtyUI(uid, filter);
|
||||
|
||||
@@ -143,7 +143,7 @@ namespace Content.Server.Atmos.Piping.Trinary.EntitySystems
|
||||
if (args.Handled || !args.Complex)
|
||||
return;
|
||||
|
||||
if (!TryComp(args.User, out ActorComponent? actor))
|
||||
if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor))
|
||||
return;
|
||||
|
||||
if (Transform(uid).Anchored)
|
||||
@@ -165,7 +165,7 @@ namespace Content.Server.Atmos.Piping.Trinary.EntitySystems
|
||||
return;
|
||||
|
||||
_userInterfaceSystem.SetUiState(uid, GasMixerUiKey.Key,
|
||||
new GasMixerBoundUserInterfaceState(Comp<MetaDataComponent>(uid).EntityName, mixer.TargetPressure, mixer.Enabled, mixer.InletOneConcentration));
|
||||
new GasMixerBoundUserInterfaceState(EntityManager.GetComponent<MetaDataComponent>(uid).EntityName, mixer.TargetPressure, mixer.Enabled, mixer.InletOneConcentration));
|
||||
}
|
||||
|
||||
private void UpdateAppearance(EntityUid uid, GasMixerComponent? mixer = null, AppearanceComponent? appearance = null)
|
||||
@@ -200,7 +200,7 @@ namespace Content.Server.Atmos.Piping.Trinary.EntitySystems
|
||||
mixer.InletOneConcentration = nodeOne;
|
||||
mixer.InletTwoConcentration = 1.0f - mixer.InletOneConcentration;
|
||||
_adminLogger.Add(LogType.AtmosRatioChanged, LogImpact.Medium,
|
||||
$"{ToPrettyString(args.Actor):player} set the ratio on {ToPrettyString(uid):device} to {mixer.InletOneConcentration}:{mixer.InletTwoConcentration}");
|
||||
$"{EntityManager.ToPrettyString(args.Actor):player} set the ratio on {EntityManager.ToPrettyString(uid):device} to {mixer.InletOneConcentration}:{mixer.InletTwoConcentration}");
|
||||
DirtyUI(uid, mixer);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
|
||||
|
||||
private void OnPortableAnchorAttempt(EntityUid uid, GasPortableComponent component, AnchorAttemptEvent args)
|
||||
{
|
||||
if (!TryComp(uid, out TransformComponent? transform))
|
||||
if (!EntityManager.TryGetComponent(uid, out TransformComponent? transform))
|
||||
return;
|
||||
|
||||
// If we can't find any ports, cancel the anchoring.
|
||||
@@ -52,7 +52,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
|
||||
|
||||
foreach (var entityUid in _mapSystem.GetLocal(gridId.Value, grid, coordinates))
|
||||
{
|
||||
if (TryComp(entityUid, out port))
|
||||
if (EntityManager.TryGetComponent(entityUid, out port))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
|
||||
|
||||
private void OnPacketRecv(EntityUid uid, GasVentPumpComponent component, DeviceNetworkPacketEvent args)
|
||||
{
|
||||
if (!TryComp(uid, out DeviceNetworkComponent? netConn)
|
||||
if (!EntityManager.TryGetComponent(uid, out DeviceNetworkComponent? netConn)
|
||||
|| !args.Data.TryGetValue(DeviceNetworkConstants.Command, out var cmd))
|
||||
return;
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
|
||||
|
||||
private void OnPacketRecv(EntityUid uid, GasVentScrubberComponent component, DeviceNetworkPacketEvent args)
|
||||
{
|
||||
if (!TryComp(uid, out DeviceNetworkComponent? netConn)
|
||||
if (!EntityManager.TryGetComponent(uid, out DeviceNetworkComponent? netConn)
|
||||
|| !args.Data.TryGetValue(DeviceNetworkConstants.Command, out var cmd))
|
||||
return;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Temperature.Components;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Rotting;
|
||||
using Content.Shared.Body.Events;
|
||||
using Content.Shared.Damage;
|
||||
using Robust.Server.Containers;
|
||||
using Robust.Shared.Physics.Components;
|
||||
|
||||
@@ -3,15 +3,12 @@ using Content.Server.GameTicking;
|
||||
using Content.Server.GameTicking.Events;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.Audio.Events;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.GameTicking;
|
||||
using Robust.Server.Audio;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
|
||||
namespace Content.Server.Audio;
|
||||
|
||||
public sealed class ContentAudioSystem : SharedContentAudioSystem
|
||||
@@ -22,36 +19,16 @@ public sealed class ContentAudioSystem : SharedContentAudioSystem
|
||||
[Dependency] private readonly AudioSystem _serverAudio = default!;
|
||||
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
|
||||
private SoundCollectionPrototype? _lobbyMusicCollection = default!;
|
||||
private SoundCollectionPrototype _lobbyMusicCollection = default!;
|
||||
private string[]? _lobbyPlaylist;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
//changes the music collection and reshuffles the playlist to update the lobby music
|
||||
Subs.CVar(
|
||||
_cfg,
|
||||
CCVars.LobbyMusicCollection,
|
||||
x =>
|
||||
{
|
||||
//Checks to see if the sound collection exists. If it does change it if not defaults to null
|
||||
// as the new _lobbyMusicCollection meaning it wont play anything in the lobby.
|
||||
if(_prototypeManager.TryIndex<SoundCollectionPrototype>(x, out var outputSoundCollection))
|
||||
{
|
||||
_lobbyMusicCollection = outputSoundCollection;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"Invalid Lobby Music sound collection specified: {x}");
|
||||
_lobbyMusicCollection = null;
|
||||
}
|
||||
|
||||
_lobbyPlaylist = ShuffleLobbyPlaylist();
|
||||
},
|
||||
true);
|
||||
_lobbyMusicCollection = _prototypeManager.Index<SoundCollectionPrototype>(LobbyMusicCollection);
|
||||
_lobbyPlaylist = ShuffleLobbyPlaylist();
|
||||
|
||||
SubscribeLocalEvent<RoundEndMessageEvent>(OnRoundEnd);
|
||||
SubscribeLocalEvent<PlayerJoinedLobbyEvent>(OnPlayerJoinedLobby);
|
||||
@@ -99,16 +76,11 @@ public sealed class ContentAudioSystem : SharedContentAudioSystem
|
||||
|
||||
private string[] ShuffleLobbyPlaylist()
|
||||
{
|
||||
if (_lobbyMusicCollection == null)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
var playlist = _lobbyMusicCollection.PickFiles
|
||||
.Select(x => x.ToString())
|
||||
.ToArray();
|
||||
_robustRandom.Shuffle(playlist);
|
||||
_robustRandom.Shuffle(playlist);
|
||||
|
||||
return playlist;
|
||||
return playlist;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,8 @@ public sealed class CryostorageSystem : SharedCryostorageSystem
|
||||
EntityUid? entity = null;
|
||||
if (args.Type == CryostorageRemoveItemBuiMessage.RemovalType.Hand)
|
||||
{
|
||||
entity = _hands.GetHeldItem(cryoContained, args.Key);
|
||||
if (_hands.TryGetHand(cryoContained, args.Key, out var hand))
|
||||
entity = hand.HeldEntity;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -319,10 +320,10 @@ public sealed class CryostorageSystem : SharedCryostorageSystem
|
||||
|
||||
foreach (var hand in _hands.EnumerateHands(uid))
|
||||
{
|
||||
if (!_hands.TryGetHeldItem(uid, hand, out var heldEntity))
|
||||
if (hand.HeldEntity == null)
|
||||
continue;
|
||||
|
||||
data.HeldItems.Add(hand, Name(heldEntity.Value));
|
||||
data.HeldItems.Add(hand.Name, Name(hand.HeldEntity.Value));
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace Content.Server.Bible
|
||||
// Clean up the old body
|
||||
if (summonableComp.Summon != null)
|
||||
{
|
||||
Del(summonableComp.Summon.Value);
|
||||
EntityManager.DeleteEntity(summonableComp.Summon.Value);
|
||||
summonableComp.Summon = null;
|
||||
}
|
||||
summonableComp.AlreadySummoned = false;
|
||||
@@ -235,7 +235,7 @@ namespace Content.Server.Bible
|
||||
return;
|
||||
|
||||
// Make this familiar the component's summon
|
||||
var familiar = Spawn(component.SpecialItemPrototype, position.Coordinates);
|
||||
var familiar = EntityManager.SpawnEntity(component.SpecialItemPrototype, position.Coordinates);
|
||||
component.Summon = familiar;
|
||||
|
||||
// If this is going to use a ghost role mob spawner, attach it to the bible.
|
||||
|
||||
7
Content.Server/Body/Components/BeingGibbedEvent.cs
Normal file
7
Content.Server/Body/Components/BeingGibbedEvent.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Content.Server.Body.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when a body gets gibbed, before it is deleted.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public readonly record struct BeingGibbedEvent(HashSet<EntityUid> GibbedParts);
|
||||
186
Content.Server/Body/Components/BloodstreamComponent.cs
Normal file
186
Content.Server/Body/Components/BloodstreamComponent.cs
Normal file
@@ -0,0 +1,186 @@
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.Chemistry.EntitySystems;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
|
||||
namespace Content.Server.Body.Components
|
||||
{
|
||||
[RegisterComponent, Access(typeof(BloodstreamSystem), typeof(ReactionMixerSystem))]
|
||||
public sealed partial class BloodstreamComponent : Component
|
||||
{
|
||||
public static string DefaultChemicalsSolutionName = "chemicals";
|
||||
public static string DefaultBloodSolutionName = "bloodstream";
|
||||
public static string DefaultBloodTemporarySolutionName = "bloodstreamTemporary";
|
||||
|
||||
/// <summary>
|
||||
/// The next time that blood level will be updated and bloodloss damage dealt.
|
||||
/// </summary>
|
||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
|
||||
public TimeSpan NextUpdate;
|
||||
|
||||
/// <summary>
|
||||
/// The interval at which this component updates.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public TimeSpan UpdateInterval = TimeSpan.FromSeconds(3);
|
||||
|
||||
/// <summary>
|
||||
/// How much is this entity currently bleeding?
|
||||
/// Higher numbers mean more blood lost every tick.
|
||||
///
|
||||
/// Goes down slowly over time, and items like bandages
|
||||
/// or clotting reagents can lower bleeding.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This generally corresponds to an amount of damage and can't go above 100.
|
||||
/// </remarks>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float BleedAmount;
|
||||
|
||||
/// <summary>
|
||||
/// How much should bleeding be reduced every update interval?
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float BleedReductionAmount = 0.33f;
|
||||
|
||||
/// <summary>
|
||||
/// How high can <see cref="BleedAmount"/> go?
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float MaxBleedAmount = 10.0f;
|
||||
|
||||
/// <summary>
|
||||
/// What percentage of current blood is necessary to avoid dealing blood loss damage?
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float BloodlossThreshold = 0.9f;
|
||||
|
||||
/// <summary>
|
||||
/// The base bloodloss damage to be incurred if below <see cref="BloodlossThreshold"/>
|
||||
/// The default values are defined per mob/species in YML.
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public DamageSpecifier BloodlossDamage = new();
|
||||
|
||||
/// <summary>
|
||||
/// The base bloodloss damage to be healed if above <see cref="BloodlossThreshold"/>
|
||||
/// The default values are defined per mob/species in YML.
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public DamageSpecifier BloodlossHealDamage = new();
|
||||
|
||||
// TODO shouldn't be hardcoded, should just use some organ simulation like bone marrow or smth.
|
||||
/// <summary>
|
||||
/// How much reagent of blood should be restored each update interval?
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public FixedPoint2 BloodRefreshAmount = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// How much blood needs to be in the temporary solution in order to create a puddle?
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public FixedPoint2 BleedPuddleThreshold = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// A modifier set prototype ID corresponding to how damage should be modified
|
||||
/// before taking it into account for bloodloss.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// For example, piercing damage is increased while poison damage is nullified entirely.
|
||||
/// </remarks>
|
||||
[DataField]
|
||||
public ProtoId<DamageModifierSetPrototype> DamageBleedModifiers = "BloodlossHuman";
|
||||
|
||||
/// <summary>
|
||||
/// The sound to be played when a weapon instantly deals blood loss damage.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public SoundSpecifier InstantBloodSound = new SoundCollectionSpecifier("blood");
|
||||
|
||||
/// <summary>
|
||||
/// The sound to be played when some damage actually heals bleeding rather than starting it.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public SoundSpecifier BloodHealedSound = new SoundPathSpecifier("/Audio/Effects/lightburn.ogg");
|
||||
|
||||
/// <summary>
|
||||
/// The minimum amount damage reduction needed to play the healing sound/popup.
|
||||
/// This prevents tiny amounts of heat damage from spamming the sound, e.g. spacing.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float BloodHealedSoundThreshold = -0.1f;
|
||||
|
||||
// TODO probably damage bleed thresholds.
|
||||
|
||||
/// <summary>
|
||||
/// Max volume of internal chemical solution storage
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public FixedPoint2 ChemicalMaxVolume = FixedPoint2.New(250);
|
||||
|
||||
/// <summary>
|
||||
/// Max volume of internal blood storage,
|
||||
/// and starting level of blood.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public FixedPoint2 BloodMaxVolume = FixedPoint2.New(300);
|
||||
|
||||
/// <summary>
|
||||
/// Which reagent is considered this entities 'blood'?
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Slime-people might use slime as their blood or something like that.
|
||||
/// </remarks>
|
||||
[DataField]
|
||||
public ProtoId<ReagentPrototype> BloodReagent = "Blood";
|
||||
|
||||
/// <summary>Name/Key that <see cref="BloodSolution"/> is indexed by.</summary>
|
||||
[DataField]
|
||||
public string BloodSolutionName = DefaultBloodSolutionName;
|
||||
|
||||
/// <summary>Name/Key that <see cref="ChemicalSolution"/> is indexed by.</summary>
|
||||
[DataField]
|
||||
public string ChemicalSolutionName = DefaultChemicalsSolutionName;
|
||||
|
||||
/// <summary>Name/Key that <see cref="TemporarySolution"/> is indexed by.</summary>
|
||||
[DataField]
|
||||
public string BloodTemporarySolutionName = DefaultBloodTemporarySolutionName;
|
||||
|
||||
/// <summary>
|
||||
/// Internal solution for blood storage
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public Entity<SolutionComponent>? BloodSolution;
|
||||
|
||||
/// <summary>
|
||||
/// Internal solution for reagent storage
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public Entity<SolutionComponent>? ChemicalSolution;
|
||||
|
||||
/// <summary>
|
||||
/// Temporary blood solution.
|
||||
/// When blood is lost, it goes to this solution, and when this
|
||||
/// solution hits a certain cap, the blood is actually spilled as a puddle.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public Entity<SolutionComponent>? TemporarySolution;
|
||||
|
||||
/// <summary>
|
||||
/// Variable that stores the amount of status time added by having a low blood level.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public TimeSpan StatusTime;
|
||||
|
||||
[DataField]
|
||||
public ProtoId<AlertPrototype> BleedingAlert = "Bleed";
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Shared.Body.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Chat.Prototypes;
|
||||
using Content.Shared.Damage;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -11,28 +9,6 @@ namespace Content.Server.Body.Components
|
||||
[RegisterComponent, Access(typeof(RespiratorSystem))]
|
||||
public sealed partial class RespiratorComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Gas container for this entity
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public GasMixture Air = new()
|
||||
{
|
||||
Volume = 6, // 6 liters, the average lung capacity for a human according to Google
|
||||
Temperature = Atmospherics.NormalBodyTemperature
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Volume of our breath in liters
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float BreathVolume = Atmospherics.BreathVolume;
|
||||
|
||||
/// <summary>
|
||||
/// How much of the gas we inhale is metabolized? Value range is (0, 1]
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float Ratio = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The next time that this body will inhale or exhale.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,32 +1,189 @@
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Body.Systems;
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Fluids.EntitySystems;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Body.Events;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.Chemistry.Reaction;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.Drunk;
|
||||
using Content.Shared.EntityEffects.Effects;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Forensics;
|
||||
using Content.Shared.Forensics.Components;
|
||||
using Content.Shared.HealthExaminable;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Rejuvenate;
|
||||
using Content.Shared.Speech.EntitySystems;
|
||||
using Robust.Server.Audio;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Body.Systems;
|
||||
|
||||
public sealed class BloodstreamSystem : SharedBloodstreamSystem
|
||||
public sealed class BloodstreamSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
||||
[Dependency] private readonly AudioSystem _audio = default!;
|
||||
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly PuddleSystem _puddleSystem = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobStateSystem = default!;
|
||||
[Dependency] private readonly SharedDrunkSystem _drunkSystem = default!;
|
||||
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
|
||||
[Dependency] private readonly SharedStutteringSystem _stutteringSystem = default!;
|
||||
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<BloodstreamComponent, ComponentInit>(OnComponentInit);
|
||||
SubscribeLocalEvent<BloodstreamComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<BloodstreamComponent, EntityUnpausedEvent>(OnUnpaused);
|
||||
SubscribeLocalEvent<BloodstreamComponent, DamageChangedEvent>(OnDamageChanged);
|
||||
SubscribeLocalEvent<BloodstreamComponent, HealthBeingExaminedEvent>(OnHealthBeingExamined);
|
||||
SubscribeLocalEvent<BloodstreamComponent, BeingGibbedEvent>(OnBeingGibbed);
|
||||
SubscribeLocalEvent<BloodstreamComponent, ApplyMetabolicMultiplierEvent>(OnApplyMetabolicMultiplier);
|
||||
SubscribeLocalEvent<BloodstreamComponent, ReactionAttemptEvent>(OnReactionAttempt);
|
||||
SubscribeLocalEvent<BloodstreamComponent, SolutionRelayEvent<ReactionAttemptEvent>>(OnReactionAttempt);
|
||||
SubscribeLocalEvent<BloodstreamComponent, RejuvenateEvent>(OnRejuvenate);
|
||||
SubscribeLocalEvent<BloodstreamComponent, GenerateDnaEvent>(OnDnaGenerated);
|
||||
}
|
||||
|
||||
// not sure if we can move this to shared or not
|
||||
// it would certainly help if SolutionContainer was documented
|
||||
// but since we usually don't add the component dynamically to entities we can keep this unpredicted for now
|
||||
private void OnMapInit(Entity<BloodstreamComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
ent.Comp.NextUpdate = _gameTiming.CurTime + ent.Comp.UpdateInterval;
|
||||
}
|
||||
|
||||
private void OnUnpaused(Entity<BloodstreamComponent> ent, ref EntityUnpausedEvent args)
|
||||
{
|
||||
ent.Comp.NextUpdate += args.PausedTime;
|
||||
}
|
||||
|
||||
private void OnReactionAttempt(Entity<BloodstreamComponent> entity, ref ReactionAttemptEvent args)
|
||||
{
|
||||
if (args.Cancelled)
|
||||
return;
|
||||
|
||||
foreach (var effect in args.Reaction.Effects)
|
||||
{
|
||||
switch (effect)
|
||||
{
|
||||
case CreateEntityReactionEffect: // Prevent entities from spawning in the bloodstream
|
||||
case AreaReactionEffect: // No spontaneous smoke or foam leaking out of blood vessels.
|
||||
args.Cancelled = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// The area-reaction effect canceling is part of avoiding smoke-fork-bombs (create two smoke bombs, that when
|
||||
// ingested by mobs create more smoke). This also used to act as a rapid chemical-purge, because all the
|
||||
// reagents would get carried away by the smoke/foam. This does still work for the stomach (I guess people vomit
|
||||
// up the smoke or spawned entities?).
|
||||
|
||||
// TODO apply organ damage instead of just blocking the reaction?
|
||||
// Having cheese-clots form in your veins can't be good for you.
|
||||
}
|
||||
|
||||
private void OnReactionAttempt(Entity<BloodstreamComponent> entity, ref SolutionRelayEvent<ReactionAttemptEvent> args)
|
||||
{
|
||||
if (args.Name != entity.Comp.BloodSolutionName
|
||||
&& args.Name != entity.Comp.ChemicalSolutionName
|
||||
&& args.Name != entity.Comp.BloodTemporarySolutionName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OnReactionAttempt(entity, ref args.Event);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<BloodstreamComponent>();
|
||||
while (query.MoveNext(out var uid, out var bloodstream))
|
||||
{
|
||||
if (_gameTiming.CurTime < bloodstream.NextUpdate)
|
||||
continue;
|
||||
|
||||
bloodstream.NextUpdate += bloodstream.UpdateInterval;
|
||||
|
||||
if (!_solutionContainerSystem.ResolveSolution(uid, bloodstream.BloodSolutionName, ref bloodstream.BloodSolution, out var bloodSolution))
|
||||
continue;
|
||||
|
||||
// Adds blood to their blood level if it is below the maximum; Blood regeneration. Must be alive.
|
||||
if (bloodSolution.Volume < bloodSolution.MaxVolume && !_mobStateSystem.IsDead(uid))
|
||||
{
|
||||
TryModifyBloodLevel(uid, bloodstream.BloodRefreshAmount, bloodstream);
|
||||
}
|
||||
|
||||
// Removes blood from the bloodstream based on bleed amount (bleed rate)
|
||||
// as well as stop their bleeding to a certain extent.
|
||||
if (bloodstream.BleedAmount > 0)
|
||||
{
|
||||
// Blood is removed from the bloodstream at a 1-1 rate with the bleed amount
|
||||
TryModifyBloodLevel(uid, (-bloodstream.BleedAmount), bloodstream);
|
||||
// Bleed rate is reduced by the bleed reduction amount in the bloodstream component.
|
||||
TryModifyBleedAmount(uid, -bloodstream.BleedReductionAmount, bloodstream);
|
||||
}
|
||||
|
||||
// deal bloodloss damage if their blood level is below a threshold.
|
||||
var bloodPercentage = GetBloodLevelPercentage(uid, bloodstream);
|
||||
if (bloodPercentage < bloodstream.BloodlossThreshold && !_mobStateSystem.IsDead(uid))
|
||||
{
|
||||
// bloodloss damage is based on the base value, and modified by how low your blood level is.
|
||||
var amt = bloodstream.BloodlossDamage / (0.1f + bloodPercentage);
|
||||
|
||||
_damageableSystem.TryChangeDamage(uid, amt,
|
||||
ignoreResistances: false, interruptsDoAfters: false);
|
||||
|
||||
// Apply dizziness as a symptom of bloodloss.
|
||||
// The effect is applied in a way that it will never be cleared without being healthy.
|
||||
// Multiplying by 2 is arbitrary but works for this case, it just prevents the time from running out
|
||||
_drunkSystem.TryApplyDrunkenness(
|
||||
uid,
|
||||
(float) bloodstream.UpdateInterval.TotalSeconds * 2,
|
||||
applySlur: false);
|
||||
_stutteringSystem.DoStutter(uid, bloodstream.UpdateInterval * 2, refresh: false);
|
||||
|
||||
// storing the drunk and stutter time so we can remove it independently from other effects additions
|
||||
bloodstream.StatusTime += bloodstream.UpdateInterval * 2;
|
||||
}
|
||||
else if (!_mobStateSystem.IsDead(uid))
|
||||
{
|
||||
// If they're healthy, we'll try and heal some bloodloss instead.
|
||||
_damageableSystem.TryChangeDamage(
|
||||
uid,
|
||||
bloodstream.BloodlossHealDamage * bloodPercentage,
|
||||
ignoreResistances: true, interruptsDoAfters: false);
|
||||
|
||||
// Remove the drunk effect when healthy. Should only remove the amount of drunk and stutter added by low blood level
|
||||
_drunkSystem.TryRemoveDrunkenessTime(uid, bloodstream.StatusTime.TotalSeconds);
|
||||
_stutteringSystem.DoRemoveStutterTime(uid, bloodstream.StatusTime.TotalSeconds);
|
||||
// Reset the drunk and stutter time to zero
|
||||
bloodstream.StatusTime = TimeSpan.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnComponentInit(Entity<BloodstreamComponent> entity, ref ComponentInit args)
|
||||
{
|
||||
if (!SolutionContainer.EnsureSolution(entity.Owner,
|
||||
if (!_solutionContainerSystem.EnsureSolution(entity.Owner,
|
||||
entity.Comp.ChemicalSolutionName,
|
||||
out var chemicalSolution) ||
|
||||
!SolutionContainer.EnsureSolution(entity.Owner,
|
||||
!_solutionContainerSystem.EnsureSolution(entity.Owner,
|
||||
entity.Comp.BloodSolutionName,
|
||||
out var bloodSolution) ||
|
||||
!SolutionContainer.EnsureSolution(entity.Owner,
|
||||
!_solutionContainerSystem.EnsureSolution(entity.Owner,
|
||||
entity.Comp.BloodTemporarySolutionName,
|
||||
out var tempSolution))
|
||||
return;
|
||||
@@ -40,10 +197,298 @@ public sealed class BloodstreamSystem : SharedBloodstreamSystem
|
||||
bloodSolution.AddReagent(new ReagentId(entity.Comp.BloodReagent, GetEntityBloodData(entity.Owner)), entity.Comp.BloodMaxVolume - bloodSolution.Volume);
|
||||
}
|
||||
|
||||
// forensics is not predicted yet
|
||||
private void OnDamageChanged(Entity<BloodstreamComponent> ent, ref DamageChangedEvent args)
|
||||
{
|
||||
if (args.DamageDelta is null || !args.DamageIncreased)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO probably cache this or something. humans get hurt a lot
|
||||
if (!_prototypeManager.TryIndex(ent.Comp.DamageBleedModifiers, out var modifiers))
|
||||
return;
|
||||
|
||||
// some reagents may deal and heal different damage types in the same tick, which means DamageIncreased will be true
|
||||
// but we only want to consider the dealt damage when causing bleeding
|
||||
var damage = DamageSpecifier.GetPositive(args.DamageDelta);
|
||||
var bloodloss = DamageSpecifier.ApplyModifierSet(damage, modifiers);
|
||||
|
||||
if (bloodloss.Empty)
|
||||
return;
|
||||
|
||||
// Does the calculation of how much bleed rate should be added/removed, then applies it
|
||||
var oldBleedAmount = ent.Comp.BleedAmount;
|
||||
var total = bloodloss.GetTotal();
|
||||
var totalFloat = total.Float();
|
||||
TryModifyBleedAmount(ent, totalFloat, ent);
|
||||
|
||||
/// <summary>
|
||||
/// Critical hit. Causes target to lose blood, using the bleed rate modifier of the weapon, currently divided by 5
|
||||
/// The crit chance is currently the bleed rate modifier divided by 25.
|
||||
/// Higher damage weapons have a higher chance to crit!
|
||||
/// </summary>
|
||||
var prob = Math.Clamp(totalFloat / 25, 0, 1);
|
||||
if (totalFloat > 0 && _robustRandom.Prob(prob))
|
||||
{
|
||||
TryModifyBloodLevel(ent, -total / 5, ent);
|
||||
_audio.PlayPvs(ent.Comp.InstantBloodSound, ent);
|
||||
}
|
||||
|
||||
// Heat damage will cauterize, causing the bleed rate to be reduced.
|
||||
else if (totalFloat <= ent.Comp.BloodHealedSoundThreshold && oldBleedAmount > 0)
|
||||
{
|
||||
// Magically, this damage has healed some bleeding, likely
|
||||
// because it's burn damage that cauterized their wounds.
|
||||
|
||||
// We'll play a special sound and popup for feedback.
|
||||
_audio.PlayPvs(ent.Comp.BloodHealedSound, ent);
|
||||
_popupSystem.PopupEntity(Loc.GetString("bloodstream-component-wounds-cauterized"), ent,
|
||||
ent, PopupType.Medium);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Shows text on health examine, based on bleed rate and blood level.
|
||||
/// </summary>
|
||||
private void OnHealthBeingExamined(Entity<BloodstreamComponent> ent, ref HealthBeingExaminedEvent args)
|
||||
{
|
||||
// Shows massively bleeding at 0.75x the max bleed rate.
|
||||
if (ent.Comp.BleedAmount > ent.Comp.MaxBleedAmount * 0.75f)
|
||||
{
|
||||
args.Message.PushNewline();
|
||||
args.Message.AddMarkupOrThrow(Loc.GetString("bloodstream-component-massive-bleeding", ("target", ent.Owner)));
|
||||
}
|
||||
// Shows bleeding message when bleeding above half the max rate, but less than massively.
|
||||
else if (ent.Comp.BleedAmount > ent.Comp.MaxBleedAmount * 0.5f)
|
||||
{
|
||||
args.Message.PushNewline();
|
||||
args.Message.AddMarkupOrThrow(Loc.GetString("bloodstream-component-strong-bleeding", ("target", ent.Owner)));
|
||||
}
|
||||
// Shows bleeding message when bleeding above 0.25x the max rate, but less than half the max.
|
||||
else if (ent.Comp.BleedAmount > ent.Comp.MaxBleedAmount * 0.25f)
|
||||
{
|
||||
args.Message.PushNewline();
|
||||
args.Message.AddMarkupOrThrow(Loc.GetString("bloodstream-component-bleeding", ("target", ent.Owner)));
|
||||
}
|
||||
// Shows bleeding message when bleeding below 0.25x the max cap
|
||||
else if (ent.Comp.BleedAmount > 0)
|
||||
{
|
||||
args.Message.PushNewline();
|
||||
args.Message.AddMarkupOrThrow(Loc.GetString("bloodstream-component-slight-bleeding", ("target", ent.Owner)));
|
||||
}
|
||||
|
||||
// If the mob's blood level is below the damage threshhold, the pale message is added.
|
||||
if (GetBloodLevelPercentage(ent, ent) < ent.Comp.BloodlossThreshold)
|
||||
{
|
||||
args.Message.PushNewline();
|
||||
args.Message.AddMarkupOrThrow(Loc.GetString("bloodstream-component-looks-pale", ("target", ent.Owner)));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBeingGibbed(Entity<BloodstreamComponent> ent, ref BeingGibbedEvent args)
|
||||
{
|
||||
SpillAllSolutions(ent, ent);
|
||||
}
|
||||
|
||||
private void OnApplyMetabolicMultiplier(
|
||||
Entity<BloodstreamComponent> ent,
|
||||
ref ApplyMetabolicMultiplierEvent args)
|
||||
{
|
||||
// TODO REFACTOR THIS
|
||||
// This will slowly drift over time due to floating point errors.
|
||||
// Instead, raise an event with the base rates and allow modifiers to get applied to it.
|
||||
if (args.Apply)
|
||||
{
|
||||
ent.Comp.UpdateInterval *= args.Multiplier;
|
||||
return;
|
||||
}
|
||||
ent.Comp.UpdateInterval /= args.Multiplier;
|
||||
}
|
||||
|
||||
private void OnRejuvenate(Entity<BloodstreamComponent> entity, ref RejuvenateEvent args)
|
||||
{
|
||||
TryModifyBleedAmount(entity.Owner, -entity.Comp.BleedAmount, entity.Comp);
|
||||
|
||||
if (_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.BloodSolutionName, ref entity.Comp.BloodSolution, out var bloodSolution))
|
||||
TryModifyBloodLevel(entity.Owner, bloodSolution.AvailableVolume, entity.Comp);
|
||||
|
||||
if (_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.ChemicalSolutionName, ref entity.Comp.ChemicalSolution))
|
||||
_solutionContainerSystem.RemoveAllSolution(entity.Comp.ChemicalSolution.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to transfer provided solution to internal solution.
|
||||
/// </summary>
|
||||
public bool TryAddToChemicals(EntityUid uid, Solution solution, BloodstreamComponent? component = null)
|
||||
{
|
||||
return Resolve(uid, ref component, logMissing: false)
|
||||
&& _solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution)
|
||||
&& _solutionContainerSystem.TryAddSolution(component.ChemicalSolution.Value, solution);
|
||||
}
|
||||
|
||||
public bool FlushChemicals(EntityUid uid, string excludedReagentID, FixedPoint2 quantity, BloodstreamComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component, logMissing: false)
|
||||
|| !_solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution, out var chemSolution))
|
||||
return false;
|
||||
|
||||
for (var i = chemSolution.Contents.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var (reagentId, _) = chemSolution.Contents[i];
|
||||
if (reagentId.Prototype != excludedReagentID)
|
||||
{
|
||||
_solutionContainerSystem.RemoveReagent(component.ChemicalSolution.Value, reagentId, quantity);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public float GetBloodLevelPercentage(EntityUid uid, BloodstreamComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component)
|
||||
|| !_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution, out var bloodSolution))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return bloodSolution.FillFraction;
|
||||
}
|
||||
|
||||
public void SetBloodLossThreshold(EntityUid uid, float threshold, BloodstreamComponent? comp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref comp))
|
||||
return;
|
||||
|
||||
comp.BloodlossThreshold = threshold;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to modify the blood level of this entity directly.
|
||||
/// </summary>
|
||||
public bool TryModifyBloodLevel(EntityUid uid, FixedPoint2 amount, BloodstreamComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component, logMissing: false)
|
||||
|| !_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (amount >= 0)
|
||||
return _solutionContainerSystem.TryAddReagent(component.BloodSolution.Value, component.BloodReagent, amount, null, GetEntityBloodData(uid));
|
||||
|
||||
// Removal is more involved,
|
||||
// since we also wanna handle moving it to the temporary solution
|
||||
// and then spilling it if necessary.
|
||||
var newSol = _solutionContainerSystem.SplitSolution(component.BloodSolution.Value, -amount);
|
||||
|
||||
if (!_solutionContainerSystem.ResolveSolution(uid, component.BloodTemporarySolutionName, ref component.TemporarySolution, out var tempSolution))
|
||||
return true;
|
||||
|
||||
tempSolution.AddSolution(newSol, _prototypeManager);
|
||||
|
||||
if (tempSolution.Volume > component.BleedPuddleThreshold)
|
||||
{
|
||||
// Pass some of the chemstream into the spilled blood.
|
||||
if (_solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution))
|
||||
{
|
||||
var temp = _solutionContainerSystem.SplitSolution(component.ChemicalSolution.Value, tempSolution.Volume / 10);
|
||||
tempSolution.AddSolution(temp, _prototypeManager);
|
||||
}
|
||||
|
||||
_puddleSystem.TrySpillAt(uid, tempSolution, out var puddleUid, sound: false);
|
||||
|
||||
tempSolution.RemoveAllSolution();
|
||||
}
|
||||
|
||||
_solutionContainerSystem.UpdateChemicals(component.TemporarySolution.Value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to make an entity bleed more or less
|
||||
/// </summary>
|
||||
public bool TryModifyBleedAmount(EntityUid uid, float amount, BloodstreamComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component, logMissing: false))
|
||||
return false;
|
||||
|
||||
component.BleedAmount += amount;
|
||||
component.BleedAmount = Math.Clamp(component.BleedAmount, 0, component.MaxBleedAmount);
|
||||
|
||||
if (component.BleedAmount == 0)
|
||||
_alertsSystem.ClearAlert(uid, component.BleedingAlert);
|
||||
else
|
||||
{
|
||||
var severity = (short) Math.Clamp(Math.Round(component.BleedAmount, MidpointRounding.ToZero), 0, 10);
|
||||
_alertsSystem.ShowAlert(uid, component.BleedingAlert, severity);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// BLOOD FOR THE BLOOD GOD
|
||||
/// </summary>
|
||||
public void SpillAllSolutions(EntityUid uid, BloodstreamComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return;
|
||||
|
||||
var tempSol = new Solution();
|
||||
|
||||
if (_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution, out var bloodSolution))
|
||||
{
|
||||
tempSol.MaxVolume += bloodSolution.MaxVolume;
|
||||
tempSol.AddSolution(bloodSolution, _prototypeManager);
|
||||
_solutionContainerSystem.RemoveAllSolution(component.BloodSolution.Value);
|
||||
}
|
||||
|
||||
if (_solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution, out var chemSolution))
|
||||
{
|
||||
tempSol.MaxVolume += chemSolution.MaxVolume;
|
||||
tempSol.AddSolution(chemSolution, _prototypeManager);
|
||||
_solutionContainerSystem.RemoveAllSolution(component.ChemicalSolution.Value);
|
||||
}
|
||||
|
||||
if (_solutionContainerSystem.ResolveSolution(uid, component.BloodTemporarySolutionName, ref component.TemporarySolution, out var tempSolution))
|
||||
{
|
||||
tempSol.MaxVolume += tempSolution.MaxVolume;
|
||||
tempSol.AddSolution(tempSolution, _prototypeManager);
|
||||
_solutionContainerSystem.RemoveAllSolution(component.TemporarySolution.Value);
|
||||
}
|
||||
|
||||
_puddleSystem.TrySpillAt(uid, tempSol, out var puddleUid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Change what someone's blood is made of, on the fly.
|
||||
/// </summary>
|
||||
public void ChangeBloodReagent(EntityUid uid, string reagent, BloodstreamComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component, logMissing: false)
|
||||
|| reagent == component.BloodReagent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution, out var bloodSolution))
|
||||
{
|
||||
component.BloodReagent = reagent;
|
||||
return;
|
||||
}
|
||||
|
||||
var currentVolume = bloodSolution.RemoveReagent(component.BloodReagent, bloodSolution.Volume, ignoreReagentData: true);
|
||||
|
||||
component.BloodReagent = reagent;
|
||||
|
||||
if (currentVolume > 0)
|
||||
_solutionContainerSystem.TryAddReagent(component.BloodSolution.Value, component.BloodReagent, currentVolume, null, GetEntityBloodData(uid));
|
||||
}
|
||||
|
||||
private void OnDnaGenerated(Entity<BloodstreamComponent> entity, ref GenerateDnaEvent args)
|
||||
{
|
||||
if (SolutionContainer.ResolveSolution(entity.Owner, entity.Comp.BloodSolutionName, ref entity.Comp.BloodSolution, out var bloodSolution))
|
||||
if (_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.BloodSolutionName, ref entity.Comp.BloodSolution, out var bloodSolution))
|
||||
{
|
||||
foreach (var reagent in bloodSolution.Contents)
|
||||
{
|
||||
@@ -55,4 +500,22 @@ public sealed class BloodstreamSystem : SharedBloodstreamSystem
|
||||
else
|
||||
Log.Error("Unable to set bloodstream DNA, solution entity could not be resolved");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the reagent data for blood that a specific entity should have.
|
||||
/// </summary>
|
||||
public List<ReagentData> GetEntityBloodData(EntityUid uid)
|
||||
{
|
||||
var bloodData = new List<ReagentData>();
|
||||
var dnaData = new DnaData();
|
||||
|
||||
if (TryComp<DnaComponent>(uid, out var donorComp) && donorComp.DNA != null)
|
||||
dnaData.DNA = donorComp.DNA;
|
||||
else
|
||||
dnaData.DNA = Loc.GetString("forensics-dna-unknown");
|
||||
|
||||
bloodData.Add(dnaData);
|
||||
|
||||
return bloodData;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Numerics;
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Ghost;
|
||||
using Content.Server.Humanoid;
|
||||
using Content.Shared.Body.Components;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Atmos;
|
||||
@@ -59,7 +58,7 @@ public sealed class InternalsSystem : SharedInternalsSystem
|
||||
if (AreInternalsWorking(ent))
|
||||
{
|
||||
var gasTank = Comp<GasTankComponent>(ent.Comp.GasTankEntity!.Value);
|
||||
args.Gas = _gasTank.RemoveAirVolume((ent.Comp.GasTankEntity.Value, gasTank), args.Respirator.BreathVolume);
|
||||
args.Gas = _gasTank.RemoveAirVolume((ent.Comp.GasTankEntity.Value, gasTank), Atmospherics.BreathVolume);
|
||||
// TODO: Should listen to gas tank updates instead I guess?
|
||||
_alerts.ShowAlert(ent, ent.Comp.InternalsAlert, GetSeverity(ent));
|
||||
}
|
||||
|
||||
@@ -63,9 +63,6 @@ public sealed class LungSystem : EntitySystem
|
||||
_solutionContainerSystem.UpdateChemicals(lung.Solution.Value);
|
||||
}
|
||||
|
||||
/* This should really be moved to somewhere in the atmos system and modernized,
|
||||
so that other systems, like CondenserSystem, can use it.
|
||||
*/
|
||||
private void GasToReagent(GasMixture gas, Solution solution)
|
||||
{
|
||||
foreach (var gasId in Enum.GetValues<Gas>())
|
||||
|
||||
@@ -50,8 +50,6 @@ public sealed class RespiratorSystem : EntitySystem
|
||||
SubscribeLocalEvent<RespiratorComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<RespiratorComponent, EntityUnpausedEvent>(OnUnpaused);
|
||||
SubscribeLocalEvent<RespiratorComponent, ApplyMetabolicMultiplierEvent>(OnApplyMetabolicMultiplier);
|
||||
SubscribeLocalEvent<BodyComponent, InhaledGasEvent>(OnGasInhaled);
|
||||
SubscribeLocalEvent<BodyComponent, ExhaledGasEvent>(OnGasExhaled);
|
||||
}
|
||||
|
||||
private void OnMapInit(Entity<RespiratorComponent> ent, ref MapInitEvent args)
|
||||
@@ -79,18 +77,18 @@ public sealed class RespiratorSystem : EntitySystem
|
||||
if (_mobState.IsDead(uid))
|
||||
continue;
|
||||
|
||||
UpdateSaturation(uid, -(float)respirator.UpdateInterval.TotalSeconds, respirator);
|
||||
UpdateSaturation(uid, -(float) respirator.UpdateInterval.TotalSeconds, respirator);
|
||||
|
||||
if (!_mobState.IsIncapacitated(uid)) // cannot breathe in crit.
|
||||
{
|
||||
switch (respirator.Status)
|
||||
{
|
||||
case RespiratorStatus.Inhaling:
|
||||
Inhale(uid);
|
||||
Inhale(uid, body);
|
||||
respirator.Status = RespiratorStatus.Exhaling;
|
||||
break;
|
||||
case RespiratorStatus.Exhaling:
|
||||
Exhale(uid);
|
||||
Exhale(uid, body);
|
||||
respirator.Status = RespiratorStatus.Inhaling;
|
||||
break;
|
||||
}
|
||||
@@ -101,10 +99,7 @@ public sealed class RespiratorSystem : EntitySystem
|
||||
if (_gameTiming.CurTime >= respirator.LastGaspEmoteTime + respirator.GaspEmoteCooldown)
|
||||
{
|
||||
respirator.LastGaspEmoteTime = _gameTiming.CurTime;
|
||||
_chat.TryEmoteWithChat(uid,
|
||||
respirator.GaspEmote,
|
||||
ChatTransmitRange.HideChat,
|
||||
ignoreActionBlocker: true);
|
||||
_chat.TryEmoteWithChat(uid, respirator.GaspEmote, ChatTransmitRange.HideChat, ignoreActionBlocker: true);
|
||||
}
|
||||
|
||||
TakeSuffocationDamage((uid, respirator));
|
||||
@@ -117,54 +112,68 @@ public sealed class RespiratorSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
public bool Inhale(Entity<RespiratorComponent?> entity)
|
||||
public void Inhale(EntityUid uid, BodyComponent? body = null)
|
||||
{
|
||||
if (!Resolve(entity, ref entity.Comp, logMissing: false))
|
||||
return false;
|
||||
if (!Resolve(uid, ref body, logMissing: false))
|
||||
return;
|
||||
|
||||
var organs = _bodySystem.GetBodyOrganEntityComps<LungComponent>((uid, body));
|
||||
|
||||
// Inhale gas
|
||||
var ev = new InhaleLocationEvent
|
||||
{
|
||||
Respirator = entity.Comp,
|
||||
};
|
||||
RaiseLocalEvent(entity, ref ev);
|
||||
var ev = new InhaleLocationEvent();
|
||||
RaiseLocalEvent(uid, ref ev);
|
||||
|
||||
ev.Gas ??= _atmosSys.GetContainingMixture(entity.Owner, excite: true);
|
||||
ev.Gas ??= _atmosSys.GetContainingMixture(uid, excite: true);
|
||||
|
||||
if (ev.Gas is null)
|
||||
{
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
var gas = ev.Gas.RemoveVolume(entity.Comp.BreathVolume);
|
||||
var actualGas = ev.Gas.RemoveVolume(Atmospherics.BreathVolume);
|
||||
|
||||
var inhaleEv = new InhaledGasEvent(gas);
|
||||
RaiseLocalEvent(entity, ref inhaleEv);
|
||||
|
||||
return inhaleEv.Handled && inhaleEv.Succeeded;
|
||||
var lungRatio = 1.0f / organs.Count;
|
||||
var gas = organs.Count == 1 ? actualGas : actualGas.RemoveRatio(lungRatio);
|
||||
foreach (var (organUid, lung, _) in organs)
|
||||
{
|
||||
// Merge doesn't remove gas from the giver.
|
||||
_atmosSys.Merge(lung.Air, gas);
|
||||
_lungSystem.GasToReagent(organUid, lung);
|
||||
}
|
||||
}
|
||||
|
||||
public void Exhale(Entity<RespiratorComponent?> entity)
|
||||
public void Exhale(EntityUid uid, BodyComponent? body = null)
|
||||
{
|
||||
if (!Resolve(entity, ref entity.Comp, logMissing: false))
|
||||
if (!Resolve(uid, ref body, logMissing: false))
|
||||
return;
|
||||
|
||||
var organs = _bodySystem.GetBodyOrganEntityComps<LungComponent>((uid, body));
|
||||
|
||||
// exhale gas
|
||||
|
||||
var ev = new ExhaleLocationEvent();
|
||||
RaiseLocalEvent(entity, ref ev, broadcast: false);
|
||||
RaiseLocalEvent(uid, ref ev, broadcast: false);
|
||||
|
||||
if (ev.Gas is null)
|
||||
{
|
||||
ev.Gas = _atmosSys.GetContainingMixture(entity.Owner, excite: true);
|
||||
ev.Gas = _atmosSys.GetContainingMixture(uid, excite: true);
|
||||
|
||||
// Walls and grids without atmos comp return null. I guess it makes sense to not be able to exhale in walls,
|
||||
// but this also means you cannot exhale on some grids.
|
||||
ev.Gas ??= GasMixture.SpaceGas;
|
||||
}
|
||||
|
||||
var exhaleEv = new ExhaledGasEvent(ev.Gas);
|
||||
RaiseLocalEvent(entity, ref exhaleEv);
|
||||
var outGas = new GasMixture(ev.Gas.Volume);
|
||||
foreach (var (organUid, lung, _) in organs)
|
||||
{
|
||||
_atmosSys.Merge(outGas, lung.Air);
|
||||
lung.Air.Clear();
|
||||
|
||||
if (_solutionContainerSystem.ResolveSolution(organUid, lung.SolutionName, ref lung.Solution))
|
||||
_solutionContainerSystem.RemoveAllSolution(lung.Solution.Value);
|
||||
}
|
||||
|
||||
_atmosSys.Merge(ev.Gas, outGas);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -190,15 +199,14 @@ public sealed class RespiratorSystem : EntitySystem
|
||||
if (!Resolve(ent, ref ent.Comp))
|
||||
return false;
|
||||
|
||||
if (!Inhale(ent))
|
||||
var ev = new InhaleLocationEvent();
|
||||
RaiseLocalEvent(ent, ref ev);
|
||||
|
||||
var gas = ev.Gas ?? _atmosSys.GetContainingMixture(ent.Owner);
|
||||
if (gas == null)
|
||||
return false;
|
||||
|
||||
// If we don't have a body we can't be poisoned by gas, yet...
|
||||
var success = TryMetabolizeGas((ent, ent.Comp));
|
||||
|
||||
// Don't keep that gas in our lungs lest it poisons a poor nuclear operative.
|
||||
Exhale(ent);
|
||||
return success;
|
||||
return CanMetabolizeGas(ent, gas);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -216,7 +224,7 @@ public sealed class RespiratorSystem : EntitySystem
|
||||
|
||||
gas = new GasMixture(gas);
|
||||
var lungRatio = 1.0f / organs.Count;
|
||||
gas.Multiply(MathF.Min(lungRatio * gas.Volume / ent.Comp.BreathVolume, lungRatio));
|
||||
gas.Multiply(MathF.Min(lungRatio * gas.Volume/Atmospherics.BreathVolume, lungRatio));
|
||||
var solution = _lungSystem.GasToReagent(gas);
|
||||
|
||||
float saturation = 0;
|
||||
@@ -230,71 +238,6 @@ public sealed class RespiratorSystem : EntitySystem
|
||||
return saturation > ent.Comp.UpdateInterval.TotalSeconds;
|
||||
}
|
||||
|
||||
public bool TryInhaleGasToBody(Entity<BodyComponent?> entity, GasMixture gas)
|
||||
{
|
||||
if (!Resolve(entity, ref entity.Comp))
|
||||
return false;
|
||||
|
||||
var organs = _bodySystem.GetBodyOrganEntityComps<LungComponent>((entity, entity.Comp));
|
||||
if (organs.Count == 0)
|
||||
return false;
|
||||
|
||||
var lungRatio = 1.0f / organs.Count;
|
||||
var splitGas = organs.Count == 1 ? gas : gas.RemoveRatio(lungRatio);
|
||||
foreach (var (organUid, lung, _) in organs)
|
||||
{
|
||||
// Merge doesn't remove gas from the giver.
|
||||
_atmosSys.Merge(lung.Air, splitGas);
|
||||
_lungSystem.GasToReagent(organUid, lung);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void RemoveGasFromBody(Entity<BodyComponent> ent, GasMixture gas)
|
||||
{
|
||||
var outGas = new GasMixture(gas.Volume);
|
||||
|
||||
var organs = _bodySystem.GetBodyOrganEntityComps<LungComponent>((ent, ent.Comp));
|
||||
if (organs.Count == 0)
|
||||
return;
|
||||
|
||||
foreach (var (organUid, lung, _) in organs)
|
||||
{
|
||||
_atmosSys.Merge(outGas, lung.Air);
|
||||
lung.Air.Clear();
|
||||
|
||||
if (_solutionContainerSystem.ResolveSolution(organUid, lung.SolutionName, ref lung.Solution))
|
||||
_solutionContainerSystem.RemoveAllSolution(lung.Solution.Value);
|
||||
}
|
||||
|
||||
_atmosSys.Merge(gas, outGas);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to safely metabolize the current solutions in a body's lungs.
|
||||
/// </summary>
|
||||
private bool TryMetabolizeGas(Entity<RespiratorComponent, BodyComponent?> ent)
|
||||
{
|
||||
if (!Resolve(ent, ref ent.Comp2))
|
||||
return false;
|
||||
|
||||
var organs = _bodySystem.GetBodyOrganEntityComps<LungComponent>((ent, null));
|
||||
if (organs.Count == 0)
|
||||
return false;
|
||||
|
||||
float saturation = 0;
|
||||
foreach (var organ in organs)
|
||||
{
|
||||
var solution = _lungSystem.GasToReagent(organ.Comp1.Air);
|
||||
saturation += GetSaturation(solution, organ.Owner, out var toxic);
|
||||
if (toxic)
|
||||
return false;
|
||||
}
|
||||
|
||||
return saturation > ent.Comp1.UpdateInterval.TotalSeconds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the amount of saturation that would be generated if the lung were to metabolize the given solution.
|
||||
/// </summary>
|
||||
@@ -358,8 +301,6 @@ public sealed class RespiratorSystem : EntitySystem
|
||||
if (ent.Comp.SuffocationCycles == 2)
|
||||
_adminLogger.Add(LogType.Asphyxiation, $"{ToPrettyString(ent):entity} started suffocating");
|
||||
|
||||
_damageableSys.TryChangeDamage(ent, ent.Comp.Damage, interruptsDoAfters: false);
|
||||
|
||||
if (ent.Comp.SuffocationCycles >= ent.Comp.SuffocationCycleThreshold)
|
||||
{
|
||||
// TODO: This is not going work with multiple different lungs, if that ever becomes a possibility
|
||||
@@ -369,6 +310,8 @@ public sealed class RespiratorSystem : EntitySystem
|
||||
_alertsSystem.ShowAlert(ent, entity.Comp1.Alert);
|
||||
}
|
||||
}
|
||||
|
||||
_damageableSys.TryChangeDamage(ent, ent.Comp.Damage, interruptsDoAfters: false);
|
||||
}
|
||||
|
||||
private void StopSuffocation(Entity<RespiratorComponent> ent)
|
||||
@@ -376,17 +319,18 @@ public sealed class RespiratorSystem : EntitySystem
|
||||
if (ent.Comp.SuffocationCycles >= 2)
|
||||
_adminLogger.Add(LogType.Asphyxiation, $"{ToPrettyString(ent):entity} stopped suffocating");
|
||||
|
||||
_damageableSys.TryChangeDamage(ent, ent.Comp.DamageRecovery);
|
||||
|
||||
// TODO: This is not going work with multiple different lungs, if that ever becomes a possibility
|
||||
var organs = _bodySystem.GetBodyOrganEntityComps<LungComponent>((ent, null));
|
||||
foreach (var entity in organs)
|
||||
{
|
||||
_alertsSystem.ClearAlert(ent, entity.Comp1.Alert);
|
||||
}
|
||||
|
||||
_damageableSys.TryChangeDamage(ent, ent.Comp.DamageRecovery);
|
||||
}
|
||||
|
||||
public void UpdateSaturation(EntityUid uid, float amount, RespiratorComponent? respirator = null)
|
||||
public void UpdateSaturation(EntityUid uid, float amount,
|
||||
RespiratorComponent? respirator = null)
|
||||
{
|
||||
if (!Resolve(uid, ref respirator, false))
|
||||
return;
|
||||
@@ -418,30 +362,10 @@ public sealed class RespiratorSystem : EntitySystem
|
||||
ent.Comp.MaxSaturation /= args.Multiplier;
|
||||
ent.Comp.MinSaturation /= args.Multiplier;
|
||||
}
|
||||
|
||||
private void OnGasInhaled(Entity<BodyComponent> entity, ref InhaledGasEvent args)
|
||||
{
|
||||
args.Handled = true;
|
||||
|
||||
args.Succeeded = TryInhaleGasToBody((entity, entity.Comp), args.Gas);
|
||||
}
|
||||
|
||||
private void OnGasExhaled(Entity<BodyComponent> entity, ref ExhaledGasEvent args)
|
||||
{
|
||||
args.Handled = true;
|
||||
|
||||
RemoveGasFromBody(entity, args.Gas);
|
||||
}
|
||||
}
|
||||
|
||||
[ByRefEvent]
|
||||
public record struct InhaleLocationEvent(GasMixture? Gas, RespiratorComponent Respirator);
|
||||
public record struct InhaleLocationEvent(GasMixture? Gas);
|
||||
|
||||
[ByRefEvent]
|
||||
public record struct ExhaleLocationEvent(GasMixture? Gas);
|
||||
|
||||
[ByRefEvent]
|
||||
public record struct InhaledGasEvent(GasMixture Gas, bool Handled = false, bool Succeeded = false);
|
||||
|
||||
[ByRefEvent]
|
||||
public record struct ExhaledGasEvent(GasMixture Gas, bool Handled = false);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Botany.Components;
|
||||
using Content.Server.Hands.Systems;
|
||||
using Content.Server.Kitchen.Components;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
@@ -38,7 +37,6 @@ public sealed class PlantHolderSystem : EntitySystem
|
||||
[Dependency] private readonly MutationSystem _mutation = default!;
|
||||
[Dependency] private readonly AppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly HandsSystem _hands = default!;
|
||||
[Dependency] private readonly PopupSystem _popup = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
|
||||
@@ -47,7 +45,7 @@ public sealed class PlantHolderSystem : EntitySystem
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
|
||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||
|
||||
|
||||
public const float HydroponicsSpeedMultiplier = 1f;
|
||||
public const float HydroponicsConsumptionMultiplier = 2f;
|
||||
|
||||
@@ -708,9 +706,9 @@ public sealed class PlantHolderSystem : EntitySystem
|
||||
|
||||
if (component.Harvest && !component.Dead)
|
||||
{
|
||||
if (_hands.TryGetActiveItem(user, out var activeItem))
|
||||
if (TryComp<HandsComponent>(user, out var hands))
|
||||
{
|
||||
if (!_botany.CanHarvest(component.Seed, activeItem))
|
||||
if (!_botany.CanHarvest(component.Seed, hands.ActiveHandEntity))
|
||||
{
|
||||
_popup.PopupCursor(Loc.GetString("plant-holder-component-ligneous-cant-harvest-message"), user);
|
||||
return false;
|
||||
|
||||
@@ -626,7 +626,7 @@ namespace Content.Server.Cargo.Systems
|
||||
_transformSystem.Unanchor(item, Transform(item));
|
||||
|
||||
// Create a sheet of paper to write the order details on
|
||||
var printed = Spawn(paperProto, spawn);
|
||||
var printed = EntityManager.SpawnEntity(paperProto, spawn);
|
||||
if (TryComp<PaperComponent>(printed, out var paper))
|
||||
{
|
||||
// fill in the order data
|
||||
|
||||
@@ -47,7 +47,7 @@ public sealed class NanoTaskCartridgeSystem : SharedNanoTaskCartridgeSystem
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!TryComp<NanoTaskPrintedComponent>(args.Used, out var printed))
|
||||
if (!EntityManager.TryGetComponent<NanoTaskPrintedComponent>(args.Used, out var printed))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -55,7 +55,7 @@ public sealed class NanoTaskCartridgeSystem : SharedNanoTaskCartridgeSystem
|
||||
{
|
||||
program.Tasks.Add(new(program.Counter++, printed.Task));
|
||||
args.Handled = true;
|
||||
Del(args.Used);
|
||||
EntityManager.DeleteEntity(args.Used);
|
||||
UpdateUiState(new Entity<NanoTaskCartridgeComponent>(uid.Value, program), ent.Owner);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using Content.Server.Ghost;
|
||||
using Content.Server.Hands.Systems;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Chat;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Item;
|
||||
@@ -22,7 +22,6 @@ public sealed class SuicideSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly EntityLookupSystem _entityLookupSystem = default!;
|
||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly HandsSystem _hands = default!;
|
||||
[Dependency] private readonly TagSystem _tagSystem = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
@@ -51,7 +50,7 @@ public sealed class SuicideSystem : EntitySystem
|
||||
if (!TryComp<MobStateComponent>(victim, out var mobState) || _mobState.IsDead(victim, mobState))
|
||||
return false;
|
||||
|
||||
_adminLogger.Add(LogType.Mind, $"{ToPrettyString(victim):player} is attempting to suicide");
|
||||
_adminLogger.Add(LogType.Mind, $"{EntityManager.ToPrettyString(victim):player} is attempting to suicide");
|
||||
|
||||
ICommonSession? session = null;
|
||||
|
||||
@@ -77,7 +76,7 @@ public sealed class SuicideSystem : EntitySystem
|
||||
}
|
||||
else
|
||||
{
|
||||
_adminLogger.Add(LogType.Mind, $"{ToPrettyString(victim):player} suicided.");
|
||||
_adminLogger.Add(LogType.Mind, $"{EntityManager.ToPrettyString(victim):player} suicided.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -117,9 +116,10 @@ public sealed class SuicideSystem : EntitySystem
|
||||
var suicideByEnvironmentEvent = new SuicideByEnvironmentEvent(victim);
|
||||
|
||||
// Try to suicide by raising an event on the held item
|
||||
if (_hands.TryGetActiveItem(victim.Owner, out var item))
|
||||
if (EntityManager.TryGetComponent(victim, out HandsComponent? handsComponent)
|
||||
&& handsComponent.ActiveHandEntity is { } item)
|
||||
{
|
||||
RaiseLocalEvent(item.Value, suicideByEnvironmentEvent);
|
||||
RaiseLocalEvent(item, suicideByEnvironmentEvent);
|
||||
if (suicideByEnvironmentEvent.Handled)
|
||||
{
|
||||
args.Handled = suicideByEnvironmentEvent.Handled;
|
||||
|
||||
@@ -397,7 +397,7 @@ public sealed partial class ChatSystem : SharedChatSystem
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryComp<StationDataComponent>(station, out var stationDataComp)) return;
|
||||
if (!EntityManager.TryGetComponent<StationDataComponent>(station, out var stationDataComp)) return;
|
||||
|
||||
var filter = _stationSystem.GetInStation(stationDataComp);
|
||||
|
||||
|
||||
@@ -7,31 +7,32 @@ using Robust.Shared.Prototypes;
|
||||
namespace Content.Server.Chemistry.Commands;
|
||||
|
||||
[AdminCommand(AdminFlags.Debug)]
|
||||
public sealed class DumpReagentGuideText : LocalizedEntityCommands
|
||||
public sealed class DumpReagentGuideText : IConsoleCommand
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
[Dependency] private readonly IEntitySystemManager _entSys = default!;
|
||||
|
||||
public override string Command => "dumpreagentguidetext";
|
||||
public string Command => "dumpreagentguidetext";
|
||||
public string Description => "Dumps the guidebook text for a reagent to the console";
|
||||
public string Help => "dumpreagentguidetext <reagent>";
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length != 1)
|
||||
{
|
||||
shell.WriteError(Loc.GetString($"shell-need-exactly-one-argument"));
|
||||
shell.WriteError("Must have only 1 argument");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_prototype.TryIndex<ReagentPrototype>(args[0], out var reagent))
|
||||
{
|
||||
shell.WriteError(Loc.GetString($"shell-argument-must-be-prototype",
|
||||
("index", args[0]),
|
||||
("prototype", nameof(ReagentPrototype))));
|
||||
shell.WriteError($"Invalid prototype: {args[0]}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (reagent.Metabolisms is null)
|
||||
{
|
||||
shell.WriteLine(Loc.GetString($"cmd-dumpreagentguidetext-nothing-to-dump"));
|
||||
shell.WriteLine("Nothing to dump.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -39,8 +40,7 @@ public sealed class DumpReagentGuideText : LocalizedEntityCommands
|
||||
{
|
||||
foreach (var effect in entry.Effects)
|
||||
{
|
||||
shell.WriteLine(effect.GuidebookEffectDescription(_prototype, EntityManager.EntitySysManager) ??
|
||||
Loc.GetString($"cmd-dumpreagentguidetext-skipped", ("effect", effect.GetType())));
|
||||
shell.WriteLine(effect.GuidebookEffectDescription(_prototype, _entSys) ?? $"[skipped effect of type {effect.GetType()}]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Content.Server.Chemistry.EntitySystems.DeleteOnSolutionEmptySystem
|
||||
|
||||
if (_solutionContainerSystem.TryGetSolution((entity.Owner, solutions), entity.Comp.Solution, out _, out var solution))
|
||||
if (solution.Volume <= 0)
|
||||
QueueDel(entity);
|
||||
EntityManager.QueueDeleteEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Shared._CP14.Farming;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Components.SolutionManager;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.FixedPoint;
|
||||
@@ -176,12 +177,12 @@ public sealed class InjectorSystem : SharedInjectorSystem
|
||||
if (injector.Comp.ToggleState == InjectorToggleMode.Inject)
|
||||
{
|
||||
AdminLogger.Add(LogType.ForceFeed,
|
||||
$"{ToPrettyString(user):user} is attempting to inject {ToPrettyString(target):target} with a solution {SharedSolutionContainerSystem.ToPrettyString(solution):solution}");
|
||||
$"{EntityManager.ToPrettyString(user):user} is attempting to inject {EntityManager.ToPrettyString(target):target} with a solution {SharedSolutionContainerSystem.ToPrettyString(solution):solution}");
|
||||
}
|
||||
else
|
||||
{
|
||||
AdminLogger.Add(LogType.ForceFeed,
|
||||
$"{ToPrettyString(user):user} is attempting to draw {injector.Comp.TransferAmount.ToString()} units from {ToPrettyString(target):target}");
|
||||
$"{EntityManager.ToPrettyString(user):user} is attempting to draw {injector.Comp.TransferAmount.ToString()} units from {EntityManager.ToPrettyString(target):target}");
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -192,12 +193,12 @@ public sealed class InjectorSystem : SharedInjectorSystem
|
||||
if (injector.Comp.ToggleState == InjectorToggleMode.Inject)
|
||||
{
|
||||
AdminLogger.Add(LogType.Ingestion,
|
||||
$"{ToPrettyString(user):user} is attempting to inject themselves with a solution {SharedSolutionContainerSystem.ToPrettyString(solution):solution}.");
|
||||
$"{EntityManager.ToPrettyString(user):user} is attempting to inject themselves with a solution {SharedSolutionContainerSystem.ToPrettyString(solution):solution}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
AdminLogger.Add(LogType.ForceFeed,
|
||||
$"{ToPrettyString(user):user} is attempting to draw {injector.Comp.TransferAmount.ToString()} units from themselves.");
|
||||
$"{EntityManager.ToPrettyString(user):user} is attempting to draw {injector.Comp.TransferAmount.ToString()} units from themselves.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,7 +238,7 @@ public sealed class InjectorSystem : SharedInjectorSystem
|
||||
// Move units from attackSolution to targetSolution
|
||||
var removedSolution = SolutionContainers.SplitSolution(target.Comp.ChemicalSolution.Value, realTransferAmount);
|
||||
|
||||
_blood.TryAddToChemicals(target.AsNullable(), removedSolution);
|
||||
_blood.TryAddToChemicals(target, removedSolution, target.Comp);
|
||||
|
||||
_reactiveSystem.DoEntityReaction(target, removedSolution, ReactionMethod.Injection);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Chemistry.Events;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Popups;
|
||||
@@ -148,7 +148,7 @@ public sealed class SolutionInjectOnCollideSystem : EntitySystem
|
||||
// Take our portion of the adjusted solution for this target
|
||||
var individualInjection = solutionToInject.SplitSolution(volumePerBloodstream);
|
||||
// Inject our portion into the target's bloodstream
|
||||
if (_bloodstream.TryAddToChemicals(targetBloodstream.AsNullable(), individualInjection))
|
||||
if (_bloodstream.TryAddToChemicals(targetBloodstream.Owner, individualInjection, targetBloodstream.Comp))
|
||||
anySuccess = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Content.Server.Chemistry.EntitySystems
|
||||
|
||||
private void HandleCollide(Entity<VaporComponent> entity, ref StartCollideEvent args)
|
||||
{
|
||||
if (!TryComp(entity.Owner, out SolutionContainerManagerComponent? contents)) return;
|
||||
if (!EntityManager.TryGetComponent(entity.Owner, out SolutionContainerManagerComponent? contents)) return;
|
||||
|
||||
foreach (var (_, soln) in _solutionContainerSystem.EnumerateSolutions((entity.Owner, contents)))
|
||||
{
|
||||
@@ -50,7 +50,7 @@ namespace Content.Server.Chemistry.EntitySystems
|
||||
// Check for collision with a impassable object (e.g. wall) and stop
|
||||
if ((args.OtherFixture.CollisionLayer & (int)CollisionGroup.Impassable) != 0 && args.OtherFixture.Hard)
|
||||
{
|
||||
QueueDel(entity);
|
||||
EntityManager.QueueDeleteEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace Content.Server.Chemistry.EntitySystems
|
||||
despawn.Lifetime = aliveTime;
|
||||
|
||||
// Set Move
|
||||
if (TryComp(vapor, out PhysicsComponent? physics))
|
||||
if (EntityManager.TryGetComponent(vapor, out PhysicsComponent? physics))
|
||||
{
|
||||
_physics.SetLinearDamping(vapor, physics, 0f);
|
||||
_physics.SetAngularDamping(vapor, physics, 0f);
|
||||
@@ -156,7 +156,7 @@ namespace Content.Server.Chemistry.EntitySystems
|
||||
|
||||
// Delete the vapor entity if it has no contents
|
||||
if (contents.Volume == 0)
|
||||
QueueDel(uid);
|
||||
EntityManager.QueueDeleteEntity(uid);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -41,33 +41,33 @@ public sealed partial class CreateEntityTileReaction : ITileReaction
|
||||
IEntityManager entityManager,
|
||||
List<ReagentData>? data)
|
||||
{
|
||||
if (reactVolume < Usage)
|
||||
return FixedPoint2.Zero;
|
||||
|
||||
if (Whitelist != null)
|
||||
if (reactVolume >= Usage)
|
||||
{
|
||||
var lookup = entityManager.System<EntityLookupSystem>();
|
||||
|
||||
int acc = 0;
|
||||
foreach (var ent in lookup.GetEntitiesInTile(tile, LookupFlags.Static))
|
||||
if (Whitelist != null)
|
||||
{
|
||||
var whitelistSystem = entityManager.System<EntityWhitelistSystem>();
|
||||
if (whitelistSystem.IsWhitelistPass(Whitelist, ent))
|
||||
acc += 1;
|
||||
int acc = 0;
|
||||
foreach (var ent in tile.GetEntitiesInTile())
|
||||
{
|
||||
var whitelistSystem = entityManager.System<EntityWhitelistSystem>();
|
||||
if (whitelistSystem.IsWhitelistPass(Whitelist, ent))
|
||||
acc += 1;
|
||||
|
||||
if (acc >= MaxOnTile)
|
||||
return FixedPoint2.Zero;
|
||||
if (acc >= MaxOnTile)
|
||||
return FixedPoint2.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
var random = IoCManager.Resolve<IRobustRandom>();
|
||||
var xoffs = random.NextFloat(-RandomOffsetMax, RandomOffsetMax);
|
||||
var yoffs = random.NextFloat(-RandomOffsetMax, RandomOffsetMax);
|
||||
|
||||
var center = entityManager.System<TurfSystem>().GetTileCenter(tile);
|
||||
var pos = center.Offset(new Vector2(xoffs, yoffs));
|
||||
entityManager.SpawnEntity(Entity, pos);
|
||||
|
||||
return Usage;
|
||||
}
|
||||
|
||||
var random = IoCManager.Resolve<IRobustRandom>();
|
||||
var xoffs = random.NextFloat(-RandomOffsetMax, RandomOffsetMax);
|
||||
var yoffs = random.NextFloat(-RandomOffsetMax, RandomOffsetMax);
|
||||
|
||||
var center = entityManager.System<TurfSystem>().GetTileCenter(tile);
|
||||
var pos = center.Offset(new Vector2(xoffs, yoffs));
|
||||
entityManager.SpawnEntity(Entity, pos);
|
||||
|
||||
return Usage;
|
||||
return FixedPoint2.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ public sealed class CloningPodSystem : EntitySystem
|
||||
internal void TransferMindToClone(EntityUid mindId, MindComponent mind)
|
||||
{
|
||||
if (!ClonesWaitingForMind.TryGetValue(mind, out var entity) ||
|
||||
!Exists(entity) ||
|
||||
!EntityManager.EntityExists(entity) ||
|
||||
!TryComp<MindContainerComponent>(entity, out var mindComp) ||
|
||||
mindComp.Mind != null)
|
||||
return;
|
||||
@@ -93,11 +93,11 @@ public sealed class CloningPodSystem : EntitySystem
|
||||
private void HandleMindAdded(EntityUid uid, BeingClonedComponent clonedComponent, MindAddedMessage message)
|
||||
{
|
||||
if (clonedComponent.Parent == EntityUid.Invalid ||
|
||||
!Exists(clonedComponent.Parent) ||
|
||||
!EntityManager.EntityExists(clonedComponent.Parent) ||
|
||||
!TryComp<CloningPodComponent>(clonedComponent.Parent, out var cloningPodComponent) ||
|
||||
uid != cloningPodComponent.BodyContainer.ContainedEntity)
|
||||
{
|
||||
RemComp<BeingClonedComponent>(uid);
|
||||
EntityManager.RemoveComponent<BeingClonedComponent>(uid);
|
||||
return;
|
||||
}
|
||||
UpdateStatus(clonedComponent.Parent, CloningPodStatus.Cloning, cloningPodComponent);
|
||||
@@ -139,7 +139,7 @@ public sealed class CloningPodSystem : EntitySystem
|
||||
var mind = mindEnt.Comp;
|
||||
if (ClonesWaitingForMind.TryGetValue(mind, out var clone))
|
||||
{
|
||||
if (Exists(clone) &&
|
||||
if (EntityManager.EntityExists(clone) &&
|
||||
!_mobStateSystem.IsDead(clone) &&
|
||||
TryComp<MindContainerComponent>(clone, out var cloneMindComp) &&
|
||||
(cloneMindComp.Mind == null || cloneMindComp.Mind == mindEnt))
|
||||
@@ -204,7 +204,7 @@ public sealed class CloningPodSystem : EntitySystem
|
||||
return false;
|
||||
}
|
||||
|
||||
var cloneMindReturn = AddComp<BeingClonedComponent>(mob.Value);
|
||||
var cloneMindReturn = EntityManager.AddComponent<BeingClonedComponent>(mob.Value);
|
||||
cloneMindReturn.Mind = mind;
|
||||
cloneMindReturn.Parent = uid;
|
||||
_containerSystem.Insert(mob.Value, clonePod.BodyContainer);
|
||||
@@ -272,7 +272,7 @@ public sealed class CloningPodSystem : EntitySystem
|
||||
if (clonePod.BodyContainer.ContainedEntity is not { Valid: true } entity || clonePod.CloningProgress < clonePod.CloningTime)
|
||||
return;
|
||||
|
||||
RemComp<BeingClonedComponent>(entity);
|
||||
EntityManager.RemoveComponent<BeingClonedComponent>(entity);
|
||||
_containerSystem.Remove(entity, clonePod.BodyContainer);
|
||||
clonePod.CloningProgress = 0f;
|
||||
clonePod.UsedBiomass = 0;
|
||||
|
||||
@@ -175,7 +175,7 @@ public sealed partial class CloningSystem : EntitySystem
|
||||
if (prototype == null)
|
||||
return null;
|
||||
|
||||
var spawned = SpawnAtPosition(prototype, coords);
|
||||
var spawned = EntityManager.SpawnAtPosition(prototype, coords);
|
||||
|
||||
// copy over important component data
|
||||
var ev = new CloningItemEvent(spawned);
|
||||
|
||||
@@ -56,7 +56,7 @@ public sealed class CodewordSystem : EntitySystem
|
||||
var factionProto = _prototypeManager.Index<CodewordFactionPrototype>(faction.Id);
|
||||
|
||||
var codewords = GenerateCodewords(factionProto.Generator);
|
||||
var codewordsContainer = Spawn(prototype: null, MapCoordinates.Nullspace);
|
||||
var codewordsContainer = EntityManager.Spawn(protoName:null, MapCoordinates.Nullspace);
|
||||
EnsureComp<CodewordComponent>(codewordsContainer)
|
||||
.Codewords = codewords;
|
||||
manager.Codewords[faction] = codewordsContainer;
|
||||
|
||||
@@ -58,7 +58,9 @@ namespace Content.Server.Construction.Conditions
|
||||
if (!entityManager.System<SharedMapSystem>().TryGetTileRef(transform.GridUid.Value, grid, indices, out var tile))
|
||||
return !HasEntity;
|
||||
|
||||
foreach (var ent in lookup.GetEntitiesInTile(tile, flags: LookupFlags.Approximate | LookupFlags.Static))
|
||||
var entities = tile.GetEntitiesInTile(LookupFlags.Approximate | LookupFlags.Static, lookup);
|
||||
|
||||
foreach (var ent in entities)
|
||||
{
|
||||
if (entityManager.HasComponent(ent, type))
|
||||
return HasEntity;
|
||||
|
||||
@@ -60,7 +60,7 @@ public sealed partial class ConstructionSystem
|
||||
if (container.ContainedEntities.Count != 0)
|
||||
return;
|
||||
|
||||
var board = Spawn(component.BoardPrototype, Transform(ent).Coordinates);
|
||||
var board = EntityManager.SpawnEntity(component.BoardPrototype, Transform(ent).Coordinates);
|
||||
|
||||
if (!_container.Insert(board, container))
|
||||
Log.Warning($"Couldn't insert board {board} to computer {ent}!");
|
||||
|
||||
@@ -325,7 +325,7 @@ namespace Content.Server.Construction
|
||||
var newUid = EntityManager.CreateEntityUninitialized(newEntity, transform.Coordinates);
|
||||
|
||||
// Construction transferring.
|
||||
var newConstruction = EnsureComp<ConstructionComponent>(newUid);
|
||||
var newConstruction = EntityManager.EnsureComponent<ConstructionComponent>(newUid);
|
||||
|
||||
// Transfer all construction-owned containers.
|
||||
newConstruction.Containers.UnionWith(construction.Containers);
|
||||
@@ -372,7 +372,7 @@ namespace Content.Server.Construction
|
||||
if (containerManager != null)
|
||||
{
|
||||
// Ensure the new entity has a container manager. Also for resolve goodness.
|
||||
var newContainerManager = EnsureComp<ContainerManagerComponent>(newUid);
|
||||
var newContainerManager = EntityManager.EnsureComponent<ContainerManagerComponent>(newUid);
|
||||
|
||||
// Transfer all construction-owned containers from the old entity to the new one.
|
||||
foreach (var container in construction.Containers)
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace Content.Server.Construction
|
||||
if(!containerSlot.ContainedEntity.HasValue)
|
||||
continue;
|
||||
|
||||
if (TryComp(containerSlot.ContainedEntity.Value, out StorageComponent? storage))
|
||||
if (EntityManager.TryGetComponent(containerSlot.ContainedEntity.Value, out StorageComponent? storage))
|
||||
{
|
||||
foreach (var storedEntity in storage.Container.ContainedEntities)
|
||||
{
|
||||
@@ -301,7 +301,7 @@ namespace Content.Server.Construction
|
||||
}
|
||||
|
||||
var newEntityProto = graph.Nodes[edge.Target].Entity.GetId(null, user, new(EntityManager));
|
||||
var newEntity = SpawnAttachedTo(newEntityProto, coords, rotation: angle);
|
||||
var newEntity = EntityManager.SpawnAttachedTo(newEntityProto, coords, rotation: angle);
|
||||
|
||||
if (!TryComp(newEntity, out ConstructionComponent? construction))
|
||||
{
|
||||
@@ -502,7 +502,7 @@ namespace Content.Server.Construction
|
||||
}
|
||||
|
||||
if (!_actionBlocker.CanInteract(user, null)
|
||||
|| !TryComp(user, out HandsComponent? hands) || _handsSystem.GetActiveItem((user, hands)) == null)
|
||||
|| !EntityManager.TryGetComponent(user, out HandsComponent? hands) || hands.ActiveHandEntity == null)
|
||||
{
|
||||
Cleanup();
|
||||
return;
|
||||
@@ -527,7 +527,7 @@ namespace Content.Server.Construction
|
||||
|
||||
var valid = false;
|
||||
|
||||
if (_handsSystem.GetActiveItem((user, hands)) is not {Valid: true} holding)
|
||||
if (hands.ActiveHandEntity is not {Valid: true} holding)
|
||||
{
|
||||
Cleanup();
|
||||
return;
|
||||
|
||||
@@ -41,13 +41,13 @@ namespace Content.Server.Construction
|
||||
var construction = ent.Comp;
|
||||
if (GetCurrentGraph(ent, construction) is not {} graph)
|
||||
{
|
||||
Log.Warning($"Prototype {Comp<MetaDataComponent>(ent).EntityPrototype?.ID}'s construction component has an invalid graph specified.");
|
||||
Log.Warning($"Prototype {EntityManager.GetComponent<MetaDataComponent>(ent).EntityPrototype?.ID}'s construction component has an invalid graph specified.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetNodeFromGraph(graph, construction.Node) is not {} node)
|
||||
{
|
||||
Log.Warning($"Prototype {Comp<MetaDataComponent>(ent).EntityPrototype?.ID}'s construction component has an invalid node specified.");
|
||||
Log.Warning($"Prototype {EntityManager.GetComponent<MetaDataComponent>(ent).EntityPrototype?.ID}'s construction component has an invalid node specified.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace Content.Server.Construction
|
||||
{
|
||||
if (GetEdgeFromNode(node, edgeIndex) is not {} currentEdge)
|
||||
{
|
||||
Log.Warning($"Prototype {Comp<MetaDataComponent>(ent).EntityPrototype?.ID}'s construction component has an invalid edge index specified.");
|
||||
Log.Warning($"Prototype {EntityManager.GetComponent<MetaDataComponent>(ent).EntityPrototype?.ID}'s construction component has an invalid edge index specified.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace Content.Server.Construction
|
||||
{
|
||||
if (GetNodeFromGraph(graph, targetNodeId) is not { } targetNode)
|
||||
{
|
||||
Log.Warning($"Prototype {Comp<MetaDataComponent>(ent).EntityPrototype?.ID}'s construction component has an invalid target node specified.");
|
||||
Log.Warning($"Prototype {EntityManager.GetComponent<MetaDataComponent>(ent).EntityPrototype?.ID}'s construction component has an invalid target node specified.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<OutputType Condition="'$(FullRelease)' != 'True'">Exe</OutputType>
|
||||
<NoWarn>1998</NoWarn>
|
||||
<WarningsAsErrors>RA0032;nullable</WarningsAsErrors>
|
||||
<WarningsAsErrors>nullable</WarningsAsErrors>
|
||||
<Nullable>enable</Nullable>
|
||||
<ServerGarbageCollection>true</ServerGarbageCollection>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -76,7 +76,7 @@ public sealed class CrayonSystem : SharedCrayonSystem
|
||||
component.Charges--;
|
||||
Dirty(uid, component);
|
||||
|
||||
_adminLogger.Add(LogType.CrayonDraw, LogImpact.Low, $"{ToPrettyString(args.User):user} drew a {component.Color:color} {component.SelectedState}");
|
||||
_adminLogger.Add(LogType.CrayonDraw, LogImpact.Low, $"{EntityManager.ToPrettyString(args.User):user} drew a {component.Color:color} {component.SelectedState}");
|
||||
args.Handled = true;
|
||||
|
||||
if (component.DeleteEmpty && component.Charges <= 0)
|
||||
@@ -143,6 +143,6 @@ public sealed class CrayonSystem : SharedCrayonSystem
|
||||
private void UseUpCrayon(EntityUid uid, EntityUid user)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("crayon-interact-used-up-text", ("owner", uid)), user, user);
|
||||
QueueDel(uid);
|
||||
EntityManager.QueueDeleteEntity(uid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,45 +251,56 @@ public sealed class CrewManifestSystem : EntitySystem
|
||||
}
|
||||
|
||||
[AdminCommand(AdminFlags.Admin)]
|
||||
public sealed class CrewManifestCommand : LocalizedEntityCommands
|
||||
public sealed class CrewManifestCommand : IConsoleCommand
|
||||
{
|
||||
[Dependency] private readonly CrewManifestSystem _manifestSystem = default!;
|
||||
public string Command => "crewmanifest";
|
||||
public string Description => "Opens the crew manifest for the given station.";
|
||||
public string Help => $"Usage: {Command} <entity uid>";
|
||||
|
||||
public override string Command => "crewmanifest";
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
public CrewManifestCommand()
|
||||
{
|
||||
if (args.Length != 1)
|
||||
{
|
||||
shell.WriteLine(Loc.GetString($"shell-need-exactly-one-argument"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NetEntity.TryParse(args[0], out var uidNet) || !EntityManager.TryGetEntity(uidNet, out var uid))
|
||||
{
|
||||
shell.WriteLine(Loc.GetString($"shell-argument-station-id-invalid", ("index", args[0])));
|
||||
return;
|
||||
}
|
||||
|
||||
if (shell.Player is not { } session)
|
||||
{
|
||||
shell.WriteLine(Loc.GetString($"shell-cannot-run-command-from-server"));
|
||||
return;
|
||||
}
|
||||
|
||||
_manifestSystem.OpenEui(uid.Value, session);
|
||||
IoCManager.InjectDependencies(this);
|
||||
}
|
||||
|
||||
public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length != 1)
|
||||
{
|
||||
shell.WriteLine($"Invalid argument count.\n{Help}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NetEntity.TryParse(args[0], out var uidNet) || !_entityManager.TryGetEntity(uidNet, out var uid))
|
||||
{
|
||||
shell.WriteLine($"{args[0]} is not a valid entity UID.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (shell.Player == null || shell.Player is not { } session)
|
||||
{
|
||||
shell.WriteLine("You must run this from a client.");
|
||||
return;
|
||||
}
|
||||
|
||||
var crewManifestSystem = _entityManager.System<CrewManifestSystem>();
|
||||
|
||||
crewManifestSystem.OpenEui(uid.Value, session);
|
||||
}
|
||||
|
||||
public CompletionResult GetCompletion(IConsoleShell shell, string[] args)
|
||||
{
|
||||
if (args.Length != 1)
|
||||
{
|
||||
return CompletionResult.Empty;
|
||||
}
|
||||
|
||||
var stations = new List<CompletionOption>();
|
||||
var query = EntityManager.EntityQueryEnumerator<StationDataComponent>();
|
||||
var query = _entityManager.EntityQueryEnumerator<StationDataComponent>();
|
||||
while (query.MoveNext(out var uid, out _))
|
||||
{
|
||||
var meta = EntityManager.GetComponent<MetaDataComponent>(uid);
|
||||
var meta = _entityManager.GetComponent<MetaDataComponent>(uid);
|
||||
stations.Add(new CompletionOption(uid.ToString(), meta.EntityName));
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Content.Server.Damage.Systems
|
||||
return;
|
||||
|
||||
if (component.WeldingDamage is {} weldingDamage
|
||||
&& TryComp(args.Used, out WelderComponent? welder)
|
||||
&& EntityManager.TryGetComponent(args.Used, out WelderComponent? welder)
|
||||
&& itemToggle.Activated
|
||||
&& !welder.TankSafe)
|
||||
{
|
||||
|
||||
@@ -54,9 +54,8 @@ namespace Content.Server.Decals.Commands
|
||||
}
|
||||
|
||||
var mapSystem = _entManager.System<MapSystem>();
|
||||
var turfSystem = _entManager.System<TurfSystem>();
|
||||
var coordinates = new EntityCoordinates(gridIdRaw.Value, new Vector2(x, y));
|
||||
if (turfSystem.IsSpace(mapSystem.GetTileRef(gridIdRaw.Value, grid, coordinates)))
|
||||
if (mapSystem.GetTileRef(gridIdRaw.Value, grid, coordinates).IsSpace())
|
||||
{
|
||||
shell.WriteError($"Cannot create decal on space tile at {coordinates}.");
|
||||
return;
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace Content.Server.Decals
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IAdminManager _adminManager = default!;
|
||||
[Dependency] private readonly ITileDefinitionManager _tileDefMan = default!;
|
||||
[Dependency] private readonly IParallelManager _parMan = default!;
|
||||
[Dependency] private readonly ChunkingSystem _chunking = default!;
|
||||
[Dependency] private readonly IConfigurationManager _conf = default!;
|
||||
@@ -36,7 +37,6 @@ namespace Content.Server.Decals
|
||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly TurfSystem _turf = default!;
|
||||
|
||||
private readonly Dictionary<NetEntity, HashSet<Vector2i>> _dirtyChunks = new();
|
||||
private readonly Dictionary<ICommonSession, Dictionary<NetEntity, HashSet<Vector2i>>> _previousSentChunks = new();
|
||||
@@ -167,7 +167,7 @@ namespace Content.Server.Decals
|
||||
|
||||
foreach (var change in args.Changes)
|
||||
{
|
||||
if (!_turf.IsSpace(change.NewTile))
|
||||
if (!change.NewTile.IsSpace(_tileDefMan))
|
||||
continue;
|
||||
|
||||
var indices = GetChunkIndices(change.GridIndices);
|
||||
@@ -308,7 +308,7 @@ namespace Content.Server.Decals
|
||||
if (!TryComp(gridId, out MapGridComponent? grid))
|
||||
return false;
|
||||
|
||||
if (_turf.IsSpace(_mapSystem.GetTileRef(gridId.Value, grid, coordinates)))
|
||||
if (_mapSystem.GetTileRef(gridId.Value, grid, coordinates).IsSpace(_tileDefMan))
|
||||
return false;
|
||||
|
||||
if (!TryComp(gridId, out DecalGridComponent? comp))
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Content.Server.DeviceLinking.Components;
|
||||
using Content.Server.DeviceNetwork;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Lock;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
|
||||
@@ -11,7 +10,6 @@ public sealed class SignalSwitchSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly DeviceLinkSystem _deviceLink = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly LockSystem _lock = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -31,9 +29,6 @@ public sealed class SignalSwitchSystem : EntitySystem
|
||||
if (args.Handled || !args.Complex)
|
||||
return;
|
||||
|
||||
if (_lock.IsLocked(uid))
|
||||
return;
|
||||
|
||||
comp.State = !comp.State;
|
||||
_deviceLink.InvokePort(uid, comp.State ? comp.OnPort : comp.OffPort);
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Content.Server.DeviceNetwork.Systems
|
||||
/// </summary>
|
||||
private void OnBeforePacketSent(EntityUid uid, ApcNetworkComponent receiver, BeforePacketSentEvent args)
|
||||
{
|
||||
if (!TryComp(args.Sender, out ApcNetworkComponent? sender)) return;
|
||||
if (!EntityManager.TryGetComponent(args.Sender, out ApcNetworkComponent? sender)) return;
|
||||
|
||||
if (sender.ConnectedNode?.NodeGroup == null || !sender.ConnectedNode.NodeGroup.Equals(receiver.ConnectedNode?.NodeGroup))
|
||||
{
|
||||
@@ -39,7 +39,7 @@ namespace Content.Server.DeviceNetwork.Systems
|
||||
|
||||
private void OnProviderConnected(EntityUid uid, ApcNetworkComponent component, ExtensionCableSystem.ProviderConnectedEvent args)
|
||||
{
|
||||
if (!TryComp(args.Provider.Owner, out NodeContainerComponent? nodeContainer)) return;
|
||||
if (!EntityManager.TryGetComponent(args.Provider.Owner, out NodeContainerComponent? nodeContainer)) return;
|
||||
|
||||
if (_nodeContainer.TryGetNode(nodeContainer, "power", out CableNode? node))
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Content.Server.DeviceNetwork.Systems.Devices
|
||||
/// </summary>
|
||||
private void OnInteracted(EntityUid uid, ApcNetSwitchComponent component, InteractHandEvent args)
|
||||
{
|
||||
if (!TryComp(uid, out DeviceNetworkComponent? networkComponent)) return;
|
||||
if (!EntityManager.TryGetComponent(uid, out DeviceNetworkComponent? networkComponent)) return;
|
||||
|
||||
component.State = !component.State;
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Content.Server.DeviceNetwork.Systems.Devices
|
||||
/// </summary>
|
||||
private void OnPackedReceived(EntityUid uid, ApcNetSwitchComponent component, DeviceNetworkPacketEvent args)
|
||||
{
|
||||
if (!TryComp(uid, out DeviceNetworkComponent? networkComponent) || args.SenderAddress == networkComponent.Address) return;
|
||||
if (!EntityManager.TryGetComponent(uid, out DeviceNetworkComponent? networkComponent) || args.SenderAddress == networkComponent.Address) return;
|
||||
if (!args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? command) || command != DeviceNetworkConstants.CmdSetState) return;
|
||||
if (!args.Data.TryGetValue(DeviceNetworkConstants.StateEnabled, out bool enabled)) return;
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ using Robust.Server.Audio;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Map.Events;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -497,15 +496,14 @@ public sealed class NetworkConfiguratorSystem : SharedNetworkConfiguratorSystem
|
||||
return;
|
||||
|
||||
var sources = _deviceLinkSystem.GetSourcePorts(sourceUid, sourceComponent);
|
||||
var sinks = _deviceLinkSystem.GetSinkPortIds((sinkUid, sinkComponent));
|
||||
var sinks = _deviceLinkSystem.GetSinkPorts(sinkUid, sinkComponent);
|
||||
var links = _deviceLinkSystem.GetLinks(sourceUid, sinkUid, sourceComponent);
|
||||
var defaults = _deviceLinkSystem.GetDefaults(sources);
|
||||
var sourceIds = sources.Select(s => (ProtoId<SourcePortPrototype>)s.ID).ToArray();
|
||||
|
||||
var sourceAddress = Resolve(sourceUid, ref sourceNetworkComponent, false) ? sourceNetworkComponent.Address : "";
|
||||
var sinkAddress = Resolve(sinkUid, ref sinkNetworkComponent, false) ? sinkNetworkComponent.Address : "";
|
||||
|
||||
var state = new DeviceLinkUserInterfaceState(sourceIds, sinks, links, sourceAddress, sinkAddress, defaults);
|
||||
var state = new DeviceLinkUserInterfaceState(sources, sinks, links, sourceAddress, sinkAddress, defaults);
|
||||
_uiSystem.SetUiState(configuratorUid, NetworkConfiguratorUiKey.Link, state);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Shared.Body.Events;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Devour;
|
||||
using Content.Shared.Devour.Components;
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace Content.Server.Disposal.Tube
|
||||
/// <param name="msg">A user interface message from the client.</param>
|
||||
private void OnUiAction(EntityUid uid, DisposalRouterComponent router, SharedDisposalRouterComponent.UiActionMessage msg)
|
||||
{
|
||||
if (!Exists(msg.Actor))
|
||||
if (!EntityManager.EntityExists(msg.Actor))
|
||||
return;
|
||||
|
||||
if (TryComp<PhysicsComponent>(uid, out var physBody) && physBody.BodyType != BodyType.Static)
|
||||
|
||||
@@ -156,7 +156,7 @@ namespace Content.Server.Disposal.Unit
|
||||
holder.Air.Clear();
|
||||
}
|
||||
|
||||
Del(uid);
|
||||
EntityManager.DeleteEntity(uid);
|
||||
}
|
||||
|
||||
// Note: This function will cause an ExitDisposals on any failure that does not make an ExitDisposals impossible.
|
||||
@@ -243,7 +243,7 @@ namespace Content.Server.Disposal.Unit
|
||||
holder.TimeLeft -= time;
|
||||
frameTime -= time;
|
||||
|
||||
if (!Exists(holder.CurrentTube))
|
||||
if (!EntityManager.EntityExists(holder.CurrentTube))
|
||||
{
|
||||
ExitDisposals(uid, holder);
|
||||
break;
|
||||
@@ -268,7 +268,7 @@ namespace Content.Server.Disposal.Unit
|
||||
|
||||
// Find next tube
|
||||
var nextTube = _disposalTubeSystem.NextTubeFor(currentTube, holder.CurrentDirection);
|
||||
if (!Exists(nextTube))
|
||||
if (!EntityManager.EntityExists(nextTube))
|
||||
{
|
||||
ExitDisposals(uid, holder);
|
||||
break;
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace Content.Server.Dragon;
|
||||
public sealed partial class DragonSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly CarpRiftsConditionSystem _carpRifts = default!;
|
||||
[Dependency] private readonly ITileDefinitionManager _tileDef = default!;
|
||||
[Dependency] private readonly MovementSpeedModifierSystem _movement = default!;
|
||||
[Dependency] private readonly NpcFactionSystem _faction = default!;
|
||||
[Dependency] private readonly PopupSystem _popup = default!;
|
||||
@@ -29,7 +30,6 @@ public sealed partial class DragonSystem : EntitySystem
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedMapSystem _map = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly TurfSystem _turf = default!;
|
||||
|
||||
private EntityQuery<CarpRiftsConditionComponent> _objQuery;
|
||||
|
||||
@@ -159,7 +159,7 @@ public sealed partial class DragonSystem : EntitySystem
|
||||
// cant put a rift on solars
|
||||
foreach (var tile in _map.GetTilesIntersecting(xform.GridUid.Value, grid, new Circle(_transform.GetWorldPosition(xform), RiftTileRadius), false))
|
||||
{
|
||||
if (!_turf.IsSpace(tile))
|
||||
if (!tile.IsSpace(_tileDef))
|
||||
continue;
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("carp-rift-space-proximity", ("proximity", RiftTileRadius)), uid, uid);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using Content.Server.StatusEffectNew;
|
||||
using Content.Shared.Bed.Sleep;
|
||||
using Content.Shared.Bed.Sleep;
|
||||
using Content.Shared.Drowsiness;
|
||||
using Content.Shared.StatusEffectNew;
|
||||
using Content.Shared.StatusEffectNew.Components;
|
||||
using Content.Shared.StatusEffect;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
@@ -10,6 +8,9 @@ namespace Content.Server.Drowsiness;
|
||||
|
||||
public sealed class DrowsinessSystem : SharedDrowsinessSystem
|
||||
{
|
||||
[ValidatePrototypeId<StatusEffectPrototype>]
|
||||
private const string SleepKey = "ForcedSleep"; // Same one used by N2O and other sleep chems.
|
||||
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
|
||||
@@ -17,37 +18,33 @@ public sealed class DrowsinessSystem : SharedDrowsinessSystem
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<DrowsinessStatusEffectComponent, StatusEffectAppliedEvent>(OnEffectApplied);
|
||||
SubscribeLocalEvent<DrowsinessComponent, ComponentStartup>(OnInit);
|
||||
}
|
||||
|
||||
private void OnEffectApplied(Entity<DrowsinessStatusEffectComponent> ent, ref StatusEffectAppliedEvent args)
|
||||
private void OnInit(EntityUid uid, DrowsinessComponent component, ComponentStartup args)
|
||||
{
|
||||
ent.Comp.NextIncidentTime = _timing.CurTime + TimeSpan.FromSeconds(_random.NextFloat(ent.Comp.TimeBetweenIncidents.X, ent.Comp.TimeBetweenIncidents.Y));
|
||||
component.NextIncidentTime = _timing.CurTime + TimeSpan.FromSeconds(_random.NextFloat(component.TimeBetweenIncidents.X, component.TimeBetweenIncidents.Y));
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<DrowsinessStatusEffectComponent, StatusEffectComponent>();
|
||||
while (query.MoveNext(out var uid, out var drowsiness, out var statusEffect))
|
||||
var query = EntityQueryEnumerator<DrowsinessComponent>();
|
||||
while (query.MoveNext(out var uid, out var component))
|
||||
{
|
||||
if (_timing.CurTime < drowsiness.NextIncidentTime)
|
||||
continue;
|
||||
|
||||
if (statusEffect.AppliedTo is null)
|
||||
if (_timing.CurTime < component.NextIncidentTime)
|
||||
continue;
|
||||
|
||||
// Set the new time.
|
||||
drowsiness.NextIncidentTime = _timing.CurTime + TimeSpan.FromSeconds(_random.NextFloat(drowsiness.TimeBetweenIncidents.X, drowsiness.TimeBetweenIncidents.Y));
|
||||
component.NextIncidentTime = _timing.CurTime + TimeSpan.FromSeconds(_random.NextFloat(component.TimeBetweenIncidents.X, component.TimeBetweenIncidents.Y));
|
||||
|
||||
// sleep duration
|
||||
var duration = TimeSpan.FromSeconds(_random.NextFloat(drowsiness.DurationOfIncident.X, drowsiness.DurationOfIncident.Y));
|
||||
var duration = TimeSpan.FromSeconds(_random.NextFloat(component.DurationOfIncident.X, component.DurationOfIncident.Y));
|
||||
|
||||
// Make sure the sleep time doesn't cut into the time to next incident.
|
||||
drowsiness.NextIncidentTime += duration;
|
||||
component.NextIncidentTime += duration;
|
||||
|
||||
_statusEffects.TryAddStatusEffectDuration(statusEffect.AppliedTo.Value, SleepingSystem.StatusEffectForcedSleeping, duration);
|
||||
_statusEffects.TryAddStatusEffect<ForcedSleepingComponent>(uid, SleepKey, duration, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,47 +3,55 @@ using Content.Shared.Administration;
|
||||
using Content.Shared.StatusEffect;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
namespace Content.Server.Electrocution;
|
||||
|
||||
[AdminCommand(AdminFlags.Fun)]
|
||||
public sealed class ElectrocuteCommand : LocalizedEntityCommands
|
||||
namespace Content.Server.Electrocution
|
||||
{
|
||||
[Dependency] private readonly ElectrocutionSystem _electrocution = default!;
|
||||
[Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
|
||||
|
||||
public override string Command => "electrocute";
|
||||
|
||||
[ValidatePrototypeId<StatusEffectPrototype>]
|
||||
private const string ElectrocutionStatusEffect = "Electrocution";
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
[AdminCommand(AdminFlags.Fun)]
|
||||
public sealed class ElectrocuteCommand : IConsoleCommand
|
||||
{
|
||||
if (args.Length is < 1 or > 3)
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
|
||||
public string Command => "electrocute";
|
||||
public string Description => Loc.GetString("electrocute-command-description");
|
||||
public string Help => $"{Command} <uid> <seconds> <damage>";
|
||||
|
||||
[ValidatePrototypeId<StatusEffectPrototype>]
|
||||
public const string ElectrocutionStatusEffect = "Electrocution";
|
||||
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
shell.WriteError(Loc.GetString($"shell-need-between-arguments",
|
||||
("lower", 1),
|
||||
("upper", 3)));
|
||||
return;
|
||||
if (args.Length < 1)
|
||||
{
|
||||
// TODO: Localize this.
|
||||
shell.WriteError("Not enough arguments!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NetEntity.TryParse(args[0], out var uidNet) ||
|
||||
!_entManager.TryGetEntity(uidNet, out var uid) ||
|
||||
!_entManager.EntityExists(uid))
|
||||
{
|
||||
shell.WriteError($"Invalid entity specified!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_entManager.EntitySysManager.GetEntitySystem<StatusEffectsSystem>().CanApplyEffect(uid.Value, ElectrocutionStatusEffect))
|
||||
{
|
||||
shell.WriteError(Loc.GetString("electrocute-command-entity-cannot-be-electrocuted"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Length < 2 || !int.TryParse(args[1], out var seconds))
|
||||
{
|
||||
seconds = 10;
|
||||
}
|
||||
|
||||
if (args.Length < 3 || !int.TryParse(args[2], out var damage))
|
||||
{
|
||||
damage = 10;
|
||||
}
|
||||
|
||||
_entManager.EntitySysManager.GetEntitySystem<ElectrocutionSystem>()
|
||||
.TryDoElectrocution(uid.Value, null, damage, TimeSpan.FromSeconds(seconds), refresh: true, ignoreInsulation: true);
|
||||
}
|
||||
|
||||
if (!NetEntity.TryParse(args[0], out var uidNet) || !EntityManager.TryGetEntity(uidNet, out var uid) || !EntityManager.EntityExists(uid))
|
||||
{
|
||||
shell.WriteError(Loc.GetString($"shell-could-not-find-entity-with-uid", ("uid", args[0])));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_statusEffects.CanApplyEffect(uid.Value, ElectrocutionStatusEffect))
|
||||
{
|
||||
shell.WriteError(Loc.GetString("cmd-electrocute-entity-cannot-be-electrocuted"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Length < 2 || !int.TryParse(args[1], out var seconds))
|
||||
seconds = 10;
|
||||
|
||||
if (args.Length < 3 || !int.TryParse(args[2], out var damage))
|
||||
damage = 10;
|
||||
|
||||
_electrocution.TryDoElectrocution(uid.Value, null, damage, TimeSpan.FromSeconds(seconds), refresh: true, ignoreInsulation: true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,6 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
|
||||
[Dependency] private readonly SharedStutteringSystem _stuttering = default!;
|
||||
[Dependency] private readonly TagSystem _tag = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||
[Dependency] private readonly TurfSystem _turf = default!;
|
||||
|
||||
[ValidatePrototypeId<StatusEffectPrototype>]
|
||||
private const string StatusEffectKey = "Electrocution";
|
||||
@@ -138,7 +137,7 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
|
||||
return false;
|
||||
if (electrified.NoWindowInTile)
|
||||
{
|
||||
var tileRef = _turf.GetTileRef(transform.Coordinates);
|
||||
var tileRef = transform.Coordinates.GetTileRef(EntityManager, _mapManager);
|
||||
|
||||
if (tileRef != null)
|
||||
{
|
||||
|
||||
@@ -63,13 +63,13 @@ namespace Content.Server.Engineering.EntitySystems
|
||||
if (component.Deleted || !IsTileClear())
|
||||
return;
|
||||
|
||||
if (TryComp(uid, out StackComponent? stackComp)
|
||||
if (EntityManager.TryGetComponent(uid, out StackComponent? stackComp)
|
||||
&& component.RemoveOnInteract && !_stackSystem.Use(uid, 1, stackComp))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Spawn(component.Prototype, args.ClickLocation.SnapToGrid(grid));
|
||||
EntityManager.SpawnEntity(component.Prototype, args.ClickLocation.SnapToGrid(grid));
|
||||
|
||||
if (component.RemoveOnInteract && stackComp == null)
|
||||
TryQueueDel(uid);
|
||||
|
||||
@@ -10,6 +10,7 @@ using Content.Server.Botany;
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Server.Emp;
|
||||
using Content.Server.Explosion.EntitySystems;
|
||||
using Content.Server.Flash;
|
||||
using Content.Server.Fluids.EntitySystems;
|
||||
using Content.Server.Ghost.Roles.Components;
|
||||
using Content.Server.Medical;
|
||||
@@ -22,13 +23,13 @@ using Content.Server.Temperature.Systems;
|
||||
using Content.Server.Traits.Assorted;
|
||||
using Content.Server.Zombies;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.Coordinates.Helpers;
|
||||
using Content.Shared.EntityEffects.EffectConditions;
|
||||
using Content.Shared.EntityEffects.Effects.PlantMetabolism;
|
||||
using Content.Shared.EntityEffects.Effects.StatusEffects;
|
||||
using Content.Shared.EntityEffects.Effects;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.Flash;
|
||||
using Content.Shared.Maps;
|
||||
using Content.Shared.Mind.Components;
|
||||
using Content.Shared.Popups;
|
||||
@@ -37,6 +38,7 @@ using Content.Shared.Zombies;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
@@ -54,7 +56,7 @@ public sealed class EntityEffectSystem : EntitySystem
|
||||
[Dependency] private readonly EmpSystem _emp = default!;
|
||||
[Dependency] private readonly ExplosionSystem _explosion = default!;
|
||||
[Dependency] private readonly FlammableSystem _flammable = default!;
|
||||
[Dependency] private readonly SharedFlashSystem _flash = default!;
|
||||
[Dependency] private readonly FlashSystem _flash = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
@@ -72,7 +74,6 @@ public sealed class EntityEffectSystem : EntitySystem
|
||||
[Dependency] private readonly TemperatureSystem _temperature = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _xform = default!;
|
||||
[Dependency] private readonly VomitSystem _vomit = default!;
|
||||
[Dependency] private readonly TurfSystem _turf = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -519,7 +520,7 @@ public sealed class EntityEffectSystem : EntitySystem
|
||||
|
||||
var spreadAmount = (int) Math.Max(0, Math.Ceiling((reagentArgs.Quantity / args.Effect.OverflowThreshold).Float()));
|
||||
var splitSolution = reagentArgs.Source.SplitSolution(reagentArgs.Source.Volume);
|
||||
var transform = Comp<TransformComponent>(reagentArgs.TargetEntity);
|
||||
var transform = EntityManager.GetComponent<TransformComponent>(reagentArgs.TargetEntity);
|
||||
var mapCoords = _xform.GetMapCoordinates(reagentArgs.TargetEntity, xform: transform);
|
||||
|
||||
if (!_mapManager.TryFindGridAt(mapCoords, out var gridUid, out var grid) ||
|
||||
@@ -528,11 +529,11 @@ public sealed class EntityEffectSystem : EntitySystem
|
||||
return;
|
||||
}
|
||||
|
||||
if (_spreader.RequiresFloorToSpread(args.Effect.PrototypeId) && _turf.IsSpace(tileRef))
|
||||
if (_spreader.RequiresFloorToSpread(args.Effect.PrototypeId) && tileRef.Tile.IsSpace())
|
||||
return;
|
||||
|
||||
var coords = _map.MapToGrid(gridUid, mapCoords);
|
||||
var ent = Spawn(args.Effect.PrototypeId, coords.SnapToGrid());
|
||||
var ent = EntityManager.SpawnEntity(args.Effect.PrototypeId, coords.SnapToGrid());
|
||||
|
||||
_smoke.StartSmoke(ent, splitSolution, args.Effect.Duration, spreadAmount);
|
||||
|
||||
@@ -559,11 +560,11 @@ public sealed class EntityEffectSystem : EntitySystem
|
||||
return;
|
||||
|
||||
cleanseRate *= reagentArgs.Scale.Float();
|
||||
_bloodstream.FlushChemicals(args.Args.TargetEntity, reagentArgs.Reagent, cleanseRate);
|
||||
_bloodstream.FlushChemicals(args.Args.TargetEntity, reagentArgs.Reagent.ID, cleanseRate);
|
||||
}
|
||||
else
|
||||
{
|
||||
_bloodstream.FlushChemicals(args.Args.TargetEntity, null, cleanseRate);
|
||||
_bloodstream.FlushChemicals(args.Args.TargetEntity, "", cleanseRate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,7 +643,7 @@ public sealed class EntityEffectSystem : EntitySystem
|
||||
|
||||
private void OnExecuteEmpReactionEffect(ref ExecuteEntityEffectEvent<EmpReactionEffect> args)
|
||||
{
|
||||
var transform = Comp<TransformComponent>(args.Args.TargetEntity);
|
||||
var transform = EntityManager.GetComponent<TransformComponent>(args.Args.TargetEntity);
|
||||
|
||||
var range = args.Effect.EmpRangePerUnit;
|
||||
|
||||
@@ -698,7 +699,7 @@ public sealed class EntityEffectSystem : EntitySystem
|
||||
|
||||
private void OnExecuteFlashReactionEffect(ref ExecuteEntityEffectEvent<FlashReactionEffect> args)
|
||||
{
|
||||
var transform = Comp<TransformComponent>(args.Args.TargetEntity);
|
||||
var transform = EntityManager.GetComponent<TransformComponent>(args.Args.TargetEntity);
|
||||
|
||||
var range = 1f;
|
||||
|
||||
@@ -709,7 +710,7 @@ public sealed class EntityEffectSystem : EntitySystem
|
||||
args.Args.TargetEntity,
|
||||
null,
|
||||
range,
|
||||
args.Effect.Duration,
|
||||
args.Effect.Duration * 1000,
|
||||
slowTo: args.Effect.SlowTo,
|
||||
sound: args.Effect.Sound);
|
||||
|
||||
@@ -765,7 +766,7 @@ public sealed class EntityEffectSystem : EntitySystem
|
||||
ghostRole = AddComp<GhostRoleComponent>(uid);
|
||||
EnsureComp<GhostTakeoverAvailableComponent>(uid);
|
||||
|
||||
var entityData = Comp<MetaDataComponent>(uid);
|
||||
var entityData = EntityManager.GetComponent<MetaDataComponent>(uid);
|
||||
ghostRole.RoleName = entityData.EntityName;
|
||||
ghostRole.RoleDescription = Loc.GetString("ghost-role-information-cognizine-description");
|
||||
}
|
||||
@@ -781,7 +782,7 @@ public sealed class EntityEffectSystem : EntitySystem
|
||||
amt *= reagentArgs.Scale.Float();
|
||||
}
|
||||
|
||||
_bloodstream.TryModifyBleedAmount((args.Args.TargetEntity, blood), amt);
|
||||
_bloodstream.TryModifyBleedAmount(args.Args.TargetEntity, amt, blood);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -797,7 +798,7 @@ public sealed class EntityEffectSystem : EntitySystem
|
||||
amt *= reagentArgs.Scale;
|
||||
}
|
||||
|
||||
_bloodstream.TryModifyBloodLevel((args.Args.TargetEntity, blood), amt);
|
||||
_bloodstream.TryModifyBloodLevel(args.Args.TargetEntity, amt, blood);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -848,7 +849,7 @@ public sealed class EntityEffectSystem : EntitySystem
|
||||
|
||||
private void OnExecutePlantMutateChemicals(ref ExecuteEntityEffectEvent<PlantMutateChemicals> args)
|
||||
{
|
||||
var plantholder = Comp<PlantHolderComponent>(args.Args.TargetEntity);
|
||||
var plantholder = EntityManager.GetComponent<PlantHolderComponent>(args.Args.TargetEntity);
|
||||
|
||||
if (plantholder.Seed == null)
|
||||
return;
|
||||
@@ -882,7 +883,7 @@ public sealed class EntityEffectSystem : EntitySystem
|
||||
|
||||
private void OnExecutePlantMutateConsumeGasses(ref ExecuteEntityEffectEvent<PlantMutateConsumeGasses> args)
|
||||
{
|
||||
var plantholder = Comp<PlantHolderComponent>(args.Args.TargetEntity);
|
||||
var plantholder = EntityManager.GetComponent<PlantHolderComponent>(args.Args.TargetEntity);
|
||||
|
||||
if (plantholder.Seed == null)
|
||||
return;
|
||||
@@ -904,7 +905,7 @@ public sealed class EntityEffectSystem : EntitySystem
|
||||
|
||||
private void OnExecutePlantMutateExudeGasses(ref ExecuteEntityEffectEvent<PlantMutateExudeGasses> args)
|
||||
{
|
||||
var plantholder = Comp<PlantHolderComponent>(args.Args.TargetEntity);
|
||||
var plantholder = EntityManager.GetComponent<PlantHolderComponent>(args.Args.TargetEntity);
|
||||
|
||||
if (plantholder.Seed == null)
|
||||
return;
|
||||
@@ -926,7 +927,7 @@ public sealed class EntityEffectSystem : EntitySystem
|
||||
|
||||
private void OnExecutePlantMutateHarvest(ref ExecuteEntityEffectEvent<PlantMutateHarvest> args)
|
||||
{
|
||||
var plantholder = Comp<PlantHolderComponent>(args.Args.TargetEntity);
|
||||
var plantholder = EntityManager.GetComponent<PlantHolderComponent>(args.Args.TargetEntity);
|
||||
|
||||
if (plantholder.Seed == null)
|
||||
return;
|
||||
@@ -939,7 +940,7 @@ public sealed class EntityEffectSystem : EntitySystem
|
||||
|
||||
private void OnExecutePlantSpeciesChange(ref ExecuteEntityEffectEvent<PlantSpeciesChange> args)
|
||||
{
|
||||
var plantholder = Comp<PlantHolderComponent>(args.Args.TargetEntity);
|
||||
var plantholder = EntityManager.GetComponent<PlantHolderComponent>(args.Args.TargetEntity);
|
||||
if (plantholder.Seed == null)
|
||||
return;
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace Content.Server.Examine
|
||||
var entity = GetEntity(request.NetEntity);
|
||||
|
||||
if (session.AttachedEntity is not {Valid: true} playerEnt
|
||||
|| !Exists(entity))
|
||||
|| !EntityManager.EntityExists(entity))
|
||||
{
|
||||
RaiseNetworkEvent(new ExamineSystemMessages.ExamineInfoResponseMessage(
|
||||
request.NetEntity, request.Id, _entityNotFoundMessage), channel);
|
||||
|
||||
@@ -66,9 +66,9 @@ public sealed partial class ExplosionSystem
|
||||
if (!_airtightMap.ContainsKey(gridId))
|
||||
_airtightMap[gridId] = new();
|
||||
|
||||
query ??= GetEntityQuery<AirtightComponent>();
|
||||
var damageQuery = GetEntityQuery<DamageableComponent>();
|
||||
var destructibleQuery = GetEntityQuery<DestructibleComponent>();
|
||||
query ??= EntityManager.GetEntityQuery<AirtightComponent>();
|
||||
var damageQuery = EntityManager.GetEntityQuery<DamageableComponent>();
|
||||
var destructibleQuery = EntityManager.GetEntityQuery<DestructibleComponent>();
|
||||
var anchoredEnumerator = _mapSystem.GetAnchoredEntitiesEnumerator(gridId, grid, tile);
|
||||
|
||||
while (anchoredEnumerator.MoveNext(out var uid))
|
||||
@@ -99,7 +99,7 @@ public sealed partial class ExplosionSystem
|
||||
if (!airtight.AirBlocked)
|
||||
return;
|
||||
|
||||
if (!TryComp(uid, out TransformComponent? transform) || !transform.Anchored)
|
||||
if (!EntityManager.TryGetComponent(uid, out TransformComponent? transform) || !transform.Anchored)
|
||||
return;
|
||||
|
||||
if (!TryComp<MapGridComponent>(transform.GridUid, out var grid))
|
||||
|
||||
@@ -102,7 +102,7 @@ public sealed partial class ExplosionSystem
|
||||
continue;
|
||||
}
|
||||
|
||||
var xforms = GetEntityQuery<TransformComponent>();
|
||||
var xforms = EntityManager.GetEntityQuery<TransformComponent>();
|
||||
var xform = xforms.GetComponent(gridToTransform);
|
||||
var (_, gridWorldRotation, gridWorldMatrix, invGridWorldMatrid) = _transformSystem.GetWorldPositionRotationMatrixWithInv(xform, xforms);
|
||||
|
||||
|
||||
@@ -913,10 +913,10 @@ sealed class Explosion
|
||||
/// <summary>
|
||||
/// Data needed to spawn an explosion with <see cref="ExplosionSystem.SpawnExplosion"/>.
|
||||
/// </summary>
|
||||
public sealed class QueuedExplosion(ExplosionPrototype proto)
|
||||
public sealed class QueuedExplosion
|
||||
{
|
||||
public MapCoordinates Epicenter;
|
||||
public ExplosionPrototype Proto = proto;
|
||||
public ExplosionPrototype Proto = new();
|
||||
public float TotalIntensity, Slope, MaxTileIntensity, TileBreakScale;
|
||||
public int MaxTileBreak;
|
||||
public bool CanCreateVacuum;
|
||||
|
||||
@@ -167,7 +167,7 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem
|
||||
user);
|
||||
|
||||
if (explosive.DeleteAfterExplosion ?? delete)
|
||||
QueueDel(uid);
|
||||
EntityManager.QueueDeleteEntity(uid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -306,9 +306,10 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem
|
||||
return;
|
||||
}
|
||||
|
||||
var boom = new QueuedExplosion(type)
|
||||
var boom = new QueuedExplosion()
|
||||
{
|
||||
Epicenter = epicenter,
|
||||
Proto = type,
|
||||
TotalIntensity = totalIntensity,
|
||||
Slope = slope,
|
||||
MaxTileIntensity = maxTileIntensity,
|
||||
|
||||
@@ -20,7 +20,6 @@ public sealed class SmokeOnTriggerSystem : SharedSmokeOnTriggerSystem
|
||||
[Dependency] private readonly SmokeSystem _smoke = default!;
|
||||
[Dependency] private readonly TransformSystem _transform = default!;
|
||||
[Dependency] private readonly SpreaderSystem _spreader = default!;
|
||||
[Dependency] private readonly TurfSystem _turf = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -40,7 +39,7 @@ public sealed class SmokeOnTriggerSystem : SharedSmokeOnTriggerSystem
|
||||
return;
|
||||
}
|
||||
|
||||
if (_spreader.RequiresFloorToSpread(comp.SmokePrototype.ToString()) && _turf.IsSpace(tileRef))
|
||||
if (_spreader.RequiresFloorToSpread(comp.SmokePrototype.ToString()) && tileRef.Tile.IsSpace())
|
||||
return;
|
||||
|
||||
var coords = _map.MapToGrid(gridUid, mapCoords);
|
||||
|
||||
@@ -82,7 +82,7 @@ public sealed partial class TriggerSystem
|
||||
|
||||
private void SetProximityAppearance(EntityUid uid, TriggerOnProximityComponent component)
|
||||
{
|
||||
if (TryComp(uid, out AppearanceComponent? appearance))
|
||||
if (EntityManager.TryGetComponent(uid, out AppearanceComponent? appearance))
|
||||
{
|
||||
_appearance.SetData(uid, ProximityTriggerVisualState.State, component.Enabled ? ProximityTriggerVisuals.Inactive : ProximityTriggerVisuals.Off, appearance);
|
||||
}
|
||||
@@ -107,7 +107,7 @@ public sealed partial class TriggerSystem
|
||||
// Queue a visual update for when the animation is complete.
|
||||
component.NextVisualUpdate = curTime + component.AnimationDuration;
|
||||
|
||||
if (TryComp(uid, out AppearanceComponent? appearance))
|
||||
if (EntityManager.TryGetComponent(uid, out AppearanceComponent? appearance))
|
||||
{
|
||||
_appearance.SetData(uid, ProximityTriggerVisualState.State, ProximityTriggerVisuals.Active, appearance);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.Explosion.Components;
|
||||
using Content.Shared.Flash;
|
||||
using Content.Server.Flash;
|
||||
using Content.Server.Electrocution;
|
||||
using Content.Server.Pinpointer;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
@@ -69,7 +69,7 @@ namespace Content.Server.Explosion.EntitySystems
|
||||
{
|
||||
[Dependency] private readonly ExplosionSystem _explosions = default!;
|
||||
[Dependency] private readonly FixtureSystem _fixtures = default!;
|
||||
[Dependency] private readonly SharedFlashSystem _flashSystem = default!;
|
||||
[Dependency] private readonly FlashSystem _flashSystem = default!;
|
||||
[Dependency] private readonly SharedBroadphaseSystem _broadphase = default!;
|
||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||
@@ -196,13 +196,14 @@ namespace Content.Server.Explosion.EntitySystems
|
||||
|
||||
private void HandleFlashTrigger(EntityUid uid, FlashOnTriggerComponent component, TriggerEvent args)
|
||||
{
|
||||
_flashSystem.FlashArea(uid, args.User, component.Range, component.Duration, probability: component.Probability);
|
||||
// TODO Make flash durations sane ffs.
|
||||
_flashSystem.FlashArea(uid, args.User, component.Range, component.Duration * 1000f, probability: component.Probability);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void HandleDeleteTrigger(EntityUid uid, DeleteOnTriggerComponent component, TriggerEvent args)
|
||||
{
|
||||
QueueDel(uid);
|
||||
EntityManager.QueueDeleteEntity(uid);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ public sealed class TwoStageTriggerSystem : EntitySystem
|
||||
RemComp(uid, c);
|
||||
|
||||
_serializationManager.CopyTo(entry.Component, ref temp);
|
||||
AddComp(uid, comp);
|
||||
EntityManager.AddComponent(uid, comp);
|
||||
}
|
||||
component.ComponentsIsLoaded = true;
|
||||
}
|
||||
|
||||
@@ -591,7 +591,7 @@ public sealed class FaxSystem : EntitySystem
|
||||
var printout = component.PrintingQueue.Dequeue();
|
||||
|
||||
var entityToSpawn = printout.PrototypeId.Length == 0 ? component.PrintPaperId.ToString() : printout.PrototypeId;
|
||||
var printed = Spawn(entityToSpawn, Transform(uid).Coordinates);
|
||||
var printed = EntityManager.SpawnEntity(entityToSpawn, Transform(uid).Coordinates);
|
||||
|
||||
if (TryComp<PaperComponent>(printed, out var paper))
|
||||
{
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using Content.Shared.Damage;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Flash.Components;
|
||||
|
||||
[RegisterComponent, Access(typeof(DamagedByFlashingSystem))]
|
||||
public sealed partial class DamagedByFlashingComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// damage from flashing
|
||||
/// </summary>
|
||||
[DataField(required: true), ViewVariables(VVAccess.ReadWrite)]
|
||||
public DamageSpecifier FlashDamage = new();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user