diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 177e6a0fe6d..ae1287bc28a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -41,41 +41,36 @@ jobs: - name: Package client run: dotnet run --project Content.Packaging client --no-wipe-release - - name: Update Build Info - run: Tools/gen_build_info.py - - - name: Shuffle files around - run: | - mkdir "release/${{ github.sha }}" - mv release/*.zip "release/${{ github.sha }}" - - - name: Upload files to centcomm - uses: appleboy/scp-action@master + - name: Upload build artifact + id: artifact-upload-step + uses: actions/upload-artifact@v4 with: - host: ${{ secrets.PUBLISH_HOST }} - username: ${{ secrets.PUBLISH_USER }} - key: ${{ secrets.PUBLISH_KEY }} - port: ${{ secrets.PUBLISH_PORT }} - source: "release/${{ github.sha }}" - target: "/var/www/builds.delta-v.org/delta-v/builds/" - strip_components: 1 + name: build + path: release/*.zip + compression-level: 0 + retention-days: 0 - - name: Update manifest JSON - uses: appleboy/ssh-action@master - with: - host: ${{ secrets.PUBLISH_HOST }} - username: ${{ secrets.PUBLISH_USER }} - key: ${{ secrets.PUBLISH_KEY }} - port: ${{ secrets.PUBLISH_PORT }} - script: /home/deltav/publish/push.ps1 ${{ github.sha }} + - name: Publish version + run: Tools/publish_github_artifact.py + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} + ARTIFACT_ID: ${{ steps.artifact-upload-step.outputs.artifact-id }} + GITHUB_REPOSITORY: ${{ vars.GITHUB_REPOSITORY }} - name: Publish changelog (Discord) run: Tools/actions_changelogs_since_last_run.py env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CHANGELOG_DIR: ${{ vars.CHANGELOG_DIR }} DISCORD_WEBHOOK_URL: ${{ secrets.CHANGELOG_DISCORD_WEBHOOK }} - name: Publish changelog (RSS) run: Tools/actions_changelog_rss.py env: CHANGELOG_RSS_KEY: ${{ secrets.CHANGELOG_RSS_KEY }} + + - uses: geekyeggo/delete-artifact@v5 + if: always() + with: + name: build diff --git a/.github/workflows/test-packaging.yml b/.github/workflows/test-packaging.yml index 27cf5d2d7b1..a8ef52ef526 100644 --- a/.github/workflows/test-packaging.yml +++ b/.github/workflows/test-packaging.yml @@ -65,9 +65,6 @@ jobs: - name: Package client run: dotnet run --project Content.Packaging client --no-wipe-release - - name: Update Build Info - run: Tools/gen_build_info.py - - name: Shuffle files around run: | mkdir "release/${{ github.sha }}" diff --git a/.vscode/settings.json b/.vscode/settings.json index 0e0d3ae890c..dc6e26cbeaa 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,10 @@ { "omnisharp.analyzeOpenDocumentsOnly": true, - "dotnet.defaultSolution": "SpaceStation14.sln" + "dotnet.defaultSolution": "SpaceStation14.sln", + "json.schemas": [ + { + "fileMatch": [ "**/meta.json" ], + "url": "https://raw.githubusercontent.com/Simple-Station/Einstein-Engines/master/.github/rsi-schema.json" + } + ] } diff --git a/Content.Client/Alerts/ClientAlertsSystem.cs b/Content.Client/Alerts/ClientAlertsSystem.cs index 237f24e3eae..223bf7876ac 100644 --- a/Content.Client/Alerts/ClientAlertsSystem.cs +++ b/Content.Client/Alerts/ClientAlertsSystem.cs @@ -49,24 +49,23 @@ public IReadOnlyDictionary? ActiveAlerts protected override void AfterShowAlert(Entity alerts) { - if (_playerManager.LocalEntity != alerts.Owner) - return; - - SyncAlerts?.Invoke(this, alerts.Comp.Alerts); + UpdateHud(alerts); } - protected override void AfterClearAlert(Entity alertsComponent) + protected override void AfterClearAlert(Entity alerts) { - if (_playerManager.LocalEntity != alertsComponent.Owner) - return; + UpdateHud(alerts); + } - SyncAlerts?.Invoke(this, alertsComponent.Comp.Alerts); + private void ClientAlertsHandleState(Entity alerts, ref AfterAutoHandleStateEvent args) + { + UpdateHud(alerts); } - private void ClientAlertsHandleState(EntityUid uid, AlertsComponent component, ref AfterAutoHandleStateEvent args) + private void UpdateHud(Entity entity) { - if (_playerManager.LocalEntity == uid) - SyncAlerts?.Invoke(this, component.Alerts); + if (_playerManager.LocalEntity == entity.Owner) + SyncAlerts?.Invoke(this, entity.Comp.Alerts); } private void OnPlayerAttached(EntityUid uid, AlertsComponent component, LocalPlayerAttachedEvent args) diff --git a/Content.Client/Announcements/Systems/AnnouncerSystem.cs b/Content.Client/Announcements/Systems/AnnouncerSystem.cs new file mode 100644 index 00000000000..de76396f705 --- /dev/null +++ b/Content.Client/Announcements/Systems/AnnouncerSystem.cs @@ -0,0 +1,69 @@ +using Content.Client.Audio; +using Content.Shared.Announcements.Events; +using Content.Shared.Announcements.Systems; +using Content.Shared.CCVar; +using Robust.Client.Audio; +using Robust.Client.Player; +using Robust.Client.ResourceManagement; +using Robust.Shared.Audio.Sources; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Configuration; + +namespace Content.Client.Announcements.Systems; + +public sealed class AnnouncerSystem : SharedAnnouncerSystem +{ + [Dependency] private readonly IPlayerManager _player = default!; + [Dependency] private readonly IConfigurationManager _config = default!; + [Dependency] private readonly IResourceCache _cache = default!; + [Dependency] private readonly IAudioManager _audioManager = default!; + + private IAudioSource? AnnouncerSource { get; set; } + private float AnnouncerVolume { get; set; } + + + public override void Initialize() + { + base.Initialize(); + + AnnouncerVolume = _config.GetCVar(CCVars.AnnouncerVolume) * 100f / ContentAudioSystem.AnnouncerMultiplier; + + SubscribeNetworkEvent(OnAnnouncementReceived); + _config.OnValueChanged(CCVars.AnnouncerVolume, OnAnnouncerVolumeChanged); + } + + public override void Shutdown() + { + base.Shutdown(); + + _config.UnsubValueChanged(CCVars.AnnouncerVolume, OnAnnouncerVolumeChanged); + } + + + private void OnAnnouncerVolumeChanged(float value) + { + AnnouncerVolume = value; + + if (AnnouncerSource != null) + AnnouncerSource.Gain = AnnouncerVolume; + } + + private void OnAnnouncementReceived(AnnouncementSendEvent ev) + { + if (!ev.Recipients.Contains(_player.LocalSession!.UserId) + || !_cache.TryGetResource(GetAnnouncementPath(ev.AnnouncementId, ev.AnnouncerId), + out var resource)) + return; + + var source = _audioManager.CreateAudioSource(resource); + if (source != null) + { + source.Gain = AnnouncerVolume * SharedAudioSystem.VolumeToGain(ev.AudioParams.Volume); + source.Global = true; + } + + AnnouncerSource?.Dispose(); + AnnouncerSource = source; + AnnouncerSource?.StartPlaying(); + } +} diff --git a/Content.Client/Audio/AmbientSoundSystem.cs b/Content.Client/Audio/AmbientSoundSystem.cs index 9d30cabb1ec..0206017baef 100644 --- a/Content.Client/Audio/AmbientSoundSystem.cs +++ b/Content.Client/Audio/AmbientSoundSystem.cs @@ -50,7 +50,6 @@ protected override void QueueUpdate(EntityUid uid, AmbientSoundComponent ambienc private static AudioParams _params = AudioParams.Default .WithVariation(0.01f) .WithLoop(true) - .WithAttenuation(Attenuation.LinearDistance) .WithMaxDistance(7f); /// diff --git a/Content.Client/Audio/ContentAudioSystem.LobbyMusic.cs b/Content.Client/Audio/ContentAudioSystem.LobbyMusic.cs index 0fdcc7a86dd..92c5b7a4191 100644 --- a/Content.Client/Audio/ContentAudioSystem.LobbyMusic.cs +++ b/Content.Client/Audio/ContentAudioSystem.LobbyMusic.cs @@ -23,8 +23,8 @@ public sealed partial class ContentAudioSystem [Dependency] private readonly IStateManager _stateManager = default!; [Dependency] private readonly IResourceCache _resourceCache = default!; - private readonly AudioParams _lobbySoundtrackParams = new(-5f, 1, "Master", 0, 0, 0, false, 0f); - private readonly AudioParams _roundEndSoundEffectParams = new(-5f, 1, "Master", 0, 0, 0, false, 0f); + private readonly AudioParams _lobbySoundtrackParams = new(-5f, 1, 0, 0, 0, false, 0f); + private readonly AudioParams _roundEndSoundEffectParams = new(-5f, 1, 0, 0, 0, false, 0f); /// /// EntityUid of lobby restart sound component. diff --git a/Content.Client/Audio/ContentAudioSystem.cs b/Content.Client/Audio/ContentAudioSystem.cs index f62b34b492c..a79ff74e797 100644 --- a/Content.Client/Audio/ContentAudioSystem.cs +++ b/Content.Client/Audio/ContentAudioSystem.cs @@ -29,7 +29,8 @@ public sealed partial class ContentAudioSystem : SharedContentAudioSystem public const float AmbientMusicMultiplier = 3f; public const float LobbyMultiplier = 3f; public const float InterfaceMultiplier = 2f; - + public const float AnnouncerMultiplier = 3f; + public override void Initialize() { base.Initialize(); diff --git a/Content.Client/Clothing/ClientClothingSystem.cs b/Content.Client/Clothing/ClientClothingSystem.cs index fbe9d5ec5bb..7e78ac7d707 100644 --- a/Content.Client/Clothing/ClientClothingSystem.cs +++ b/Content.Client/Clothing/ClientClothingSystem.cs @@ -133,7 +133,7 @@ private bool TryGetDefaultVisuals(EntityUid uid, ClothingComponent clothing, str else if (TryComp(uid, out SpriteComponent? sprite)) rsi = sprite.BaseRSI; - if (rsi == null || rsi.Path == null) + if (rsi == null) return false; var correctedSlot = slot; diff --git a/Content.Client/Doors/DoorSystem.cs b/Content.Client/Doors/DoorSystem.cs index 473ae97059a..bc52730b0e7 100644 --- a/Content.Client/Doors/DoorSystem.cs +++ b/Content.Client/Doors/DoorSystem.cs @@ -4,14 +4,12 @@ using Robust.Client.GameObjects; using Robust.Client.ResourceManagement; using Robust.Shared.Serialization.TypeSerializers.Implementations; -using Robust.Shared.Timing; namespace Content.Client.Doors; public sealed class DoorSystem : SharedDoorSystem { [Dependency] private readonly AnimationPlayerSystem _animationSystem = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IResourceCache _resourceCache = default!; public override void Initialize() diff --git a/Content.Client/IconSmoothing/IconSmoothSystem.cs b/Content.Client/IconSmoothing/IconSmoothSystem.cs index 0ab33c65202..4b025608465 100644 --- a/Content.Client/IconSmoothing/IconSmoothSystem.cs +++ b/Content.Client/IconSmoothing/IconSmoothSystem.cs @@ -16,8 +16,6 @@ namespace Content.Client.IconSmoothing [UsedImplicitly] public sealed partial class IconSmoothSystem : EntitySystem { - [Dependency] private readonly IMapManager _mapManager = default!; - private readonly Queue _dirtyEntities = new(); private readonly Queue _anchorChangedEntities = new(); @@ -47,7 +45,7 @@ private void OnStartup(EntityUid uid, IconSmoothComponent component, ComponentSt var xform = Transform(uid); if (xform.Anchored) { - component.LastPosition = _mapManager.TryGetGrid(xform.GridUid, out var grid) + component.LastPosition = TryComp(xform.GridUid, out var grid) ? (xform.GridUid.Value, grid.TileIndicesFor(xform.Coordinates)) : (null, new Vector2i(0, 0)); @@ -134,7 +132,7 @@ public void DirtyNeighbours(EntityUid uid, IconSmoothComponent? comp = null, Tra Vector2i pos; - if (transform.Anchored && _mapManager.TryGetGrid(transform.GridUid, out var grid)) + if (transform.Anchored && TryComp(transform.GridUid, out var grid)) { pos = grid.CoordinatesToTile(transform.Coordinates); } @@ -144,7 +142,7 @@ public void DirtyNeighbours(EntityUid uid, IconSmoothComponent? comp = null, Tra if (comp.LastPosition is not (EntityUid gridId, Vector2i oldPos)) return; - if (!_mapManager.TryGetGrid(gridId, out grid)) + if (!TryComp(gridId, out grid)) return; pos = oldPos; @@ -206,7 +204,7 @@ private void CalculateNewSprite(EntityUid uid, { var directions = DirectionFlag.None; - if (_mapManager.TryGetGrid(xform.GridUid, out grid)) + if (TryComp(xform.GridUid, out grid)) { var pos = grid.TileIndicesFor(xform.Coordinates); @@ -240,7 +238,7 @@ private void CalculateNewSprite(EntityUid uid, if (xform.Anchored) { - if (!_mapManager.TryGetGrid(xform.GridUid, out grid)) + if (!TryComp(xform.GridUid, out grid)) { Log.Error($"Failed to calculate IconSmoothComponent sprite in {uid} because grid {xform.GridUid} was missing."); return; diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs index 6033a95f17d..63ac5efaad8 100644 --- a/Content.Client/Input/ContentContexts.cs +++ b/Content.Client/Input/ContentContexts.cs @@ -69,6 +69,7 @@ public static void SetupContexts(IInputContextContainer contexts) human.AddFunction(ContentKeyFunctions.OpenBackpack); human.AddFunction(ContentKeyFunctions.OpenBelt); human.AddFunction(ContentKeyFunctions.OfferItem); + human.AddFunction(ContentKeyFunctions.ToggleStanding); human.AddFunction(ContentKeyFunctions.MouseMiddle); human.AddFunction(ContentKeyFunctions.ArcadeUp); human.AddFunction(ContentKeyFunctions.ArcadeDown); diff --git a/Content.Client/Items/Systems/ItemSystem.cs b/Content.Client/Items/Systems/ItemSystem.cs index e406ba2b557..5e60d06d0ce 100644 --- a/Content.Client/Items/Systems/ItemSystem.cs +++ b/Content.Client/Items/Systems/ItemSystem.cs @@ -93,7 +93,7 @@ private bool TryGetDefaultVisuals(EntityUid uid, ItemComponent item, string defa else if (TryComp(uid, out SpriteComponent? sprite)) rsi = sprite.BaseRSI; - if (rsi == null || rsi.Path == null) + if (rsi == null) return false; var state = (item.HeldPrefix == null) diff --git a/Content.Client/Movement/Systems/JetpackSystem.cs b/Content.Client/Movement/Systems/JetpackSystem.cs index f0836ee9b6f..b7f5e48821f 100644 --- a/Content.Client/Movement/Systems/JetpackSystem.cs +++ b/Content.Client/Movement/Systems/JetpackSystem.cs @@ -4,6 +4,7 @@ using Content.Shared.Movement.Systems; using Robust.Client.GameObjects; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Timing; @@ -12,7 +13,6 @@ namespace Content.Client.Movement.Systems; public sealed class JetpackSystem : SharedJetpackSystem { [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly ClothingSystem _clothing = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; @@ -75,7 +75,7 @@ private void CreateParticles(EntityUid uid) var coordinates = uidXform.Coordinates; var gridUid = coordinates.GetGridUid(EntityManager); - if (_mapManager.TryGetGrid(gridUid, out var grid)) + if (TryComp(gridUid, out var grid)) { coordinates = new EntityCoordinates(gridUid.Value, grid.WorldToLocal(coordinates.ToMapPos(EntityManager, _transform))); } diff --git a/Content.Client/NPC/PathfindingSystem.cs b/Content.Client/NPC/PathfindingSystem.cs index 7bf3df1f0b9..709601a57b6 100644 --- a/Content.Client/NPC/PathfindingSystem.cs +++ b/Content.Client/NPC/PathfindingSystem.cs @@ -289,7 +289,6 @@ private void DrawScreen(OverlayDrawArgs args, DrawingHandleScreen screenHandle) var invGridMatrix = gridXform.InvWorldMatrix; DebugPathPoly? nearest = null; - var nearestDistance = float.MaxValue; foreach (var poly in tile) { diff --git a/Content.Client/NodeContainer/NodeVisualizationOverlay.cs b/Content.Client/NodeContainer/NodeVisualizationOverlay.cs index f10eb9ed8b1..691bcb41dbd 100644 --- a/Content.Client/NodeContainer/NodeVisualizationOverlay.cs +++ b/Content.Client/NodeContainer/NodeVisualizationOverlay.cs @@ -80,7 +80,7 @@ private void DrawScreen(in OverlayDrawArgs args) var xform = _entityManager.GetComponent(_entityManager.GetEntity(node.Entity)); - if (!_mapManager.TryGetGrid(xform.GridUid, out var grid)) + if (!_entityManager.TryGetComponent(xform.GridUid, out var grid)) return; var gridTile = grid.TileIndicesFor(xform.Coordinates); @@ -145,7 +145,7 @@ private void DrawWorld(in OverlayDrawArgs overlayDrawArgs) foreach (var (gridId, gridDict) in _gridIndex) { - var grid = _mapManager.GetGrid(gridId); + var grid = _entityManager.GetComponent(gridId); var (_, _, worldMatrix, invMatrix) = _entityManager.GetComponent(gridId).GetWorldPositionRotationMatrixWithInv(); var lCursorBox = invMatrix.TransformBox(cursorBox); diff --git a/Content.Client/Options/UI/Tabs/AudioTab.xaml b/Content.Client/Options/UI/Tabs/AudioTab.xaml index e54b0dc34ee..8dd723d446d 100644 --- a/Content.Client/Options/UI/Tabs/AudioTab.xaml +++ b/Content.Client/Options/UI/Tabs/AudioTab.xaml @@ -100,6 +100,19 @@ protected async Task AddGravity(EntityUid? uid = null) { - var target = uid ?? MapData.GridUid; + var target = uid ?? MapData.Grid; await Server.WaitPost(() => { var gravity = SEntMan.EnsureComponent(target); diff --git a/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs b/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs index bed27ba6efe..a4ed31e9983 100644 --- a/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs +++ b/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs @@ -184,7 +184,7 @@ public virtual async Task Setup() await Pair.CreateTestMap(); PlayerCoords = SEntMan.GetNetCoordinates(MapData.GridCoords.Offset(new Vector2(0.5f, 0.5f)).WithEntityId(MapData.MapUid, Transform, SEntMan)); TargetCoords = SEntMan.GetNetCoordinates(MapData.GridCoords.Offset(new Vector2(1.5f, 0.5f)).WithEntityId(MapData.MapUid, Transform, SEntMan)); - await SetTile(Plating, grid: MapData.MapGrid); + await SetTile(Plating, grid: MapData.Grid.Comp); // Get player data var sPlayerMan = Server.ResolveDependency(); diff --git a/Content.IntegrationTests/Tests/Interaction/MovementTest.cs b/Content.IntegrationTests/Tests/Interaction/MovementTest.cs index 553b031c2b7..dc5aec92cfc 100644 --- a/Content.IntegrationTests/Tests/Interaction/MovementTest.cs +++ b/Content.IntegrationTests/Tests/Interaction/MovementTest.cs @@ -31,7 +31,7 @@ public override async Task Setup() for (var i = -Tiles; i <= Tiles; i++) { - await SetTile(Plating, SEntMan.GetNetCoordinates(pCoords.Offset(new Vector2(i, 0))), MapData.MapGrid); + await SetTile(Plating, SEntMan.GetNetCoordinates(pCoords.Offset(new Vector2(i, 0))), MapData.Grid.Comp); } AssertGridCount(1); diff --git a/Content.IntegrationTests/Tests/Linter/StaticFieldValidationTest.cs b/Content.IntegrationTests/Tests/Linter/StaticFieldValidationTest.cs new file mode 100644 index 00000000000..30724b50a6d --- /dev/null +++ b/Content.IntegrationTests/Tests/Linter/StaticFieldValidationTest.cs @@ -0,0 +1,150 @@ +using System.Collections.Generic; +using System.Linq; +using Content.Shared.Tag; +using Robust.Shared.Prototypes; +using Robust.Shared.Reflection; +using Robust.Shared.Serialization.Manager.Attributes; + +namespace Content.IntegrationTests.Tests.Linter; + +/// +/// Verify that the yaml linter successfully validates static fields +/// +[TestFixture] +public sealed class StaticFieldValidationTest +{ + [Test] + public async Task TestStaticFieldValidation() + { + await using var pair = await PoolManager.GetServerClient(); + var protoMan = pair.Server.ProtoMan; + + var protos = new Dictionary>(); + foreach (var kind in protoMan.EnumeratePrototypeKinds()) + { + var ids = protoMan.EnumeratePrototypes(kind).Select(x => x.ID).ToHashSet(); + protos.Add(kind, ids); + } + + Assert.That(protoMan.ValidateStaticFields(typeof(StringValid), protos).Count, Is.Zero); + Assert.That(protoMan.ValidateStaticFields(typeof(StringArrayValid), protos).Count, Is.Zero); + Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdValid), protos).Count, Is.Zero); + Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdArrayValid), protos).Count, Is.Zero); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdTestValid), protos).Count, Is.Zero); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdArrayValid), protos).Count, Is.Zero); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdListValid), protos).Count, Is.Zero); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdSetValid), protos).Count, Is.Zero); + Assert.That(protoMan.ValidateStaticFields(typeof(PrivateProtoIdArrayValid), protos).Count, Is.Zero); + + Assert.That(protoMan.ValidateStaticFields(typeof(StringInvalid), protos).Count, Is.EqualTo(1)); + Assert.That(protoMan.ValidateStaticFields(typeof(StringArrayInvalid), protos).Count, Is.EqualTo(2)); + Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdInvalid), protos).Count, Is.EqualTo(1)); + Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdArrayInvalid), protos).Count, Is.EqualTo(2)); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdTestInvalid), protos).Count, Is.EqualTo(1)); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdArrayInvalid), protos).Count, Is.EqualTo(2)); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdListInvalid), protos).Count, Is.EqualTo(2)); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdSetInvalid), protos).Count, Is.EqualTo(2)); + Assert.That(protoMan.ValidateStaticFields(typeof(PrivateProtoIdArrayInvalid), protos).Count, Is.EqualTo(2)); + + await pair.CleanReturnAsync(); + } + + [TestPrototypes] + private const string TestPrototypes = @" +- type: entity + id: StaticFieldTestEnt + +- type: Tag + id: StaticFieldTestTag +"; + + [Reflect(false)] private sealed class StringValid + { + [ValidatePrototypeId] public static string Tag = "StaticFieldTestTag"; + } + + [Reflect(false)] private sealed class StringInvalid + { + [ValidatePrototypeId] public static string Tag = string.Empty; + } + + [Reflect(false)] private sealed class StringArrayValid + { + [ValidatePrototypeId] public static string[] Tag = {"StaticFieldTestTag", "StaticFieldTestTag"}; + } + + [Reflect(false)] private sealed class StringArrayInvalid + { + [ValidatePrototypeId] public static string[] Tag = {string.Empty, "StaticFieldTestTag", string.Empty}; + } + + [Reflect(false)] private sealed class EntProtoIdValid + { + public static EntProtoId Tag = "StaticFieldTestEnt"; + } + + [Reflect(false)] private sealed class EntProtoIdInvalid + { + public static EntProtoId Tag = string.Empty; + } + + [Reflect(false)] private sealed class EntProtoIdArrayValid + { + public static EntProtoId[] Tag = {"StaticFieldTestEnt", "StaticFieldTestEnt"}; + } + + [Reflect(false)] private sealed class EntProtoIdArrayInvalid + { + public static EntProtoId[] Tag = {string.Empty, "StaticFieldTestEnt", string.Empty}; + } + + [Reflect(false)] private sealed class ProtoIdTestValid + { + public static ProtoId Tag = "StaticFieldTestTag"; + } + + [Reflect(false)] private sealed class ProtoIdTestInvalid + { + public static ProtoId Tag = string.Empty; + } + + [Reflect(false)] private sealed class ProtoIdArrayValid + { + public static ProtoId[] Tag = {"StaticFieldTestTag", "StaticFieldTestTag"}; + } + + [Reflect(false)] private sealed class ProtoIdArrayInvalid + { + public static ProtoId[] Tag = {string.Empty, "StaticFieldTestTag", string.Empty}; + } + + [Reflect(false)] private sealed class ProtoIdListValid + { + public static List> Tag = new() {"StaticFieldTestTag", "StaticFieldTestTag"}; + } + + [Reflect(false)] private sealed class ProtoIdListInvalid + { + public static List> Tag = new() {string.Empty, "StaticFieldTestTag", string.Empty}; + } + + [Reflect(false)] private sealed class ProtoIdSetValid + { + public static HashSet> Tag = new() {"StaticFieldTestTag", "StaticFieldTestTag"}; + } + + [Reflect(false)] private sealed class ProtoIdSetInvalid + { + public static HashSet> Tag = new() {string.Empty, "StaticFieldTestTag", string.Empty, " "}; + } + + [Reflect(false)] private sealed class PrivateProtoIdArrayValid + { + private static ProtoId[] Tag = {"StaticFieldTestTag", "StaticFieldTestTag"}; + } + + [Reflect(false)] private sealed class PrivateProtoIdArrayInvalid + { + private static ProtoId[] Tag = {string.Empty, "StaticFieldTestTag", string.Empty}; + } +} diff --git a/Content.IntegrationTests/Tests/Power/PowerTest.cs b/Content.IntegrationTests/Tests/Power/PowerTest.cs index d4e2cde9b0d..a6af3e6a65b 100644 --- a/Content.IntegrationTests/Tests/Power/PowerTest.cs +++ b/Content.IntegrationTests/Tests/Power/PowerTest.cs @@ -176,16 +176,18 @@ await server.WaitAssertion(() => var map = mapManager.CreateMap(); var grid = mapManager.CreateGrid(map); + var gridOwner = grid.Owner; + // Power only works when anchored for (var i = 0; i < 3; i++) { grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i)); + entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); } - var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates()); - var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 1)); - var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 2)); + var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates()); + var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 1)); + var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 2)); supplier = entityManager.GetComponent(generatorEnt); consumer1 = entityManager.GetComponent(consumerEnt1); @@ -237,16 +239,18 @@ await server.WaitAssertion(() => var map = mapManager.CreateMap(); var grid = mapManager.CreateGrid(map); + var gridOwner = grid.Owner; + // Power only works when anchored for (var i = 0; i < 3; i++) { grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i)); + entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); } - var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates()); - var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 1)); - var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 2)); + var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates()); + var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 1)); + var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 2)); supplier = entityManager.GetComponent(generatorEnt); consumer1 = entityManager.GetComponent(consumerEnt1); @@ -292,16 +296,17 @@ await server.WaitAssertion(() => { var map = mapManager.CreateMap(); var grid = mapManager.CreateGrid(map); + var gridOwner = grid.Owner; // Power only works when anchored for (var i = 0; i < 3; i++) { grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i)); + entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); } - var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates()); - var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 2)); + var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates()); + var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 2)); supplier = entityManager.GetComponent(generatorEnt); consumer = entityManager.GetComponent(consumerEnt); @@ -383,16 +388,17 @@ await server.WaitAssertion(() => { var map = mapManager.CreateMap(); var grid = mapManager.CreateGrid(map); + var gridOwner = grid.Owner; // Power only works when anchored for (var i = 0; i < 3; i++) { grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i)); + entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); } - var generatorEnt = entityManager.SpawnEntity("DischargingBatteryDummy", grid.ToCoordinates()); - var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 2)); + var generatorEnt = entityManager.SpawnEntity("DischargingBatteryDummy", gridOwner.ToCoordinates()); + var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 2)); netBattery = entityManager.GetComponent(generatorEnt); battery = entityManager.GetComponent(generatorEnt); @@ -486,17 +492,18 @@ await server.WaitAssertion(() => { var map = mapManager.CreateMap(); var grid = mapManager.CreateGrid(map); + var gridOwner = grid.Owner; // Power only works when anchored for (var i = 0; i < 3; i++) { grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i)); + entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); } - var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates()); - var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 1)); - var batteryEnt = entityManager.SpawnEntity("DischargingBatteryDummy", grid.ToCoordinates(0, 2)); + var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates()); + var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 1)); + var batteryEnt = entityManager.SpawnEntity("DischargingBatteryDummy", gridOwner.ToCoordinates(0, 2)); netBattery = entityManager.GetComponent(batteryEnt); battery = entityManager.GetComponent(batteryEnt); supplier = entityManager.GetComponent(generatorEnt); @@ -577,16 +584,17 @@ await server.WaitAssertion(() => { var map = mapManager.CreateMap(); var grid = mapManager.CreateGrid(map); + var gridOwner = grid.Owner; // Power only works when anchored for (var i = 0; i < 3; i++) { grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i)); + entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); } - var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates()); - var batteryEnt = entityManager.SpawnEntity("ChargingBatteryDummy", grid.ToCoordinates(0, 2)); + var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates()); + var batteryEnt = entityManager.SpawnEntity("ChargingBatteryDummy", gridOwner.ToCoordinates(0, 2)); supplier = entityManager.GetComponent(generatorEnt); var netBattery = entityManager.GetComponent(batteryEnt); @@ -635,20 +643,21 @@ await server.WaitAssertion(() => { var map = mapManager.CreateMap(); var grid = mapManager.CreateGrid(map); + var gridOwner = grid.Owner; // Power only works when anchored for (var i = 0; i < 4; i++) { grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i)); + entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); } - var terminal = entityManager.SpawnEntity("CableTerminal", grid.ToCoordinates(0, 1)); + var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 1)); entityManager.GetComponent(terminal).LocalRotation = Angle.FromDegrees(180); - var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", grid.ToCoordinates(0, 2)); - var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates(0, 0)); - var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 3)); + var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 2)); + var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 0)); + var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 3)); consumer = entityManager.GetComponent(consumerEnt); supplier = entityManager.GetComponent(supplyEnt); @@ -712,20 +721,21 @@ await server.WaitAssertion(() => { var map = mapManager.CreateMap(); var grid = mapManager.CreateGrid(map); + var gridOwner = grid.Owner; // Power only works when anchored for (var i = 0; i < 4; i++) { grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i)); + entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); } - var terminal = entityManager.SpawnEntity("CableTerminal", grid.ToCoordinates(0, 1)); + var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 1)); entityManager.GetComponent(terminal).LocalRotation = Angle.FromDegrees(180); - var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", grid.ToCoordinates(0, 2)); - var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates(0, 0)); - var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 3)); + var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 2)); + var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 0)); + var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 3)); consumer = entityManager.GetComponent(consumerEnt); supplier = entityManager.GetComponent(supplyEnt); @@ -787,6 +797,7 @@ await server.WaitAssertion(() => { var map = mapManager.CreateMap(); var grid = mapManager.CreateGrid(map); + var gridOwner = grid.Owner; // Map layout here is // C - consumer @@ -800,18 +811,18 @@ await server.WaitAssertion(() => for (var i = 0; i < 5; i++) { grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i)); + entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); } - entityManager.SpawnEntity("CableTerminal", grid.ToCoordinates(0, 2)); - var terminal = entityManager.SpawnEntity("CableTerminal", grid.ToCoordinates(0, 2)); + entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 2)); + var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 2)); entityManager.GetComponent(terminal).LocalRotation = Angle.FromDegrees(180); - var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", grid.ToCoordinates(0, 1)); - var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", grid.ToCoordinates(0, 3)); - var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates(0, 2)); - var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 0)); - var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 4)); + var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 1)); + var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 3)); + var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 2)); + var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 0)); + var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 4)); consumer1 = entityManager.GetComponent(consumerEnt1); consumer2 = entityManager.GetComponent(consumerEnt2); @@ -888,6 +899,7 @@ await server.WaitAssertion(() => { var map = mapManager.CreateMap(); var grid = mapManager.CreateGrid(map); + var gridOwner = grid.Owner; // Layout is two generators, two batteries, and one load. As to why two: because previously this test // would fail ONLY if there were more than two batteries present, because each of them tries to supply @@ -900,16 +912,16 @@ await server.WaitAssertion(() => for (var i = -2; i <= 2; i++) { grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i)); + entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); } - var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", grid.ToCoordinates(0, 2)); - var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", grid.ToCoordinates(0, -2)); + var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 2)); + var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, -2)); - var supplyEnt1 = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates(0, 1)); - var supplyEnt2 = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates(0, -1)); + var supplyEnt1 = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 1)); + var supplyEnt2 = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, -1)); - var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 0)); + var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 0)); consumer = entityManager.GetComponent(consumerEnt); supplier1 = entityManager.GetComponent(supplyEnt1); @@ -981,6 +993,7 @@ await server.WaitAssertion(() => { var map = mapManager.CreateMap(); var grid = mapManager.CreateGrid(map); + var gridOwner = grid.Owner; // Map layout here is // C - consumer @@ -994,18 +1007,18 @@ await server.WaitAssertion(() => for (var i = 0; i < 5; i++) { grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i)); + entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); } - entityManager.SpawnEntity("CableTerminal", grid.ToCoordinates(0, 2)); - var terminal = entityManager.SpawnEntity("CableTerminal", grid.ToCoordinates(0, 2)); + entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 2)); + var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 2)); entityManager.GetComponent(terminal).LocalRotation = Angle.FromDegrees(180); - var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", grid.ToCoordinates(0, 1)); - var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", grid.ToCoordinates(0, 3)); - var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates(0, 2)); - var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 0)); - var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 4)); + var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 1)); + var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 3)); + var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 2)); + var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 0)); + var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 4)); consumer1 = entityManager.GetComponent(consumerEnt1); consumer2 = entityManager.GetComponent(consumerEnt2); @@ -1068,20 +1081,21 @@ await server.WaitPost(() => { var map = mapManager.CreateMap(); var grid = mapManager.CreateGrid(map); + var gridOwner = grid.Owner; // Power only works when anchored for (var i = 0; i < 4; i++) { grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i)); + entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); } - var terminal = entityManager.SpawnEntity("CableTerminal", grid.ToCoordinates(0, 1)); + var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 1)); entityManager.GetComponent(terminal).LocalRotation = Angle.FromDegrees(180); - var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", grid.ToCoordinates(0, 2)); - var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates(0, 0)); - var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 3)); + var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 2)); + var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 0)); + var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 3)); consumer = entityManager.GetComponent(consumerEnt); supplier = entityManager.GetComponent(supplyEnt); @@ -1153,6 +1167,7 @@ await server.WaitAssertion(() => { var map = mapManager.CreateMap(); var grid = mapManager.CreateGrid(map); + var gridOwner = grid.Owner; // Power only works when anchored for (var i = 0; i < 4; i++) @@ -1160,15 +1175,15 @@ await server.WaitAssertion(() => grid.SetTile(new Vector2i(0, i), new Tile(1)); } - var leftEnt = entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, 0)); - entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, 1)); - entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, 2)); - var rightEnt = entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, 3)); + var leftEnt = entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 0)); + entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 1)); + entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 2)); + var rightEnt = entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 3)); - var terminal = entityManager.SpawnEntity("CableTerminal", grid.ToCoordinates(0, 1)); + var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 1)); entityManager.GetComponent(terminal).LocalRotation = Angle.FromDegrees(180); - var battery = entityManager.SpawnEntity("FullBatteryDummy", grid.ToCoordinates(0, 2)); + var battery = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 2)); var batteryNodeContainer = entityManager.GetComponent(battery); if (nodeContainer.TryGetNode(entityManager.GetComponent(leftEnt), @@ -1216,6 +1231,7 @@ await server.WaitAssertion(() => { var map = mapManager.CreateMap(); var grid = mapManager.CreateGrid(map); + var gridOwner = grid.Owner; // Power only works when anchored for (var i = 0; i < 3; i++) @@ -1223,14 +1239,14 @@ await server.WaitAssertion(() => grid.SetTile(new Vector2i(0, i), new Tile(1)); } - entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, 0)); - entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, 1)); - entityManager.SpawnEntity("CableMV", grid.ToCoordinates(0, 1)); - entityManager.SpawnEntity("CableMV", grid.ToCoordinates(0, 2)); + entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 0)); + entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 1)); + entityManager.SpawnEntity("CableMV", gridOwner.ToCoordinates(0, 1)); + entityManager.SpawnEntity("CableMV", gridOwner.ToCoordinates(0, 2)); - var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates(0, 0)); - var substationEnt = entityManager.SpawnEntity("SubstationDummy", grid.ToCoordinates(0, 1)); - var apcEnt = entityManager.SpawnEntity("ApcDummy", grid.ToCoordinates(0, 2)); + var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 0)); + var substationEnt = entityManager.SpawnEntity("SubstationDummy", gridOwner.ToCoordinates(0, 1)); + var apcEnt = entityManager.SpawnEntity("ApcDummy", gridOwner.ToCoordinates(0, 2)); var generatorSupplier = entityManager.GetComponent(generatorEnt); substationNetBattery = entityManager.GetComponent(substationEnt); @@ -1273,6 +1289,7 @@ await server.WaitAssertion(() => { var map = mapManager.CreateMap(); var grid = mapManager.CreateGrid(map); + var gridOwner = grid.Owner; const int range = 5; @@ -1282,15 +1299,15 @@ await server.WaitAssertion(() => grid.SetTile(new Vector2i(0, i), new Tile(1)); } - var apcEnt = entityManager.SpawnEntity("ApcDummy", grid.ToCoordinates(0, 0)); - var apcExtensionEnt = entityManager.SpawnEntity("CableApcExtension", grid.ToCoordinates(0, 0)); + var apcEnt = entityManager.SpawnEntity("ApcDummy", gridOwner.ToCoordinates(0, 0)); + var apcExtensionEnt = entityManager.SpawnEntity("CableApcExtension", gridOwner.ToCoordinates(0, 0)); // Create a powered receiver in range (range is 0 indexed) - var powerReceiverEnt = entityManager.SpawnEntity("ApcPowerReceiverDummy", grid.ToCoordinates(0, range - 1)); + var powerReceiverEnt = entityManager.SpawnEntity("ApcPowerReceiverDummy", gridOwner.ToCoordinates(0, range - 1)); receiver = entityManager.GetComponent(powerReceiverEnt); // Create an unpowered receiver outside range - var unpoweredReceiverEnt = entityManager.SpawnEntity("ApcPowerReceiverDummy", grid.ToCoordinates(0, range)); + var unpoweredReceiverEnt = entityManager.SpawnEntity("ApcPowerReceiverDummy", gridOwner.ToCoordinates(0, range)); unpoweredReceiver = entityManager.GetComponent(unpoweredReceiverEnt); var battery = entityManager.GetComponent(apcEnt); diff --git a/Content.IntegrationTests/Tests/PrototypeSaveTest.cs b/Content.IntegrationTests/Tests/PrototypeSaveTest.cs index 6096c497efa..9e26fa5eaa2 100644 --- a/Content.IntegrationTests/Tests/PrototypeSaveTest.cs +++ b/Content.IntegrationTests/Tests/PrototypeSaveTest.cs @@ -38,31 +38,15 @@ public async Task UninitializedSaveTest() var mapManager = server.ResolveDependency(); var entityMan = server.ResolveDependency(); var prototypeMan = server.ResolveDependency(); - var tileDefinitionManager = server.ResolveDependency(); var seriMan = server.ResolveDependency(); var compFact = server.ResolveDependency(); var prototypes = new List(); - MapGridComponent grid = default!; EntityUid uid; - MapId mapId = default; - //Build up test environment - await server.WaitPost(() => - { - // Create a one tile grid to stave off the grid 0 monsters - mapId = mapManager.CreateMap(); - - mapManager.AddUninitializedMap(mapId); - - grid = mapManager.CreateGrid(mapId); - - var tileDefinition = tileDefinitionManager["FloorSteel"]; // Wires n such disable ambiance while under the floor - var tile = new Tile(tileDefinition.TileId); - var coordinates = grid.ToCoordinates(); - - grid.SetTile(coordinates, tile); - }); + await pair.CreateTestMap(false, "FloorSteel"); // Wires n such disable ambiance while under the floor + var mapId = pair.TestMap.MapId; + var grid = pair.TestMap.Grid; await server.WaitRunTicks(5); @@ -94,7 +78,7 @@ await server.WaitPost(() => await server.WaitAssertion(() => { Assert.That(!mapManager.IsMapInitialized(mapId)); - var testLocation = grid.ToCoordinates(); + var testLocation = grid.Owner.ToCoordinates(); Assert.Multiple(() => { diff --git a/Content.IntegrationTests/Tests/Puller/PullerTest.cs b/Content.IntegrationTests/Tests/Puller/PullerTest.cs index ba91f54ff77..87d174f7272 100644 --- a/Content.IntegrationTests/Tests/Puller/PullerTest.cs +++ b/Content.IntegrationTests/Tests/Puller/PullerTest.cs @@ -1,6 +1,6 @@ using Content.Shared.Hands.Components; +using Content.Shared.Movement.Pulling.Components; using Content.Shared.Prototypes; -using Content.Shared.Pulling.Components; using Robust.Shared.GameObjects; using Robust.Shared.Prototypes; @@ -29,7 +29,7 @@ await server.WaitAssertion(() => { foreach (var proto in protoManager.EnumeratePrototypes()) { - if (!proto.TryGetComponent(out SharedPullerComponent? puller)) + if (!proto.TryGetComponent(out PullerComponent? puller)) continue; if (!puller.NeedsHands) diff --git a/Content.IntegrationTests/Tests/Shuttle/DockTest.cs b/Content.IntegrationTests/Tests/Shuttle/DockTest.cs index b6fc273570a..a1aa462a697 100644 --- a/Content.IntegrationTests/Tests/Shuttle/DockTest.cs +++ b/Content.IntegrationTests/Tests/Shuttle/DockTest.cs @@ -39,7 +39,7 @@ public async Task TestDockingConfig(Vector2 dock1Pos, Vector2 dock2Pos, Angle do await server.WaitAssertion(() => { - entManager.DeleteEntity(map.GridUid); + entManager.DeleteEntity(map.Grid); var grid1 = mapManager.CreateGridEntity(mapId); var grid2 = mapManager.CreateGridEntity(mapId); var grid1Ent = grid1.Owner; @@ -104,7 +104,7 @@ public async Task TestPlanetDock() // Spawn shuttle and affirm no valid docks. await server.WaitAssertion(() => { - entManager.DeleteEntity(map.GridUid); + entManager.DeleteEntity(map.Grid); Assert.That(entManager.System().TryLoad(otherMap.MapId, "/Maps/Shuttles/emergency.yml", out var rootUids)); shuttle = rootUids[0]; diff --git a/Content.IntegrationTests/Tests/Tiles/TileConstructionTests.cs b/Content.IntegrationTests/Tests/Tiles/TileConstructionTests.cs index 0a2af88887a..083e817d697 100644 --- a/Content.IntegrationTests/Tests/Tiles/TileConstructionTests.cs +++ b/Content.IntegrationTests/Tests/Tiles/TileConstructionTests.cs @@ -37,7 +37,7 @@ public async Task CutThenPlaceLatticeNewGrid() // Remove grid await SetTile(null); await SetTile(null, PlayerCoords); - Assert.That(MapData.MapGrid.Deleted); + Assert.That(MapData.Grid.Comp.Deleted); AssertGridCount(0); // Place Lattice @@ -70,7 +70,7 @@ public async Task FloorConstructDeconstruct() // Remove grid await SetTile(null); await SetTile(null, PlayerCoords); - Assert.That(MapData.MapGrid.Deleted); + Assert.That(MapData.Grid.Comp.Deleted); AssertGridCount(0); // Space -> Lattice diff --git a/Content.Packaging/ClientPackaging.cs b/Content.Packaging/ClientPackaging.cs index a989ebd968e..a66d4ec5b91 100644 --- a/Content.Packaging/ClientPackaging.cs +++ b/Content.Packaging/ClientPackaging.cs @@ -13,7 +13,7 @@ public static class ClientPackaging /// /// Be advised this can be called from server packaging during a HybridACZ build. /// - public static async Task PackageClient(bool skipBuild, IPackageLogger logger) + public static async Task PackageClient(bool skipBuild, string configuration, IPackageLogger logger) { logger.Info("Building client..."); @@ -26,7 +26,7 @@ await ProcessHelpers.RunCheck(new ProcessStartInfo { "build", Path.Combine("Content.Client", "Content.Client.csproj"), - "-c", "Release", + "-c", configuration, "--nologo", "/v:m", "/t:Rebuild", diff --git a/Content.Packaging/CommandLineArgs.cs b/Content.Packaging/CommandLineArgs.cs index 9f2b0755357..23f661921e0 100644 --- a/Content.Packaging/CommandLineArgs.cs +++ b/Content.Packaging/CommandLineArgs.cs @@ -31,6 +31,11 @@ public sealed class CommandLineArgs /// public bool HybridAcz { get; set; } + /// + /// Configuration used for when packaging the server. (Release, Debug, Tools) + /// + public string Configuration { get; set; } + // CommandLineArgs, 3rd of her name. public static bool TryParse(IReadOnlyList args, [NotNullWhen(true)] out CommandLineArgs? parsed) { @@ -39,6 +44,7 @@ public static bool TryParse(IReadOnlyList args, [NotNullWhen(true)] out var skipBuild = false; var wipeRelease = true; var hybridAcz = false; + var configuration = "Release"; List? platforms = null; using var enumerator = args.GetEnumerator(); @@ -89,6 +95,16 @@ public static bool TryParse(IReadOnlyList args, [NotNullWhen(true)] out platforms ??= new List(); platforms.Add(enumerator.Current); } + else if (arg == "--configuration") + { + if (!enumerator.MoveNext()) + { + Console.WriteLine("No configuration provided"); + return false; + } + + configuration = enumerator.Current; + } else if (arg == "--help") { PrintHelp(); @@ -106,7 +122,7 @@ public static bool TryParse(IReadOnlyList args, [NotNullWhen(true)] out return false; } - parsed = new CommandLineArgs(client.Value, skipBuild, wipeRelease, hybridAcz, platforms); + parsed = new CommandLineArgs(client.Value, skipBuild, wipeRelease, hybridAcz, platforms, configuration); return true; } @@ -120,6 +136,7 @@ private static void PrintHelp() --no-wipe-release Don't wipe the release folder before creating files. --hybrid-acz Use HybridACZ for server builds. --platform Platform for server builds. Default will output several x64 targets. + --configuration Configuration to use for building the server (Release, Debug, Tools). Default is Release. "); } @@ -128,12 +145,14 @@ private CommandLineArgs( bool skipBuild, bool wipeRelease, bool hybridAcz, - List? platforms) + List? platforms, + string configuration) { Client = client; SkipBuild = skipBuild; WipeRelease = wipeRelease; HybridAcz = hybridAcz; Platforms = platforms; + Configuration = configuration; } } diff --git a/Content.Packaging/Program.cs b/Content.Packaging/Program.cs index ba5924ec3e9..65c0e0131a4 100644 --- a/Content.Packaging/Program.cs +++ b/Content.Packaging/Program.cs @@ -17,11 +17,11 @@ if (parsed.Client) { - await ClientPackaging.PackageClient(parsed.SkipBuild, logger); + await ClientPackaging.PackageClient(parsed.SkipBuild, parsed.Configuration, logger); } else { - await ServerPackaging.PackageServer(parsed.SkipBuild, parsed.HybridAcz, logger, parsed.Platforms); + await ServerPackaging.PackageServer(parsed.SkipBuild, parsed.HybridAcz, logger, parsed.Configuration, parsed.Platforms); } void WipeBin() diff --git a/Content.Packaging/ServerPackaging.cs b/Content.Packaging/ServerPackaging.cs index ba489629f79..d9ca57c4d11 100644 --- a/Content.Packaging/ServerPackaging.cs +++ b/Content.Packaging/ServerPackaging.cs @@ -69,7 +69,7 @@ public static class ServerPackaging "zh-Hant" }; - public static async Task PackageServer(bool skipBuild, bool hybridAcz, IPackageLogger logger, List? platforms = null) + public static async Task PackageServer(bool skipBuild, bool hybridAcz, IPackageLogger logger, string configuration, List? platforms = null) { if (platforms == null) { @@ -82,7 +82,7 @@ public static async Task PackageServer(bool skipBuild, bool hybridAcz, IPackageL // Rather than hosting the client ZIP on the watchdog or on a separate server, // Hybrid ACZ uses the ACZ hosting functionality to host it as part of the status host, // which means that features such as automatic UPnP forwarding still work properly. - await ClientPackaging.PackageClient(skipBuild, logger); + await ClientPackaging.PackageClient(skipBuild, configuration, logger); } // Good variable naming right here. @@ -91,13 +91,13 @@ public static async Task PackageServer(bool skipBuild, bool hybridAcz, IPackageL if (!platforms.Contains(platform.Rid)) continue; - await BuildPlatform(platform, skipBuild, hybridAcz, logger); + await BuildPlatform(platform, skipBuild, hybridAcz, configuration, logger); } } - private static async Task BuildPlatform(PlatformReg platform, bool skipBuild, bool hybridAcz, IPackageLogger logger) + private static async Task BuildPlatform(PlatformReg platform, bool skipBuild, bool hybridAcz, string configuration, IPackageLogger logger) { - logger.Info($"Building project for {platform}..."); + logger.Info($"Building project for {platform.TargetOs}..."); if (!skipBuild) { @@ -108,7 +108,7 @@ await ProcessHelpers.RunCheck(new ProcessStartInfo { "build", Path.Combine("Content.Server", "Content.Server.csproj"), - "-c", "Release", + "-c", configuration, "--nologo", "/v:m", $"/p:TargetOs={platform.TargetOs}", @@ -118,7 +118,7 @@ await ProcessHelpers.RunCheck(new ProcessStartInfo } }); - await PublishClientServer(platform.Rid, platform.TargetOs); + await PublishClientServer(platform.Rid, platform.TargetOs, configuration); } logger.Info($"Packaging {platform.Rid} server..."); @@ -137,7 +137,7 @@ await ProcessHelpers.RunCheck(new ProcessStartInfo logger.Info($"Finished packaging server in {sw.Elapsed}"); } - private static async Task PublishClientServer(string runtime, string targetOs) + private static async Task PublishClientServer(string runtime, string targetOs, string configuration) { await ProcessHelpers.RunCheck(new ProcessStartInfo { @@ -147,7 +147,7 @@ await ProcessHelpers.RunCheck(new ProcessStartInfo "publish", "--runtime", runtime, "--no-self-contained", - "-c", "Release", + "-c", configuration, $"/p:TargetOs={targetOs}", "/p:FullRelease=True", "/m", diff --git a/Content.Server/Administration/Commands/AdminWhoCommand.cs b/Content.Server/Administration/Commands/AdminWhoCommand.cs index 9765e8385f0..cf2f8c453c8 100644 --- a/Content.Server/Administration/Commands/AdminWhoCommand.cs +++ b/Content.Server/Administration/Commands/AdminWhoCommand.cs @@ -19,6 +19,16 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) var adminMgr = IoCManager.Resolve(); var afk = IoCManager.Resolve(); + var seeStealth = true; + + // If null it (hopefully) means it is being called from the console. + if (shell.Player != null) + { + var playerData = adminMgr.GetAdminData(shell.Player); + + seeStealth = playerData != null && playerData.CanStealth(); + } + var sb = new StringBuilder(); var first = true; foreach (var admin in adminMgr.ActiveAdmins) @@ -30,10 +40,16 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) var adminData = adminMgr.GetAdminData(admin)!; DebugTools.AssertNotNull(adminData); + if (adminData.Stealth && !seeStealth) + continue; + sb.Append(admin.Name); if (adminData.Title is { } title) sb.Append($": [{title}]"); + if (adminData.Stealth) + sb.Append(" (S)"); + if (shell.Player is { } player && adminMgr.HasAdminFlag(player, AdminFlags.Admin)) { if (afk.IsAfk(admin)) diff --git a/Content.Server/Administration/Commands/PersistenceSaveCommand.cs b/Content.Server/Administration/Commands/PersistenceSaveCommand.cs index 2684e85d5f1..7ef1932c568 100644 --- a/Content.Server/Administration/Commands/PersistenceSaveCommand.cs +++ b/Content.Server/Administration/Commands/PersistenceSaveCommand.cs @@ -1,11 +1,6 @@ -using Content.Server.GameTicking; -using Content.Server.Ghost.Components; -using Content.Server.Players; using Content.Shared.Administration; using Content.Shared.CCVar; -using Content.Shared.Ghost; using Robust.Server.GameObjects; -using Robust.Server.Player; using Robust.Shared.Configuration; using Robust.Shared.Console; using Robust.Shared.Map; @@ -17,7 +12,6 @@ namespace Content.Server.Administration.Commands; public sealed class PersistenceSave : IConsoleCommand { [Dependency] private readonly IConfigurationManager _config = default!; - [Dependency] private readonly IEntityManager _entities = default!; [Dependency] private readonly IEntitySystemManager _system = default!; [Dependency] private readonly IMapManager _map = default!; diff --git a/Content.Server/Administration/Commands/PlayGlobalSoundCommand.cs b/Content.Server/Administration/Commands/PlayGlobalSoundCommand.cs index ac55ce83259..f1a5a57aa65 100644 --- a/Content.Server/Administration/Commands/PlayGlobalSoundCommand.cs +++ b/Content.Server/Administration/Commands/PlayGlobalSoundCommand.cs @@ -6,6 +6,7 @@ using Robust.Shared.Console; using Robust.Shared.ContentPack; using Robust.Shared.Player; +using Robust.Shared.Prototypes; namespace Content.Server.Administration.Commands; @@ -14,6 +15,7 @@ public sealed class PlayGlobalSoundCommand : IConsoleCommand { [Dependency] private readonly IEntityManager _entManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; + [Dependency] private readonly IPrototypeManager _protoManager = default!; [Dependency] private readonly IResourceManager _res = default!; public string Command => "playglobalsound"; @@ -95,7 +97,7 @@ public CompletionResult GetCompletion(IConsoleShell shell, string[] args) { var hint = Loc.GetString("play-global-sound-command-arg-path"); - var options = CompletionHelper.ContentFilePath(args[0], _res); + var options = CompletionHelper.AudioFilePath(args[0], _protoManager, _res); return CompletionResult.FromHintOptions(options, hint); } diff --git a/Content.Server/Administration/Commands/StealthminCommand.cs b/Content.Server/Administration/Commands/StealthminCommand.cs new file mode 100644 index 00000000000..aa0e77a794a --- /dev/null +++ b/Content.Server/Administration/Commands/StealthminCommand.cs @@ -0,0 +1,34 @@ +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 +{ + 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("cmd-stealthmin-no-console")); + return; + } + + var mgr = IoCManager.Resolve(); + var adminData = mgr.GetAdminData(player); + + DebugTools.AssertNotNull(adminData); + + if (!adminData!.Stealth) + mgr.Stealth(player); + else + mgr.UnStealth(player); + } +} diff --git a/Content.Server/Administration/Commands/VariantizeCommand.cs b/Content.Server/Administration/Commands/VariantizeCommand.cs index 7aabd76335e..3f9b7efd07e 100644 --- a/Content.Server/Administration/Commands/VariantizeCommand.cs +++ b/Content.Server/Administration/Commands/VariantizeCommand.cs @@ -3,7 +3,6 @@ using Robust.Shared.Console; using Robust.Shared.Map; using Robust.Shared.Map.Components; -using Robust.Shared.Random; namespace Content.Server.Administration.Commands; @@ -11,7 +10,6 @@ namespace Content.Server.Administration.Commands; public sealed class VariantizeCommand : IConsoleCommand { [Dependency] private readonly IEntityManager _entManager = default!; - [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly ITileDefinitionManager _tileDefManager = default!; public string Command => "variantize"; diff --git a/Content.Server/Administration/Managers/AdminManager.cs b/Content.Server/Administration/Managers/AdminManager.cs index 57d6e089bd4..8fb28b7ec4d 100644 --- a/Content.Server/Administration/Managers/AdminManager.cs +++ b/Content.Server/Administration/Managers/AdminManager.cs @@ -98,6 +98,40 @@ public void DeAdmin(ICommonSession session) UpdateAdminStatus(session); } + public void Stealth(ICommonSession session) + { + if (!_admins.TryGetValue(session, out var reg)) + throw new ArgumentException($"Player {session} is not an admin"); + + if (reg.Data.Stealth) + return; + + var playerData = session.ContentData()!; + playerData.Stealthed = true; + reg.Data.Stealth = true; + + _chat.DispatchServerMessage(session, Loc.GetString("admin-manager-stealthed-message")); + _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-de-admin-message", ("exAdminName", session.Name)), AdminFlags.Stealth); + _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-enable-stealth", ("stealthAdminName", session.Name)), flagWhitelist: AdminFlags.Stealth); + } + + public void UnStealth(ICommonSession session) + { + if (!_admins.TryGetValue(session, out var reg)) + throw new ArgumentException($"Player {session} is not an admin"); + + if (!reg.Data.Stealth) + return; + + var playerData = session.ContentData()!; + playerData.Stealthed = false; + reg.Data.Stealth = false; + + _chat.DispatchServerMessage(session, Loc.GetString("admin-manager-unstealthed-message")); + _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-re-admin-message", ("newAdminName", session.Name)), flagBlacklist: AdminFlags.Stealth); + _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-disable-stealth", ("exStealthAdminName", session.Name)), flagWhitelist: AdminFlags.Stealth); + } + public void ReAdmin(ICommonSession session) { if (!_admins.TryGetValue(session, out var reg)) @@ -116,7 +150,16 @@ public void ReAdmin(ICommonSession session) plyData.ExplicitlyDeadminned = false; reg.Data.Active = true; - _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-re-admin-message", ("newAdminName", session.Name))); + if (reg.Data.Stealth) + { + _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-re-admin-message", ("newAdminName", session.Name))); + } + else + { + _chat.DispatchServerMessage(session, Loc.GetString("admin-manager-stealthed-message")); + _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-re-admin-message", + ("newAdminName", session.Name)), flagWhitelist: AdminFlags.Stealth); + } SendPermsChangedEvent(session); UpdateAdminStatus(session); @@ -168,6 +211,9 @@ public async void ReloadAdmin(ICommonSession player) _chat.DispatchServerMessage(player, Loc.GetString("admin-manager-admin-permissions-updated-message")); } + + if (player.ContentData()!.Stealthed) + aData.Stealth = true; } SendPermsChangedEvent(player); @@ -290,9 +336,14 @@ private void PlayerStatusChanged(object? sender, SessionStatusEventArgs e) } else if (e.NewStatus == SessionStatus.Disconnected) { - if (_admins.Remove(e.Session) && _cfg.GetCVar(CCVars.AdminAnnounceLogout)) + if (_admins.Remove(e.Session, out var reg ) && _cfg.GetCVar(CCVars.AdminAnnounceLogout)) { - _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-admin-logout-message", ("name", e.Session.Name))); + if (reg.Data.Stealth) + _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-admin-logout-message", + ("name", e.Session.Name)), flagWhitelist: AdminFlags.Stealth); + else + _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-admin-logout-message", + ("name", e.Session.Name))); } } } @@ -315,13 +366,27 @@ private async void LoginAdminMaybe(ICommonSession session) _admins.Add(session, reg); + if (session.ContentData()!.Stealthed) + reg.Data.Stealth = true; + if (!session.ContentData()?.ExplicitlyDeadminned ?? false) { reg.Data.Active = true; if (_cfg.GetCVar(CCVars.AdminAnnounceLogin)) { - _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-admin-login-message", ("name", session.Name))); + if (reg.Data.Stealth) + { + + _chat.DispatchServerMessage(session, Loc.GetString("admin-manager-stealthed-message")); + _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-admin-login-message", + ("name", session.Name)), flagWhitelist: AdminFlags.Stealth); + } + else + { + _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-admin-login-message", + ("name", session.Name))); + } } SendPermsChangedEvent(session); diff --git a/Content.Server/Administration/Managers/IAdminManager.cs b/Content.Server/Administration/Managers/IAdminManager.cs index a52ec7b099c..95967b24aca 100644 --- a/Content.Server/Administration/Managers/IAdminManager.cs +++ b/Content.Server/Administration/Managers/IAdminManager.cs @@ -41,6 +41,16 @@ public interface IAdminManager : ISharedAdminManager /// void ReAdmin(ICommonSession session); + /// + /// Make admin hidden from adminwho. + /// + void Stealth(ICommonSession session); + + /// + /// Unhide admin from adminwho. + /// + void UnStealth(ICommonSession session); + /// /// Re-loads the permissions of an player in case their admin data changed DB-side. /// diff --git a/Content.Server/Administration/UI/AdminAnnounceEui.cs b/Content.Server/Administration/UI/AdminAnnounceEui.cs index b6a6ba99840..e6d17b5af40 100644 --- a/Content.Server/Administration/UI/AdminAnnounceEui.cs +++ b/Content.Server/Administration/UI/AdminAnnounceEui.cs @@ -5,6 +5,8 @@ using Content.Server.EUI; using Content.Shared.Administration; using Content.Shared.Eui; +using Content.Server.Announcements.Systems; +using Robust.Shared.Player; namespace Content.Server.Administration.UI { @@ -12,11 +14,14 @@ public sealed class AdminAnnounceEui : BaseEui { [Dependency] private readonly IAdminManager _adminManager = default!; [Dependency] private readonly IChatManager _chatManager = default!; + private readonly AnnouncerSystem _announcer; private readonly ChatSystem _chatSystem; public AdminAnnounceEui() { IoCManager.InjectDependencies(this); + + _announcer = IoCManager.Resolve().GetEntitySystem(); _chatSystem = IoCManager.Resolve().GetEntitySystem(); } @@ -50,7 +55,8 @@ public override void HandleMessage(EuiMessageBase msg) break; // TODO: Per-station announcement support case AdminAnnounceType.Station: - _chatSystem.DispatchGlobalAnnouncement(doAnnounce.Announcement, doAnnounce.Announcer, colorOverride: Color.Gold); + _announcer.SendAnnouncement(_announcer.GetAnnouncementId("Announce"), Filter.Broadcast(), + doAnnounce.Announcement, doAnnounce.Announcer, Color.Gold); break; } diff --git a/Content.Server/Alert/Click/StopBeingPulled.cs b/Content.Server/Alert/Click/StopBeingPulled.cs index 2cf076fbeed..b02da38ecfa 100644 --- a/Content.Server/Alert/Click/StopBeingPulled.cs +++ b/Content.Server/Alert/Click/StopBeingPulled.cs @@ -1,7 +1,7 @@ using Content.Shared.ActionBlocker; using Content.Shared.Alert; -using Content.Shared.Pulling.Components; -using Content.Shared.Pulling; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Systems; using JetBrains.Annotations; namespace Content.Server.Alert.Click @@ -20,9 +20,9 @@ public void AlertClicked(EntityUid player) if (!entityManager.System().CanInteract(player, null)) return; - if (entityManager.TryGetComponent(player, out SharedPullableComponent? playerPullable)) + if (entityManager.TryGetComponent(player, out PullableComponent? playerPullable)) { - entityManager.System().TryStopPull(playerPullable); + entityManager.System().TryStopPull(player, playerPullable, user: player); } } } diff --git a/Content.Server/Alert/Click/StopPulling.cs b/Content.Server/Alert/Click/StopPulling.cs index 00a41495985..76f9569429f 100644 --- a/Content.Server/Alert/Click/StopPulling.cs +++ b/Content.Server/Alert/Click/StopPulling.cs @@ -1,6 +1,6 @@ using Content.Shared.Alert; -using Content.Shared.Pulling; -using Content.Shared.Pulling.Components; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Systems; using JetBrains.Annotations; namespace Content.Server.Alert.Click @@ -15,12 +15,12 @@ public sealed partial class StopPulling : IAlertClick public void AlertClicked(EntityUid player) { var entManager = IoCManager.Resolve(); + var ps = entManager.System(); - var ps = entManager.System(); - var playerTarget = ps.GetPulled(player); - if (playerTarget != default && entManager.TryGetComponent(playerTarget, out SharedPullableComponent? playerPullable)) + if (entManager.TryGetComponent(player, out PullerComponent? puller) && + entManager.TryGetComponent(puller.Pulling, out PullableComponent? pullableComp)) { - ps.TryStopPull(playerPullable); + ps.TryStopPull(puller.Pulling.Value, pullableComp, user: player); } } } diff --git a/Content.Server/AlertLevel/AlertLevelSystem.cs b/Content.Server/AlertLevel/AlertLevelSystem.cs index 848170ba9dc..d856fab9da7 100644 --- a/Content.Server/AlertLevel/AlertLevelSystem.cs +++ b/Content.Server/AlertLevel/AlertLevelSystem.cs @@ -6,6 +6,7 @@ using Robust.Shared.Audio.Systems; using Robust.Shared.Configuration; using Robust.Shared.Prototypes; +using Content.Server.Announcements.Systems; namespace Content.Server.AlertLevel; @@ -16,6 +17,7 @@ public sealed class AlertLevelSystem : EntitySystem [Dependency] private readonly ChatSystem _chatSystem = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly StationSystem _stationSystem = default!; + [Dependency] private readonly AnnouncerSystem _announcer = default!; // Until stations are a prototype, this is how it's going to have to be. public const string DefaultAlertLevelSet = "stationAlerts"; @@ -122,18 +124,14 @@ public void SetLevel(EntityUid station, string level, bool playSound, bool annou || component.AlertLevels == null || !component.AlertLevels.Levels.TryGetValue(level, out var detail) || component.CurrentLevel == level) - { return; - } if (!force) { if (!detail.Selectable || component.CurrentDelay > 0 || component.IsLevelLocked) - { return; - } component.CurrentDelay = _cfg.GetCVar(CCVars.GameAlertLevelChangeDelay); component.ActiveDelay = true; @@ -142,64 +140,31 @@ public void SetLevel(EntityUid station, string level, bool playSound, bool annou component.CurrentLevel = level; component.IsLevelLocked = locked; - var stationName = dataComponent.EntityName; - var name = level.ToLower(); - if (Loc.TryGetString($"alert-level-{level}", out var locName)) - { name = locName.ToLower(); - } // Announcement text. Is passed into announcementFull. var announcement = detail.Announcement; if (Loc.TryGetString(detail.Announcement, out var locAnnouncement)) - { announcement = locAnnouncement; - } - // The full announcement to be spat out into chat. - var announcementFull = Loc.GetString("alert-level-announcement", ("name", name), ("announcement", announcement)); - - var playDefault = false; + var alert = _announcer.GetAnnouncementId($"Alert{level}"); if (playSound) - { - if (detail.Sound != null) - { - var filter = _stationSystem.GetInOwningStation(station); - _audio.PlayGlobal(detail.Sound, filter, true, detail.Sound.Params); - } - else - { - playDefault = true; - } - } - + _announcer.SendAnnouncementAudio(alert, _stationSystem.GetInOwningStation(station)); if (announce) - { - _chatSystem.DispatchStationAnnouncement(station, announcementFull, playDefaultSound: playDefault, - colorOverride: detail.Color, sender: stationName); - } + _announcer.SendAnnouncementMessage(alert, "alert-level-announcement", null, detail.Color, null, null, + ("name", name), ("announcement", announcement)); RaiseLocalEvent(new AlertLevelChangedEvent(station, level)); } } -public sealed class AlertLevelDelayFinishedEvent : EntityEventArgs -{} - -public sealed class AlertLevelPrototypeReloadedEvent : EntityEventArgs -{} - -public sealed class AlertLevelChangedEvent : EntityEventArgs +public sealed class AlertLevelDelayFinishedEvent : EntityEventArgs; +public sealed class AlertLevelPrototypeReloadedEvent : EntityEventArgs; +public sealed class AlertLevelChangedEvent(EntityUid station, string alertLevel) : EntityEventArgs { - public EntityUid Station { get; } - public string AlertLevel { get; } - - public AlertLevelChangedEvent(EntityUid station, string alertLevel) - { - Station = station; - AlertLevel = alertLevel; - } + public EntityUid Station { get; } = station; + public string AlertLevel { get; } = alertLevel; } diff --git a/Content.Server/Announcements/AnnounceCommand.cs b/Content.Server/Announcements/AnnounceCommand.cs index cedde3fc140..c7158eac009 100644 --- a/Content.Server/Announcements/AnnounceCommand.cs +++ b/Content.Server/Announcements/AnnounceCommand.cs @@ -1,8 +1,11 @@ +using System.Linq; using Content.Server.Administration; -using Content.Server.Chat; -using Content.Server.Chat.Systems; +using Content.Server.Announcements.Systems; using Content.Shared.Administration; +using Content.Shared.Announcements.Prototypes; using Robust.Shared.Console; +using Robust.Shared.Player; +using Robust.Shared.Prototypes; namespace Content.Server.Announcements { @@ -11,27 +14,77 @@ public sealed class AnnounceCommand : IConsoleCommand { public string Command => "announce"; public string Description => "Send an in-game announcement."; - public string Help => $"{Command} or {Command} to send announcement as CentCom."; + public string Help => $"{Command} "; public void Execute(IConsoleShell shell, string argStr, string[] args) { - var chat = IoCManager.Resolve().GetEntitySystem(); + var announcer = IoCManager.Resolve().GetEntitySystem(); + var proto = IoCManager.Resolve(); - if (args.Length == 0) + switch (args.Length) { - shell.WriteError("Not enough arguments! Need at least 1."); - return; + case 0: + shell.WriteError("Not enough arguments! Need at least 1."); + return; + case 1: + announcer.SendAnnouncement(announcer.GetAnnouncementId("CommandReport"), Filter.Broadcast(), + args[0], "Central Command", Color.Gold); + break; + case 2: + announcer.SendAnnouncement(announcer.GetAnnouncementId("CommandReport"), Filter.Broadcast(), + args[1], args[0], Color.Gold); + break; + case 3: + announcer.SendAnnouncement(announcer.GetAnnouncementId(args[2]), Filter.Broadcast(), args[1], + args[0], Color.Gold); + break; + case 4: + if (!proto.TryIndex(args[3], out AnnouncerPrototype? prototype)) + { + shell.WriteError($"No announcer prototype with ID {args[3]} found!"); + return; + } + announcer.SendAnnouncement(args[2], Filter.Broadcast(), args[1], args[0], Color.Gold, null, + prototype); + break; } - if (args.Length == 1) - { - chat.DispatchGlobalAnnouncement(args[0], colorOverride: Color.Gold); - } - else + shell.WriteLine("Sent!"); + } + + public CompletionResult GetCompletion(IConsoleShell shell, string[] args) + { + switch (args.Length) { - var message = string.Join(' ', new ArraySegment(args, 1, args.Length-1)); - chat.DispatchGlobalAnnouncement(message, args[0], colorOverride: Color.Gold); + case 3: + { + var list = new List(); + + foreach (var prototype in IoCManager.Resolve() + .EnumeratePrototypes() + .SelectMany(p => p.Announcements.Select(a => a.ID))) + { + if (!list.Contains(prototype)) + list.Add(prototype); + } + + return CompletionResult.FromHintOptions(list, Loc.GetString("admin-announce-hint-sound")); + } + case 4: + { + var list = new List(); + + foreach (var prototype in IoCManager.Resolve() + .EnumeratePrototypes()) + { + if (!list.Contains(prototype.ID)) + list.Add(prototype.ID); + } + + return CompletionResult.FromHintOptions(list, Loc.GetString("admin-announce-hint-voice")); + } + default: + return CompletionResult.Empty; } - shell.WriteLine("Sent!"); } } } diff --git a/Content.Server/Announcements/Systems/AnnouncerSystem.Announce.cs b/Content.Server/Announcements/Systems/AnnouncerSystem.Announce.cs new file mode 100644 index 00000000000..3342bc9aef8 --- /dev/null +++ b/Content.Server/Announcements/Systems/AnnouncerSystem.Announce.cs @@ -0,0 +1,96 @@ +using System.Linq; +using Content.Shared.Announcements.Events; +using Content.Shared.Announcements.Prototypes; +using Robust.Shared.Audio; +using Robust.Shared.Player; + +namespace Content.Server.Announcements.Systems; + +public sealed partial class AnnouncerSystem +{ + /// + /// Gets an announcement message from the announcer + /// + /// ID of the announcement from the announcer to get information from + private string? GetAnnouncementMessage(string announcementId) + { + // Get the announcement data from the announcer + // Will be the fallback if the data for the announcementId is not found + var announcementType = Announcer.Announcements.FirstOrDefault(a => a.ID == announcementId) ?? + Announcer.Announcements.First(a => a.ID == "fallback"); + + // Return the announcementType.MessageOverride if it exists, otherwise return null + return announcementType.MessageOverride != null ? Loc.GetString(announcementType.MessageOverride) : null; + } + + + /// + /// Sends an announcement audio + /// + /// ID of the announcement to get information from + /// Who hears the announcement audio + /// Uses this announcer instead of the current global one + public void SendAnnouncementAudio(string announcementId, Filter filter, AnnouncerPrototype? announcerOverride = null) + { + var ev = new AnnouncementSendEvent( + announcerOverride?.ID ?? Announcer.ID, + announcementId, + filter.Recipients.ToList().ConvertAll(p => p.UserId), // I hate this but IEnumerable isn't serializable, and then ICommonSession wasn't, so you get the User ID + GetAudioParams(announcementId, Announcer) ?? AudioParams.Default + ); + + RaiseNetworkEvent(ev); + } + + /// + /// Sends an announcement message + /// + /// ID of the announcement to get information from + /// Text to send in the announcement + /// Who to show as the announcement announcer, defaults to the current announcer's name + /// What color the announcement should be + /// Station ID to send the announcement to + /// Uses this announcer instead of the current global one + /// Locale arguments to pass to the announcement message + public void SendAnnouncementMessage(string announcementId, string locale, string? sender = null, + Color? colorOverride = null, EntityUid? station = null, AnnouncerPrototype? announcerOverride = null, + params (string, object)[] localeArgs) + { + sender ??= Loc.GetString($"announcer-{announcerOverride?.ID ?? Announcer.ID}-name"); + + // If the announcement has a message override, use that instead of the message parameter + if (GetAnnouncementMessage(announcementId, announcerOverride?.ID ?? Announcer.ID) is { } announcementMessage) + locale = Loc.GetString(announcementMessage, localeArgs); + else + locale = Loc.GetString(locale, localeArgs); + + // Don't send nothing + if (string.IsNullOrEmpty(locale)) + return; + + // If there is a station, send the announcement to the station, otherwise send it to everyone + if (station == null) + _chat.DispatchGlobalAnnouncement(locale, sender, false, colorOverride: colorOverride); + else + _chat.DispatchStationAnnouncement(station.Value, locale, sender, false, colorOverride: colorOverride); + } + + /// + /// Sends an announcement with a message and audio + /// + /// ID of the announcement to get information from + /// Who hears the announcement audio + /// Text to send in the announcement + /// Who to show as the announcement announcer, defaults to the current announcer's name + /// What color the announcement should be + /// Station ID to send the announcement to + /// Uses this announcer instead of the current global one + /// Locale arguments to pass to the announcement message + public void SendAnnouncement(string announcementId, Filter filter, string locale, string? sender = null, + Color? colorOverride = null, EntityUid? station = null, AnnouncerPrototype? announcerOverride = null, + params (string, object)[] localeArgs) + { + SendAnnouncementAudio(announcementId, filter, announcerOverride); + SendAnnouncementMessage(announcementId, locale, sender, colorOverride, station, announcerOverride, localeArgs); + } +} diff --git a/Content.Server/Announcements/Systems/AnnouncerSystem.Announcer.cs b/Content.Server/Announcements/Systems/AnnouncerSystem.Announcer.cs new file mode 100644 index 00000000000..30969361110 --- /dev/null +++ b/Content.Server/Announcements/Systems/AnnouncerSystem.Announcer.cs @@ -0,0 +1,68 @@ +using System.Linq; +using Content.Shared.GameTicking; +using Content.Shared.Announcements.Prototypes; +using Content.Shared.CCVar; +using Content.Shared.Random; +using Content.Shared.Random.Helpers; +using Robust.Shared.Utility; + +namespace Content.Server.Announcements.Systems; + +public sealed partial class AnnouncerSystem +{ + private void OnRoundRestarting(RoundRestartCleanupEvent ev) + { + NewAnnouncer(); + } + + + /// + /// Sets the announcer to a random one or the CVar + /// + private void NewAnnouncer() + { + var announcer = _config.GetCVar(CCVars.Announcer); + if (string.IsNullOrEmpty(announcer) || !_proto.TryIndex(announcer, out _)) + SetAnnouncer(PickAnnouncer()); + else + SetAnnouncer(announcer); + } + + /// + /// Picks a random announcer prototype following blacklists + /// + public AnnouncerPrototype PickAnnouncer() + { + var list = _proto.Index(_config.GetCVar(CCVars.AnnouncerList)); + var blacklist = _config.GetCVar(CCVars.AnnouncerBlacklist).Split(',').Select(a => a.Trim()).ToList(); + var modWeights = list.Weights.Where(a => !blacklist.Contains(a.Key)); + + list = new WeightedRandomPrototype(); + foreach (var (key, value) in modWeights) + list.Weights.Add(key, value); + + return _proto.Index(list.Pick()); + } + + + /// + /// Sets the announcer + /// + /// ID of the announcer to choose + public void SetAnnouncer(string announcerId) + { + if (!_proto.TryIndex(announcerId, out var announcer)) + DebugTools.Assert($"Set announcer {announcerId} does not exist, attempting to use previously set one."); + else + Announcer = announcer; + } + + /// + /// Sets the announcer + /// + /// The announcer prototype to set the current announcer to + public void SetAnnouncer(AnnouncerPrototype announcer) + { + Announcer = announcer; + } +} diff --git a/Content.Server/Announcements/Systems/AnnouncerSystem.cs b/Content.Server/Announcements/Systems/AnnouncerSystem.cs new file mode 100644 index 00000000000..1770a2ce937 --- /dev/null +++ b/Content.Server/Announcements/Systems/AnnouncerSystem.cs @@ -0,0 +1,33 @@ +using Content.Server.Chat.Systems; +using Content.Shared.GameTicking; +using Content.Shared.Announcements.Prototypes; +using Content.Shared.Announcements.Systems; +using Content.Shared.CCVar; +using Robust.Shared.Configuration; +using Robust.Shared.Prototypes; + +namespace Content.Server.Announcements.Systems; + +public sealed partial class AnnouncerSystem : SharedAnnouncerSystem +{ + [Dependency] private readonly IConfigurationManager _config = default!; + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly ChatSystem _chat = default!; + + /// + /// The currently selected announcer + /// + [Access(typeof(AnnouncerSystem))] + public AnnouncerPrototype Announcer { get; set; } = default!; + + + public override void Initialize() + { + base.Initialize(); + NewAnnouncer(); + + _config.OnValueChanged(CCVars.Announcer, _ => NewAnnouncer()); + + SubscribeLocalEvent(OnRoundRestarting); + } +} diff --git a/Content.Server/Anomaly/AnomalySystem.Generator.cs b/Content.Server/Anomaly/AnomalySystem.Generator.cs index 2053a7bbbe6..e03c566593e 100644 --- a/Content.Server/Anomaly/AnomalySystem.Generator.cs +++ b/Content.Server/Anomaly/AnomalySystem.Generator.cs @@ -24,7 +24,7 @@ namespace Content.Server.Anomaly; /// public sealed partial class AnomalySystem { - [Dependency] private readonly MapSystem _mapSystem = default!; + [Dependency] private readonly SharedMapSystem _mapSystem = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; private void InitializeGenerator() diff --git a/Content.Server/Anomaly/Effects/BluespaceAnomalySystem.cs b/Content.Server/Anomaly/Effects/BluespaceAnomalySystem.cs index 87c0ba4a4ee..dd2da82c9d6 100644 --- a/Content.Server/Anomaly/Effects/BluespaceAnomalySystem.cs +++ b/Content.Server/Anomaly/Effects/BluespaceAnomalySystem.cs @@ -8,6 +8,7 @@ using Content.Shared.Teleportation.Components; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; +using Robust.Shared.Collections; using Robust.Shared.Random; namespace Content.Server.Anomaly.Effects; @@ -35,20 +36,19 @@ private void OnPulse(EntityUid uid, BluespaceAnomalyComponent component, ref Ano var range = component.MaxShuffleRadius * args.Severity; var mobs = new HashSet>(); _lookup.GetEntitiesInRange(xform.Coordinates, range, mobs); - var allEnts = new List(mobs.Select(m => m.Owner)) { uid }; - var coords = new List(); + var allEnts = new ValueList(mobs.Select(m => m.Owner)) { uid }; + var coords = new ValueList(); foreach (var ent in allEnts) { - if (xformQuery.TryGetComponent(ent, out var xf)) - coords.Add(xf.MapPosition.Position); + if (xformQuery.TryGetComponent(ent, out var allXform)) + coords.Add(_xform.GetWorldPosition(allXform)); } _random.Shuffle(coords); for (var i = 0; i < allEnts.Count; i++) { - _adminLogger.Add(LogType.Teleport, $"{ToPrettyString(allEnts[i])} has been shuffled to {coords[i]} by the {ToPrettyString(uid)} at {xform.Coordinates}"); - _xform.SetWorldPosition(allEnts[i], coords[i], xformQuery); + _xform.SetWorldPosition(allEnts[i], coords[i]); } } diff --git a/Content.Server/Anomaly/Effects/EntityAnomalySystem.cs b/Content.Server/Anomaly/Effects/EntityAnomalySystem.cs index 7c397d68887..90a655fbba7 100644 --- a/Content.Server/Anomaly/Effects/EntityAnomalySystem.cs +++ b/Content.Server/Anomaly/Effects/EntityAnomalySystem.cs @@ -2,7 +2,6 @@ using Content.Shared.Anomaly.Components; using Content.Shared.Anomaly.Effects; using Content.Shared.Anomaly.Effects.Components; -using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Random; @@ -12,7 +11,6 @@ namespace Content.Server.Anomaly.Effects; public sealed class EntityAnomalySystem : SharedEntityAnomalySystem { [Dependency] private readonly SharedAnomalySystem _anomaly = default!; - [Dependency] private readonly IMapManager _map = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly SharedMapSystem _mapSystem = default!; diff --git a/Content.Server/Anomaly/Effects/GasProducerAnomalySystem.cs b/Content.Server/Anomaly/Effects/GasProducerAnomalySystem.cs index a5e42be5400..2408ad0b3dd 100644 --- a/Content.Server/Anomaly/Effects/GasProducerAnomalySystem.cs +++ b/Content.Server/Anomaly/Effects/GasProducerAnomalySystem.cs @@ -2,11 +2,10 @@ using Content.Server.Anomaly.Components; using Content.Shared.Anomaly.Components; using Content.Shared.Atmos; -using Robust.Server.GameObjects; -using Robust.Shared.Map; using Robust.Shared.Random; using System.Linq; using System.Numerics; +using Robust.Shared.Map.Components; namespace Content.Server.Anomaly.Effects; @@ -16,8 +15,6 @@ namespace Content.Server.Anomaly.Effects; public sealed class GasProducerAnomalySystem : EntitySystem { [Dependency] private readonly AtmosphereSystem _atmosphere = default!; - [Dependency] private readonly TransformSystem _xform = default!; - [Dependency] private readonly IMapManager _map = default!; [Dependency] private readonly IRobustRandom _random = default!; public override void Initialize() @@ -55,7 +52,7 @@ private void ReleaseGas(EntityUid uid, Gas gas, float mols, float radius, int co { var xform = Transform(uid); - if (!_map.TryGetGrid(xform.GridUid, out var grid)) + if (!TryComp(xform.GridUid, out var grid)) return; var localpos = xform.Coordinates.Position; diff --git a/Content.Server/Atmos/Commands/DeleteGasCommand.cs b/Content.Server/Atmos/Commands/DeleteGasCommand.cs index 9e7594c024b..f4279db926a 100644 --- a/Content.Server/Atmos/Commands/DeleteGasCommand.cs +++ b/Content.Server/Atmos/Commands/DeleteGasCommand.cs @@ -3,7 +3,7 @@ using Content.Shared.Administration; using Content.Shared.Atmos; using Robust.Shared.Console; -using Robust.Shared.Map; +using Robust.Shared.Map.Components; namespace Content.Server.Atmos.Commands { @@ -11,7 +11,6 @@ namespace Content.Server.Atmos.Commands public sealed class DeleteGasCommand : IConsoleCommand { [Dependency] private readonly IEntityManager _entManager = default!; - [Dependency] private readonly IMapManager _mapManager = default!; public string Command => "deletegas"; public string Description => "Removes all gases from a grid, or just of one type if specified."; @@ -119,7 +118,7 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) return; } - if (!_mapManager.TryGetGrid(gridId, out _)) + if (!_entManager.TryGetComponent(gridId, out _)) { shell.WriteLine($"No grid exists with id {gridId}"); return; diff --git a/Content.Server/Atmos/EntitySystems/AirFilterSystem.cs b/Content.Server/Atmos/EntitySystems/AirFilterSystem.cs index 416045fc5ed..d947e60b6da 100644 --- a/Content.Server/Atmos/EntitySystems/AirFilterSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AirFilterSystem.cs @@ -1,8 +1,6 @@ -using Content.Server.Atmos; using Content.Server.Atmos.Components; using Content.Server.Atmos.Piping.Components; using Content.Shared.Atmos; -using Robust.Shared.GameObjects; using Robust.Shared.Map; using System.Diagnostics.CodeAnalysis; @@ -15,7 +13,6 @@ public sealed class AirFilterSystem : EntitySystem { [Dependency] private readonly AtmosphereSystem _atmosphere = default!; [Dependency] private readonly IMapManager _map = default!; - [Dependency] private readonly SharedTransformSystem _transform = default!; public override void Initialize() { diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs index 3aaa5429fb0..4d50700738b 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs @@ -12,9 +12,14 @@ public sealed partial class AtmosphereSystem public float SpaceWindPressureForceDivisorPush { get; private set; } public float SpaceWindMaxVelocity { get; private set; } public float SpaceWindMaxPushForce { get; private set; } + public float SpaceWindMinimumCalculatedMass { get; private set; } + public float SpaceWindMaximumCalculatedInverseMass { get; private set; } + public bool MonstermosUseExpensiveAirflow { get; private set; } public bool MonstermosEqualization { get; private set; } public bool MonstermosDepressurization { get; private set; } public bool MonstermosRipTiles { get; private set; } + public float MonstermosRipTilesMinimumPressure { get; private set; } + public float MonstermosRipTilesPressureOffset { get; private set; } public bool GridImpulse { get; private set; } public float SpacingEscapeRatio { get; private set; } public float SpacingMinGas { get; private set; } @@ -26,6 +31,7 @@ public sealed partial class AtmosphereSystem public float AtmosTickRate { get; private set; } public float Speedup { get; private set; } public float HeatScale { get; private set; } + public float HumanoidThrowMultiplier { get; private set; } /// /// Time between each atmos sub-update. If you are writing an atmos device, use AtmosDeviceUpdateEvent.dt @@ -41,9 +47,14 @@ private void InitializeCVars() Subs.CVar(_cfg, CCVars.SpaceWindPressureForceDivisorPush, value => SpaceWindPressureForceDivisorPush = value, true); Subs.CVar(_cfg, CCVars.SpaceWindMaxVelocity, value => SpaceWindMaxVelocity = value, true); Subs.CVar(_cfg, CCVars.SpaceWindMaxPushForce, value => SpaceWindMaxPushForce = value, true); + Subs.CVar(_cfg, CCVars.SpaceWindMinimumCalculatedMass, value => SpaceWindMinimumCalculatedMass = value, true); + Subs.CVar(_cfg, CCVars.SpaceWindMaximumCalculatedInverseMass, value => SpaceWindMaximumCalculatedInverseMass = value, true); + Subs.CVar(_cfg, CCVars.MonstermosUseExpensiveAirflow, value => MonstermosUseExpensiveAirflow = value, true); Subs.CVar(_cfg, CCVars.MonstermosEqualization, value => MonstermosEqualization = value, true); Subs.CVar(_cfg, CCVars.MonstermosDepressurization, value => MonstermosDepressurization = value, true); Subs.CVar(_cfg, CCVars.MonstermosRipTiles, value => MonstermosRipTiles = value, true); + Subs.CVar(_cfg, CCVars.MonstermosRipTilesMinimumPressure, value => MonstermosRipTilesMinimumPressure = value, true); + Subs.CVar(_cfg, CCVars.MonstermosRipTilesPressureOffset, value => MonstermosRipTilesPressureOffset = value, true); Subs.CVar(_cfg, CCVars.AtmosGridImpulse, value => GridImpulse = value, true); Subs.CVar(_cfg, CCVars.AtmosSpacingEscapeRatio, value => SpacingEscapeRatio = value, true); Subs.CVar(_cfg, CCVars.AtmosSpacingMinGas, value => SpacingMinGas = value, true); @@ -55,6 +66,7 @@ private void InitializeCVars() Subs.CVar(_cfg, CCVars.AtmosHeatScale, value => { HeatScale = value; InitializeGases(); }, true); Subs.CVar(_cfg, CCVars.ExcitedGroups, value => ExcitedGroups = value, true); Subs.CVar(_cfg, CCVars.ExcitedGroupsSpaceIsAllConsuming, value => ExcitedGroupsSpaceIsAllConsuming = value, true); + Subs.CVar(_cfg, CCVars.AtmosHumanoidThrowMultiplier, value => HumanoidThrowMultiplier = value, true); } } } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs index cb50ff114e0..461435f0624 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs @@ -1,5 +1,6 @@ using Content.Server.Atmos.Components; using Content.Shared.Atmos; +using Content.Shared.Humanoid; using Content.Shared.Mobs.Components; using Content.Shared.Physics; using Robust.Shared.Audio; @@ -49,8 +50,7 @@ private void UpdateHighPressure(float frameTime) comp.Accumulator = 0f; toRemove.Add(ent); - if (HasComp(uid) && - TryComp(uid, out var body)) + if (TryComp(uid, out var body)) { _physics.SetBodyStatus(uid, body, BodyStatus.OnGround); } @@ -70,27 +70,10 @@ private void UpdateHighPressure(float frameTime) } } - private void AddMobMovedByPressure(EntityUid uid, MovedByPressureComponent component, PhysicsComponent body) - { - if (!TryComp(uid, out var fixtures)) - return; - - _physics.SetBodyStatus(uid, body, BodyStatus.InAir); - - foreach (var (id, fixture) in fixtures.Fixtures) - { - _physics.RemoveCollisionMask(uid, id, fixture, (int) CollisionGroup.TableLayer, manager: fixtures); - } - - // TODO: Make them dynamic type? Ehh but they still want movement so uhh make it non-predicted like weightless? - // idk it's hard. - - component.Accumulator = 0f; - _activePressures.Add((uid, component)); - } - private void HighPressureMovements(Entity gridAtmosphere, TileAtmosphere tile, EntityQuery bodies, EntityQuery xforms, EntityQuery pressureQuery, EntityQuery metas) { + if (tile.PressureDifference < SpaceWindMinimumCalculatedMass * SpaceWindMinimumCalculatedMass) + return; // TODO ATMOS finish this // Don't play the space wind sound on tiles that are on fire... @@ -120,7 +103,8 @@ private void HighPressureMovements(Entity gridAtmospher var gridWorldRotation = xforms.GetComponent(gridAtmosphere).WorldRotation; // If we're using monstermos, smooth out the yeet direction to follow the flow - if (MonstermosEqualization) + //TODO This is bad, don't run this. It just makes the throws worse by somehow rounding them to orthogonal + if (!MonstermosEqualization) { // We step through tiles according to the pressure direction on the current tile. // The goal is to get a general direction of the airflow in the area. @@ -160,7 +144,7 @@ private void HighPressureMovements(Entity gridAtmospher (entity, pressureMovements), gridAtmosphere.Comp.UpdateCounter, tile.PressureDifference, - tile.PressureDirection, 0, + tile.PressureDirection, tile.PressureSpecificTarget != null ? _mapSystem.ToCenterCoordinates(tile.GridIndex, tile.PressureSpecificTarget.GridIndices) : EntityCoordinates.Invalid, gridWorldRotation, xforms.GetComponent(entity), @@ -181,12 +165,29 @@ private void ConsiderPressureDifference(GridAtmosphereComponent gridAtmosphere, tile.PressureDirection = differenceDirection; } + //INFO The EE version of this function drops pressureResistanceProbDelta, since it's not needed. If you are for whatever reason calling this function + //INFO And if it isn't working, you've probably still got the pressureResistanceProbDelta line included. + /// + /// EXPLANATION: + /// pressureDifference = Force of Air Flow on a given tile + /// physics.Mass = Mass of the object potentially being thrown + /// physics.InvMass = 1 divided by said Mass. More CPU efficient way to do division. + /// + /// Objects can only be thrown if the force of air flow is greater than the SQUARE of their mass or {SpaceWindMinimumCalculatedMass}, whichever is heavier + /// This means that the heavier an object is, the exponentially more force is required to move it + /// The force of a throw is equal to the force of air pressure, divided by an object's mass. So not only are heavier objects + /// less likely to be thrown, they are also harder to throw, + /// while lighter objects are yeeted easily, and from great distance. + /// + /// For a human sized entity with a standard weight of 80kg and a spacing between a hard vacuum and a room pressurized at 101kpa, + /// The human shall only be moved if he is either very close to the hole, or is standing in a region of high airflow + /// + public void ExperiencePressureDifference( Entity ent, int cycle, float pressureDifference, AtmosDirection direction, - float pressureResistanceProbDelta, EntityCoordinates throwTarget, Angle gridWorldRotation, TransformComponent? xform = null, @@ -199,50 +200,28 @@ public void ExperiencePressureDifference( if (!Resolve(uid, ref xform)) return; - // TODO ATMOS stuns? - - var maxForce = MathF.Sqrt(pressureDifference) * 2.25f; - var moveProb = 100f; - if (component.PressureResistance > 0) - moveProb = MathF.Abs((pressureDifference / component.PressureResistance * MovedByPressureComponent.ProbabilityBasePercent) - - MovedByPressureComponent.ProbabilityOffset); - - // Can we yeet the thing (due to probability, strength, etc.) - if (moveProb > MovedByPressureComponent.ProbabilityOffset && _robustRandom.Prob(MathF.Min(moveProb / 100f, 1f)) - && !float.IsPositiveInfinity(component.MoveResist) - && (physics.BodyType != BodyType.Static - && (maxForce >= (component.MoveResist * MovedByPressureComponent.MoveForcePushRatio))) - || (physics.BodyType == BodyType.Static && (maxForce >= (component.MoveResist * MovedByPressureComponent.MoveForceForcePushRatio)))) + if (physics.BodyType != BodyType.Static + && !float.IsPositiveInfinity(component.MoveResist)) { - if (HasComp(uid)) + var moveForce = pressureDifference * MathF.Max(physics.InvMass, SpaceWindMaximumCalculatedInverseMass); + if (HasComp(ent)) + moveForce *= HumanoidThrowMultiplier; + if (moveForce > physics.Mass) { - AddMobMovedByPressure(uid, component, physics); - } - - if (maxForce > MovedByPressureComponent.ThrowForce) - { - var moveForce = maxForce; - moveForce /= (throwTarget != EntityCoordinates.Invalid) ? SpaceWindPressureForceDivisorThrow : SpaceWindPressureForceDivisorPush; - moveForce *= MathHelper.Clamp(moveProb, 0, 100); - - // Apply a sanity clamp to prevent being thrown through objects. - var maxSafeForceForObject = SpaceWindMaxVelocity * physics.Mass; - moveForce = MathF.Min(moveForce, maxSafeForceForObject); - // Grid-rotation adjusted direction var dirVec = (direction.ToAngle() + gridWorldRotation).ToWorldVec(); + moveForce *= MathF.Max(physics.InvMass, SpaceWindMaximumCalculatedInverseMass); - // TODO: Technically these directions won't be correct but uhh I'm just here for optimisations buddy not to fix my old bugs. + //TODO Consider replacing throw target with proper trigonometry angles. if (throwTarget != EntityCoordinates.Invalid) { - var pos = ((throwTarget.ToMap(EntityManager, _transformSystem).Position - xform.WorldPosition).Normalized() + dirVec).Normalized(); - _physics.ApplyLinearImpulse(uid, pos * moveForce, body: physics); + var pos = throwTarget.ToMap(EntityManager, _transformSystem).Position - xform.WorldPosition + dirVec; + _throwing.TryThrow(uid, pos.Normalized() * MathF.Min(moveForce, SpaceWindMaxVelocity), moveForce); } else { - moveForce = MathF.Min(moveForce, SpaceWindMaxPushForce); - _physics.ApplyLinearImpulse(uid, dirVec * moveForce, body: physics); + _throwing.TryThrow(uid, dirVec.Normalized() * MathF.Min(moveForce, SpaceWindMaxVelocity), moveForce); } component.LastHighPressureMovementAirCycle = cycle; diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs index dcbc1e86ee2..1ba9a48aa0c 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs @@ -5,11 +5,13 @@ using Content.Shared.Atmos; using Content.Shared.Atmos.Components; using Content.Shared.Database; +using Content.Shared.Maps; +using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; +using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Utility; - namespace Content.Server.Atmos.EntitySystems { public sealed partial class AtmosphereSystem @@ -137,7 +139,7 @@ private void EqualizePressureInZone( var logN = MathF.Log2(tileCount); // Optimization - try to spread gases using an O(n log n) algorithm that has a chance of not working first to avoid O(n^2) - if (giverTilesLength > logN && takerTilesLength > logN) + if (!MonstermosUseExpensiveAirflow && giverTilesLength > logN && takerTilesLength > logN) { // Even if it fails, it will speed up the next part. Array.Sort(_equalizeTiles, 0, tileCount, _monstermosComparer); @@ -550,7 +552,8 @@ private void ExplosivelyDepressurize( } InvalidateVisuals(otherTile.GridIndex, otherTile.GridIndices, visuals); - HandleDecompressionFloorRip(mapGrid, otherTile, otherTile.MonstermosInfo.CurrentTransferAmount); + if (MonstermosRipTiles && otherTile.PressureDifference > MonstermosRipTilesMinimumPressure) + HandleDecompressionFloorRip(mapGrid, otherTile, otherTile.PressureDifference); } if (GridImpulse && tileCount > 0) @@ -676,14 +679,14 @@ private void AdjustEqMovement(TileAtmosphere tile, AtmosDirection direction, flo adj.MonstermosInfo[direction.GetOpposite()] -= amount; } - private void HandleDecompressionFloorRip(MapGridComponent mapGrid, TileAtmosphere tile, float sum) + private void HandleDecompressionFloorRip(MapGridComponent mapGrid, TileAtmosphere tile, float delta) { - if (!MonstermosRipTiles) + if (!mapGrid.TryGetTileRef(tile.GridIndices, out var tileRef)) return; + var tileref = tileRef.Tile; - var chance = MathHelper.Clamp(0.01f + (sum / SpacingMaxWind) * 0.3f, 0.003f, 0.3f); - - if (sum > 20 && _robustRandom.Prob(chance)) + var tileDef = (ContentTileDefinition) _tileDefinitionManager[tileref.TypeId]; + if (!tileDef.Reinforced && tileDef.TileRipResistance < delta * MonstermosRipTilesPressureOffset) PryTile(mapGrid, tile.GridIndices); } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs index d2f40e77169..39425157ad4 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs @@ -6,6 +6,7 @@ using Content.Shared.Atmos.EntitySystems; using Content.Shared.Doors.Components; using Content.Shared.Maps; +using Content.Shared.Throwing; using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Shared.Audio.Systems; @@ -37,6 +38,7 @@ public sealed partial class AtmosphereSystem : SharedAtmosphereSystem [Dependency] private readonly TileSystem _tile = default!; [Dependency] private readonly MapSystem _map = default!; [Dependency] public readonly PuddleSystem Puddle = default!; + [Dependency] private readonly ThrowingSystem _throwing = default!; private const float ExposedUpdateDelay = 1f; private float _exposedTimer = 0f; diff --git a/Content.Server/Atmos/EntitySystems/GasTankSystem.cs b/Content.Server/Atmos/EntitySystems/GasTankSystem.cs index dfe84473402..aed00432e1f 100644 --- a/Content.Server/Atmos/EntitySystems/GasTankSystem.cs +++ b/Content.Server/Atmos/EntitySystems/GasTankSystem.cs @@ -1,4 +1,3 @@ -using System.Numerics; using Content.Server.Atmos.Components; using Content.Server.Body.Components; using Content.Server.Body.Systems; @@ -17,8 +16,6 @@ using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; -using Robust.Shared.Physics.Systems; -using Robust.Shared.Player; using Robust.Shared.Random; namespace Content.Server.Atmos.EntitySystems @@ -33,7 +30,6 @@ public sealed class GasTankSystem : EntitySystem [Dependency] private readonly SharedContainerSystem _containers = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly UserInterfaceSystem _ui = default!; - [Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly ThrowingSystem _throwing = default!; diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs index 10b9cccc099..8e478bd2b54 100644 --- a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs +++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs @@ -27,7 +27,6 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems public sealed class GasVolumePumpSystem : EntitySystem { [Dependency] private readonly IAdminLogManager _adminLogger = default!; - [Dependency] private readonly TransformSystem _transformSystem = default!; [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!; [Dependency] private readonly SharedAmbientSoundSystem _ambientSoundSystem = default!; diff --git a/Content.Server/Atmos/Piping/EntitySystems/AtmosPipeAppearanceSystem.cs b/Content.Server/Atmos/Piping/EntitySystems/AtmosPipeAppearanceSystem.cs index 6fbf60f403d..10049e273bc 100644 --- a/Content.Server/Atmos/Piping/EntitySystems/AtmosPipeAppearanceSystem.cs +++ b/Content.Server/Atmos/Piping/EntitySystems/AtmosPipeAppearanceSystem.cs @@ -3,14 +3,12 @@ using Content.Server.NodeContainer.Nodes; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; -using Robust.Server.GameObjects; -using Robust.Shared.Map; +using Robust.Shared.Map.Components; namespace Content.Server.Atmos.Piping.EntitySystems; public sealed class AtmosPipeAppearanceSystem : EntitySystem { - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; public override void Initialize() @@ -31,7 +29,7 @@ private void UpdateAppearance(EntityUid uid, AppearanceComponent? appearance = n if (!Resolve(uid, ref appearance, ref container, ref xform, false)) return; - if (!_mapManager.TryGetGrid(xform.GridUid, out var grid)) + if (!TryComp(xform.GridUid, out var grid)) return; // get connected entities diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs index ad647fad1b8..170586339db 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs @@ -13,7 +13,6 @@ using Content.Shared.Atmos.Piping.Binary.Components; using Content.Shared.Containers.ItemSlots; using Content.Shared.Database; -using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; using Content.Shared.Lock; using Robust.Server.GameObjects; @@ -29,8 +28,6 @@ public sealed class GasCanisterSystem : EntitySystem [Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly SharedContainerSystem _container = default!; - [Dependency] private readonly SharedHandsSystem _hands = default!; [Dependency] private readonly PopupSystem _popup = default!; [Dependency] private readonly UserInterfaceSystem _ui = default!; [Dependency] private readonly NodeContainerSystem _nodeContainer = default!; diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPortableSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPortableSystem.cs index b1caa6c197e..4ddd19dd45e 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPortableSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPortableSystem.cs @@ -7,15 +7,14 @@ using Content.Shared.Atmos.Piping.Unary.Components; using Content.Shared.Construction.Components; using JetBrains.Annotations; -using Robust.Server.GameObjects; using Robust.Shared.Map; +using Robust.Shared.Map.Components; namespace Content.Server.Atmos.Piping.Unary.EntitySystems { [UsedImplicitly] public sealed class GasPortableSystem : EntitySystem { - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly NodeContainerSystem _nodeContainer = default!; @@ -58,7 +57,7 @@ public bool FindGasPortIn(EntityUid? gridId, EntityCoordinates coordinates, [Not { port = null; - if (!_mapManager.TryGetGrid(gridId, out var grid)) + if (!TryComp(gridId, out var grid)) return false; foreach (var entityUid in grid.GetLocal(coordinates)) diff --git a/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs b/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs index 71e4c2d0def..00be83e86d9 100644 --- a/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs +++ b/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs @@ -26,7 +26,7 @@ public Dictionary Read(ISerializationManager serializa { node.TryGetValue(new ValueDataNode("version"), out var versionNode); var version = ((ValueDataNode?) versionNode)?.AsInt() ?? 1; - Dictionary tiles; + Dictionary tiles = new(); // Backwards compatability if (version == 1) @@ -36,8 +36,6 @@ public Dictionary Read(ISerializationManager serializa var mixies = serializationManager.Read?>(tile2, hookCtx, context); var unique = serializationManager.Read?>(node["uniqueMixes"], hookCtx, context); - tiles = new Dictionary(); - if (unique != null && mixies != null) { foreach (var (indices, mix) in mixies) @@ -58,15 +56,14 @@ public Dictionary Read(ISerializationManager serializa else { var dataNode = (MappingDataNode) node["data"]; - var tileNode = (MappingDataNode) dataNode["tiles"]; var chunkSize = serializationManager.Read(dataNode["chunkSize"], hookCtx, context); - var unique = serializationManager.Read?>(dataNode["uniqueMixes"], hookCtx, context); - - tiles = new Dictionary(); + dataNode.TryGetValue(new ValueDataNode("uniqueMixes"), out var mixNode); + var unique = mixNode == null ? null : serializationManager.Read?>(mixNode, hookCtx, context); if (unique != null) { + var tileNode = (MappingDataNode) dataNode["tiles"]; foreach (var (chunkNode, valueNode) in tileNode) { var chunkOrigin = serializationManager.Read(chunkNode, hookCtx, context); diff --git a/Content.Server/Bed/BedSystem.cs b/Content.Server/Bed/BedSystem.cs index 131bd4b1829..49021c142f4 100644 --- a/Content.Server/Bed/BedSystem.cs +++ b/Content.Server/Bed/BedSystem.cs @@ -93,9 +93,8 @@ private void OnBuckleChange(EntityUid uid, StasisBedComponent component, ref Buc if (!this.IsPowered(uid, EntityManager)) return; - var metabolicEvent = new ApplyMetabolicMultiplierEvent - {Uid = args.BuckledEntity, Multiplier = component.Multiplier, Apply = args.Buckling}; - RaiseLocalEvent(args.BuckledEntity, metabolicEvent); + var metabolicEvent = new ApplyMetabolicMultiplierEvent(args.BuckledEntity, component.Multiplier, args.Buckling); + RaiseLocalEvent(args.BuckledEntity, ref metabolicEvent); } private void OnPowerChanged(EntityUid uid, StasisBedComponent component, ref PowerChangedEvent args) @@ -121,9 +120,8 @@ private void UpdateMetabolisms(EntityUid uid, StasisBedComponent component, bool foreach (var buckledEntity in strap.BuckledEntities) { - var metabolicEvent = new ApplyMetabolicMultiplierEvent - {Uid = buckledEntity, Multiplier = component.Multiplier, Apply = shouldApply}; - RaiseLocalEvent(buckledEntity, metabolicEvent); + var metabolicEvent = new ApplyMetabolicMultiplierEvent(buckledEntity, component.Multiplier, shouldApply); + RaiseLocalEvent(buckledEntity, ref metabolicEvent); } } } diff --git a/Content.Server/Body/Commands/AddHandCommand.cs b/Content.Server/Body/Commands/AddHandCommand.cs index 655d0c88f9b..3e006c539c7 100644 --- a/Content.Server/Body/Commands/AddHandCommand.cs +++ b/Content.Server/Body/Commands/AddHandCommand.cs @@ -34,7 +34,6 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) switch (args.Length) { case 0: - { if (player == null) { shell.WriteLine("Only a player can run this command without arguments."); @@ -50,71 +49,68 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) entity = player.AttachedEntity.Value; hand = _entManager.SpawnEntity(DefaultHandPrototype, _entManager.GetComponent(entity).Coordinates); break; - } case 1: - { - if (NetEntity.TryParse(args[0], out var uidNet) && _entManager.TryGetEntity(uidNet, out var uid)) { - if (!_entManager.EntityExists(uid)) + if (NetEntity.TryParse(args[0], out var uidNet) && _entManager.TryGetEntity(uidNet, out var uid)) { - shell.WriteLine($"No entity found with uid {uid}"); - return; + if (!_entManager.EntityExists(uid)) + { + shell.WriteLine($"No entity found with uid {uid}"); + return; + } + + entity = uid.Value; + hand = _entManager.SpawnEntity(DefaultHandPrototype, _entManager.GetComponent(entity).Coordinates); + } + else + { + if (player == null) + { + shell.WriteLine("You must specify an entity to add a hand to when using this command from the server terminal."); + return; + } + + if (player.AttachedEntity == null) + { + shell.WriteLine("You don't have an entity to add a hand to."); + return; + } + + entity = player.AttachedEntity.Value; + hand = _entManager.SpawnEntity(args[0], _entManager.GetComponent(entity).Coordinates); } - entity = uid.Value; - hand = _entManager.SpawnEntity(DefaultHandPrototype, _entManager.GetComponent(entity).Coordinates); + break; } - else + case 2: { - if (player == null) + if (!NetEntity.TryParse(args[0], out var netEnt) || !_entManager.TryGetEntity(netEnt, out var uid)) { - shell.WriteLine("You must specify an entity to add a hand to when using this command from the server terminal."); + shell.WriteLine($"{args[0]} is not a valid entity uid."); return; } - if (player.AttachedEntity == null) + if (!_entManager.EntityExists(uid)) { - shell.WriteLine("You don't have an entity to add a hand to."); + shell.WriteLine($"No entity exists with uid {uid}."); return; } - entity = player.AttachedEntity.Value; - hand = _entManager.SpawnEntity(args[0], _entManager.GetComponent(entity).Coordinates); - } - - break; - } - case 2: - { - if (!NetEntity.TryParse(args[0], out var netEnt) || !_entManager.TryGetEntity(netEnt, out var uid)) - { - shell.WriteLine($"{args[0]} is not a valid entity uid."); - return; - } + entity = uid.Value; - if (!_entManager.EntityExists(uid)) - { - shell.WriteLine($"No entity exists with uid {uid}."); - return; - } + if (!_protoManager.HasIndex(args[1])) + { + shell.WriteLine($"No hand entity exists with id {args[1]}."); + return; + } - entity = uid.Value; + hand = _entManager.SpawnEntity(args[1], _entManager.GetComponent(entity).Coordinates); - if (!_protoManager.HasIndex(args[1])) - { - shell.WriteLine($"No hand entity exists with id {args[1]}."); - return; + break; } - - hand = _entManager.SpawnEntity(args[1], _entManager.GetComponent(entity).Coordinates); - - break; - } default: - { shell.WriteLine(Help); return; - } } if (!_entManager.TryGetComponent(entity, out BodyComponent? body) || body.RootContainer.ContainedEntity == null) @@ -139,7 +135,7 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) var slotId = part.GetHashCode().ToString(); - if (!bodySystem.TryCreatePartSlotAndAttach(attachAt.Id, slotId, hand, BodyPartType.Hand,attachAt.Component, part)) + if (!bodySystem.TryCreatePartSlotAndAttach(attachAt.Id, slotId, hand, BodyPartType.Hand, attachAt.Component, part)) { shell.WriteError($"Couldn't create a slot with id {slotId} on entity {_entManager.ToPrettyString(entity)}"); return; diff --git a/Content.Server/Body/Commands/AttachBodyPartCommand.cs b/Content.Server/Body/Commands/AttachBodyPartCommand.cs index 24604b88b7a..82f71619370 100644 --- a/Content.Server/Body/Commands/AttachBodyPartCommand.cs +++ b/Content.Server/Body/Commands/AttachBodyPartCommand.cs @@ -103,11 +103,11 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract if (body.RootContainer.ContainedEntity != null) { - bodySystem.AttachPartToRoot(bodyId,partUid.Value, body ,part); + bodySystem.AttachPartToRoot(bodyId, partUid.Value, body, part); } else { - var (rootPartId,rootPart) = bodySystem.GetRootPartOrNull(bodyId, body)!.Value; + var (rootPartId, rootPart) = bodySystem.GetRootPartOrNull(bodyId, body)!.Value; if (!bodySystem.TryCreatePartSlotAndAttach(rootPartId, slotId, partUid.Value, part.PartType, rootPart, part)) { shell.WriteError($"Could not create slot {slotId} on entity {_entManager.ToPrettyString(bodyId)}"); diff --git a/Content.Server/Body/Components/BeingGibbedEvent.cs b/Content.Server/Body/Components/BeingGibbedEvent.cs index 66b52af47bd..a010855f784 100644 --- a/Content.Server/Body/Components/BeingGibbedEvent.cs +++ b/Content.Server/Body/Components/BeingGibbedEvent.cs @@ -1,11 +1,7 @@ namespace Content.Server.Body.Components; -public sealed class BeingGibbedEvent : EntityEventArgs -{ - public readonly HashSet GibbedParts; - - public BeingGibbedEvent(HashSet gibbedParts) - { - GibbedParts = gibbedParts; - } -} +/// +/// Raised when a body gets gibbed, before it is deleted. +/// +[ByRefEvent] +public readonly record struct BeingGibbedEvent(HashSet GibbedParts); diff --git a/Content.Server/Body/Components/BloodstreamComponent.cs b/Content.Server/Body/Components/BloodstreamComponent.cs index 7041df44481..d448c4aab21 100644 --- a/Content.Server/Body/Components/BloodstreamComponent.cs +++ b/Content.Server/Body/Components/BloodstreamComponent.cs @@ -1,11 +1,13 @@ using Content.Server.Body.Systems; using Content.Server.Chemistry.EntitySystems; 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.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Server.Body.Components { @@ -16,7 +18,17 @@ public sealed partial class BloodstreamComponent : Component public static string DefaultBloodSolutionName = "bloodstream"; public static string DefaultBloodTemporarySolutionName = "bloodstreamTemporary"; - public float AccumulatedFrametime = 0.0f; + /// + /// The next time that blood level will be updated and bloodloss damage dealt. + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + public TimeSpan NextUpdate; + + /// + /// The interval at which this component updates. + /// + [DataField] + public TimeSpan UpdateInterval = TimeSpan.FromSeconds(3); /// /// How much is this entity currently bleeding? @@ -32,7 +44,7 @@ public sealed partial class BloodstreamComponent : Component public float BleedAmount; /// - /// How much should bleeding should be reduced every update interval? + /// How much should bleeding be reduced every update interval? /// [DataField] public float BleedReductionAmount = 0.33f; @@ -63,18 +75,12 @@ public sealed partial class BloodstreamComponent : Component [DataField(required: true)] public DamageSpecifier BloodlossHealDamage = new(); - /// - /// How frequently should this bloodstream update, in seconds? - /// - [DataField] - public float UpdateInterval = 3.0f; - // TODO shouldn't be hardcoded, should just use some organ simulation like bone marrow or smth. /// /// How much reagent of blood should be restored each update interval? /// [DataField] - public float BloodRefreshAmount = 1.0f; + public FixedPoint2 BloodRefreshAmount = 1.0f; /// /// How much blood needs to be in the temporary solution in order to create a puddle? @@ -89,8 +95,8 @@ public sealed partial class BloodstreamComponent : Component /// /// For example, piercing damage is increased while poison damage is nullified entirely. /// - [DataField(customTypeSerializer:typeof(PrototypeIdSerializer))] - public string DamageBleedModifiers = "BloodlossHuman"; + [DataField] + public ProtoId DamageBleedModifiers = "BloodlossHuman"; /// /// The sound to be played when a weapon instantly deals blood loss damage. @@ -126,7 +132,7 @@ public sealed partial class BloodstreamComponent : Component /// Slime-people might use slime as their blood or something like that. /// [DataField] - public string BloodReagent = "Blood"; + public ProtoId BloodReagent = "Blood"; /// Name/Key that is indexed by. [DataField] @@ -164,6 +170,6 @@ public sealed partial class BloodstreamComponent : Component /// Variable that stores the amount of status time added by having a low blood level. /// [ViewVariables(VVAccess.ReadWrite)] - public float StatusTime; + public TimeSpan StatusTime; } } diff --git a/Content.Server/Body/Components/InternalsComponent.cs b/Content.Server/Body/Components/InternalsComponent.cs index 4eda008b0f9..18caab8dcf0 100644 --- a/Content.Server/Body/Components/InternalsComponent.cs +++ b/Content.Server/Body/Components/InternalsComponent.cs @@ -1,4 +1,3 @@ -using System.Threading; namespace Content.Server.Body.Components { /// @@ -7,14 +6,17 @@ namespace Content.Server.Body.Components [RegisterComponent] public sealed partial class InternalsComponent : Component { - [ViewVariables] public EntityUid? GasTankEntity { get; set; } - [ViewVariables] public EntityUid? BreathToolEntity { get; set; } + [ViewVariables] + public EntityUid? GasTankEntity; + + [ViewVariables] + public EntityUid? BreathToolEntity; /// - /// Toggle Internals delay (seconds) when the target is not you. + /// Toggle Internals delay when the target is not you. /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("delay")] - public float Delay = 3; + [DataField] + public TimeSpan Delay = TimeSpan.FromSeconds(3); } } diff --git a/Content.Server/Body/Components/LungComponent.cs b/Content.Server/Body/Components/LungComponent.cs index 0656ef8fad3..46600b30207 100644 --- a/Content.Server/Body/Components/LungComponent.cs +++ b/Content.Server/Body/Components/LungComponent.cs @@ -1,4 +1,4 @@ -using Content.Server.Atmos; +using Content.Server.Atmos; using Content.Server.Body.Systems; using Content.Shared.Alert; using Content.Shared.Atmos; @@ -11,7 +11,7 @@ public sealed partial class LungComponent : Component { [DataField] [Access(typeof(LungSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends - public GasMixture Air { get; set; } = new() + public GasMixture Air = new() { Volume = 6, Temperature = Atmospherics.NormalBodyTemperature diff --git a/Content.Server/Body/Components/MetabolizerComponent.cs b/Content.Server/Body/Components/MetabolizerComponent.cs index a8c82f3d369..90c99df7db2 100644 --- a/Content.Server/Body/Components/MetabolizerComponent.cs +++ b/Content.Server/Body/Components/MetabolizerComponent.cs @@ -1,8 +1,8 @@ -using Content.Server.Body.Systems; +using Content.Server.Body.Systems; using Content.Shared.Body.Prototypes; using Content.Shared.FixedPoint; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Server.Body.Components { @@ -12,20 +12,24 @@ namespace Content.Server.Body.Components [RegisterComponent, Access(typeof(MetabolizerSystem))] public sealed partial class MetabolizerComponent : Component { - public float AccumulatedFrametime = 0.0f; + /// + /// The next time that reagents will be metabolized. + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + public TimeSpan NextUpdate; /// - /// How often to metabolize reagents, in seconds. + /// How often to metabolize reagents. /// /// [DataField] - public float UpdateFrequency = 1.0f; + public TimeSpan UpdateInterval = TimeSpan.FromSeconds(1); /// /// From which solution will this metabolizer attempt to metabolize chemicals /// [DataField("solution")] - public string SolutionName { get; set; } = BloodstreamComponent.DefaultChemicalsSolutionName; + public string SolutionName = BloodstreamComponent.DefaultChemicalsSolutionName; /// /// Does this component use a solution on it's parent entity (the body) or itself @@ -39,9 +43,9 @@ public sealed partial class MetabolizerComponent : Component /// /// List of metabolizer types that this organ is. ex. Human, Slime, Felinid, w/e. /// - [DataField(customTypeSerializer:typeof(PrototypeIdHashSetSerializer))] + [DataField] [Access(typeof(MetabolizerSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends - public HashSet? MetabolizerTypes = null; + public HashSet>? MetabolizerTypes = null; /// /// Should this metabolizer remove chemicals that have no metabolisms defined? @@ -72,8 +76,8 @@ public sealed partial class MetabolizerComponent : Component [DataDefinition] public sealed partial class MetabolismGroupEntry { - [DataField(required: true, customTypeSerializer:typeof(PrototypeIdSerializer))] - public string Id = default!; + [DataField(required: true)] + public ProtoId Id = default!; [DataField("rateModifier")] public FixedPoint2 MetabolismRateModifier = 1.0; diff --git a/Content.Server/Body/Components/RespiratorComponent.cs b/Content.Server/Body/Components/RespiratorComponent.cs index 9f080a3dd9d..4045e21e26a 100644 --- a/Content.Server/Body/Components/RespiratorComponent.cs +++ b/Content.Server/Body/Components/RespiratorComponent.cs @@ -1,5 +1,6 @@ using Content.Server.Body.Systems; using Content.Shared.Damage; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Server.Body.Components { @@ -7,36 +8,49 @@ namespace Content.Server.Body.Components public sealed partial class RespiratorComponent : Component { /// - /// Saturation level. Reduced by CycleDelay each tick. + /// The next time that this body will inhale or exhale. + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + public TimeSpan NextUpdate; + + /// + /// The interval between updates. Each update is either inhale or exhale, + /// so a full cycle takes twice as long. + /// + [DataField] + public TimeSpan UpdateInterval = TimeSpan.FromSeconds(2); + + /// + /// Saturation level. Reduced by UpdateInterval each tick. /// Can be thought of as 'how many seconds you have until you start suffocating' in this configuration. /// - [DataField("saturation")] + [DataField] public float Saturation = 5.0f; /// /// At what level of saturation will you begin to suffocate? /// - [DataField("suffocationThreshold")] + [DataField] public float SuffocationThreshold; - [DataField("maxSaturation")] + [DataField] public float MaxSaturation = 5.0f; - [DataField("minSaturation")] + [DataField] public float MinSaturation = -2.0f; // TODO HYPEROXIA? - [DataField("damage", required: true)] + [DataField(required: true)] [ViewVariables(VVAccess.ReadWrite)] public DamageSpecifier Damage = default!; - [DataField("damageRecovery", required: true)] + [DataField(required: true)] [ViewVariables(VVAccess.ReadWrite)] public DamageSpecifier DamageRecovery = default!; - [DataField("gaspPopupCooldown")] - public TimeSpan GaspPopupCooldown { get; private set; } = TimeSpan.FromSeconds(8); + [DataField] + public TimeSpan GaspPopupCooldown = TimeSpan.FromSeconds(8); [ViewVariables] public TimeSpan LastGaspPopupTime; @@ -55,11 +69,6 @@ public sealed partial class RespiratorComponent : Component [ViewVariables] public RespiratorStatus Status = RespiratorStatus.Inhaling; - - [DataField("cycleDelay")] - public float CycleDelay = 2.0f; - - public float AccumulatedFrametime; } } diff --git a/Content.Server/Body/Components/StomachComponent.cs b/Content.Server/Body/Components/StomachComponent.cs index fe93468f74e..d541ca4d7c4 100644 --- a/Content.Server/Body/Components/StomachComponent.cs +++ b/Content.Server/Body/Components/StomachComponent.cs @@ -1,21 +1,26 @@ -using Content.Server.Body.Systems; +using Content.Server.Body.Systems; using Content.Server.Nutrition.EntitySystems; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; using Content.Shared.Whitelist; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Server.Body.Components { [RegisterComponent, Access(typeof(StomachSystem), typeof(FoodSystem))] public sealed partial class StomachComponent : Component { - public float AccumulatedFrameTime; + /// + /// The next time that the stomach will try to digest its contents. + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + public TimeSpan NextUpdate; /// - /// How fast should this component update, in seconds? + /// The interval at which this stomach digests its contents. /// [DataField] - public float UpdateInterval = 1.0f; + public TimeSpan UpdateInterval = TimeSpan.FromSeconds(1); /// /// The solution inside of this stomach this transfers reagents to the body. @@ -30,11 +35,11 @@ public sealed partial class StomachComponent : Component public string BodySolutionName = BloodstreamComponent.DefaultChemicalsSolutionName; /// - /// Time in seconds between reagents being ingested and them being + /// Time between reagents being ingested and them being /// transferred to /// [DataField] - public float DigestionDelay = 20; + public TimeSpan DigestionDelay = TimeSpan.FromSeconds(20); /// /// A whitelist for what special-digestible-required foods this stomach is capable of eating. @@ -54,15 +59,15 @@ public sealed partial class StomachComponent : Component public sealed class ReagentDelta { public readonly ReagentQuantity ReagentQuantity; - public float Lifetime { get; private set; } + public TimeSpan Lifetime { get; private set; } public ReagentDelta(ReagentQuantity reagentQuantity) { ReagentQuantity = reagentQuantity; - Lifetime = 0.0f; + Lifetime = TimeSpan.Zero; } - public void Increment(float delta) => Lifetime += delta; + public void Increment(TimeSpan delta) => Lifetime += delta; } } } diff --git a/Content.Server/Body/Components/ThermalRegulatorComponent.cs b/Content.Server/Body/Components/ThermalRegulatorComponent.cs index 4acdccf1ba7..19b76189e09 100644 --- a/Content.Server/Body/Components/ThermalRegulatorComponent.cs +++ b/Content.Server/Body/Components/ThermalRegulatorComponent.cs @@ -1,4 +1,5 @@ using Content.Server.Body.Systems; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Server.Body.Components; @@ -6,48 +7,58 @@ namespace Content.Server.Body.Components; [Access(typeof(ThermalRegulatorSystem))] public sealed partial class ThermalRegulatorComponent : Component { + /// + /// The next time that the body will regulate its heat. + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + public TimeSpan NextUpdate; + + /// + /// The interval at which thermal regulation is processed. + /// + [DataField] + public TimeSpan UpdateInterval = TimeSpan.FromSeconds(1); + /// /// Heat generated due to metabolism. It's generated via metabolism /// - [DataField("metabolismHeat")] - public float MetabolismHeat { get; private set; } + [DataField] + public float MetabolismHeat; /// /// Heat output via radiation. /// - [DataField("radiatedHeat")] - public float RadiatedHeat { get; private set; } + [DataField] + public float RadiatedHeat; /// /// Maximum heat regulated via sweat /// - [DataField("sweatHeatRegulation")] - public float SweatHeatRegulation { get; private set; } + [DataField] + public float SweatHeatRegulation; /// /// Maximum heat regulated via shivering /// - [DataField("shiveringHeatRegulation")] - public float ShiveringHeatRegulation { get; private set; } + [DataField] + public float ShiveringHeatRegulation; /// /// Amount of heat regulation that represents thermal regulation processes not /// explicitly coded. /// - [DataField("implicitHeatRegulation")] - public float ImplicitHeatRegulation { get; private set; } + [DataField] + public float ImplicitHeatRegulation; /// /// Normal body temperature /// - [DataField("normalBodyTemperature")] - public float NormalBodyTemperature { get; private set; } + [DataField] + public float NormalBodyTemperature; /// /// Deviation from normal temperature for body to start thermal regulation /// - [DataField("thermalRegulationTemperatureThreshold")] - public float ThermalRegulationTemperatureThreshold { get; private set; } - - public float AccumulatedFrametime; + [DataField] + public float ThermalRegulationTemperatureThreshold; } diff --git a/Content.Server/Body/Systems/BloodstreamSystem.cs b/Content.Server/Body/Systems/BloodstreamSystem.cs index f6fdcfedff4..9e29fdf7568 100644 --- a/Content.Server/Body/Systems/BloodstreamSystem.cs +++ b/Content.Server/Body/Systems/BloodstreamSystem.cs @@ -13,7 +13,6 @@ using Content.Shared.Damage.Prototypes; using Content.Shared.Drunk; using Content.Shared.FixedPoint; -using Content.Shared.IdentityManagement; using Content.Shared.Mobs.Systems; using Content.Shared.Popups; using Content.Shared.Rejuvenate; @@ -21,11 +20,13 @@ 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 : 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!; @@ -44,6 +45,8 @@ public override void Initialize() base.Initialize(); SubscribeLocalEvent(OnComponentInit); + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnDamageChanged); SubscribeLocalEvent(OnHealthBeingExamined); SubscribeLocalEvent(OnBeingGibbed); @@ -53,6 +56,16 @@ public override void Initialize() SubscribeLocalEvent(OnRejuvenate); } + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + ent.Comp.NextUpdate = _gameTiming.CurTime + ent.Comp.UpdateInterval; + } + + private void OnUnpaused(Entity ent, ref EntityUnpausedEvent args) + { + ent.Comp.NextUpdate += args.PausedTime; + } + private void OnReactionAttempt(Entity entity, ref ReactionAttemptEvent args) { if (args.Cancelled) @@ -83,7 +96,9 @@ private void OnReactionAttempt(Entity entity, ref Solution if (args.Name != entity.Comp.BloodSolutionName && args.Name != entity.Comp.ChemicalSolutionName && args.Name != entity.Comp.BloodTemporarySolutionName) + { return; + } OnReactionAttempt(entity, ref args.Event); } @@ -95,12 +110,10 @@ public override void Update(float frameTime) var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var bloodstream)) { - bloodstream.AccumulatedFrametime += frameTime; - - if (bloodstream.AccumulatedFrametime < bloodstream.UpdateInterval) + if (_gameTiming.CurTime < bloodstream.NextUpdate) continue; - bloodstream.AccumulatedFrametime -= bloodstream.UpdateInterval; + bloodstream.NextUpdate += bloodstream.UpdateInterval; if (!_solutionContainerSystem.ResolveSolution(uid, bloodstream.BloodSolutionName, ref bloodstream.BloodSolution, out var bloodSolution)) continue; @@ -128,13 +141,17 @@ public override void Update(float frameTime) // 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, false, false); + _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, bloodstream.UpdateInterval*2, false); - _stutteringSystem.DoStutter(uid, TimeSpan.FromSeconds(bloodstream.UpdateInterval*2), false); + _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; @@ -142,13 +159,16 @@ public override void Update(float frameTime) else if (!_mobStateSystem.IsDead(uid)) { // If they're healthy, we'll try and heal some bloodloss instead. - _damageableSystem.TryChangeDamage(uid, bloodstream.BloodlossHealDamage * bloodPercentage, true, false); + _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); - _stutteringSystem.DoRemoveStutterTime(uid, bloodstream.StatusTime); + _drunkSystem.TryRemoveDrunkenessTime(uid, bloodstream.StatusTime.TotalSeconds); + _stutteringSystem.DoRemoveStutterTime(uid, bloodstream.StatusTime.TotalSeconds); // Reset the drunk and stutter time to zero - bloodstream.StatusTime = 0; + bloodstream.StatusTime = TimeSpan.Zero; } } } @@ -167,17 +187,15 @@ private void OnComponentInit(Entity entity, ref ComponentI bloodSolution.AddReagent(entity.Comp.BloodReagent, entity.Comp.BloodMaxVolume - bloodSolution.Volume); } - private void OnDamageChanged(EntityUid uid, BloodstreamComponent component, DamageChangedEvent args) + private void OnDamageChanged(Entity ent, ref DamageChangedEvent args) { - if (args.DamageDelta is null) - return; - - // definitely don't make them bleed if they got healed - if (!args.DamageIncreased) + if (args.DamageDelta is null || !args.DamageIncreased) + { return; + } // TODO probably cache this or something. humans get hurt a lot - if (!_prototypeManager.TryIndex(component.DamageBleedModifiers, out var modifiers)) + if (!_prototypeManager.TryIndex(ent.Comp.DamageBleedModifiers, out var modifiers)) return; var bloodloss = DamageSpecifier.ApplyModifierSet(args.DamageDelta, modifiers); @@ -186,10 +204,10 @@ private void OnDamageChanged(EntityUid uid, BloodstreamComponent component, Dama return; // Does the calculation of how much bleed rate should be added/removed, then applies it - var oldBleedAmount = component.BleedAmount; + var oldBleedAmount = ent.Comp.BleedAmount; var total = bloodloss.GetTotal(); var totalFloat = total.Float(); - TryModifyBleedAmount(uid, totalFloat, component); + TryModifyBleedAmount(ent, totalFloat, ent); /// /// Critical hit. Causes target to lose blood, using the bleed rate modifier of the weapon, currently divided by 5 @@ -199,8 +217,8 @@ private void OnDamageChanged(EntityUid uid, BloodstreamComponent component, Dama var prob = Math.Clamp(totalFloat / 25, 0, 1); if (totalFloat > 0 && _robustRandom.Prob(prob)) { - TryModifyBloodLevel(uid, (-total) / 5, component); - _audio.PlayPvs(component.InstantBloodSound, uid); + TryModifyBloodLevel(ent, (-total) / 5, ent); + _audio.PlayPvs(ent.Comp.InstantBloodSound, ent); } // Heat damage will cauterize, causing the bleed rate to be reduced. @@ -210,53 +228,52 @@ private void OnDamageChanged(EntityUid uid, BloodstreamComponent component, Dama // because it's burn damage that cauterized their wounds. // We'll play a special sound and popup for feedback. - _audio.PlayPvs(component.BloodHealedSound, uid); - _popupSystem.PopupEntity(Loc.GetString("bloodstream-component-wounds-cauterized"), uid, - uid, PopupType.Medium); + _audio.PlayPvs(ent.Comp.BloodHealedSound, ent); + _popupSystem.PopupEntity(Loc.GetString("bloodstream-component-wounds-cauterized"), ent, + ent, PopupType.Medium); } } /// /// Shows text on health examine, based on bleed rate and blood level. /// - private void OnHealthBeingExamined(EntityUid uid, BloodstreamComponent component, HealthBeingExaminedEvent args) + private void OnHealthBeingExamined(Entity ent, ref HealthBeingExaminedEvent args) { // Shows profusely bleeding at half the max bleed rate. - if (component.BleedAmount > component.MaxBleedAmount / 2) + if (ent.Comp.BleedAmount > ent.Comp.MaxBleedAmount / 2) { args.Message.PushNewline(); - args.Message.AddMarkup(Loc.GetString("bloodstream-component-profusely-bleeding", ("target", Identity.Entity(uid, EntityManager)))); + args.Message.AddMarkup(Loc.GetString("bloodstream-component-profusely-bleeding", ("target", ent.Owner))); } // Shows bleeding message when bleeding, but less than profusely. - else if (component.BleedAmount > 0) + else if (ent.Comp.BleedAmount > 0) { args.Message.PushNewline(); - args.Message.AddMarkup(Loc.GetString("bloodstream-component-bleeding", ("target", Identity.Entity(uid, EntityManager)))); + args.Message.AddMarkup(Loc.GetString("bloodstream-component-bleeding", ("target", ent.Owner))); } // If the mob's blood level is below the damage threshhold, the pale message is added. - if (GetBloodLevelPercentage(uid, component) < component.BloodlossThreshold) + if (GetBloodLevelPercentage(ent, ent) < ent.Comp.BloodlossThreshold) { args.Message.PushNewline(); - args.Message.AddMarkup(Loc.GetString("bloodstream-component-looks-pale", ("target", Identity.Entity(uid, EntityManager)))); + args.Message.AddMarkup(Loc.GetString("bloodstream-component-looks-pale", ("target", ent.Owner))); } } - private void OnBeingGibbed(EntityUid uid, BloodstreamComponent component, BeingGibbedEvent args) + private void OnBeingGibbed(Entity ent, ref BeingGibbedEvent args) { - SpillAllSolutions(uid, component); + SpillAllSolutions(ent, ent); } - private void OnApplyMetabolicMultiplier(EntityUid uid, BloodstreamComponent component, ApplyMetabolicMultiplierEvent args) + private void OnApplyMetabolicMultiplier( + Entity ent, + ref ApplyMetabolicMultiplierEvent args) { if (args.Apply) { - component.UpdateInterval *= args.Multiplier; + ent.Comp.UpdateInterval *= args.Multiplier; return; } - component.UpdateInterval /= args.Multiplier; - // Reset the accumulator properly - if (component.AccumulatedFrametime >= component.UpdateInterval) - component.AccumulatedFrametime = component.UpdateInterval; + ent.Comp.UpdateInterval /= args.Multiplier; } private void OnRejuvenate(Entity entity, ref RejuvenateEvent args) @@ -275,21 +292,15 @@ private void OnRejuvenate(Entity entity, ref RejuvenateEve /// public bool TryAddToChemicals(EntityUid uid, Solution solution, BloodstreamComponent? component = null) { - if (!Resolve(uid, ref component, false)) - return false; - - if (!_solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution)) - return false; - - return _solutionContainerSystem.TryAddSolution(component.ChemicalSolution.Value, solution); + 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, false)) - return false; - - if (!_solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution, out var chemSolution)) + 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--) @@ -306,11 +317,11 @@ public bool FlushChemicals(EntityUid uid, string excludedReagentID, FixedPoint2 public float GetBloodLevelPercentage(EntityUid uid, BloodstreamComponent? component = null) { - if (!Resolve(uid, ref component)) - return 0.0f; - - if (!_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution, out var bloodSolution)) + if (!Resolve(uid, ref component) + || !_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution, out var bloodSolution)) + { return 0.0f; + } return bloodSolution.FillFraction; } @@ -328,11 +339,11 @@ public void SetBloodLossThreshold(EntityUid uid, float threshold, BloodstreamCom /// public bool TryModifyBloodLevel(EntityUid uid, FixedPoint2 amount, BloodstreamComponent? component = null) { - if (!Resolve(uid, ref component, false)) - return false; - - if (!_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution)) + 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, out _); @@ -356,9 +367,9 @@ public bool TryModifyBloodLevel(EntityUid uid, FixedPoint2 amount, BloodstreamCo tempSolution.AddSolution(temp, _prototypeManager); } - if (_puddleSystem.TrySpillAt(uid, tempSolution, out var puddleUid, false)) + if (_puddleSystem.TrySpillAt(uid, tempSolution, out var puddleUid, sound: false)) { - _forensicsSystem.TransferDna(puddleUid, uid, false); + _forensicsSystem.TransferDna(puddleUid, uid, canDnaBeCleaned: false); } tempSolution.RemoveAllSolution(); @@ -374,7 +385,7 @@ public bool TryModifyBloodLevel(EntityUid uid, FixedPoint2 amount, BloodstreamCo /// public bool TryModifyBleedAmount(EntityUid uid, float amount, BloodstreamComponent? component = null) { - if (!Resolve(uid, ref component, false)) + if (!Resolve(uid, ref component, logMissing: false)) return false; component.BleedAmount += amount; @@ -424,7 +435,7 @@ public void SpillAllSolutions(EntityUid uid, BloodstreamComponent? component = n if (_puddleSystem.TrySpillAt(uid, tempSol, out var puddleUid)) { - _forensicsSystem.TransferDna(puddleUid, uid, false); + _forensicsSystem.TransferDna(puddleUid, uid, canDnaBeCleaned: false); } } @@ -433,11 +444,11 @@ public void SpillAllSolutions(EntityUid uid, BloodstreamComponent? component = n /// public void ChangeBloodReagent(EntityUid uid, string reagent, BloodstreamComponent? component = null) { - if (!Resolve(uid, ref component, false)) - return; - - if (reagent == component.BloodReagent) + if (!Resolve(uid, ref component, logMissing: false) + || reagent == component.BloodReagent) + { return; + } if (!_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution, out var bloodSolution)) { diff --git a/Content.Server/Body/Systems/BodySystem.cs b/Content.Server/Body/Systems/BodySystem.cs index 18119909abc..37f78ed81a0 100644 --- a/Content.Server/Body/Systems/BodySystem.cs +++ b/Content.Server/Body/Systems/BodySystem.cs @@ -1,23 +1,19 @@ using Content.Server.Body.Components; using Content.Server.GameTicking; using Content.Server.Humanoid; -using Content.Server.Kitchen.Components; using Content.Shared.Body.Components; using Content.Shared.Body.Part; using Content.Shared.Body.Systems; using Content.Shared.Humanoid; -using Content.Shared.Kitchen.Components; using Content.Shared.Mind; using Content.Shared.Mobs.Systems; using Content.Shared.Movement.Events; +using Content.Shared.Movement.Systems; using Robust.Shared.Audio; -using Robust.Shared.Player; +using Robust.Shared.Audio.Systems; using Robust.Shared.Random; using Robust.Shared.Timing; using System.Numerics; -using Content.Shared.Gibbing.Components; -using Content.Shared.Movement.Systems; -using Robust.Shared.Audio.Systems; namespace Content.Server.Body.Systems; @@ -28,9 +24,7 @@ public sealed class BodySystem : SharedBodySystem [Dependency] private readonly HumanoidAppearanceSystem _humanoidSystem = default!; [Dependency] private readonly MobStateSystem _mobState = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedMindSystem _mindSystem = default!; - [Dependency] private readonly IRobustRandom _random = default!; public override void Initialize() { @@ -40,7 +34,7 @@ public override void Initialize() SubscribeLocalEvent(OnApplyMetabolicMultiplier); } - private void OnRelayMoveInput(EntityUid uid, BodyComponent component, ref MoveInputEvent args) + private void OnRelayMoveInput(Entity ent, ref MoveInputEvent args) { // If they haven't actually moved then ignore it. if ((args.Component.HeldMoveButtons & @@ -49,68 +43,67 @@ private void OnRelayMoveInput(EntityUid uid, BodyComponent component, ref MoveIn return; } - if (_mobState.IsDead(uid) && _mindSystem.TryGetMind(uid, out var mindId, out var mind)) + if (_mobState.IsDead(ent) && _mindSystem.TryGetMind(ent, out var mindId, out var mind)) { mind.TimeOfDeath ??= _gameTiming.RealTime; - _ticker.OnGhostAttempt(mindId, true, mind: mind); + _ticker.OnGhostAttempt(mindId, canReturnGlobal: true, mind: mind); } } - private void OnApplyMetabolicMultiplier(EntityUid uid, BodyComponent component, - ApplyMetabolicMultiplierEvent args) + private void OnApplyMetabolicMultiplier( + Entity ent, + ref ApplyMetabolicMultiplierEvent args) { - foreach (var organ in GetBodyOrgans(uid, component)) + foreach (var organ in GetBodyOrgans(ent, ent)) { - RaiseLocalEvent(organ.Id, args); + RaiseLocalEvent(organ.Id, ref args); } } protected override void AddPart( - EntityUid bodyUid, - EntityUid partUid, - string slotId, - BodyPartComponent component, - BodyComponent? bodyComp = null) + Entity bodyEnt, + Entity partEnt, + string slotId) { // TODO: Predict this probably. - base.AddPart(bodyUid, partUid, slotId, component, bodyComp); + base.AddPart(bodyEnt, partEnt, slotId); - if (TryComp(bodyUid, out var humanoid)) + if (TryComp(bodyEnt, out var humanoid)) { - var layer = component.ToHumanoidLayers(); + var layer = partEnt.Comp.ToHumanoidLayers(); if (layer != null) { var layers = HumanoidVisualLayersExtension.Sublayers(layer.Value); - _humanoidSystem.SetLayersVisibility(bodyUid, layers, true, true, humanoid); + _humanoidSystem.SetLayersVisibility( + bodyEnt, layers, visible: true, permanent: true, humanoid); } } } protected override void RemovePart( - EntityUid bodyUid, - EntityUid partUid, - string slotId, - BodyPartComponent component, - BodyComponent? bodyComp = null) + Entity bodyEnt, + Entity partEnt, + string slotId) { - base.RemovePart(bodyUid, partUid, slotId, component, bodyComp); + base.RemovePart(bodyEnt, partEnt, slotId); - if (!TryComp(bodyUid, out var humanoid)) + if (!TryComp(bodyEnt, out var humanoid)) return; - var layer = component.ToHumanoidLayers(); + var layer = partEnt.Comp.ToHumanoidLayers(); - if (layer == null) + if (layer is null) return; var layers = HumanoidVisualLayersExtension.Sublayers(layer.Value); - _humanoidSystem.SetLayersVisibility(bodyUid, layers, false, true, humanoid); + _humanoidSystem.SetLayersVisibility( + bodyEnt, layers, visible: false, permanent: true, humanoid); } public override HashSet GibBody( EntityUid bodyId, bool gibOrgans = false, - BodyComponent? body = null , + BodyComponent? body = null, bool launchGibs = true, Vector2? splatDirection = null, float splatModifier = 1, @@ -118,19 +111,23 @@ public override HashSet GibBody( SoundSpecifier? gibSoundOverride = null ) { - if (!Resolve(bodyId, ref body, false)) - return new HashSet(); - - if (TerminatingOrDeleted(bodyId) || EntityManager.IsQueuedForDeletion(bodyId)) + if (!Resolve(bodyId, ref body, logMissing: false) + || TerminatingOrDeleted(bodyId) + || EntityManager.IsQueuedForDeletion(bodyId)) + { return new HashSet(); + } var xform = Transform(bodyId); - if (xform.MapUid == null) + if (xform.MapUid is null) return new HashSet(); var gibs = base.GibBody(bodyId, gibOrgans, body, launchGibs: launchGibs, splatDirection: splatDirection, splatModifier: splatModifier, splatCone:splatCone); - RaiseLocalEvent(bodyId, new BeingGibbedEvent(gibs)); + + var ev = new BeingGibbedEvent(gibs); + RaiseLocalEvent(bodyId, ref ev); + QueueDel(bodyId); return gibs; diff --git a/Content.Server/Body/Systems/BrainSystem.cs b/Content.Server/Body/Systems/BrainSystem.cs index abb54971209..86d2cb61ffe 100644 --- a/Content.Server/Body/Systems/BrainSystem.cs +++ b/Content.Server/Body/Systems/BrainSystem.cs @@ -16,8 +16,8 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent((uid, _, args) => HandleMind(args.Body, uid)); - SubscribeLocalEvent((uid, _, args) => HandleMind(uid, args.OldBody)); + SubscribeLocalEvent((uid, _, args) => HandleMind(args.Body, uid)); + SubscribeLocalEvent((uid, _, args) => HandleMind(uid, args.OldBody)); SubscribeLocalEvent(OnPointAttempt); } @@ -39,7 +39,7 @@ private void HandleMind(EntityUid newEntity, EntityUid oldEntity) _mindSystem.TransferTo(mindId, newEntity, mind: mind); } - private void OnPointAttempt(EntityUid uid, BrainComponent component, PointAttemptEvent args) + private void OnPointAttempt(Entity ent, ref PointAttemptEvent args) { args.Cancel(); } diff --git a/Content.Server/Body/Systems/InternalsSystem.cs b/Content.Server/Body/Systems/InternalsSystem.cs index 007cbdf0848..9607a808f65 100644 --- a/Content.Server/Body/Systems/InternalsSystem.cs +++ b/Content.Server/Body/Systems/InternalsSystem.cs @@ -1,7 +1,6 @@ using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; using Content.Server.Body.Components; -using Content.Server.Hands.Systems; using Content.Server.Popups; using Content.Shared.Alert; using Content.Shared.Atmos; @@ -11,19 +10,16 @@ using Content.Shared.Inventory; using Content.Shared.Verbs; using Robust.Shared.Containers; -using Robust.Shared.Prototypes; using Robust.Shared.Utility; namespace Content.Server.Body.Systems; public sealed class InternalsSystem : EntitySystem { - [Dependency] private readonly IPrototypeManager _protoManager = default!; [Dependency] private readonly AlertsSystem _alerts = default!; [Dependency] private readonly AtmosphereSystem _atmos = default!; [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; [Dependency] private readonly GasTankSystem _gasTank = default!; - [Dependency] private readonly HandsSystem _hands = default!; [Dependency] private readonly InventorySystem _inventory = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; @@ -40,28 +36,36 @@ public override void Initialize() SubscribeLocalEvent(OnDoAfter); } - private void OnGetInteractionVerbs(EntityUid uid, InternalsComponent component, GetVerbsEvent args) + private void OnGetInteractionVerbs( + Entity ent, + ref GetVerbsEvent args) { - if (!args.CanAccess || !args.CanInteract || args.Hands == null) + if (!args.CanAccess || !args.CanInteract || args.Hands is null) return; + var user = args.User; + InteractionVerb verb = new() { Act = () => { - ToggleInternals(uid, args.User, false, component); + ToggleInternals(ent, user, force: false, ent); }, Message = Loc.GetString("action-description-internals-toggle"), - Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/dot.svg.192dpi.png")), + Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/dot.svg.192dpi.png")), Text = Loc.GetString("action-name-internals-toggle"), }; args.Verbs.Add(verb); } - public void ToggleInternals(EntityUid uid, EntityUid user, bool force, InternalsComponent? internals = null) + public void ToggleInternals( + EntityUid uid, + EntityUid user, + bool force, + InternalsComponent? internals = null) { - if (!Resolve(uid, ref internals, false)) + if (!Resolve(uid, ref internals, logMissing: false)) return; // Toggle off if they're on @@ -73,12 +77,12 @@ public void ToggleInternals(EntityUid uid, EntityUid user, bool force, Internals return; } - StartToggleInternalsDoAfter(user, uid, internals); + StartToggleInternalsDoAfter(user, (uid, internals)); return; } // If they're not on then check if we have a mask to use - if (internals.BreathToolEntity == null) + if (internals.BreathToolEntity is null) { _popupSystem.PopupEntity(Loc.GetString("internals-no-breath-tool"), uid, user); return; @@ -86,7 +90,7 @@ public void ToggleInternals(EntityUid uid, EntityUid user, bool force, Internals var tank = FindBestGasTank(uid); - if (tank == null) + if (tank is null) { _popupSystem.PopupEntity(Loc.GetString("internals-no-tank"), uid, user); return; @@ -94,20 +98,20 @@ public void ToggleInternals(EntityUid uid, EntityUid user, bool force, Internals if (!force) { - StartToggleInternalsDoAfter(user, uid, internals); + StartToggleInternalsDoAfter(user, (uid, internals)); return; } _gasTank.ConnectToInternals(tank.Value); } - private void StartToggleInternalsDoAfter(EntityUid user, EntityUid target, InternalsComponent internals) + private void StartToggleInternalsDoAfter(EntityUid user, Entity targetEnt) { // Is the target not you? If yes, use a do-after to give them time to respond. - var isUser = user == target; - var delay = !isUser ? internals.Delay : 0f; + var isUser = user == targetEnt.Owner; + var delay = !isUser ? targetEnt.Comp.Delay : TimeSpan.Zero; - _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, user, delay, new InternalsDoAfterEvent(), target, target: target) + _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, user, delay, new InternalsDoAfterEvent(), targetEnt, target: targetEnt) { BreakOnUserMove = true, BreakOnDamage = true, @@ -116,66 +120,64 @@ private void StartToggleInternalsDoAfter(EntityUid user, EntityUid target, Inter }); } - private void OnDoAfter(EntityUid uid, InternalsComponent component, InternalsDoAfterEvent args) + private void OnDoAfter(Entity ent, ref InternalsDoAfterEvent args) { if (args.Cancelled || args.Handled) return; - ToggleInternals(uid, args.User, true, component); + ToggleInternals(ent, args.User, force: true, ent); args.Handled = true; } - private void OnInternalsStartup(EntityUid uid, InternalsComponent component, ComponentStartup args) + private void OnInternalsStartup(Entity ent, ref ComponentStartup args) { - _alerts.ShowAlert(uid, AlertType.Internals, GetSeverity(component)); + _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent)); } - private void OnInternalsShutdown(EntityUid uid, InternalsComponent component, ComponentShutdown args) + private void OnInternalsShutdown(Entity ent, ref ComponentShutdown args) { - _alerts.ClearAlert(uid, AlertType.Internals); + _alerts.ClearAlert(ent, AlertType.Internals); } - private void OnInhaleLocation(EntityUid uid, InternalsComponent component, InhaleLocationEvent args) + private void OnInhaleLocation(Entity ent, ref InhaleLocationEvent args) { - if (AreInternalsWorking(component)) + if (AreInternalsWorking(ent)) { - var gasTank = Comp(component.GasTankEntity!.Value); - args.Gas = _gasTank.RemoveAirVolume((component.GasTankEntity.Value, gasTank), Atmospherics.BreathVolume); + var gasTank = Comp(ent.Comp.GasTankEntity!.Value); + args.Gas = _gasTank.RemoveAirVolume((ent.Comp.GasTankEntity.Value, gasTank), Atmospherics.BreathVolume); // TODO: Should listen to gas tank updates instead I guess? - _alerts.ShowAlert(uid, AlertType.Internals, GetSeverity(component)); + _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent)); } } public void DisconnectBreathTool(Entity ent) { - var (owner, component) = ent; - var old = component.BreathToolEntity; - component.BreathToolEntity = null; + var old = ent.Comp.BreathToolEntity; + ent.Comp.BreathToolEntity = null; - if (TryComp(old, out BreathToolComponent? breathTool) ) + if (TryComp(old, out BreathToolComponent? breathTool)) { _atmos.DisconnectInternals(breathTool); DisconnectTank(ent); } - _alerts.ShowAlert(owner, AlertType.Internals, GetSeverity(component)); + _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent)); } public void ConnectBreathTool(Entity ent, EntityUid toolEntity) { - var (owner, component) = ent; - if (TryComp(component.BreathToolEntity, out BreathToolComponent? tool)) + if (TryComp(ent.Comp.BreathToolEntity, out BreathToolComponent? tool)) { _atmos.DisconnectInternals(tool); } - component.BreathToolEntity = toolEntity; - _alerts.ShowAlert(owner, AlertType.Internals, GetSeverity(component)); + ent.Comp.BreathToolEntity = toolEntity; + _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent)); } public void DisconnectTank(InternalsComponent? component) { - if (component == null) + if (component is null) return; if (TryComp(component.GasTankEntity, out GasTankComponent? tank)) @@ -187,46 +189,47 @@ public void DisconnectTank(InternalsComponent? component) public bool TryConnectTank(Entity ent, EntityUid tankEntity) { - var component = ent.Comp; - if (component.BreathToolEntity == null) + if (ent.Comp.BreathToolEntity is null) return false; - if (TryComp(component.GasTankEntity, out GasTankComponent? tank)) - _gasTank.DisconnectFromInternals((component.GasTankEntity.Value, tank)); + if (TryComp(ent.Comp.GasTankEntity, out GasTankComponent? tank)) + _gasTank.DisconnectFromInternals((ent.Comp.GasTankEntity.Value, tank)); - component.GasTankEntity = tankEntity; - _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(component)); + ent.Comp.GasTankEntity = tankEntity; + _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent)); return true; } public bool AreInternalsWorking(EntityUid uid, InternalsComponent? component = null) { - if (!Resolve(uid, ref component, false)) - return false; - - return AreInternalsWorking(component); + return Resolve(uid, ref component, logMissing: false) + && AreInternalsWorking(component); } public bool AreInternalsWorking(InternalsComponent component) { - return TryComp(component.BreathToolEntity, out BreathToolComponent? breathTool) && - breathTool.IsFunctional && - TryComp(component.GasTankEntity, out GasTankComponent? _); + return TryComp(component.BreathToolEntity, out BreathToolComponent? breathTool) + && breathTool.IsFunctional + && HasComp(component.GasTankEntity); } private short GetSeverity(InternalsComponent component) { - if (component.BreathToolEntity == null || !AreInternalsWorking(component)) + if (component.BreathToolEntity is null || !AreInternalsWorking(component)) return 2; // If pressure in the tank is below low pressure threshhold, flash warning on internals UI - if (TryComp(component.GasTankEntity, out var gasTank) && gasTank.IsLowPressure) + if (TryComp(component.GasTankEntity, out var gasTank) + && gasTank.IsLowPressure) + { return 0; + } return 1; } - public Entity? FindBestGasTank(Entity user) + public Entity? FindBestGasTank( + Entity user) { // Prioritise // 1. back equipped tanks @@ -234,17 +237,17 @@ private short GetSeverity(InternalsComponent component) // 3. in-hand tanks // 4. pocket/belt tanks - if (!Resolve(user.Owner, ref user.Comp1, ref user.Comp2, ref user.Comp3)) + if (!Resolve(user, ref user.Comp1, ref user.Comp2, ref user.Comp3)) return null; - if (_inventory.TryGetSlotEntity(user.Owner, "back", out var backEntity, user.Comp2, user.Comp3) && + if (_inventory.TryGetSlotEntity(user, "back", out var backEntity, user.Comp2, user.Comp3) && TryComp(backEntity, out var backGasTank) && _gasTank.CanConnectToInternals(backGasTank)) { return (backEntity.Value, backGasTank); } - if (_inventory.TryGetSlotEntity(user.Owner, "suitstorage", out var entity, user.Comp2, user.Comp3) && + if (_inventory.TryGetSlotEntity(user, "suitstorage", out var entity, user.Comp2, user.Comp3) && TryComp(entity, out var gasTank) && _gasTank.CanConnectToInternals(gasTank)) { diff --git a/Content.Server/Body/Systems/LungSystem.cs b/Content.Server/Body/Systems/LungSystem.cs index 4b60f8814b5..e83d3c32a25 100644 --- a/Content.Server/Body/Systems/LungSystem.cs +++ b/Content.Server/Body/Systems/LungSystem.cs @@ -1,4 +1,4 @@ -using Content.Server.Atmos.Components; +using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; using Content.Server.Body.Components; using Content.Server.Chemistry.Containers.EntitySystems; @@ -26,21 +26,24 @@ public override void Initialize() SubscribeLocalEvent(OnMaskToggled); } - private void OnGotUnequipped(EntityUid uid, BreathToolComponent component, GotUnequippedEvent args) + private void OnGotUnequipped(Entity ent, ref GotUnequippedEvent args) { - _atmosphereSystem.DisconnectInternals(component); + _atmosphereSystem.DisconnectInternals(ent); } - private void OnGotEquipped(EntityUid uid, BreathToolComponent component, GotEquippedEvent args) + private void OnGotEquipped(Entity ent, ref GotEquippedEvent args) { + if ((args.SlotFlags & ent.Comp.AllowedSlots) == 0) + { + return; + } - if ((args.SlotFlags & component.AllowedSlots) == 0) return; - component.IsFunctional = true; + ent.Comp.IsFunctional = true; if (TryComp(args.Equipee, out InternalsComponent? internals)) { - component.ConnectedInternalsEntity = args.Equipee; - _internals.ConnectBreathTool((args.Equipee, internals), uid); + ent.Comp.ConnectedInternalsEntity = args.Equipee; + _internals.ConnectBreathTool((args.Equipee, internals), ent); } } @@ -81,7 +84,7 @@ public void GasToReagent(EntityUid uid, LungComponent lung) if (moles <= 0) continue; var reagent = _atmosphereSystem.GasReagents[i]; - if (reagent == null) continue; + if (reagent is null) continue; var amount = moles * Atmospherics.BreathMolesToReagentMultiplier; solution.AddReagent(reagent, amount); diff --git a/Content.Server/Body/Systems/MetabolizerSystem.cs b/Content.Server/Body/Systems/MetabolizerSystem.cs index e5f604f70df..066bf0a1c5b 100644 --- a/Content.Server/Body/Systems/MetabolizerSystem.cs +++ b/Content.Server/Body/Systems/MetabolizerSystem.cs @@ -12,11 +12,13 @@ using Robust.Shared.Collections; using Robust.Shared.Prototypes; using Robust.Shared.Random; +using Robust.Shared.Timing; namespace Content.Server.Body.Systems { public sealed class MetabolizerSystem : EntitySystem { + [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; @@ -34,9 +36,21 @@ public override void Initialize() _solutionQuery = GetEntityQuery(); SubscribeLocalEvent(OnMetabolizerInit); + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnApplyMetabolicMultiplier); } + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + ent.Comp.NextUpdate = _gameTiming.CurTime + ent.Comp.UpdateInterval; + } + + private void OnUnpaused(Entity ent, ref EntityUnpausedEvent args) + { + ent.Comp.NextUpdate += args.PausedTime; + } + private void OnMetabolizerInit(Entity entity, ref ComponentInit args) { if (!entity.Comp.SolutionOnBody) @@ -49,19 +63,17 @@ private void OnMetabolizerInit(Entity entity, ref Componen } } - private void OnApplyMetabolicMultiplier(EntityUid uid, MetabolizerComponent component, - ApplyMetabolicMultiplierEvent args) + private void OnApplyMetabolicMultiplier( + Entity ent, + ref ApplyMetabolicMultiplierEvent args) { if (args.Apply) { - component.UpdateFrequency *= args.Multiplier; + ent.Comp.UpdateInterval *= args.Multiplier; return; } - component.UpdateFrequency /= args.Multiplier; - // Reset the accumulator properly - if (component.AccumulatedFrametime >= component.UpdateFrequency) - component.AccumulatedFrametime = component.UpdateFrequency; + ent.Comp.UpdateInterval /= args.Multiplier; } public override void Update(float frameTime) @@ -78,50 +90,52 @@ public override void Update(float frameTime) foreach (var (uid, metab) in metabolizers) { - metab.AccumulatedFrametime += frameTime; - // Only update as frequently as it should - if (metab.AccumulatedFrametime < metab.UpdateFrequency) + if (_gameTiming.CurTime < metab.NextUpdate) continue; - metab.AccumulatedFrametime -= metab.UpdateFrequency; - TryMetabolize(uid, metab); + metab.NextUpdate += metab.UpdateInterval; + TryMetabolize((uid, metab)); } } - private void TryMetabolize(EntityUid uid, MetabolizerComponent meta, OrganComponent? organ = null) + private void TryMetabolize(Entity ent) { - _organQuery.Resolve(uid, ref organ, false); + _organQuery.Resolve(ent, ref ent.Comp2, logMissing: false); // First step is get the solution we actually care about + var solutionName = ent.Comp1.SolutionName; Solution? solution = null; Entity? soln = default!; EntityUid? solutionEntityUid = null; - SolutionContainerManagerComponent? manager = null; - - if (meta.SolutionOnBody) + if (ent.Comp1.SolutionOnBody) { - if (organ?.Body is { } body) + if (ent.Comp2?.Body is { } body) { - if (!_solutionQuery.Resolve(body, ref manager, false)) + if (!_solutionQuery.Resolve(body, ref ent.Comp3, logMissing: false)) return; - _solutionContainerSystem.TryGetSolution((body, manager), meta.SolutionName, out soln, out solution); + _solutionContainerSystem.TryGetSolution((body, ent.Comp3), solutionName, out soln, out solution); solutionEntityUid = body; } } else { - if (!_solutionQuery.Resolve(uid, ref manager, false)) + if (!_solutionQuery.Resolve(ent, ref ent.Comp3, logMissing: false)) return; - _solutionContainerSystem.TryGetSolution((uid, manager), meta.SolutionName, out soln, out solution); - solutionEntityUid = uid; + _solutionContainerSystem.TryGetSolution((ent, ent), solutionName, out soln, out solution); + solutionEntityUid = ent; } - if (solutionEntityUid == null || soln is null || solution is null || solution.Contents.Count == 0) + if (solutionEntityUid is null + || soln is null + || solution is null + || solution.Contents.Count == 0) + { return; + } // randomize the reagent list so we don't have any weird quirks // like alphabetical order or insertion order mattering for processing @@ -135,9 +149,9 @@ private void TryMetabolize(EntityUid uid, MetabolizerComponent meta, OrganCompon continue; var mostToRemove = FixedPoint2.Zero; - if (proto.Metabolisms == null) + if (proto.Metabolisms is null) { - if (meta.RemoveEmpty) + if (ent.Comp1.RemoveEmpty) { solution.RemoveReagent(reagent, FixedPoint2.New(1)); } @@ -146,15 +160,15 @@ private void TryMetabolize(EntityUid uid, MetabolizerComponent meta, OrganCompon } // we're done here entirely if this is true - if (reagents >= meta.MaxReagentsProcessable) + if (reagents >= ent.Comp1.MaxReagentsProcessable) return; // loop over all our groups and see which ones apply - if (meta.MetabolismGroups == null) + if (ent.Comp1.MetabolismGroups is null) continue; - foreach (var group in meta.MetabolismGroups) + foreach (var group in ent.Comp1.MetabolismGroups) { if (!proto.Metabolisms.TryGetValue(group.Id, out var entry)) continue; @@ -169,15 +183,18 @@ private void TryMetabolize(EntityUid uid, MetabolizerComponent meta, OrganCompon // if it's possible for them to be dead, and they are, // then we shouldn't process any effects, but should probably // still remove reagents - if (EntityManager.TryGetComponent(solutionEntityUid.Value, out var state)) + if (TryComp(solutionEntityUid.Value, out var state)) { if (!proto.WorksOnTheDead && _mobStateSystem.IsDead(solutionEntityUid.Value, state)) continue; } - var actualEntity = organ?.Body ?? solutionEntityUid.Value; - var args = new ReagentEffectArgs(actualEntity, uid, solution, proto, mostToRemove, - EntityManager, null, scale); + var actualEntity = ent.Comp2?.Body ?? solutionEntityUid.Value; + var ev = new TryMetabolizeReagent(reagent, proto, quantity); + RaiseLocalEvent(actualEntity, ref ev); + + var args = new ReagentEffectArgs(actualEntity, ent, solution, proto, mostToRemove, + EntityManager, null, scale * ev.Scale, ev.QuantityMultiplier); // do all effects, if conditions apply foreach (var effect in entry.Effects) @@ -187,8 +204,14 @@ private void TryMetabolize(EntityUid uid, MetabolizerComponent meta, OrganCompon if (effect.ShouldLog) { - _adminLogger.Add(LogType.ReagentEffect, effect.LogImpact, - $"Metabolism effect {effect.GetType().Name:effect} of reagent {proto.LocalizedName:reagent} applied on entity {actualEntity:entity} at {Transform(actualEntity).Coordinates:coordinates}"); + _adminLogger.Add( + LogType.ReagentEffect, + effect.LogImpact, + $"Metabolism effect {effect.GetType().Name:effect}" + + $" of reagent {proto.LocalizedName:reagent}" + + $" applied on entity {actualEntity:entity}" + + $" at {Transform(actualEntity).Coordinates:coordinates}" + ); } effect.Effect(args); @@ -209,15 +232,28 @@ private void TryMetabolize(EntityUid uid, MetabolizerComponent meta, OrganCompon } } - public sealed class ApplyMetabolicMultiplierEvent : EntityEventArgs + [ByRefEvent] + public readonly record struct ApplyMetabolicMultiplierEvent( + EntityUid Uid, + float Multiplier, + bool Apply) { - // The entity whose metabolism is being modified - public EntityUid Uid; - - // What the metabolism's update rate will be multiplied by - public float Multiplier; - - // Apply this multiplier or ignore / reset it? - public bool Apply; + /// + /// The entity whose metabolism is being modified. + /// + public readonly EntityUid Uid = Uid; + + /// + /// What the metabolism's update rate will be multiplied by. + /// + public readonly float Multiplier = Multiplier; + + /// + /// If true, apply the multiplier. If false, revert it. + /// + public readonly bool Apply = Apply; } } + +[ByRefEvent] +public record struct TryMetabolizeReagent(ReagentId Reagent, ReagentPrototype Prototype, FixedPoint2 Quantity, float Scale = 1f, float QuantityMultiplier = 1f); diff --git a/Content.Server/Body/Systems/RespiratorSystem.cs b/Content.Server/Body/Systems/RespiratorSystem.cs index 0fd61a9cb7b..c7266e2c463 100644 --- a/Content.Server/Body/Systems/RespiratorSystem.cs +++ b/Content.Server/Body/Systems/RespiratorSystem.cs @@ -35,9 +35,21 @@ public override void Initialize() // We want to process lung reagents before we inhale new reagents. UpdatesAfter.Add(typeof(MetabolizerSystem)); + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnApplyMetabolicMultiplier); } + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + ent.Comp.NextUpdate = _gameTiming.CurTime + ent.Comp.UpdateInterval; + } + + private void OnUnpaused(Entity ent, ref EntityUnpausedEvent args) + { + ent.Comp.NextUpdate += args.PausedTime; + } + public override void Update(float frameTime) { base.Update(frameTime); @@ -45,17 +57,15 @@ public override void Update(float frameTime) var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var respirator, out var body)) { - if (_mobState.IsDead(uid)) - { + if (_gameTiming.CurTime < respirator.NextUpdate) continue; - } - respirator.AccumulatedFrametime += frameTime; + respirator.NextUpdate += respirator.UpdateInterval; - if (respirator.AccumulatedFrametime < respirator.CycleDelay) + if (_mobState.IsDead(uid)) continue; - respirator.AccumulatedFrametime -= respirator.CycleDelay; - UpdateSaturation(uid, -respirator.CycleDelay, respirator); + + UpdateSaturation(uid, -(float) respirator.UpdateInterval.TotalSeconds, respirator); if (!_mobState.IsIncapacitated(uid)) // cannot breathe in crit. { @@ -80,30 +90,30 @@ public override void Update(float frameTime) _popupSystem.PopupEntity(Loc.GetString("lung-behavior-gasp"), uid); } - TakeSuffocationDamage(uid, respirator); + TakeSuffocationDamage((uid, respirator)); respirator.SuffocationCycles += 1; continue; } - StopSuffocation(uid, respirator); + StopSuffocation((uid, respirator)); respirator.SuffocationCycles = 0; } } public void Inhale(EntityUid uid, BodyComponent? body = null) { - if (!Resolve(uid, ref body, false)) + if (!Resolve(uid, ref body, logMissing: false)) return; var organs = _bodySystem.GetBodyOrganComponents(uid, body); // Inhale gas var ev = new InhaleLocationEvent(); - RaiseLocalEvent(uid, ev); + RaiseLocalEvent(uid, ref ev, broadcast: false); - ev.Gas ??= _atmosSys.GetContainingMixture(uid, false, true); + ev.Gas ??= _atmosSys.GetContainingMixture(uid, excite: true); - if (ev.Gas == null) + if (ev.Gas is null) { return; } @@ -122,7 +132,7 @@ public void Inhale(EntityUid uid, BodyComponent? body = null) public void Exhale(EntityUid uid, BodyComponent? body = null) { - if (!Resolve(uid, ref body, false)) + if (!Resolve(uid, ref body, logMissing: false)) return; var organs = _bodySystem.GetBodyOrganComponents(uid, body); @@ -130,11 +140,11 @@ public void Exhale(EntityUid uid, BodyComponent? body = null) // exhale gas var ev = new ExhaleLocationEvent(); - RaiseLocalEvent(uid, ev, false); + RaiseLocalEvent(uid, ref ev, broadcast: false); - if (ev.Gas == null) + if (ev.Gas is null) { - ev.Gas = _atmosSys.GetContainingMixture(uid, false, 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. @@ -154,37 +164,37 @@ public void Exhale(EntityUid uid, BodyComponent? body = null) _atmosSys.Merge(ev.Gas, outGas); } - private void TakeSuffocationDamage(EntityUid uid, RespiratorComponent respirator) + private void TakeSuffocationDamage(Entity ent) { - if (respirator.SuffocationCycles == 2) - _adminLogger.Add(LogType.Asphyxiation, $"{ToPrettyString(uid):entity} started suffocating"); + if (ent.Comp.SuffocationCycles == 2) + _adminLogger.Add(LogType.Asphyxiation, $"{ToPrettyString(ent):entity} started suffocating"); - if (respirator.SuffocationCycles >= respirator.SuffocationCycleThreshold) + if (ent.Comp.SuffocationCycles >= ent.Comp.SuffocationCycleThreshold) { // TODO: This is not going work with multiple different lungs, if that ever becomes a possibility - var organs = _bodySystem.GetBodyOrganComponents(uid); + var organs = _bodySystem.GetBodyOrganComponents(ent); foreach (var (comp, _) in organs) { - _alertsSystem.ShowAlert(uid, comp.Alert); + _alertsSystem.ShowAlert(ent, comp.Alert); } } - _damageableSys.TryChangeDamage(uid, respirator.Damage, false, false); + _damageableSys.TryChangeDamage(ent, ent.Comp.Damage, interruptsDoAfters: false); } - private void StopSuffocation(EntityUid uid, RespiratorComponent respirator) + private void StopSuffocation(Entity ent) { - if (respirator.SuffocationCycles >= 2) - _adminLogger.Add(LogType.Asphyxiation, $"{ToPrettyString(uid):entity} stopped suffocating"); + if (ent.Comp.SuffocationCycles >= 2) + _adminLogger.Add(LogType.Asphyxiation, $"{ToPrettyString(ent):entity} stopped suffocating"); // TODO: This is not going work with multiple different lungs, if that ever becomes a possibility - var organs = _bodySystem.GetBodyOrganComponents(uid); + var organs = _bodySystem.GetBodyOrganComponents(ent); foreach (var (comp, _) in organs) { - _alertsSystem.ClearAlert(uid, comp.Alert); + _alertsSystem.ClearAlert(ent, comp.Alert); } - _damageableSys.TryChangeDamage(uid, respirator.DamageRecovery); + _damageableSys.TryChangeDamage(ent, ent.Comp.DamageRecovery); } public void UpdateSaturation(EntityUid uid, float amount, @@ -198,35 +208,29 @@ public void UpdateSaturation(EntityUid uid, float amount, Math.Clamp(respirator.Saturation, respirator.MinSaturation, respirator.MaxSaturation); } - private void OnApplyMetabolicMultiplier(EntityUid uid, RespiratorComponent component, - ApplyMetabolicMultiplierEvent args) + private void OnApplyMetabolicMultiplier( + Entity ent, + ref ApplyMetabolicMultiplierEvent args) { if (args.Apply) { - component.CycleDelay *= args.Multiplier; - component.Saturation *= args.Multiplier; - component.MaxSaturation *= args.Multiplier; - component.MinSaturation *= args.Multiplier; + ent.Comp.UpdateInterval *= args.Multiplier; + ent.Comp.Saturation *= args.Multiplier; + ent.Comp.MaxSaturation *= args.Multiplier; + ent.Comp.MinSaturation *= args.Multiplier; return; } // This way we don't have to worry about it breaking if the stasis bed component is destroyed - component.CycleDelay /= args.Multiplier; - component.Saturation /= args.Multiplier; - component.MaxSaturation /= args.Multiplier; - component.MinSaturation /= args.Multiplier; - // Reset the accumulator properly - if (component.AccumulatedFrametime >= component.CycleDelay) - component.AccumulatedFrametime = component.CycleDelay; + ent.Comp.UpdateInterval /= args.Multiplier; + ent.Comp.Saturation /= args.Multiplier; + ent.Comp.MaxSaturation /= args.Multiplier; + ent.Comp.MinSaturation /= args.Multiplier; } } -public sealed class InhaleLocationEvent : EntityEventArgs -{ - public GasMixture? Gas; -} +[ByRefEvent] +public record struct InhaleLocationEvent(GasMixture? Gas); -public sealed class ExhaleLocationEvent : EntityEventArgs -{ - public GasMixture? Gas; -} +[ByRefEvent] +public record struct ExhaleLocationEvent(GasMixture? Gas); diff --git a/Content.Server/Body/Systems/StomachSystem.cs b/Content.Server/Body/Systems/StomachSystem.cs index 4c11244c379..a4c2e8292dd 100644 --- a/Content.Server/Body/Systems/StomachSystem.cs +++ b/Content.Server/Body/Systems/StomachSystem.cs @@ -3,32 +3,44 @@ using Content.Shared.Body.Organ; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; +using Robust.Shared.Timing; using Robust.Shared.Utility; namespace Content.Server.Body.Systems { public sealed class StomachSystem : EntitySystem { + [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; public const string DefaultSolutionName = "stomach"; public override void Initialize() { + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnApplyMetabolicMultiplier); } + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + ent.Comp.NextUpdate = _gameTiming.CurTime + ent.Comp.UpdateInterval; + } + + private void OnUnpaused(Entity ent, ref EntityUnpausedEvent args) + { + ent.Comp.NextUpdate += args.PausedTime; + } + public override void Update(float frameTime) { var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var stomach, out var organ, out var sol)) { - stomach.AccumulatedFrameTime += frameTime; - - if (stomach.AccumulatedFrameTime < stomach.UpdateInterval) + if (_gameTiming.CurTime < stomach.NextUpdate) continue; - stomach.AccumulatedFrameTime -= stomach.UpdateInterval; + stomach.NextUpdate += stomach.UpdateInterval; // Get our solutions if (!_solutionContainerSystem.ResolveSolution((uid, sol), DefaultSolutionName, ref stomach.Solution, out var stomachSolution)) @@ -70,49 +82,44 @@ public override void Update(float frameTime) } } - private void OnApplyMetabolicMultiplier(EntityUid uid, StomachComponent component, - ApplyMetabolicMultiplierEvent args) + private void OnApplyMetabolicMultiplier( + Entity ent, + ref ApplyMetabolicMultiplierEvent args) { if (args.Apply) { - component.UpdateInterval *= args.Multiplier; + ent.Comp.UpdateInterval *= args.Multiplier; return; } // This way we don't have to worry about it breaking if the stasis bed component is destroyed - component.UpdateInterval /= args.Multiplier; - // Reset the accumulator properly - if (component.AccumulatedFrameTime >= component.UpdateInterval) - component.AccumulatedFrameTime = component.UpdateInterval; + ent.Comp.UpdateInterval /= args.Multiplier; } - public bool CanTransferSolution(EntityUid uid, Solution solution, + public bool CanTransferSolution( + EntityUid uid, + Solution solution, StomachComponent? stomach = null, SolutionContainerManagerComponent? solutions = null) { - if (!Resolve(uid, ref stomach, ref solutions, false)) - return false; - - if (!_solutionContainerSystem.ResolveSolution((uid, solutions), DefaultSolutionName, ref stomach.Solution, out var stomachSolution)) - return false; - - // TODO: For now no partial transfers. Potentially change by design - if (!stomachSolution.CanAddSolution(solution)) - return false; - - return true; + return Resolve(uid, ref stomach, ref solutions, logMissing: false) + && _solutionContainerSystem.ResolveSolution((uid, solutions), DefaultSolutionName, ref stomach.Solution, out var stomachSolution) + // TODO: For now no partial transfers. Potentially change by design + && stomachSolution.CanAddSolution(solution); } - public bool TryTransferSolution(EntityUid uid, Solution solution, + public bool TryTransferSolution( + EntityUid uid, + Solution solution, StomachComponent? stomach = null, SolutionContainerManagerComponent? solutions = null) { - if (!Resolve(uid, ref stomach, ref solutions, false)) - return false; - - if (!_solutionContainerSystem.ResolveSolution((uid, solutions), DefaultSolutionName, ref stomach.Solution) + if (!Resolve(uid, ref stomach, ref solutions, logMissing: false) + || !_solutionContainerSystem.ResolveSolution((uid, solutions), DefaultSolutionName, ref stomach.Solution) || !CanTransferSolution(uid, solution, stomach, solutions)) + { return false; + } _solutionContainerSystem.TryAddSolution(stomach.Solution.Value, solution); // Add each reagent to ReagentDeltas. Used to track how long each reagent has been in the stomach diff --git a/Content.Server/Body/Systems/ThermalRegulatorSystem.cs b/Content.Server/Body/Systems/ThermalRegulatorSystem.cs index a9556be7738..a8bf4184ac8 100644 --- a/Content.Server/Body/Systems/ThermalRegulatorSystem.cs +++ b/Content.Server/Body/Systems/ThermalRegulatorSystem.cs @@ -1,73 +1,95 @@ -using Content.Server.Body.Components; +using Content.Server.Body.Components; using Content.Server.Temperature.Components; using Content.Server.Temperature.Systems; using Content.Shared.ActionBlocker; +using Robust.Shared.Timing; namespace Content.Server.Body.Systems; public sealed class ThermalRegulatorSystem : EntitySystem { + [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly TemperatureSystem _tempSys = default!; [Dependency] private readonly ActionBlockerSystem _actionBlockerSys = default!; + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnUnpaused); + } + + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + ent.Comp.NextUpdate = _gameTiming.CurTime + ent.Comp.UpdateInterval; + } + + private void OnUnpaused(Entity ent, ref EntityUnpausedEvent args) + { + ent.Comp.NextUpdate += args.PausedTime; + } + public override void Update(float frameTime) { var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var regulator)) { - regulator.AccumulatedFrametime += frameTime; - if (regulator.AccumulatedFrametime < 1) + if (_gameTiming.CurTime < regulator.NextUpdate) continue; - regulator.AccumulatedFrametime -= 1; - ProcessThermalRegulation(uid, regulator); + regulator.NextUpdate += regulator.UpdateInterval; + ProcessThermalRegulation((uid, regulator)); } } /// /// Processes thermal regulation for a mob /// - private void ProcessThermalRegulation(EntityUid uid, ThermalRegulatorComponent comp) + private void ProcessThermalRegulation(Entity ent) { - if (!EntityManager.TryGetComponent(uid, out TemperatureComponent? temperatureComponent)) return; + if (!Resolve(ent, ref ent.Comp2, logMissing: false)) + return; - var totalMetabolismTempChange = comp.MetabolismHeat - comp.RadiatedHeat; + var totalMetabolismTempChange = ent.Comp1.MetabolismHeat - ent.Comp1.RadiatedHeat; // implicit heat regulation - var tempDiff = Math.Abs(temperatureComponent.CurrentTemperature - comp.NormalBodyTemperature); - var heatCapacity = _tempSys.GetHeatCapacity(uid, temperatureComponent); + var tempDiff = Math.Abs(ent.Comp2.CurrentTemperature - ent.Comp1.NormalBodyTemperature); + var heatCapacity = _tempSys.GetHeatCapacity(ent, ent); var targetHeat = tempDiff * heatCapacity; - if (temperatureComponent.CurrentTemperature > comp.NormalBodyTemperature) + if (ent.Comp2.CurrentTemperature > ent.Comp1.NormalBodyTemperature) { - totalMetabolismTempChange -= Math.Min(targetHeat, comp.ImplicitHeatRegulation); + totalMetabolismTempChange -= Math.Min(targetHeat, ent.Comp1.ImplicitHeatRegulation); } else { - totalMetabolismTempChange += Math.Min(targetHeat, comp.ImplicitHeatRegulation); + totalMetabolismTempChange += Math.Min(targetHeat, ent.Comp1.ImplicitHeatRegulation); } - _tempSys.ChangeHeat(uid, totalMetabolismTempChange, true, temperatureComponent); + _tempSys.ChangeHeat(ent, totalMetabolismTempChange, ignoreHeatResistance: true, ent); // recalc difference and target heat - tempDiff = Math.Abs(temperatureComponent.CurrentTemperature - comp.NormalBodyTemperature); + tempDiff = Math.Abs(ent.Comp2.CurrentTemperature - ent.Comp1.NormalBodyTemperature); targetHeat = tempDiff * heatCapacity; // if body temperature is not within comfortable, thermal regulation // processes starts - if (tempDiff > comp.ThermalRegulationTemperatureThreshold) + if (tempDiff > ent.Comp1.ThermalRegulationTemperatureThreshold) return; - if (temperatureComponent.CurrentTemperature > comp.NormalBodyTemperature) + if (ent.Comp2.CurrentTemperature > ent.Comp1.NormalBodyTemperature) { - if (!_actionBlockerSys.CanSweat(uid)) return; - _tempSys.ChangeHeat(uid, -Math.Min(targetHeat, comp.SweatHeatRegulation), true, - temperatureComponent); + if (!_actionBlockerSys.CanSweat(ent)) + return; + + _tempSys.ChangeHeat(ent, -Math.Min(targetHeat, ent.Comp1.SweatHeatRegulation), ignoreHeatResistance: true, ent); } else { - if (!_actionBlockerSys.CanShiver(uid)) return; - _tempSys.ChangeHeat(uid, Math.Min(targetHeat, comp.ShiveringHeatRegulation), true, - temperatureComponent); + if (!_actionBlockerSys.CanShiver(ent)) + return; + + _tempSys.ChangeHeat(ent, Math.Min(targetHeat, ent.Comp1.ShiveringHeatRegulation), ignoreHeatResistance: true, ent); } } } diff --git a/Content.Server/Cargo/Components/StationCargoBountyDatabaseComponent.cs b/Content.Server/Cargo/Components/StationCargoBountyDatabaseComponent.cs index 48c58321b38..d26794a6323 100644 --- a/Content.Server/Cargo/Components/StationCargoBountyDatabaseComponent.cs +++ b/Content.Server/Cargo/Components/StationCargoBountyDatabaseComponent.cs @@ -12,7 +12,7 @@ public sealed partial class StationCargoBountyDatabaseComponent : Component /// Maximum amount of bounties a station can have. /// [DataField, ViewVariables(VVAccess.ReadWrite)] - public int MaxBounties = 5; + public int MaxBounties = 6; /// /// A list of all the bounties currently active for a station. diff --git a/Content.Server/Cargo/Systems/CargoSystem.cs b/Content.Server/Cargo/Systems/CargoSystem.cs index 2609d06b55d..3d6fc964725 100644 --- a/Content.Server/Cargo/Systems/CargoSystem.cs +++ b/Content.Server/Cargo/Systems/CargoSystem.cs @@ -39,7 +39,6 @@ public sealed partial class CargoSystem : SharedCargoSystem [Dependency] private readonly PricingSystem _pricing = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly SharedTransformSystem _xformSystem = default!; [Dependency] private readonly ShuttleConsoleSystem _console = default!; [Dependency] private readonly StackSystem _stack = default!; [Dependency] private readonly StationSystem _station = default!; diff --git a/Content.Server/Cargo/Systems/PricingSystem.cs b/Content.Server/Cargo/Systems/PricingSystem.cs index 6fb36c96083..9e1970d63c9 100644 --- a/Content.Server/Cargo/Systems/PricingSystem.cs +++ b/Content.Server/Cargo/Systems/PricingSystem.cs @@ -12,7 +12,6 @@ using Content.Shared.Stacks; using Robust.Shared.Console; using Robust.Shared.Containers; -using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Prototypes; using Robust.Shared.Utility; @@ -27,7 +26,6 @@ public sealed class PricingSystem : EntitySystem { [Dependency] private readonly IComponentFactory _factory = default!; [Dependency] private readonly IConsoleHost _consoleHost = default!; - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly BodySystem _bodySystem = default!; [Dependency] private readonly MobStateSystem _mobStateSystem = default!; diff --git a/Content.Server/Chat/Managers/ChatManager.cs b/Content.Server/Chat/Managers/ChatManager.cs index 6d54bedf86c..d12bbfe53c9 100644 --- a/Content.Server/Chat/Managers/ChatManager.cs +++ b/Content.Server/Chat/Managers/ChatManager.cs @@ -125,9 +125,23 @@ public void DispatchServerMessage(ICommonSession player, string message, bool su _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Server message to {player:Player}: {message}"); } - public void SendAdminAnnouncement(string message) + public void SendAdminAnnouncement(string message, AdminFlags? flagBlacklist, AdminFlags? flagWhitelist) { - var clients = _adminManager.ActiveAdmins.Select(p => p.Channel); + var clients = _adminManager.ActiveAdmins.Where(p => + { + var adminData = _adminManager.GetAdminData(p); + + DebugTools.AssertNotNull(adminData); + + if (adminData == null) + return false; + + if (flagBlacklist != null && adminData.HasFlag(flagBlacklist.Value)) + return false; + + return flagWhitelist == null || adminData.HasFlag(flagWhitelist.Value); + + }).Select(p => p.Channel); var wrappedMessage = Loc.GetString("chat-manager-send-admin-announcement-wrap-message", ("adminChannelName", Loc.GetString("chat-manager-admin-channel-name")), ("message", FormattedMessage.EscapeText(message))); diff --git a/Content.Server/Chat/Managers/IChatManager.cs b/Content.Server/Chat/Managers/IChatManager.cs index e5fa8d5f4dc..59945bf5ca6 100644 --- a/Content.Server/Chat/Managers/IChatManager.cs +++ b/Content.Server/Chat/Managers/IChatManager.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; +using Content.Shared.Administration; using Content.Shared.Chat; using Robust.Shared.Network; using Robust.Shared.Player; @@ -21,7 +22,7 @@ public interface IChatManager void TrySendOOCMessage(ICommonSession player, string message, OOCChatType type); void SendHookOOC(string sender, string message); - void SendAdminAnnouncement(string message); + void SendAdminAnnouncement(string message, AdminFlags? flagBlacklist = null, AdminFlags? flagWhitelist = null); void SendAdminAlert(string message); void SendAdminAlert(EntityUid player, string message); diff --git a/Content.Server/Chat/Systems/AnnounceOnSpawnSystem.cs b/Content.Server/Chat/Systems/AnnounceOnSpawnSystem.cs index 0f0365e56ba..11dcf42dfd7 100644 --- a/Content.Server/Chat/Systems/AnnounceOnSpawnSystem.cs +++ b/Content.Server/Chat/Systems/AnnounceOnSpawnSystem.cs @@ -1,10 +1,13 @@ using Content.Server.Chat; +using Content.Server.Announcements.Systems; +using Robust.Shared.Player; namespace Content.Server.Chat.Systems; public sealed class AnnounceOnSpawnSystem : EntitySystem { [Dependency] private readonly ChatSystem _chat = default!; + [Dependency] private readonly AnnouncerSystem _announcer = default!; public override void Initialize() { @@ -15,8 +18,8 @@ public override void Initialize() private void OnInit(EntityUid uid, AnnounceOnSpawnComponent comp, MapInitEvent args) { - var message = Loc.GetString(comp.Message); var sender = comp.Sender != null ? Loc.GetString(comp.Sender) : "Central Command"; - _chat.DispatchGlobalAnnouncement(message, sender, playSound: true, comp.Sound, comp.Color); + _announcer.SendAnnouncement(_announcer.GetAnnouncementId("SpawnAnnounceCaptain"), Filter.Broadcast(), + comp.Message, sender, comp.Color); } } diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs index cd48b6de716..d2ed6e04346 100644 --- a/Content.Server/Chat/Systems/ChatSystem.cs +++ b/Content.Server/Chat/Systems/ChatSystem.cs @@ -241,6 +241,17 @@ public void TrySendInGameICMessage( if (string.IsNullOrEmpty(message)) return; + // Check if the message is in sign language + if (desiredType == InGameICChatType.Speak || desiredType == InGameICChatType.Whisper) + { + var language = languageOverride ?? _language.GetLanguage(source); + if (language.SignLanguage ?? false) + { + SendEntityEmote(source, message, range, nameOverride, ignoreActionBlocker, signLanguage: true, languageOverride: languageOverride); + return; + } + } + // This message may have a radio prefix, and should then be whispered to the resolved radio channel if (checkRadioPrefix) { @@ -576,7 +587,9 @@ private void SendEntityEmote( bool hideLog = false, bool checkEmote = true, bool ignoreActionBlocker = false, - NetUserId? author = null + NetUserId? author = null, + LanguagePrototype? languageOverride = null, + bool? signLanguage = false ) { if (!_actionBlocker.CanEmote(source) && !ignoreActionBlocker) @@ -586,15 +599,32 @@ private void SendEntityEmote( var ent = Identity.Entity(source, EntityManager); string name = FormattedMessage.EscapeText(nameOverride ?? Name(ent)); + var language = languageOverride ?? _language.GetLanguage(source); + // Emotes use Identity.Name, since it doesn't actually involve your voice at all. - var wrappedMessage = Loc.GetString("chat-manager-entity-me-wrap-message", - ("entityName", name), - ("entity", ent), - ("message", FormattedMessage.RemoveMarkup(action))); + var wrappedMessage = ""; + var obfuscatedWrappedMessage = ""; + if (signLanguage == true) + { + wrappedMessage = Loc.GetString("entity-signlanguage-message", + ("entityName", name), + ("message", FormattedMessage.EscapeText(action))); + + obfuscatedWrappedMessage = Loc.GetString(_language.ObfuscateSpeech(action, language), + ("entityName", name)); + } + else + { + wrappedMessage = Loc.GetString("chat-manager-entity-me-wrap-message", + ("entityName", name), + ("entity", ent), + ("message", FormattedMessage.RemoveMarkup(action))); + + } if (checkEmote) TryEmoteChatInput(source, action); - SendInVoiceRange(ChatChannel.Emotes, name, action, wrappedMessage, obfuscated: "", obfuscatedWrappedMessage: "", source, range, author); + SendInVoiceRange(ChatChannel.Emotes, name, action, wrappedMessage, obfuscated: "", obfuscatedWrappedMessage, source, range, author, signLanguage: true); if (!hideLog) if (name != Name(source)) _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Emote from {ToPrettyString(source):user} as {name}: {action}"); @@ -749,7 +779,7 @@ private MessageRangeCheckResult MessageRangeCheck(ICommonSession session, ICChat /// /// Sends a chat message to the given players in range of the source entity. /// - private void SendInVoiceRange(ChatChannel channel, string name, string message, string wrappedMessage, string obfuscated, string obfuscatedWrappedMessage, EntityUid source, ChatTransmitRange range, NetUserId? author = null, LanguagePrototype? languageOverride = null) + private void SendInVoiceRange(ChatChannel channel, string name, string message, string wrappedMessage, string obfuscated, string obfuscatedWrappedMessage, EntityUid source, ChatTransmitRange range, NetUserId? author = null, LanguagePrototype? languageOverride = null, bool? signLanguage = false) { var language = languageOverride ?? _language.GetLanguage(source); foreach (var (session, data) in GetRecipients(source, VoiceRange)) @@ -762,9 +792,17 @@ private void SendInVoiceRange(ChatChannel channel, string name, string message, continue; EntityUid listener = session.AttachedEntity.Value; + // Quickly Checking if the Emote is a real one or Sign Language. + var notSignLanguage = false; + if (channel == ChatChannel.Emotes) + { + notSignLanguage = true; + if (signLanguage == true) + notSignLanguage = false; + } // If the channel does not support languages, or the entity can understand the message, send the original message, otherwise send the obfuscated version - if (channel == ChatChannel.LOOC || channel == ChatChannel.Emotes || _language.CanUnderstand(listener, language.ID)) + if (channel == ChatChannel.LOOC || notSignLanguage || _language.CanUnderstand(listener, language.ID)) { _chatManager.ChatMessageToOne(channel, message, wrappedMessage, source, entHideChat, session.Channel, author: author); } diff --git a/Content.Server/Chemistry/Containers/EntitySystems/SolutionContainerSystem.cs b/Content.Server/Chemistry/Containers/EntitySystems/SolutionContainerSystem.cs index 7926121c2b3..468212f5eaf 100644 --- a/Content.Server/Chemistry/Containers/EntitySystems/SolutionContainerSystem.cs +++ b/Content.Server/Chemistry/Containers/EntitySystems/SolutionContainerSystem.cs @@ -4,7 +4,6 @@ using Content.Shared.FixedPoint; using Robust.Shared.Containers; using Robust.Shared.Map; -using Robust.Shared.Network; using Robust.Shared.Utility; using System.Numerics; @@ -12,8 +11,6 @@ namespace Content.Server.Chemistry.Containers.EntitySystems; public sealed partial class SolutionContainerSystem : SharedSolutionContainerSystem { - [Dependency] private readonly INetManager _netManager = default!; - public override void Initialize() { base.Initialize(); diff --git a/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs b/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs index b93498fe31b..a8583e6bcb3 100644 --- a/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs @@ -1,4 +1,3 @@ -using Content.Server.Administration.Logs; using Content.Server.Chemistry.Components; using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Nutrition.EntitySystems; @@ -30,7 +29,6 @@ public sealed class ReagentDispenserSystem : EntitySystem [Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!; [Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly OpenableSystem _openable = default!; public override void Initialize() diff --git a/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs b/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs index 664569d7be4..50be89581fb 100644 --- a/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs +++ b/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs @@ -31,7 +31,7 @@ public override bool Condition(ReagentEffectArgs args) var quant = FixedPoint2.Zero; if (args.Source != null) - quant = args.Source.GetTotalPrototypeQuantity(reagent); + quant = args.Source.GetTotalPrototypeQuantity(reagent) * args.QuantityMultiplier; return quant >= Min && quant <= Max; } diff --git a/Content.Server/Chemistry/ReagentEffects/Drunk.cs b/Content.Server/Chemistry/ReagentEffects/Drunk.cs index dbce995ca2e..6088db5787c 100644 --- a/Content.Server/Chemistry/ReagentEffects/Drunk.cs +++ b/Content.Server/Chemistry/ReagentEffects/Drunk.cs @@ -25,7 +25,7 @@ public override void Effect(ReagentEffectArgs args) { var boozePower = BoozePower; - boozePower *= args.Scale; + boozePower *= Math.Max(args.Scale, 1); var drunkSys = args.EntityManager.EntitySysManager.GetEntitySystem(); drunkSys.TryApplyDrunkenness(args.SolutionEntity, boozePower, SlurSpeech); diff --git a/Content.Server/Communications/CommsHackerSystem.cs b/Content.Server/Communications/CommsHackerSystem.cs index 1248d214003..bbe64a7987a 100644 --- a/Content.Server/Communications/CommsHackerSystem.cs +++ b/Content.Server/Communications/CommsHackerSystem.cs @@ -9,6 +9,8 @@ using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Serialization; +using Content.Server.Announcements.Systems; +using Robust.Shared.Player; namespace Content.Server.Communications; @@ -21,6 +23,7 @@ public sealed class CommsHackerSystem : SharedCommsHackerSystem // TODO: remove when generic check event is used [Dependency] private readonly NinjaGlovesSystem _gloves = default!; [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; + [Dependency] private readonly AnnouncerSystem _announcer = default!; public override void Initialize() { @@ -79,7 +82,8 @@ private void OnDoAfter(EntityUid uid, CommsHackerComponent comp, TerrorDoAfterEv public void CallInThreat(NinjaHackingThreatPrototype ninjaHackingThreat) { _gameTicker.StartGameRule(ninjaHackingThreat.Rule, out _); - _chat.DispatchGlobalAnnouncement(Loc.GetString(ninjaHackingThreat.Announcement), playSound: true, colorOverride: Color.Red); + _announcer.SendAnnouncement(_announcer.GetAnnouncementId("NinjaHacking"), Filter.Broadcast(), + ninjaHackingThreat.Announcement, colorOverride: Color.Red); } } diff --git a/Content.Server/Communications/CommunicationsConsoleSystem.cs b/Content.Server/Communications/CommunicationsConsoleSystem.cs index 6b745c8cd95..17573c3da64 100644 --- a/Content.Server/Communications/CommunicationsConsoleSystem.cs +++ b/Content.Server/Communications/CommunicationsConsoleSystem.cs @@ -24,6 +24,9 @@ using Content.Shared.Popups; using Robust.Server.GameObjects; using Robust.Shared.Configuration; +using Content.Server.Announcements.Systems; +using Robust.Shared.Player; +using Content.Server.Station.Components; namespace Content.Server.Communications { @@ -42,6 +45,7 @@ public sealed class CommunicationsConsoleSystem : EntitySystem [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly IAdminLogManager _adminLogger = default!; + [Dependency] private readonly AnnouncerSystem _announcer = default!; private const float UIUpdateInterval = 5.0f; @@ -276,17 +280,19 @@ private void OnAnnounceMessage(EntityUid uid, CommunicationsConsoleComponent com Loc.TryGetString(comp.Title, out var title); title ??= comp.Title; - msg += "\n" + Loc.GetString("comms-console-announcement-sent-by") + " " + author; + msg += $"\n{Loc.GetString("comms-console-announcement-sent-by")} {author}"; if (comp.Global) { - _chatSystem.DispatchGlobalAnnouncement(msg, title, announcementSound: comp.Sound, colorOverride: comp.Color); + _announcer.SendAnnouncement("announce", Filter.Broadcast(), msg, title, comp.Color); if (message.Session.AttachedEntity != null) _adminLogger.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(message.Session.AttachedEntity.Value):player} has sent the following global announcement: {msg}"); return; } - _chatSystem.DispatchStationAnnouncement(uid, msg, title, colorOverride: comp.Color); + if (TryComp(_stationSystem.GetOwningStation(uid), out var stationData)) + _announcer.SendAnnouncement("announce", _stationSystem.GetInStation(stationData), msg, title, + comp.Color); if (message.Session.AttachedEntity != null) _adminLogger.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(message.Session.AttachedEntity.Value):player} has sent the following station announcement: {msg}"); diff --git a/Content.Server/Decals/Commands/EditDecalCommand.cs b/Content.Server/Decals/Commands/EditDecalCommand.cs index baaef1f3f64..2ae814113f0 100644 --- a/Content.Server/Decals/Commands/EditDecalCommand.cs +++ b/Content.Server/Decals/Commands/EditDecalCommand.cs @@ -3,6 +3,7 @@ using Content.Shared.Administration; using Robust.Shared.Console; using Robust.Shared.Map; +using Robust.Shared.Map.Components; namespace Content.Server.Decals; @@ -10,7 +11,6 @@ namespace Content.Server.Decals; public sealed class EditDecalCommand : IConsoleCommand { [Dependency] private readonly IEntityManager _entManager = default!; - [Dependency] private readonly IMapManager _mapManager = default!; public string Command => "editdecal"; public string Description => "Edits a decal."; @@ -43,7 +43,7 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) return; } - if (!_mapManager.GridExists(gridId)) + if (!_entManager.HasComponent(gridId)) { shell.WriteError($"No grid with gridId {gridId} exists."); return; diff --git a/Content.Server/Decals/Commands/RemoveDecalCommand.cs b/Content.Server/Decals/Commands/RemoveDecalCommand.cs index 771c66fbbd5..6b6a91c9d33 100644 --- a/Content.Server/Decals/Commands/RemoveDecalCommand.cs +++ b/Content.Server/Decals/Commands/RemoveDecalCommand.cs @@ -2,6 +2,7 @@ using Content.Shared.Administration; using Robust.Shared.Console; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using SQLitePCL; namespace Content.Server.Decals.Commands @@ -10,7 +11,6 @@ namespace Content.Server.Decals.Commands public sealed class RemoveDecalCommand : IConsoleCommand { [Dependency] private readonly IEntityManager _entManager = default!; - [Dependency] private readonly IMapManager _mapManager = default!; public string Command => "rmdecal"; public string Description => "removes a decal"; @@ -31,7 +31,7 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) if (!NetEntity.TryParse(args[1], out var rawGridIdNet) || !_entManager.TryGetEntity(rawGridIdNet, out var rawGridId) || - !_mapManager.GridExists(rawGridId)) + !_entManager.HasComponent(rawGridId)) { shell.WriteError("Failed parsing gridId."); return; diff --git a/Content.Server/Decals/DecalSystem.cs b/Content.Server/Decals/DecalSystem.cs index ad225afe224..da95401d206 100644 --- a/Content.Server/Decals/DecalSystem.cs +++ b/Content.Server/Decals/DecalSystem.cs @@ -105,7 +105,7 @@ private void OnGridSplit(ref PostGridSplitEvent ev) return; // Transfer decals over to the new grid. - var enumerator = MapManager.GetGrid(ev.Grid).GetAllTilesEnumerator(); + var enumerator = Comp(ev.Grid).GetAllTilesEnumerator(); var oldChunkCollection = oldComp.ChunkCollection.ChunkCollection; var chunkCollection = newComp.ChunkCollection.ChunkCollection; diff --git a/Content.Server/DeltaV/StationEvents/Events/PirateRadioSpawnRule.cs b/Content.Server/DeltaV/StationEvents/Events/PirateRadioSpawnRule.cs index f0538c47f95..ba042d89662 100644 --- a/Content.Server/DeltaV/StationEvents/Events/PirateRadioSpawnRule.cs +++ b/Content.Server/DeltaV/StationEvents/Events/PirateRadioSpawnRule.cs @@ -39,7 +39,7 @@ protected override void Started(EntityUid uid, PirateRadioSpawnRuleComponent com var xformQuery = GetEntityQuery(); var aabbs = EntityQuery().SelectMany(x => x.Grids.Select(x => - xformQuery.GetComponent(x).WorldMatrix.TransformBox(_mapManager.GetGridComp(x).LocalAABB))) + xformQuery.GetComponent(x).WorldMatrix.TransformBox(_entities.GetComponent(x).LocalAABB))) .ToArray(); if (aabbs.Length < 1) return; var aabb = aabbs[0]; diff --git a/Content.Server/Disposal/Tube/DisposalTubeSystem.cs b/Content.Server/Disposal/Tube/DisposalTubeSystem.cs index 20aa8b6d2c5..6c0bced53e0 100644 --- a/Content.Server/Disposal/Tube/DisposalTubeSystem.cs +++ b/Content.Server/Disposal/Tube/DisposalTubeSystem.cs @@ -6,20 +6,16 @@ using Content.Server.Disposal.Unit.Components; using Content.Server.Disposal.Unit.EntitySystems; using Content.Server.Popups; -using Content.Server.UserInterface; using Content.Shared.Destructible; using Content.Shared.Disposal.Components; -using Content.Shared.Hands.Components; -using Content.Shared.Movement.Events; using Robust.Server.GameObjects; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; -using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Random; -using Robust.Shared.Timing; using static Content.Shared.Disposal.Components.SharedDisposalRouterComponent; using static Content.Shared.Disposal.Components.SharedDisposalTaggerComponent; @@ -27,8 +23,6 @@ namespace Content.Server.Disposal.Tube { public sealed class DisposalTubeSystem : EntitySystem { - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!; [Dependency] private readonly PopupSystem _popups = default!; @@ -349,7 +343,7 @@ private void UpdateAnchored(EntityUid uid, DisposalTubeComponent component, bool var oppositeDirection = nextDirection.GetOpposite(); var xform = Transform(target); - if (!_mapManager.TryGetGrid(xform.GridUid, out var grid)) + if (!TryComp(xform.GridUid, out var grid)) return null; var position = xform.Coordinates; diff --git a/Content.Server/Disposal/Unit/EntitySystems/DisposableSystem.cs b/Content.Server/Disposal/Unit/EntitySystems/DisposableSystem.cs index eb3cda4db9b..38e39238039 100644 --- a/Content.Server/Disposal/Unit/EntitySystems/DisposableSystem.cs +++ b/Content.Server/Disposal/Unit/EntitySystems/DisposableSystem.cs @@ -1,4 +1,3 @@ -using System.Linq; using Content.Server.Atmos.EntitySystems; using Content.Server.Disposal.Tube; using Content.Server.Disposal.Tube.Components; @@ -12,14 +11,12 @@ using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; -using Robust.Shared.Random; namespace Content.Server.Disposal.Unit.EntitySystems { public sealed class DisposableSystem : EntitySystem { [Dependency] private readonly ThrowingSystem _throwing = default!; - [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Dependency] private readonly DamageableSystem _damageable = default!; [Dependency] private readonly DisposalUnitSystem _disposalUnitSystem = default!; diff --git a/Content.Server/Dragon/DragonRiftSystem.cs b/Content.Server/Dragon/DragonRiftSystem.cs index f7d5cd783d4..819e7f833f3 100644 --- a/Content.Server/Dragon/DragonRiftSystem.cs +++ b/Content.Server/Dragon/DragonRiftSystem.cs @@ -13,6 +13,7 @@ using System.Numerics; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; +using Content.Server.Announcements.Systems; namespace Content.Server.Dragon; @@ -27,6 +28,7 @@ public sealed class DragonRiftSystem : EntitySystem [Dependency] private readonly NavMapSystem _navMap = default!; [Dependency] private readonly NPCSystem _npc = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly AnnouncerSystem _announcer = default!; public override void Initialize() { @@ -70,7 +72,8 @@ public override void Update(float frameTime) Dirty(comp); var location = xform.LocalPosition; - _chat.DispatchGlobalAnnouncement(Loc.GetString("carp-rift-warning", ("location", location)), playSound: false, colorOverride: Color.Red); + _announcer.SendAnnouncement(_announcer.GetAnnouncementId("CarpRift"), Filter.Broadcast(), + "carp-rift-warning", colorOverride: Color.Red, localeArgs: ("location", location)); _audio.PlayGlobal("/Audio/Misc/notice1.ogg", Filter.Broadcast(), true); _navMap.SetBeaconEnabled(uid, true); } diff --git a/Content.Server/Dragon/DragonSystem.cs b/Content.Server/Dragon/DragonSystem.cs index 6400472d036..79e5c0a2a9c 100644 --- a/Content.Server/Dragon/DragonSystem.cs +++ b/Content.Server/Dragon/DragonSystem.cs @@ -10,18 +10,16 @@ using Content.Shared.Mind.Components; using Content.Shared.Mobs; using Content.Shared.Movement.Systems; -using Robust.Shared.Audio; +using Content.Shared.Zombies; using Robust.Shared.Audio.Systems; -using Robust.Shared.GameStates; using Robust.Shared.Map; -using Robust.Shared.Player; +using Robust.Shared.Map.Components; namespace Content.Server.Dragon; public sealed partial class DragonSystem : EntitySystem { [Dependency] private readonly CarpRiftsConditionSystem _carpRifts = default!; - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly ITileDefinitionManager _tileDef = default!; [Dependency] private readonly MovementSpeedModifierSystem _movement = default!; [Dependency] private readonly PopupSystem _popup = default!; @@ -138,7 +136,7 @@ private void OnSpawnRift(EntityUid uid, DragonComponent component, DragonSpawnRi var xform = Transform(uid); // Have to be on a grid fam - if (!_mapManager.TryGetGrid(xform.GridUid, out var grid)) + if (!TryComp(xform.GridUid, out var grid)) { _popup.PopupEntity(Loc.GetString("carp-rift-anchor"), uid, uid); return; diff --git a/Content.Server/Electrocution/ElectrocutionSystem.cs b/Content.Server/Electrocution/ElectrocutionSystem.cs index f71f8b69742..d967013f652 100644 --- a/Content.Server/Electrocution/ElectrocutionSystem.cs +++ b/Content.Server/Electrocution/ElectrocutionSystem.cs @@ -19,7 +19,6 @@ using Content.Shared.Maps; using Content.Shared.Mobs; using Content.Shared.Popups; -using Content.Shared.Pulling.Components; using Content.Shared.Speech.EntitySystems; using Content.Shared.StatusEffect; using Content.Shared.Stunnable; @@ -32,6 +31,8 @@ using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; +using PullableComponent = Content.Shared.Movement.Pulling.Components.PullableComponent; +using PullerComponent = Content.Shared.Movement.Pulling.Components.PullerComponent; namespace Content.Server.Electrocution; @@ -475,14 +476,14 @@ private void GetChainedElectrocutionTargetsRecurse( all.Add((entity, depth)); visited.Add(entity); - if (TryComp(entity, out var pullable) && + if (TryComp(entity, out var pullable) && pullable.Puller is { Valid: true } pullerId && !visited.Contains(pullerId)) { GetChainedElectrocutionTargetsRecurse(pullerId, depth + 1, visited, all); } - if (TryComp(entity, out var puller) && + if (TryComp(entity, out var puller) && puller.Pulling is { Valid: true } pullingId && !visited.Contains(pullingId)) { diff --git a/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs b/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs index 61c4937a271..a0bbbdf350a 100644 --- a/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs +++ b/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs @@ -6,14 +6,13 @@ using Content.Shared.Maps; using Content.Shared.Stacks; using JetBrains.Annotations; -using Robust.Shared.Map; +using Robust.Shared.Map.Components; namespace Content.Server.Engineering.EntitySystems { [UsedImplicitly] public sealed class SpawnAfterInteractSystem : EntitySystem { - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; [Dependency] private readonly StackSystem _stackSystem = default!; @@ -30,7 +29,7 @@ private async void HandleAfterInteract(EntityUid uid, SpawnAfterInteractComponen return; if (string.IsNullOrEmpty(component.Prototype)) return; - if (!_mapManager.TryGetGrid(args.ClickLocation.GetGridUid(EntityManager), out var grid)) + if (!TryComp(args.ClickLocation.GetGridUid(EntityManager), out var grid)) return; if (!grid.TryGetTileRef(args.ClickLocation, out var tileRef)) return; diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs index af150c93250..55e8de26321 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs @@ -4,7 +4,6 @@ using Content.Shared.Damage; using Content.Shared.Explosion; using Content.Shared.FixedPoint; -using Robust.Shared.Map; using Robust.Shared.Map.Components; namespace Content.Server.Explosion.EntitySystems; @@ -102,7 +101,7 @@ private void OnAirtightDamaged(EntityUid uid, AirtightComponent airtight, Damage if (!EntityManager.TryGetComponent(uid, out TransformComponent? transform) || !transform.Anchored) return; - if (!_mapManager.TryGetGrid(transform.GridUid, out var grid)) + if (!TryComp(transform.GridUid, out var grid)) return; UpdateAirtightMap(transform.GridUid.Value, grid, grid.CoordinatesToTile(transform.Coordinates)); diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs index b04642a8db0..719a2eca797 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs @@ -23,7 +23,7 @@ public sealed partial class ExplosionSystem : EntitySystem /// private void OnGridStartup(GridStartupEvent ev) { - var grid = _mapManager.GetGrid(ev.EntityUid); + var grid = Comp(ev.EntityUid); Dictionary edges = new(); _gridEdges[ev.EntityUid] = edges; diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs index 4a9477e7443..ccfcee46124 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs @@ -1,4 +1,3 @@ -using System.Linq; using System.Numerics; using Content.Shared.CCVar; using Content.Shared.Damage; @@ -17,6 +16,7 @@ using Robust.Shared.Timing; using Robust.Shared.Utility; using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent; +using Content.Server.Atmos.EntitySystems; namespace Content.Server.Explosion.EntitySystems; @@ -44,13 +44,6 @@ public sealed partial class ExplosionSystem /// private Explosion? _activeExplosion; - /// - /// While processing an explosion, the "progress" is sent to clients, so that the explosion fireball effect - /// syncs up with the damage. When the tile iteration increments, an update needs to be sent to clients. - /// This integer keeps track of the last value sent to clients. - /// - private int _previousTileIteration; - /// /// This list is used when raising to avoid allocating a new list per event. /// @@ -108,8 +101,6 @@ public override void Update(float frameTime) if (_activeExplosion == null) continue; - _previousTileIteration = 0; - // just a lil nap if (SleepNodeSys) { diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs index afad0e27e09..a42dd110831 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs @@ -4,6 +4,7 @@ using Content.Shared.Explosion; using Content.Shared.Explosion.Components; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Timing; @@ -56,7 +57,7 @@ public sealed partial class ExplosionSystem : EntitySystem else if (referenceGrid != null) { // reference grid defines coordinate system that the explosion in space will use - initialTile = _mapManager.GetGrid(referenceGrid.Value).WorldToTile(epicenter.Position); + initialTile = Comp(referenceGrid.Value).WorldToTile(epicenter.Position); } else { @@ -87,7 +88,7 @@ public sealed partial class ExplosionSystem : EntitySystem var spaceAngle = Angle.Zero; if (referenceGrid != null) { - var xform = Transform(_mapManager.GetGrid(referenceGrid.Value).Owner); + var xform = Transform(Comp(referenceGrid.Value).Owner); spaceMatrix = xform.WorldMatrix; spaceAngle = xform.WorldRotation; } @@ -102,7 +103,7 @@ public sealed partial class ExplosionSystem : EntitySystem airtightMap = new(); var initialGridData = new ExplosionGridTileFlood( - _mapManager.GetGrid(epicentreGrid.Value), + Comp(epicentreGrid.Value), airtightMap, maxIntensity, stepSize, @@ -191,7 +192,7 @@ public sealed partial class ExplosionSystem : EntitySystem airtightMap = new(); data = new ExplosionGridTileFlood( - _mapManager.GetGrid(grid), + Comp(grid), airtightMap, maxIntensity, stepSize, diff --git a/Content.Server/Eye/Blinding/EyeProtection/EyeProtectionSystem.cs b/Content.Server/Eye/Blinding/EyeProtection/EyeProtectionSystem.cs index 24ee2b71541..2d54c03b51b 100644 --- a/Content.Server/Eye/Blinding/EyeProtection/EyeProtectionSystem.cs +++ b/Content.Server/Eye/Blinding/EyeProtection/EyeProtectionSystem.cs @@ -1,10 +1,8 @@ using Content.Shared.StatusEffect; using Content.Shared.Inventory; -using Content.Shared.Item; using Content.Shared.Eye.Blinding.Components; using Content.Shared.Eye.Blinding.Systems; using Content.Shared.Tools.Components; -using Content.Shared.Item.ItemToggle; using Content.Shared.Item.ItemToggle.Components; namespace Content.Server.Eye.Blinding.EyeProtection @@ -13,7 +11,6 @@ public sealed class EyeProtectionSystem : EntitySystem { [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; [Dependency] private readonly BlindableSystem _blindingSystem = default!; - [Dependency] private readonly SharedItemToggleSystem _itemToggle = default!; public override void Initialize() { diff --git a/Content.Server/GameTicking/GameTicker.RoundFlow.cs b/Content.Server/GameTicking/GameTicker.RoundFlow.cs index 6e02c4ac404..a154765f34b 100644 --- a/Content.Server/GameTicking/GameTicker.RoundFlow.cs +++ b/Content.Server/GameTicking/GameTicker.RoundFlow.cs @@ -19,6 +19,7 @@ using Robust.Shared.Player; using Robust.Shared.Random; using Robust.Shared.Utility; +using Content.Server.Announcements.Systems; namespace Content.Server.GameTicking { @@ -26,6 +27,7 @@ public sealed partial class GameTicker { [Dependency] private readonly DiscordWebhook _discord = default!; [Dependency] private readonly ITaskManager _taskManager = default!; + [Dependency] private readonly AnnouncerSystem _announcer = default!; private static readonly Counter RoundNumberMetric = Metrics.CreateCounter( "ss14_round_number", @@ -601,11 +603,8 @@ private void AnnounceRound() var proto = _robustRandom.Pick(options); - if (proto.Message != null) - _chatSystem.DispatchGlobalAnnouncement(Loc.GetString(proto.Message), playSound: true); - - if (proto.Sound != null) - _audio.PlayGlobal(proto.Sound, Filter.Broadcast(), true); + _announcer.SendAnnouncement(_announcer.GetAnnouncementId(proto.ID), Filter.Broadcast(), + proto.Message ?? "game-ticker-welcome-to-the-station"); } private async void SendRoundStartedDiscordMessage() diff --git a/Content.Server/GameTicking/Rules/PiratesRuleSystem.cs b/Content.Server/GameTicking/Rules/PiratesRuleSystem.cs index 98926536b9d..128f1123043 100644 --- a/Content.Server/GameTicking/Rules/PiratesRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/PiratesRuleSystem.cs @@ -24,6 +24,7 @@ using Robust.Shared.Configuration; using Robust.Shared.Enums; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; @@ -180,7 +181,7 @@ private void OnPlayerSpawningEvent(RulePlayerSpawningEvent ev) var aabbs = EntityQuery().SelectMany(x => x.Grids.Select(x => - xformQuery.GetComponent(x).WorldMatrix.TransformBox(_mapManager.GetGridComp(x).LocalAABB))) + xformQuery.GetComponent(x).WorldMatrix.TransformBox(Comp(x).LocalAABB))) .ToArray(); var aabb = aabbs[0]; diff --git a/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs b/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs index 0b7cb9cf8f7..edeafb45847 100644 --- a/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs @@ -22,6 +22,7 @@ using Robust.Shared.Random; using Robust.Shared.Timing; using System.Globalization; +using Content.Server.Announcements.Systems; namespace Content.Server.GameTicking.Rules; @@ -41,6 +42,7 @@ public sealed class ZombieRuleSystem : GameRuleSystem [Dependency] private readonly StationSystem _station = default!; [Dependency] private readonly AntagSelectionSystem _antagSelection = default!; [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly AnnouncerSystem _announcer = default!; public override void Initialize() { @@ -123,7 +125,9 @@ private void CheckRoundEnd(ZombieRuleComponent zombieRuleComponent) { foreach (var station in _station.GetStations()) { - _chat.DispatchStationAnnouncement(station, Loc.GetString("zombie-shuttle-call"), colorOverride: Color.Crimson); + _announcer.SendAnnouncement(_announcer.GetAnnouncementId("ShuttleCalled"), + _station.GetInOwningStation(station), "zombie-shuttle-call", + colorOverride: Color.Crimson); } _roundEnd.RequestRoundEnd(null, false); } @@ -249,7 +253,7 @@ private void InfectInitialPlayers(ZombieRuleComponent component) _playerManager.Sessions, component.PatientZeroPrototypeId, includeAllJobs: false, - customExcludeCondition: player => HasComp(player) || HasComp(player) + customExcludeCondition: player => HasComp(player) || HasComp(player) ); //And get all players, excluding ZombieImmune and roles with CanBeAntag = False - to fill any leftover initial infected slots @@ -259,7 +263,7 @@ private void InfectInitialPlayers(ZombieRuleComponent component) acceptableAntags: Shared.Antag.AntagAcceptability.All, includeAllJobs: false , ignorePreferences: true, - customExcludeCondition: HasComp + customExcludeCondition: HasComp ); //If there are no players to choose, abort diff --git a/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs b/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs index 7558f7afc0b..c934fb66bfb 100644 --- a/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs +++ b/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs @@ -1,23 +1,16 @@ using System.Linq; -using System.Numerics; using Content.Server.Gateway.Components; using Content.Server.Parallax; using Content.Server.Procedural; -using Content.Server.Salvage; using Content.Shared.CCVar; using Content.Shared.Dataset; using Content.Shared.Maps; -using Content.Shared.Movement.Components; using Content.Shared.Parallax.Biomes; -using Content.Shared.Physics; using Content.Shared.Procedural; using Content.Shared.Salvage; using Robust.Shared.Configuration; using Robust.Shared.Map; using Robust.Shared.Map.Components; -using Robust.Shared.Physics.Collision.Shapes; -using Robust.Shared.Physics.Components; -using Robust.Shared.Physics.Systems; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; @@ -40,7 +33,6 @@ public sealed class GatewayGeneratorSystem : EntitySystem [Dependency] private readonly DungeonSystem _dungeon = default!; [Dependency] private readonly GatewaySystem _gateway = default!; [Dependency] private readonly MetaDataSystem _metadata = default!; - [Dependency] private readonly RestrictedRangeSystem _restricted = default!; [Dependency] private readonly SharedMapSystem _maps = default!; [Dependency] private readonly TileSystem _tile = default!; diff --git a/Content.Server/Hands/Systems/HandsSystem.cs b/Content.Server/Hands/Systems/HandsSystem.cs index a0e872dbeb1..e836b658381 100644 --- a/Content.Server/Hands/Systems/HandsSystem.cs +++ b/Content.Server/Hands/Systems/HandsSystem.cs @@ -1,6 +1,5 @@ using System.Numerics; using Content.Server.Inventory; -using Content.Server.Pulling; using Content.Server.Stack; using Content.Server.Stunnable; using Content.Shared.ActionBlocker; @@ -11,8 +10,9 @@ using Content.Shared.Hands.EntitySystems; using Content.Shared.Input; using Content.Shared.Inventory.VirtualItem; -using Content.Shared.Physics.Pull; -using Content.Shared.Pulling.Components; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Events; +using Content.Shared.Movement.Pulling.Systems; using Content.Shared.Stacks; using Content.Shared.Throwing; using Robust.Shared.GameStates; @@ -84,9 +84,8 @@ private void OnDisarmed(EntityUid uid, HandsComponent component, DisarmedEvent a return; // Break any pulls - if (TryComp(uid, out SharedPullerComponent? puller) && puller.Pulling is EntityUid pulled && - TryComp(pulled, out SharedPullableComponent? pullable)) - _pullingSystem.TryStopPull(pullable); + if (TryComp(uid, out PullerComponent? puller) && TryComp(puller.Pulling, out PullableComponent? pullable)) + _pullingSystem.TryStopPull(puller.Pulling.Value, pullable); if (!_handsSystem.TryDrop(uid, component.ActiveHand!, null, checkActionBlocker: false)) return; @@ -96,17 +95,17 @@ private void OnDisarmed(EntityUid uid, HandsComponent component, DisarmedEvent a private void HandleBodyPartAdded(EntityUid uid, HandsComponent component, ref BodyPartAddedEvent args) { - if (args.Part.PartType != BodyPartType.Hand) + if (args.Part.Comp.PartType != BodyPartType.Hand) return; // If this annoys you, which it should. // Ping Smugleaf. - var location = args.Part.Symmetry switch + var location = args.Part.Comp.Symmetry switch { BodyPartSymmetry.None => HandLocation.Middle, BodyPartSymmetry.Left => HandLocation.Left, BodyPartSymmetry.Right => HandLocation.Right, - _ => throw new ArgumentOutOfRangeException(nameof(args.Part.Symmetry)) + _ => throw new ArgumentOutOfRangeException(nameof(args.Part.Comp.Symmetry)) }; AddHand(uid, args.Slot, location); @@ -114,7 +113,7 @@ private void HandleBodyPartAdded(EntityUid uid, HandsComponent component, ref Bo private void HandleBodyPartRemoved(EntityUid uid, HandsComponent component, ref BodyPartRemovedEvent args) { - if (args.Part.PartType != BodyPartType.Hand) + if (args.Part.Comp.PartType != BodyPartType.Hand) return; RemoveHand(uid, args.Slot); @@ -124,13 +123,13 @@ private void HandleBodyPartRemoved(EntityUid uid, HandsComponent component, ref private void HandlePullStarted(EntityUid uid, HandsComponent component, PullStartedMessage args) { - if (args.Puller.Owner != uid) + if (args.PullerUid != uid) return; - if (TryComp(args.Puller.Owner, out var pullerComp) && !pullerComp.NeedsHands) + if (TryComp(args.PullerUid, out var pullerComp) && !pullerComp.NeedsHands) return; - if (!_virtualItemSystem.TrySpawnVirtualItemInHand(args.Pulled.Owner, uid)) + if (!_virtualItemSystem.TrySpawnVirtualItemInHand(args.PulledUid, uid)) { DebugTools.Assert("Unable to find available hand when starting pulling??"); } @@ -138,7 +137,7 @@ private void HandlePullStarted(EntityUid uid, HandsComponent component, PullStar private void HandlePullStopped(EntityUid uid, HandsComponent component, PullStoppedMessage args) { - if (args.Puller.Owner != uid) + if (args.PullerUid != uid) return; // Try find hand that is doing this pull. @@ -147,8 +146,10 @@ private void HandlePullStopped(EntityUid uid, HandsComponent component, PullStop { if (hand.HeldEntity == null || !TryComp(hand.HeldEntity, out VirtualItemComponent? virtualItem) - || virtualItem.BlockingEntity != args.Pulled.Owner) + || virtualItem.BlockingEntity != args.PulledUid) + { continue; + } QueueDel(hand.HeldEntity.Value); break; diff --git a/Content.Server/ImmovableRod/ImmovableRodSystem.cs b/Content.Server/ImmovableRod/ImmovableRodSystem.cs index 31aa39cf03a..429361cd8cd 100644 --- a/Content.Server/ImmovableRod/ImmovableRodSystem.cs +++ b/Content.Server/ImmovableRod/ImmovableRodSystem.cs @@ -6,6 +6,7 @@ using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Systems; @@ -16,7 +17,6 @@ namespace Content.Server.ImmovableRod; public sealed class ImmovableRodSystem : EntitySystem { [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly IMapManager _map = default!; [Dependency] private readonly BodySystem _bodySystem = default!; [Dependency] private readonly PopupSystem _popup = default!; @@ -33,7 +33,7 @@ public override void Update(float frameTime) if (!rod.DestroyTiles) continue; - if (!_map.TryGetGrid(trans.GridUid, out var grid)) + if (!TryComp(trans.GridUid, out var grid)) continue; grid.SetTile(trans.Coordinates, Tile.Empty); diff --git a/Content.Server/Implants/SubdermalImplantSystem.cs b/Content.Server/Implants/SubdermalImplantSystem.cs index 8eb27414481..6b58f6eb092 100644 --- a/Content.Server/Implants/SubdermalImplantSystem.cs +++ b/Content.Server/Implants/SubdermalImplantSystem.cs @@ -19,6 +19,8 @@ using Robust.Shared.Physics.Components; using Robust.Shared.Random; using System.Numerics; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Systems; namespace Content.Server.Implants; @@ -34,6 +36,7 @@ public sealed class SubdermalImplantSystem : SharedSubdermalImplantSystem [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedTransformSystem _xform = default!; [Dependency] private readonly ForensicsSystem _forensicsSystem = default!; + [Dependency] private readonly PullingSystem _pullingSystem = default!; private EntityQuery _physicsQuery; @@ -98,6 +101,11 @@ private void OnScramImplant(EntityUid uid, SubdermalImplantComponent component, if (!TryComp(uid, out var implant)) return; + // We need stop the user from being pulled so they don't just get "attached" with whoever is pulling them. + // This can for example happen when the user is cuffed and being pulled. + if (TryComp(ent, out var pull) && _pullingSystem.IsPulled(ent, pull)) + _pullingSystem.TryStopPull(ent, pull); + var xform = Transform(ent); var entityCoords = xform.Coordinates.ToMap(EntityManager, _xform); diff --git a/Content.Server/Instruments/InstrumentComponent.cs b/Content.Server/Instruments/InstrumentComponent.cs index 4302ab6791b..1b7913386d2 100644 --- a/Content.Server/Instruments/InstrumentComponent.cs +++ b/Content.Server/Instruments/InstrumentComponent.cs @@ -1,6 +1,5 @@ using Content.Server.UserInterface; using Content.Shared.Instruments; -using Robust.Server.GameObjects; using Robust.Shared.Player; namespace Content.Server.Instruments; diff --git a/Content.Server/Interaction/InteractionSystem.cs b/Content.Server/Interaction/InteractionSystem.cs index 6692886daee..203781bcdaa 100644 --- a/Content.Server/Interaction/InteractionSystem.cs +++ b/Content.Server/Interaction/InteractionSystem.cs @@ -1,4 +1,3 @@ -using Content.Shared.ActionBlocker; using Content.Shared.Interaction; using Content.Shared.Storage; using JetBrains.Annotations; @@ -14,7 +13,6 @@ namespace Content.Server.Interaction [UsedImplicitly] public sealed partial class InteractionSystem : SharedInteractionSystem { - [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; diff --git a/Content.Server/Interaction/TilePryCommand.cs b/Content.Server/Interaction/TilePryCommand.cs index 57b07e8181b..006a245ead3 100644 --- a/Content.Server/Interaction/TilePryCommand.cs +++ b/Content.Server/Interaction/TilePryCommand.cs @@ -4,6 +4,7 @@ using Content.Shared.Maps; using Robust.Shared.Console; using Robust.Shared.Map; +using Robust.Shared.Map.Components; namespace Content.Server.Interaction { @@ -46,7 +47,7 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) var xform = _entities.GetComponent(attached); var playerGrid = xform.GridUid; - if (!mapManager.TryGetGrid(playerGrid, out var mapGrid)) + if (!_entities.TryGetComponent(playerGrid, out var mapGrid)) return; var playerPosition = xform.Coordinates; diff --git a/Content.Server/Language/TranslatorSystem.cs b/Content.Server/Language/TranslatorSystem.cs index 5022e540960..adbfe2d681f 100644 --- a/Content.Server/Language/TranslatorSystem.cs +++ b/Content.Server/Language/TranslatorSystem.cs @@ -1,15 +1,12 @@ using System.Linq; -using Content.Server.Language.Events; using Content.Server.Popups; using Content.Server.PowerCell; using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.Language; -using Content.Shared.Language.Events; using Content.Shared.Language.Systems; using Content.Shared.PowerCell; using Content.Shared.Language.Components.Translators; -using Robust.Shared.Utility; namespace Content.Server.Language; diff --git a/Content.Server/Magic/MagicSystem.cs b/Content.Server/Magic/MagicSystem.cs index 92cd794ce2c..86555924712 100644 --- a/Content.Server/Magic/MagicSystem.cs +++ b/Content.Server/Magic/MagicSystem.cs @@ -21,6 +21,7 @@ using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Random; using Robust.Shared.Serialization.Manager; using Robust.Shared.Spawners; @@ -217,7 +218,7 @@ private List GetSpawnPositions(TransformComponent casterXform // This is shit but you get the idea. var directionPos = casterXform.Coordinates.Offset(casterXform.LocalRotation.ToWorldVec().Normalized()); - if (!_mapManager.TryGetGrid(casterXform.GridUid, out var mapGrid)) + if (!TryComp(casterXform.GridUid, out var mapGrid)) return new List(); if (!directionPos.TryGetTileRef(out var tileReference, EntityManager, _mapManager)) diff --git a/Content.Server/Mapping/MappingCommand.cs b/Content.Server/Mapping/MappingCommand.cs index 08ba0de8334..08f3dcccf9f 100644 --- a/Content.Server/Mapping/MappingCommand.cs +++ b/Content.Server/Mapping/MappingCommand.cs @@ -1,17 +1,14 @@ -// ReSharper disable once RedundantUsingDirective -// Used to warn the player in big red letters in debug mode - using System.Linq; using Content.Server.Administration; using Content.Server.GameTicking; using Content.Shared.Administration; using Content.Shared.CCVar; -using Robust.Server.Player; +using Robust.Server.GameObjects; +using Robust.Server.Maps; using Robust.Shared.Configuration; using Robust.Shared.Console; using Robust.Shared.ContentPack; using Robust.Shared.Map; -using Robust.Shared.Utility; namespace Content.Server.Mapping { @@ -19,6 +16,8 @@ namespace Content.Server.Mapping sealed class MappingCommand : IConsoleCommand { [Dependency] private readonly IEntityManager _entities = default!; + [Dependency] private readonly IMapManager _map = default!; + [Dependency] private readonly IConfigurationManager _cfg = default!; public string Command => "mapping"; public string Description => Loc.GetString("cmd-mapping-desc"); @@ -57,13 +56,13 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) shell.WriteError(Loc.GetString("cmd-mapping-warning")); #endif - var mapManager = IoCManager.Resolve(); MapId mapId; + string? toLoad = null; + var mapSys = _entities.System(); // Get the map ID to use if (args.Length is 1 or 2) { - if (!int.TryParse(args[0], out var intMapId)) { shell.WriteError(Loc.GetString("cmd-mapping-failure-integer", ("arg", args[0]))); @@ -79,35 +78,33 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) return; } - if (mapManager.MapExists(mapId)) + if (_map.MapExists(mapId)) { shell.WriteError(Loc.GetString("cmd-mapping-exists", ("mapId", mapId))); return; } - } - else - { - mapId = mapManager.NextMapId(); - } + // either load a map or create a new one. + if (args.Length <= 1) + { + mapSys.CreateMap(mapId, runMapInit: false); + } + else + { + var loadOptions = new MapLoadOptions {StoreMapUids = true}; + _entities.System().TryLoad(mapId, args[1], out _, loadOptions); + } - string? toLoad = null; - // either load a map or create a new one. - if (args.Length <= 1) - { - shell.ExecuteCommand($"addmap {mapId} false"); + // was the map actually created or did it fail somehow? + if (!_map.MapExists(mapId)) + { + shell.WriteError(Loc.GetString("cmd-mapping-error")); + return; + } } else { - toLoad = CommandParsing.Escape(args[1]); - shell.ExecuteCommand($"loadmap {mapId} \"{toLoad}\" 0 0 0 true"); - } - - // was the map actually created? - if (!mapManager.MapExists(mapId)) - { - shell.WriteError(Loc.GetString("cmd-mapping-error")); - return; + mapSys.CreateMap(out mapId, runMapInit: false); } // map successfully created. run misc helpful mapping commands @@ -117,17 +114,15 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) shell.ExecuteCommand("aghost"); } - var cfg = IoCManager.Resolve(); - // don't interrupt mapping with events or auto-shuttle shell.ExecuteCommand("sudo cvar events.enabled false"); shell.ExecuteCommand("sudo cvar shuttle.auto_call_time 0"); - if (cfg.GetCVar(CCVars.AutosaveEnabled)) + if (_cfg.GetCVar(CCVars.AutosaveEnabled)) shell.ExecuteCommand($"toggleautosave {mapId} {toLoad ?? "NEWMAP"}"); shell.ExecuteCommand($"tp 0 0 {mapId}"); shell.RemoteExecuteCommand("mappingclientsidesetup"); - mapManager.SetMapPaused(mapId, true); + _map.SetMapPaused(mapId, true); if (args.Length == 2) shell.WriteLine(Loc.GetString("cmd-mapping-success-load",("mapId",mapId),("path", args[1]))); diff --git a/Content.Server/Mech/Systems/MechSystem.cs b/Content.Server/Mech/Systems/MechSystem.cs index 1012b9727df..f592de9e7eb 100644 --- a/Content.Server/Mech/Systems/MechSystem.cs +++ b/Content.Server/Mech/Systems/MechSystem.cs @@ -20,7 +20,6 @@ using Robust.Server.Containers; using Robust.Server.GameObjects; using Robust.Shared.Containers; -using Robust.Shared.Map; using Robust.Shared.Player; namespace Content.Server.Mech.Systems; @@ -33,8 +32,6 @@ public sealed partial class MechSystem : SharedMechSystem [Dependency] private readonly BatterySystem _battery = default!; [Dependency] private readonly ContainerSystem _container = default!; [Dependency] private readonly DamageableSystem _damageable = default!; - [Dependency] private readonly IMapManager _map = default!; - [Dependency] private readonly MapSystem _mapSystem = default!; [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly UserInterfaceSystem _ui = default!; diff --git a/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs b/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs index f19b3d5b814..09497c7136b 100644 --- a/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs +++ b/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs @@ -9,7 +9,6 @@ using Content.Server.Station.Systems; using Content.Shared.Damage; using Content.Shared.DeviceNetwork; -using Content.Shared.Emp; using Content.Shared.Examine; using Content.Shared.Inventory.Events; using Content.Shared.Medical.SuitSensor; @@ -27,7 +26,6 @@ public sealed class SuitSensorSystem : EntitySystem { [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly CrewMonitoringServerSystem _monitoringServerSystem = default!; [Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!; [Dependency] private readonly IdCardSystem _idCardSystem = default!; [Dependency] private readonly MobStateSystem _mobStateSystem = default!; diff --git a/Content.Server/NPC/HTN/Preconditions/PulledPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/PulledPrecondition.cs index 64a72b13cfa..d276be72187 100644 --- a/Content.Server/NPC/HTN/Preconditions/PulledPrecondition.cs +++ b/Content.Server/NPC/HTN/Preconditions/PulledPrecondition.cs @@ -1,4 +1,5 @@ using Content.Shared.Pulling; +using PullingSystem = Content.Shared.Movement.Pulling.Systems.PullingSystem; namespace Content.Server.NPC.HTN.Preconditions; @@ -7,14 +8,14 @@ namespace Content.Server.NPC.HTN.Preconditions; /// public sealed partial class PulledPrecondition : HTNPrecondition { - private SharedPullingSystem _pulling = default!; + private PullingSystem _pulling = default!; [ViewVariables(VVAccess.ReadWrite)] [DataField("isPulled")] public bool IsPulled = true; public override void Initialize(IEntitySystemManager sysManager) { base.Initialize(sysManager); - _pulling = sysManager.GetEntitySystem(); + _pulling = sysManager.GetEntitySystem(); } public override bool IsMet(NPCBlackboard blackboard) diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/MoveToOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/MoveToOperator.cs index dd35d2112c9..e64343fdd8a 100644 --- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/MoveToOperator.cs +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/MoveToOperator.cs @@ -4,6 +4,7 @@ using Content.Server.NPC.Pathfinding; using Content.Server.NPC.Systems; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators; @@ -14,7 +15,6 @@ namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators; public sealed partial class MoveToOperator : HTNOperator, IHtnConditionalShutdown { [Dependency] private readonly IEntityManager _entManager = default!; - [Dependency] private readonly IMapManager _mapManager = default!; private NPCSteeringSystem _steering = default!; private PathfindingSystem _pathfind = default!; private SharedTransformSystem _transform = default!; @@ -85,8 +85,8 @@ public override void Initialize(IEntitySystemManager sysManager) !_entManager.TryGetComponent(owner, out var body)) return (false, null); - if (!_mapManager.TryGetGrid(xform.GridUid, out var ownerGrid) || - !_mapManager.TryGetGrid(targetCoordinates.GetGridUid(_entManager), out var targetGrid)) + if (!_entManager.TryGetComponent(xform.GridUid, out var ownerGrid) || + !_entManager.TryGetComponent(targetCoordinates.GetGridUid(_entManager), out var targetGrid)) { return (false, null); } diff --git a/Content.Server/NPC/Systems/NPCCombatSystem.Ranged.cs b/Content.Server/NPC/Systems/NPCCombatSystem.Ranged.cs index 10ec54c8954..efb85b23ae3 100644 --- a/Content.Server/NPC/Systems/NPCCombatSystem.Ranged.cs +++ b/Content.Server/NPC/Systems/NPCCombatSystem.Ranged.cs @@ -203,6 +203,7 @@ private void UpdateRanged(float frameTime) return; } + _gun.SetTarget(gun, comp.Target); _gun.AttemptShoot(uid, gunUid, gun, targetCordinates); } } diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs index e7af2c91073..ce10d4f5d5e 100644 --- a/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs +++ b/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs @@ -58,7 +58,7 @@ private bool IsFreeSpace( // TODO: Ideally for "FreeSpace" we check all entities on the tile and build flags dynamically (pathfinder refactor in future). var ents = _entSetPool.Get(); - _lookup.GetLocalEntitiesIntersecting(node.GraphUid, node.ChunkOrigin, ents, flags: LookupFlags.Static); + _lookup.GetLocalEntitiesIntersecting(node.GraphUid, node.Box.Enlarged(-0.04f), ents, flags: LookupFlags.Static); var result = true; if (ents.Count > 0) @@ -158,42 +158,42 @@ private bool TrySeek( } } + // Check if mapids match. + var targetMap = targetCoordinates.ToMap(EntityManager, _transform); + var ourMap = ourCoordinates.ToMap(EntityManager, _transform); + + if (targetMap.MapId != ourMap.MapId) + { + steering.Status = SteeringStatus.NoPath; + return false; + } + + var direction = targetMap.Position - ourMap.Position; + // Need to be pretty close if it's just a node to make sure LOS for door bashes or the likes. - float arrivalDistance; + bool arrived; if (targetCoordinates.Equals(steering.Coordinates)) { // What's our tolerance for arrival. // If it's a pathfinding node it might be different to the destination. - arrivalDistance = steering.Range; + arrived = direction.Length() <= steering.Range; } // If next node is a free tile then get within its bounds. // This is to avoid popping it too early else if (steering.CurrentPath.TryPeek(out var node) && IsFreeSpace(uid, steering, node)) { - arrivalDistance = MathF.Max(0.05f, MathF.Min(node.Box.Width / 2f, node.Box.Height / 2f) - 0.05f); + arrived = node.Box.Contains(ourCoordinates.Position); } // Try getting into blocked range I guess? // TODO: Consider melee range or the likes. else { - arrivalDistance = SharedInteractionSystem.InteractionRange - 0.05f; + arrived = direction.Length() <= SharedInteractionSystem.InteractionRange - 0.05f; } - // Check if mapids match. - var targetMap = targetCoordinates.ToMap(EntityManager, _transform); - var ourMap = ourCoordinates.ToMap(EntityManager, _transform); - - if (targetMap.MapId != ourMap.MapId) - { - steering.Status = SteeringStatus.NoPath; - return false; - } - - var direction = targetMap.Position - ourMap.Position; - // Are we in range - if (direction.Length() <= arrivalDistance) + if (arrived) { // Node needs some kind of special handling like access or smashing. if (steering.CurrentPath.TryPeek(out var node) && !IsFreeSpace(uid, steering, node)) diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs index 70d1e89bc4f..3bc4eae9e49 100644 --- a/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs +++ b/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs @@ -6,6 +6,7 @@ using Content.Shared.DoAfter; using Content.Shared.Doors.Components; using Content.Shared.NPC; +using Robust.Shared.Map.Components; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Utility; @@ -201,7 +202,7 @@ private SteeringObstacleStatus TryHandleFlags(EntityUid uid, NPCSteeringComponen private void GetObstacleEntities(PathPoly poly, int mask, int layer, List ents) { // TODO: Can probably re-use this from pathfinding or something - if (!_mapManager.TryGetGrid(poly.GraphUid, out var grid)) + if (!TryComp(poly.GraphUid, out var grid)) { return; } diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.cs index c00375d6488..447792b6ff2 100644 --- a/Content.Server/NPC/Systems/NPCSteeringSystem.cs +++ b/Content.Server/NPC/Systems/NPCSteeringSystem.cs @@ -45,7 +45,6 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem [Dependency] private readonly IAdminManager _admin = default!; [Dependency] private readonly IConfigurationManager _configManager = default!; [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly ClimbSystem _climb = default!; [Dependency] private readonly DoAfterSystem _doAfter = default!; @@ -273,6 +272,8 @@ private void SetDirection(InputMoverComponent component, NPCSteeringComponent st if (clear && value.Equals(Vector2.Zero)) { steering.CurrentPath.Clear(); + Array.Clear(steering.Interest); + Array.Clear(steering.Danger); } component.CurTickSprintMovement = value; diff --git a/Content.Server/Ninja/Systems/StunProviderSystem.cs b/Content.Server/Ninja/Systems/StunProviderSystem.cs index 636037060a9..970ca78e2cc 100644 --- a/Content.Server/Ninja/Systems/StunProviderSystem.cs +++ b/Content.Server/Ninja/Systems/StunProviderSystem.cs @@ -1,14 +1,11 @@ using Content.Server.Ninja.Events; using Content.Server.Power.EntitySystems; using Content.Shared.Damage; -using Content.Shared.Damage.Prototypes; using Content.Shared.Interaction; using Content.Shared.Ninja.Components; using Content.Shared.Ninja.Systems; using Content.Shared.Popups; using Content.Shared.Stunnable; -using Content.Shared.Whitelist; -using Robust.Shared.Audio; using Robust.Shared.Prototypes; using Robust.Shared.Audio.Systems; using Robust.Shared.Timing; @@ -23,7 +20,6 @@ public sealed class StunProviderSystem : SharedStunProviderSystem [Dependency] private readonly BatterySystem _battery = default!; [Dependency] private readonly DamageableSystem _damageable = default!; [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedNinjaGlovesSystem _gloves = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; diff --git a/Content.Server/NodeContainer/EntitySystems/NodeGroupSystem.cs b/Content.Server/NodeContainer/EntitySystems/NodeGroupSystem.cs index 5e31bd68722..2296de2eb6a 100644 --- a/Content.Server/NodeContainer/EntitySystems/NodeGroupSystem.cs +++ b/Content.Server/NodeContainer/EntitySystems/NodeGroupSystem.cs @@ -8,7 +8,7 @@ using JetBrains.Annotations; using Robust.Server.Player; using Robust.Shared.Enums; -using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Player; using Robust.Shared.Utility; @@ -25,7 +25,6 @@ public sealed class NodeGroupSystem : EntitySystem [Dependency] private readonly IAdminManager _adminManager = default!; [Dependency] private readonly INodeGroupFactory _nodeGroupFactory = default!; [Dependency] private readonly ILogManager _logManager = default!; - [Dependency] private readonly IMapManager _mapManager = default!; private readonly List _visDeletes = new(); private readonly List _visSends = new(); @@ -343,7 +342,7 @@ private List FloodFillNode(Node rootNode) private IEnumerable GetCompatibleNodes(Node node, EntityQuery xformQuery, EntityQuery nodeQuery) { var xform = xformQuery.GetComponent(node.Owner); - _mapManager.TryGetGrid(xform.GridUid, out var grid); + TryComp(xform.GridUid, out var grid); if (!node.Connectable(EntityManager, xform)) yield break; diff --git a/Content.Server/Nuke/NukeCodePaperSystem.cs b/Content.Server/Nuke/NukeCodePaperSystem.cs index 8df25feebfa..36268d5648d 100644 --- a/Content.Server/Nuke/NukeCodePaperSystem.cs +++ b/Content.Server/Nuke/NukeCodePaperSystem.cs @@ -7,6 +7,8 @@ using Content.Shared.Paper; using Robust.Shared.Random; using Robust.Shared.Utility; +using Content.Server.Announcements.Systems; +using Robust.Shared.Player; namespace Content.Server.Nuke { @@ -17,6 +19,7 @@ public sealed class NukeCodePaperSystem : EntitySystem [Dependency] private readonly StationSystem _station = default!; [Dependency] private readonly PaperSystem _paper = default!; [Dependency] private readonly FaxSystem _faxSystem = default!; + [Dependency] private readonly AnnouncerSystem _announcer = default!; public override void Initialize() { @@ -57,9 +60,7 @@ public bool SendNukeCodes(EntityUid station) while (faxes.MoveNext(out var faxEnt, out var fax)) { if (!fax.ReceiveNukeCodes || !TryGetRelativeNukeCode(faxEnt, out var paperContent, station)) - { continue; - } var printout = new FaxPrintout( paperContent, @@ -77,10 +78,8 @@ public bool SendNukeCodes(EntityUid station) } if (wasSent) - { - var msg = Loc.GetString("nuke-component-announcement-send-codes"); - _chatSystem.DispatchStationAnnouncement(station, msg, colorOverride: Color.Red); - } + _announcer.SendAnnouncement(_announcer.GetAnnouncementId("NukeCodes"), Filter.Broadcast(), + "nuke-component-announcement-send-codes", colorOverride: Color.Red); return wasSent; } diff --git a/Content.Server/Nuke/NukeSystem.cs b/Content.Server/Nuke/NukeSystem.cs index d6767cd2de8..3a1331774d8 100644 --- a/Content.Server/Nuke/NukeSystem.cs +++ b/Content.Server/Nuke/NukeSystem.cs @@ -18,8 +18,10 @@ using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Player; using Robust.Shared.Random; +using Content.Server.Announcements.Systems; namespace Content.Server.Nuke; @@ -28,7 +30,6 @@ public sealed class NukeSystem : EntitySystem [Dependency] private readonly AlertLevelSystem _alertLevel = default!; [Dependency] private readonly ChatSystem _chatSystem = default!; [Dependency] private readonly ExplosionSystem _explosions = default!; - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly ITileDefinitionManager _tileDefManager = default!; [Dependency] private readonly ItemSlotsSystem _itemSlots = default!; @@ -42,6 +43,7 @@ public sealed class NukeSystem : EntitySystem [Dependency] private readonly StationSystem _station = default!; [Dependency] private readonly UserInterfaceSystem _ui = default!; [Dependency] private readonly AppearanceSystem _appearance = default!; + [Dependency] private readonly AnnouncerSystem _announcer = default!; /// /// Used to calculate when the nuke song should start playing for maximum kino with the nuke sfx @@ -175,7 +177,7 @@ private async void OnAnchorButtonPressed(EntityUid uid, NukeComponent component, } else { - if (!_mapManager.TryGetGrid(xform.GridUid, out var grid)) + if (!TryComp(xform.GridUid, out var grid)) return; var worldPos = _transform.GetWorldPosition(xform); @@ -461,11 +463,15 @@ public void ArmBomb(EntityUid uid, NukeComponent? component = null) // We are collapsing the randomness here, otherwise we would get separate random song picks for checking duration and when actually playing the song afterwards _selectedNukeSong = _audio.GetSound(component.ArmMusic); - // warn a crew - var announcement = Loc.GetString("nuke-component-announcement-armed", - ("time", (int) component.RemainingTime), ("position", posText)); - var sender = Loc.GetString("nuke-component-announcement-sender"); - _chatSystem.DispatchStationAnnouncement(stationUid ?? uid, announcement, sender, false, null, Color.Red); + _announcer.SendAnnouncementMessage( + _announcer.GetAnnouncementId("NukeArm"), + "nuke-component-announcement-armed", + Loc.GetString("nuke-component-announcement-sender"), + Color.Red, + stationUid ?? uid, + null, + ("time", (int) component.RemainingTime), ("position", posText) + ); _sound.PlayGlobalOnStation(uid, _audio.GetSound(component.ArmSound)); _nukeSongLength = (float) _audio.GetAudioLength(_selectedNukeSong).TotalSeconds; @@ -502,10 +508,12 @@ public void DisarmBomb(EntityUid uid, NukeComponent? component = null) if (stationUid != null) _alertLevel.SetLevel(stationUid.Value, component.AlertLevelOnDeactivate, true, true, true); - // warn a crew - var announcement = Loc.GetString("nuke-component-announcement-unarmed"); - var sender = Loc.GetString("nuke-component-announcement-sender"); - _chatSystem.DispatchStationAnnouncement(uid, announcement, sender, false); + _announcer.SendAnnouncementMessage( + _announcer.GetAnnouncementId("NukeDisarm"), + "nuke-component-announcement-unarmed", + Loc.GetString("nuke-component-announcement-sender"), + station: stationUid ?? uid + ); component.PlayedNukeSong = false; _sound.PlayGlobalOnStation(uid, _audio.GetSound(component.DisarmSound)); @@ -647,4 +655,3 @@ public sealed class NukeDisarmSuccessEvent : EntityEventArgs { } - diff --git a/Content.Server/NukeOps/WarDeclaratorSystem.cs b/Content.Server/NukeOps/WarDeclaratorSystem.cs index bcc0b9c0ea6..dee0c10c40e 100644 --- a/Content.Server/NukeOps/WarDeclaratorSystem.cs +++ b/Content.Server/NukeOps/WarDeclaratorSystem.cs @@ -10,6 +10,8 @@ using Robust.Server.GameObjects; using Robust.Shared.Configuration; using Robust.Shared.Timing; +using Content.Server.Announcements.Systems; +using Robust.Shared.Player; namespace Content.Server.NukeOps; @@ -25,6 +27,7 @@ public sealed class WarDeclaratorSystem : EntitySystem [Dependency] private readonly ChatSystem _chat = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!; + [Dependency] private readonly AnnouncerSystem _announcer = default!; public override void Initialize() { @@ -74,7 +77,7 @@ private void OnActivated(Entity ent, ref WarDeclaratorAc if (ev.Status == WarConditionStatus.WarReady) { var title = Loc.GetString(ent.Comp.SenderTitle); - _chat.DispatchGlobalAnnouncement(ent.Comp.Message, title, true, ent.Comp.Sound, ent.Comp.Color); + _announcer.SendAnnouncement("war", Filter.Broadcast(), ent.Comp.Message, title, ent.Comp.Color); _adminLogger.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(playerEntity):player} has declared war with this text: {ent.Comp.Message}"); } diff --git a/Content.Server/Nutrition/EntitySystems/CreamPieSystem.cs b/Content.Server/Nutrition/EntitySystems/CreamPieSystem.cs index f8d781bcfff..a28679ddbc9 100644 --- a/Content.Server/Nutrition/EntitySystems/CreamPieSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/CreamPieSystem.cs @@ -1,12 +1,11 @@ using Content.Server.Chemistry.Containers.EntitySystems; -using Content.Server.Explosion.Components; using Content.Server.Explosion.EntitySystems; using Content.Server.Fluids.EntitySystems; using Content.Server.Nutrition.Components; using Content.Server.Popups; using Content.Shared.Containers.ItemSlots; using Content.Shared.Explosion.Components; -using Content.Shared.Interaction; +using Content.Shared.Nutrition; using Content.Shared.Nutrition.Components; using Content.Shared.Nutrition.EntitySystems; using Content.Shared.Rejuvenate; @@ -32,7 +31,10 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnInteractUsing); + // activate BEFORE entity is deleted and trash is spawned + SubscribeLocalEvent(OnConsume, before: [typeof(FoodSystem)]); + SubscribeLocalEvent(OnSlice); + SubscribeLocalEvent(OnRejuvenate); } @@ -56,7 +58,12 @@ protected override void SplattedCreamPie(EntityUid uid, CreamPieComponent creamP EntityManager.QueueDeleteEntity(uid); } - private void OnInteractUsing(Entity entity, ref InteractUsingEvent args) + private void OnConsume(Entity entity, ref ConsumeDoAfterEvent args) + { + ActivatePayload(entity); + } + + private void OnSlice(Entity entity, ref SliceFoodEvent args) { ActivatePayload(entity); } diff --git a/Content.Server/Nutrition/EntitySystems/SliceableFoodSystem.cs b/Content.Server/Nutrition/EntitySystems/SliceableFoodSystem.cs index e92b046f2e3..abb6f393ac5 100644 --- a/Content.Server/Nutrition/EntitySystems/SliceableFoodSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/SliceableFoodSystem.cs @@ -1,11 +1,11 @@ using Content.Server.Nutrition; // DeltaV using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Nutrition.Components; +using Content.Shared.Nutrition; using Content.Shared.Nutrition.Components; using Content.Shared.Chemistry.Components; using Content.Shared.Examine; using Content.Shared.FixedPoint; -using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; using Robust.Server.GameObjects; using Robust.Shared.Audio; @@ -19,7 +19,6 @@ public sealed class SliceableFoodSystem : EntitySystem [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedContainerSystem _containerSystem = default!; - [Dependency] private readonly SharedHandsSystem _handsSystem = default!; [Dependency] private readonly TransformSystem _xformSystem = default!; public override void Initialize() @@ -67,6 +66,8 @@ private bool TrySliceFood(EntityUid uid, EntityUid user, EntityUid usedItem, FillSlice(sliceUid, lostSolution); _audio.PlayPvs(component.Sound, transform.Coordinates, AudioParams.Default.WithVolume(-2)); + var ev = new SliceFoodEvent(uid, user, usedItem); + RaiseLocalEvent(ev); // Decrease size of item based on count - Could implement in the future // Bug with this currently is the size in a container is not updated diff --git a/Content.Server/Nyanotrasen/Carrying/CarryingSystem.cs b/Content.Server/Nyanotrasen/Carrying/CarryingSystem.cs index 103731b1b04..ff4c097080c 100644 --- a/Content.Server/Nyanotrasen/Carrying/CarryingSystem.cs +++ b/Content.Server/Nyanotrasen/Carrying/CarryingSystem.cs @@ -2,12 +2,10 @@ using System.Threading; using Content.Server.DoAfter; using Content.Server.Body.Systems; -using Content.Server.Hands.Systems; using Content.Server.Resist; using Content.Server.Popups; using Content.Server.Inventory; using Content.Server.Nyanotrasen.Item.PseudoItem; -using Content.Shared.Climbing; // Shared instead of Server using Content.Shared.Mobs; using Content.Shared.DoAfter; using Content.Shared.Buckle.Components; @@ -20,14 +18,14 @@ using Content.Shared.Carrying; using Content.Shared.Movement.Events; using Content.Shared.Movement.Systems; -using Content.Shared.Pulling; -using Content.Shared.Pulling.Components; using Content.Shared.Standing; using Content.Shared.ActionBlocker; using Content.Shared.Inventory.VirtualItem; using Content.Shared.Item; using Content.Shared.Throwing; -using Content.Shared.Physics.Pull; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Events; +using Content.Shared.Movement.Pulling.Systems; using Content.Shared.Mobs.Systems; using Content.Shared.Nyanotrasen.Item.PseudoItem; using Content.Shared.Storage; @@ -38,17 +36,16 @@ namespace Content.Server.Carrying { public sealed class CarryingSystem : EntitySystem { - [Dependency] private readonly VirtualItemSystem _virtualItemSystem = default!; + [Dependency] private readonly VirtualItemSystem _virtualItemSystem = default!; [Dependency] private readonly CarryingSlowdownSystem _slowdown = default!; [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; [Dependency] private readonly StandingStateSystem _standingState = default!; [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; - [Dependency] private readonly SharedPullingSystem _pullingSystem = default!; + [Dependency] private readonly PullingSystem _pullingSystem = default!; [Dependency] private readonly MobStateSystem _mobStateSystem = default!; [Dependency] private readonly EscapeInventorySystem _escapeInventorySystem = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly MovementSpeedModifierSystem _movementSpeed = default!; - [Dependency] private readonly RespiratorSystem _respirator = default!; [Dependency] private readonly PseudoItemSystem _pseudoItem = default!; public override void Initialize() @@ -280,8 +277,8 @@ private void StartCarryDoAfter(EntityUid carrier, EntityUid carried, CarriableCo private void Carry(EntityUid carrier, EntityUid carried) { - if (TryComp(carried, out var pullable)) - _pullingSystem.TryStopPull(pullable); + if (TryComp(carried, out var pullable)) + _pullingSystem.TryStopPull(carried, pullable); Transform(carrier).AttachToGridOrMap(); Transform(carried).AttachToGridOrMap(); diff --git a/Content.Server/Nyanotrasen/Item/ShockCollar/ShockCollarComponent.cs b/Content.Server/Nyanotrasen/Item/ShockCollar/ShockCollarComponent.cs index 781f2d00030..1dcbc48676a 100644 --- a/Content.Server/Nyanotrasen/Item/ShockCollar/ShockCollarComponent.cs +++ b/Content.Server/Nyanotrasen/Item/ShockCollar/ShockCollarComponent.cs @@ -2,5 +2,11 @@ namespace Content.Server.ShockCollar; [RegisterComponent] public sealed partial class ShockCollarComponent : Component -{} +{ + [DataField] + public int ShockDamage = 1; + + [DataField] + public TimeSpan ShockTime = TimeSpan.FromSeconds(2); +} diff --git a/Content.Server/Nyanotrasen/Item/ShockCollar/ShockCollarSystem.cs b/Content.Server/Nyanotrasen/Item/ShockCollar/ShockCollarSystem.cs index 70e5ee65abd..eeb0f59d42a 100644 --- a/Content.Server/Nyanotrasen/Item/ShockCollar/ShockCollarSystem.cs +++ b/Content.Server/Nyanotrasen/Item/ShockCollar/ShockCollarSystem.cs @@ -33,7 +33,7 @@ private void OnTrigger(EntityUid uid, ShockCollarComponent component, TriggerEve && !_useDelay.TryResetDelay((uid, useDelay), true)) return; - _electrocutionSystem.TryDoElectrocution(containerEnt, null, 1, TimeSpan.FromSeconds(2), true); + _electrocutionSystem.TryDoElectrocution(containerEnt, null, component.ShockDamage, component.ShockTime, true, ignoreInsulation: true); } } diff --git a/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.cs b/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.cs index aa6de572cee..80c38f4630e 100644 --- a/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.cs +++ b/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.cs @@ -86,7 +86,7 @@ public sealed partial class DeepFryerSystem : SharedDeepfryerSystem private static readonly string MobFlavorMeat = "meaty"; private static readonly AudioParams - AudioParamsInsertRemove = new(0.5f, 1f, "Master", 5f, 1.5f, 1f, false, 0f, 0.2f); + AudioParamsInsertRemove = new(0.5f, 1f, 5f, 1.5f, 1f, false, 0f, 0.2f); private ISawmill _sawmill = default!; diff --git a/Content.Server/Objectives/Systems/NinjaConditionsSystem.cs b/Content.Server/Objectives/Systems/NinjaConditionsSystem.cs index 2bd8538af16..888a365a5dd 100644 --- a/Content.Server/Objectives/Systems/NinjaConditionsSystem.cs +++ b/Content.Server/Objectives/Systems/NinjaConditionsSystem.cs @@ -1,7 +1,6 @@ using Content.Server.Objectives.Components; using Content.Server.Warps; using Content.Shared.Objectives.Components; -using Content.Shared.Mind; using Content.Shared.Ninja.Components; using Robust.Shared.Random; using Content.Server.Roles; @@ -16,7 +15,6 @@ public sealed class NinjaConditionsSystem : EntitySystem { [Dependency] private readonly MetaDataSystem _metaData = default!; [Dependency] private readonly NumberObjectiveSystem _number = default!; - [Dependency] private readonly SharedMindSystem _mind = default!; [Dependency] private readonly IRobustRandom _random = default!; public override void Initialize() diff --git a/Content.Server/Objectives/Systems/StealConditionSystem.cs b/Content.Server/Objectives/Systems/StealConditionSystem.cs index 02d4ee010b5..0fe6f0947c8 100644 --- a/Content.Server/Objectives/Systems/StealConditionSystem.cs +++ b/Content.Server/Objectives/Systems/StealConditionSystem.cs @@ -6,11 +6,10 @@ using Robust.Shared.Containers; using Robust.Shared.Prototypes; using Robust.Shared.Random; -using Content.Shared.Pulling.Components; -using Content.Shared.Objectives; using Content.Shared.Mind.Components; using Content.Shared.Mobs.Systems; using Content.Shared.Mobs.Components; +using Content.Shared.Movement.Pulling.Components; namespace Content.Server.Objectives.Systems; @@ -100,19 +99,19 @@ private float GetProgress(MindComponent mind, StealConditionComponent condition) var count = 0; //check pulling object - if (TryComp(mind.OwnedEntity, out var pull)) //TO DO: to make the code prettier? don't like the repetition + if (TryComp(mind.OwnedEntity, out var pull)) //TO DO: to make the code prettier? don't like the repetition { - var pullid = pull.Pulling; - if (pullid != null) + var pulledEntity = pull.Pulling; + if (pulledEntity != null) { // check if this is the item - if (CheckStealTarget(pullid.Value, condition)) count++; + if (CheckStealTarget(pulledEntity.Value, condition)) count++; //we don't check the inventories of sentient entity - if (!TryComp(pullid, out var pullMind)) + if (!HasComp(pulledEntity)) { // if it is a container check its contents - if (_containerQuery.TryGetComponent(pullid, out var containerManager)) + if (_containerQuery.TryGetComponent(pulledEntity, out var containerManager)) stack.Push(containerManager); } } diff --git a/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.cs b/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.cs index ddc7e2a0830..e9b62bc4a80 100644 --- a/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.cs +++ b/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.cs @@ -2,7 +2,6 @@ using Content.Server.Chat.Managers; using Content.Server.Projectiles; using Robust.Shared.Physics.Systems; -using Robust.Shared.Map; using Robust.Shared.Timing; using Robust.Server.GameObjects; using Robust.Shared.Configuration; @@ -13,7 +12,6 @@ public sealed partial class ParticleAcceleratorSystem : EntitySystem { [Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly IChatManager _chat = default!; [Dependency] private readonly ProjectileSystem _projectileSystem = default!; diff --git a/Content.Server/Physics/Controllers/MoverController.cs b/Content.Server/Physics/Controllers/MoverController.cs index c362507f19a..759b8ef29c6 100644 --- a/Content.Server/Physics/Controllers/MoverController.cs +++ b/Content.Server/Physics/Controllers/MoverController.cs @@ -6,17 +6,16 @@ using Content.Shared.Movement.Systems; using Content.Shared.Shuttles.Components; using Content.Shared.Shuttles.Systems; -using Robust.Shared.Map; using Robust.Shared.Physics.Components; using Robust.Shared.Player; using DroneConsoleComponent = Content.Server.Shuttles.DroneConsoleComponent; using DependencyAttribute = Robust.Shared.IoC.DependencyAttribute; +using Robust.Shared.Map.Components; namespace Content.Server.Physics.Controllers { public sealed class MoverController : SharedMoverController { - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly ThrusterSystem _thruster = default!; [Dependency] private readonly SharedTransformSystem _xformSystem = default!; @@ -276,7 +275,7 @@ private void HandleShuttleMovement(float frameTime) var gridId = xform.GridUid; // This tries to see if the grid is a shuttle and if the console should work. - if (!_mapManager.TryGetGrid(gridId, out var _) || + if (!TryComp(gridId, out var _) || !shuttleQuery.TryGetComponent(gridId, out var shuttleComponent) || !shuttleComponent.Enabled) continue; diff --git a/Content.Server/Physics/Controllers/PullController.cs b/Content.Server/Physics/Controllers/PullController.cs deleted file mode 100644 index 8f58f807aae..00000000000 --- a/Content.Server/Physics/Controllers/PullController.cs +++ /dev/null @@ -1,207 +0,0 @@ -using System.Numerics; -using Content.Shared.ActionBlocker; -using Content.Shared.Gravity; -using Content.Shared.Pulling; -using Content.Shared.Pulling.Components; -using Content.Shared.Rotatable; -using Robust.Shared.Physics; -using Robust.Shared.Physics.Components; -using Robust.Shared.Physics.Controllers; - -namespace Content.Server.Physics.Controllers -{ - public sealed class PullController : VirtualController - { - // Parameterization for pulling: - // Speeds. Note that the speed is mass-independent (multiplied by mass). - // Instead, tuning to mass is done via the mass values below. - // Note that setting the speed too high results in overshoots (stabilized by drag, but bad) - private const float AccelModifierHigh = 15f; - private const float AccelModifierLow = 60.0f; - // High/low-mass marks. Curve is constant-lerp-constant, i.e. if you can even pull an item, - // you'll always get at least AccelModifierLow and no more than AccelModifierHigh. - private const float AccelModifierHighMass = 70.0f; // roundstart saltern emergency closet - private const float AccelModifierLowMass = 5.0f; // roundstart saltern emergency crowbar - // Used to control settling (turns off pulling). - private const float MaximumSettleVelocity = 0.1f; - private const float MaximumSettleDistance = 0.1f; - // Settle shutdown control. - // Mustn't be too massive, as that causes severe mispredicts *and can prevent it ever resolving*. - // Exists to bleed off "I pulled my crowbar" overshoots. - // Minimum velocity for shutdown to be necessary. This prevents stuff getting stuck b/c too much shutdown. - private const float SettleMinimumShutdownVelocity = 0.25f; - // Distance in which settle shutdown multiplier is at 0. It then scales upwards linearly with closer distances. - private const float SettleShutdownDistance = 1.0f; - // Velocity change of -LinearVelocity * frameTime * this - private const float SettleShutdownMultiplier = 20.0f; - - // How much you must move for the puller movement check to actually hit. - private const float MinimumMovementDistance = 0.005f; - - [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; - [Dependency] private readonly SharedPullingSystem _pullableSystem = default!; - [Dependency] private readonly SharedGravitySystem _gravity = default!; - [Dependency] private readonly SharedTransformSystem _transform = default!; - - // TODO: Move this stuff to pullingsystem - /// - /// If distance between puller and pulled entity lower that this threshold, - /// pulled entity will not change its rotation. - /// Helps with small distance jittering - /// - private const float ThresholdRotDistance = 1; - - /// - /// If difference between puller and pulled angle lower that this threshold, - /// pulled entity will not change its rotation. - /// Helps with diagonal movement jittering - /// As of further adjustments, should divide cleanly into 90 degrees - /// - private const float ThresholdRotAngle = 22.5f; - - public override void Initialize() - { - UpdatesAfter.Add(typeof(MoverController)); - SubscribeLocalEvent(OnPullerMove); - - base.Initialize(); - } - - private void OnPullerMove(EntityUid uid, SharedPullerComponent component, ref MoveEvent args) - { - if (component.Pulling is not { } pullable || !TryComp(pullable, out var pullableComponent)) - return; - - UpdatePulledRotation(uid, pullable); - - if (args.NewPosition.EntityId == args.OldPosition.EntityId && - (args.NewPosition.Position - args.OldPosition.Position).LengthSquared() < MinimumMovementDistance * MinimumMovementDistance) - return; - - if (TryComp(pullable, out var physics)) - PhysicsSystem.WakeBody(pullable, body: physics); - - _pullableSystem.StopMoveTo(pullableComponent); - } - - private void UpdatePulledRotation(EntityUid puller, EntityUid pulled) - { - // TODO: update once ComponentReference works with directed event bus. - if (!TryComp(pulled, out RotatableComponent? rotatable)) - return; - - if (!rotatable.RotateWhilePulling) - return; - - var xforms = GetEntityQuery(); - var pulledXform = xforms.GetComponent(pulled); - var pullerXform = xforms.GetComponent(puller); - - var pullerData = TransformSystem.GetWorldPositionRotation(pullerXform, xforms); - var pulledData = TransformSystem.GetWorldPositionRotation(pulledXform, xforms); - - var dir = pullerData.WorldPosition - pulledData.WorldPosition; - if (dir.LengthSquared() > ThresholdRotDistance * ThresholdRotDistance) - { - var oldAngle = pulledData.WorldRotation; - var newAngle = Angle.FromWorldVec(dir); - - var diff = newAngle - oldAngle; - if (Math.Abs(diff.Degrees) > ThresholdRotAngle / 2f) - { - // Ok, so this bit is difficult because ideally it would look like it's snapping to sane angles. - // Otherwise PIANO DOOR STUCK! happens. - // But it also needs to work with station rotation / align to the local parent. - // So... - var baseRotation = pulledData.WorldRotation - pulledXform.LocalRotation; - var localRotation = newAngle - baseRotation; - var localRotationSnapped = Angle.FromDegrees(Math.Floor((localRotation.Degrees / ThresholdRotAngle) + 0.5f) * ThresholdRotAngle); - TransformSystem.SetLocalRotation(pulledXform, localRotationSnapped); - } - } - } - - public override void UpdateBeforeSolve(bool prediction, float frameTime) - { - base.UpdateBeforeSolve(prediction, frameTime); - - foreach (var pullable in _pullableSystem.Moving) - { - // There's a 1-frame delay between stopping moving something and it leaving the Moving set. - // This can include if leaving the Moving set due to not being pulled anymore, - // or due to being deleted. - - if (pullable.Deleted) - continue; - - if (pullable.MovingTo == null) - continue; - - if (pullable.Puller is not {Valid: true} puller) - continue; - - var pullableEnt = pullable.Owner; - var pullableXform = Transform(pullableEnt); - var pullerXform = Transform(puller); - - // Now that's over with... - - var pullerPosition = pullerXform.MapPosition; - var movingTo = pullable.MovingTo.Value.ToMap(EntityManager, _transform); - if (movingTo.MapId != pullerPosition.MapId) - { - _pullableSystem.StopMoveTo(pullable); - continue; - } - - if (!TryComp(pullableEnt, out var physics) || - physics.BodyType == BodyType.Static || - movingTo.MapId != pullableXform.MapID) - { - _pullableSystem.StopMoveTo(pullable); - continue; - } - - var movingPosition = movingTo.Position; - var ownerPosition = pullableXform.MapPosition.Position; - - var diff = movingPosition - ownerPosition; - var diffLength = diff.Length(); - - if (diffLength < MaximumSettleDistance && physics.LinearVelocity.Length() < MaximumSettleVelocity) - { - PhysicsSystem.SetLinearVelocity(pullableEnt, Vector2.Zero, body: physics); - _pullableSystem.StopMoveTo(pullable); - continue; - } - - var impulseModifierLerp = Math.Min(1.0f, Math.Max(0.0f, (physics.Mass - AccelModifierLowMass) / (AccelModifierHighMass - AccelModifierLowMass))); - var impulseModifier = MathHelper.Lerp(AccelModifierLow, AccelModifierHigh, impulseModifierLerp); - var multiplier = diffLength < 1 ? impulseModifier * diffLength : impulseModifier; - // Note the implication that the real rules of physics don't apply to pulling control. - var accel = diff.Normalized() * multiplier; - // Now for the part where velocity gets shutdown... - if (diffLength < SettleShutdownDistance && physics.LinearVelocity.Length() >= SettleMinimumShutdownVelocity) - { - // Shutdown velocity increases as we get closer to centre - var scaling = (SettleShutdownDistance - diffLength) / SettleShutdownDistance; - accel -= physics.LinearVelocity * SettleShutdownMultiplier * scaling; - } - - PhysicsSystem.WakeBody(pullableEnt, body: physics); - - var impulse = accel * physics.Mass * frameTime; - PhysicsSystem.ApplyLinearImpulse(pullableEnt, impulse, body: physics); - - // if the puller is weightless or can't move, then we apply the inverse impulse (Newton's third law). - // doing it under gravity produces an unsatisfying wiggling when pulling. - // If player can't move, assume they are on a chair and we need to prevent pull-moving. - if ((_gravity.IsWeightless(puller) && pullerXform.GridUid == null) || !_actionBlockerSystem.CanMove(puller)) - { - PhysicsSystem.WakeBody(puller); - PhysicsSystem.ApplyLinearImpulse(puller, -impulse); - } - } - } - } -} diff --git a/Content.Server/Polymorph/Systems/PolymorphSystem.cs b/Content.Server/Polymorph/Systems/PolymorphSystem.cs index 66dc9dab99d..5fe29dcd30e 100644 --- a/Content.Server/Polymorph/Systems/PolymorphSystem.cs +++ b/Content.Server/Polymorph/Systems/PolymorphSystem.cs @@ -32,7 +32,6 @@ public sealed partial class PolymorphSystem : EntitySystem [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly ActionsSystem _actions = default!; - [Dependency] private readonly ActionContainerSystem _actionContainer = default!; [Dependency] private readonly AudioSystem _audio = default!; [Dependency] private readonly SharedBuckleSystem _buckle = default!; [Dependency] private readonly ContainerSystem _container = default!; diff --git a/Content.Server/Power/EntitySystems/CableSystem.Placer.cs b/Content.Server/Power/EntitySystems/CableSystem.Placer.cs index c5ca36c3a15..263d626ef55 100644 --- a/Content.Server/Power/EntitySystems/CableSystem.Placer.cs +++ b/Content.Server/Power/EntitySystems/CableSystem.Placer.cs @@ -4,6 +4,7 @@ using Content.Shared.Interaction; using Content.Shared.Maps; using Content.Shared.Stacks; +using Robust.Shared.Map.Components; namespace Content.Server.Power.EntitySystems; @@ -25,7 +26,7 @@ private void OnCablePlacerAfterInteract(Entity placer, ref if (component.CablePrototypeId == null) return; - if(!_mapManager.TryGetGrid(args.ClickLocation.GetGridUid(EntityManager), out var grid)) + if(!TryComp(args.ClickLocation.GetGridUid(EntityManager), out var grid)) return; var snapPos = grid.TileIndicesFor(args.ClickLocation); diff --git a/Content.Server/Power/EntitySystems/CableSystem.cs b/Content.Server/Power/EntitySystems/CableSystem.cs index dd478753be3..62eb08d7cbc 100644 --- a/Content.Server/Power/EntitySystems/CableSystem.cs +++ b/Content.Server/Power/EntitySystems/CableSystem.cs @@ -5,10 +5,7 @@ using Content.Shared.Database; using Content.Shared.DoAfter; using Content.Shared.Interaction; -using Content.Shared.Tools; -using Content.Shared.Tools.Components; using Robust.Shared.Map; -using System.Xml.Schema; using CableCuttingFinishedEvent = Content.Shared.Tools.Systems.CableCuttingFinishedEvent; using SharedToolSystem = Content.Shared.Tools.Systems.SharedToolSystem; @@ -16,13 +13,11 @@ namespace Content.Server.Power.EntitySystems; public sealed partial class CableSystem : EntitySystem { - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly ITileDefinitionManager _tileManager = default!; [Dependency] private readonly SharedToolSystem _toolSystem = default!; [Dependency] private readonly StackSystem _stack = default!; [Dependency] private readonly ElectrocutionSystem _electrocutionSystem = default!; [Dependency] private readonly IAdminLogManager _adminLogs = default!; - [Dependency] private readonly PowerMonitoringConsoleSystem _powerMonitoringSystem = default!; public override void Initialize() { diff --git a/Content.Server/Power/EntitySystems/CableVisSystem.cs b/Content.Server/Power/EntitySystems/CableVisSystem.cs index fcf0ae3d58d..ec08523d447 100644 --- a/Content.Server/Power/EntitySystems/CableVisSystem.cs +++ b/Content.Server/Power/EntitySystems/CableVisSystem.cs @@ -4,15 +4,13 @@ using Content.Server.Power.Nodes; using Content.Shared.Wires; using JetBrains.Annotations; -using Robust.Server.GameObjects; -using Robust.Shared.Map; +using Robust.Shared.Map.Components; namespace Content.Server.Power.EntitySystems { [UsedImplicitly] public sealed class CableVisSystem : EntitySystem { - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly NodeContainerSystem _nodeContainer = default!; @@ -32,7 +30,7 @@ private void UpdateAppearance(EntityUid uid, CableVisComponent cableVis, ref Nod return; var transform = Transform(uid); - if (!_mapManager.TryGetGrid(transform.GridUid, out var grid)) + if (!TryComp(transform.GridUid, out var grid)) return; var mask = WireVisDirFlags.None; diff --git a/Content.Server/Power/EntitySystems/ExtensionCableSystem.cs b/Content.Server/Power/EntitySystems/ExtensionCableSystem.cs index acfb8ff87b3..85e553031fc 100644 --- a/Content.Server/Power/EntitySystems/ExtensionCableSystem.cs +++ b/Content.Server/Power/EntitySystems/ExtensionCableSystem.cs @@ -1,6 +1,5 @@ using System.Diagnostics.CodeAnalysis; using Content.Server.Power.Components; -using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; @@ -9,8 +8,6 @@ namespace Content.Server.Power.EntitySystems { public sealed class ExtensionCableSystem : EntitySystem { - [Dependency] private readonly IMapManager _mapManager = default!; - public override void Initialize() { base.Initialize(); diff --git a/Content.Server/Power/Generator/PortableGeneratorSystem.cs b/Content.Server/Power/Generator/PortableGeneratorSystem.cs index e8e9c5b45e3..e7dfa351789 100644 --- a/Content.Server/Power/Generator/PortableGeneratorSystem.cs +++ b/Content.Server/Power/Generator/PortableGeneratorSystem.cs @@ -1,5 +1,4 @@ using Content.Server.DoAfter; -using Content.Server.NodeContainer.NodeGroups; using Content.Server.Popups; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; @@ -28,7 +27,6 @@ public sealed class PortableGeneratorSystem : SharedPortableGeneratorSystem [Dependency] private readonly GeneratorSystem _generator = default!; [Dependency] private readonly PowerSwitchableSystem _switchable = default!; [Dependency] private readonly ActiveGeneratorRevvingSystem _revving = default!; - [Dependency] private readonly PowerNetSystem _powerNet = default!; public override void Initialize() { diff --git a/Content.Server/PowerSink/PowerSinkSystem.cs b/Content.Server/PowerSink/PowerSinkSystem.cs index 298e35db469..903cb7ce12e 100644 --- a/Content.Server/PowerSink/PowerSinkSystem.cs +++ b/Content.Server/PowerSink/PowerSinkSystem.cs @@ -8,6 +8,7 @@ using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Content.Server.Power.EntitySystems; +using Content.Server.Announcements.Systems; namespace Content.Server.PowerSink { @@ -33,6 +34,7 @@ public sealed class PowerSinkSystem : EntitySystem [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly StationSystem _station = default!; [Dependency] private readonly BatterySystem _battery = default!; + [Dependency] private readonly AnnouncerSystem _announcer = default!; public override void Initialize() { @@ -126,12 +128,9 @@ private void NotifyStationOfImminentExplosion(EntityUid uid, PowerSinkComponent if (station == null) return; - _chat.DispatchStationAnnouncement( - station.Value, - Loc.GetString("powersink-immiment-explosion-announcement"), - playDefaultSound: true, - colorOverride: Color.Yellow - ); + _announcer.SendAnnouncement(_announcer.GetAnnouncementId("PowerSinkExplosion"), + _station.GetInOwningStation(station.Value), "powersink-immiment-explosion-announcement", + colorOverride: Color.Yellow, station: station.Value); } } } diff --git a/Content.Server/Pulling/PullingSystem.cs b/Content.Server/Pulling/PullingSystem.cs deleted file mode 100644 index 69bb7c93704..00000000000 --- a/Content.Server/Pulling/PullingSystem.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Content.Shared.Input; -using Content.Shared.Pulling; -using Content.Shared.Pulling.Components; -using JetBrains.Annotations; -using Robust.Server.GameObjects; -using Robust.Shared.Input.Binding; -using Robust.Shared.Player; - -namespace Content.Server.Pulling -{ - [UsedImplicitly] - public sealed class PullingSystem : SharedPullingSystem - { - public override void Initialize() - { - base.Initialize(); - - UpdatesAfter.Add(typeof(PhysicsSystem)); - - SubscribeLocalEvent(OnPullableMove); - SubscribeLocalEvent(OnPullableStopMove); - - CommandBinds.Builder - .Bind(ContentKeyFunctions.ReleasePulledObject, InputCmdHandler.FromDelegate(HandleReleasePulledObject)) - .Register(); - } - - private void HandleReleasePulledObject(ICommonSession? session) - { - if (session?.AttachedEntity is not {Valid: true} player) - { - return; - } - - if (!TryGetPulled(player, out var pulled)) - { - return; - } - - if (!EntityManager.TryGetComponent(pulled.Value, out SharedPullableComponent? pullable)) - { - return; - } - - TryStopPull(pullable); - } - } -} diff --git a/Content.Server/RatKing/RatKingSystem.cs b/Content.Server/RatKing/RatKingSystem.cs index f676e89ac3f..4b82dba3359 100644 --- a/Content.Server/RatKing/RatKingSystem.cs +++ b/Content.Server/RatKing/RatKingSystem.cs @@ -11,7 +11,6 @@ using Content.Shared.Nutrition.EntitySystems; using Content.Shared.Pointing; using Content.Shared.RatKing; -using Robust.Server.GameObjects; using Robust.Shared.Map; using Robust.Shared.Random; @@ -26,7 +25,6 @@ public sealed class RatKingSystem : SharedRatKingSystem [Dependency] private readonly HungerSystem _hunger = default!; [Dependency] private readonly NPCSystem _npc = default!; [Dependency] private readonly PopupSystem _popup = default!; - [Dependency] private readonly TransformSystem _xform = default!; public override void Initialize() { diff --git a/Content.Server/Remotes/DoorRemoteComponent.cs b/Content.Server/Remotes/DoorRemoteComponent.cs deleted file mode 100644 index 91cb7ccad10..00000000000 --- a/Content.Server/Remotes/DoorRemoteComponent.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Content.Server.Remotes -{ - [RegisterComponent] - [Access(typeof(DoorRemoteSystem))] - public sealed partial class DoorRemoteComponent : Component - { - public OperatingMode Mode = OperatingMode.OpenClose; - - public enum OperatingMode : byte - { - OpenClose, - ToggleBolts, - ToggleEmergencyAccess - } - } -} diff --git a/Content.Server/Remotes/DoorRemoteSystem.cs b/Content.Server/Remotes/DoorRemoteSystem.cs index d335911901a..e42bc700912 100644 --- a/Content.Server/Remotes/DoorRemoteSystem.cs +++ b/Content.Server/Remotes/DoorRemoteSystem.cs @@ -1,74 +1,43 @@ using Content.Server.Administration.Logs; -using Robust.Shared.Player; using Content.Shared.Interaction; -using Content.Shared.Popups; using Content.Shared.Doors.Components; -using Content.Shared.Doors.Systems; -using Content.Shared.Physics; using Content.Shared.Access.Components; using Content.Server.Doors.Systems; using Content.Server.Power.EntitySystems; using Content.Shared.Database; -using Content.Shared.Interaction.Events; using Content.Shared.Examine; -using static Content.Server.Remotes.DoorRemoteComponent; +using Content.Shared.Remotes.EntitySystems; +using Content.Shared.Remotes.Components; -namespace Content.Server.Remotes +namespace Content.Shared.Remotes { - public sealed class DoorRemoteSystem : EntitySystem + public sealed class DoorRemoteSystem : SharedDoorRemoteSystem { [Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly AirlockSystem _airlock = default!; - [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly DoorSystem _doorSystem = default!; [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; [Dependency] private readonly ExamineSystemShared _examine = default!; // I'm so sorry [Dependency] private readonly SharedAirlockSystem _sharedAirlockSystem = default!; - + public override void Initialize() { - SubscribeLocalEvent(OnInHandActivation); - SubscribeLocalEvent(OnBeforeInteract); - } - - public void OnInHandActivation(EntityUid user, DoorRemoteComponent component, UseInHandEvent args) - { - string switchMessageId; - switch (component.Mode) - { - case OperatingMode.OpenClose: - component.Mode = OperatingMode.ToggleBolts; - switchMessageId = "door-remote-switch-state-toggle-bolts"; - break; + base.Initialize(); - // Skip toggle bolts mode and move on from there (to emergency access) - case OperatingMode.ToggleBolts: - component.Mode = OperatingMode.ToggleEmergencyAccess; - switchMessageId = "door-remote-switch-state-toggle-emergency-access"; - break; - - // Skip ToggleEmergencyAccess mode and move on from there (to door toggle) - case OperatingMode.ToggleEmergencyAccess: - component.Mode = OperatingMode.OpenClose; - switchMessageId = "door-remote-switch-state-open-close"; - break; - default: - throw new InvalidOperationException( - $"{nameof(DoorRemoteComponent)} had invalid mode {component.Mode}"); - } - ShowPopupToUser(switchMessageId, args.User); + SubscribeLocalEvent(OnBeforeInteract); } - private void OnBeforeInteract(EntityUid uid, DoorRemoteComponent component, BeforeRangedInteractEvent args) + private void OnBeforeInteract(Entity entity, ref BeforeRangedInteractEvent args) { bool isAirlock = TryComp(args.Target, out var airlockComp); if (args.Handled || args.Target == null || !TryComp(args.Target, out var doorComp) // If it isn't a door we don't use it - // Only able to control doors if they are within your vision and within your max range. - // Not affected by mobs or machines anymore. + // Only able to control doors if they are within your vision and within your max range. + // Not affected by mobs or machines anymore. || !_examine.InRangeUnOccluded(args.User, args.Target.Value, SharedInteractionSystem.MaxRaycastRange, null)) + { return; } @@ -77,7 +46,7 @@ private void OnBeforeInteract(EntityUid uid, DoorRemoteComponent component, Befo if (!this.IsPowered(args.Target.Value, EntityManager)) { - ShowPopupToUser("door-remote-no-power", args.User); + Popup.PopupEntity(Loc.GetString("door-remote-no-power"), args.User, args.User); return; } @@ -85,11 +54,11 @@ private void OnBeforeInteract(EntityUid uid, DoorRemoteComponent component, Befo && !_doorSystem.HasAccess(args.Target.Value, args.Used, doorComp, accessComponent)) { _doorSystem.Deny(args.Target.Value, doorComp, args.User); - ShowPopupToUser("door-remote-denied", args.User); + Popup.PopupEntity(Loc.GetString("door-remote-denied"), args.User, args.User); return; } - switch (component.Mode) + switch (entity.Comp.Mode) { case OperatingMode.OpenClose: if (_doorSystem.TryToggleDoor(args.Target.Value, doorComp, args.Used)) @@ -115,11 +84,8 @@ private void OnBeforeInteract(EntityUid uid, DoorRemoteComponent component, Befo break; default: throw new InvalidOperationException( - $"{nameof(DoorRemoteComponent)} had invalid mode {component.Mode}"); + $"{nameof(DoorRemoteComponent)} had invalid mode {entity.Comp.Mode}"); } } - - private void ShowPopupToUser(string messageId, EntityUid user) => - _popupSystem.PopupEntity(Loc.GetString(messageId), user, user); } } diff --git a/Content.Server/Research/Systems/ResearchStealerSystem.cs b/Content.Server/Research/Systems/ResearchStealerSystem.cs index 5bab6048de5..d40134f1e9f 100644 --- a/Content.Server/Research/Systems/ResearchStealerSystem.cs +++ b/Content.Server/Research/Systems/ResearchStealerSystem.cs @@ -1,11 +1,13 @@ using Content.Shared.Research.Components; using Content.Shared.Research.Systems; +using Robust.Shared.Random; namespace Content.Server.Research.Systems; public sealed class ResearchStealerSystem : SharedResearchStealerSystem { [Dependency] private readonly SharedResearchSystem _research = default!; + [Dependency] private readonly IRobustRandom _random = default!; public override void Initialize() { @@ -24,16 +26,26 @@ private void OnDoAfter(EntityUid uid, ResearchStealerComponent comp, ResearchSte if (!TryComp(target, out var database)) return; - var ev = new ResearchStolenEvent(uid, target, database.UnlockedTechnologies); + var ev = new ResearchStolenEvent(uid, target, new()); + var count = _random.Next(comp.MinToSteal, comp.MaxToSteal + 1); + for (var i = 0; i < count; i++) + { + if (database.UnlockedTechnologies.Count == 0) + break; + + var toRemove = _random.Pick(database.UnlockedTechnologies); + if (_research.TryRemoveTechnology((target, database), toRemove)) + ev.Techs.Add(toRemove); + } RaiseLocalEvent(uid, ref ev); - // oops, no more advanced lasers! - _research.ClearTechs(target, database); + + args.Handled = true; } } /// -/// Event raised on the user when research is stolen from a R&D server. +/// Event raised on the user when research is stolen from a RND server. /// Techs contains every technology id researched. /// [ByRefEvent] -public record struct ResearchStolenEvent(EntityUid Used, EntityUid Target, List Techs); +public record struct ResearchStolenEvent(EntityUid Used, EntityUid Target, List Techs); diff --git a/Content.Server/Respawn/SpecialRespawnSystem.cs b/Content.Server/Respawn/SpecialRespawnSystem.cs index 2822c94093f..2463bcd7402 100644 --- a/Content.Server/Respawn/SpecialRespawnSystem.cs +++ b/Content.Server/Respawn/SpecialRespawnSystem.cs @@ -9,13 +9,13 @@ using Content.Shared.Physics; using Content.Shared.Respawn; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Random; namespace Content.Server.Respawn; public sealed class SpecialRespawnSystem : SharedSpecialRespawnSystem { - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IAdminLogManager _adminLog = default!; [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!; [Dependency] private readonly AtmosphereSystem _atmosphere = default!; @@ -84,7 +84,7 @@ private void OnTermination(EntityUid uid, SpecialRespawnComponent component, ref if (!component.Respawn || !HasComp(entityGridUid) || entityMapUid == null) return; - if (!_mapManager.TryGetGrid(entityGridUid, out var grid) || MetaData(entityGridUid.Value).EntityLifeStage >= EntityLifeStage.Terminating) + if (!TryComp(entityGridUid, out var grid) || MetaData(entityGridUid.Value).EntityLifeStage >= EntityLifeStage.Terminating) return; if (TryFindRandomTile(entityGridUid.Value, entityMapUid.Value, 10, out var coords)) @@ -146,7 +146,7 @@ public bool TryFindRandomTile(EntityUid targetGrid, EntityUid targetMap, int max { targetCoords = EntityCoordinates.Invalid; - if (!_mapManager.TryGetGrid(targetGrid, out var grid)) + if (!TryComp(targetGrid, out var grid)) return false; var xform = Transform(targetGrid); diff --git a/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs b/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs index eb6eb5a426f..cd64f043a08 100644 --- a/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs +++ b/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs @@ -2,7 +2,6 @@ using Content.Shared.Damage; using Content.Shared.Revenant; using Robust.Shared.Random; -using Robust.Shared.Map; using Content.Shared.Tag; using Content.Server.Storage.Components; using Content.Server.Light.Components; @@ -15,7 +14,6 @@ using Content.Shared.Bed.Sleep; using System.Linq; using System.Numerics; -using Content.Server.Maps; using Content.Server.Revenant.Components; using Content.Shared.DoAfter; using Content.Shared.Emag.Systems; @@ -28,12 +26,12 @@ using Content.Shared.Revenant.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Utility; +using Robust.Shared.Map.Components; namespace Content.Server.Revenant.EntitySystems; public sealed partial class RevenantSystem { - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly ThrowingSystem _throwing = default!; [Dependency] private readonly EntityStorageSystem _entityStorage = default!; [Dependency] private readonly EmagSystem _emag = default!; @@ -213,7 +211,7 @@ private void OnDefileAction(EntityUid uid, RevenantComponent component, Revenant //var coords = Transform(uid).Coordinates; //var gridId = coords.GetGridUid(EntityManager); var xform = Transform(uid); - if (!_mapManager.TryGetGrid(xform.GridUid, out var map)) + if (!TryComp(xform.GridUid, out var map)) return; var tiles = map.GetTilesIntersecting(Box2.CenteredAround(xform.WorldPosition, new Vector2(component.DefileRadius * 2, component.DefileRadius))).ToArray(); diff --git a/Content.Server/Roles/RemoveRoleCommand.cs b/Content.Server/Roles/RemoveRoleCommand.cs index edb29da624f..feba63a253f 100644 --- a/Content.Server/Roles/RemoveRoleCommand.cs +++ b/Content.Server/Roles/RemoveRoleCommand.cs @@ -5,14 +5,12 @@ using Content.Shared.Roles.Jobs; using Robust.Server.Player; using Robust.Shared.Console; -using Robust.Shared.Prototypes; namespace Content.Server.Roles { [AdminCommand(AdminFlags.Admin)] public sealed class RemoveRoleCommand : IConsoleCommand { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!; public string Command => "rmrole"; diff --git a/Content.Server/RoundEnd/RoundEndSystem.cs b/Content.Server/RoundEnd/RoundEndSystem.cs index 3a8331f3f7a..d79fe2d2cca 100644 --- a/Content.Server/RoundEnd/RoundEndSystem.cs +++ b/Content.Server/RoundEnd/RoundEndSystem.cs @@ -22,6 +22,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Timing; using Timer = Robust.Shared.Timing.Timer; +using Content.Server.Announcements.Systems; namespace Content.Server.RoundEnd { @@ -42,6 +43,7 @@ public sealed class RoundEndSystem : EntitySystem [Dependency] private readonly EmergencyShuttleSystem _shuttle = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly StationSystem _stationSystem = default!; + [Dependency] private readonly AnnouncerSystem _announcer = default!; public TimeSpan DefaultCooldownDuration { get; set; } = TimeSpan.FromSeconds(30); @@ -176,15 +178,16 @@ public void RequestRoundEnd(TimeSpan countdownTime, EntityUid? requester = null, units = "eta-units-minutes"; } - _chatSystem.DispatchGlobalAnnouncement(Loc.GetString(text, - ("time", time), - ("units", Loc.GetString(units))), + _announcer.SendAnnouncement(_announcer.GetAnnouncementId("ShuttleCalled"), + Filter.Broadcast(), + text, name, - false, + Color.Gold, null, - Color.Gold); - - _audio.PlayGlobal("/Audio/Announcements/shuttlecalled.ogg", Filter.Broadcast(), true); + null, + ("time", time), + ("units", Loc.GetString(units)) + ); LastCountdownStart = _gameTiming.CurTime; ExpectedCountdownEnd = _gameTiming.CurTime + countdownTime; @@ -227,10 +230,13 @@ public void CancelRoundEndCountdown(EntityUid? requester = null, bool checkCoold _adminLogger.Add(LogType.ShuttleRecalled, LogImpact.High, $"Shuttle recalled"); } - _chatSystem.DispatchGlobalAnnouncement(Loc.GetString("round-end-system-shuttle-recalled-announcement"), - Loc.GetString("Station"), false, colorOverride: Color.Gold); - - _audio.PlayGlobal("/Audio/Announcements/shuttlerecalled.ogg", Filter.Broadcast(), true); + _announcer.SendAnnouncement( + _announcer.GetAnnouncementId("ShuttleRecalled"), + Filter.Broadcast(), + "round-end-system-shuttle-recalled-announcement", + Loc.GetString("Station"), + Color.Gold + ); LastCountdownStart = null; ExpectedCountdownEnd = null; @@ -309,9 +315,13 @@ public void DoRoundEndBehavior(RoundEndBehavior behavior, // Check is shuttle called or not. We should only dispatch announcement if it's already called if (IsRoundEndRequested()) { - _chatSystem.DispatchGlobalAnnouncement(Loc.GetString(textAnnounce), + _announcer.SendAnnouncement( + _announcer.GetAnnouncementId("ShuttleCalled"), + Filter.Broadcast(), + textAnnounce, Loc.GetString(sender), - colorOverride: Color.Gold); + Color.Gold + ); } else { diff --git a/Content.Server/Salvage/SalvageSystem.Expeditions.cs b/Content.Server/Salvage/SalvageSystem.Expeditions.cs index 7e4a9c9310e..36e3a574ea0 100644 --- a/Content.Server/Salvage/SalvageSystem.Expeditions.cs +++ b/Content.Server/Salvage/SalvageSystem.Expeditions.cs @@ -162,6 +162,8 @@ private void SpawnMission(SalvageMissionParams missionParams, EntityUid station) _biome, _dungeon, _metaData, + _transform, + _mapSystem, station, missionParams, cancelToken.Token); diff --git a/Content.Server/Salvage/SalvageSystem.cs b/Content.Server/Salvage/SalvageSystem.cs index a1a3b686b2f..5a68005dd3a 100644 --- a/Content.Server/Salvage/SalvageSystem.cs +++ b/Content.Server/Salvage/SalvageSystem.cs @@ -53,6 +53,7 @@ public sealed partial class SalvageSystem : SharedSalvageSystem [Dependency] private readonly RadioSystem _radioSystem = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly SharedMapSystem _mapSystem = default!; [Dependency] private readonly ShuttleSystem _shuttle = default!; [Dependency] private readonly ShuttleConsoleSystem _shuttleConsoles = default!; [Dependency] private readonly StationSystem _station = default!; diff --git a/Content.Server/Salvage/SpawnSalvageMissionJob.cs b/Content.Server/Salvage/SpawnSalvageMissionJob.cs index e2b17b58724..5f7e356830c 100644 --- a/Content.Server/Salvage/SpawnSalvageMissionJob.cs +++ b/Content.Server/Salvage/SpawnSalvageMissionJob.cs @@ -46,6 +46,8 @@ public sealed class SpawnSalvageMissionJob : Job private readonly BiomeSystem _biome; private readonly DungeonSystem _dungeon; private readonly MetaDataSystem _metaData; + private readonly SharedTransformSystem _xforms; + private readonly SharedMapSystem _map; public readonly EntityUid Station; private readonly SalvageMissionParams _missionParams; @@ -63,6 +65,8 @@ public SpawnSalvageMissionJob( BiomeSystem biome, DungeonSystem dungeon, MetaDataSystem metaData, + SharedTransformSystem xform, + SharedMapSystem map, EntityUid station, SalvageMissionParams missionParams, CancellationToken cancellation = default) : base(maxTime, cancellation) @@ -75,6 +79,8 @@ public SpawnSalvageMissionJob( _biome = biome; _dungeon = dungeon; _metaData = metaData; + _xforms = xform; + _map = map; Station = station; _missionParams = missionParams; _sawmill = logManager.GetSawmill("salvage_job"); @@ -86,9 +92,7 @@ public SpawnSalvageMissionJob( protected override async Task Process() { _sawmill.Debug("salvage", $"Spawning salvage mission with seed {_missionParams.Seed}"); - var mapId = _mapManager.CreateMap(); - var mapUid = _mapManager.GetMapEntityId(mapId); - _mapManager.AddUninitializedMap(mapId); + var mapUid = _map.CreateMap(out var mapId, runMapInit: false); MetaDataComponent? metadata = null; var grid = _entManager.EnsureComponent(mapUid); var random = new Random(_missionParams.Seed); diff --git a/Content.Server/Sandbox/Commands/ColorNetworkCommand.cs b/Content.Server/Sandbox/Commands/ColorNetworkCommand.cs index 2ab29d1b2f0..6ce8edd1d84 100644 --- a/Content.Server/Sandbox/Commands/ColorNetworkCommand.cs +++ b/Content.Server/Sandbox/Commands/ColorNetworkCommand.cs @@ -11,7 +11,6 @@ namespace Content.Server.Sandbox.Commands [AnyCommand] public sealed class ColorNetworkCommand : IConsoleCommand { - [Dependency] private readonly IAdminManager _adminManager = default!; [Dependency] private readonly IEntityManager _entManager = default!; public string Command => "colornetwork"; diff --git a/Content.Server/Shuttles/Systems/ArrivalsSystem.cs b/Content.Server/Shuttles/Systems/ArrivalsSystem.cs index f4dd502b375..ae742cf1f9e 100644 --- a/Content.Server/Shuttles/Systems/ArrivalsSystem.cs +++ b/Content.Server/Shuttles/Systems/ArrivalsSystem.cs @@ -1,13 +1,10 @@ using System.Linq; -using System.Numerics; using Content.Server.Administration; using Content.Server.GameTicking; using Content.Server.GameTicking.Events; using Content.Server.Parallax; -using Content.Server.DeviceNetwork; using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Systems; -using Content.Server.Salvage; using Content.Server.Screens.Components; using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Events; @@ -22,7 +19,6 @@ using Content.Shared.Parallax.Biomes; using Content.Shared.Salvage; using Content.Shared.Shuttles.Components; -using Robust.Shared.Spawners; using Content.Shared.Tiles; using Robust.Server.GameObjects; using Robust.Shared.Collections; @@ -51,7 +47,6 @@ public sealed class ArrivalsSystem : EntitySystem [Dependency] private readonly GameTicker _ticker = default!; [Dependency] private readonly MapLoaderSystem _loader = default!; [Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!; - [Dependency] private readonly RestrictedRangeSystem _restricted = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly ShuttleSystem _shuttles = default!; [Dependency] private readonly StationSpawningSystem _stationSpawning = default!; diff --git a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs index aeb2ebdbba1..3f6eafb454c 100644 --- a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs +++ b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs @@ -209,7 +209,13 @@ private void UpdateEmergencyConsole(float frameTime) if (!ShuttlesLeft && _consoleAccumulator <= 0f) { ShuttlesLeft = true; - _chatSystem.DispatchGlobalAnnouncement(Loc.GetString("emergency-shuttle-left", ("transitTime", $"{TransitTime:0}"))); + _announcer.SendAnnouncement( + _announcer.GetAnnouncementId("ShuttleLeft"), + Filter.Broadcast(), + "emergency-shuttle-left", + null, null, null, null, + ("transitTime", $"{TransitTime:0}") + ); Timer.Spawn((int) (TransitTime * 1000) + _bufferTime.Milliseconds, () => _roundEnd.EndRound(), _roundEndCancelToken?.Token ?? default); } @@ -248,7 +254,13 @@ private void OnEmergencyRepealAll(EntityUid uid, EmergencyShuttleConsoleComponen return; _logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle early launch REPEAL ALL by {args.Session:user}"); - _chatSystem.DispatchGlobalAnnouncement(Loc.GetString("emergency-shuttle-console-auth-revoked", ("remaining", component.AuthorizationsRequired))); + _announcer.SendAnnouncement( + _announcer.GetAnnouncementId("ShuttleAuthRevoked"), + Filter.Broadcast(), + "emergency-shuttle-console-auth-revoked", + null, null, null, null, + ("remaining", component.AuthorizationsRequired) + ); component.AuthorizedEntities.Clear(); UpdateAllEmergencyConsoles(); } @@ -271,7 +283,13 @@ private void OnEmergencyRepeal(EntityUid uid, EmergencyShuttleConsoleComponent c _logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle early launch REPEAL by {args.Session:user}"); var remaining = component.AuthorizationsRequired - component.AuthorizedEntities.Count; - _chatSystem.DispatchGlobalAnnouncement(Loc.GetString("emergency-shuttle-console-auth-revoked", ("remaining", remaining))); + _announcer.SendAnnouncement( + _announcer.GetAnnouncementId("ShuttleAuthRevoked"), + Filter.Broadcast(), + "emergency-shuttle-console-auth-revoked", + null, null, null, null, + ("remaining", remaining) + ); CheckForLaunch(component); UpdateAllEmergencyConsoles(); } @@ -296,9 +314,14 @@ private void OnEmergencyAuthorize(EntityUid uid, EmergencyShuttleConsoleComponen var remaining = component.AuthorizationsRequired - component.AuthorizedEntities.Count; if (remaining > 0) - _chatSystem.DispatchGlobalAnnouncement( - Loc.GetString("emergency-shuttle-console-auth-left", ("remaining", remaining)), - playSound: false, colorOverride: DangerColor); + _announcer.SendAnnouncement(_announcer.GetAnnouncementId("ShuttleAuthAdded"), + Filter.Broadcast(), + "emergency-shuttle-console-auth-left", + null, + DangerColor, + null, null, + ("remaining", remaining) + ); if (!CheckForLaunch(component)) _audio.PlayGlobal("/Audio/Misc/notice1.ogg", Filter.Broadcast(), recordReplay: true); @@ -399,12 +422,13 @@ private void AnnounceLaunch() if (_announced) return; _announced = true; - _chatSystem.DispatchGlobalAnnouncement( - Loc.GetString("emergency-shuttle-launch-time", ("consoleAccumulator", $"{_consoleAccumulator:0}")), - playSound: false, - colorOverride: DangerColor); - - _audio.PlayGlobal("/Audio/Misc/notice1.ogg", Filter.Broadcast(), recordReplay: true); + _announcer.SendAnnouncement( + _announcer.GetAnnouncementId("ShuttleAlmostLaunching"), + Filter.Broadcast(), + "emergency-shuttle-launch-time", + null, null, null, null, + ("consoleAccumulator", $"{_consoleAccumulator:0}") + ); } public bool DelayEmergencyRoundEnd() diff --git a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs index f8d995b8a4b..5cbc10e4f60 100644 --- a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs @@ -33,6 +33,7 @@ using Robust.Shared.Player; using Robust.Shared.Random; using Robust.Shared.Timing; +using Content.Server.Announcements.Systems; namespace Content.Server.Shuttles.Systems; @@ -63,6 +64,7 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem [Dependency] private readonly StationSystem _station = default!; [Dependency] private readonly TransformSystem _transformSystem = default!; [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; + [Dependency] private readonly AnnouncerSystem _announcer = default!; private const float ShuttleSpawnBuffer = 1f; @@ -268,9 +270,8 @@ public void CallEmergencyShuttle(EntityUid stationUid, StationEmergencyShuttleCo if (targetGrid == null) { _logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle {ToPrettyString(stationUid)} unable to dock with station {ToPrettyString(stationUid)}"); - _chatSystem.DispatchStationAnnouncement(stationUid, Loc.GetString("emergency-shuttle-good-luck"), playDefaultSound: false); - // TODO: Need filter extensions or something don't blame me. - _audio.PlayGlobal("/Audio/Misc/notice1.ogg", Filter.Broadcast(), true); + _announcer.SendAnnouncement(_announcer.GetAnnouncementId("ShuttleGoodLuck"), Filter.Broadcast(), + "emergency-shuttle-good-luck", colorOverride: DangerColor); return; } @@ -281,7 +282,13 @@ public void CallEmergencyShuttle(EntityUid stationUid, StationEmergencyShuttleCo if (TryComp(targetGrid.Value, out var targetXform)) { var angle = _dock.GetAngle(stationShuttle.EmergencyShuttle.Value, xform, targetGrid.Value, targetXform, xformQuery); - _chatSystem.DispatchStationAnnouncement(stationUid, Loc.GetString("emergency-shuttle-docked", ("time", $"{_consoleAccumulator:0}"), ("direction", angle.GetDir())), playDefaultSound: false); + _announcer.SendAnnouncementMessage( + _announcer.GetAnnouncementId("ShuttleDock"), + "emergency-shuttle-docked", + null, null, null, null, + ("time", $"{_consoleAccumulator:0}"), + ("direction", angle.GetDir()) + ); } // shuttle timers @@ -302,20 +309,23 @@ public void CallEmergencyShuttle(EntityUid stationUid, StationEmergencyShuttleCo } _logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle {ToPrettyString(stationUid)} docked with stations"); - // TODO: Need filter extensions or something don't blame me. - _audio.PlayGlobal("/Audio/Announcements/shuttle_dock.ogg", Filter.Broadcast(), true); + _announcer.SendAnnouncementAudio(_announcer.GetAnnouncementId("ShuttleDock"), Filter.Broadcast()); } else { if (TryComp(targetGrid.Value, out var targetXform)) { var angle = _dock.GetAngle(stationShuttle.EmergencyShuttle.Value, xform, targetGrid.Value, targetXform, xformQuery); - _chatSystem.DispatchStationAnnouncement(stationUid, Loc.GetString("emergency-shuttle-nearby", ("direction", angle.GetDir())), playDefaultSound: false); + _announcer.SendAnnouncementMessage( + _announcer.GetAnnouncementId("ShuttleNearby"), + "emergency-shuttle-nearby", + null, null, null, null, + ("direction", angle.GetDir()) + ); } _logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle {ToPrettyString(stationUid)} unable to find a valid docking port for {ToPrettyString(stationUid)}"); - // TODO: Need filter extensions or something don't blame me. - _audio.PlayGlobal("/Audio/Misc/notice1.ogg", Filter.Broadcast(), true); + _announcer.SendAnnouncementAudio(_announcer.GetAnnouncementId("ShuttleNearby"), Filter.Broadcast()); } } @@ -492,7 +502,7 @@ private void AddEmergencyShuttle(EntityUid uid, StationEmergencyShuttleComponent return; } - centcomm.ShuttleIndex += _mapManager.GetGrid(shuttle.Value).LocalAABB.Width + ShuttleSpawnBuffer; + centcomm.ShuttleIndex += Comp(shuttle.Value).LocalAABB.Width + ShuttleSpawnBuffer; // Update indices for all centcomm comps pointing to same map var query = AllEntityQuery(); diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs index e4e4534b0c5..cb322ac3964 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs @@ -559,7 +559,7 @@ private void UpdateHyperspace(float frameTime) private float GetSoundRange(EntityUid uid) { - if (!_mapManager.TryGetGrid(uid, out var grid)) + if (!TryComp(uid, out var grid)) return 4f; return MathF.Max(grid.LocalAABB.Width, grid.LocalAABB.Height) + 12.5f; diff --git a/Content.Server/Shuttles/Systems/ThrusterSystem.cs b/Content.Server/Shuttles/Systems/ThrusterSystem.cs index 1baffd4690e..74c42ccbc53 100644 --- a/Content.Server/Shuttles/Systems/ThrusterSystem.cs +++ b/Content.Server/Shuttles/Systems/ThrusterSystem.cs @@ -1,6 +1,5 @@ using System.Numerics; using Content.Server.Audio; -using Content.Server.Construction; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Server.Shuttles.Components; @@ -12,6 +11,7 @@ using Content.Shared.Shuttles.Components; using Content.Shared.Temperature; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Physics.Collision.Shapes; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; @@ -24,7 +24,6 @@ namespace Content.Server.Shuttles.Systems; public sealed class ThrusterSystem : EntitySystem { [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly ITileDefinitionManager _tileDefManager = default!; [Dependency] private readonly AmbientSoundSystem _ambient = default!; [Dependency] private readonly FixtureSystem _fixtureSystem = default!; @@ -95,7 +94,7 @@ private void OnShuttleTileChange(EntityUid uid, ShuttleComponent component, ref return; var tilePos = args.NewTile.GridIndices; - var grid = _mapManager.GetGrid(uid); + var grid = Comp(uid); var xformQuery = GetEntityQuery(); var thrusterQuery = GetEntityQuery(); @@ -436,7 +435,7 @@ private bool NozzleExposed(TransformComponent xform) return true; var (x, y) = xform.LocalPosition + xform.LocalRotation.Opposite().ToWorldVec(); - var tile = _mapManager.GetGrid(xform.GridUid.Value).GetTileRef(new Vector2i((int) Math.Floor(x), (int) Math.Floor(y))); + var tile = Comp(xform.GridUid.Value).GetTileRef(new Vector2i((int) Math.Floor(x), (int) Math.Floor(y))); return tile.Tile.IsSpace(); } diff --git a/Content.Server/Silicons/Laws/SiliconLawSystem.cs b/Content.Server/Silicons/Laws/SiliconLawSystem.cs index 4584a9e88b5..010682bc0d3 100644 --- a/Content.Server/Silicons/Laws/SiliconLawSystem.cs +++ b/Content.Server/Silicons/Laws/SiliconLawSystem.cs @@ -19,7 +19,6 @@ using Content.Shared.Stunnable; using Content.Shared.Wires; using Robust.Server.GameObjects; -using Robust.Shared.Audio.Systems; using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Toolshed; @@ -38,7 +37,6 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem [Dependency] private readonly SharedStunSystem _stunSystem = default!; [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly SharedRoleSystem _roles = default!; - [Dependency] private readonly SharedAudioSystem _audioSystem = default!; /// public override void Initialize() diff --git a/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs b/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs index ba07375699b..ed53c3e1018 100644 --- a/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs +++ b/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs @@ -232,7 +232,7 @@ public void ConsumeEntitiesInContainer(EntityUid hungry, BaseContainer container /// public void ConsumeTile(EntityUid hungry, TileRef tile, EventHorizonComponent eventHorizon) { - ConsumeTiles(hungry, new List<(Vector2i, Tile)>(new[] { (tile.GridIndices, Tile.Empty) }), tile.GridUid, _mapMan.GetGrid(tile.GridUid), eventHorizon); + ConsumeTiles(hungry, new List<(Vector2i, Tile)>(new[] { (tile.GridIndices, Tile.Empty) }), tile.GridUid, Comp(tile.GridUid), eventHorizon); } /// @@ -240,7 +240,7 @@ public void ConsumeTile(EntityUid hungry, TileRef tile, EventHorizonComponent ev /// public void AttemptConsumeTile(EntityUid hungry, TileRef tile, EventHorizonComponent eventHorizon) { - AttemptConsumeTiles(hungry, new TileRef[1] { tile }, tile.GridUid, _mapMan.GetGrid(tile.GridUid), eventHorizon); + AttemptConsumeTiles(hungry, new TileRef[1] { tile }, tile.GridUid, Comp(tile.GridUid), eventHorizon); } /// diff --git a/Content.Server/Singularity/EntitySystems/RadiationCollectorSystem.cs b/Content.Server/Singularity/EntitySystems/RadiationCollectorSystem.cs index 92b963e2017..b26ab301c64 100644 --- a/Content.Server/Singularity/EntitySystems/RadiationCollectorSystem.cs +++ b/Content.Server/Singularity/EntitySystems/RadiationCollectorSystem.cs @@ -24,7 +24,6 @@ public sealed class RadiationCollectorSystem : EntitySystem [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedContainerSystem _containerSystem = default!; [Dependency] private readonly UseDelaySystem _useDelay = default!; - [Dependency] private readonly BatterySystem _batterySystem = default!; private const string GasTankContainer = "gas_tank"; diff --git a/Content.Server/Species/Systems/NymphSystem.cs b/Content.Server/Species/Systems/NymphSystem.cs index b7751afbf18..d491b957bfb 100644 --- a/Content.Server/Species/Systems/NymphSystem.cs +++ b/Content.Server/Species/Systems/NymphSystem.cs @@ -19,10 +19,10 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnRemovedFromPart); + SubscribeLocalEvent(OnRemovedFromPart); } - private void OnRemovedFromPart(EntityUid uid, NymphComponent comp, RemovedFromPartInBodyEvent args) + private void OnRemovedFromPart(EntityUid uid, NymphComponent comp, ref OrganRemovedFromBodyEvent args) { if (!_timing.IsFirstTimePredicted) return; diff --git a/Content.Server/Spreader/SpreaderSystem.cs b/Content.Server/Spreader/SpreaderSystem.cs index 5b2f3298a2b..671c281d1f4 100644 --- a/Content.Server/Spreader/SpreaderSystem.cs +++ b/Content.Server/Spreader/SpreaderSystem.cs @@ -18,7 +18,6 @@ namespace Content.Server.Spreader; /// public sealed class SpreaderSystem : EntitySystem { - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IRobustRandom _robustRandom = default!; [Dependency] private readonly SharedMapSystem _map = default!; diff --git a/Content.Server/Standing/LayingDownComponent.cs b/Content.Server/Standing/LayingDownComponent.cs new file mode 100644 index 00000000000..7921749f148 --- /dev/null +++ b/Content.Server/Standing/LayingDownComponent.cs @@ -0,0 +1,14 @@ +namespace Content.Server.Standing; + +[RegisterComponent] +public sealed partial class LayingDownComponent : Component +{ + [DataField] + public float DownedSpeedMultiplier = 0.15f; + + [DataField] + public TimeSpan Cooldown = TimeSpan.FromSeconds(2.5f); + + [DataField] + public TimeSpan NextToggleAttempt = TimeSpan.Zero; +} diff --git a/Content.Server/Standing/LayingDownSystem.cs b/Content.Server/Standing/LayingDownSystem.cs new file mode 100644 index 00000000000..69787ae8308 --- /dev/null +++ b/Content.Server/Standing/LayingDownSystem.cs @@ -0,0 +1,101 @@ +using Content.Shared.ActionBlocker; +using Content.Shared.Input; +using Content.Shared.Movement.Systems; +using Content.Shared.Popups; +using Content.Shared.Standing; +using Robust.Shared.Input.Binding; +using Robust.Shared.Player; +using Robust.Shared.Timing; + +namespace Content.Server.Standing; + +/// Unfortunately cannot be shared because some standing conditions are server-side only +public sealed class LayingDownSystem : EntitySystem +{ + [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!; + [Dependency] private readonly MovementSpeedModifierSystem _movement = default!; + [Dependency] private readonly SharedPopupSystem _popups = default!; + [Dependency] private readonly Shared.Standing.StandingStateSystem _standing = default!; // WHY IS THERE TWO DIFFERENT STANDING SYSTEMS?! + [Dependency] private readonly IGameTiming _timing = default!; + + + public override void Initialize() + { + CommandBinds.Builder + .Bind(ContentKeyFunctions.ToggleStanding, InputCmdHandler.FromDelegate(ToggleStanding, handle: false, outsidePrediction: false)) + .Register(); + + SubscribeLocalEvent(DoRefreshMovementSpeed); + SubscribeLocalEvent(DoRefreshMovementSpeed); + SubscribeLocalEvent(OnRefreshMovementSpeed); + SubscribeLocalEvent(OnParentChanged); + } + + public override void Shutdown() + { + base.Shutdown(); + + CommandBinds.Unregister(); + } + + private void DoRefreshMovementSpeed(EntityUid uid, LayingDownComponent component, object args) + { + _movement.RefreshMovementSpeedModifiers(uid); + } + + private void OnRefreshMovementSpeed(EntityUid uid, LayingDownComponent component, RefreshMovementSpeedModifiersEvent args) + { + if (TryComp(uid, out var standingState) && standingState.Standing) + return; + + args.ModifySpeed(component.DownedSpeedMultiplier, component.DownedSpeedMultiplier); + } + + private void OnParentChanged(EntityUid uid, LayingDownComponent component, EntParentChangedMessage args) + { + // If the entity is not on a grid, try to make it stand up to avoid issues + if (!TryComp(uid, out var standingState) + || standingState.Standing + || Transform(uid).GridUid != null) + return; + + _standing.Stand(uid, standingState); + } + + private void ToggleStanding(ICommonSession? session) + { + if (session is not { AttachedEntity: { Valid: true } uid } playerSession + || !Exists(uid) + || !TryComp(uid, out var standingState) + || !TryComp(uid, out var layingDown)) + return; + + // If successful, show popup to self and others. Otherwise, only to self. + if (ToggleStandingImpl(uid, standingState, layingDown, out var popupBranch)) + { + _popups.PopupEntity(Loc.GetString($"laying-comp-{popupBranch}-other", ("entity", uid)), uid, Filter.PvsExcept(uid), true); + layingDown.NextToggleAttempt = _timing.CurTime + layingDown.Cooldown; + } + + _popups.PopupEntity(Loc.GetString($"laying-comp-{popupBranch}-self", ("entity", uid)), uid, uid); + } + + private bool ToggleStandingImpl(EntityUid uid, StandingStateComponent standingState, LayingDownComponent layingDown, out string popupBranch) + { + var success = layingDown.NextToggleAttempt <= _timing.CurTime; + + if (_standing.IsDown(uid, standingState)) + { + success = success && _standing.Stand(uid, standingState, force: false); + popupBranch = success ? "stand-success" : "stand-fail"; + } + else + { + success = success && Transform(uid).GridUid != null; // Do not allow laying down when not on a surface. + success = success && _standing.Down(uid, standingState: standingState, playSound: true, dropHeldItems: false); + popupBranch = success ? "lay-success" : "lay-fail"; + } + + return success; + } +} diff --git a/Content.Server/Station/Systems/StationJobsSystem.cs b/Content.Server/Station/Systems/StationJobsSystem.cs index a3b7a573545..debac8902e2 100644 --- a/Content.Server/Station/Systems/StationJobsSystem.cs +++ b/Content.Server/Station/Systems/StationJobsSystem.cs @@ -25,7 +25,6 @@ public sealed partial class StationJobsSystem : EntitySystem [Dependency] private readonly IConfigurationManager _configurationManager = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly GameTicker _gameTicker = default!; - [Dependency] private readonly StationSystem _stationSystem = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; /// diff --git a/Content.Server/Station/Systems/StationSystem.cs b/Content.Server/Station/Systems/StationSystem.cs index b9ff8a4339d..492f15c8e2b 100644 --- a/Content.Server/Station/Systems/StationSystem.cs +++ b/Content.Server/Station/Systems/StationSystem.cs @@ -29,7 +29,6 @@ public sealed class StationSystem : EntitySystem { [Dependency] private readonly IConfigurationManager _configurationManager = default!; [Dependency] private readonly ILogManager _logManager = default!; - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IPlayerManager _player = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly ChatSystem _chatSystem = default!; diff --git a/Content.Server/StationEvents/Components/RampingStationEventSchedulerComponent.cs b/Content.Server/StationEvents/Components/RampingStationEventSchedulerComponent.cs index 53bc8b62a43..282ee5b612a 100644 --- a/Content.Server/StationEvents/Components/RampingStationEventSchedulerComponent.cs +++ b/Content.Server/StationEvents/Components/RampingStationEventSchedulerComponent.cs @@ -3,6 +3,30 @@ [RegisterComponent, Access(typeof(RampingStationEventSchedulerSystem))] public sealed partial class RampingStationEventSchedulerComponent : Component { + /// + /// The maximum number by which the event rate will be multiplied when shift time reaches the end time. + /// + [DataField] + public float ChaosModifier = 3f; + + /// + /// The minimum number by which the event rate will be multiplied when the shift has just begun. + /// + [DataField] + public float StartingChaosRatio = 0.1f; + + /// + /// The number by which all event delays will be multiplied. Unlike chaos, remains constant throughout the shift. + /// + [DataField] + public float EventDelayModifier = 1f; + + /// + /// The number by which average expected shift length is multiplied. Higher values lead to slower chaos growth. + /// + public float ShiftLengthModifier = 1f; + + // Everything below is overridden in the RampingStationEventSchedulerSystem based on CVars [DataField("endTime"), ViewVariables(VVAccess.ReadWrite)] public float EndTime; diff --git a/Content.Server/StationEvents/Components/StationEventComponent.cs b/Content.Server/StationEvents/Components/StationEventComponent.cs index b4456a4b5b7..980034aa7b7 100644 --- a/Content.Server/StationEvents/Components/StationEventComponent.cs +++ b/Content.Server/StationEvents/Components/StationEventComponent.cs @@ -19,16 +19,10 @@ public sealed partial class StationEventComponent : Component public float Weight = WeightNormal; [DataField("startAnnouncement")] - public string? StartAnnouncement; + public bool StartAnnouncement; [DataField("endAnnouncement")] - public string? EndAnnouncement; - - [DataField("startAudio")] - public SoundSpecifier? StartAudio; - - [DataField("endAudio")] - public SoundSpecifier? EndAudio; + public bool EndAnnouncement; /// /// In minutes, when is the first round time this event can start diff --git a/Content.Server/StationEvents/Events/AnomalySpawnRule.cs b/Content.Server/StationEvents/Events/AnomalySpawnRule.cs index 48a3b900c44..4cd94d3e719 100644 --- a/Content.Server/StationEvents/Events/AnomalySpawnRule.cs +++ b/Content.Server/StationEvents/Events/AnomalySpawnRule.cs @@ -2,20 +2,29 @@ using Content.Server.GameTicking.Rules.Components; using Content.Server.Station.Components; using Content.Server.StationEvents.Components; +using Content.Server.Announcements.Systems; +using Robust.Shared.Player; namespace Content.Server.StationEvents.Events; public sealed class AnomalySpawnRule : StationEventSystem { [Dependency] private readonly AnomalySystem _anomaly = default!; + [Dependency] private readonly AnnouncerSystem _announcer = default!; protected override void Added(EntityUid uid, AnomalySpawnRuleComponent component, GameRuleComponent gameRule, GameRuleAddedEvent args) { base.Added(uid, component, gameRule, args); - var str = Loc.GetString("anomaly-spawn-event-announcement", - ("sighting", Loc.GetString($"anomaly-spawn-sighting-{RobustRandom.Next(1, 6)}"))); - ChatSystem.DispatchGlobalAnnouncement(str, colorOverride: Color.FromHex("#18abf5")); + _announcer.SendAnnouncement( + _announcer.GetAnnouncementId(args.RuleId), + Filter.Broadcast(), + "anomaly-spawn-event-announcement", + null, + Color.FromHex("#18abf5"), + null, null, + ("sighting", Loc.GetString($"anomaly-spawn-sighting-{RobustRandom.Next(1, 6)}")) + ); } protected override void Started(EntityUid uid, AnomalySpawnRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args) diff --git a/Content.Server/StationEvents/Events/BluespaceArtifactRule.cs b/Content.Server/StationEvents/Events/BluespaceArtifactRule.cs index 0eed77f1543..b25c1d6561c 100644 --- a/Content.Server/StationEvents/Events/BluespaceArtifactRule.cs +++ b/Content.Server/StationEvents/Events/BluespaceArtifactRule.cs @@ -1,18 +1,28 @@ using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; using Robust.Shared.Random; +using Content.Server.Announcements.Systems; +using Robust.Shared.Player; namespace Content.Server.StationEvents.Events; public sealed class BluespaceArtifactRule : StationEventSystem { + [Dependency] private readonly AnnouncerSystem _announcer = default!; + protected override void Added(EntityUid uid, BluespaceArtifactRuleComponent component, GameRuleComponent gameRule, GameRuleAddedEvent args) { base.Added(uid, component, gameRule, args); - var str = Loc.GetString("bluespace-artifact-event-announcement", - ("sighting", Loc.GetString(RobustRandom.Pick(component.PossibleSighting)))); - ChatSystem.DispatchGlobalAnnouncement(str, colorOverride: Color.FromHex("#18abf5")); + _announcer.SendAnnouncement( + _announcer.GetAnnouncementId(args.RuleId), + Filter.Broadcast(), + "bluespace-artifact-event-announcement", + null, + Color.FromHex("#18abf5"), + null, null, + ("sighting", Loc.GetString(RobustRandom.Pick(component.PossibleSighting))) + ); } protected override void Started(EntityUid uid, BluespaceArtifactRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args) diff --git a/Content.Server/StationEvents/Events/BreakerFlipRule.cs b/Content.Server/StationEvents/Events/BreakerFlipRule.cs index 494779fe350..b465cc1f556 100644 --- a/Content.Server/StationEvents/Events/BreakerFlipRule.cs +++ b/Content.Server/StationEvents/Events/BreakerFlipRule.cs @@ -4,6 +4,8 @@ using Content.Server.Station.Components; using Content.Server.StationEvents.Components; using JetBrains.Annotations; +using Content.Server.Announcements.Systems; +using Robust.Shared.Player; namespace Content.Server.StationEvents.Events; @@ -11,13 +13,21 @@ namespace Content.Server.StationEvents.Events; public sealed class BreakerFlipRule : StationEventSystem { [Dependency] private readonly ApcSystem _apcSystem = default!; + [Dependency] private readonly AnnouncerSystem _announcer = default!; protected override void Added(EntityUid uid, BreakerFlipRuleComponent component, GameRuleComponent gameRule, GameRuleAddedEvent args) { base.Added(uid, component, gameRule, args); - var str = Loc.GetString("station-event-breaker-flip-announcement", ("data", Loc.GetString(Loc.GetString($"random-sentience-event-data-{RobustRandom.Next(1, 6)}")))); - ChatSystem.DispatchGlobalAnnouncement(str, playSound: false, colorOverride: Color.Gold); + _announcer.SendAnnouncement( + _announcer.GetAnnouncementId(args.RuleId), + Filter.Broadcast(), + "station-event-breaker-flip-announcement", + null, + Color.Gold, + null, null, + ("data", Loc.GetString(Loc.GetString($"random-sentience-event-data-{RobustRandom.Next(1, 6)}"))) + ); } protected override void Started(EntityUid uid, BreakerFlipRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args) diff --git a/Content.Server/StationEvents/Events/CargoGiftsRule.cs b/Content.Server/StationEvents/Events/CargoGiftsRule.cs index c174cc48c09..80af23c6fa4 100644 --- a/Content.Server/StationEvents/Events/CargoGiftsRule.cs +++ b/Content.Server/StationEvents/Events/CargoGiftsRule.cs @@ -6,6 +6,8 @@ using Content.Server.Station.Components; using Content.Server.StationEvents.Components; using Robust.Shared.Prototypes; +using Content.Server.Announcements.Systems; +using Robust.Shared.Player; namespace Content.Server.StationEvents.Events; @@ -14,14 +16,23 @@ public sealed class CargoGiftsRule : StationEventSystem [Dependency] private readonly CargoSystem _cargoSystem = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly GameTicker _ticker = default!; + [Dependency] private readonly AnnouncerSystem _announcer = default!; protected override void Added(EntityUid uid, CargoGiftsRuleComponent component, GameRuleComponent gameRule, GameRuleAddedEvent args) { base.Added(uid, component, gameRule, args); - var str = Loc.GetString(component.Announce, - ("sender", Loc.GetString(component.Sender)), ("description", Loc.GetString(component.Description)), ("dest", Loc.GetString(component.Dest))); - ChatSystem.DispatchGlobalAnnouncement(str, colorOverride: Color.FromHex("#18abf5")); + _announcer.SendAnnouncement( + _announcer.GetAnnouncementId(args.RuleId), + Filter.Broadcast(), + component.Announce, + null, + Color.FromHex("#18abf5"), + null, null, + ("sender", Loc.GetString(component.Sender)), + ("description", Loc.GetString(component.Description)), + ("dest", Loc.GetString(component.Dest)) + ); } /// diff --git a/Content.Server/StationEvents/Events/FalseAlarmRule.cs b/Content.Server/StationEvents/Events/FalseAlarmRule.cs index 05e9435b40a..e971a0aa982 100644 --- a/Content.Server/StationEvents/Events/FalseAlarmRule.cs +++ b/Content.Server/StationEvents/Events/FalseAlarmRule.cs @@ -4,6 +4,7 @@ using JetBrains.Annotations; using Robust.Shared.Player; using Robust.Shared.Random; +using Content.Server.Announcements.Systems; namespace Content.Server.StationEvents.Events; @@ -11,18 +12,20 @@ namespace Content.Server.StationEvents.Events; public sealed class FalseAlarmRule : StationEventSystem { [Dependency] private readonly EventManagerSystem _event = default!; + [Dependency] private readonly AnnouncerSystem _announcer = default!; protected override void Started(EntityUid uid, FalseAlarmRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args) { base.Started(uid, component, gameRule, args); - var allEv = _event.AllEvents().Select(p => p.Value).ToList(); + var allEv = _event.AllEvents().Select(p => p.Key).ToList(); var picked = RobustRandom.Pick(allEv); - if (picked.StartAnnouncement != null) - { - ChatSystem.DispatchGlobalAnnouncement(Loc.GetString(picked.StartAnnouncement), playSound: false, colorOverride: Color.Gold); - } - Audio.PlayGlobal(picked.StartAudio, Filter.Broadcast(), true); + _announcer.SendAnnouncement( + _announcer.GetAnnouncementId(picked.ID), + Filter.Broadcast(), + _announcer.GetEventLocaleString(_announcer.GetAnnouncementId(picked.ID)), + colorOverride: Color.Gold + ); } } diff --git a/Content.Server/StationEvents/Events/NinjaSpawnRule.cs b/Content.Server/StationEvents/Events/NinjaSpawnRule.cs index c60f3298e74..8ad5c8602e3 100644 --- a/Content.Server/StationEvents/Events/NinjaSpawnRule.cs +++ b/Content.Server/StationEvents/Events/NinjaSpawnRule.cs @@ -2,10 +2,8 @@ using Content.Server.Ninja.Systems; using Content.Server.Station.Components; using Content.Server.StationEvents.Components; -using Robust.Server.GameObjects; using Robust.Shared.Map; using Robust.Shared.Map.Components; -using Robust.Shared.Random; namespace Content.Server.StationEvents.Events; @@ -14,7 +12,6 @@ namespace Content.Server.StationEvents.Events; /// public sealed class NinjaSpawnRule : StationEventSystem { - [Dependency] private readonly SpaceNinjaSystem _ninja = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; protected override void Started(EntityUid uid, NinjaSpawnRuleComponent comp, GameRuleComponent gameRule, GameRuleStartedEvent args) diff --git a/Content.Server/StationEvents/Events/PowerGridCheckRule.cs b/Content.Server/StationEvents/Events/PowerGridCheckRule.cs index 5503438df8a..97e89484612 100644 --- a/Content.Server/StationEvents/Events/PowerGridCheckRule.cs +++ b/Content.Server/StationEvents/Events/PowerGridCheckRule.cs @@ -54,13 +54,6 @@ protected override void Ended(EntityUid uid, PowerGridCheckRuleComponent compone } } - // Can't use the default EndAudio - component.AnnounceCancelToken?.Cancel(); - component.AnnounceCancelToken = new CancellationTokenSource(); - Timer.Spawn(3000, () => - { - Audio.PlayGlobal("/Audio/Announcements/power_on.ogg", Filter.Broadcast(), true, AudioParams.Default.WithVolume(-4f)); - }, component.AnnounceCancelToken.Token); component.Unpowered.Clear(); } diff --git a/Content.Server/StationEvents/Events/RandomSentienceRule.cs b/Content.Server/StationEvents/Events/RandomSentienceRule.cs index 4b7606d01f9..f667ad79750 100644 --- a/Content.Server/StationEvents/Events/RandomSentienceRule.cs +++ b/Content.Server/StationEvents/Events/RandomSentienceRule.cs @@ -2,11 +2,15 @@ using Content.Server.GameTicking.Rules.Components; using Content.Server.Ghost.Roles.Components; using Content.Server.StationEvents.Components; +using Content.Server.Announcements.Systems; +using Content.Server.Station.Components; namespace Content.Server.StationEvents.Events; public sealed class RandomSentienceRule : StationEventSystem { + [Dependency] private readonly AnnouncerSystem _announcer = default!; + protected override void Started(EntityUid uid, RandomSentienceRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args) { HashSet stationsToNotify = new(); @@ -53,14 +57,16 @@ protected override void Started(EntityUid uid, RandomSentienceRuleComponent comp } foreach (var station in stationsToNotify) { - ChatSystem.DispatchStationAnnouncement( - station, - Loc.GetString("station-event-random-sentience-announcement", - ("kind1", kind1), ("kind2", kind2), ("kind3", kind3), ("amount", groupList.Count), + _announcer.SendAnnouncement( + _announcer.GetAnnouncementId(args.RuleId), + StationSystem.GetInStation(EntityManager.GetComponent(station)), + "station-event-random-sentience-announcement", + null, + Color.Gold, + null, null, + ("kind1", kind1), ("kind2", kind2), ("kind3", kind3), ("amount", groupList.Count), ("data", Loc.GetString($"random-sentience-event-data-{RobustRandom.Next(1, 6)}")), - ("strength", Loc.GetString($"random-sentience-event-strength-{RobustRandom.Next(1, 8)}"))), - playDefaultSound: false, - colorOverride: Color.Gold + ("strength", Loc.GetString($"random-sentience-event-strength-{RobustRandom.Next(1, 8)}")) ); } } diff --git a/Content.Server/StationEvents/Events/StationEventSystem.cs b/Content.Server/StationEvents/Events/StationEventSystem.cs index 7f05f8940d9..6de8024bd0a 100644 --- a/Content.Server/StationEvents/Events/StationEventSystem.cs +++ b/Content.Server/StationEvents/Events/StationEventSystem.cs @@ -9,6 +9,9 @@ using Robust.Shared.Map; using Robust.Shared.Player; using Robust.Shared.Prototypes; +using Content.Server.Announcements.Systems; +using Robust.Shared.Player; +using Content.Server.Station.Components; namespace Content.Server.StationEvents.Events; @@ -23,6 +26,7 @@ public abstract class StationEventSystem : GameRuleSystem where T : ICompo [Dependency] protected readonly ChatSystem ChatSystem = default!; [Dependency] protected readonly SharedAudioSystem Audio = default!; [Dependency] protected readonly StationSystem StationSystem = default!; + [Dependency] private readonly AnnouncerSystem _announcer = default!; protected ISawmill Sawmill = default!; @@ -43,12 +47,6 @@ protected override void Added(EntityUid uid, T component, GameRuleComponent game AdminLogManager.Add(LogType.EventAnnounced, $"Event added / announced: {ToPrettyString(uid)}"); - if (stationEvent.StartAnnouncement != null) - { - ChatSystem.DispatchGlobalAnnouncement(Loc.GetString(stationEvent.StartAnnouncement), playSound: false, colorOverride: Color.Gold); - } - - Audio.PlayGlobal(stationEvent.StartAudio, Filter.Broadcast(), true); stationEvent.StartTime = Timing.CurTime + stationEvent.StartDelay; } @@ -62,6 +60,16 @@ protected override void Started(EntityUid uid, T component, GameRuleComponent ga AdminLogManager.Add(LogType.EventStarted, LogImpact.High, $"Event started: {ToPrettyString(uid)}"); + if (stationEvent.StartAnnouncement) + { + _announcer.SendAnnouncement( + _announcer.GetAnnouncementId(args.RuleId), + Filter.Broadcast(), + _announcer.GetEventLocaleString(_announcer.GetAnnouncementId(args.RuleId)), + colorOverride: Color.Gold + ); + } + if (stationEvent.Duration != null) { var duration = stationEvent.MaxDuration == null @@ -82,12 +90,14 @@ protected override void Ended(EntityUid uid, T component, GameRuleComponent game AdminLogManager.Add(LogType.EventStopped, $"Event ended: {ToPrettyString(uid)}"); - if (stationEvent.EndAnnouncement != null) + if (stationEvent.EndAnnouncement) { - ChatSystem.DispatchGlobalAnnouncement(Loc.GetString(stationEvent.EndAnnouncement), playSound: false, colorOverride: Color.Gold); + _announcer.SendAnnouncement( + _announcer.GetAnnouncementId(args.RuleId, true), + Filter.Broadcast(), + _announcer.GetEventLocaleString(_announcer.GetAnnouncementId(args.RuleId, true)), + colorOverride: Color.Gold); } - - Audio.PlayGlobal(stationEvent.EndAudio, Filter.Broadcast(), true); } /// diff --git a/Content.Server/StationEvents/RampingStationEventSchedulerSystem.cs b/Content.Server/StationEvents/RampingStationEventSchedulerSystem.cs index 53a98e8b762..aa0c9b214b4 100644 --- a/Content.Server/StationEvents/RampingStationEventSchedulerSystem.cs +++ b/Content.Server/StationEvents/RampingStationEventSchedulerSystem.cs @@ -29,15 +29,15 @@ protected override void Started(EntityUid uid, RampingStationEventSchedulerCompo { base.Started(uid, component, gameRule, args); - var avgChaos = _cfg.GetCVar(CCVars.EventsRampingAverageChaos); - var avgTime = _cfg.GetCVar(CCVars.EventsRampingAverageEndTime); + var avgChaos = _cfg.GetCVar(CCVars.EventsRampingAverageChaos) * component.ChaosModifier; + var avgTime = _cfg.GetCVar(CCVars.EventsRampingAverageEndTime) * component.ShiftLengthModifier; // Worlds shittiest probability distribution // Got a complaint? Send them to - component.MaxChaos = _random.NextFloat(avgChaos - avgChaos / 4, avgChaos + avgChaos / 4); + component.MaxChaos = avgChaos * _random.NextFloat(0.75f, 1.25f); // This is in minutes, so *60 for seconds (for the chaos calc) - component.EndTime = _random.NextFloat(avgTime - avgTime / 4, avgTime + avgTime / 4) * 60f; - component.StartingChaos = component.MaxChaos / 10; + component.EndTime = avgTime * _random.NextFloat(0.75f, 1.25f) * 60f; + component.StartingChaos = component.MaxChaos * component.StartingChaosRatio; PickNextEventTime(uid, component); } @@ -68,9 +68,10 @@ public override void Update(float frameTime) private void PickNextEventTime(EntityUid uid, RampingStationEventSchedulerComponent component) { - var mod = GetChaosModifier(uid, component); + component.TimeUntilNextEvent = _random.NextFloat( + _cfg.GetCVar(CCVars.GameEventsRampingMinimumTime), + _cfg.GetCVar(CCVars.GameEventsRampingMaximumTime)); - component.TimeUntilNextEvent = _random.NextFloat(_cfg.GetCVar(CCVars.GameEventsRampingMinimumTime) / mod, - _cfg.GetCVar(CCVars.GameEventsRampingMaximumTime)) / mod; + component.TimeUntilNextEvent *= component.EventDelayModifier / GetChaosModifier(uid, component); } } diff --git a/Content.Server/SubFloor/SubFloorHideSystem.cs b/Content.Server/SubFloor/SubFloorHideSystem.cs index 7820badcebf..2767f500f9a 100644 --- a/Content.Server/SubFloor/SubFloorHideSystem.cs +++ b/Content.Server/SubFloor/SubFloorHideSystem.cs @@ -1,5 +1,6 @@ using Content.Shared.Construction.Components; using Content.Shared.SubFloor; +using Robust.Shared.Map.Components; namespace Content.Server.SubFloor; @@ -17,7 +18,7 @@ private void OnAnchorAttempt(EntityUid uid, SubFloorHideComponent component, Anc // No teleporting entities through floor tiles when anchoring them. var xform = Transform(uid); - if (MapManager.TryGetGrid(xform.GridUid, out var grid) + if (TryComp(xform.GridUid, out var grid) && HasFloorCover(grid, grid.TileIndicesFor(xform.Coordinates))) { args.Cancel(); diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSpeakerSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSpeakerSystem.cs index 7544fc376ba..0e694a801eb 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSpeakerSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSpeakerSystem.cs @@ -1,10 +1,7 @@ using Content.Server.Chat.Systems; using Content.Server.Speech; using Content.Shared.Speech; -using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; -using Robust.Shared.Prototypes; -using Robust.Shared.Random; using Robust.Shared.Timing; namespace Content.Server.SurveillanceCamera; @@ -18,8 +15,6 @@ public sealed class SurveillanceCameraSpeakerSystem : EntitySystem [Dependency] private readonly SpeechSoundSystem _speechSound = default!; [Dependency] private readonly ChatSystem _chatSystem = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly IRobustRandom _random = default!; /// public override void Initialize() diff --git a/Content.Server/Temperature/Systems/TemperatureSystem.cs b/Content.Server/Temperature/Systems/TemperatureSystem.cs index aef4b89d509..0f57da4b881 100644 --- a/Content.Server/Temperature/Systems/TemperatureSystem.cs +++ b/Content.Server/Temperature/Systems/TemperatureSystem.cs @@ -11,7 +11,6 @@ using Content.Shared.Inventory; using Content.Shared.Rejuvenate; using Content.Shared.Temperature; -using Robust.Server.GameObjects; using Robust.Shared.Physics.Components; namespace Content.Server.Temperature.Systems; @@ -22,7 +21,6 @@ public sealed class TemperatureSystem : EntitySystem [Dependency] private readonly AtmosphereSystem _atmosphere = default!; [Dependency] private readonly DamageableSystem _damageable = default!; [Dependency] private readonly IAdminLogManager _adminLogger = default!; - [Dependency] private readonly TransformSystem _transform = default!; /// /// All the components that will have their damage updated at the end of the tick. @@ -163,8 +161,9 @@ public float GetHeatCapacity(EntityUid uid, TemperatureComponent? comp = null, P { return Atmospherics.MinimumHeatCapacity; } - - return comp.SpecificHeat * physics.FixturesMass; + if (physics.Mass < 1) + return comp.SpecificHeat; + else return comp.SpecificHeat * physics.FixturesMass; } private void OnInit(EntityUid uid, InternalTemperatureComponent comp, MapInitEvent args) diff --git a/Content.Server/Traits/Assorted/ForeignerTraitComponent.cs b/Content.Server/Traits/Assorted/ForeignerTraitComponent.cs new file mode 100644 index 00000000000..756f44e7429 --- /dev/null +++ b/Content.Server/Traits/Assorted/ForeignerTraitComponent.cs @@ -0,0 +1,38 @@ +using Content.Shared.Language; +using Content.Shared.Language.Systems; +using Robust.Shared.Prototypes; + +namespace Content.Server.Traits.Assorted; + +/// +/// When applied to a not-yet-spawned player entity, removes from the lists of their languages +/// and gives them a translator instead. +/// +[RegisterComponent] +public sealed partial class ForeignerTraitComponent : Component +{ + /// + /// The "base" language that is to be removed and substituted with a translator. + /// By default, equals to the fallback language, which is GalacticCommon. + /// + [DataField] + public ProtoId BaseLanguage = SharedLanguageSystem.FallbackLanguagePrototype; + + /// + /// Whether this trait prevents the entity from understanding the base language. + /// + [DataField] + public bool CantUnderstand = true; + + /// + /// Whether this trait prevents the entity from speaking the base language. + /// + [DataField] + public bool CantSpeak = true; + + /// + /// The base translator prototype to use when creating a translator for the entity. + /// + [DataField(required: true)] + public ProtoId BaseTranslator = default!; +} diff --git a/Content.Server/Traits/Assorted/ForeignerTraitSystem.cs b/Content.Server/Traits/Assorted/ForeignerTraitSystem.cs new file mode 100644 index 00000000000..58e974227ce --- /dev/null +++ b/Content.Server/Traits/Assorted/ForeignerTraitSystem.cs @@ -0,0 +1,105 @@ +using System.Linq; +using Content.Server.Hands.Systems; +using Content.Server.Language; +using Content.Server.Storage.EntitySystems; +using Content.Shared.Clothing.Components; +using Content.Shared.Inventory; +using Content.Shared.Language; +using Content.Shared.Language.Components; +using Content.Shared.Language.Components.Translators; +using Content.Shared.Storage; +using Robust.Shared.Prototypes; + +namespace Content.Server.Traits.Assorted; + + +public sealed partial class ForeignerTraitSystem : EntitySystem +{ + [Dependency] private readonly EntityManager _entMan = default!; + [Dependency] private readonly HandsSystem _hands = default!; + [Dependency] private readonly InventorySystem _inventory = default!; + [Dependency] private readonly LanguageSystem _languages = default!; + [Dependency] private readonly StorageSystem _storage = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnSpawn); // TraitSystem adds it after PlayerSpawnCompleteEvent so it's fine + } + + private void OnSpawn(Entity entity, ref ComponentInit args) + { + if (entity.Comp.CantUnderstand && !entity.Comp.CantSpeak) + Log.Warning($"Allowing entity {entity.Owner} to speak a language but not understand it leads to undefined behavior."); + + if (!TryComp(entity, out var knowledge)) + { + Log.Warning($"Entity {entity.Owner} does not have a LanguageKnowledge but has a ForeignerTrait!"); + return; + } + + var alternateLanguage = knowledge.SpokenLanguages.Find(it => it != entity.Comp.BaseLanguage); + if (alternateLanguage == null) + { + Log.Warning($"Entity {entity.Owner} does not have an alternative language to choose from (must have at least one non-GC for ForeignerTrait)!"); + return; + } + + if (TryGiveTranslator(entity.Owner, entity.Comp.BaseTranslator, entity.Comp.BaseLanguage, alternateLanguage, out var translator)) + { + _languages.RemoveLanguage(entity, entity.Comp.BaseLanguage, entity.Comp.CantSpeak, entity.Comp.CantUnderstand, knowledge); + } + } + + /// + /// Tries to create and give the entity a translator to translator that translates speech between the two specified languages. + /// + public bool TryGiveTranslator( + EntityUid uid, + string baseTranslatorPrototype, + ProtoId translatorLanguage, + ProtoId entityLanguage, + out EntityUid result) + { + result = EntityUid.Invalid; + if (translatorLanguage == entityLanguage) + return false; + + var translator = _entMan.SpawnNextToOrDrop(baseTranslatorPrototype, uid); + result = translator; + + if (!TryComp(translator, out var handheld)) + { + handheld = AddComp(translator); + handheld.ToggleOnInteract = true; + handheld.SetLanguageOnInteract = true; + } + + // Allows to speak the specified language and requires entities language. + handheld.SpokenLanguages = [translatorLanguage]; + handheld.UnderstoodLanguages = [translatorLanguage]; + handheld.RequiredLanguages = [entityLanguage]; + + // Try to put it in entities hand + if (_hands.TryPickupAnyHand(uid, translator, false, false, false)) + return true; + + // Try to find a valid clothing slot on the entity and equip the translator there + if (TryComp(translator, out var clothing) + && clothing.Slots != SlotFlags.NONE + && _inventory.TryGetSlots(uid, out var slots) + && slots.Any(it => _inventory.TryEquip(uid, translator, it.Name, true, false))) + return true; + + // Try to put the translator into entities bag, if it has one + if (_inventory.TryGetSlotEntity(uid, "back", out var bag) + && TryComp(bag, out var storage) + && _storage.Insert(bag.Value, translator, out _, null, storage, false, false)) + return true; + + // If all of the above has failed, just drop it at the same location as the entity + // This should ideally never happen, but who knows. + Transform(translator).Coordinates = Transform(uid).Coordinates; + + return true; + } +} diff --git a/Content.Shared/Traits/Assorted/Components/LightweightDrunkComponent.cs b/Content.Server/Traits/Assorted/LightweightDrunkComponent.cs similarity index 50% rename from Content.Shared/Traits/Assorted/Components/LightweightDrunkComponent.cs rename to Content.Server/Traits/Assorted/LightweightDrunkComponent.cs index 62d2f5899a4..4daff2e1338 100644 --- a/Content.Shared/Traits/Assorted/Components/LightweightDrunkComponent.cs +++ b/Content.Server/Traits/Assorted/LightweightDrunkComponent.cs @@ -1,13 +1,9 @@ -using Content.Shared.Drunk; -using Robust.Shared.GameStates; - namespace Content.Shared.Traits.Assorted.Components; /// -/// Used for the lightweight trait. DrunkSystem will check for this component and modify the boozePower accordingly if it finds it. +/// Used for the lightweight trait. LightweightDrunkSystem will multiply the effects of ethanol being metabolized /// -[RegisterComponent, NetworkedComponent] -[Access(typeof(SharedDrunkSystem))] +[RegisterComponent] public sealed partial class LightweightDrunkComponent : Component { [DataField("boozeStrengthMultiplier"), ViewVariables(VVAccess.ReadWrite)] diff --git a/Content.Server/Traits/Assorted/LightweightDrunkSystem.cs b/Content.Server/Traits/Assorted/LightweightDrunkSystem.cs new file mode 100644 index 00000000000..b5e9b877764 --- /dev/null +++ b/Content.Server/Traits/Assorted/LightweightDrunkSystem.cs @@ -0,0 +1,23 @@ +using Content.Server.Body.Components; +using Content.Server.Body.Systems; +using Content.Shared.Chemistry.Reagent; +using Content.Shared.Traits.Assorted.Components; + +namespace Content.Shared.Traits.Assorted.Systems; +public sealed class LightweightDrunkSystem : EntitySystem +{ + public override void Initialize() + { + SubscribeLocalEvent(OnTryMetabolizeReagent); + } + + private void OnTryMetabolizeReagent(EntityUid uid, LightweightDrunkComponent comp, ref TryMetabolizeReagent args) + { + Log.Debug(args.Prototype.ID); + if (args.Prototype.ID != "Ethanol") + return; + + args.Scale *= comp.BoozeStrengthMultiplier; + args.QuantityMultiplier *= comp.BoozeStrengthMultiplier; + } +} \ No newline at end of file diff --git a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs index 31c9b0d2b86..4749fd8b4b3 100644 --- a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs +++ b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs @@ -8,6 +8,7 @@ using Content.Shared.Actions.Events; using Content.Shared.Administration.Components; using Content.Shared.CombatMode; +using Content.Shared.Contests; using Content.Shared.Damage.Events; using Content.Shared.Damage.Systems; using Content.Shared.Database; @@ -43,6 +44,7 @@ public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem [Dependency] private readonly SharedColorFlashEffectSystem _color = default!; [Dependency] private readonly SolutionContainerSystem _solutions = default!; [Dependency] private readonly TagSystem _tag = default!; + [Dependency] private readonly ContestsSystem _contests = default!; public override void Initialize() { @@ -138,7 +140,7 @@ protected override bool DoDisarm(EntityUid user, DisarmAttackEvent ev, EntityUid if (attemptEvent.Cancelled) return false; - var chance = CalculateDisarmChance(user, target, inTargetHand, combatMode); + var chance = CalculateDisarmChance(user, target, inTargetHand, combatMode) * _contests.MassContest(user, target); if (_random.Prob(chance)) { diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs index c0adf730f11..9db00d2949c 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs @@ -1,11 +1,11 @@ using System.Linq; using System.Numerics; -using Content.Server.Administration.Logs; using Content.Server.Cargo.Systems; using Content.Server.Interaction; using Content.Server.Power.EntitySystems; using Content.Server.Stunnable; using Content.Server.Weapons.Ranged.Components; +using Content.Shared.Contests; using Content.Shared.Damage; using Content.Shared.Damage.Systems; using Content.Shared.Database; @@ -29,7 +29,6 @@ namespace Content.Server.Weapons.Ranged.Systems; public sealed partial class GunSystem : SharedGunSystem { - [Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly IComponentFactory _factory = default!; [Dependency] private readonly BatterySystem _battery = default!; [Dependency] private readonly DamageExamineSystem _damageExamine = default!; @@ -39,6 +38,7 @@ public sealed partial class GunSystem : SharedGunSystem [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly StaminaSystem _stamina = default!; [Dependency] private readonly StunSystem _stun = default!; + [Dependency] private readonly ContestsSystem _contests = default!; public const float DamagePitchVariation = SharedMeleeWeaponSystem.DamagePitchVariation; public const float GunClumsyChance = 0.5f; @@ -97,7 +97,7 @@ public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid? var toMap = toCoordinates.ToMapPos(EntityManager, TransformSystem); var mapDirection = toMap - fromMap.Position; var mapAngle = mapDirection.ToAngle(); - var angle = GetRecoilAngle(Timing.CurTime, gun, mapDirection.ToAngle()); + var angle = GetRecoilAngle(Timing.CurTime, gun, mapDirection.ToAngle(), user); // If applicable, this ensures the projectile is parented to grid on spawn, instead of the map. var fromEnt = MapManager.TryFindGridAt(fromMap, out var gridUid, out var grid) @@ -318,7 +318,7 @@ private Angle[] LinearSpread(Angle start, Angle end, int intervals) return angles; } - private Angle GetRecoilAngle(TimeSpan curTime, GunComponent component, Angle direction) + private Angle GetRecoilAngle(TimeSpan curTime, GunComponent component, Angle direction, EntityUid? shooter) { var timeSinceLastFire = (curTime - component.LastFire).TotalSeconds; var newTheta = MathHelper.Clamp(component.CurrentAngle.Theta + component.AngleIncreaseModified.Theta - component.AngleDecayModified.Theta * timeSinceLastFire, component.MinAngleModified.Theta, component.MaxAngleModified.Theta); @@ -326,7 +326,8 @@ private Angle GetRecoilAngle(TimeSpan curTime, GunComponent component, Angle dir component.LastFire = component.NextFire; // Convert it so angle can go either side. - var random = Random.NextFloat(-0.5f, 0.5f); + + var random = Random.NextFloat(-0.5f, 0.5f) / _contests.MassContest(shooter); var spread = component.CurrentAngle.Theta * random; var angle = new Angle(direction.Theta + component.CurrentAngle.Theta * random); DebugTools.Assert(spread <= component.MaxAngleModified.Theta); diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/ThrowArtifactSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/ThrowArtifactSystem.cs index 85783b552da..57a30a2fd9e 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/ThrowArtifactSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/ThrowArtifactSystem.cs @@ -1,12 +1,10 @@ using System.Numerics; -using Content.Server.Maps; using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components; using Content.Server.Xenoarchaeology.XenoArtifacts.Events; -using Content.Shared.Ghost; using Content.Shared.Maps; using Content.Shared.Physics; using Content.Shared.Throwing; -using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Random; @@ -14,7 +12,6 @@ namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems; public sealed class ThrowArtifactSystem : EntitySystem { - [Dependency] private readonly IMapManager _map = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly ThrowingSystem _throwing = default!; @@ -29,7 +26,7 @@ public override void Initialize() private void OnActivated(EntityUid uid, ThrowArtifactComponent component, ArtifactActivatedEvent args) { var xform = Transform(uid); - if (_map.TryGetGrid(xform.GridUid, out var grid)) + if (TryComp(xform.GridUid, out var grid)) { var tiles = grid.GetTilesIntersecting( Box2.CenteredAround(xform.WorldPosition, new Vector2(component.Range * 2, component.Range))); diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactGasTriggerSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactGasTriggerSystem.cs index 96f1dc37835..00f409f5533 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactGasTriggerSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactGasTriggerSystem.cs @@ -1,7 +1,6 @@ using Content.Server.Atmos.EntitySystems; using Content.Server.Xenoarchaeology.XenoArtifacts.Events; using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components; -using Robust.Server.GameObjects; namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Systems; @@ -9,7 +8,6 @@ public sealed class ArtifactGasTriggerSystem : EntitySystem { [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Dependency] private readonly ArtifactSystem _artifactSystem = default!; - [Dependency] private readonly TransformSystem _transformSystem = default!; public override void Initialize() { diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactHeatTriggerSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactHeatTriggerSystem.cs index 33d1a43c125..5525cdf3591 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactHeatTriggerSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactHeatTriggerSystem.cs @@ -3,7 +3,6 @@ using Content.Shared.Interaction; using Content.Shared.Temperature; using Content.Shared.Weapons.Melee.Events; -using Robust.Server.GameObjects; namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Systems; @@ -11,7 +10,6 @@ public sealed class ArtifactHeatTriggerSystem : EntitySystem { [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Dependency] private readonly ArtifactSystem _artifactSystem = default!; - [Dependency] private readonly TransformSystem _transformSystem = default!; public override void Initialize() { diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactInteractionTriggerSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactInteractionTriggerSystem.cs index 239b6741608..9976d56da0b 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactInteractionTriggerSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactInteractionTriggerSystem.cs @@ -1,6 +1,6 @@ using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components; using Content.Shared.Interaction; -using Content.Shared.Physics.Pull; +using Content.Shared.Movement.Pulling.Events; using Content.Shared.Weapons.Melee.Events; namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Systems; @@ -22,7 +22,7 @@ private void OnPull(EntityUid uid, ArtifactInteractionTriggerComponent component if (!component.PullActivation) return; - _artifactSystem.TryActivateArtifact(uid, args.Puller.Owner); + _artifactSystem.TryActivateArtifact(uid, args.PullerUid); } private void OnAttack(EntityUid uid, ArtifactInteractionTriggerComponent component, AttackedEvent args) diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactPressureTriggerSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactPressureTriggerSystem.cs index 4388756cce0..8777ab0a8c7 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactPressureTriggerSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactPressureTriggerSystem.cs @@ -1,6 +1,5 @@ using Content.Server.Atmos.EntitySystems; using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components; -using Robust.Server.GameObjects; namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Systems; @@ -11,7 +10,6 @@ public sealed class ArtifactPressureTriggerSystem : EntitySystem { [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Dependency] private readonly ArtifactSystem _artifactSystem = default!; - [Dependency] private readonly TransformSystem _transformSystem = default!; public override void Update(float frameTime) { diff --git a/Content.Server/Zombies/ZombieSystem.Transform.cs b/Content.Server/Zombies/ZombieSystem.Transform.cs index 21f25080426..c7e29166a0e 100644 --- a/Content.Server/Zombies/ZombieSystem.Transform.cs +++ b/Content.Server/Zombies/ZombieSystem.Transform.cs @@ -26,12 +26,12 @@ using Content.Shared.Mobs; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; +using Content.Shared.Movement.Pulling.Components; using Content.Shared.Movement.Systems; using Content.Shared.Nutrition.AnimalHusbandry; using Content.Shared.Nutrition.Components; using Content.Shared.Popups; using Content.Shared.Roles; -using Content.Shared.Pulling.Components; using Content.Shared.Weapons.Melee; using Content.Shared.Zombies; using Content.Shared.Prying.Components; @@ -280,7 +280,9 @@ public void ZombifyEntity(EntityUid target, MobStateComponent? mobState = null) RemComp(target, handsComp); } - RemComp(target); + // Sloth: What the fuck? + // How long until compregistry lmao. + RemComp(target); // No longer waiting to become a zombie: // Requires deferral because this is (probably) the event which called ZombifyEntity in the first place. diff --git a/Content.Server/Zombies/ZombieSystem.cs b/Content.Server/Zombies/ZombieSystem.cs index bef57eceb39..080bef44e7a 100644 --- a/Content.Server/Zombies/ZombieSystem.cs +++ b/Content.Server/Zombies/ZombieSystem.cs @@ -2,9 +2,7 @@ using Content.Server.Body.Systems; using Content.Server.Chat; using Content.Server.Chat.Systems; -using Content.Server.Cloning; using Content.Server.Emoting.Systems; -using Content.Server.Inventory; using Content.Server.Speech.EntitySystems; using Content.Shared.Bed.Sleep; using Content.Shared.Cloning; @@ -31,7 +29,6 @@ public sealed partial class ZombieSystem : SharedZombieSystem [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly BloodstreamSystem _bloodstream = default!; [Dependency] private readonly DamageableSystem _damageable = default!; - [Dependency] private readonly ServerInventorySystem _inv = default!; [Dependency] private readonly ChatSystem _chat = default!; [Dependency] private readonly AutoEmoteSystem _autoEmote = default!; [Dependency] private readonly EmoteOnDamageSystem _emoteOnDamage = default!; diff --git a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs index a914a8f267d..f5ed2df227c 100644 --- a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs +++ b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs @@ -202,7 +202,7 @@ public bool CanChangeDirection(EntityUid uid) public bool CanShiver(EntityUid uid) { var ev = new ShiverAttemptEvent(uid); - RaiseLocalEvent(uid, ev); + RaiseLocalEvent(uid, ref ev); return !ev.Cancelled; } @@ -210,7 +210,7 @@ public bool CanShiver(EntityUid uid) public bool CanSweat(EntityUid uid) { var ev = new SweatAttemptEvent(uid); - RaiseLocalEvent(uid, ev); + RaiseLocalEvent(uid, ref ev); return !ev.Cancelled; } diff --git a/Content.Shared/Administration/AdminData.cs b/Content.Shared/Administration/AdminData.cs index 5b5873bce36..229edbcd4c3 100644 --- a/Content.Shared/Administration/AdminData.cs +++ b/Content.Shared/Administration/AdminData.cs @@ -12,6 +12,11 @@ public sealed class AdminData /// public bool Active; + /// + /// Whether the admin is in stealth mode and won't appear in adminwho to admins without the Stealth flag. + /// + public bool Stealth; + /// /// The admin's title. /// @@ -56,6 +61,14 @@ public bool CanAdminMenu() return HasFlag(AdminFlags.Admin); } + /// + /// Check if this admin can be hidden and see other hidden admins. + /// + public bool CanStealth() + { + return HasFlag(AdminFlags.Stealth); + } + public bool CanAdminReloadPrototypes() { return HasFlag(AdminFlags.Host); diff --git a/Content.Shared/Administration/AdminFlags.cs b/Content.Shared/Administration/AdminFlags.cs index 64cf522faaf..9842e638c2c 100644 --- a/Content.Shared/Administration/AdminFlags.cs +++ b/Content.Shared/Administration/AdminFlags.cs @@ -96,7 +96,12 @@ public enum AdminFlags : uint MassBan = 1 << 15, /// - /// DeltaV - The ability to whitelist people. Either this permission or +BAN is required for remove. + /// Allows you to remain hidden from adminwho except to other admins with this flag. + /// + Stealth = 1 << 16, + + /// + /// DeltaV - The ability to whitelist people. Either this permission or +BAN is required for remove. /// Whitelist = 1 << 20, diff --git a/Content.Shared/Administration/AdminFrozenSystem.cs b/Content.Shared/Administration/AdminFrozenSystem.cs index 14438cc5912..4ec9600b0bd 100644 --- a/Content.Shared/Administration/AdminFrozenSystem.cs +++ b/Content.Shared/Administration/AdminFrozenSystem.cs @@ -1,13 +1,10 @@ using Content.Shared.ActionBlocker; using Content.Shared.Interaction.Events; using Content.Shared.Item; -using Content.Shared.Movement; using Content.Shared.Movement.Events; -using Content.Shared.Physics.Pull; -using Content.Shared.Pulling; -using Content.Shared.Pulling.Components; -using Content.Shared.Pulling.Events; -using Content.Shared.Stunnable; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Events; +using Content.Shared.Movement.Pulling.Systems; using Content.Shared.Throwing; namespace Content.Shared.Administration; @@ -15,7 +12,7 @@ namespace Content.Shared.Administration; public sealed class AdminFrozenSystem : EntitySystem { [Dependency] private readonly ActionBlockerSystem _blocker = default!; - [Dependency] private readonly SharedPullingSystem _pulling = default!; + [Dependency] private readonly PullingSystem _pulling = default!; public override void Initialize() { @@ -45,9 +42,9 @@ private void OnPullAttempt(EntityUid uid, AdminFrozenComponent component, PullAt private void OnStartup(EntityUid uid, AdminFrozenComponent component, ComponentStartup args) { - if (TryComp(uid, out var pullable)) + if (TryComp(uid, out var pullable)) { - _pulling.TryStopPull(pullable); + _pulling.TryStopPull(uid, pullable); } UpdateCanMove(uid, component, args); diff --git a/Content.Shared/Alert/AlertType.cs b/Content.Shared/Alert/AlertType.cs index 941e908db6d..dc323dc64a8 100644 --- a/Content.Shared/Alert/AlertType.cs +++ b/Content.Shared/Alert/AlertType.cs @@ -37,6 +37,7 @@ public enum AlertType : byte Internals, Toxins, Muted, + Walking, VowOfSilence, VowBroken, Essence, diff --git a/Content.Shared/Announcements/Events/AnnouncementSendEvent.cs b/Content.Shared/Announcements/Events/AnnouncementSendEvent.cs new file mode 100644 index 00000000000..ca75742aed6 --- /dev/null +++ b/Content.Shared/Announcements/Events/AnnouncementSendEvent.cs @@ -0,0 +1,23 @@ +using Robust.Shared.Audio; +using Robust.Shared.Network; +using Robust.Shared.Serialization; + +namespace Content.Shared.Announcements.Events; + + +[Serializable, NetSerializable] +public sealed class AnnouncementSendEvent : EntityEventArgs +{ + public string AnnouncerId { get; } + public string AnnouncementId { get; } + public List Recipients { get; } + public AudioParams AudioParams { get; } + + public AnnouncementSendEvent(string announcerId, string announcementId, List recipients, AudioParams audioParams) + { + AnnouncerId = announcerId; + AnnouncementId = announcementId; + Recipients = recipients; + AudioParams = audioParams; + } +} diff --git a/Content.Shared/Announcements/Prototypes/AnnouncerPrototype.cs b/Content.Shared/Announcements/Prototypes/AnnouncerPrototype.cs new file mode 100644 index 00000000000..42db148df9c --- /dev/null +++ b/Content.Shared/Announcements/Prototypes/AnnouncerPrototype.cs @@ -0,0 +1,71 @@ +using Robust.Shared.Audio; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Announcements.Prototypes; + +/// +/// Defines an announcer and their announcement file paths +/// +[Prototype("announcer")] +public sealed class AnnouncerPrototype : IPrototype +{ + [IdDataField] + public string ID { get; } = default!; + + /// + /// A prefix to add to all announcement paths unless told not to by + /// + /// Paths always start in Resources/ + [DataField("basePath")] + public string BasePath { get; } = default!; + + /// + /// Audio parameters to apply to all announcement sounds unless overwritten by + /// + [DataField("baseAudioParams")] + public AudioParams? BaseAudioParams { get; } + + [DataField("announcements")] + public AnnouncementData[] Announcements { get; } = default!; +} + +/// +/// Defines a path to an announcement file and that announcement's ID +/// +[DataDefinition] +public sealed partial class AnnouncementData +{ + [DataField("id")] + public string ID = default!; + + /// + /// If true, the will not be prepended to this announcement's path + /// + [DataField("ignoreBasePath")] + public bool IgnoreBasePath = false; + + /// + /// Where to look for the announcement audio file + /// + [DataField("path")] + public string? Path; + + /// + /// Use a soundCollection instead of a single sound + /// + [DataField("collection"), ValidatePrototypeId] + public string? Collection; + + /// + /// Overrides the default announcement message for this announcement type + /// + [DataField("message")] + public string? MessageOverride; + + /// + /// Audio parameters to apply to this announcement sound + /// Will override + /// + [DataField("audioParams")] + public AudioParams? AudioParams; +} diff --git a/Content.Shared/Announcements/Systems/SharedAnnouncerSystem.cs b/Content.Shared/Announcements/Systems/SharedAnnouncerSystem.cs new file mode 100644 index 00000000000..5e02b602d06 --- /dev/null +++ b/Content.Shared/Announcements/Systems/SharedAnnouncerSystem.cs @@ -0,0 +1,150 @@ +using System.Linq; +using System.Text.RegularExpressions; +using Content.Shared.Announcements.Prototypes; +using Robust.Shared.Audio; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Announcements.Systems; + +public abstract class SharedAnnouncerSystem : EntitySystem +{ + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + + + /// + /// Gets an announcement path from the announcer + /// + /// ID of the announcement from the announcer to get information for + /// ID of the announcer to use instead of the current one + public string GetAnnouncementPath(string announcementId, string announcerId) + { + if (!_proto.TryIndex(announcerId, out var announcer)) + return ""; + + // Get the announcement data from the announcer + // Will be the fallback if the data for the announcementId is not found + var announcementType = announcer.Announcements.FirstOrDefault(a => a.ID == announcementId) ?? + announcer.Announcements.First(a => a.ID.ToLower() == "fallback"); + + // If the greedy announcementType wants to do the job of announcer, ignore the base path and just return the path + if (announcementType.IgnoreBasePath) + return announcementType.Path!; + // If the announcementType has a collection, get the sound from the collection + if (announcementType.Collection != null) + return _audio.GetSound(new SoundCollectionSpecifier(announcementType.Collection)); + // If nothing is overriding the base paths, return the base path + the announcement file path + return $"{announcer.BasePath}/{announcementType.Path}"; + } + + /// + /// Gets audio params from the announcer + /// + /// ID of the announcement from the announcer to get information for + /// Announcer prototype to get information from + public string GetAnnouncementPath(string announcementId, AnnouncerPrototype announcer) + { + // Get the announcement data from the announcer + // Will be the fallback if the data for the announcementId is not found + var announcementType = announcer.Announcements.FirstOrDefault(a => a.ID == announcementId) ?? + announcer.Announcements.First(a => a.ID.ToLower() == "fallback"); + + // If the greedy announcementType wants to do the job of announcer, ignore the base path and just return the path + if (announcementType.IgnoreBasePath) + return announcementType.Path!; + // If the announcementType has a collection, get the sound from the collection + if (announcementType.Collection != null) + return _audio.GetSound(new SoundCollectionSpecifier(announcementType.Collection)); + // If nothing is overriding the base paths, return the base path + the announcement file path + return $"{announcer.BasePath}/{announcementType.Path}"; + } + + /// + /// Converts a prototype ID to a consistently used format for announcements + /// + public string GetAnnouncementId(string announcementId, bool ended = false) + { + // Replace the first letter with lowercase + var id = char.ToLowerInvariant(announcementId[0]) + announcementId[1..]; + + // If the event has ended, add "Complete" to the end + if (ended) + id += "Complete"; + + return id; + } + + + /// + /// Gets audio params from the announcer + /// + /// ID of the announcement from the announcer to get information from + /// ID of the announcer to use instead of the current one + public AudioParams? GetAudioParams(string announcementId, string announcerId) + { + if (!_proto.TryIndex(announcerId, out var announcer)) + return null; + + // Get the announcement data from the announcer + // Will be the fallback if the data for the announcementId is not found + var announcementType = announcer.Announcements.FirstOrDefault(a => a.ID == announcementId) ?? + announcer.Announcements.First(a => a.ID == "fallback"); + + // Return the announcer.BaseAudioParams if the announcementType doesn't have an override + return announcementType.AudioParams ?? announcer.BaseAudioParams ?? null; // For some reason the formatter doesn't warn me about "?? null" being redundant, so it stays for the funnies + } + + /// + /// Gets audio params from the announcer + /// + /// ID of the announcement from the announcer to get information from + /// Announcer prototype to get information from + public AudioParams? GetAudioParams(string announcementId, AnnouncerPrototype announcer) + { + // Get the announcement data from the announcer + // Will be the fallback if the data for the announcementId is not found + var announcementType = announcer.Announcements.FirstOrDefault(a => a.ID == announcementId) ?? + announcer.Announcements.First(a => a.ID == "fallback"); + + // Return the announcer.BaseAudioParams if the announcementType doesn't have an override + return announcementType.AudioParams ?? announcer.BaseAudioParams; + } + + + /// + /// Gets an announcement message from the announcer + /// + /// ID of the announcement from the announcer to get information from + /// ID of the announcer to get information from + public string? GetAnnouncementMessage(string announcementId, string announcerId) + { + if (!_proto.TryIndex(announcerId, out var announcer)) + return null; + + // Get the announcement data from the announcer + // Will be the fallback if the data for the announcementId is not found + var announcementType = announcer.Announcements.FirstOrDefault(a => a.ID == announcementId) ?? + announcer.Announcements.First(a => a.ID == "fallback"); + + // Return the announcementType.MessageOverride if it exists, otherwise return null + return announcementType.MessageOverride != null ? announcementType.MessageOverride : null; + } + + /// + /// Gets an announcement message from an event ID + /// + /// ID of the event to convert + /// Format for the locale string, replaces "{}" with the converted ID + /// The IDs use a hardcoded format, you can probably handle other formats yourself + /// Localized announcement + public string GetEventLocaleString(string eventId, string localeBase = "station-event-{}-announcement") + { + // Replace capital letters with lowercase plus a hyphen before it + var capsCapture = new Regex("([A-Z])"); + var id = capsCapture.Replace(eventId, "-$1").ToLower(); + + // Replace {} with the converted ID + return localeBase.Replace("{}", id); + } +} diff --git a/Content.Shared/Body/Events/MechanismBodyEvents.cs b/Content.Shared/Body/Events/MechanismBodyEvents.cs index b52a333613f..968b172aef5 100644 --- a/Content.Shared/Body/Events/MechanismBodyEvents.cs +++ b/Content.Shared/Body/Events/MechanismBodyEvents.cs @@ -1,61 +1,28 @@ -namespace Content.Shared.Body.Events -{ - // All of these events are raised on a mechanism entity when added/removed to a body in different - // ways. - - /// - /// Raised on a mechanism when it is added to a body part. - /// - public sealed class AddedToPartEvent : EntityEventArgs - { - public EntityUid Part; - - public AddedToPartEvent(EntityUid part) - { - Part = part; - } - } - - /// - /// Raised on a mechanism when it is added to a body part within a body. - /// - public sealed class AddedToPartInBodyEvent : EntityEventArgs - { - public EntityUid Body; - public EntityUid Part; - - public AddedToPartInBodyEvent(EntityUid body, EntityUid part) - { - Body = body; - Part = part; - } - } - - /// - /// Raised on a mechanism when it is removed from a body part. - /// - public sealed class RemovedFromPartEvent : EntityEventArgs - { - public EntityUid OldPart; - - public RemovedFromPartEvent(EntityUid oldPart) - { - OldPart = oldPart; - } - } - - /// - /// Raised on a mechanism when it is removed from a body part within a body. - /// - public sealed class RemovedFromPartInBodyEvent : EntityEventArgs - { - public EntityUid OldBody; - public EntityUid OldPart; - - public RemovedFromPartInBodyEvent(EntityUid oldBody, EntityUid oldPart) - { - OldBody = oldBody; - OldPart = oldPart; - } - } -} +namespace Content.Shared.Body.Events; + +// All of these events are raised on a mechanism entity when added/removed to a body in different +// ways. + +/// +/// Raised on a mechanism when it is added to a body part. +/// +[ByRefEvent] +public readonly record struct OrganAddedEvent(EntityUid Part); + +/// +/// Raised on a mechanism when it is added to a body part within a body. +/// +[ByRefEvent] +public readonly record struct OrganAddedToBodyEvent(EntityUid Body, EntityUid Part); + +/// +/// Raised on a mechanism when it is removed from a body part. +/// +[ByRefEvent] +public readonly record struct OrganRemovedEvent(EntityUid OldPart); + +/// +/// Raised on a mechanism when it is removed from a body part within a body. +/// +[ByRefEvent] +public readonly record struct OrganRemovedFromBodyEvent(EntityUid OldBody, EntityUid OldPart); diff --git a/Content.Shared/Body/Events/ShiverAttemptEvent.cs b/Content.Shared/Body/Events/ShiverAttemptEvent.cs index 8c2761f545d..e9400bc48d7 100644 --- a/Content.Shared/Body/Events/ShiverAttemptEvent.cs +++ b/Content.Shared/Body/Events/ShiverAttemptEvent.cs @@ -1,12 +1,8 @@ -namespace Content.Shared.Body.Events -{ - public sealed class ShiverAttemptEvent : CancellableEntityEventArgs - { - public ShiverAttemptEvent(EntityUid uid) - { - Uid = uid; - } +namespace Content.Shared.Body.Events; - public EntityUid Uid { get; } - } +[ByRefEvent] +public record struct ShiverAttemptEvent(EntityUid Uid) +{ + public readonly EntityUid Uid = Uid; + public bool Cancelled = false; } diff --git a/Content.Shared/Body/Events/SweatAttemptEvent.cs b/Content.Shared/Body/Events/SweatAttemptEvent.cs index 7f4b3fab15d..7506538c439 100644 --- a/Content.Shared/Body/Events/SweatAttemptEvent.cs +++ b/Content.Shared/Body/Events/SweatAttemptEvent.cs @@ -1,12 +1,8 @@ -namespace Content.Shared.Body.Events -{ - public sealed class SweatAttemptEvent : CancellableEntityEventArgs - { - public SweatAttemptEvent(EntityUid uid) - { - Uid = uid; - } +namespace Content.Shared.Body.Events; - public EntityUid Uid { get; } - } +[ByRefEvent] +public record struct SweatAttemptEvent(EntityUid Uid) +{ + public readonly EntityUid Uid = Uid; + public bool Cancelled = false; } diff --git a/Content.Shared/Body/Organ/OrganComponent.cs b/Content.Shared/Body/Organ/OrganComponent.cs index 9e1de6b3559..3048927b5fb 100644 --- a/Content.Shared/Body/Organ/OrganComponent.cs +++ b/Content.Shared/Body/Organ/OrganComponent.cs @@ -1,4 +1,4 @@ -using Content.Shared.Body.Systems; +using Content.Shared.Body.Systems; using Robust.Shared.Containers; using Robust.Shared.GameStates; @@ -11,6 +11,6 @@ public sealed partial class OrganComponent : Component /// /// Relevant body this organ is attached to. /// - [DataField("body"), AutoNetworkedField] + [DataField, AutoNetworkedField] public EntityUid? Body; } diff --git a/Content.Shared/Body/Part/BodyPartEvents.cs b/Content.Shared/Body/Part/BodyPartEvents.cs index 4dbc543fc8e..0d8d2c8a268 100644 --- a/Content.Shared/Body/Part/BodyPartEvents.cs +++ b/Content.Shared/Body/Part/BodyPartEvents.cs @@ -1,7 +1,7 @@ -namespace Content.Shared.Body.Part; +namespace Content.Shared.Body.Part; [ByRefEvent] -public readonly record struct BodyPartAddedEvent(string Slot, BodyPartComponent Part); +public readonly record struct BodyPartAddedEvent(string Slot, Entity Part); [ByRefEvent] -public readonly record struct BodyPartRemovedEvent(string Slot, BodyPartComponent Part); +public readonly record struct BodyPartRemovedEvent(string Slot, Entity Part); diff --git a/Content.Shared/Body/Systems/SharedBodySystem.Body.cs b/Content.Shared/Body/Systems/SharedBodySystem.Body.cs index bc7cf63124c..1a35afdbe00 100644 --- a/Content.Shared/Body/Systems/SharedBodySystem.Body.cs +++ b/Content.Shared/Body/Systems/SharedBodySystem.Body.cs @@ -9,7 +9,6 @@ using Content.Shared.Gibbing.Events; using Content.Shared.Gibbing.Systems; using Content.Shared.Inventory; -using Content.Shared.Inventory.Events; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; @@ -30,8 +29,10 @@ public partial class SharedBodySystem [Dependency] private readonly InventorySystem _inventory = default!; [Dependency] private readonly GibbingSystem _gibbingSystem = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + private const float GibletLaunchImpulse = 8; private const float GibletLaunchImpulseVariance = 3; + private void InitializeBody() { // Body here to handle root body parts. @@ -43,7 +44,7 @@ private void InitializeBody() SubscribeLocalEvent(OnBodyCanDrag); } - private void OnBodyInserted(EntityUid uid, BodyComponent component, EntInsertedIntoContainerMessage args) + private void OnBodyInserted(Entity ent, ref EntInsertedIntoContainerMessage args) { // Root body part? var slotId = args.Container.ID; @@ -51,21 +52,21 @@ private void OnBodyInserted(EntityUid uid, BodyComponent component, EntInsertedI if (slotId != BodyRootContainerId) return; - var entity = args.Entity; + var insertedUid = args.Entity; - if (TryComp(entity, out BodyPartComponent? childPart)) + if (TryComp(insertedUid, out BodyPartComponent? part)) { - AddPart(uid, entity, slotId, childPart); - RecursiveBodyUpdate(entity, uid, childPart); + AddPart((ent, ent), (insertedUid, part), slotId); + RecursiveBodyUpdate((insertedUid, part), ent); } - if (TryComp(entity, out OrganComponent? organ)) + if (TryComp(insertedUid, out OrganComponent? organ)) { - AddOrgan(entity, uid, uid, organ); + AddOrgan((insertedUid, organ), ent, ent); } } - private void OnBodyRemoved(EntityUid uid, BodyComponent component, EntRemovedFromContainerMessage args) + private void OnBodyRemoved(Entity ent, ref EntRemovedFromContainerMessage args) { // Root body part? var slotId = args.Container.ID; @@ -73,55 +74,55 @@ private void OnBodyRemoved(EntityUid uid, BodyComponent component, EntRemovedFro if (slotId != BodyRootContainerId) return; - var entity = args.Entity; - DebugTools.Assert(!TryComp(entity, out BodyPartComponent? b) || b.Body == uid); - DebugTools.Assert(!TryComp(entity, out OrganComponent? o) || o.Body == uid); + var removedUid = args.Entity; + DebugTools.Assert(!TryComp(removedUid, out BodyPartComponent? b) || b.Body == ent); + DebugTools.Assert(!TryComp(removedUid, out OrganComponent? o) || o.Body == ent); - if (TryComp(entity, out BodyPartComponent? childPart)) + if (TryComp(removedUid, out BodyPartComponent? part)) { - RemovePart(uid, entity, slotId, childPart); - RecursiveBodyUpdate(entity, null, childPart); + RemovePart((ent, ent), (removedUid, part), slotId); + RecursiveBodyUpdate((removedUid, part), null); } - if (TryComp(entity, out OrganComponent? organ)) - RemoveOrgan(entity, uid, organ); + if (TryComp(removedUid, out OrganComponent? organ)) + RemoveOrgan((removedUid, organ), ent); } - private void OnBodyInit(EntityUid bodyId, BodyComponent body, ComponentInit args) + private void OnBodyInit(Entity ent, ref ComponentInit args) { // Setup the initial container. - body.RootContainer = Containers.EnsureContainer(bodyId, BodyRootContainerId); + ent.Comp.RootContainer = Containers.EnsureContainer(ent, BodyRootContainerId); } - private void OnBodyMapInit(EntityUid bodyId, BodyComponent body, MapInitEvent args) + private void OnBodyMapInit(Entity ent, ref MapInitEvent args) { - if (body.Prototype == null) + if (ent.Comp.Prototype is null) return; // One-time setup // Obviously can't run in Init to avoid double-spawns on save / load. - var prototype = Prototypes.Index(body.Prototype.Value); - MapInitBody(bodyId, prototype); + var prototype = Prototypes.Index(ent.Comp.Prototype.Value); + MapInitBody(ent, prototype); } private void MapInitBody(EntityUid bodyEntity, BodyPrototype prototype) { var protoRoot = prototype.Slots[prototype.Root]; - if (protoRoot.Part == null) + if (protoRoot.Part is null) return; // This should already handle adding the entity to the root. - var rootPartEntity = SpawnInContainerOrDrop(protoRoot.Part, bodyEntity, BodyRootContainerId); - var rootPart = Comp(rootPartEntity); + var rootPartUid = SpawnInContainerOrDrop(protoRoot.Part, bodyEntity, BodyRootContainerId); + var rootPart = Comp(rootPartUid); rootPart.Body = bodyEntity; - Dirty(rootPartEntity, rootPart); + Dirty(rootPartUid, rootPart); // Setup the rest of the body entities. - SetupOrgans(rootPartEntity, rootPart, protoRoot.Organs); - MapInitParts(rootPartEntity, prototype); + SetupOrgans((rootPartUid, rootPart), protoRoot.Organs); + MapInitParts(rootPartUid, prototype); } - private void OnBodyCanDrag(EntityUid uid, BodyComponent component, ref CanDragEvent args) + private void OnBodyCanDrag(Entity ent, ref CanDragEvent args) { args.Handled = true; } @@ -169,7 +170,7 @@ private void MapInitParts(EntityUid rootPartId, BodyPrototype prototype) var partSlot = CreatePartSlot(parentEntity, connection, childPartComponent.PartType, parentPartComponent); var cont = Containers.GetContainer(parentEntity, GetPartSlotContainerId(connection)); - if (partSlot == null || !Containers.Insert(childPart, cont)) + if (partSlot is null || !Containers.Insert(childPart, cont)) { Log.Error($"Could not create slot for connection {connection} in body {prototype.ID}"); QueueDel(childPart); @@ -177,7 +178,7 @@ private void MapInitParts(EntityUid rootPartId, BodyPrototype prototype) } // Add organs - SetupOrgans(childPart, childPartComponent, connectionSlot.Organs); + SetupOrgans((childPart, childPartComponent), connectionSlot.Organs); // Enqueue it so we can also get its neighbors. frontier.Enqueue(connection); @@ -185,16 +186,16 @@ private void MapInitParts(EntityUid rootPartId, BodyPrototype prototype) } } - private void SetupOrgans(EntityUid partId, BodyPartComponent partComponent, Dictionary organs) + private void SetupOrgans(Entity ent, Dictionary organs) { foreach (var (organSlotId, organProto) in organs) { - var slot = CreateOrganSlot(organSlotId, partId, partComponent); - SpawnInContainerOrDrop(organProto, partId, GetOrganContainerId(organSlotId)); + var slot = CreateOrganSlot((ent, ent), organSlotId); + SpawnInContainerOrDrop(organProto, ent, GetOrganContainerId(organSlotId)); - if (slot == null) + if (slot is null) { - Log.Error($"Could not create organ for slot {organSlotId} in {ToPrettyString(partId)}"); + Log.Error($"Could not create organ for slot {organSlotId} in {ToPrettyString(ent)}"); } } } @@ -202,12 +203,14 @@ private void SetupOrgans(EntityUid partId, BodyPartComponent partComponent, Dict /// /// Gets all body containers on this entity including the root one. /// - public IEnumerable GetBodyContainers(EntityUid id, BodyComponent? body = null, + public IEnumerable GetBodyContainers( + EntityUid id, + BodyComponent? body = null, BodyPartComponent? rootPart = null) { - if (!Resolve(id, ref body, false) || - body.RootContainer.ContainedEntity == null || - !Resolve(body.RootContainer.ContainedEntity.Value, ref rootPart)) + if (!Resolve(id, ref body, logMissing: false) + || body.RootContainer.ContainedEntity is null + || !Resolve(body.RootContainer.ContainedEntity.Value, ref rootPart)) { yield break; } @@ -223,13 +226,15 @@ public IEnumerable GetBodyContainers(EntityUid id, BodyComponent? /// /// Gets all child body parts of this entity, including the root entity. /// - public IEnumerable<(EntityUid Id, BodyPartComponent Component)> GetBodyChildren(EntityUid? id, BodyComponent? body = null, + public IEnumerable<(EntityUid Id, BodyPartComponent Component)> GetBodyChildren( + EntityUid? id, + BodyComponent? body = null, BodyPartComponent? rootPart = null) { - if (id == null || - !Resolve(id.Value, ref body, false) || - body.RootContainer.ContainedEntity == null || - !Resolve(body.RootContainer.ContainedEntity.Value, ref rootPart)) + if (id is null + || !Resolve(id.Value, ref body, logMissing: false) + || body.RootContainer.ContainedEntity is null + || !Resolve(body.RootContainer.ContainedEntity.Value, ref rootPart)) { yield break; } @@ -240,9 +245,11 @@ public IEnumerable GetBodyContainers(EntityUid id, BodyComponent? } } - public IEnumerable<(EntityUid Id, OrganComponent Component)> GetBodyOrgans(EntityUid? bodyId, BodyComponent? body = null) + public IEnumerable<(EntityUid Id, OrganComponent Component)> GetBodyOrgans( + EntityUid? bodyId, + BodyComponent? body = null) { - if (bodyId == null || !Resolve(bodyId.Value, ref body, false)) + if (bodyId is null || !Resolve(bodyId.Value, ref body, logMissing: false)) yield break; foreach (var part in GetBodyChildren(bodyId, body)) @@ -260,10 +267,15 @@ public IEnumerable GetBodyContainers(EntityUid id, BodyComponent? /// /// /// - public IEnumerable GetBodyAllSlots(EntityUid bodyId, BodyComponent? body = null) + public IEnumerable GetBodyAllSlots( + EntityUid bodyId, + BodyComponent? body = null) { - if (!Resolve(bodyId, ref body, false) || body.RootContainer.ContainedEntity == null) + if (!Resolve(bodyId, ref body, logMissing: false) + || body.RootContainer.ContainedEntity is null) + { yield break; + } foreach (var slot in GetAllBodyPartSlots(body.RootContainer.ContainedEntity.Value)) { @@ -279,12 +291,11 @@ public virtual HashSet GibBody( Vector2? splatDirection = null, float splatModifier = 1, Angle splatCone = default, - SoundSpecifier? gibSoundOverride = null - ) + SoundSpecifier? gibSoundOverride = null) { var gibs = new HashSet(); - if (!Resolve(bodyId, ref body, false)) + if (!Resolve(bodyId, ref body, logMissing: false)) return gibs; var root = GetRootPartOrNull(bodyId, body); @@ -311,7 +322,7 @@ public virtual HashSet GibBody( launchImpulseVariance:GibletLaunchImpulseVariance, launchCone: splatCone); } } - if(TryComp(bodyId, out var inventory)) + if (TryComp(bodyId, out var inventory)) { foreach (var item in _inventory.GetHandOrInventoryEntities(bodyId)) { diff --git a/Content.Shared/Body/Systems/SharedBodySystem.Organs.cs b/Content.Shared/Body/Systems/SharedBodySystem.Organs.cs index fa113907058..efabebfc858 100644 --- a/Content.Shared/Body/Systems/SharedBodySystem.Organs.cs +++ b/Content.Shared/Body/Systems/SharedBodySystem.Organs.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using Content.Shared.Body.Components; using Content.Shared.Body.Events; using Content.Shared.Body.Organ; @@ -9,41 +9,50 @@ namespace Content.Shared.Body.Systems; public partial class SharedBodySystem { - private void AddOrgan(EntityUid uid, EntityUid bodyUid, EntityUid parentPartUid, OrganComponent component) + private void AddOrgan( + Entity organEnt, + EntityUid bodyUid, + EntityUid parentPartUid) { - component.Body = bodyUid; - RaiseLocalEvent(uid, new AddedToPartEvent(parentPartUid)); + organEnt.Comp.Body = bodyUid; + var addedEv = new OrganAddedEvent(parentPartUid); + RaiseLocalEvent(organEnt, ref addedEv); - if (component.Body != null) - RaiseLocalEvent(uid, new AddedToPartInBodyEvent(component.Body.Value, parentPartUid)); + if (organEnt.Comp.Body is not null) + { + var addedInBodyEv = new OrganAddedToBodyEvent(bodyUid, parentPartUid); + RaiseLocalEvent(organEnt, ref addedInBodyEv); + } - Dirty(uid, component); + Dirty(organEnt, organEnt.Comp); } - private void RemoveOrgan(EntityUid uid, EntityUid parentPartUid, OrganComponent component) + private void RemoveOrgan(Entity organEnt, EntityUid parentPartUid) { - RaiseLocalEvent(uid, new RemovedFromPartEvent(parentPartUid)); + var removedEv = new OrganRemovedEvent(parentPartUid); + RaiseLocalEvent(organEnt, ref removedEv); - if (component.Body != null) + if (organEnt.Comp.Body is { Valid: true } bodyUid) { - RaiseLocalEvent(uid, new RemovedFromPartInBodyEvent(component.Body.Value, parentPartUid)); + var removedInBodyEv = new OrganRemovedFromBodyEvent(bodyUid, parentPartUid); + RaiseLocalEvent(organEnt, ref removedInBodyEv); } - component.Body = null; - Dirty(uid, component); + organEnt.Comp.Body = null; + Dirty(organEnt, organEnt.Comp); } /// /// Creates the specified organ slot on the parent entity. /// - private OrganSlot? CreateOrganSlot(string slotId, EntityUid parent, BodyPartComponent? part = null) + private OrganSlot? CreateOrganSlot(Entity parentEnt, string slotId) { - if (!Resolve(parent, ref part, false)) + if (!Resolve(parentEnt, ref parentEnt.Comp, logMissing: false)) return null; - Containers.EnsureContainer(parent, GetOrganContainerId(slotId)); + Containers.EnsureContainer(parentEnt, GetOrganContainerId(slotId)); var slot = new OrganSlot(slotId); - part.Organs.Add(slotId, slot); + parentEnt.Comp.Organs.Add(slotId, slot); return slot; } @@ -58,20 +67,23 @@ public bool TryCreateOrganSlot( { slot = null; - if (parent == null || !Resolve(parent.Value, ref part, false)) + if (parent is null || !Resolve(parent.Value, ref part, logMissing: false)) { return false; } Containers.EnsureContainer(parent.Value, GetOrganContainerId(slotId)); slot = new OrganSlot(slotId); - return part.Organs.TryAdd(slotId,slot.Value); + return part.Organs.TryAdd(slotId, slot.Value); } /// /// Returns whether the slotId exists on the partId. /// - public bool CanInsertOrgan(EntityUid partId, string slotId, BodyPartComponent? part = null) + public bool CanInsertOrgan( + EntityUid partId, + string slotId, + BodyPartComponent? part = null) { return Resolve(partId, ref part) && part.Organs.ContainsKey(slotId); } @@ -79,26 +91,32 @@ public bool CanInsertOrgan(EntityUid partId, string slotId, BodyPartComponent? p /// /// Returns whether the specified organ slot exists on the partId. /// - public bool CanInsertOrgan(EntityUid partId, OrganSlot slot, BodyPartComponent? part = null) + public bool CanInsertOrgan( + EntityUid partId, + OrganSlot slot, + BodyPartComponent? part = null) { return CanInsertOrgan(partId, slot.Id, part); } - public bool InsertOrgan(EntityUid partId, EntityUid organId, string slotId, BodyPartComponent? part = null, OrganComponent? organ = null) + public bool InsertOrgan( + EntityUid partId, + EntityUid organId, + string slotId, + BodyPartComponent? part = null, + OrganComponent? organ = null) { - if (!Resolve(organId, ref organ, false) || - !Resolve(partId, ref part, false) || - !CanInsertOrgan(partId, slotId, part)) + if (!Resolve(organId, ref organ, logMissing: false) + || !Resolve(partId, ref part, logMissing: false) + || !CanInsertOrgan(partId, slotId, part)) { return false; } var containerId = GetOrganContainerId(slotId); - if (!Containers.TryGetContainer(partId, containerId, out var container)) - return false; - - return Containers.Insert(organId, container); + return Containers.TryGetContainer(partId, containerId, out var container) + && Containers.Insert(organId, container); } /// @@ -111,10 +129,8 @@ public bool RemoveOrgan(EntityUid organId, OrganComponent? organ = null) var parent = container.Owner; - if (!HasComp(parent)) - return false; - - return Containers.Remove(organId, container); + return HasComp(parent) + && Containers.Remove(organId, container); } /// @@ -126,8 +142,8 @@ public bool AddOrganToFirstValidSlot( BodyPartComponent? part = null, OrganComponent? organ = null) { - if (!Resolve(partId, ref part, false) || - !Resolve(organId, ref organ, false)) + if (!Resolve(partId, ref part, logMissing: false) + || !Resolve(organId, ref organ, logMissing: false)) { return false; } diff --git a/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs b/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs index e07aac06226..ee79faa0b8e 100644 --- a/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs +++ b/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using System.Linq; using Content.Shared.Body.Components; using Content.Shared.Body.Events; @@ -23,52 +23,52 @@ private void InitializeParts() SubscribeLocalEvent(OnBodyPartRemoved); } - private void OnBodyPartInserted(EntityUid uid, BodyPartComponent component, EntInsertedIntoContainerMessage args) + private void OnBodyPartInserted(Entity ent, ref EntInsertedIntoContainerMessage args) { // Body part inserted into another body part. - var entity = args.Entity; + var insertedUid = args.Entity; var slotId = args.Container.ID; - if (component.Body == null) + if (ent.Comp.Body is null) return; - if (TryComp(entity, out BodyPartComponent? childPart)) + if (TryComp(insertedUid, out BodyPartComponent? part)) { - AddPart(component.Body.Value, entity, slotId, childPart); - RecursiveBodyUpdate(entity, component.Body.Value, childPart); + AddPart(ent.Comp.Body.Value, (insertedUid, part), slotId); + RecursiveBodyUpdate((insertedUid, part), ent.Comp.Body.Value); } - if (TryComp(entity, out OrganComponent? organ)) - AddOrgan(entity, component.Body.Value, uid, organ); + if (TryComp(insertedUid, out OrganComponent? organ)) + AddOrgan((insertedUid, organ), ent.Comp.Body.Value, ent); } - private void OnBodyPartRemoved(EntityUid uid, BodyPartComponent component, EntRemovedFromContainerMessage args) + private void OnBodyPartRemoved(Entity ent, ref EntRemovedFromContainerMessage args) { // Body part removed from another body part. - var entity = args.Entity; + var removedUid = args.Entity; var slotId = args.Container.ID; - DebugTools.Assert(!TryComp(entity, out BodyPartComponent? b) || b.Body == component.Body); - DebugTools.Assert(!TryComp(entity, out OrganComponent? o) || o.Body == component.Body); + DebugTools.Assert(!TryComp(removedUid, out BodyPartComponent? b) || b.Body == ent.Comp.Body); + DebugTools.Assert(!TryComp(removedUid, out OrganComponent? o) || o.Body == ent.Comp.Body); - if (TryComp(entity, out BodyPartComponent? childPart) && childPart.Body != null) + if (TryComp(removedUid, out BodyPartComponent? part) && part.Body is not null) { - RemovePart(childPart.Body.Value, entity, slotId, childPart); - RecursiveBodyUpdate(entity, null, childPart); + RemovePart(part.Body.Value, (removedUid, part), slotId); + RecursiveBodyUpdate((removedUid, part), null); } - if (TryComp(entity, out OrganComponent? organ)) - RemoveOrgan(entity, uid, organ); + if (TryComp(removedUid, out OrganComponent? organ)) + RemoveOrgan((removedUid, organ), ent); } - private void RecursiveBodyUpdate(EntityUid uid, EntityUid? bodyUid, BodyPartComponent component) + private void RecursiveBodyUpdate(Entity ent, EntityUid? bodyUid) { - component.Body = bodyUid; - Dirty(uid, component); + ent.Comp.Body = bodyUid; + Dirty(ent, ent.Comp); - foreach (var slotId in component.Organs.Keys) + foreach (var slotId in ent.Comp.Organs.Keys) { - if (!Containers.TryGetContainer(uid, GetOrganContainerId(slotId), out var container)) + if (!Containers.TryGetContainer(ent, GetOrganContainerId(slotId), out var container)) continue; foreach (var organ in container.ContainedEntities) @@ -78,105 +78,108 @@ private void RecursiveBodyUpdate(EntityUid uid, EntityUid? bodyUid, BodyPartComp Dirty(organ, organComp); - if (organComp.Body != null) - RaiseLocalEvent(organ, new RemovedFromPartInBodyEvent(organComp.Body.Value, uid)); + if (organComp.Body is { Valid: true } oldBodyUid) + { + var removedEv = new OrganRemovedFromBodyEvent(oldBodyUid, ent); + RaiseLocalEvent(organ, ref removedEv); + } organComp.Body = bodyUid; - if (bodyUid != null) - RaiseLocalEvent(organ, new AddedToPartInBodyEvent(bodyUid.Value, uid)); + if (bodyUid is not null) + { + var addedEv = new OrganAddedToBodyEvent(bodyUid.Value, ent); + RaiseLocalEvent(organ, ref addedEv); + } } } - foreach (var slotId in component.Children.Keys) + foreach (var slotId in ent.Comp.Children.Keys) { - if (!Containers.TryGetContainer(uid, GetPartSlotContainerId(slotId), out var container)) + if (!Containers.TryGetContainer(ent, GetPartSlotContainerId(slotId), out var container)) continue; - foreach (var containedEnt in container.ContainedEntities) + foreach (var containedUid in container.ContainedEntities) { - if (TryComp(containedEnt, out BodyPartComponent? childPart)) - RecursiveBodyUpdate(containedEnt, bodyUid, childPart); + if (TryComp(containedUid, out BodyPartComponent? childPart)) + RecursiveBodyUpdate((containedUid, childPart), bodyUid); } } } protected virtual void AddPart( - EntityUid bodyUid, - EntityUid partUid, - string slotId, - BodyPartComponent component, - BodyComponent? bodyComp = null) + Entity bodyEnt, + Entity partEnt, + string slotId) { - DebugTools.AssertOwner(partUid, component); - Dirty(partUid, component); - component.Body = bodyUid; + Dirty(partEnt, partEnt.Comp); + partEnt.Comp.Body = bodyEnt; - var ev = new BodyPartAddedEvent(slotId, component); - RaiseLocalEvent(bodyUid, ref ev); + var ev = new BodyPartAddedEvent(slotId, partEnt); + RaiseLocalEvent(bodyEnt, ref ev); - AddLeg(partUid, bodyUid, component, bodyComp); + AddLeg(partEnt, bodyEnt); } protected virtual void RemovePart( - EntityUid bodyUid, - EntityUid partUid, - string slotId, - BodyPartComponent component, - BodyComponent? bodyComp = null) + Entity bodyEnt, + Entity partEnt, + string slotId) { - DebugTools.AssertOwner(partUid, component); - Resolve(bodyUid, ref bodyComp, false); - Dirty(partUid, component); - component.Body = null; + Resolve(bodyEnt, ref bodyEnt.Comp, logMissing: false); + Dirty(partEnt, partEnt.Comp); + partEnt.Comp.Body = null; - var ev = new BodyPartRemovedEvent(slotId, component); - RaiseLocalEvent(bodyUid, ref ev); + var ev = new BodyPartRemovedEvent(slotId, partEnt); + RaiseLocalEvent(bodyEnt, ref ev); - RemoveLeg(partUid, bodyUid, component); - PartRemoveDamage(bodyUid, component, bodyComp); + RemoveLeg(partEnt, bodyEnt); + PartRemoveDamage(bodyEnt, partEnt); } - private void AddLeg(EntityUid uid, EntityUid bodyUid, BodyPartComponent component, BodyComponent? bodyComp = null) + private void AddLeg(Entity legEnt, Entity bodyEnt) { - if (!Resolve(bodyUid, ref bodyComp, false)) + if (!Resolve(bodyEnt, ref bodyEnt.Comp, logMissing: false)) return; - if (component.PartType == BodyPartType.Leg) + if (legEnt.Comp.PartType == BodyPartType.Leg) { - bodyComp.LegEntities.Add(uid); - UpdateMovementSpeed(bodyUid); - Dirty(bodyUid, bodyComp); + bodyEnt.Comp.LegEntities.Add(legEnt); + UpdateMovementSpeed(bodyEnt); + Dirty(bodyEnt, bodyEnt.Comp); } } - private void RemoveLeg(EntityUid uid, EntityUid bodyUid, BodyPartComponent component, BodyComponent? bodyComp = null) + private void RemoveLeg(Entity legEnt, Entity bodyEnt) { - if (!Resolve(bodyUid, ref bodyComp, false)) + if (!Resolve(bodyEnt, ref bodyEnt.Comp, logMissing: false)) return; - if (component.PartType == BodyPartType.Leg) + if (legEnt.Comp.PartType == BodyPartType.Leg) { - bodyComp.LegEntities.Remove(uid); - UpdateMovementSpeed(bodyUid); - Dirty(bodyUid, bodyComp); + bodyEnt.Comp.LegEntities.Remove(legEnt); + UpdateMovementSpeed(bodyEnt); + Dirty(bodyEnt, bodyEnt.Comp); - if (!bodyComp.LegEntities.Any()) + if (!bodyEnt.Comp.LegEntities.Any()) { - Standing.Down(bodyUid); + Standing.Down(bodyEnt); } } } - private void PartRemoveDamage(EntityUid parent, BodyPartComponent component, BodyComponent? bodyComp = null) + private void PartRemoveDamage(Entity bodyEnt, Entity partEnt) { - if (!Resolve(parent, ref bodyComp, false)) + if (!Resolve(bodyEnt, ref bodyEnt.Comp, logMissing: false)) return; - if (!_timing.ApplyingState && component.IsVital && !GetBodyChildrenOfType(parent, component.PartType, bodyComp).Any()) + if (!_timing.ApplyingState + && partEnt.Comp.IsVital + && !GetBodyChildrenOfType(bodyEnt, partEnt.Comp.PartType, bodyEnt.Comp).Any() + ) { // TODO BODY SYSTEM KILL : remove this when wounding and required parts are implemented properly var damage = new DamageSpecifier(Prototypes.Index("Bloodloss"), 300); - Damageable.TryChangeDamage(parent, damage); + Damageable.TryChangeDamage(bodyEnt, damage); } } @@ -212,7 +215,8 @@ private void PartRemoveDamage(EntityUid parent, BodyPartComponent component, Bod var parent = container.Owner; - if (!TryComp(parent, out var parentBody) || !parentBody.Children.ContainsKey(slotId)) + if (!TryComp(parent, out var parentBody) + || !parentBody.Children.ContainsKey(slotId)) return null; return (parent, slotId); @@ -252,7 +256,7 @@ public bool TryGetParentBodyPart( BodyPartType partType, BodyPartComponent? part = null) { - if (!Resolve(partUid, ref part, false)) + if (!Resolve(partUid, ref part, logMissing: false)) return null; Containers.EnsureContainer(partUid, GetPartSlotContainerId(slotId)); @@ -275,8 +279,8 @@ public bool TryCreatePartSlot( { slot = null; - if (partId == null || - !Resolve(partId.Value, ref part, false)) + if (partId is null + || !Resolve(partId.Value, ref part, logMissing: false)) { return false; } @@ -310,24 +314,31 @@ public bool TryCreatePartSlotAndAttach( /// /// Returns true if the partId is the root body container for the specified bodyId. /// - public bool IsPartRoot(EntityUid bodyId, EntityUid partId, BodyComponent? body = null, BodyPartComponent? part = null) + public bool IsPartRoot( + EntityUid bodyId, + EntityUid partId, + BodyComponent? body = null, + BodyPartComponent? part = null) { - if (!Resolve(partId, ref part)|| !Resolve(bodyId, ref body)) - return false; - - return Containers.TryGetContainingContainer(bodyId, partId, out var container) && container.ID == BodyRootContainerId; + return Resolve(partId, ref part) + && Resolve(bodyId, ref body) + && Containers.TryGetContainingContainer(bodyId, partId, out var container) + && container.ID == BodyRootContainerId; } /// /// Returns true if we can attach the partId to the bodyId as the root entity. /// - public bool CanAttachToRoot(EntityUid bodyId, EntityUid partId, BodyComponent? body = null, + public bool CanAttachToRoot( + EntityUid bodyId, + EntityUid partId, + BodyComponent? body = null, BodyPartComponent? part = null) { - return Resolve(bodyId, ref body) && - Resolve(partId, ref part) && - body.RootContainer.ContainedEntity == null && - bodyId != part.Body; + return Resolve(bodyId, ref body) + && Resolve(partId, ref part) + && body.RootContainer.ContainedEntity is null + && bodyId != part.Body; } /// @@ -335,8 +346,11 @@ public bool CanAttachToRoot(EntityUid bodyId, EntityUid partId, BodyComponent? b /// public (EntityUid Entity, BodyPartComponent BodyPart)? GetRootPartOrNull(EntityUid bodyId, BodyComponent? body = null) { - if (!Resolve(bodyId, ref body) || body.RootContainer.ContainedEntity == null) + if (!Resolve(bodyId, ref body) + || body.RootContainer.ContainedEntity is null) + { return null; + } return (body.RootContainer.ContainedEntity.Value, Comp(body.RootContainer.ContainedEntity.Value)); @@ -352,13 +366,9 @@ public bool CanAttachPart( BodyPartComponent? parentPart = null, BodyPartComponent? part = null) { - if (!Resolve(partId, ref part, false) || - !Resolve(parentId, ref parentPart, false)) - { - return false; - } - - return CanAttachPart(parentId, slot.Id, partId, parentPart, part); + return Resolve(partId, ref part, logMissing: false) + && Resolve(parentId, ref parentPart, logMissing: false) + && CanAttachPart(parentId, slot.Id, partId, parentPart, part); } /// @@ -371,16 +381,12 @@ public bool CanAttachPart( BodyPartComponent? parentPart = null, BodyPartComponent? part = null) { - if (!Resolve(partId, ref part, false) || - !Resolve(parentId, ref parentPart, false) || - !parentPart.Children.TryGetValue(slotId, out var parentSlotData)) - { - return false; - } - - return part.PartType == parentSlotData.Type && - Containers.TryGetContainer(parentId, GetPartSlotContainerId(slotId), out var container) && - Containers.CanInsert(partId, container); + return Resolve(partId, ref part, logMissing: false) + && Resolve(parentId, ref parentPart, logMissing: false) + && parentPart.Children.TryGetValue(slotId, out var parentSlotData) + && part.PartType == parentSlotData.Type + && Containers.TryGetContainer(parentId, GetPartSlotContainerId(slotId), out var container) + && Containers.CanInsert(partId, container); } public bool AttachPartToRoot( @@ -389,14 +395,10 @@ public bool AttachPartToRoot( BodyComponent? body = null, BodyPartComponent? part = null) { - if (!Resolve(bodyId, ref body) || - !Resolve(partId, ref part) || - !CanAttachToRoot(bodyId, partId, body, part)) - { - return false; - } - - return Containers.Insert(partId, body.RootContainer); + return Resolve(bodyId, ref body) + && Resolve(partId, ref part) + && CanAttachToRoot(bodyId, partId, body, part) + && Containers.Insert(partId, body.RootContainer); } #endregion @@ -406,20 +408,16 @@ public bool AttachPartToRoot( /// /// Attaches a body part to the specified body part parent. /// - public bool AttachPart( - EntityUid parentPartId, - string slotId, - EntityUid partId, - BodyPartComponent? parentPart = null, - BodyPartComponent? part = null) - { - if (!Resolve(parentPartId, ref parentPart, false) || - !parentPart.Children.TryGetValue(slotId, out var slot)) - { - return false; - } - - return AttachPart(parentPartId, slot, partId, parentPart, part); + public bool AttachPart( + EntityUid parentPartId, + string slotId, + EntityUid partId, + BodyPartComponent? parentPart = null, + BodyPartComponent? part = null) + { + return Resolve(parentPartId, ref parentPart, logMissing: false) + && parentPart.Children.TryGetValue(slotId, out var slot) + && AttachPart(parentPartId, slot, partId, parentPart, part); } /// @@ -432,10 +430,10 @@ public bool AttachPart( BodyPartComponent? parentPart = null, BodyPartComponent? part = null) { - if (!Resolve(parentPartId, ref parentPart, false) || - !Resolve(partId, ref part, false) || - !CanAttachPart(parentPartId, slot.Id, partId, parentPart, part) || - !parentPart.Children.ContainsKey(slot.Id)) + if (!Resolve(parentPartId, ref parentPart, logMissing: false) + || !Resolve(partId, ref part, logMissing: false) + || !CanAttachPart(parentPartId, slot.Id, partId, parentPart, part) + || !parentPart.Children.ContainsKey(slot.Id)) { return false; } @@ -453,13 +451,16 @@ public bool AttachPart( #region Misc - public void UpdateMovementSpeed(EntityUid bodyId, BodyComponent? body = null, MovementSpeedModifierComponent? movement = null) + public void UpdateMovementSpeed( + EntityUid bodyId, + BodyComponent? body = null, + MovementSpeedModifierComponent? movement = null) { - if (!Resolve(bodyId, ref body, ref movement, false)) - return; - - if (body.RequiredLegs <= 0) + if (!Resolve(bodyId, ref body, ref movement, logMissing: false) + || body.RequiredLegs <= 0) + { return; + } var walkSpeed = 0f; var sprintSpeed = 0f; @@ -488,7 +489,7 @@ public void UpdateMovementSpeed(EntityUid bodyId, BodyComponent? body = null, Mo /// public IEnumerable<(EntityUid Id, OrganComponent Component)> GetPartOrgans(EntityUid partId, BodyPartComponent? part = null) { - if (!Resolve(partId, ref part, false)) + if (!Resolve(partId, ref part, logMissing: false)) yield break; foreach (var slotId in part.Organs.Keys) @@ -513,7 +514,7 @@ public void UpdateMovementSpeed(EntityUid bodyId, BodyComponent? body = null, Mo /// public IEnumerable GetPartContainers(EntityUid id, BodyPartComponent? part = null) { - if (!Resolve(id, ref part, false) || + if (!Resolve(id, ref part, logMissing: false) || part.Children.Count == 0) { yield break; @@ -541,9 +542,11 @@ public IEnumerable GetPartContainers(EntityUid id, BodyPartCompon /// /// Returns all body part components for this entity including itself. /// - public IEnumerable<(EntityUid Id, BodyPartComponent Component)> GetBodyPartChildren(EntityUid partId, BodyPartComponent? part = null) + public IEnumerable<(EntityUid Id, BodyPartComponent Component)> GetBodyPartChildren( + EntityUid partId, + BodyPartComponent? part = null) { - if (!Resolve(partId, ref part, false)) + if (!Resolve(partId, ref part, logMissing: false)) yield break; yield return (partId, part); @@ -571,9 +574,11 @@ public IEnumerable GetPartContainers(EntityUid id, BodyPartCompon /// /// Returns all body part slots for this entity. /// - public IEnumerable GetAllBodyPartSlots(EntityUid partId, BodyPartComponent? part = null) + public IEnumerable GetAllBodyPartSlots( + EntityUid partId, + BodyPartComponent? part = null) { - if (!Resolve(partId, ref part, false)) + if (!Resolve(partId, ref part, logMissing: false)) yield break; foreach (var (slotId, slot) in part.Children) @@ -601,7 +606,10 @@ public IEnumerable GetAllBodyPartSlots(EntityUid partId, BodyPartC /// /// Returns true if the bodyId has any parts of this type. /// - public bool BodyHasPartType(EntityUid bodyId, BodyPartType type, BodyComponent? body = null) + public bool BodyHasPartType( + EntityUid bodyId, + BodyPartType type, + BodyComponent? body = null) { return GetBodyChildrenOfType(bodyId, type, body).Any(); } @@ -615,8 +623,8 @@ public bool PartHasChild( BodyPartComponent? parent, BodyPartComponent? child) { - if (!Resolve(parentId, ref parent, false) || - !Resolve(childId, ref child, false)) + if (!Resolve(parentId, ref parent, logMissing: false) + || !Resolve(childId, ref child, logMissing: false)) { return false; } @@ -638,15 +646,11 @@ public bool BodyHasChild( BodyComponent? body = null, BodyPartComponent? part = null) { - if (!Resolve(bodyId, ref body, false) || - body.RootContainer.ContainedEntity == null || - !Resolve(partId, ref part, false) || - !TryComp(body.RootContainer.ContainedEntity, out BodyPartComponent? rootPart)) - { - return false; - } - - return PartHasChild(body.RootContainer.ContainedEntity.Value, partId, rootPart, part); + return Resolve(bodyId, ref body, logMissing: false) + && body.RootContainer.ContainedEntity is not null + && Resolve(partId, ref part, logMissing: false) + && TryComp(body.RootContainer.ContainedEntity, out BodyPartComponent? rootPart) + && PartHasChild(body.RootContainer.ContainedEntity.Value, partId, rootPart, part); } public IEnumerable<(EntityUid Id, BodyPartComponent Component)> GetBodyChildrenOfType( @@ -721,9 +725,11 @@ public bool TryGetBodyPartOrganComponents( /// /// Gets the parent body part and all immediate child body parts for the partId. /// - public IEnumerable GetBodyPartAdjacentParts(EntityUid partId, BodyPartComponent? part = null) + public IEnumerable GetBodyPartAdjacentParts( + EntityUid partId, + BodyPartComponent? part = null) { - if (!Resolve(partId, ref part, false)) + if (!Resolve(partId, ref part, logMissing: false)) yield break; if (TryGetParentBodyPart(partId, out var parentUid, out _)) @@ -745,7 +751,7 @@ public IEnumerable GetBodyPartAdjacentParts(EntityUid partId, BodyPar BodyPartComponent? part = null) where T : IComponent { - if (!Resolve(partId, ref part, false)) + if (!Resolve(partId, ref part, logMissing: false)) yield break; var query = GetEntityQuery(); @@ -762,7 +768,7 @@ public bool TryGetBodyPartAdjacentPartsComponents( BodyPartComponent? part = null) where T : IComponent { - if (!Resolve(partId, ref part, false)) + if (!Resolve(partId, ref part, logMissing: false)) { comps = null; return false; diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs index 8172947a039..3355713bb2e 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs @@ -10,7 +10,6 @@ using Content.Shared.Mobs.Components; using Content.Shared.Movement.Events; using Content.Shared.Popups; -using Content.Shared.Pulling.Components; using Content.Shared.Standing; using Content.Shared.Storage.Components; using Content.Shared.Stunnable; @@ -19,6 +18,7 @@ using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; using Robust.Shared.Utility; +using PullableComponent = Content.Shared.Movement.Pulling.Components.PullableComponent; namespace Content.Shared.Buckle; @@ -348,11 +348,11 @@ public bool TryBuckle(EntityUid buckleUid, EntityUid userUid, EntityUid strapUid RaiseLocalEvent(ev.BuckledEntity, ref ev); RaiseLocalEvent(ev.StrapEntity, ref ev); - if (TryComp(buckleUid, out var ownerPullable)) + if (TryComp(buckleUid, out var ownerPullable)) { if (ownerPullable.Puller != null) { - _pulling.TryStopPull(ownerPullable); + _pulling.TryStopPull(buckleUid, ownerPullable); } } @@ -361,12 +361,12 @@ public bool TryBuckle(EntityUid buckleUid, EntityUid userUid, EntityUid strapUid _physics.ResetDynamics(buckleUid, physics); } - if (!buckleComp.PullStrap && TryComp(strapUid, out var toPullable)) + if (!buckleComp.PullStrap && TryComp(strapUid, out var toPullable)) { if (toPullable.Puller == buckleUid) { // can't pull it and buckle to it at the same time - _pulling.TryStopPull(toPullable); + _pulling.TryStopPull(strapUid, toPullable); } } diff --git a/Content.Shared/Buckle/SharedBuckleSystem.cs b/Content.Shared/Buckle/SharedBuckleSystem.cs index 8f683356637..67218657e52 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.cs @@ -15,6 +15,7 @@ using Robust.Shared.Physics.Systems; using Robust.Shared.Player; using Robust.Shared.Timing; +using PullingSystem = Content.Shared.Movement.Pulling.Systems.PullingSystem; namespace Content.Shared.Buckle; @@ -35,7 +36,7 @@ public abstract partial class SharedBuckleSystem : EntitySystem [Dependency] private readonly SharedInteractionSystem _interaction = default!; [Dependency] private readonly SharedJointSystem _joints = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; - [Dependency] private readonly SharedPullingSystem _pulling = default!; + [Dependency] private readonly PullingSystem _pulling = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly StandingStateSystem _standing = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs index 4486ff1883c..c1f2b7ff3d0 100644 --- a/Content.Shared/CCVar/CCVars.cs +++ b/Content.Shared/CCVar/CCVars.cs @@ -435,6 +435,36 @@ public static readonly CVarDef CVarDef.Create("game.round_end_sound_collection", "RoundEnd", CVar.SERVERONLY); + /* + * Announcers + */ + + /// + /// Weighted list of announcers to choose from + /// + public static readonly CVarDef AnnouncerList = + CVarDef.Create("announcer.list", "RandomAnnouncers", CVar.REPLICATED); + + /// + /// Optionally force set an announcer + /// + public static readonly CVarDef Announcer = + CVarDef.Create("announcer.announcer", "", CVar.SERVERONLY); + + /// + /// Optionally blacklist announcers + /// List of IDs separated by commas + /// + public static readonly CVarDef AnnouncerBlacklist = + CVarDef.Create("announcer.blacklist", "", CVar.SERVERONLY); + + /// + /// Changes how loud the announcers are for the client + /// + public static readonly CVarDef AnnouncerVolume = + CVarDef.Create("announcer.volume", 0.5f, CVar.ARCHIVE | CVar.CLIENTONLY); + + /* * Queue */ @@ -443,8 +473,8 @@ public static readonly CVarDef /// Controls if the connections queue is enabled /// If enabled plyaers will be added to a queue instead of being kicked after SoftMaxPlayers is reached /// - public static readonly CVarDef - QueueEnabled = CVarDef.Create("queue.enabled", false, CVar.SERVERONLY); + public static readonly CVarDef QueueEnabled = + CVarDef.Create("queue.enabled", false, CVar.SERVERONLY); /* @@ -1139,7 +1169,7 @@ public static readonly CVarDef /// Useful to prevent clipping through objects. /// public static readonly CVarDef SpaceWindMaxVelocity = - CVarDef.Create("atmos.space_wind_max_velocity", 30f, CVar.SERVERONLY); + CVarDef.Create("atmos.space_wind_max_velocity", 15f, CVar.SERVERONLY); /// /// The maximum force that may be applied to an object by pushing (i.e. not throwing) atmospheric pressure differences. @@ -1148,6 +1178,24 @@ public static readonly CVarDef public static readonly CVarDef SpaceWindMaxPushForce = CVarDef.Create("atmos.space_wind_max_push_force", 20f, CVar.SERVERONLY); + /// + /// If an object's mass is below this number, then this number is used in place of mass to determine whether air pressure can throw an object. + /// This has nothing to do with throwing force, only acting as a way of reducing the odds of tiny 5 gram objects from being yeeted by people's breath + /// + /// + /// If you are reading this because you want to change it, consider looking into why almost every item in the game weighs only 5 grams + /// And maybe do your part to fix that? :) + /// + public static readonly CVarDef SpaceWindMinimumCalculatedMass = + CVarDef.Create("atmos.space_wind_minimum_calculated_mass", 10f, CVar.SERVERONLY); + + /// + /// Calculated as 1/Mass, where Mass is the physics.Mass of the desired threshold. + /// If an object's inverse mass is lower than this, it is capped at this. Basically, an upper limit to how heavy an object can be before it stops resisting space wind more. + /// + public static readonly CVarDef SpaceWindMaximumCalculatedInverseMass = + CVarDef.Create("atmos.space_wind_maximum_calculated_inverse_mass", 0.04f, CVar.SERVERONLY); + /// /// Whether monstermos tile equalization is enabled. /// @@ -1169,7 +1217,21 @@ public static readonly CVarDef /// Also looks weird on slow spacing for unrelated reasons. If you do want to enable this, you should probably turn on instaspacing. /// public static readonly CVarDef MonstermosRipTiles = - CVarDef.Create("atmos.monstermos_rip_tiles", false, CVar.SERVERONLY); + CVarDef.Create("atmos.monstermos_rip_tiles", true, CVar.SERVERONLY); + + /// + /// Taken as the cube of a tile's mass, this acts as a minimum threshold of mass for which air pressure calculates whether or not to rip a tile from the floor + /// This should be set by default to the cube of the game's lowest mass tile as defined in their prototypes, but can be increased for server performance reasons + /// + public static readonly CVarDef MonstermosRipTilesMinimumPressure = + CVarDef.Create("atmos.monstermos_rip_tiles_min_pressure", 7500f, CVar.SERVERONLY); + + /// + /// Taken after the minimum pressure is checked, the effective pressure is multiplied by this amount. + /// This allows server hosts to finely tune how likely floor tiles are to be ripped apart by air pressure + /// + public static readonly CVarDef MonstermosRipTilesPressureOffset = + CVarDef.Create("atmos.monstermos_rip_tiles_pressure_offset", 0.44f, CVar.SERVERONLY); /// /// Whether explosive depressurization will cause the grid to gain an impulse. @@ -1200,6 +1262,13 @@ public static readonly CVarDef public static readonly CVarDef AtmosSpacingMaxWind = CVarDef.Create("atmos.mmos_max_wind", 500f, CVar.SERVERONLY); + /// + /// Increases default airflow calculations to O(n^2) complexity, for use with heavy space wind optimizations. Potato servers BEWARE + /// This solves the problem of objects being trapped in an infinite loop of slamming into a wall repeatedly. + /// + public static readonly CVarDef MonstermosUseExpensiveAirflow = + CVarDef.Create("atmos.mmos_expensive_airflow", true, CVar.SERVERONLY); + /// /// Whether atmos superconduction is enabled. /// @@ -1256,6 +1325,13 @@ public static readonly CVarDef public static readonly CVarDef AtmosHeatScale = CVarDef.Create("atmos.heat_scale", 8f, CVar.SERVERONLY); + /// + /// A multiplier on the amount of force applied to Humanoid entities, as tracked by HumanoidAppearanceComponent + /// This multiplier is added after all other checks are made, and applies to both throwing force, and how easy it is for an entity to be thrown. + /// + public static readonly CVarDef AtmosHumanoidThrowMultiplier = + CVarDef.Create("atmos.humanoid_throw_multiplier", 2f, CVar.SERVERONLY); + /* * MIDI instruments */ @@ -1641,6 +1717,23 @@ public static readonly CVarDef public static readonly CVarDef ViewportWidth = CVarDef.Create("viewport.width", 21, CVar.CLIENTONLY | CVar.ARCHIVE); + /* + * FOV + */ + + /// + /// The number by which the current FOV size is divided for each level. + /// + public static readonly CVarDef ZoomLevelStep = + CVarDef.Create("fov.zoom_step", 1.2f, CVar.SERVER | CVar.REPLICATED); + + /// + /// How many times the player can zoom in until they reach the minimum zoom. + /// This does not affect the maximum zoom. + /// + public static readonly CVarDef ZoomLevels = + CVarDef.Create("fov.zoom_levels", 7, CVar.SERVER | CVar.REPLICATED); + /* * UI */ @@ -2182,7 +2275,20 @@ public static readonly CVarDef CVarDef.Create("game.station_goals_chance", 0.1f, CVar.SERVERONLY); /// - /// How many characters the consent text can be. + /// Toggles all MassContest functions. All mass contests output 1f when false + /// + public static readonly CVarDef DoMassContests = + CVarDef.Create("contests.do_mass_contests", true, CVar.REPLICATED | CVar.SERVER); + + /// + /// The maximum amount that Mass Contests can modify a physics multiplier, given as a +/- percentage + /// Default of 0.25f outputs between * 0.75f and 1.25f + /// + public static readonly CVarDef MassContestsMaxPercentage = + CVarDef.Create("contests.max_percentage", 0.25f, CVar.REPLICATED | CVar.SERVER); + + /// + /// How many characters the consent text can be. // Floofstation /// public static readonly CVarDef ConsentFreetextMaxLength = CVarDef.Create("consent.freetext_max_length", 1000, CVar.REPLICATED | CVar.SERVER); diff --git a/Content.Shared/Chat/V2/Moderation/ChatCensor.cs b/Content.Shared/Chat/V2/Moderation/ChatCensor.cs new file mode 100644 index 00000000000..b5d6aa03441 --- /dev/null +++ b/Content.Shared/Chat/V2/Moderation/ChatCensor.cs @@ -0,0 +1,59 @@ +using System.Linq; + +namespace Content.Shared.Chat.V2.Moderation; + +public interface IChatCensor +{ + public bool Censor(string input, out string output, char replaceWith = '*'); +} + +public sealed class CompoundChatCensor(IEnumerable censors) : IChatCensor +{ + public bool Censor(string input, out string output, char replaceWith = '*') + { + var censored = false; + + foreach (var censor in censors) + { + if (censor.Censor(input, out output, replaceWith)) + { + censored = true; + } + } + + output = input; + + return censored; + } +} + +public sealed class ChatCensorFactory +{ + private List _censors = new(); + + public void With(IChatCensor censor) + { + _censors.Add(censor); + } + + /// + /// Builds a ChatCensor that combines all the censors that have been added to this. + /// + public IChatCensor Build() + { + return new CompoundChatCensor(_censors.ToArray()); + } + + /// + /// Resets the build state to zero, allowing for different rules to be provided to the next censor(s) built. + /// + /// True if the builder had any setup prior to the reset. + public bool Reset() + { + var notEmpty = _censors.Count > 0; + + _censors = new List(); + + return notEmpty; + } +} diff --git a/Content.Shared/Chat/V2/Moderation/RegexCensor.cs b/Content.Shared/Chat/V2/Moderation/RegexCensor.cs new file mode 100644 index 00000000000..cd47bf0c33c --- /dev/null +++ b/Content.Shared/Chat/V2/Moderation/RegexCensor.cs @@ -0,0 +1,15 @@ +using System.Text.RegularExpressions; + +namespace Content.Shared.Chat.V2.Moderation; + +public sealed class RegexCensor(Regex censorInstruction) : IChatCensor +{ + private readonly Regex _censorInstruction = censorInstruction; + + public bool Censor(string input, out string output, char replaceWith = '*') + { + output = _censorInstruction.Replace(input, replaceWith.ToString()); + + return !string.Equals(input, output); + } +} diff --git a/Content.Shared/Chat/V2/Moderation/SimpleCensor.cs b/Content.Shared/Chat/V2/Moderation/SimpleCensor.cs new file mode 100644 index 00000000000..a6bb70dd9f6 --- /dev/null +++ b/Content.Shared/Chat/V2/Moderation/SimpleCensor.cs @@ -0,0 +1,340 @@ +using System.Collections.Frozen; +using System.Linq; +using System.Text; +using System.Text.Unicode; + +namespace Content.Shared.Chat.V2.Moderation; + +/// +/// A basic censor. Not bullet-proof. +/// +public sealed class SimpleCensor : IChatCensor +{ + // Common substitution symbols are replaced with one of the characters they commonly substitute. + private bool _shouldSanitizeLeetspeak; + private FrozenDictionary _leetspeakReplacements = FrozenDictionary.Empty; + + // Special characters are replaced with spaces. + private bool _shouldSanitizeSpecialCharacters; + private HashSet _specialCharacterReplacements = []; + + // Censored words are removed unless they're a false positive (e.g. Scunthorpe) + private string[] _censoredWords = Array.Empty(); + private string[] _falsePositives = Array.Empty(); + + // False negatives are censored words that contain a false positives. + private string[] _falseNegatives = Array.Empty(); + + // What unicode ranges are allowed? If this array is empty, don't filter by range. + private UnicodeRange[] _allowedUnicodeRanges= Array.Empty(); + + /// + /// Censors the input string. + /// + /// The input string + /// The output string + /// The character to replace with + /// If output is valid + public bool Censor(string input, out string output, char replaceWith = '*') + { + output = Censor(input, replaceWith); + + return !string.Equals(input, output); + } + + public string Censor(string input, char replaceWith = '*') + { + // We flat-out ban anything not in the allowed unicode ranges, stripping them + input = SanitizeOutBlockedUnicode(input); + + var originalInput = input.ToCharArray(); + + input = SanitizeInput(input); + + var censored = input.ToList(); + + // Remove false negatives + input = CheckProfanity(input, censored, _falseNegatives, replaceWith); + + // Get false positives + var falsePositives = FindFalsePositives(censored, replaceWith); + + // Remove censored words + CheckProfanity(input, censored, _censoredWords, replaceWith); + + // Reconstruct + // Reconstruct false positives + for (var i = 0; i < falsePositives.Length; i++) + { + if (falsePositives[i] != replaceWith) + { + censored[i] = falsePositives[i]; + } + } + + for (var i = 0; i < originalInput.Length; i++) + { + if (originalInput[i] == ' ') + { + censored.Insert(i, ' '); + + continue; + } + + if (_shouldSanitizeSpecialCharacters && _specialCharacterReplacements.Contains(originalInput[i])) + { + censored.Insert(i, originalInput[i]); + + continue; + } + + if (_shouldSanitizeLeetspeak || _shouldSanitizeSpecialCharacters) + { + // detect "()" + if (originalInput[i] == '(' && i != originalInput.Length - 1 && originalInput[i+1] == ')') + { + // censored has now had "o" replaced with "o) so both strings line up again..." + censored.Insert(i+1, censored[i] != replaceWith ? ')' : replaceWith); + } + } + + if (censored[i] != replaceWith) + { + censored[i] = originalInput[i]; + } + } + + // SO says this is fast... + return string.Concat(censored); + } + + /// + /// Adds a l33tsp34k sanitization rule + /// + /// The censor for further configuration + public SimpleCensor WithSanitizeLeetSpeak() + { + _shouldSanitizeLeetspeak = true; + + return BuildCharacterReplacements(); + } + + /// + /// Adds a l33tsp34k sanitization rule + /// + /// The censor for further configuration + public SimpleCensor WithSanitizeSpecialCharacters() + { + _shouldSanitizeSpecialCharacters = true; + + return BuildCharacterReplacements(); + } + + public SimpleCensor WithRanges(UnicodeRange[] ranges) + { + _allowedUnicodeRanges = ranges; + + return this; + } + + public SimpleCensor WithCustomDictionary(string[] naughtyWords) + { + _censoredWords = naughtyWords; + + return this; + } + + public SimpleCensor WithFalsePositives(string[] falsePositives) + { + _falsePositives = falsePositives; + + return this; + } + + public SimpleCensor WithFalseNegatives(string[] falseNegatives) + { + _falseNegatives = falseNegatives; + + return this; + } + + public SimpleCensor WithLeetspeakReplacements(Dictionary replacements) + { + _leetspeakReplacements = replacements.ToFrozenDictionary(); + + return this; + } + + public SimpleCensor WithSpecialCharacterReplacements(Dictionary replacements) + { + _leetspeakReplacements = replacements.ToFrozenDictionary(); + + return this; + } + + private string CheckProfanity(string input, List censored, string[] words, char replaceWith = '*') + { + foreach (var word in words) + { + var wordLength = word.Length; + var endOfFoundWord = 0; + var foundIndex = input.IndexOf(word, endOfFoundWord, StringComparison.OrdinalIgnoreCase); + + while(foundIndex > -1) + { + endOfFoundWord = foundIndex + wordLength; + + for (var i = 0; i < wordLength; i++) + { + censored[foundIndex+i] = replaceWith; + } + + foundIndex = input.IndexOf(word, endOfFoundWord, StringComparison.OrdinalIgnoreCase); + } + } + + return input; + } + + private char[] FindFalsePositives(List chars, char replaceWith = '*') + { + var input = string.Concat(chars); + + var output = Enumerable.Repeat(replaceWith, input.Length).ToArray(); + var inputAsARr = input.ToArray(); + + foreach (var word in _falsePositives) + { + var wordLength = word.Length; + var endOfFoundWord = 0; + var foundIndex = input.IndexOf(word, endOfFoundWord, StringComparison.OrdinalIgnoreCase); + + while(foundIndex > -1) + { + endOfFoundWord = foundIndex + wordLength; + + for (var i = foundIndex; i < endOfFoundWord; i++) + { + output[i] = inputAsARr[i]; + } + + foundIndex = input.IndexOf(word, endOfFoundWord, StringComparison.OrdinalIgnoreCase); + } + } + + return output; + } + + private string SanitizeInput(string input) + { + // "()" is a broad enough trick to beat censors that we we should check for it broadly. + if (_shouldSanitizeLeetspeak || _shouldSanitizeSpecialCharacters) + { + input = input.Replace("()", "o"); + } + + var sb = new StringBuilder(); + + // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator + foreach (var character in input) + { + if (character == ' ' || _shouldSanitizeSpecialCharacters && _specialCharacterReplacements.Contains(character)) + { + continue; + } + + if (_shouldSanitizeLeetspeak && _leetspeakReplacements.TryGetValue(character, out var leetRepl)) + { + sb.Append(leetRepl); + + continue; + } + + sb.Append(character); + } + + return sb.ToString(); + } + + /// + /// Returns a string with all characters not in ISO-8851-1 replaced with question marks + /// + private string SanitizeOutBlockedUnicode(string input) + { + if (_allowedUnicodeRanges.Length <= 0) + { + return input; + } + + var sb = new StringBuilder(); + + foreach (var symbol in input.EnumerateRunes()) + { + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (var range in _allowedUnicodeRanges) + { + if (symbol.Value < range.FirstCodePoint || symbol.Value >= range.FirstCodePoint + range.Length) + continue; + + sb.Append(symbol); + + break; + } + } + + return sb.ToString(); + } + + private SimpleCensor BuildCharacterReplacements() + { + if (_shouldSanitizeSpecialCharacters) + { + _specialCharacterReplacements = + [ + '-', + '_', + '|', + '.', + ',', + '(', + ')', + '<', + '>', + '"', + '`', + '~', + '*', + '&', + '%', + '$', + '#', + '@', + '!', + '?', + '+' + ]; + } + + if (_shouldSanitizeLeetspeak) + { + _leetspeakReplacements = new Dictionary + { + ['4'] = 'a', + ['$'] = 's', + ['!'] = 'i', + ['+'] = 't', + ['#'] = 'h', + ['@'] = 'a', + ['0'] = 'o', + ['1'] = 'i', // also obviously can be l; gamer-words need i's more though. + ['7'] = 'l', + ['3'] = 'e', + ['5'] = 's', + ['9'] = 'g', + ['<'] = 'c' + }.ToFrozenDictionary(); + } + + return this; + } +} diff --git a/Content.Shared/Chemistry/Reagent/ReagentEffect.cs b/Content.Shared/Chemistry/Reagent/ReagentEffect.cs index 5bcb21fedb3..41eea55cca4 100644 --- a/Content.Shared/Chemistry/Reagent/ReagentEffect.cs +++ b/Content.Shared/Chemistry/Reagent/ReagentEffect.cs @@ -107,6 +107,7 @@ public readonly record struct ReagentEffectArgs( FixedPoint2 Quantity, IEntityManager EntityManager, ReactionMethod? Method, - float Scale + float Scale = 1f, + float QuantityMultiplier = 1f ); } diff --git a/Content.Shared/Climbing/Systems/ClimbSystem.cs b/Content.Shared/Climbing/Systems/ClimbSystem.cs index 6a2976a8387..fceb6143e19 100644 --- a/Content.Shared/Climbing/Systems/ClimbSystem.cs +++ b/Content.Shared/Climbing/Systems/ClimbSystem.cs @@ -34,7 +34,6 @@ public sealed partial class ClimbSystem : VirtualController [Dependency] private readonly DamageableSystem _damageableSystem = default!; [Dependency] private readonly FixtureSystem _fixtureSystem = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly SharedBodySystem _bodySystem = default!; [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!; diff --git a/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs b/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs index 70bcfbab43f..c041cf1ba06 100644 --- a/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs +++ b/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs @@ -6,16 +6,15 @@ using Content.Shared.Database; using Content.Shared.DoAfter; using Content.Shared.Interaction; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Systems; using Content.Shared.Popups; -using Content.Shared.Pulling; -using Content.Shared.Pulling.Components; using Content.Shared.Tools; using Content.Shared.Tools.Components; using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Content.Shared.Tag; -using Robust.Shared.Player; using Robust.Shared.Serialization; using Robust.Shared.Utility; using SharedToolSystem = Content.Shared.Tools.Systems.SharedToolSystem; @@ -27,7 +26,7 @@ public sealed partial class AnchorableSystem : EntitySystem [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; - [Dependency] private readonly SharedPullingSystem _pulling = default!; + [Dependency] private readonly PullingSystem _pulling = default!; [Dependency] private readonly SharedToolSystem _tool = default!; [Dependency] private readonly SharedTransformSystem _transformSystem = default!; [Dependency] private readonly TagSystem _tagSystem = default!; @@ -132,9 +131,9 @@ private void OnAnchorComplete(EntityUid uid, AnchorableComponent component, TryA var rot = xform.LocalRotation; xform.LocalRotation = Math.Round(rot / (Math.PI / 2)) * (Math.PI / 2); - if (TryComp(uid, out var pullable) && pullable.Puller != null) + if (TryComp(uid, out var pullable) && pullable.Puller != null) { - _pulling.TryStopPull(pullable); + _pulling.TryStopPull(uid, pullable); } // TODO: Anchoring snaps rn anyway! @@ -175,7 +174,7 @@ private void OnAnchorComplete(EntityUid uid, AnchorableComponent component, TryA public void TryToggleAnchor(EntityUid uid, EntityUid userUid, EntityUid usingUid, AnchorableComponent? anchorable = null, TransformComponent? transform = null, - SharedPullableComponent? pullable = null, + PullableComponent? pullable = null, ToolComponent? usingTool = null) { if (!Resolve(uid, ref transform)) @@ -198,7 +197,7 @@ public void TryToggleAnchor(EntityUid uid, EntityUid userUid, EntityUid usingUid private void TryAnchor(EntityUid uid, EntityUid userUid, EntityUid usingUid, AnchorableComponent? anchorable = null, TransformComponent? transform = null, - SharedPullableComponent? pullable = null, + PullableComponent? pullable = null, ToolComponent? usingTool = null) { if (!Resolve(uid, ref anchorable, ref transform)) @@ -271,7 +270,7 @@ private bool TileFree(EntityCoordinates coordinates, PhysicsComponent anchorBody // Probably ignore CanCollide on the anchoring body? var gridUid = coordinates.GetGridUid(EntityManager); - if (!_mapManager.TryGetGrid(gridUid, out var grid)) + if (!TryComp(gridUid, out var grid)) return false; var tileIndices = grid.TileIndicesFor(coordinates); diff --git a/Content.Shared/Construction/SharedFlatpackSystem.cs b/Content.Shared/Construction/SharedFlatpackSystem.cs index a62488d6f38..8b21bca52ae 100644 --- a/Content.Shared/Construction/SharedFlatpackSystem.cs +++ b/Content.Shared/Construction/SharedFlatpackSystem.cs @@ -114,8 +114,7 @@ public void SetupFlatpack(Entity ent, EntityUid? board) if (!Resolve(ent, ref ent.Comp)) return; - EntProtoId machinePrototypeId; - string? entityPrototype; + var machinePrototypeId = new EntProtoId(); if (TryComp(board, out var machineBoard) && machineBoard.Prototype is not null) machinePrototypeId = machineBoard.Prototype; else if (TryComp(board, out var computerBoard) && computerBoard.Prototype is not null) diff --git a/Content.Shared/Contests/ContestsSystem.cs b/Content.Shared/Contests/ContestsSystem.cs new file mode 100644 index 00000000000..6386bfd7a23 --- /dev/null +++ b/Content.Shared/Contests/ContestsSystem.cs @@ -0,0 +1,116 @@ +using Content.Shared.CCVar; +using Robust.Shared.Configuration; +using Robust.Shared.Physics.Components; + +namespace Content.Shared.Contests +{ + public sealed partial class ContestsSystem : EntitySystem + { + [Dependency] private readonly IConfigurationManager _cfg = default!; + + /// + /// The presumed average mass of a player entity + /// Defaulted to the average mass of an adult human + /// + private const float AverageMass = 71f; + + #region Mass Contests + /// + /// Outputs the ratio of mass between a performer and the average human mass + /// + /// Uid of Performer + public float MassContest(EntityUid performerUid, float otherMass = AverageMass) + { + if (_cfg.GetCVar(CCVars.DoMassContests) + && TryComp(performerUid, out var performerPhysics) + && performerPhysics.Mass != 0) + return Math.Clamp(performerPhysics.Mass / otherMass, 1 - _cfg.GetCVar(CCVars.MassContestsMaxPercentage), 1 + _cfg.GetCVar(CCVars.MassContestsMaxPercentage)); + + return 1f; + } + + /// + /// + /// MaybeMassContest, in case your entity doesn't exist + /// + public float MassContest(EntityUid? performerUid, float otherMass = AverageMass) + { + if (_cfg.GetCVar(CCVars.DoMassContests)) + { + var ratio = performerUid is { } uid ? MassContest(uid, otherMass) : 1f; + return ratio; + } + + return 1f; + } + + /// + /// Outputs the ratio of mass between a performer and the average human mass + /// If a function already has the performer's physics component, this is faster + /// + /// + public float MassContest(PhysicsComponent performerPhysics, float otherMass = AverageMass) + { + if (_cfg.GetCVar(CCVars.DoMassContests) + && performerPhysics.Mass != 0) + return Math.Clamp(performerPhysics.Mass / otherMass, 1 - _cfg.GetCVar(CCVars.MassContestsMaxPercentage), 1 + _cfg.GetCVar(CCVars.MassContestsMaxPercentage)); + + return 1f; + } + + /// + /// Outputs the ratio of mass between a performer and a target, accepts either EntityUids or PhysicsComponents in any combination + /// If you have physics components already in your function, use instead + /// + /// + /// + public float MassContest(EntityUid performerUid, EntityUid targetUid) + { + if (_cfg.GetCVar(CCVars.DoMassContests) + && TryComp(performerUid, out var performerPhysics) + && TryComp(targetUid, out var targetPhysics) + && performerPhysics.Mass != 0 + && targetPhysics.InvMass != 0) + return Math.Clamp(performerPhysics.Mass * targetPhysics.InvMass, 1 - _cfg.GetCVar(CCVars.MassContestsMaxPercentage), 1 + _cfg.GetCVar(CCVars.MassContestsMaxPercentage)); + + return 1f; + } + + /// + public float MassContest(EntityUid performerUid, PhysicsComponent targetPhysics) + { + if (_cfg.GetCVar(CCVars.DoMassContests) + && TryComp(performerUid, out var performerPhysics) + && performerPhysics.Mass != 0 + && targetPhysics.InvMass != 0) + return Math.Clamp(performerPhysics.Mass * targetPhysics.InvMass, 1 - _cfg.GetCVar(CCVars.MassContestsMaxPercentage), 1 + _cfg.GetCVar(CCVars.MassContestsMaxPercentage)); + + return 1f; + } + + /// + public float MassContest(PhysicsComponent performerPhysics, EntityUid targetUid) + { + if (_cfg.GetCVar(CCVars.DoMassContests) + && TryComp(targetUid, out var targetPhysics) + && performerPhysics.Mass != 0 + && targetPhysics.InvMass != 0) + return Math.Clamp(performerPhysics.Mass * targetPhysics.InvMass, 1 - _cfg.GetCVar(CCVars.MassContestsMaxPercentage), 1 + _cfg.GetCVar(CCVars.MassContestsMaxPercentage)); + + return 1f; + } + + /// + public float MassContest(PhysicsComponent performerPhysics, PhysicsComponent targetPhysics) + { + if (_cfg.GetCVar(CCVars.DoMassContests) + && performerPhysics.Mass != 0 + && targetPhysics.InvMass != 0) + return Math.Clamp(performerPhysics.Mass * targetPhysics.InvMass, 1 - _cfg.GetCVar(CCVars.MassContestsMaxPercentage), 1 + _cfg.GetCVar(CCVars.MassContestsMaxPercentage)); + + return 1f; + } + + #endregion + } +} diff --git a/Content.Shared/Coordinates/EntityCoordinatesExtensions.cs b/Content.Shared/Coordinates/EntityCoordinatesExtensions.cs index b9083eabe19..47d359d3875 100644 --- a/Content.Shared/Coordinates/EntityCoordinatesExtensions.cs +++ b/Content.Shared/Coordinates/EntityCoordinatesExtensions.cs @@ -1,6 +1,5 @@ using System.Numerics; using Robust.Shared.Map; -using Robust.Shared.Map.Components; namespace Content.Shared.Coordinates { @@ -20,17 +19,5 @@ public static EntityCoordinates ToCoordinates(this EntityUid id, float x, float { return new EntityCoordinates(id, x, y); } - - [Obsolete] - public static EntityCoordinates ToCoordinates(this MapGridComponent grid, float x, float y) - { - return ToCoordinates(grid.Owner, x, y); - } - - [Obsolete] - public static EntityCoordinates ToCoordinates(this MapGridComponent grid) - { - return ToCoordinates(grid.Owner, Vector2.Zero); - } } } diff --git a/Content.Shared/Coordinates/Helpers/SnapgridHelper.cs b/Content.Shared/Coordinates/Helpers/SnapgridHelper.cs index 567a600388e..db9ee85a0cd 100644 --- a/Content.Shared/Coordinates/Helpers/SnapgridHelper.cs +++ b/Content.Shared/Coordinates/Helpers/SnapgridHelper.cs @@ -22,7 +22,7 @@ public static EntityCoordinates SnapToGrid(this EntityCoordinates coordinates, I return EntityCoordinates.FromMap(coordinates.EntityId, mapPos, xformSys); } - var grid = mapManager.GetGrid(gridId.Value); + var grid = entMan.GetComponent(gridId.Value); var tileSize = grid.TileSize; var localPos = coordinates.WithEntityId(gridId.Value).Position; var x = (int)Math.Floor(localPos.X / tileSize) + tileSize / 2f; diff --git a/Content.Shared/Cuffs/Components/HandcuffComponent.cs b/Content.Shared/Cuffs/Components/HandcuffComponent.cs index cd94437637b..db8047208c8 100644 --- a/Content.Shared/Cuffs/Components/HandcuffComponent.cs +++ b/Content.Shared/Cuffs/Components/HandcuffComponent.cs @@ -18,37 +18,37 @@ public sealed partial class HandcuffComponent : Component /// /// The time it takes to cuff an entity. /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public float CuffTime = 3.5f; /// /// The time it takes to uncuff an entity. /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public float UncuffTime = 3.5f; /// /// The time it takes for a cuffed entity to uncuff itself. /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public float BreakoutTime = 15f; /// /// If an entity being cuffed is stunned, this amount of time is subtracted from the time it takes to add/remove their cuffs. /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public float StunBonus = 2f; /// /// Will the cuffs break when removed? /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public bool BreakOnRemove; /// /// Will the cuffs break when removed? /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public EntProtoId? BrokenPrototype; /// @@ -61,35 +61,42 @@ public sealed partial class HandcuffComponent : Component /// /// The path of the RSI file used for the player cuffed overlay. /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public string? CuffedRSI = "Objects/Misc/handcuffs.rsi"; /// /// The iconstate used with the RSI file for the player cuffed overlay. /// - [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + [DataField, AutoNetworkedField] public string? BodyIconState = "body-overlay"; /// /// An opptional color specification for /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public Color Color = Color.White; - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public SoundSpecifier StartCuffSound = new SoundPathSpecifier("/Audio/Items/Handcuffs/cuff_start.ogg"); - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public SoundSpecifier EndCuffSound = new SoundPathSpecifier("/Audio/Items/Handcuffs/cuff_end.ogg"); - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public SoundSpecifier StartBreakoutSound = new SoundPathSpecifier("/Audio/Items/Handcuffs/cuff_breakout_start.ogg"); - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public SoundSpecifier StartUncuffSound = new SoundPathSpecifier("/Audio/Items/Handcuffs/cuff_takeoff_start.ogg"); - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public SoundSpecifier EndUncuffSound = new SoundPathSpecifier("/Audio/Items/Handcuffs/cuff_takeoff_end.ogg"); + + /// + /// Acts as a two-state option for handcuff speed. When true, handcuffs will be easier to get out of if you are larger than average. Representing the use of strength to break things like zipties. + /// When false, handcuffs are easier to get out of if you are smaller than average, representing the use of dexterity to slip the cuffs. + /// + [DataField] + public bool UncuffEasierWhenLarge = false; } /// diff --git a/Content.Shared/Cuffs/SharedCuffableSystem.cs b/Content.Shared/Cuffs/SharedCuffableSystem.cs index fc005fd30fa..641d2bffc2d 100644 --- a/Content.Shared/Cuffs/SharedCuffableSystem.cs +++ b/Content.Shared/Cuffs/SharedCuffableSystem.cs @@ -5,6 +5,7 @@ using Content.Shared.Alert; using Content.Shared.Atmos.Piping.Unary.Components; using Content.Shared.Buckle.Components; +using Content.Shared.Contests; using Content.Shared.Cuffs.Components; using Content.Shared.Database; using Content.Shared.DoAfter; @@ -21,9 +22,8 @@ using Content.Shared.Item; using Content.Shared.Mobs.Systems; using Content.Shared.Movement.Events; -using Content.Shared.Physics.Pull; +using Content.Shared.Movement.Pulling.Events; using Content.Shared.Popups; -using Content.Shared.Pulling.Components; using Content.Shared.Pulling.Events; using Content.Shared.Rejuvenate; using Content.Shared.Stunnable; @@ -36,6 +36,7 @@ using Robust.Shared.Network; using Robust.Shared.Player; using Robust.Shared.Serialization; +using PullableComponent = Content.Shared.Movement.Pulling.Components.PullableComponent; namespace Content.Shared.Cuffs { @@ -58,6 +59,7 @@ public abstract partial class SharedCuffableSystem : EntitySystem [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly UseDelaySystem _delay = default!; + [Dependency] private readonly ContestsSystem _contests = default!; public override void Initialize() { @@ -70,7 +72,7 @@ public override void Initialize() SubscribeLocalEvent(OnCuffsInsertedIntoContainer); SubscribeLocalEvent(OnRejuvenate); SubscribeLocalEvent(OnStartup); - SubscribeLocalEvent(HandleStopPull); + SubscribeLocalEvent(HandleStopPull); SubscribeLocalEvent(HandleMoveAttempt); SubscribeLocalEvent(OnEquipAttempt); SubscribeLocalEvent(OnUnequipAttempt); @@ -182,7 +184,7 @@ public void UpdateCuffState(EntityUid uid, CuffableComponent component) private void OnBeingPulledAttempt(EntityUid uid, CuffableComponent component, BeingPulledAttemptEvent args) { - if (!TryComp(uid, out var pullable)) + if (!TryComp(uid, out var pullable)) return; if (pullable.Puller != null && !component.CanStillInteract) // If we are being pulled already and cuffed, we can't get pulled again. @@ -214,19 +216,19 @@ private void OnPull(EntityUid uid, CuffableComponent component, PullMessage args private void HandleMoveAttempt(EntityUid uid, CuffableComponent component, UpdateCanMoveEvent args) { - if (component.CanStillInteract || !EntityManager.TryGetComponent(uid, out SharedPullableComponent? pullable) || !pullable.BeingPulled) + if (component.CanStillInteract || !EntityManager.TryGetComponent(uid, out PullableComponent? pullable) || !pullable.BeingPulled) return; args.Cancel(); } - private void HandleStopPull(EntityUid uid, CuffableComponent component, StopPullingEvent args) + private void HandleStopPull(EntityUid uid, CuffableComponent component, AttemptStopPullingEvent args) { if (args.User == null || !Exists(args.User.Value)) return; if (args.User.Value == uid && !component.CanStillInteract) - args.Cancel(); + args.Cancelled = true; } private void AddUncuffVerb(EntityUid uid, CuffableComponent component, GetVerbsEvent args) @@ -559,7 +561,7 @@ public void TryUncuff(EntityUid target, EntityUid user, EntityUid? cuffsToRemove return; } - var uncuffTime = isOwner ? cuff.BreakoutTime : cuff.UncuffTime; + var uncuffTime = (isOwner ? cuff.BreakoutTime : cuff.UncuffTime) * (cuff.UncuffEasierWhenLarge ? 1 / _contests.MassContest(user) : _contests.MassContest(user)); if (isOwner) { diff --git a/Content.Shared/Disposal/SharedDisposalUnitSystem.cs b/Content.Shared/Disposal/SharedDisposalUnitSystem.cs index 600036a8910..9afd683cbdc 100644 --- a/Content.Shared/Disposal/SharedDisposalUnitSystem.cs +++ b/Content.Shared/Disposal/SharedDisposalUnitSystem.cs @@ -127,9 +127,6 @@ public virtual bool CanInsert(EntityUid uid, SharedDisposalUnitComponent compone return damageState != null && (!component.MobsCanEnter || _mobState.IsDead(entity, damageState)); } - /// - /// TODO: Proper prediction - /// public abstract void DoInsertDisposalUnit(EntityUid uid, EntityUid toInsert, EntityUid user, SharedDisposalUnitComponent? disposal = null); [Serializable, NetSerializable] diff --git a/Content.Shared/Drunk/DrunkSystem.cs b/Content.Shared/Drunk/DrunkSystem.cs index 161d4729ede..ed022cae31b 100644 --- a/Content.Shared/Drunk/DrunkSystem.cs +++ b/Content.Shared/Drunk/DrunkSystem.cs @@ -18,9 +18,6 @@ public void TryApplyDrunkenness(EntityUid uid, float boozePower, bool applySlur if (!Resolve(uid, ref status, false)) return; - if (TryComp(uid, out var trait)) - boozePower *= trait.BoozeStrengthMultiplier; - if (applySlur) { _slurredSystem.DoSlur(uid, TimeSpan.FromSeconds(boozePower), status); diff --git a/Content.Shared/Follower/FollowerSystem.cs b/Content.Shared/Follower/FollowerSystem.cs index 5656778a3f9..fc7cccf9bd6 100644 --- a/Content.Shared/Follower/FollowerSystem.cs +++ b/Content.Shared/Follower/FollowerSystem.cs @@ -4,8 +4,8 @@ using Content.Shared.Ghost; using Content.Shared.Hands; using Content.Shared.Movement.Events; +using Content.Shared.Movement.Pulling.Events; using Content.Shared.Movement.Systems; -using Content.Shared.Physics.Pull; using Content.Shared.Tag; using Content.Shared.Verbs; using Robust.Shared.Containers; diff --git a/Content.Shared/Friction/TileFrictionController.cs b/Content.Shared/Friction/TileFrictionController.cs index ba4d9fc24f8..3583947ee36 100644 --- a/Content.Shared/Friction/TileFrictionController.cs +++ b/Content.Shared/Friction/TileFrictionController.cs @@ -2,8 +2,8 @@ using Content.Shared.CCVar; using Content.Shared.Gravity; using Content.Shared.Movement.Events; +using Content.Shared.Movement.Pulling.Components; using Content.Shared.Movement.Systems; -using Content.Shared.Pulling.Components; using JetBrains.Annotations; using Robust.Shared.Configuration; using Robust.Shared.Map; @@ -23,6 +23,12 @@ public sealed class TileFrictionController : VirtualController [Dependency] private readonly SharedMoverController _mover = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; + private EntityQuery _frictionQuery; + private EntityQuery _xformQuery; + private EntityQuery _pullerQuery; + private EntityQuery _pullableQuery; + private EntityQuery _gridQuery; + private float _stopSpeed; private float _frictionModifier; public const float DefaultFriction = 0.3f; @@ -33,18 +39,17 @@ public override void Initialize() Subs.CVar(_configManager, CCVars.TileFrictionModifier, value => _frictionModifier = value, true); Subs.CVar(_configManager, CCVars.StopSpeed, value => _stopSpeed = value, true); + _frictionQuery = GetEntityQuery(); + _xformQuery = GetEntityQuery(); + _pullerQuery = GetEntityQuery(); + _pullableQuery = GetEntityQuery(); + _gridQuery = GetEntityQuery(); } public override void UpdateBeforeMapSolve(bool prediction, PhysicsMapComponent mapComponent, float frameTime) { base.UpdateBeforeMapSolve(prediction, mapComponent, frameTime); - var frictionQuery = GetEntityQuery(); - var xformQuery = GetEntityQuery(); - var pullerQuery = GetEntityQuery(); - var pullableQuery = GetEntityQuery(); - var gridQuery = GetEntityQuery(); - foreach (var body in mapComponent.AwakeBodies) { var uid = body.Owner; @@ -60,16 +65,16 @@ public override void UpdateBeforeMapSolve(bool prediction, PhysicsMapComponent m if (body.LinearVelocity.Equals(Vector2.Zero) && body.AngularVelocity.Equals(0f)) continue; - if (!xformQuery.TryGetComponent(uid, out var xform)) + if (!_xformQuery.TryGetComponent(uid, out var xform)) { Log.Error($"Unable to get transform for {ToPrettyString(uid)} in tilefrictioncontroller"); continue; } - var surfaceFriction = GetTileFriction(uid, body, xform, gridQuery, frictionQuery); + var surfaceFriction = GetTileFriction(uid, body, xform); var bodyModifier = 1f; - if (frictionQuery.TryGetComponent(uid, out var frictionComp)) + if (_frictionQuery.TryGetComponent(uid, out var frictionComp)) { bodyModifier = frictionComp.Modifier; } @@ -82,8 +87,8 @@ public override void UpdateBeforeMapSolve(bool prediction, PhysicsMapComponent m // If we're sandwiched between 2 pullers reduce friction // Might be better to make this dynamic and check how many are in the pull chain? // Either way should be much faster for now. - if (pullerQuery.TryGetComponent(uid, out var puller) && puller.Pulling != null && - pullableQuery.TryGetComponent(uid, out var pullable) && pullable.BeingPulled) + if (_pullerQuery.TryGetComponent(uid, out var puller) && puller.Pulling != null && + _pullableQuery.TryGetComponent(uid, out var pullable) && pullable.BeingPulled) { bodyModifier *= 0.2f; } @@ -163,9 +168,7 @@ private void ReduceAngularVelocity(EntityUid uid, bool prediction, PhysicsCompon private float GetTileFriction( EntityUid uid, PhysicsComponent body, - TransformComponent xform, - EntityQuery gridQuery, - EntityQuery frictionQuery) + TransformComponent xform) { // TODO: Make IsWeightless event-based; we already have grid traversals tracked so just raise events if (_gravity.IsWeightless(uid, body, xform)) @@ -175,9 +178,9 @@ private float GetTileFriction( return 0.0f; // If not on a grid then return the map's friction. - if (!gridQuery.TryGetComponent(xform.GridUid, out var grid)) + if (!_gridQuery.TryGetComponent(xform.GridUid, out var grid)) { - return frictionQuery.TryGetComponent(xform.MapUid, out var friction) + return _frictionQuery.TryGetComponent(xform.MapUid, out var friction) ? friction.Modifier : DefaultFriction; } @@ -197,7 +200,7 @@ private float GetTileFriction( while (anc.MoveNext(out var tileEnt)) { - if (frictionQuery.TryGetComponent(tileEnt, out var friction)) + if (_frictionQuery.TryGetComponent(tileEnt, out var friction)) return friction.Modifier; } diff --git a/Content.Shared/IdentityManagement/Components/IdentityBlockerComponent.cs b/Content.Shared/IdentityManagement/Components/IdentityBlockerComponent.cs index 3857063783d..e7a88b6ef29 100644 --- a/Content.Shared/IdentityManagement/Components/IdentityBlockerComponent.cs +++ b/Content.Shared/IdentityManagement/Components/IdentityBlockerComponent.cs @@ -6,6 +6,7 @@ namespace Content.Shared.IdentityManagement.Components; [RegisterComponent, NetworkedComponent] public sealed partial class IdentityBlockerComponent : Component { + [DataField] public bool Enabled = true; /// diff --git a/Content.Shared/Input/ContentKeyFunctions.cs b/Content.Shared/Input/ContentKeyFunctions.cs index 66f72e77b25..76a67793daf 100644 --- a/Content.Shared/Input/ContentKeyFunctions.cs +++ b/Content.Shared/Input/ContentKeyFunctions.cs @@ -56,6 +56,7 @@ public static class ContentKeyFunctions public static readonly BoundKeyFunction ZoomIn = "ZoomIn"; public static readonly BoundKeyFunction ResetZoom = "ResetZoom"; public static readonly BoundKeyFunction OfferItem = "OfferItem"; + public static readonly BoundKeyFunction ToggleStanding = "ToggleStanding"; public static readonly BoundKeyFunction ArcadeUp = "ArcadeUp"; public static readonly BoundKeyFunction ArcadeDown = "ArcadeDown"; diff --git a/Content.Shared/Interaction/SharedInteractionSystem.cs b/Content.Shared/Interaction/SharedInteractionSystem.cs index 0e390ecea45..e4864b1f7fc 100644 --- a/Content.Shared/Interaction/SharedInteractionSystem.cs +++ b/Content.Shared/Interaction/SharedInteractionSystem.cs @@ -15,10 +15,10 @@ using Content.Shared.Inventory.Events; using Content.Shared.Item; using Content.Shared.Movement.Components; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Systems; using Content.Shared.Physics; using Content.Shared.Popups; -using Content.Shared.Pulling; -using Content.Shared.Pulling.Components; using Content.Shared.Tag; using Content.Shared.Timing; using Content.Shared.Verbs; @@ -60,7 +60,7 @@ public abstract partial class SharedInteractionSystem : EntitySystem [Dependency] private readonly SharedVerbSystem _verbSystem = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly UseDelaySystem _useDelay = default!; - [Dependency] private readonly SharedPullingSystem _pullSystem = default!; + [Dependency] private readonly PullingSystem _pullSystem = default!; [Dependency] private readonly InventorySystem _inventory = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly TagSystem _tagSystem = default!; @@ -185,10 +185,10 @@ private bool HandleTryPullObject(ICommonSession? session, EntityCoordinates coor if (!InRangeUnobstructed(userEntity.Value, uid, popup: true)) return false; - if (!TryComp(uid, out SharedPullableComponent? pull)) + if (!TryComp(uid, out PullableComponent? pull)) return false; - _pullSystem.TogglePull(userEntity.Value, pull); + _pullSystem.TogglePull(uid, userEntity.Value, pull); return false; } diff --git a/Content.Shared/Language/Components/LanguageKnowledgeComponent.cs b/Content.Shared/Language/Components/LanguageKnowledgeComponent.cs index 0632f5d9cb2..ddbdc742be4 100644 --- a/Content.Shared/Language/Components/LanguageKnowledgeComponent.cs +++ b/Content.Shared/Language/Components/LanguageKnowledgeComponent.cs @@ -2,6 +2,8 @@ namespace Content.Shared.Language.Components; +// TODO: move to server side, it's never synchronized! + /// /// Stores data about entities' intrinsic language knowledge. /// diff --git a/Content.Shared/Language/LanguagePrototype.cs b/Content.Shared/Language/LanguagePrototype.cs index be54b45aa1f..79c17daccd8 100644 --- a/Content.Shared/Language/LanguagePrototype.cs +++ b/Content.Shared/Language/LanguagePrototype.cs @@ -16,7 +16,13 @@ public sealed class LanguagePrototype : IPrototype [DataField("fontSize")] public int? FontSize; - + + /// + /// If true, will mark the language as a SignLanguage and will be handled as such. + /// + [DataField("signLanguage")] + public bool? SignLanguage; + /// /// Obfuscation method used by this language. By default, uses /// diff --git a/Content.Shared/Language/Systems/SharedTranslatorSystem.cs b/Content.Shared/Language/Systems/SharedTranslatorSystem.cs index 08a016efa9c..4a72de791f0 100644 --- a/Content.Shared/Language/Systems/SharedTranslatorSystem.cs +++ b/Content.Shared/Language/Systems/SharedTranslatorSystem.cs @@ -1,3 +1,4 @@ +using System.Linq; using Content.Shared.Examine; using Content.Shared.Toggleable; using Content.Shared.Language.Components.Translators; @@ -17,11 +18,20 @@ public override void Initialize() private void OnExamined(EntityUid uid, HandheldTranslatorComponent component, ExaminedEvent args) { - var state = Loc.GetString(component.Enabled - ? "translator-enabled" - : "translator-disabled"); + var understoodLanguageNames = component.UnderstoodLanguages + .Select(it => Loc.GetString($"language-{it}-name")); + var spokenLanguageNames = component.SpokenLanguages + .Select(it => Loc.GetString($"language-{it}-name")); + var requiredLanguageNames = component.RequiredLanguages + .Select(it => Loc.GetString($"language-{it}-name")); - args.PushMarkup(state); + args.PushMarkup(Loc.GetString("translator-examined-langs-understood", ("languages", string.Join(", ", understoodLanguageNames)))); + args.PushMarkup(Loc.GetString("translator-examined-langs-spoken", ("languages", string.Join(", ", spokenLanguageNames)))); + + args.PushMarkup(Loc.GetString(component.RequiresAllLanguages ? "translator-examined-requires-all" : "translator-examined-requires-any", + ("languages", string.Join(", ", requiredLanguageNames)))); + + args.PushMarkup(Loc.GetString(component.Enabled ? "translator-examined-enabled" : "translator-examined-disabled")); } protected void OnAppearanceChange(EntityUid translator, HandheldTranslatorComponent? comp = null) diff --git a/Content.Shared/Light/Components/SharedExpendableLightComponent.cs b/Content.Shared/Light/Components/SharedExpendableLightComponent.cs index c802700b62c..e40174ab783 100644 --- a/Content.Shared/Light/Components/SharedExpendableLightComponent.cs +++ b/Content.Shared/Light/Components/SharedExpendableLightComponent.cs @@ -7,7 +7,7 @@ namespace Content.Shared.Light.Components; [NetworkedComponent] public abstract partial class SharedExpendableLightComponent : Component { - public static readonly AudioParams LoopedSoundParams = new(0, 1, "Master", 62.5f, 1, 1, true, 0.3f); + public static readonly AudioParams LoopedSoundParams = new(0, 1, 62.5f, 1, 1, true, 0.3f); [ViewVariables(VVAccess.ReadOnly)] public ExpendableLightState CurrentState { get; set; } diff --git a/Content.Shared/Maps/ContentTileDefinition.cs b/Content.Shared/Maps/ContentTileDefinition.cs index 32f5db0e821..be171559d02 100644 --- a/Content.Shared/Maps/ContentTileDefinition.cs +++ b/Content.Shared/Maps/ContentTileDefinition.cs @@ -121,5 +121,11 @@ public void AssignTileId(ushort id) { TileId = id; } + + [DataField] + public bool Reinforced = false; + + [DataField] + public float TileRipResistance = 125f; } } diff --git a/Content.Shared/Maps/TurfHelpers.cs b/Content.Shared/Maps/TurfHelpers.cs index 58a5d133b55..f1c1beef7d1 100644 --- a/Content.Shared/Maps/TurfHelpers.cs +++ b/Content.Shared/Maps/TurfHelpers.cs @@ -3,6 +3,7 @@ using System.Runtime.CompilerServices; using Content.Shared.Physics; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Random; namespace Content.Shared.Maps @@ -11,6 +12,22 @@ namespace Content.Shared.Maps // That, or make the interface arguments non-optional so people stop failing to pass them in. public static class TurfHelpers { + /// + /// Attempts to get the turf at map indices with grid id or null if no such turf is found. + /// + public static TileRef GetTileRef(this Vector2i vector2i, EntityUid gridId, IEntityManager? entityManager = null) + { + entityManager ??= IoCManager.Resolve(); + + if (!entityManager.TryGetComponent(gridId, out var grid)) + return default; + + if (!grid.TryGetTileRef(vector2i, out var tile)) + return default; + + return tile; + } + /// /// Attempts to get the turf at a certain coordinates or null if no such turf is found. /// @@ -119,9 +136,8 @@ public static bool IsBlockedTurf(this TileRef turf, bool filterMobs, EntityLooku private static bool GetWorldTileBox(TileRef turf, out Box2Rotated res) { var entManager = IoCManager.Resolve(); - var map = IoCManager.Resolve(); - if (map.TryGetGrid(turf.GridUid, out var tileGrid)) + if (entManager.TryGetComponent(turf.GridUid, out var tileGrid)) { var gridRot = entManager.GetComponent(turf.GridUid).WorldRotation; diff --git a/Content.Shared/Maps/TurfSystem.cs b/Content.Shared/Maps/TurfSystem.cs index a344193f123..ad8b3ddea8d 100644 --- a/Content.Shared/Maps/TurfSystem.cs +++ b/Content.Shared/Maps/TurfSystem.cs @@ -13,7 +13,6 @@ public sealed class TurfSystem : EntitySystem { [Dependency] private readonly EntityLookupSystem _entityLookup = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; - [Dependency] private readonly IMapManager _mapMan = default!; /// /// Returns true if a given tile is blocked by physics-enabled entities. @@ -92,7 +91,7 @@ public bool IsTileBlocked(EntityUid gridUid, /// public EntityCoordinates GetTileCenter(TileRef turf) { - var grid = _mapMan.GetGrid(turf.GridUid); + var grid = Comp(turf.GridUid); var center = (turf.GridIndices + new Vector2(0.5f, 0.5f)) * grid.TileSize; return new EntityCoordinates(turf.GridUid, center); } diff --git a/Content.Shared/Materials/SharedMaterialReclaimerSystem.cs b/Content.Shared/Materials/SharedMaterialReclaimerSystem.cs index 5a9ada7f586..50dce3c7669 100644 --- a/Content.Shared/Materials/SharedMaterialReclaimerSystem.cs +++ b/Content.Shared/Materials/SharedMaterialReclaimerSystem.cs @@ -1,7 +1,8 @@ -using System.Linq; +using System.Linq; using Content.Shared.Administration.Logs; using Content.Shared.Audio; using Content.Shared.Body.Components; +using Content.Shared.Coordinates; using Content.Shared.Database; using Content.Shared.Emag.Components; using Content.Shared.Emag.Systems; @@ -11,6 +12,7 @@ using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; +using Robust.Shared.Map; using Robust.Shared.Physics.Events; using Robust.Shared.Timing; @@ -110,6 +112,9 @@ public bool TryStartProcessItem(EntityUid uid, EntityUid item, MaterialReclaimer component.NextSound = Timing.CurTime + component.SoundCooldown; } + var reclaimedEvent = new GotReclaimedEvent(Transform(uid).Coordinates); + RaiseLocalEvent(item, ref reclaimedEvent); + var duration = GetReclaimingDuration(uid, item, component); // if it's instant, don't bother with all the active comp stuff. if (duration == TimeSpan.Zero) @@ -238,3 +243,6 @@ public override void Update(float frameTime) } } } + +[ByRefEvent] +public record struct GotReclaimedEvent(EntityCoordinates ReclaimerCoordinates); diff --git a/Content.Shared/Movement/Components/CanWalkComponent.cs b/Content.Shared/Movement/Components/CanWalkComponent.cs new file mode 100644 index 00000000000..fab851595c7 --- /dev/null +++ b/Content.Shared/Movement/Components/CanWalkComponent.cs @@ -0,0 +1,11 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Movement.Components; + +/// +/// Indicates if the entity can toggle walking or not. +/// +[NetworkedComponent, RegisterComponent] +public sealed partial class CanWalkComponent : Component +{ +} diff --git a/Content.Shared/Movement/Components/InputMoverComponent.cs b/Content.Shared/Movement/Components/InputMoverComponent.cs index f1e34c90df4..263190d46fd 100644 --- a/Content.Shared/Movement/Components/InputMoverComponent.cs +++ b/Content.Shared/Movement/Components/InputMoverComponent.cs @@ -1,9 +1,11 @@ using System.Numerics; +using Content.Shared.Alert; using Content.Shared.Movement.Systems; using Robust.Shared.GameStates; using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; using Robust.Shared.Timing; +using Robust.Shared.Prototypes; namespace Content.Shared.Movement.Components { @@ -74,6 +76,9 @@ public sealed partial class InputMoverComponent : Component [ViewVariables(VVAccess.ReadWrite)] public bool CanMove = true; + + [DataField] + public ProtoId WalkingAlert = "Walking"; } [Serializable, NetSerializable] diff --git a/Content.Shared/Movement/Pulling/Components/PullableComponent.cs b/Content.Shared/Movement/Pulling/Components/PullableComponent.cs new file mode 100644 index 00000000000..db889e7e3bd --- /dev/null +++ b/Content.Shared/Movement/Pulling/Components/PullableComponent.cs @@ -0,0 +1,39 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Movement.Pulling.Components; + +/// +/// Specifies an entity as being pullable by an entity with +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(Systems.PullingSystem))] +public sealed partial class PullableComponent : Component +{ + /// + /// The current entity pulling this component. + /// + [AutoNetworkedField, DataField] + public EntityUid? Puller; + + /// + /// The pull joint. + /// + [AutoNetworkedField, DataField] + public string? PullJointId; + + public bool BeingPulled => Puller != null; + + /// + /// If the physics component has FixedRotation should we keep it upon being pulled + /// + [Access(typeof(Systems.PullingSystem), Other = AccessPermissions.ReadExecute)] + [ViewVariables(VVAccess.ReadWrite), DataField("fixedRotation")] + public bool FixedRotationOnPull; + + /// + /// What the pullable's fixedrotation was set to before being pulled. + /// + [Access(typeof(Systems.PullingSystem), Other = AccessPermissions.ReadExecute)] + [AutoNetworkedField, DataField] + public bool PrevFixedRotation; +} diff --git a/Content.Shared/Movement/Pulling/Components/PullerComponent.cs b/Content.Shared/Movement/Pulling/Components/PullerComponent.cs new file mode 100644 index 00000000000..1fc9b731bd5 --- /dev/null +++ b/Content.Shared/Movement/Pulling/Components/PullerComponent.cs @@ -0,0 +1,41 @@ +using Content.Shared.Movement.Pulling.Systems; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared.Movement.Pulling.Components; + +/// +/// Specifies an entity as being able to pull another entity with +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(PullingSystem))] +public sealed partial class PullerComponent : Component +{ + // My raiding guild + /// + /// Next time the puller can throw what is being pulled. + /// Used to avoid spamming it for infinite spin + velocity. + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] + public TimeSpan NextThrow; + + [DataField] + public TimeSpan ThrowCooldown = TimeSpan.FromSeconds(1); + + // Before changing how this is updated, please see SharedPullerSystem.RefreshMovementSpeed + public float WalkSpeedModifier => Pulling == default ? 1.0f : 0.95f; + + public float SprintSpeedModifier => Pulling == default ? 1.0f : 0.95f; + + /// + /// Entity currently being pulled if applicable. + /// + [AutoNetworkedField, DataField] + public EntityUid? Pulling; + + /// + /// Does this entity need hands to be able to pull something? + /// + [DataField] + public bool NeedsHands = true; +} diff --git a/Content.Shared/Movement/Pulling/Events/AttemptPullEvent.cs b/Content.Shared/Movement/Pulling/Events/AttemptPullEvent.cs new file mode 100644 index 00000000000..b0101c46996 --- /dev/null +++ b/Content.Shared/Movement/Pulling/Events/AttemptPullEvent.cs @@ -0,0 +1,13 @@ +using Robust.Shared.Physics.Components; + +namespace Content.Shared.Movement.Pulling.Events; + +/// +/// Raised directed on puller and pullable to determine if it can be pulled. +/// +public sealed class PullAttemptEvent : PullMessage +{ + public PullAttemptEvent(EntityUid pullerUid, EntityUid pullableUid) : base(pullerUid, pullableUid) { } + + public bool Cancelled { get; set; } +} diff --git a/Content.Shared/Movement/Pulling/Events/AttemptStopPullingEvent.cs b/Content.Shared/Movement/Pulling/Events/AttemptStopPullingEvent.cs new file mode 100644 index 00000000000..cd7edc5f623 --- /dev/null +++ b/Content.Shared/Movement/Pulling/Events/AttemptStopPullingEvent.cs @@ -0,0 +1,10 @@ +namespace Content.Shared.Pulling.Events; + +/// +/// Raised when a request is made to stop pulling an entity. +/// +public record struct AttemptStopPullingEvent(EntityUid? User = null) +{ + public readonly EntityUid? User = User; + public bool Cancelled; +} \ No newline at end of file diff --git a/Content.Shared/Pulling/Events/BeingPulledAttemptEvent.cs b/Content.Shared/Movement/Pulling/Events/BeingPulledAttemptEvent.cs similarity index 100% rename from Content.Shared/Pulling/Events/BeingPulledAttemptEvent.cs rename to Content.Shared/Movement/Pulling/Events/BeingPulledAttemptEvent.cs diff --git a/Content.Shared/Movement/Pulling/Events/PullMessage.cs b/Content.Shared/Movement/Pulling/Events/PullMessage.cs new file mode 100644 index 00000000000..a427e448d5c --- /dev/null +++ b/Content.Shared/Movement/Pulling/Events/PullMessage.cs @@ -0,0 +1,13 @@ +namespace Content.Shared.Movement.Pulling.Events; + +public abstract class PullMessage : EntityEventArgs +{ + public readonly EntityUid PullerUid; + public readonly EntityUid PulledUid; + + protected PullMessage(EntityUid pullerUid, EntityUid pulledUid) + { + PullerUid = pullerUid; + PulledUid = pulledUid; + } +} diff --git a/Content.Shared/Movement/Pulling/Events/PullStartedMessage.cs b/Content.Shared/Movement/Pulling/Events/PullStartedMessage.cs new file mode 100644 index 00000000000..29460e1dfc1 --- /dev/null +++ b/Content.Shared/Movement/Pulling/Events/PullStartedMessage.cs @@ -0,0 +1,9 @@ +namespace Content.Shared.Movement.Pulling.Events; + +public sealed class PullStartedMessage : PullMessage +{ + public PullStartedMessage(EntityUid pullerUid, EntityUid pullableUid) : + base(pullerUid, pullableUid) + { + } +} diff --git a/Content.Shared/Movement/Pulling/Events/PullStoppedMessage.cs b/Content.Shared/Movement/Pulling/Events/PullStoppedMessage.cs new file mode 100644 index 00000000000..47aa34562fb --- /dev/null +++ b/Content.Shared/Movement/Pulling/Events/PullStoppedMessage.cs @@ -0,0 +1,13 @@ +using Robust.Shared.Physics.Components; + +namespace Content.Shared.Movement.Pulling.Events; + +/// +/// Raised directed on both puller and pullable. +/// +public sealed class PullStoppedMessage : PullMessage +{ + public PullStoppedMessage(EntityUid pullerUid, EntityUid pulledUid) : base(pullerUid, pulledUid) + { + } +} diff --git a/Content.Shared/Pulling/Events/StartPullAttemptEvent.cs b/Content.Shared/Movement/Pulling/Events/StartPullAttemptEvent.cs similarity index 100% rename from Content.Shared/Pulling/Events/StartPullAttemptEvent.cs rename to Content.Shared/Movement/Pulling/Events/StartPullAttemptEvent.cs diff --git a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs new file mode 100644 index 00000000000..b347c6da164 --- /dev/null +++ b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs @@ -0,0 +1,494 @@ +using System.Numerics; +using Content.Shared.ActionBlocker; +using Content.Shared.Administration.Logs; +using Content.Shared.Alert; +using Content.Shared.Buckle.Components; +using Content.Shared.Database; +using Content.Shared.Hands; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Input; +using Content.Shared.Interaction; +using Content.Shared.Movement.Events; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Events; +using Content.Shared.Movement.Systems; +using Content.Shared.Pulling.Events; +using Content.Shared.Throwing; +using Content.Shared.Verbs; +using Robust.Shared.Containers; +using Robust.Shared.Input.Binding; +using Robust.Shared.Map; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Components; +using Robust.Shared.Physics.Events; +using Robust.Shared.Physics.Systems; +using Robust.Shared.Player; +using Robust.Shared.Timing; + +namespace Content.Shared.Movement.Pulling.Systems; + +/// +/// Allows one entity to pull another behind them via a physics distance joint. +/// +public sealed class PullingSystem : EntitySystem +{ + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; + [Dependency] private readonly ActionBlockerSystem _blocker = default!; + [Dependency] private readonly AlertsSystem _alertsSystem = default!; + [Dependency] private readonly MovementSpeedModifierSystem _modifierSystem = default!; + [Dependency] private readonly SharedJointSystem _joints = default!; + [Dependency] private readonly SharedContainerSystem _containerSystem = default!; + [Dependency] private readonly SharedHandsSystem _handsSystem = default!; + [Dependency] private readonly SharedInteractionSystem _interaction = default!; + [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly SharedTransformSystem _xformSys = default!; + [Dependency] private readonly ThrowingSystem _throwing = default!; + + public override void Initialize() + { + base.Initialize(); + + UpdatesAfter.Add(typeof(SharedPhysicsSystem)); + UpdatesOutsidePrediction = true; + + SubscribeLocalEvent(OnPullableMoveInput); + SubscribeLocalEvent(OnPullableCollisionChange); + SubscribeLocalEvent(OnJointRemoved); + SubscribeLocalEvent>(AddPullVerbs); + SubscribeLocalEvent(OnPullableContainerInsert); + + SubscribeLocalEvent(OnPullerContainerInsert); + SubscribeLocalEvent(OnPullerUnpaused); + SubscribeLocalEvent(OnVirtualItemDeleted); + SubscribeLocalEvent(OnRefreshMovespeed); + + CommandBinds.Builder + .Bind(ContentKeyFunctions.MovePulledObject, new PointerInputCmdHandler(OnRequestMovePulledObject)) + .Bind(ContentKeyFunctions.ReleasePulledObject, InputCmdHandler.FromDelegate(OnReleasePulledObject, handle: false)) + .Register(); + } + + private void OnPullerContainerInsert(Entity ent, ref EntGotInsertedIntoContainerMessage args) + { + if (ent.Comp.Pulling == null) return; + + if (!TryComp(ent.Comp.Pulling.Value, out PullableComponent? pulling)) + return; + + TryStopPull(ent.Comp.Pulling.Value, pulling, ent.Owner); + } + + private void OnPullableContainerInsert(Entity ent, ref EntGotInsertedIntoContainerMessage args) + { + TryStopPull(ent.Owner, ent.Comp); + } + + public override void Shutdown() + { + base.Shutdown(); + CommandBinds.Unregister(); + } + + private void OnPullerUnpaused(EntityUid uid, PullerComponent component, ref EntityUnpausedEvent args) + { + component.NextThrow += args.PausedTime; + } + + private void OnVirtualItemDeleted(EntityUid uid, PullerComponent component, VirtualItemDeletedEvent args) + { + // If client deletes the virtual hand then stop the pull. + if (component.Pulling == null) + return; + + if (component.Pulling != args.BlockingEntity) + return; + + if (EntityManager.TryGetComponent(args.BlockingEntity, out PullableComponent? comp)) + { + TryStopPull(args.BlockingEntity, comp, uid); + } + } + + private void AddPullVerbs(EntityUid uid, PullableComponent component, GetVerbsEvent args) + { + if (!args.CanAccess || !args.CanInteract) + return; + + // Are they trying to pull themselves up by their bootstraps? + if (args.User == args.Target) + return; + + //TODO VERB ICONS add pulling icon + if (component.Puller == args.User) + { + Verb verb = new() + { + Text = Loc.GetString("pulling-verb-get-data-text-stop-pulling"), + Act = () => TryStopPull(uid, component, user: args.User), + DoContactInteraction = false // pulling handle its own contact interaction. + }; + args.Verbs.Add(verb); + } + else if (CanPull(args.User, args.Target)) + { + Verb verb = new() + { + Text = Loc.GetString("pulling-verb-get-data-text"), + Act = () => TryStartPull(args.User, args.Target), + DoContactInteraction = false // pulling handle its own contact interaction. + }; + args.Verbs.Add(verb); + } + } + + private void OnRefreshMovespeed(EntityUid uid, PullerComponent component, RefreshMovementSpeedModifiersEvent args) + { + args.ModifySpeed(component.WalkSpeedModifier, component.SprintSpeedModifier); + } + + private void OnPullableMoveInput(EntityUid uid, PullableComponent component, ref MoveInputEvent args) + { + // If someone moves then break their pulling. + if (!component.BeingPulled) + return; + + var entity = args.Entity; + + if (!_blocker.CanMove(entity)) + return; + + TryStopPull(uid, component, user: uid); + } + + private void OnPullableCollisionChange(EntityUid uid, PullableComponent component, ref CollisionChangeEvent args) + { + // IDK what this is supposed to be. + if (!_timing.ApplyingState && component.PullJointId != null && !args.CanCollide) + { + _joints.RemoveJoint(uid, component.PullJointId); + } + } + + private void OnJointRemoved(EntityUid uid, PullableComponent component, JointRemovedEvent args) + { + // Just handles the joint getting nuked without going through pulling system (valid behavior). + + // Not relevant / pullable state handle it. + if (component.Puller != args.OtherEntity || + args.Joint.ID != component.PullJointId || + _timing.ApplyingState) + { + return; + } + + if (args.Joint.ID != component.PullJointId || component.Puller == null) + return; + + StopPulling(uid, component); + } + + /// + /// Forces pulling to stop and handles cleanup. + /// + private void StopPulling(EntityUid pullableUid, PullableComponent pullableComp) + { + if (!_timing.ApplyingState) + { + if (TryComp(pullableUid, out var pullablePhysics)) + { + _physics.SetFixedRotation(pullableUid, pullableComp.PrevFixedRotation, body: pullablePhysics); + } + } + + var oldPuller = pullableComp.Puller; + pullableComp.PullJointId = null; + pullableComp.Puller = null; + Dirty(pullableUid, pullableComp); + + // No more joints with puller -> force stop pull. + if (TryComp(oldPuller, out var pullerComp)) + { + var pullerUid = oldPuller.Value; + _alertsSystem.ClearAlert(pullerUid, AlertType.Pulling); + pullerComp.Pulling = null; + Dirty(oldPuller.Value, pullerComp); + + // Messaging + var message = new PullStoppedMessage(pullerUid, pullableUid); + _modifierSystem.RefreshMovementSpeedModifiers(pullerUid); + _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(pullerUid):user} stopped pulling {ToPrettyString(pullableUid):target}"); + + RaiseLocalEvent(pullerUid, message); + RaiseLocalEvent(pullableUid, message); + } + + + _alertsSystem.ClearAlert(pullableUid, AlertType.Pulled); + } + + public bool IsPulled(EntityUid uid, PullableComponent? component = null) + { + return Resolve(uid, ref component, false) && component.BeingPulled; + } + + private bool OnRequestMovePulledObject(ICommonSession? session, EntityCoordinates coords, EntityUid uid) + { + if (session?.AttachedEntity is not { } player || + !player.IsValid()) + { + return false; + } + + if (!TryComp(player, out var pullerComp)) + return false; + + var pulled = pullerComp.Pulling; + + if (!HasComp(pulled)) + return false; + + if (_containerSystem.IsEntityInContainer(player)) + return false; + + // Cooldown buddy + if (_timing.CurTime < pullerComp.NextThrow) + return false; + + pullerComp.NextThrow = _timing.CurTime + pullerComp.ThrowCooldown; + + // Cap the distance + const float range = 2f; + var fromUserCoords = coords.WithEntityId(player, EntityManager); + var userCoords = new EntityCoordinates(player, Vector2.Zero); + + if (!userCoords.InRange(EntityManager, _xformSys, fromUserCoords, range)) + { + var userDirection = fromUserCoords.Position - userCoords.Position; + fromUserCoords = userCoords.Offset(userDirection.Normalized() * range); + } + + Dirty(player, pullerComp); + _throwing.TryThrow(pulled.Value, fromUserCoords, user: player, strength: 4f, animated: false, recoil: false, playSound: false); + return false; + } + + public bool IsPulling(EntityUid puller, PullerComponent? component = null) + { + return Resolve(puller, ref component, false) && component.Pulling != null; + } + + private void OnReleasePulledObject(ICommonSession? session) + { + if (session?.AttachedEntity is not {Valid: true} player) + { + return; + } + + if (!TryComp(player, out PullerComponent? pullerComp) || + !TryComp(pullerComp.Pulling, out PullableComponent? pullableComp)) + { + return; + } + + TryStopPull(pullerComp.Pulling.Value, pullableComp, user: player); + } + + public bool CanPull(EntityUid puller, EntityUid pullableUid, PullerComponent? pullerComp = null) + { + if (!Resolve(puller, ref pullerComp, false)) + { + return false; + } + + if (pullerComp.NeedsHands && !_handsSystem.TryGetEmptyHand(puller, out _)) + { + return false; + } + + if (!_blocker.CanInteract(puller, pullableUid)) + { + return false; + } + + if (!EntityManager.TryGetComponent(pullableUid, out var physics)) + { + return false; + } + + if (physics.BodyType == BodyType.Static) + { + return false; + } + + if (puller == pullableUid) + { + return false; + } + + if (!_containerSystem.IsInSameOrNoContainer(puller, pullableUid)) + { + return false; + } + + if (EntityManager.TryGetComponent(puller, out BuckleComponent? buckle)) + { + // Prevent people pulling the chair they're on, etc. + if (buckle is { PullStrap: false, Buckled: true } && (buckle.LastEntityBuckledTo == pullableUid)) + { + return false; + } + } + + var getPulled = new BeingPulledAttemptEvent(puller, pullableUid); + RaiseLocalEvent(pullableUid, getPulled, true); + var startPull = new StartPullAttemptEvent(puller, pullableUid); + RaiseLocalEvent(puller, startPull, true); + return !startPull.Cancelled && !getPulled.Cancelled; + } + + public bool TogglePull(EntityUid pullableUid, EntityUid pullerUid, PullableComponent pullable) + { + if (pullable.Puller == pullerUid) + { + return TryStopPull(pullableUid, pullable); + } + + return TryStartPull(pullerUid, pullableUid, pullableComp: pullable); + } + + public bool TogglePull(EntityUid pullerUid, PullerComponent puller) + { + if (!TryComp(puller.Pulling, out var pullable)) + return false; + + return TogglePull(puller.Pulling.Value, pullerUid, pullable); + } + + public bool TryStartPull(EntityUid pullerUid, EntityUid pullableUid, EntityUid? user = null, + PullerComponent? pullerComp = null, PullableComponent? pullableComp = null) + { + if (!Resolve(pullerUid, ref pullerComp, false) || + !Resolve(pullableUid, ref pullableComp, false)) + { + return false; + } + + if (pullerComp.Pulling == pullableUid) + return true; + + if (!CanPull(pullerUid, pullableUid)) + return false; + + if (!EntityManager.TryGetComponent(pullerUid, out var pullerPhysics) || + !EntityManager.TryGetComponent(pullableUid, out var pullablePhysics)) + { + return false; + } + + // Ensure that the puller is not currently pulling anything. + var oldPullable = pullerComp.Pulling; + + if (oldPullable != null) + { + // Well couldn't stop the old one. + if (!TryStopPull(oldPullable.Value, pullableComp, user)) + return false; + } + + // Is the pullable currently being pulled by something else? + if (pullableComp.Puller != null) + { + // Uhhh + if (pullableComp.Puller == pullerUid) + return false; + + if (!TryStopPull(pullableUid, pullableComp, pullerUid)) + return false; + } + + var pullAttempt = new PullAttemptEvent(pullerUid, pullableUid); + RaiseLocalEvent(pullerUid, pullAttempt); + + if (pullAttempt.Cancelled) + return false; + + RaiseLocalEvent(pullableUid, pullAttempt); + + if (pullAttempt.Cancelled) + return false; + + // Pulling confirmed + + _interaction.DoContactInteraction(pullableUid, pullerUid); + + // Use net entity so it's consistent across client and server. + pullableComp.PullJointId = $"pull-joint-{GetNetEntity(pullableUid)}"; + + pullerComp.Pulling = pullableUid; + pullableComp.Puller = pullerUid; + + // joint state handling will manage its own state + if (!_timing.ApplyingState) + { + // Joint startup + var union = _physics.GetHardAABB(pullerUid).Union(_physics.GetHardAABB(pullableUid, body: pullablePhysics)); + var length = Math.Max((float) union.Size.X, (float) union.Size.Y) * 0.75f; + + var joint = _joints.CreateDistanceJoint(pullableUid, pullerUid, id: pullableComp.PullJointId); + joint.CollideConnected = false; + // This maximum has to be there because if the object is constrained too closely, the clamping goes backwards and asserts. + joint.MaxLength = Math.Max(1.0f, length); + joint.Length = length * 0.75f; + joint.MinLength = 0f; + joint.Stiffness = 1f; + + _physics.SetFixedRotation(pullableUid, pullableComp.FixedRotationOnPull, body: pullablePhysics); + } + + pullableComp.PrevFixedRotation = pullablePhysics.FixedRotation; + + // Messaging + var message = new PullStartedMessage(pullerUid, pullableUid); + _alertsSystem.ShowAlert(pullerUid, AlertType.Pulling); + _alertsSystem.ShowAlert(pullableUid, AlertType.Pulled); + + RaiseLocalEvent(pullerUid, message); + RaiseLocalEvent(pullableUid, message); + + Dirty(pullerUid, pullerComp); + Dirty(pullableUid, pullableComp); + + _adminLogger.Add(LogType.Action, LogImpact.Low, + $"{ToPrettyString(pullerUid):user} started pulling {ToPrettyString(pullableUid):target}"); + return true; + } + + public bool TryStopPull(EntityUid pullableUid, PullableComponent pullable, EntityUid? user = null) + { + var pullerUidNull = pullable.Puller; + + if (pullerUidNull == null) + return false; + + var msg = new AttemptStopPullingEvent(user); + RaiseLocalEvent(pullableUid, msg, true); + + if (msg.Cancelled) + return false; + + // Stop pulling confirmed! + if (!_timing.ApplyingState) + { + // Joint shutdown + if (pullable.PullJointId != null) + { + _joints.RemoveJoint(pullableUid, pullable.PullJointId); + pullable.PullJointId = null; + } + } + + StopPulling(pullableUid, pullable); + return true; + } +} diff --git a/Content.Shared/Movement/Systems/SharedContentEyeSystem.cs b/Content.Shared/Movement/Systems/SharedContentEyeSystem.cs index 207f14a258a..6dc7fdfd899 100644 --- a/Content.Shared/Movement/Systems/SharedContentEyeSystem.cs +++ b/Content.Shared/Movement/Systems/SharedContentEyeSystem.cs @@ -1,9 +1,11 @@ using System.Numerics; using Content.Shared.Administration; using Content.Shared.Administration.Managers; +using Content.Shared.CCVar; using Content.Shared.Ghost; using Content.Shared.Input; using Content.Shared.Movement.Components; +using Robust.Shared.Configuration; using Robust.Shared.Input.Binding; using Robust.Shared.Player; using Robust.Shared.Serialization; @@ -16,10 +18,13 @@ namespace Content.Shared.Movement.Systems; public abstract class SharedContentEyeSystem : EntitySystem { [Dependency] private readonly ISharedAdminManager _admin = default!; + [Dependency] private readonly IConfigurationManager _config = default!; - public const float ZoomMod = 1.5f; - public static readonly Vector2 DefaultZoom = Vector2.One; - public static readonly Vector2 MinZoom = DefaultZoom * (float)Math.Pow(ZoomMod, -3); + // Will be overridden according to config. + public readonly Vector2 DefaultZoom = Vector2.One; + public float ZoomMod { get; private set; } = 1f; + public int ZoomLevels { get; private set; } = 1; + public Vector2 MinZoom { get; private set; } = Vector2.One; [Dependency] private readonly SharedEyeSystem _eye = default!; @@ -38,6 +43,17 @@ public override void Initialize() Log.Level = LogLevel.Info; UpdatesOutsidePrediction = true; + + Subs.CVar(_config, CCVars.ZoomLevelStep, value => + { + ZoomMod = value; + RecalculateZoomLevels(); + }, true); + Subs.CVar(_config, CCVars.ZoomLevels, value => + { + ZoomLevels = value; + RecalculateZoomLevels(); + }, true); } public override void Shutdown() @@ -46,6 +62,11 @@ public override void Shutdown() CommandBinds.Unregister(); } + private void RecalculateZoomLevels() + { + MinZoom = DefaultZoom * (float) Math.Pow(ZoomMod, -ZoomLevels); + } + private void ResetZoom(ICommonSession? session) { if (TryComp(session?.AttachedEntity, out ContentEyeComponent? eye)) diff --git a/Content.Shared/Movement/Systems/SharedMoverController.Input.cs b/Content.Shared/Movement/Systems/SharedMoverController.Input.cs index bce3aeff527..891bd518b1c 100644 --- a/Content.Shared/Movement/Systems/SharedMoverController.Input.cs +++ b/Content.Shared/Movement/Systems/SharedMoverController.Input.cs @@ -1,4 +1,5 @@ using System.Numerics; +using Content.Shared.Alert; using Content.Shared.CCVar; using Content.Shared.Follower.Components; using Content.Shared.Input; @@ -333,6 +334,7 @@ private void OnInputInit(EntityUid uid, InputMoverComponent component, Component component.RelativeEntity = xform.GridUid ?? xform.MapUid; component.TargetRelativeRotation = Angle.Zero; + WalkingAlert(uid, !component.Sprinting); } private void HandleRunChange(EntityUid uid, ushort subTick, bool walking) @@ -344,6 +346,7 @@ private void HandleRunChange(EntityUid uid, ushort subTick, bool walking) // if we swap to relay then stop our existing input if we ever change back. if (moverComp != null) { + WalkingAlert(uid, walking); SetMoveInput(moverComp, MoveButtons.None); } @@ -460,10 +463,11 @@ private void ResetSubtick(InputMoverComponent component) component.LastInputSubTick = 0; } + public void SetSprinting(EntityUid entity, InputMoverComponent component, ushort subTick, bool walking) { // Logger.Info($"[{_gameTiming.CurTick}/{subTick}] Sprint: {enabled}"); - + WalkingAlert(entity, walking); SetMoveInput(entity, component, subTick, walking, MoveButtons.Walk); } diff --git a/Content.Shared/Movement/Systems/SharedMoverController.cs b/Content.Shared/Movement/Systems/SharedMoverController.cs index 4d9eedbf7c4..4c2c91db6a1 100644 --- a/Content.Shared/Movement/Systems/SharedMoverController.cs +++ b/Content.Shared/Movement/Systems/SharedMoverController.cs @@ -1,5 +1,6 @@ using System.Diagnostics.CodeAnalysis; using System.Numerics; +using Content.Shared.Alert; using Content.Shared.Bed.Sleep; using Content.Shared.CCVar; using Content.Shared.Friction; @@ -9,7 +10,7 @@ using Content.Shared.Mobs.Systems; using Content.Shared.Movement.Components; using Content.Shared.Movement.Events; -using Content.Shared.Pulling.Components; +using Content.Shared.StepTrigger.Components; using Content.Shared.Tag; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; @@ -23,7 +24,8 @@ using Robust.Shared.Physics.Systems; using Robust.Shared.Timing; using Robust.Shared.Utility; -using Content.Shared.StepTrigger.Components; // Delta V-NoShoesSilentFootstepsComponent +using PullableComponent = Content.Shared.Movement.Pulling.Components.PullableComponent; + namespace Content.Shared.Movement.Systems { @@ -33,6 +35,7 @@ namespace Content.Shared.Movement.Systems /// public abstract partial class SharedMoverController : VirtualController { + [Dependency] private readonly AlertsSystem _alerts = default!; [Dependency] private readonly IConfigurationManager _configManager = default!; [Dependency] protected readonly IGameTiming Timing = default!; [Dependency] private readonly IMapManager _mapManager = default!; @@ -55,7 +58,7 @@ public abstract partial class SharedMoverController : VirtualController protected EntityQuery ModifierQuery; protected EntityQuery PhysicsQuery; protected EntityQuery RelayQuery; - protected EntityQuery PullableQuery; + protected EntityQuery PullableQuery; protected EntityQuery XformQuery; protected EntityQuery CanMoveInAirQuery; protected EntityQuery NoRotateQuery; @@ -87,7 +90,7 @@ public override void Initialize() RelayTargetQuery = GetEntityQuery(); PhysicsQuery = GetEntityQuery(); RelayQuery = GetEntityQuery(); - PullableQuery = GetEntityQuery(); + PullableQuery = GetEntityQuery(); XformQuery = GetEntityQuery(); NoRotateQuery = GetEntityQuery(); CanMoveInAirQuery = GetEntityQuery(); @@ -165,6 +168,7 @@ protected void HandleMobMovement( var (walkDir, sprintDir) = GetVelocityInput(mover); var touching = false; + // Handle wall-pushes. if (weightless) { @@ -285,6 +289,14 @@ protected void HandleMobMovement( PhysicsSystem.SetAngularVelocity(physicsUid, 0, body: physicsComponent); } + public void WalkingAlert(EntityUid player, bool walking) + { + if (HasComp(player)) + { + _alerts.ShowAlert(player, AlertType.Walking, walking ? (short) 0 : (short) 1); + } + } + public void LerpRotation(EntityUid uid, InputMoverComponent mover, float frameTime) { var angleDiff = Angle.ShortestDistance(mover.RelativeRotation, mover.TargetRelativeRotation); @@ -378,7 +390,7 @@ private bool IsAroundCollider(SharedPhysicsSystem broadPhaseSystem, TransformCom !otherCollider.CanCollide || ((collider.CollisionMask & otherCollider.CollisionLayer) == 0 && (otherCollider.CollisionMask & collider.CollisionLayer) == 0) || - (TryComp(otherCollider.Owner, out SharedPullableComponent? pullable) && pullable.BeingPulled)) + (TryComp(otherCollider.Owner, out PullableComponent? pullable) && pullable.BeingPulled)) { continue; } @@ -440,7 +452,7 @@ private bool TryGetSound( sound = moverModifier.FootstepSoundCollection; return true; } - + // If got the component in yml and no shoes = no sound. Delta V if (_entities.TryGetComponent(uid, out NoShoesSilentFootstepsComponent? _) & !_inventory.TryGetSlotEntity(uid, "shoes", out var _)) @@ -469,7 +481,7 @@ private bool TryGetFootstepSound( sound = null; // Fallback to the map? - if (!_mapManager.TryGetGrid(xform.GridUid, out var grid)) + if (!TryComp(xform.GridUid, out var grid)) { if (TryComp(xform.MapUid, out var modifier)) { diff --git a/Content.Shared/Nutrition/Events.cs b/Content.Shared/Nutrition/Events.cs index e27603763fa..f2936d603d9 100644 --- a/Content.Shared/Nutrition/Events.cs +++ b/Content.Shared/Nutrition/Events.cs @@ -53,3 +53,9 @@ public VapeDoAfterEvent(Solution solution, bool forced) public override DoAfterEvent Clone() => this; } + +/// +/// Raised before food is sliced +/// +[ByRefEvent] +public record struct SliceFoodEvent(); diff --git a/Content.Shared/OfferItem/SharedOfferItemSystem.cs b/Content.Shared/OfferItem/SharedOfferItemSystem.cs index c9d7dc5abc1..ffea2a67c0e 100644 --- a/Content.Shared/OfferItem/SharedOfferItemSystem.cs +++ b/Content.Shared/OfferItem/SharedOfferItemSystem.cs @@ -10,18 +10,18 @@ public abstract partial class SharedOfferItemSystem : EntitySystem public override void Initialize() { - SubscribeLocalEvent(SetInReceiveMode); + SubscribeLocalEvent(SetInReceiveMode); SubscribeLocalEvent(OnMove); InitializeInteractions(); } - private void SetInReceiveMode(EntityUid uid, OfferItemComponent component, AfterInteractUsingEvent args) + private void SetInReceiveMode(EntityUid uid, OfferItemComponent component, InteractUsingEvent args) { if (!TryComp(args.User, out var offerItem)) return; - if (args.User == uid || component.IsInReceiveMode || + if (args.User == uid || component.IsInReceiveMode || !offerItem.IsInOfferMode || (offerItem.IsInReceiveMode && offerItem.Target != uid)) return; @@ -44,6 +44,8 @@ private void SetInReceiveMode(EntityUid uid, OfferItemComponent component, After _popup.PopupEntity(Loc.GetString("offer-item-try-give-target", ("user", Identity.Entity(component.Target.Value, EntityManager)), ("item", Identity.Entity(offerItem.Item.Value, EntityManager))), component.Target.Value, uid); + + args.Handled = true; } private void OnMove(EntityUid uid, OfferItemComponent component, MoveEvent args) diff --git a/Content.Shared/Physics/Controllers/SharedConveyorController.cs b/Content.Shared/Physics/Controllers/SharedConveyorController.cs index ec17df7a24f..c9ec77ba1c9 100644 --- a/Content.Shared/Physics/Controllers/SharedConveyorController.cs +++ b/Content.Shared/Physics/Controllers/SharedConveyorController.cs @@ -3,6 +3,7 @@ using Content.Shared.Gravity; using Content.Shared.Movement.Systems; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Controllers; @@ -146,7 +147,7 @@ private static Vector2 Convey(Vector2 direction, float speed, float frameTime, V EntityQuery bodyQuery) { // Check if the thing's centre overlaps the grid tile. - var grid = MapManager.GetGrid(xform.GridUid!.Value); + var grid = Comp(xform.GridUid!.Value); var tile = grid.GetTileRef(xform.Coordinates); var conveyorBounds = Lookup.GetLocalBounds(tile, grid.TileSize); diff --git a/Content.Shared/Players/ContentPlayerData.cs b/Content.Shared/Players/ContentPlayerData.cs index e2074479871..cc7a7e9780f 100644 --- a/Content.Shared/Players/ContentPlayerData.cs +++ b/Content.Shared/Players/ContentPlayerData.cs @@ -1,4 +1,5 @@ -using Content.Shared.GameTicking; +using Content.Shared.Administration; +using Content.Shared.GameTicking; using Content.Shared.Mind; using Robust.Shared.Network; @@ -38,7 +39,12 @@ public sealed class ContentPlayerData public bool ExplicitlyDeadminned { get; set; } /// - /// Nyanotrasen - Are they whitelisted? Lets us avoid async. + /// If true, the admin will not show up in adminwho except to admins with the flag. + /// + public bool Stealthed { get; set; } + + /// + /// Nyanotrasen - Are they whitelisted? Lets us avoid async. /// [ViewVariables] public bool Whitelisted { get; set; } diff --git a/Content.Shared/Pulling/Components/PullableComponent.cs b/Content.Shared/Pulling/Components/PullableComponent.cs deleted file mode 100644 index c5c30688699..00000000000 --- a/Content.Shared/Pulling/Components/PullableComponent.cs +++ /dev/null @@ -1,57 +0,0 @@ -using Robust.Shared.GameStates; -using Robust.Shared.Map; -using Robust.Shared.Serialization; - -namespace Content.Shared.Pulling.Components -{ - // Before you try to add another type than SharedPullingStateManagementSystem, consider the can of worms you may be opening! - [NetworkedComponent, AutoGenerateComponentState] - [Access(typeof(SharedPullingStateManagementSystem))] - [RegisterComponent] - public sealed partial class SharedPullableComponent : Component - { - /// - /// The current entity pulling this component. - /// - [DataField, AutoNetworkedField] - public EntityUid? Puller { get; set; } - - /// - /// The pull joint. - /// - [DataField, AutoNetworkedField] - public string? PullJointId { get; set; } - - public bool BeingPulled => Puller != null; - - [Access(typeof(SharedPullingStateManagementSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends - public EntityCoordinates? MovingTo { get; set; } - - /// - /// If the physics component has FixedRotation should we keep it upon being pulled - /// - [Access(typeof(SharedPullingSystem), Other = AccessPermissions.ReadExecute)] - [ViewVariables(VVAccess.ReadWrite), DataField("fixedRotation")] - public bool FixedRotationOnPull { get; set; } - - /// - /// What the pullable's fixedrotation was set to before being pulled. - /// - [Access(typeof(SharedPullingSystem), Other = AccessPermissions.ReadExecute)] - [ViewVariables] - public bool PrevFixedRotation; - } - - /// - /// Raised when a request is made to stop pulling an entity. - /// - public sealed class StopPullingEvent : CancellableEntityEventArgs - { - public EntityUid? User { get; } - - public StopPullingEvent(EntityUid? uid = null) - { - User = uid; - } - } -} diff --git a/Content.Shared/Pulling/Components/SharedPullerComponent.cs b/Content.Shared/Pulling/Components/SharedPullerComponent.cs deleted file mode 100644 index 57a86e7f7a8..00000000000 --- a/Content.Shared/Pulling/Components/SharedPullerComponent.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared.Pulling.Components -{ - [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] - [Access(typeof(SharedPullingStateManagementSystem))] - public sealed partial class SharedPullerComponent : Component - { - // Before changing how this is updated, please see SharedPullerSystem.RefreshMovementSpeed - public float WalkSpeedModifier => Pulling == default ? 1.0f : 0.95f; - - public float SprintSpeedModifier => Pulling == default ? 1.0f : 0.95f; - - [DataField, AutoNetworkedField] - public EntityUid? Pulling { get; set; } - - /// - /// Does this entity need hands to be able to pull something? - /// - [DataField("needsHands")] - public bool NeedsHands = true; - } -} diff --git a/Content.Shared/Pulling/Events/PullAttemptEvent.cs b/Content.Shared/Pulling/Events/PullAttemptEvent.cs deleted file mode 100644 index 6296dc2f14f..00000000000 --- a/Content.Shared/Pulling/Events/PullAttemptEvent.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Robust.Shared.Physics.Components; - -namespace Content.Shared.Physics.Pull -{ - public sealed class PullAttemptEvent : PullMessage - { - public PullAttemptEvent(PhysicsComponent puller, PhysicsComponent pulled) : base(puller, pulled) { } - - public bool Cancelled { get; set; } - } -} diff --git a/Content.Shared/Pulling/Events/PullMessage.cs b/Content.Shared/Pulling/Events/PullMessage.cs deleted file mode 100644 index b11de7c1702..00000000000 --- a/Content.Shared/Pulling/Events/PullMessage.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Robust.Shared.Physics.Components; - -namespace Content.Shared.Physics.Pull -{ - public abstract class PullMessage : EntityEventArgs - { - public readonly PhysicsComponent Puller; - public readonly PhysicsComponent Pulled; - - protected PullMessage(PhysicsComponent puller, PhysicsComponent pulled) - { - Puller = puller; - Pulled = pulled; - } - } -} diff --git a/Content.Shared/Pulling/Events/PullStartedMessage.cs b/Content.Shared/Pulling/Events/PullStartedMessage.cs deleted file mode 100644 index 0ede284bb0c..00000000000 --- a/Content.Shared/Pulling/Events/PullStartedMessage.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Robust.Shared.Physics.Components; - -namespace Content.Shared.Physics.Pull -{ - public sealed class PullStartedMessage : PullMessage - { - public PullStartedMessage(PhysicsComponent puller, PhysicsComponent pulled) : - base(puller, pulled) - { - } - } -} diff --git a/Content.Shared/Pulling/Events/PullStoppedMessage.cs b/Content.Shared/Pulling/Events/PullStoppedMessage.cs deleted file mode 100644 index afcbcb70740..00000000000 --- a/Content.Shared/Pulling/Events/PullStoppedMessage.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Robust.Shared.Physics.Components; - -namespace Content.Shared.Physics.Pull -{ - public sealed class PullStoppedMessage : PullMessage - { - public PullStoppedMessage(PhysicsComponent puller, PhysicsComponent pulled) : base(puller, pulled) - { - } - } -} diff --git a/Content.Shared/Pulling/PullableMoveMessage.cs b/Content.Shared/Pulling/PullableMoveMessage.cs deleted file mode 100644 index 46c6b1291d6..00000000000 --- a/Content.Shared/Pulling/PullableMoveMessage.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Content.Shared.Pulling -{ - public sealed class PullableMoveMessage : EntityEventArgs - { - } -} diff --git a/Content.Shared/Pulling/PullableStopMovingMessage.cs b/Content.Shared/Pulling/PullableStopMovingMessage.cs deleted file mode 100644 index 0233e32f2b4..00000000000 --- a/Content.Shared/Pulling/PullableStopMovingMessage.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Content.Shared.Pulling -{ - public sealed class PullableStopMovingMessage : EntityEventArgs - { - } -} diff --git a/Content.Shared/Pulling/Systems/SharedPullableSystem.cs b/Content.Shared/Pulling/Systems/SharedPullableSystem.cs deleted file mode 100644 index 3dab476337b..00000000000 --- a/Content.Shared/Pulling/Systems/SharedPullableSystem.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Content.Shared.ActionBlocker; -using Content.Shared.Mobs.Systems; -using Content.Shared.Pulling.Components; -using Content.Shared.Movement.Events; - -namespace Content.Shared.Pulling.Systems -{ - public sealed class SharedPullableSystem : EntitySystem - { - [Dependency] private readonly ActionBlockerSystem _blocker = default!; - [Dependency] private readonly MobStateSystem _mobState = default!; - [Dependency] private readonly SharedPullingSystem _pullSystem = default!; - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnRelayMoveInput); - } - - private void OnRelayMoveInput(EntityUid uid, SharedPullableComponent component, ref MoveInputEvent args) - { - var entity = args.Entity; - if (_mobState.IsIncapacitated(entity) || !_blocker.CanMove(entity)) return; - - _pullSystem.TryStopPull(component); - } - } -} diff --git a/Content.Shared/Pulling/Systems/SharedPullerSystem.cs b/Content.Shared/Pulling/Systems/SharedPullerSystem.cs deleted file mode 100644 index e388d7a57c6..00000000000 --- a/Content.Shared/Pulling/Systems/SharedPullerSystem.cs +++ /dev/null @@ -1,90 +0,0 @@ -using Content.Shared.Administration.Logs; -using Content.Shared.Alert; -using Content.Shared.Database; -using Content.Shared.Hands; -using Content.Shared.Movement.Systems; -using Content.Shared.Physics.Pull; -using Content.Shared.Pulling.Components; -using JetBrains.Annotations; - -namespace Content.Shared.Pulling.Systems -{ - [UsedImplicitly] - public sealed class SharedPullerSystem : EntitySystem - { - [Dependency] private readonly SharedPullingStateManagementSystem _why = default!; - [Dependency] private readonly SharedPullingSystem _pullSystem = default!; - [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifierSystem = default!; - [Dependency] private readonly AlertsSystem _alertsSystem = default!; - [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(PullerHandlePullStarted); - SubscribeLocalEvent(PullerHandlePullStopped); - SubscribeLocalEvent(OnVirtualItemDeleted); - SubscribeLocalEvent(OnRefreshMovespeed); - SubscribeLocalEvent(OnPullerShutdown); - } - - private void OnPullerShutdown(EntityUid uid, SharedPullerComponent component, ComponentShutdown args) - { - _why.ForceDisconnectPuller(component); - } - - private void OnVirtualItemDeleted(EntityUid uid, SharedPullerComponent component, VirtualItemDeletedEvent args) - { - if (component.Pulling == null) - return; - - if (component.Pulling == args.BlockingEntity) - { - if (EntityManager.TryGetComponent(args.BlockingEntity, out var comp)) - { - _pullSystem.TryStopPull(comp, uid); - } - } - } - - private void PullerHandlePullStarted( - EntityUid uid, - SharedPullerComponent component, - PullStartedMessage args) - { - if (args.Puller.Owner != uid) - return; - - _alertsSystem.ShowAlert(component.Owner, AlertType.Pulling); - - RefreshMovementSpeed(component); - } - - private void PullerHandlePullStopped( - EntityUid uid, - SharedPullerComponent component, - PullStoppedMessage args) - { - if (args.Puller.Owner != uid) - return; - - var euid = component.Owner; - if (_alertsSystem.IsShowingAlert(euid, AlertType.Pulling)) - _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(euid):user} stopped pulling {ToPrettyString(args.Pulled.Owner):target}"); - _alertsSystem.ClearAlert(euid, AlertType.Pulling); - - RefreshMovementSpeed(component); - } - - private void OnRefreshMovespeed(EntityUid uid, SharedPullerComponent component, RefreshMovementSpeedModifiersEvent args) - { - args.ModifySpeed(component.WalkSpeedModifier, component.SprintSpeedModifier); - } - - private void RefreshMovementSpeed(SharedPullerComponent component) - { - _movementSpeedModifierSystem.RefreshMovementSpeedModifiers(component.Owner); - } - } -} diff --git a/Content.Shared/Pulling/Systems/SharedPullingStateManagementSystem.cs b/Content.Shared/Pulling/Systems/SharedPullingStateManagementSystem.cs deleted file mode 100644 index 38ed8998898..00000000000 --- a/Content.Shared/Pulling/Systems/SharedPullingStateManagementSystem.cs +++ /dev/null @@ -1,196 +0,0 @@ -using Content.Shared.Physics.Pull; -using Content.Shared.Pulling.Components; -using JetBrains.Annotations; -using Robust.Shared.Map; -using Robust.Shared.Physics; -using Robust.Shared.Physics.Components; -using Robust.Shared.Physics.Systems; -using Robust.Shared.Timing; - -namespace Content.Shared.Pulling -{ - /// - /// This is the core of pulling state management. - /// Because pulling state is such a mess to get right, all writes to pulling state must go through this class. - /// - [UsedImplicitly] - public sealed class SharedPullingStateManagementSystem : EntitySystem - { - [Dependency] private readonly SharedJointSystem _jointSystem = default!; - [Dependency] private readonly SharedPhysicsSystem _physics = default!; - [Dependency] private readonly IGameTiming _timing = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnShutdown); - } - - private void OnShutdown(EntityUid uid, SharedPullableComponent component, ComponentShutdown args) - { - if (component.Puller != null) - ForceRelationship(null, component); - } - - // A WARNING: - // The following 2 functions are the most internal part of the pulling system's relationship management. - // They do not expect to be cancellable. - private void ForceDisconnect(SharedPullerComponent puller, SharedPullableComponent pullable) - { - var pullerPhysics = EntityManager.GetComponent(puller.Owner); - var pullablePhysics = EntityManager.GetComponent(pullable.Owner); - - // MovingTo shutdown - ForceSetMovingTo(pullable, null); - - // Joint shutdown - if (!_timing.ApplyingState && // During state-handling, joint component will handle its own state. - pullable.PullJointId != null && - TryComp(puller.Owner, out JointComponent? jointComp)) - { - if (jointComp.GetJoints.TryGetValue(pullable.PullJointId, out var j)) - _jointSystem.RemoveJoint(j); - } - pullable.PullJointId = null; - - // State shutdown - puller.Pulling = null; - pullable.Puller = null; - - // Messaging - var message = new PullStoppedMessage(pullerPhysics, pullablePhysics); - - RaiseLocalEvent(puller.Owner, message, broadcast: false); - - if (Initialized(pullable.Owner)) - RaiseLocalEvent(pullable.Owner, message, true); - - // Networking - Dirty(puller); - Dirty(pullable); - } - - public void ForceRelationship(SharedPullerComponent? puller, SharedPullableComponent? pullable) - { - if (_timing.ApplyingState) - return; - ; - if (pullable != null && puller != null && (puller.Pulling == pullable.Owner)) - { - // Already done - return; - } - - // Start by disconnecting the pullable from whatever it is currently connected to. - var pullableOldPullerE = pullable?.Puller; - if (pullableOldPullerE != null) - { - ForceDisconnect(EntityManager.GetComponent(pullableOldPullerE.Value), pullable!); - } - - // Continue with the puller. - var pullerOldPullableE = puller?.Pulling; - if (pullerOldPullableE != null) - { - ForceDisconnect(puller!, EntityManager.GetComponent(pullerOldPullableE.Value)); - } - - // And now for the actual connection (if any). - - if (puller != null && pullable != null) - { - var pullerPhysics = EntityManager.GetComponent(puller.Owner); - var pullablePhysics = EntityManager.GetComponent(pullable.Owner); - pullable.PullJointId = $"pull-joint-{pullable.Owner}"; - - // State startup - puller.Pulling = pullable.Owner; - pullable.Puller = puller.Owner; - - // joint state handling will manage its own state - if (!_timing.ApplyingState) - { - // Joint startup - var union = _physics.GetHardAABB(puller.Owner).Union(_physics.GetHardAABB(pullable.Owner, body: pullablePhysics)); - var length = Math.Max(union.Size.X, union.Size.Y) * 0.75f; - - var joint = _jointSystem.CreateDistanceJoint(pullablePhysics.Owner, pullerPhysics.Owner, id: pullable.PullJointId); - joint.CollideConnected = false; - // This maximum has to be there because if the object is constrained too closely, the clamping goes backwards and asserts. - joint.MaxLength = Math.Max(1.0f, length); - joint.Length = length * 0.75f; - joint.MinLength = 0f; - joint.Stiffness = 1f; - } - - // Messaging - var message = new PullStartedMessage(pullerPhysics, pullablePhysics); - - RaiseLocalEvent(puller.Owner, message, broadcast: false); - RaiseLocalEvent(pullable.Owner, message, true); - - // Networking - Dirty(puller); - Dirty(pullable); - } - } - - // For OnRemove use only. - public void ForceDisconnectPuller(SharedPullerComponent puller) - { - // DO NOT ADD ADDITIONAL LOGIC IN THIS FUNCTION. Do it in ForceRelationship. - ForceRelationship(puller, null); - } - - // For OnRemove use only. - public void ForceDisconnectPullable(SharedPullableComponent pullable) - { - // DO NOT ADD ADDITIONAL LOGIC IN THIS FUNCTION. Do it in ForceRelationship. - ForceRelationship(null, pullable); - } - - public void ForceSetMovingTo(SharedPullableComponent pullable, EntityCoordinates? movingTo) - { - if (_timing.ApplyingState) - return; - - if (pullable.MovingTo == movingTo) - { - return; - } - - // Don't allow setting a MovingTo if there's no puller. - // The other half of this guarantee (shutting down a MovingTo if the puller goes away) is enforced in ForceRelationship. - if (pullable.Puller == null && movingTo != null) - { - return; - } - - pullable.MovingTo = movingTo; - Dirty(pullable); - - if (movingTo == null) - { - RaiseLocalEvent(pullable.Owner, new PullableStopMovingMessage(), true); - } - else - { - RaiseLocalEvent(pullable.Owner, new PullableMoveMessage(), true); - } - } - - /// - /// Changes if the entity needs a hand in order to be able to pull objects. - /// - public void ChangeHandRequirement(EntityUid uid, bool needsHands, SharedPullerComponent? comp) - { - if (!Resolve(uid, ref comp, false)) - return; - - comp.NeedsHands = needsHands; - - Dirty(uid, comp); - } - } -} diff --git a/Content.Shared/Pulling/Systems/SharedPullingSystem.Actions.cs b/Content.Shared/Pulling/Systems/SharedPullingSystem.Actions.cs deleted file mode 100644 index 1e2bb90c61e..00000000000 --- a/Content.Shared/Pulling/Systems/SharedPullingSystem.Actions.cs +++ /dev/null @@ -1,239 +0,0 @@ -using Content.Shared.ActionBlocker; -using Content.Shared.Administration.Logs; -using Content.Shared.Buckle.Components; -using Content.Shared.Database; -using Content.Shared.Hands.EntitySystems; -using Content.Shared.Interaction; -using Content.Shared.Physics.Pull; -using Content.Shared.Pulling.Components; -using Content.Shared.Pulling.Events; -using Robust.Shared.Containers; -using Robust.Shared.Map; -using Robust.Shared.Physics; -using Robust.Shared.Physics.Components; -using Robust.Shared.Physics.Systems; -using Robust.Shared.Timing; -using Robust.Shared.Utility; - -namespace Content.Shared.Pulling -{ - public abstract partial class SharedPullingSystem - { - [Dependency] private readonly ActionBlockerSystem _blocker = default!; - [Dependency] private readonly SharedContainerSystem _containerSystem = default!; - [Dependency] private readonly SharedHandsSystem _handsSystem = default!; - [Dependency] private readonly SharedInteractionSystem _interaction = default!; - [Dependency] private readonly SharedPhysicsSystem _physics = default!; - [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; - [Dependency] private readonly IGameTiming _timing = default!; - - public bool CanPull(EntityUid puller, EntityUid pulled) - { - if (!EntityManager.TryGetComponent(puller, out var comp)) - { - return false; - } - - if (comp.NeedsHands && !_handsSystem.TryGetEmptyHand(puller, out _)) - { - return false; - } - - if (!_blocker.CanInteract(puller, pulled)) - { - return false; - } - - if (!EntityManager.TryGetComponent(pulled, out var physics)) - { - return false; - } - - if (physics.BodyType == BodyType.Static) - { - return false; - } - - if (puller == pulled) - { - return false; - } - - if(_containerSystem.IsEntityInContainer(puller) || _containerSystem.IsEntityInContainer(pulled)) - { - return false; - } - - if (EntityManager.TryGetComponent(puller, out BuckleComponent? buckle)) - { - // Prevent people pulling the chair they're on, etc. - if (buckle is { PullStrap: false, Buckled: true } && (buckle.LastEntityBuckledTo == pulled)) - { - return false; - } - } - - var getPulled = new BeingPulledAttemptEvent(puller, pulled); - RaiseLocalEvent(pulled, getPulled, true); - var startPull = new StartPullAttemptEvent(puller, pulled); - RaiseLocalEvent(puller, startPull, true); - return (!startPull.Cancelled && !getPulled.Cancelled); - } - - public bool TogglePull(EntityUid puller, SharedPullableComponent pullable) - { - if (pullable.Puller == puller) - { - return TryStopPull(pullable); - } - return TryStartPull(puller, pullable.Owner); - } - - // -- Core attempted actions -- - - public bool TryStopPull(SharedPullableComponent pullable, EntityUid? user = null) - { - if (_timing.ApplyingState) - return false; - - if (!pullable.BeingPulled) - { - return false; - } - - var msg = new StopPullingEvent(user); - RaiseLocalEvent(pullable.Owner, msg, true); - - if (msg.Cancelled) return false; - - // Stop pulling confirmed! - - if (TryComp(pullable.Owner, out var pullablePhysics)) - { - _physics.SetFixedRotation(pullable.Owner, pullable.PrevFixedRotation, body: pullablePhysics); - } - - _pullSm.ForceRelationship(null, pullable); - return true; - } - - public bool TryStartPull(EntityUid puller, EntityUid pullable) - { - if (!EntityManager.TryGetComponent(puller, out SharedPullerComponent? pullerComp)) - { - return false; - } - if (!EntityManager.TryGetComponent(pullable, out SharedPullableComponent? pullableComp)) - { - return false; - } - return TryStartPull(pullerComp, pullableComp); - } - - // The main "start pulling" function. - public bool TryStartPull(SharedPullerComponent puller, SharedPullableComponent pullable) - { - if (_timing.ApplyingState) - return false; - - if (puller.Pulling == pullable.Owner) - return true; - - // Pulling a new object : Perform sanity checks. - - if (!CanPull(puller.Owner, pullable.Owner)) - { - return false; - } - - if (!EntityManager.TryGetComponent(puller.Owner, out var pullerPhysics)) - { - return false; - } - - if (!EntityManager.TryGetComponent(pullable.Owner, out var pullablePhysics)) - { - return false; - } - - // Ensure that the puller is not currently pulling anything. - // If this isn't done, then it happens too late, and the start/stop messages go out of order, - // and next thing you know it thinks it's not pulling anything even though it is! - - var oldPullable = puller.Pulling; - if (oldPullable != null) - { - if (EntityManager.TryGetComponent(oldPullable.Value, out SharedPullableComponent? oldPullableComp)) - { - if (!TryStopPull(oldPullableComp)) - { - return false; - } - } - else - { - Log.Warning("Well now you've done it, haven't you? Someone transferred pulling (onto {0}) while presently pulling something that has no Pullable component (on {1})!", pullable.Owner, oldPullable); - return false; - } - } - - // Ensure that the pullable is not currently being pulled. - // Same sort of reasons as before. - - var oldPuller = pullable.Puller; - if (oldPuller != null) - { - if (!TryStopPull(pullable)) - { - return false; - } - } - - // Continue with pulling process. - - var pullAttempt = new PullAttemptEvent(pullerPhysics, pullablePhysics); - - RaiseLocalEvent(puller.Owner, pullAttempt, broadcast: false); - - if (pullAttempt.Cancelled) - { - return false; - } - - RaiseLocalEvent(pullable.Owner, pullAttempt, true); - - if (pullAttempt.Cancelled) - return false; - - _interaction.DoContactInteraction(pullable.Owner, puller.Owner); - - _pullSm.ForceRelationship(puller, pullable); - pullable.PrevFixedRotation = pullablePhysics.FixedRotation; - _physics.SetFixedRotation(pullable.Owner, pullable.FixedRotationOnPull, body: pullablePhysics); - _adminLogger.Add(LogType.Action, LogImpact.Low, - $"{ToPrettyString(puller.Owner):user} started pulling {ToPrettyString(pullable.Owner):target}"); - return true; - } - - public bool TryMoveTo(SharedPullableComponent pullable, EntityCoordinates to) - { - if (pullable.Puller == null) - { - return false; - } - - if (!EntityManager.HasComponent(pullable.Owner)) - { - return false; - } - - _pullSm.ForceSetMovingTo(pullable, to); - return true; - } - - public void StopMoveTo(SharedPullableComponent pullable) - { - _pullSm.ForceSetMovingTo(pullable, null); - } - } -} diff --git a/Content.Shared/Pulling/Systems/SharedPullingSystem.cs b/Content.Shared/Pulling/Systems/SharedPullingSystem.cs deleted file mode 100644 index 0c139ee9e35..00000000000 --- a/Content.Shared/Pulling/Systems/SharedPullingSystem.cs +++ /dev/null @@ -1,243 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Content.Shared.Alert; -using Content.Shared.GameTicking; -using Content.Shared.Input; -using Content.Shared.Physics.Pull; -using Content.Shared.Pulling.Components; -using Content.Shared.Verbs; -using JetBrains.Annotations; -using Robust.Shared.Containers; -using Robust.Shared.Input.Binding; -using Robust.Shared.Map; -using Robust.Shared.Physics; -using Robust.Shared.Physics.Events; -using Robust.Shared.Physics.Systems; -using Robust.Shared.Player; - -namespace Content.Shared.Pulling -{ - [UsedImplicitly] - public abstract partial class SharedPullingSystem : EntitySystem - { - [Dependency] private readonly SharedPullingStateManagementSystem _pullSm = default!; - [Dependency] private readonly AlertsSystem _alertsSystem = default!; - [Dependency] private readonly SharedJointSystem _joints = default!; - - /// - /// A mapping of pullers to the entity that they are pulling. - /// - private readonly Dictionary _pullers = - new(); - - private readonly HashSet _moving = new(); - private readonly HashSet _stoppedMoving = new(); - - public IReadOnlySet Moving => _moving; - - public override void Initialize() - { - base.Initialize(); - - UpdatesOutsidePrediction = true; - - SubscribeLocalEvent(Reset); - SubscribeLocalEvent(OnPullStarted); - SubscribeLocalEvent(OnPullStopped); - SubscribeLocalEvent(HandleContainerInsert); - SubscribeLocalEvent(OnJointRemoved); - SubscribeLocalEvent(OnPullableCollisionChange); - - SubscribeLocalEvent(PullableHandlePullStarted); - SubscribeLocalEvent(PullableHandlePullStopped); - - SubscribeLocalEvent>(AddPullVerbs); - - CommandBinds.Builder - .Bind(ContentKeyFunctions.MovePulledObject, new PointerInputCmdHandler(HandleMovePulledObject)) - .Register(); - } - - private void OnPullableCollisionChange(EntityUid uid, SharedPullableComponent component, ref CollisionChangeEvent args) - { - if (component.PullJointId != null && !args.CanCollide) - { - _joints.RemoveJoint(uid, component.PullJointId); - } - } - - private void OnJointRemoved(EntityUid uid, SharedPullableComponent component, JointRemovedEvent args) - { - if (component.Puller != args.OtherEntity) - return; - - // Do we have some other join with our Puller? - // or alternatively: - // TODO track the relevant joint. - - if (TryComp(uid, out JointComponent? joints)) - { - foreach (var jt in joints.GetJoints.Values) - { - if (jt.BodyAUid == component.Puller || jt.BodyBUid == component.Puller) - return; - } - } - - // No more joints with puller -> force stop pull. - _pullSm.ForceDisconnectPullable(component); - } - - private void AddPullVerbs(EntityUid uid, SharedPullableComponent component, GetVerbsEvent args) - { - if (!args.CanAccess || !args.CanInteract) - return; - - // Are they trying to pull themselves up by their bootstraps? - if (args.User == args.Target) - return; - - //TODO VERB ICONS add pulling icon - if (component.Puller == args.User) - { - Verb verb = new() - { - Text = Loc.GetString("pulling-verb-get-data-text-stop-pulling"), - Act = () => TryStopPull(component, args.User), - DoContactInteraction = false // pulling handle its own contact interaction. - }; - args.Verbs.Add(verb); - } - else if (CanPull(args.User, args.Target)) - { - Verb verb = new() - { - Text = Loc.GetString("pulling-verb-get-data-text"), - Act = () => TryStartPull(args.User, args.Target), - DoContactInteraction = false // pulling handle its own contact interaction. - }; - args.Verbs.Add(verb); - } - } - - // Raise a "you are being pulled" alert if the pulled entity has alerts. - private void PullableHandlePullStarted(EntityUid uid, SharedPullableComponent component, PullStartedMessage args) - { - if (args.Pulled.Owner != uid) - return; - - _alertsSystem.ShowAlert(uid, AlertType.Pulled); - } - - private void PullableHandlePullStopped(EntityUid uid, SharedPullableComponent component, PullStoppedMessage args) - { - if (args.Pulled.Owner != uid) - return; - - _alertsSystem.ClearAlert(uid, AlertType.Pulled); - } - - public bool IsPulled(EntityUid uid, SharedPullableComponent? component = null) - { - return Resolve(uid, ref component, false) && component.BeingPulled; - } - - public override void Update(float frameTime) - { - base.Update(frameTime); - - _moving.ExceptWith(_stoppedMoving); - _stoppedMoving.Clear(); - } - - public void Reset(RoundRestartCleanupEvent ev) - { - _pullers.Clear(); - _moving.Clear(); - _stoppedMoving.Clear(); - } - - private void OnPullStarted(PullStartedMessage message) - { - SetPuller(message.Puller.Owner, message.Pulled.Owner); - } - - private void OnPullStopped(PullStoppedMessage message) - { - RemovePuller(message.Puller.Owner); - } - - protected void OnPullableMove(EntityUid uid, SharedPullableComponent component, PullableMoveMessage args) - { - _moving.Add(component); - } - - protected void OnPullableStopMove(EntityUid uid, SharedPullableComponent component, PullableStopMovingMessage args) - { - _stoppedMoving.Add(component); - } - - // TODO: When Joint networking is less shitcodey fix this to use a dedicated joints message. - private void HandleContainerInsert(EntInsertedIntoContainerMessage message) - { - if (TryComp(message.Entity, out SharedPullableComponent? pullable)) - { - TryStopPull(pullable); - } - - if (TryComp(message.Entity, out SharedPullerComponent? puller)) - { - if (puller.Pulling == null) return; - - if (!TryComp(puller.Pulling.Value, out SharedPullableComponent? pulling)) - return; - - TryStopPull(pulling); - } - } - - private bool HandleMovePulledObject(ICommonSession? session, EntityCoordinates coords, EntityUid uid) - { - if (session?.AttachedEntity is not { } player || - !player.IsValid()) - return false; - - if (!TryGetPulled(player, out var pulled)) - return false; - - if (!TryComp(pulled.Value, out SharedPullableComponent? pullable)) - return false; - - if (_containerSystem.IsEntityInContainer(player)) - return false; - - TryMoveTo(pullable, coords); - - return false; - } - - private void SetPuller(EntityUid puller, EntityUid pulled) - { - _pullers[puller] = pulled; - } - - private bool RemovePuller(EntityUid puller) - { - return _pullers.Remove(puller); - } - - public EntityUid GetPulled(EntityUid by) - { - return _pullers.GetValueOrDefault(by); - } - - public bool TryGetPulled(EntityUid by, [NotNullWhen(true)] out EntityUid? pulled) - { - return (pulled = GetPulled(by)) != null; - } - - public bool IsPulling(EntityUid puller) - { - return _pullers.ContainsKey(puller); - } - } -} diff --git a/Content.Shared/RCD/Systems/RCDSystem.cs b/Content.Shared/RCD/Systems/RCDSystem.cs index 187c8d8a9d8..9e784512076 100644 --- a/Content.Shared/RCD/Systems/RCDSystem.cs +++ b/Content.Shared/RCD/Systems/RCDSystem.cs @@ -25,7 +25,6 @@ namespace Content.Shared.RCD.Systems; public sealed class RCDSystem : EntitySystem { [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly IMapManager _mapMan = default!; [Dependency] private readonly INetManager _net = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly ITileDefinitionManager _tileDefMan = default!; @@ -39,7 +38,7 @@ public sealed class RCDSystem : EntitySystem [Dependency] private readonly TurfSystem _turf = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; - private readonly int RcdModeCount = Enum.GetValues(typeof(RcdMode)).Length; + private readonly int _rcdModeCount = Enum.GetValues(typeof(RcdMode)).Length; public override void Initialize() { @@ -133,7 +132,7 @@ private void OnDoAfterAttempt(EntityUid uid, RCDComponent comp, DoAfterAttemptEv return; } - var mapGrid = _mapMan.GetGrid(gridId.Value); + var mapGrid = Comp(gridId.Value); var tile = mapGrid.GetTileRef(location); if (!IsRCDStillValid(uid, comp, args.Event.User, args.Event.Target, mapGrid, tile, args.Event.StartingMode)) @@ -158,7 +157,7 @@ private void OnDoAfter(EntityUid uid, RCDComponent comp, RCDDoAfterEvent args) return; } - var mapGrid = _mapMan.GetGrid(gridId.Value); + var mapGrid = Comp(gridId.Value); var tile = mapGrid.GetTileRef(location); var snapPos = mapGrid.TileIndicesFor(location); @@ -311,7 +310,7 @@ private void NextMode(EntityUid uid, RCDComponent comp, EntityUid user) _audio.PlayPredicted(comp.SwapModeSound, uid, user); var mode = (int) comp.Mode; - mode = ++mode % RcdModeCount; + mode = ++mode % _rcdModeCount; comp.Mode = (RcdMode) mode; Dirty(comp); diff --git a/Content.Shared/Remotes/Components/DoorRemoteComponent.cs b/Content.Shared/Remotes/Components/DoorRemoteComponent.cs new file mode 100644 index 00000000000..b157596e3b9 --- /dev/null +++ b/Content.Shared/Remotes/Components/DoorRemoteComponent.cs @@ -0,0 +1,19 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Remotes.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class DoorRemoteComponent : Component +{ + [AutoNetworkedField] + [DataField] + public OperatingMode Mode = OperatingMode.OpenClose; +} + +public enum OperatingMode : byte +{ + OpenClose, + ToggleBolts, + ToggleEmergencyAccess, + placeholderForUiUpdates +} diff --git a/Content.Shared/Remotes/EntitySystems/SharedDoorRemoteSystem.cs b/Content.Shared/Remotes/EntitySystems/SharedDoorRemoteSystem.cs new file mode 100644 index 00000000000..e9bbd27ada4 --- /dev/null +++ b/Content.Shared/Remotes/EntitySystems/SharedDoorRemoteSystem.cs @@ -0,0 +1,44 @@ +using Content.Shared.Popups; +using Content.Shared.Interaction.Events; +using Content.Shared.Remotes.Components; + +namespace Content.Shared.Remotes.EntitySystems; + +public abstract class SharedDoorRemoteSystem : EntitySystem +{ + [Dependency] protected readonly SharedPopupSystem Popup = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnInHandActivation); + } + + private void OnInHandActivation(Entity entity, ref UseInHandEvent args) + { + string switchMessageId; + switch (entity.Comp.Mode) + { + case OperatingMode.OpenClose: + entity.Comp.Mode = OperatingMode.ToggleBolts; + switchMessageId = "door-remote-switch-state-toggle-bolts"; + break; + + // Skip toggle bolts mode and move on from there (to emergency access) + case OperatingMode.ToggleBolts: + entity.Comp.Mode = OperatingMode.ToggleEmergencyAccess; + switchMessageId = "door-remote-switch-state-toggle-emergency-access"; + break; + + // Skip ToggleEmergencyAccess mode and move on from there (to door toggle) + case OperatingMode.ToggleEmergencyAccess: + entity.Comp.Mode = OperatingMode.OpenClose; + switchMessageId = "door-remote-switch-state-open-close"; + break; + default: + throw new InvalidOperationException( + $"{nameof(DoorRemoteComponent)} had invalid mode {entity.Comp.Mode}"); + } + Dirty(entity); + Popup.PopupClient(Loc.GetString(switchMessageId), entity, args.User); + } +} diff --git a/Content.Shared/Research/Components/ResearchStealerComponent.cs b/Content.Shared/Research/Components/ResearchStealerComponent.cs index e0331fad1bb..df8878e6516 100644 --- a/Content.Shared/Research/Components/ResearchStealerComponent.cs +++ b/Content.Shared/Research/Components/ResearchStealerComponent.cs @@ -14,4 +14,16 @@ public sealed partial class ResearchStealerComponent : Component /// [DataField("delay"), ViewVariables(VVAccess.ReadWrite)] public TimeSpan Delay = TimeSpan.FromSeconds(20); + + /// + /// The minimum number of technologies that will be stolen + /// + [DataField] + public int MinToSteal = 4; + + /// + /// The maximum number of technologies that will be stolen + /// + [DataField] + public int MaxToSteal = 8; } diff --git a/Content.Shared/Research/Systems/SharedResearchSystem.cs b/Content.Shared/Research/Systems/SharedResearchSystem.cs index 12f27d0b9c9..9819e949b8b 100644 --- a/Content.Shared/Research/Systems/SharedResearchSystem.cs +++ b/Content.Shared/Research/Systems/SharedResearchSystem.cs @@ -1,6 +1,7 @@ using System.Linq; using Content.Shared.Research.Components; using Content.Shared.Research.Prototypes; +using JetBrains.Annotations; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Utility; @@ -219,16 +220,58 @@ public void TrySetMainDiscipline(TechnologyPrototype prototype, EntityUid uid, T if (!Resolve(uid, ref component)) return; - var discipline = PrototypeManager.Index(prototype.Discipline); + var discipline = PrototypeManager.Index(prototype.Discipline); if (prototype.Tier < discipline.LockoutTier) return; component.MainDiscipline = prototype.Discipline; Dirty(uid, component); } + /// + /// Removes a technology and its recipes from a technology database. + /// + public bool TryRemoveTechnology(Entity entity, ProtoId tech) + { + return TryRemoveTechnology(entity, PrototypeManager.Index(tech)); + } + + /// + /// Removes a technology and its recipes from a technology database. + /// + [PublicAPI] + public bool TryRemoveTechnology(Entity entity, TechnologyPrototype tech) + { + if (!entity.Comp.UnlockedTechnologies.Remove(tech.ID)) + return false; + + // check to make sure we didn't somehow get the recipe from another tech. + // unlikely, but whatever + var recipes = tech.RecipeUnlocks; + foreach (var recipe in recipes) + { + var hasTechElsewhere = false; + foreach (var unlockedTech in entity.Comp.UnlockedTechnologies) + { + var unlockedTechProto = PrototypeManager.Index(unlockedTech); + + if (!unlockedTechProto.RecipeUnlocks.Contains(recipe)) + continue; + hasTechElsewhere = true; + break; + } + + if (!hasTechElsewhere) + entity.Comp.UnlockedRecipes.Remove(recipe); + } + Dirty(entity, entity.Comp); + UpdateTechnologyCards(entity, entity); + return true; + } + /// /// Clear all unlocked technologies from the database. /// + [PublicAPI] public void ClearTechs(EntityUid uid, TechnologyDatabaseComponent? comp = null) { if (!Resolve(uid, ref comp) || comp.UnlockedTechnologies.Count == 0) diff --git a/Content.Shared/Security/Systems/DeployableBarrierSystem.cs b/Content.Shared/Security/Systems/DeployableBarrierSystem.cs index 7b9ce841a99..622edc4b62e 100644 --- a/Content.Shared/Security/Systems/DeployableBarrierSystem.cs +++ b/Content.Shared/Security/Systems/DeployableBarrierSystem.cs @@ -1,6 +1,6 @@ using Content.Shared.Lock; -using Content.Shared.Pulling; -using Content.Shared.Pulling.Components; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Systems; using Content.Shared.Security.Components; using Robust.Shared.Physics.Systems; @@ -11,7 +11,7 @@ public sealed class DeployableBarrierSystem : EntitySystem [Dependency] private readonly FixtureSystem _fixtures = default!; [Dependency] private readonly SharedPointLightSystem _pointLight = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; - [Dependency] private readonly SharedPullingSystem _pulling = default!; + [Dependency] private readonly PullingSystem _pulling = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; public override void Initialize() @@ -54,8 +54,8 @@ private void ToggleBarrierDeploy(EntityUid uid, bool isDeployed, DeployableBarri _physics.SetHard(uid, fixture, false); } - if (TryComp(uid, out SharedPullableComponent? pullable)) - _pulling.TryStopPull(pullable); + if (TryComp(uid, out PullableComponent? pullable)) + _pulling.TryStopPull(uid, pullable); SharedPointLightComponent? pointLight = null; if (_pointLight.ResolveLight(uid, ref pointLight)) diff --git a/Content.Shared/Shuttles/Components/IFFComponent.cs b/Content.Shared/Shuttles/Components/IFFComponent.cs index a7e6ac1152b..6bacbd2b5b1 100644 --- a/Content.Shared/Shuttles/Components/IFFComponent.cs +++ b/Content.Shared/Shuttles/Components/IFFComponent.cs @@ -10,11 +10,6 @@ namespace Content.Shared.Shuttles.Components; [Access(typeof(SharedShuttleSystem))] public sealed partial class IFFComponent : Component { - /// - /// Should we show IFF by default? - /// - public const bool ShowIFFDefault = true; - public static readonly Color SelfColor = Color.MediumSpringGreen; /// diff --git a/Content.Shared/Shuttles/Systems/SharedShuttleSystem.IFF.cs b/Content.Shared/Shuttles/Systems/SharedShuttleSystem.IFF.cs index ed687d48f4b..8231e48e2db 100644 --- a/Content.Shared/Shuttles/Systems/SharedShuttleSystem.IFF.cs +++ b/Content.Shared/Shuttles/Systems/SharedShuttleSystem.IFF.cs @@ -28,11 +28,6 @@ public Color GetIFFColor(EntityUid gridUid, bool self = false, IFFComponent? com public string? GetIFFLabel(EntityUid gridUid, bool self = false, IFFComponent? component = null) { - if (!IFFComponent.ShowIFFDefault) - { - return null; - } - var entName = MetaData(gridUid).EntityName; if (self) diff --git a/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs b/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs index 324fd65c860..ca25a49b23f 100644 --- a/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs +++ b/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs @@ -146,7 +146,6 @@ public bool FTLFree(EntityUid shuttleUid, EntityCoordinates coordinates, Angle a // Just checks if any grids inside of a buffer range at the target position. _grids.Clear(); - var ftlRange = FTLRange; var mapCoordinates = coordinates.ToMap(EntityManager, XformSystem); var ourPos = Maps.GetGridPosition((shuttleUid, shuttlePhysics, shuttleXform)); diff --git a/Content.Shared/Sound/SharedEmitSoundSystem.cs b/Content.Shared/Sound/SharedEmitSoundSystem.cs index 22ba8e0e3ee..56a51744acf 100644 --- a/Content.Shared/Sound/SharedEmitSoundSystem.cs +++ b/Content.Shared/Sound/SharedEmitSoundSystem.cs @@ -9,6 +9,7 @@ using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Network; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; @@ -25,7 +26,6 @@ public abstract class SharedEmitSoundSystem : EntitySystem { [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly INetManager _netMan = default!; - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly ITileDefinitionManager _tileDefMan = default!; [Dependency] protected readonly IRobustRandom Random = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; @@ -54,7 +54,7 @@ private void OnEmitSoundOnLand(EntityUid uid, BaseEmitSoundComponent component, { if (!args.PlaySound || !TryComp(uid, out var xform) || - !_mapManager.TryGetGrid(xform.GridUid, out var grid)) + !TryComp(xform.GridUid, out var grid)) { return; } diff --git a/Content.Shared/Storage/EntitySystems/DumpableSystem.cs b/Content.Shared/Storage/EntitySystems/DumpableSystem.cs index 04f7231416f..568d9dab3bd 100644 --- a/Content.Shared/Storage/EntitySystems/DumpableSystem.cs +++ b/Content.Shared/Storage/EntitySystems/DumpableSystem.cs @@ -19,17 +19,16 @@ public sealed class DumpableSystem : EntitySystem [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly SharedDisposalUnitSystem _disposalUnitSystem = default!; [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; [Dependency] private readonly SharedTransformSystem _transformSystem = default!; - private EntityQuery _xformQuery; + private EntityQuery _itemQuery; public override void Initialize() { base.Initialize(); - _xformQuery = GetEntityQuery(); + _itemQuery = GetEntityQuery(); SubscribeLocalEvent(OnAfterInteract, after: new[]{ typeof(SharedEntityStorageSystem) }); SubscribeLocalEvent>(AddDumpVerb); SubscribeLocalEvent>(AddUtilityVerbs); @@ -111,7 +110,7 @@ private void AddUtilityVerbs(EntityUid uid, DumpableComponent dumpable, GetVerbs } } - private void StartDoAfter(EntityUid storageUid, EntityUid? targetUid, EntityUid userUid, DumpableComponent dumpable) + private void StartDoAfter(EntityUid storageUid, EntityUid targetUid, EntityUid userUid, DumpableComponent dumpable) { if (!TryComp(storageUid, out var storage)) return; @@ -120,7 +119,7 @@ private void StartDoAfter(EntityUid storageUid, EntityUid? targetUid, EntityUid foreach (var entity in storage.Container.ContainedEntities) { - if (!TryComp(entity, out var itemComp) || + if (!_itemQuery.TryGetComponent(entity, out var itemComp) || !_prototypeManager.TryIndex(itemComp.Size, out var itemSize)) { continue; @@ -139,33 +138,16 @@ private void StartDoAfter(EntityUid storageUid, EntityUid? targetUid, EntityUid }); } - private void OnDoAfter(EntityUid uid, DumpableComponent component, DoAfterEvent args) + private void OnDoAfter(EntityUid uid, DumpableComponent component, DumpableDoAfterEvent args) { - if (args.Handled || args.Cancelled || !TryComp(uid, out var storage)) + if (args.Handled || args.Cancelled || !TryComp(uid, out var storage) || storage.Container.ContainedEntities.Count == 0) return; - Queue dumpQueue = new(); - foreach (var entity in storage.Container.ContainedEntities) - { - dumpQueue.Enqueue(entity); - } - - if (dumpQueue.Count == 0) - return; - - foreach (var entity in dumpQueue) - { - var transform = Transform(entity); - _container.AttachParentToContainerOrGrid((entity, transform)); - _transformSystem.SetLocalPositionRotation(entity, transform.LocalPosition + _random.NextVector2Box() / 2, _random.NextAngle(), transform); - } - - if (args.Args.Target == null) - return; + var dumpQueue = new Queue(storage.Container.ContainedEntities); var dumped = false; - if (_disposalUnitSystem.HasDisposals(args.Args.Target.Value)) + if (_disposalUnitSystem.HasDisposals(args.Args.Target)) { dumped = true; @@ -174,22 +156,31 @@ private void OnDoAfter(EntityUid uid, DumpableComponent component, DoAfterEvent _disposalUnitSystem.DoInsertDisposalUnit(args.Args.Target.Value, entity, args.Args.User); } } - else if (HasComp(args.Args.Target.Value)) + else if (HasComp(args.Args.Target)) { dumped = true; - var targetPos = _xformQuery.GetComponent(args.Args.Target.Value).LocalPosition; + var targetPos = _transformSystem.GetWorldPosition(args.Args.Target.Value); + + foreach (var entity in dumpQueue) + { + _transformSystem.SetWorldPosition(entity, targetPos + _random.NextVector2Box() / 4); + } + } + else + { + var targetPos = _transformSystem.GetWorldPosition(uid); foreach (var entity in dumpQueue) { - _transformSystem.SetLocalPosition(entity, targetPos + _random.NextVector2Box() / 4); + var transform = Transform(entity); + _transformSystem.SetWorldPositionRotation(entity, targetPos + _random.NextVector2Box() / 4, _random.NextAngle(), transform); } } if (dumped) { - // TODO: Predicted when above predicted - _audio.PlayPvs(component.DumpSound, uid); + _audio.PlayPredicted(component.DumpSound, uid, args.User); } } } diff --git a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs index 11075b4a4c7..799fb7e33e9 100644 --- a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs @@ -3,6 +3,7 @@ using System.Linq; using Content.Shared.ActionBlocker; using Content.Shared.Containers.ItemSlots; +using Content.Shared.Coordinates; using Content.Shared.Destructible; using Content.Shared.DoAfter; using Content.Shared.Hands.Components; @@ -12,6 +13,7 @@ using Content.Shared.Item; using Content.Shared.Lock; using Content.Shared.Nyanotrasen.Item.PseudoItem; +using Content.Shared.Materials; using Content.Shared.Placeable; using Content.Shared.Popups; using Content.Shared.Stacks; @@ -96,6 +98,9 @@ public override void Initialize() SubscribeAllEvent(OnSetItemLocation); SubscribeAllEvent(OnInsertItemIntoLocation); SubscribeAllEvent(OnRemoveItem); + + SubscribeLocalEvent(OnReclaimed); + UpdatePrototypeCache(); } @@ -389,6 +394,11 @@ private void OnDoAfter(EntityUid uid, StorageComponent component, AreaPickupDoAf args.Handled = true; } + private void OnReclaimed(EntityUid uid, StorageComponent storageComp, GotReclaimedEvent args) + { + _containerSystem.EmptyContainer(storageComp.Container, destination: args.ReclaimerCoordinates); + } + private void OnDestroy(EntityUid uid, StorageComponent storageComp, DestructionEventArgs args) { var coordinates = TransformSystem.GetMoverCoordinates(uid); diff --git a/Content.Shared/Strip/Components/ThievingComponent.cs b/Content.Shared/Strip/Components/ThievingComponent.cs index 1d584627727..bc66c7d8328 100644 --- a/Content.Shared/Strip/Components/ThievingComponent.cs +++ b/Content.Shared/Strip/Components/ThievingComponent.cs @@ -1,9 +1,11 @@ +using Robust.Shared.GameStates; + namespace Content.Shared.Strip.Components; /// /// Give this to an entity when you want to decrease stripping times /// -[RegisterComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class ThievingComponent : Component { /// @@ -27,6 +29,6 @@ public sealed partial class ThievingComponent : Component /// /// Should the user be able to see hidden items? (i.e pockets) /// - [DataField] + [DataField, AutoNetworkedField] public bool IgnoreStripHidden; } diff --git a/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs b/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs index 02b4e617901..ba78ff651f5 100644 --- a/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs +++ b/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs @@ -15,7 +15,6 @@ namespace Content.Shared.SubFloor [UsedImplicitly] public abstract class SharedSubFloorHideSystem : EntitySystem { - [Dependency] protected readonly IMapManager MapManager = default!; [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!; [Dependency] private readonly SharedAmbientSoundSystem _ambientSoundSystem = default!; [Dependency] protected readonly SharedAppearanceSystem Appearance = default!; @@ -93,7 +92,7 @@ private void OnTileChanged(ref TileChangedEvent args) if (args.NewTile.Tile.IsEmpty) return; // Anything that was here will be unanchored anyways. - UpdateTile(MapManager.GetGrid(args.NewTile.GridUid), args.NewTile.GridIndices); + UpdateTile(Comp(args.NewTile.GridUid), args.NewTile.GridIndices); } /// @@ -104,7 +103,7 @@ private void UpdateFloorCover(EntityUid uid, SubFloorHideComponent? component = if (!Resolve(uid, ref component, ref xform)) return; - if (xform.Anchored && MapManager.TryGetGrid(xform.GridUid, out var grid)) + if (xform.Anchored && TryComp(xform.GridUid, out var grid)) component.IsUnderCover = HasFloorCover(grid, grid.TileIndicesFor(xform.Coordinates)); else component.IsUnderCover = false; diff --git a/Content.Shared/Teleportation/Systems/SharedPortalSystem.cs b/Content.Shared/Teleportation/Systems/SharedPortalSystem.cs index ebd83624114..8d67aec518a 100644 --- a/Content.Shared/Teleportation/Systems/SharedPortalSystem.cs +++ b/Content.Shared/Teleportation/Systems/SharedPortalSystem.cs @@ -1,9 +1,9 @@ using System.Linq; using Content.Shared.Ghost; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Systems; using Content.Shared.Popups; using Content.Shared.Projectiles; -using Content.Shared.Pulling; -using Content.Shared.Pulling.Components; using Content.Shared.Teleportation.Components; using Content.Shared.Verbs; using Robust.Shared.Audio; @@ -28,7 +28,7 @@ public abstract class SharedPortalSystem : EntitySystem [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; - [Dependency] private readonly SharedPullingSystem _pulling = default!; + [Dependency] private readonly PullingSystem _pulling = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; private const string PortalFixture = "portalFixture"; @@ -93,15 +93,15 @@ private void OnCollide(EntityUid uid, PortalComponent component, ref StartCollid return; // break pulls before portal enter so we dont break shit - if (TryComp(subject, out var pullable) && pullable.BeingPulled) + if (TryComp(subject, out var pullable) && pullable.BeingPulled) { - _pulling.TryStopPull(pullable); + _pulling.TryStopPull(subject, pullable); } - if (TryComp(subject, out var pulling) - && pulling.Pulling != null && TryComp(pulling.Pulling.Value, out var subjectPulling)) + if (TryComp(subject, out var pullerComp) + && TryComp(pullerComp.Pulling, out var subjectPulling)) { - _pulling.TryStopPull(subjectPulling); + _pulling.TryStopPull(subject, subjectPulling); } // if they came from another portal, just return and wait for them to exit the portal diff --git a/Content.Shared/Throwing/ThrowingSystem.cs b/Content.Shared/Throwing/ThrowingSystem.cs index 01682863389..38772eaf340 100644 --- a/Content.Shared/Throwing/ThrowingSystem.cs +++ b/Content.Shared/Throwing/ThrowingSystem.cs @@ -20,6 +20,11 @@ public sealed class ThrowingSystem : EntitySystem { public const float ThrowAngularImpulse = 5f; + /// + /// Speed cap on rotation in case of click-spam. + /// + public const float ThrowAngularCap = 3f * MathF.PI; + public const float PushbackDefault = 2f; /// @@ -42,15 +47,17 @@ public void TryThrow( float strength = 1.0f, EntityUid? user = null, float pushbackRatio = PushbackDefault, + bool recoil = true, + bool animated = true, bool playSound = true) { - var thrownPos = Transform(uid).MapPosition; - var mapPos = coordinates.ToMap(EntityManager, _transform); + var thrownPos = _transform.GetMapCoordinates(uid); + var mapPos = _transform.ToMapCoordinates(coordinates); if (mapPos.MapId != thrownPos.MapId) return; - TryThrow(uid, mapPos.Position - thrownPos.Position, strength, user, pushbackRatio, playSound); + TryThrow(uid, mapPos.Position - thrownPos.Position, strength, user, pushbackRatio, recoil: recoil, animated: animated, playSound: playSound); } /// @@ -65,6 +72,8 @@ public void TryThrow(EntityUid uid, float strength = 1.0f, EntityUid? user = null, float pushbackRatio = PushbackDefault, + bool recoil = true, + bool animated = true, bool playSound = true) { var physicsQuery = GetEntityQuery(); @@ -72,7 +81,6 @@ public void TryThrow(EntityUid uid, return; var projectileQuery = GetEntityQuery(); - var tagQuery = GetEntityQuery(); TryThrow( uid, @@ -82,8 +90,7 @@ public void TryThrow(EntityUid uid, projectileQuery, strength, user, - pushbackRatio, - playSound); + pushbackRatio, recoil: recoil, animated: animated, playSound: playSound); } /// @@ -101,6 +108,8 @@ public void TryThrow(EntityUid uid, float strength = 1.0f, EntityUid? user = null, float pushbackRatio = PushbackDefault, + bool recoil = true, + bool animated = true, bool playSound = true) { if (strength <= 0 || direction == Vector2Helpers.Infinity || direction == Vector2Helpers.NaN || direction == Vector2.Zero) @@ -116,12 +125,17 @@ public void TryThrow(EntityUid uid, if (projectileQuery.TryGetComponent(uid, out var proj) && !proj.OnlyCollideWhenShot) return; - var comp = new ThrownItemComponent(); - comp.Thrower = user; + var comp = new ThrownItemComponent + { + Thrower = user, + Animate = animated, + }; // Estimate time to arrival so we can apply OnGround status and slow it much faster. var time = direction.Length() / strength; comp.ThrownTime = _gameTiming.CurTime; + // TODO: This is a bandaid, don't do this. + // if you want to force landtime have the caller handle it or add a new method. // did we launch this with something stronger than our hands? if (TryComp(comp.Thrower, out var hands) && strength > hands.ThrowForceMultiplier) comp.LandTime = comp.ThrownTime + TimeSpan.FromSeconds(time); @@ -166,7 +180,8 @@ public void TryThrow(EntityUid uid, if (user == null) return; - _recoil.KickCamera(user.Value, -direction * 0.04f); + if (recoil) + _recoil.KickCamera(user.Value, -direction * 0.04f); // Give thrower an impulse in the other direction if (pushbackRatio != 0.0f && diff --git a/Content.Shared/Throwing/ThrownItemComponent.cs b/Content.Shared/Throwing/ThrownItemComponent.cs index 16c9b13254c..f7defaa4aab 100644 --- a/Content.Shared/Throwing/ThrownItemComponent.cs +++ b/Content.Shared/Throwing/ThrownItemComponent.cs @@ -8,6 +8,12 @@ namespace Content.Shared.Throwing [RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true), AutoGenerateComponentPause] public sealed partial class ThrownItemComponent : Component { + /// + /// Should the in-air throwing animation play. + /// + [DataField, AutoNetworkedField] + public bool Animate = true; + /// /// The entity that threw this entity. /// diff --git a/Content.Shared/Throwing/ThrownItemSystem.cs b/Content.Shared/Throwing/ThrownItemSystem.cs index cc50094e3dd..ef28db26727 100644 --- a/Content.Shared/Throwing/ThrownItemSystem.cs +++ b/Content.Shared/Throwing/ThrownItemSystem.cs @@ -3,8 +3,7 @@ using Content.Shared.Database; using Content.Shared.Gravity; using Content.Shared.Physics; -using Content.Shared.Physics.Pull; -using Robust.Shared.GameStates; +using Content.Shared.Movement.Pulling.Events; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; @@ -85,8 +84,8 @@ private void OnSleep(EntityUid uid, ThrownItemComponent thrownItem, ref PhysicsS private void HandlePullStarted(PullStartedMessage message) { // TODO: this isn't directed so things have to be done the bad way - if (EntityManager.TryGetComponent(message.Pulled.Owner, out ThrownItemComponent? thrownItemComponent)) - StopThrow(message.Pulled.Owner, thrownItemComponent); + if (EntityManager.TryGetComponent(message.PulledUid, out ThrownItemComponent? thrownItemComponent)) + StopThrow(message.PulledUid, thrownItemComponent); } public void StopThrow(EntityUid uid, ThrownItemComponent thrownItemComponent) diff --git a/Content.Shared/Tiles/FloorTileSystem.cs b/Content.Shared/Tiles/FloorTileSystem.cs index 1f8408319d3..0d368495f18 100644 --- a/Content.Shared/Tiles/FloorTileSystem.cs +++ b/Content.Shared/Tiles/FloorTileSystem.cs @@ -116,7 +116,7 @@ private void OnAfterInteract(EntityUid uid, FloorTileComponent component, AfterI } } } - _mapManager.TryGetGrid(location.EntityId, out var mapGrid); + TryComp(location.EntityId, out var mapGrid); foreach (var currentTile in component.OutputTiles) { diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Interactions.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Interactions.cs index d47d024de5e..274828a2086 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Interactions.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Interactions.cs @@ -102,7 +102,7 @@ public void CycleFire(EntityUid uid, GunComponent component, EntityUid? user = n // TODO: Actions need doing for guns anyway. private sealed partial class CycleModeEvent : InstantActionEvent { - public SelectiveFire Mode; + public SelectiveFire Mode = default; } private void OnCycleMode(EntityUid uid, GunComponent component, CycleModeEvent args) diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs index ff8b102bb57..1dfdede1afa 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs @@ -205,6 +205,14 @@ private void StopShooting(EntityUid uid, GunComponent gun) Dirty(uid, gun); } + /// + /// Sets the targeted entity of the gun. Should be called before attempting to shoot to avoid shooting over the target. + /// + public void SetTarget(GunComponent gun, EntityUid target) + { + gun.Target = target; + } + /// /// Attempts to shoot at the target coordinates. Resets the shot counter after every shot. /// diff --git a/Content.Tests/Shared/Chat/V2/Moderation/SimpleCensor.cs b/Content.Tests/Shared/Chat/V2/Moderation/SimpleCensor.cs new file mode 100644 index 00000000000..09870af317c --- /dev/null +++ b/Content.Tests/Shared/Chat/V2/Moderation/SimpleCensor.cs @@ -0,0 +1,162 @@ +using System.Text.Unicode; +using Content.Shared.Chat.V2.Moderation; +using NUnit.Framework; + +namespace Content.Tests.Shared.Chat.V2.Moderation; + +public sealed class SimpleCensorTests +{ + [Test] + public void CanCensorASingleWord() + { + var sut = new SimpleCensor().WithCustomDictionary(["amogus"]); + var output = sut.Censor("hello amogus"); + + Assert.That(output, Is.EqualTo("hello ******")); + } + + // Basics - use custom dictionary + + [Test] + public void CanCensorMultipleWordInstances() + { + var sut= new SimpleCensor().WithCustomDictionary(["amogus"]); + var output = sut.Censor("amogus hello amogus"); + + Assert.That(output, Is.EqualTo("****** hello ******")); + } + + [Test] + public void CanCensorMultipleWords() + { + var sut= new SimpleCensor().WithCustomDictionary(["amogus", "sus"]); + var output = sut.Censor("amogus hello sus"); + + Assert.That(output, Is.EqualTo("****** hello ***")); + } + + [Test] + public void CanUseDifferentCensorSymbols() + { + var sut= new SimpleCensor().WithCustomDictionary(["amogus", "sus"]); + var output = sut.Censor("amogus hello sus", '#'); + + Assert.That(output, Is.EqualTo("###### hello ###")); + } + + [Test] + public void CanCatchCapitalizedWords() + { + var sut= new SimpleCensor().WithCustomDictionary(["amogus", "sus"]); + var output = sut.Censor("AMOGUS hello SUS"); + + Assert.That(output, Is.EqualTo("****** hello ***")); + } + + [Test] + public void CanCatchWordsWithSomeCaptialsInThem() + { + var sut= new SimpleCensor().WithCustomDictionary(["amogus", "sus"]); + var output = sut.Censor("AmoGuS hello SuS"); + + Assert.That(output, Is.EqualTo("****** hello ***")); + } + + [Test] + public void CanCatchWordsHiddenInsideOtherWords() + { + var sut= new SimpleCensor().WithCustomDictionary(["amogus", "sus"]); + var output = sut.Censor("helamoguslo suspicious"); + + Assert.That(output, Is.EqualTo("hel******lo ***picious")); + } + + // Sanitizing Leetspeak + + [Test] + public void CanSanitizeLeetspeak() + { + var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithSanitizeLeetSpeak(); + var output = sut.Censor("am0gu5 hello 5u5"); + + Assert.That(output, Is.EqualTo("****** hello ***")); + } + + [Test] + public void SanitizingLeetspeakOnlyOccursWhenTheWordIsBlocked() + { + var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithSanitizeLeetSpeak(); + var output = sut.Censor("he110"); + + Assert.That(output, Is.EqualTo("he110")); + } + + [Test] + public void CanCatchLeetspeakReplacementsWithMoreThanOneLetter() + { + var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithSanitizeLeetSpeak(); + var output = sut.Censor("am()gu5 hello 5u5"); + + Assert.That(output, Is.EqualTo("******* hello ***")); + } + + // Sanitizing special characters + + [Test] + public void DoesNotSanitizeOutUncensoredSpecialCharacters() + { + var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithSanitizeSpecialCharacters(); + var output = sut.Censor("amogus!hello!sus"); + + Assert.That(output, Is.EqualTo("******!hello!***")); + } + + [Test] + public void DoesSanitizeOutCensoredSpecialCharacters() + { + var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithSanitizeSpecialCharacters(); + var output = sut.Censor("amo!gus hello s?us"); + + Assert.That(output, Is.EqualTo("***!*** hello *?**")); + } + + // Unicode ranges + + [Test] + public void SanitizesOutNonLatinCharaters() + { + var sut = new SimpleCensor().WithRanges([UnicodeRanges.BasicLatin, UnicodeRanges.Latin1Supplement]); + var output = sut.Censor("amogus Україна sus 日本"); + + Assert.That(output, Is.EqualTo("amogus sus ")); + } + + [Test] + public void SanitizesOutNonLatinOrCyrillicCharaters() + { + var sut = new SimpleCensor().WithRanges([UnicodeRanges.BasicLatin, UnicodeRanges.Latin1Supplement, UnicodeRanges.Cyrillic]); + var output = sut.Censor("amogus Україна sus 日本"); + + Assert.That(output, Is.EqualTo("amogus Україна sus ")); + } + + // False positives + [Test] + public void CanHandleFalsePositives() + { + var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithFalsePositives(["amogusus"]); + var output = sut.Censor("amogusus hello amogus hello sus"); + + Assert.That(output, Is.EqualTo("amogusus hello ****** hello ***")); + } + + // False negatives + [Test] + public void CanHandleFalseNegatives() + { + var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithFalsePositives(["amogusus"]).WithFalseNegatives(["susamogusus"]); + var output = sut.Censor("susamogusus hello amogus hello sus amogusus"); + + Assert.That(output, Is.EqualTo("*********** hello ****** hello *** ********")); + } +} diff --git a/Content.YAMLLinter/Program.cs b/Content.YAMLLinter/Program.cs index b7b70bd1188..78867fcb8ab 100644 --- a/Content.YAMLLinter/Program.cs +++ b/Content.YAMLLinter/Program.cs @@ -97,7 +97,7 @@ await instance.WaitPost(() => yamlErrors[kind] = set; } - fieldErrors = protoMan.ValidateFields(prototypes); + fieldErrors = protoMan.ValidateStaticFields(prototypes); }); return (yamlErrors, fieldErrors); diff --git a/Resources/Audio/Admin/Smites/bookify.ogg b/Resources/Audio/Admin/Smites/bookify.ogg new file mode 100644 index 00000000000..522225e3ac4 Binary files /dev/null and b/Resources/Audio/Admin/Smites/bookify.ogg differ diff --git a/Resources/Audio/Admin/Smites/manup.ogg b/Resources/Audio/Admin/Smites/manup.ogg new file mode 100644 index 00000000000..cdfa76fbf7e Binary files /dev/null and b/Resources/Audio/Admin/Smites/manup.ogg differ diff --git a/Resources/Audio/Admin/Smites/pleaseroleplay.ogg b/Resources/Audio/Admin/Smites/pleaseroleplay.ogg new file mode 100644 index 00000000000..3d2c301229e Binary files /dev/null and b/Resources/Audio/Admin/Smites/pleaseroleplay.ogg differ diff --git a/Resources/Audio/Admin/Smites/smite.ogg b/Resources/Audio/Admin/Smites/smite.ogg new file mode 100644 index 00000000000..2f62cfb3691 Binary files /dev/null and b/Resources/Audio/Admin/Smites/smite.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/announce.ogg b/Resources/Audio/Announcers/Intern/comms/announce.ogg new file mode 100644 index 00000000000..0ee0f36d56f Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/announce.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/announce/1.ogg b/Resources/Audio/Announcers/Intern/comms/announce/1.ogg new file mode 100644 index 00000000000..c4d182bc8c9 Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/announce/1.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/announce/10.ogg b/Resources/Audio/Announcers/Intern/comms/announce/10.ogg new file mode 100644 index 00000000000..7380ccdeefd Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/announce/10.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/announce/11.ogg b/Resources/Audio/Announcers/Intern/comms/announce/11.ogg new file mode 100644 index 00000000000..ca548dcc20a Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/announce/11.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/announce/12.ogg b/Resources/Audio/Announcers/Intern/comms/announce/12.ogg new file mode 100644 index 00000000000..8d71419798f Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/announce/12.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/announce/13.ogg b/Resources/Audio/Announcers/Intern/comms/announce/13.ogg new file mode 100644 index 00000000000..128c7aa424d Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/announce/13.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/announce/14.ogg b/Resources/Audio/Announcers/Intern/comms/announce/14.ogg new file mode 100644 index 00000000000..81d54101be5 Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/announce/14.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/announce/2.ogg b/Resources/Audio/Announcers/Intern/comms/announce/2.ogg new file mode 100644 index 00000000000..a2ef615d56c Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/announce/2.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/announce/3.ogg b/Resources/Audio/Announcers/Intern/comms/announce/3.ogg new file mode 100644 index 00000000000..51613ff0367 Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/announce/3.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/announce/4.ogg b/Resources/Audio/Announcers/Intern/comms/announce/4.ogg new file mode 100644 index 00000000000..874536ca72f Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/announce/4.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/announce/5.ogg b/Resources/Audio/Announcers/Intern/comms/announce/5.ogg new file mode 100644 index 00000000000..0af0d28ce18 Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/announce/5.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/announce/6.ogg b/Resources/Audio/Announcers/Intern/comms/announce/6.ogg new file mode 100644 index 00000000000..a65006a8c01 Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/announce/6.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/announce/7.ogg b/Resources/Audio/Announcers/Intern/comms/announce/7.ogg new file mode 100644 index 00000000000..4a1d3f013ae Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/announce/7.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/announce/8.ogg b/Resources/Audio/Announcers/Intern/comms/announce/8.ogg new file mode 100644 index 00000000000..83ca80f4939 Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/announce/8.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/announce/9.ogg b/Resources/Audio/Announcers/Intern/comms/announce/9.ogg new file mode 100644 index 00000000000..3c0c45b25d0 Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/announce/9.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/commandReport/1.ogg b/Resources/Audio/Announcers/Intern/comms/commandReport/1.ogg new file mode 100644 index 00000000000..e3108b13d17 Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/commandReport/1.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/commandReport/2.ogg b/Resources/Audio/Announcers/Intern/comms/commandReport/2.ogg new file mode 100644 index 00000000000..cd67500426c Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/commandReport/2.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/commandReport/3.ogg b/Resources/Audio/Announcers/Intern/comms/commandReport/3.ogg new file mode 100644 index 00000000000..94241c5ba52 Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/commandReport/3.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/welcome/1.ogg b/Resources/Audio/Announcers/Intern/comms/welcome/1.ogg new file mode 100644 index 00000000000..758f1967e09 Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/welcome/1.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/welcome/2.ogg b/Resources/Audio/Announcers/Intern/comms/welcome/2.ogg new file mode 100644 index 00000000000..c2e72be510e Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/welcome/2.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/welcome/3.ogg b/Resources/Audio/Announcers/Intern/comms/welcome/3.ogg new file mode 100644 index 00000000000..004f57371de Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/welcome/3.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/welcome/4.ogg b/Resources/Audio/Announcers/Intern/comms/welcome/4.ogg new file mode 100644 index 00000000000..c4e1f7667cd Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/welcome/4.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/welcome/5.ogg b/Resources/Audio/Announcers/Intern/comms/welcome/5.ogg new file mode 100644 index 00000000000..641b8208a4e Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/welcome/5.ogg differ diff --git a/Resources/Audio/Announcers/Intern/comms/welcome/6.ogg b/Resources/Audio/Announcers/Intern/comms/welcome/6.ogg new file mode 100644 index 00000000000..b0fc38237f8 Binary files /dev/null and b/Resources/Audio/Announcers/Intern/comms/welcome/6.ogg differ diff --git a/Resources/Audio/Announcers/Intern/events/aliens.ogg b/Resources/Audio/Announcers/Intern/events/aliens.ogg new file mode 100644 index 00000000000..9dd3c076978 Binary files /dev/null and b/Resources/Audio/Announcers/Intern/events/aliens.ogg differ diff --git a/Resources/Audio/Announcers/Intern/events/anomaly.ogg b/Resources/Audio/Announcers/Intern/events/anomaly.ogg new file mode 100644 index 00000000000..9bed8eae3aa Binary files /dev/null and b/Resources/Audio/Announcers/Intern/events/anomaly.ogg differ diff --git a/Resources/Audio/Announcers/Intern/events/ion_storm.ogg b/Resources/Audio/Announcers/Intern/events/ion_storm.ogg new file mode 100644 index 00000000000..9e7b5c6b23e Binary files /dev/null and b/Resources/Audio/Announcers/Intern/events/ion_storm.ogg differ diff --git a/Resources/Audio/Announcers/Intern/events/meteors.ogg b/Resources/Audio/Announcers/Intern/events/meteors.ogg new file mode 100644 index 00000000000..c68c4bd8cc4 Binary files /dev/null and b/Resources/Audio/Announcers/Intern/events/meteors.ogg differ diff --git a/Resources/Audio/Announcers/Intern/events/power_grid_check-complete.ogg b/Resources/Audio/Announcers/Intern/events/power_grid_check-complete.ogg new file mode 100644 index 00000000000..509cd398e6e Binary files /dev/null and b/Resources/Audio/Announcers/Intern/events/power_grid_check-complete.ogg differ diff --git a/Resources/Audio/Announcers/Intern/events/power_grid_check.ogg b/Resources/Audio/Announcers/Intern/events/power_grid_check.ogg new file mode 100644 index 00000000000..4b71053653f Binary files /dev/null and b/Resources/Audio/Announcers/Intern/events/power_grid_check.ogg differ diff --git a/Resources/Audio/Announcers/Intern/shuttle/shuttlecalled.ogg b/Resources/Audio/Announcers/Intern/shuttle/shuttlecalled.ogg new file mode 100644 index 00000000000..c903367cdff Binary files /dev/null and b/Resources/Audio/Announcers/Intern/shuttle/shuttlecalled.ogg differ diff --git a/Resources/Audio/Announcers/Intern/shuttle/shuttledock.ogg b/Resources/Audio/Announcers/Intern/shuttle/shuttledock.ogg new file mode 100644 index 00000000000..9f6ccd1a937 Binary files /dev/null and b/Resources/Audio/Announcers/Intern/shuttle/shuttledock.ogg differ diff --git a/Resources/Audio/Announcers/Intern/shuttle/shuttlerecalled.ogg b/Resources/Audio/Announcers/Intern/shuttle/shuttlerecalled.ogg new file mode 100644 index 00000000000..e259a79f35e Binary files /dev/null and b/Resources/Audio/Announcers/Intern/shuttle/shuttlerecalled.ogg differ diff --git a/Resources/Audio/Announcers/Intern/unused/animes.ogg b/Resources/Audio/Announcers/Intern/unused/animes.ogg new file mode 100644 index 00000000000..36102c3e60e Binary files /dev/null and b/Resources/Audio/Announcers/Intern/unused/animes.ogg differ diff --git a/Resources/Audio/Announcers/Intern/unused/intercept.ogg b/Resources/Audio/Announcers/Intern/unused/intercept.ogg new file mode 100644 index 00000000000..a87274abd97 Binary files /dev/null and b/Resources/Audio/Announcers/Intern/unused/intercept.ogg differ diff --git a/Resources/Audio/Announcers/Intern/unused/newai.ogg b/Resources/Audio/Announcers/Intern/unused/newai.ogg new file mode 100644 index 00000000000..c40b0990206 Binary files /dev/null and b/Resources/Audio/Announcers/Intern/unused/newai.ogg differ diff --git a/Resources/Audio/Announcers/Intern/unused/outbreak7.ogg b/Resources/Audio/Announcers/Intern/unused/outbreak7.ogg new file mode 100644 index 00000000000..297a1bbe8db Binary files /dev/null and b/Resources/Audio/Announcers/Intern/unused/outbreak7.ogg differ diff --git a/Resources/Audio/Announcers/Intern/unused/radiation.ogg b/Resources/Audio/Announcers/Intern/unused/radiation.ogg new file mode 100644 index 00000000000..08db53ebfd2 Binary files /dev/null and b/Resources/Audio/Announcers/Intern/unused/radiation.ogg differ diff --git a/Resources/Audio/Announcers/MedBot/comms/announce.ogg b/Resources/Audio/Announcers/MedBot/comms/announce.ogg new file mode 100644 index 00000000000..0ee0f36d56f Binary files /dev/null and b/Resources/Audio/Announcers/MedBot/comms/announce.ogg differ diff --git a/Resources/Audio/Announcers/MedBot/comms/attention.ogg b/Resources/Audio/Announcers/MedBot/comms/attention.ogg new file mode 100644 index 00000000000..d4d5a270852 Binary files /dev/null and b/Resources/Audio/Announcers/MedBot/comms/attention.ogg differ diff --git a/Resources/Audio/Announcers/MedBot/comms/command_report.ogg b/Resources/Audio/Announcers/MedBot/comms/command_report.ogg new file mode 100644 index 00000000000..4e5c2e1d1ff Binary files /dev/null and b/Resources/Audio/Announcers/MedBot/comms/command_report.ogg differ diff --git a/Resources/Audio/Announcers/MedBot/comms/welcome.ogg b/Resources/Audio/Announcers/MedBot/comms/welcome.ogg new file mode 100644 index 00000000000..f9a698fd080 Binary files /dev/null and b/Resources/Audio/Announcers/MedBot/comms/welcome.ogg differ diff --git a/Resources/Audio/Announcers/MedBot/events/aliens.ogg b/Resources/Audio/Announcers/MedBot/events/aliens.ogg new file mode 100644 index 00000000000..57fa70c3cae Binary files /dev/null and b/Resources/Audio/Announcers/MedBot/events/aliens.ogg differ diff --git a/Resources/Audio/Announcers/MedBot/events/anomaly.ogg b/Resources/Audio/Announcers/MedBot/events/anomaly.ogg new file mode 100644 index 00000000000..d710999e1e1 Binary files /dev/null and b/Resources/Audio/Announcers/MedBot/events/anomaly.ogg differ diff --git a/Resources/Audio/Announcers/MedBot/events/ion_storm.ogg b/Resources/Audio/Announcers/MedBot/events/ion_storm.ogg new file mode 100644 index 00000000000..15aeac9f7ff Binary files /dev/null and b/Resources/Audio/Announcers/MedBot/events/ion_storm.ogg differ diff --git a/Resources/Audio/Announcers/MedBot/events/meteors.ogg b/Resources/Audio/Announcers/MedBot/events/meteors.ogg new file mode 100644 index 00000000000..91208cae122 Binary files /dev/null and b/Resources/Audio/Announcers/MedBot/events/meteors.ogg differ diff --git a/Resources/Audio/Announcers/MedBot/events/power_grid_check-complete.ogg b/Resources/Audio/Announcers/MedBot/events/power_grid_check-complete.ogg new file mode 100644 index 00000000000..4b1605b1c74 Binary files /dev/null and b/Resources/Audio/Announcers/MedBot/events/power_grid_check-complete.ogg differ diff --git a/Resources/Audio/Announcers/MedBot/events/power_grid_check.ogg b/Resources/Audio/Announcers/MedBot/events/power_grid_check.ogg new file mode 100644 index 00000000000..875df350025 Binary files /dev/null and b/Resources/Audio/Announcers/MedBot/events/power_grid_check.ogg differ diff --git a/Resources/Audio/Announcers/MedBot/fallback.ogg b/Resources/Audio/Announcers/MedBot/fallback.ogg new file mode 100644 index 00000000000..d4d5a270852 Binary files /dev/null and b/Resources/Audio/Announcers/MedBot/fallback.ogg differ diff --git a/Resources/Audio/Announcers/MedBot/shuttle/shuttlecalled.ogg b/Resources/Audio/Announcers/MedBot/shuttle/shuttlecalled.ogg new file mode 100644 index 00000000000..a775567abed Binary files /dev/null and b/Resources/Audio/Announcers/MedBot/shuttle/shuttlecalled.ogg differ diff --git a/Resources/Audio/Announcers/MedBot/shuttle/shuttledock.ogg b/Resources/Audio/Announcers/MedBot/shuttle/shuttledock.ogg new file mode 100644 index 00000000000..933928db067 Binary files /dev/null and b/Resources/Audio/Announcers/MedBot/shuttle/shuttledock.ogg differ diff --git a/Resources/Audio/Announcers/MedBot/shuttle/shuttlerecalled.ogg b/Resources/Audio/Announcers/MedBot/shuttle/shuttlerecalled.ogg new file mode 100644 index 00000000000..53b622576d4 Binary files /dev/null and b/Resources/Audio/Announcers/MedBot/shuttle/shuttlerecalled.ogg differ diff --git a/Resources/Audio/Announcers/MedBot/unused/animes.ogg b/Resources/Audio/Announcers/MedBot/unused/animes.ogg new file mode 100644 index 00000000000..7615a744a66 Binary files /dev/null and b/Resources/Audio/Announcers/MedBot/unused/animes.ogg differ diff --git a/Resources/Audio/Announcers/MedBot/unused/intercept.ogg b/Resources/Audio/Announcers/MedBot/unused/intercept.ogg new file mode 100644 index 00000000000..c59d0455c1c Binary files /dev/null and b/Resources/Audio/Announcers/MedBot/unused/intercept.ogg differ diff --git a/Resources/Audio/Announcers/MedBot/unused/newai.ogg b/Resources/Audio/Announcers/MedBot/unused/newai.ogg new file mode 100644 index 00000000000..c40b0990206 Binary files /dev/null and b/Resources/Audio/Announcers/MedBot/unused/newai.ogg differ diff --git a/Resources/Audio/Announcers/MedBot/unused/outbreak7.ogg b/Resources/Audio/Announcers/MedBot/unused/outbreak7.ogg new file mode 100644 index 00000000000..1fc542534db Binary files /dev/null and b/Resources/Audio/Announcers/MedBot/unused/outbreak7.ogg differ diff --git a/Resources/Audio/Announcers/MedBot/unused/radiation.ogg b/Resources/Audio/Announcers/MedBot/unused/radiation.ogg new file mode 100644 index 00000000000..5c48830b5f2 Binary files /dev/null and b/Resources/Audio/Announcers/MedBot/unused/radiation.ogg differ diff --git a/Resources/Audio/Announcers/Michael/alerts/blue.ogg b/Resources/Audio/Announcers/Michael/alerts/blue.ogg new file mode 100644 index 00000000000..f6458c00bb3 Binary files /dev/null and b/Resources/Audio/Announcers/Michael/alerts/blue.ogg differ diff --git a/Resources/Audio/Announcers/Michael/alerts/delta.ogg b/Resources/Audio/Announcers/Michael/alerts/delta.ogg new file mode 100644 index 00000000000..95bea66f77a Binary files /dev/null and b/Resources/Audio/Announcers/Michael/alerts/delta.ogg differ diff --git a/Resources/Audio/Announcers/Michael/alerts/epsilon.ogg b/Resources/Audio/Announcers/Michael/alerts/epsilon.ogg new file mode 100644 index 00000000000..82815eda27d Binary files /dev/null and b/Resources/Audio/Announcers/Michael/alerts/epsilon.ogg differ diff --git a/Resources/Audio/Announcers/Michael/alerts/gamma.ogg b/Resources/Audio/Announcers/Michael/alerts/gamma.ogg new file mode 100644 index 00000000000..0a402b6d331 Binary files /dev/null and b/Resources/Audio/Announcers/Michael/alerts/gamma.ogg differ diff --git a/Resources/Audio/Announcers/Michael/alerts/green.ogg b/Resources/Audio/Announcers/Michael/alerts/green.ogg new file mode 100644 index 00000000000..d9d0f036fd4 Binary files /dev/null and b/Resources/Audio/Announcers/Michael/alerts/green.ogg differ diff --git a/Resources/Audio/Announcers/Michael/alerts/red.ogg b/Resources/Audio/Announcers/Michael/alerts/red.ogg new file mode 100644 index 00000000000..4a7f1e9472a Binary files /dev/null and b/Resources/Audio/Announcers/Michael/alerts/red.ogg differ diff --git a/Resources/Audio/Announcers/Michael/alerts/rename.js b/Resources/Audio/Announcers/Michael/alerts/rename.js new file mode 100644 index 00000000000..0c52f5fb327 --- /dev/null +++ b/Resources/Audio/Announcers/Michael/alerts/rename.js @@ -0,0 +1,191 @@ +// Set the method variable to one of these +const methods = [ + 'startsWith', // Replaces beginning with replace if matches searchfor OR cuts off the beginning if matches searchfor if replace is undefined + 'endsWith', // Replaces end with replace if matches searchfor OR cuts off the end if matches searchfor if replace is undefined + 'includes', // Replaces all instances of searchfor with replace OR removes all instances of searchfor if replace is undefined + + 'numberedSuffix', // Adds a numbered suffix to the end of the file name + 'numberedPrefix', // Adds a numbered prefix to the beginning of the file name + 'numbered', // Replaces the file name with a number +]; + +// User set variables +const dirname = './'; // Where to look for files ('./' is the current directory) +const includedirs = false; // Whether or not to include directories in the search +const searchfor = 'code_'; // What to search for +const replace = undefined; // What to replace with (undefined will remove the searchfor from the file name entirely) +const removeextraperiods = true; // Whether or not to remove extra periods in the file name (good for numbered methods) +const method = 'startsWith'; // Which method to use (see above) +const startingnumber = 0; // What number to start at (only used with numbered methods) +const debuglog = true; // Provides some extra info about what's going on +// End of user set variables + + +// Check if method is valid +if (typeof method !== 'string' || !methods.includes(method)) return console.log(`ERROR: Invalid method ${method}`); +else console.log('INFO: Using method: ' + method); + +// Check if dirname is valid +if (typeof dirname !== 'string') return console.log('ERROR: Invalid dirname'); +else console.log('INFO: Using directory: ' + dirname); + +// Warn of includedirs +if (includedirs) console.log('WARNING: Including directories in search'); +else console.log('INFO: Not including directories in search'); + +// Check if searchfor is valid +if (typeof searchfor !== 'string' && !method.includes('numbered')) return console.log('ERROR: Invalid searchfor'); +if (typeof searchfor !== 'string' && method.includes('numbered')) console.log('WARNING: Searchfor is undefined, this will replace the file name with a number'); +else console.log(`INFO: Searching for: ${searchfor}`); + +// Warn if replace is undefined +if (replace === undefined) console.log('WARNING: Replace is undefined, this will remove the searchfor from the file name entirely'); +else console.log(`INFO: Replacing with: ${replace}`); + +// Tell user if startingnumber is not 0 +if (startingnumber !== 0) console.log(`INFO: Starting number: ${startingnumber}`); + +// Check if debuglog is enabled +if (debuglog) console.log('INFO: Debug log is enabled'); +else console.log('INFO: Debug log is disabled'); + + +console.log('\n'); +console.log('INFO: Starting search...'); +console.log('\n'); + + +const fs = require('fs'); +const files = fs.readdirSync(dirname); +let number = 0 + startingnumber; + + +// Debug log +if (debuglog) { + console.log('DEBUG: Files:'); + console.log(files); + console.log(`DEBUG: Files type: ${typeof files}`); + console.log('\n'); +} + + +files.forEach((file) => { + // Split file name and extension + // If there is no extension, name[1] will be a blank string to avoid files getting fucked up + let name = file.includes('.') ? file.split('.') : [file, '']; + name.reverse(); + if (name[0].length > 0) name[0] = '.' + name[0]; + var extension = name[0]; + name.reverse(); + if (removeextraperiods) name = [name.join('').slice(0, -extension.length), extension]; + else name = [name.join('.').slice(0, -extension.length), extension]; + + + // Check if file is this script + if (process.argv[1].includes(name.join(''))) return; + + + // Debug log + if (debuglog) console.log(`DEBUG: File name: ${name[0]}`); + + + // Check if file is a directory + if (!includedirs) { + try { + if (fs.readdirSync(dirname + file).length) { + if (debuglog) console.log(`DEBUG: File is a directory, skipping: ${name[0]}`); + if (debuglog) console.log('\n'); + return; + } + } catch (e) { + if (debuglog) console.log(`DEBUG: File is a file: ${name[0]}`); + } + } else { + try { + if (fs.readdirSync(dirname + file).length) { + if (debuglog) console.log(`DEBUG: File is a directory: ${name[0]}`); + } + } catch (e) { + if (debuglog) console.log(`DEBUG: File is a file: ${name[0]}`); + } + } + + + if (method === 'startsWith') { + if (!name[0].startsWith(searchfor)) { + if (debuglog) console.log(`DEBUG: File name does not start with '${searchfor}': ${name[0]}`); + if (debuglog) console.log('\n'); + return; + } + + if (replace) { + fs.renameSync(dirname + '/' + file, dirname + '/' + replace + name[0].slice(searchfor.length) + name[1]); + } else { + fs.renameSync(dirname + '/' + file, dirname + '/' + name[0].slice(searchfor.length) + name[1]); + } + } else if (method === 'endsWith') { + if (!name[0].endsWith(searchfor)) { + if (debuglog) console.log(`DEBUG: File name does not end with '${searchfor}': ${name[0]}`); + if (debuglog) console.log('\n'); + return; + } + + if (replace) { + fs.renameSync(dirname + '/' + file, dirname + '/' + name[0].slice(0, -searchfor.length) + replace + name[1]); + } else { + fs.renameSync(dirname + '/' + file, dirname + '/' + name[0].slice(0, -searchfor.length) + name[1]); + } + } else if (method === 'includes') { + if (!name[0].includes(searchfor)) { + if (debuglog) console.log(`DEBUG: File name does not include '${searchfor}': ${name[0]}`); + if (debuglog) console.log('\n'); + return; + } + + const regex = new RegExp(searchfor, 'g'); + + if (replace) { + fs.renameSync(dirname + '/' + file, dirname + '/' + name[0].replace(regex, replace) + name[1]); + } else { + fs.renameSync(dirname + '/' + file, dirname + '/' + name[0].replace(regex, '') + name[1]); + } + } else if (method === 'numberedPrefix') { + if (!name[0].startsWith(searchfor)) { + if (debuglog) console.log(`DEBUG: File name does not start with '${searchfor}': ${name[0]}`); + if (debuglog) console.log('\n'); + return; + } + + fs.renameSync(dirname + '/' + file, dirname + '/' + number + name[0] + name[1]); + + number++; + } else if (method === 'numberedSuffix') { + if (!name[0].endsWith(searchfor)) { + if (debuglog) console.log(`DEBUG: File name does not end with '${searchfor}': ${name[0]}`); + if (debuglog) console.log('\n'); + return; + } + + fs.renameSync(dirname + '/' + file, dirname + '/' + name[0] + number + name[1]); + + number++; + } else if (method === 'numbered') { + if (typeof searchfor === 'string') { + if (!name[0].includes(searchfor)) { + if (debuglog) console.log(`DEBUG: File name does not include '${searchfor}': ${name[0]}`); + if (debuglog) console.log('\n'); + return; + } + + fs.renameSync(dirname + '/' + file, dirname + '/' + number + name[1]); + } else { + fs.renameSync(dirname + '/' + file, dirname + '/' + number + name[1]); + } + + number++; + } + + console.log('\n'); +}); + +console.log('INFO: Search complete'); diff --git a/Resources/Audio/Announcers/Michael/alerts/violet.ogg b/Resources/Audio/Announcers/Michael/alerts/violet.ogg new file mode 100644 index 00000000000..7a611d819eb Binary files /dev/null and b/Resources/Audio/Announcers/Michael/alerts/violet.ogg differ diff --git a/Resources/Audio/Announcers/Michael/alerts/white.ogg b/Resources/Audio/Announcers/Michael/alerts/white.ogg new file mode 100644 index 00000000000..1bb3afd354c Binary files /dev/null and b/Resources/Audio/Announcers/Michael/alerts/white.ogg differ diff --git a/Resources/Audio/Announcers/Michael/alerts/yellow.ogg b/Resources/Audio/Announcers/Michael/alerts/yellow.ogg new file mode 100644 index 00000000000..3a72eca3bbc Binary files /dev/null and b/Resources/Audio/Announcers/Michael/alerts/yellow.ogg differ diff --git a/Resources/Audio/Announcers/Michael/comms/attention.ogg b/Resources/Audio/Announcers/Michael/comms/attention.ogg new file mode 100644 index 00000000000..e25fdf2af7e Binary files /dev/null and b/Resources/Audio/Announcers/Michael/comms/attention.ogg differ diff --git a/Resources/Audio/Announcers/Michael/comms/welcome.ogg b/Resources/Audio/Announcers/Michael/comms/welcome.ogg new file mode 100644 index 00000000000..32d90041090 Binary files /dev/null and b/Resources/Audio/Announcers/Michael/comms/welcome.ogg differ diff --git a/Resources/Audio/Announcers/Michael/events/aliens.ogg b/Resources/Audio/Announcers/Michael/events/aliens.ogg new file mode 100644 index 00000000000..1293b3ced5b Binary files /dev/null and b/Resources/Audio/Announcers/Michael/events/aliens.ogg differ diff --git a/Resources/Audio/Announcers/Michael/events/bureaucratic_error.ogg b/Resources/Audio/Announcers/Michael/events/bureaucratic_error.ogg new file mode 100644 index 00000000000..2bb2710acf0 Binary files /dev/null and b/Resources/Audio/Announcers/Michael/events/bureaucratic_error.ogg differ diff --git a/Resources/Audio/Announcers/Michael/events/gas_leak.ogg b/Resources/Audio/Announcers/Michael/events/gas_leak.ogg new file mode 100644 index 00000000000..26912c859d1 Binary files /dev/null and b/Resources/Audio/Announcers/Michael/events/gas_leak.ogg differ diff --git a/Resources/Audio/Announcers/Michael/events/kudzu_growth.ogg b/Resources/Audio/Announcers/Michael/events/kudzu_growth.ogg new file mode 100644 index 00000000000..31eccef518b Binary files /dev/null and b/Resources/Audio/Announcers/Michael/events/kudzu_growth.ogg differ diff --git a/Resources/Audio/Announcers/Michael/events/meteors.ogg b/Resources/Audio/Announcers/Michael/events/meteors.ogg new file mode 100644 index 00000000000..62a21625712 Binary files /dev/null and b/Resources/Audio/Announcers/Michael/events/meteors.ogg differ diff --git a/Resources/Audio/Announcers/Michael/events/noospheric_storm.ogg b/Resources/Audio/Announcers/Michael/events/noospheric_storm.ogg new file mode 100644 index 00000000000..eedaaf5699b Binary files /dev/null and b/Resources/Audio/Announcers/Michael/events/noospheric_storm.ogg differ diff --git a/Resources/Audio/Announcers/Michael/events/power_grid_check-complete.ogg b/Resources/Audio/Announcers/Michael/events/power_grid_check-complete.ogg new file mode 100644 index 00000000000..de5fa1ff401 Binary files /dev/null and b/Resources/Audio/Announcers/Michael/events/power_grid_check-complete.ogg differ diff --git a/Resources/Audio/Announcers/Michael/events/power_grid_check.ogg b/Resources/Audio/Announcers/Michael/events/power_grid_check.ogg new file mode 100644 index 00000000000..07964d240e7 Binary files /dev/null and b/Resources/Audio/Announcers/Michael/events/power_grid_check.ogg differ diff --git a/Resources/Audio/Announcers/Michael/events/vent_clog.ogg b/Resources/Audio/Announcers/Michael/events/vent_clog.ogg new file mode 100644 index 00000000000..16fbf88e03f Binary files /dev/null and b/Resources/Audio/Announcers/Michael/events/vent_clog.ogg differ diff --git a/Resources/Audio/Announcers/Michael/fallback.ogg b/Resources/Audio/Announcers/Michael/fallback.ogg new file mode 100644 index 00000000000..e25fdf2af7e Binary files /dev/null and b/Resources/Audio/Announcers/Michael/fallback.ogg differ diff --git a/Resources/Audio/Announcers/Michael/shuttle/called.ogg b/Resources/Audio/Announcers/Michael/shuttle/called.ogg new file mode 100644 index 00000000000..261ecabf6e5 Binary files /dev/null and b/Resources/Audio/Announcers/Michael/shuttle/called.ogg differ diff --git a/Resources/Audio/Announcers/Michael/shuttle/dock.ogg b/Resources/Audio/Announcers/Michael/shuttle/dock.ogg new file mode 100644 index 00000000000..a83b482f49a Binary files /dev/null and b/Resources/Audio/Announcers/Michael/shuttle/dock.ogg differ diff --git a/Resources/Audio/Announcers/Michael/shuttle/recalled.ogg b/Resources/Audio/Announcers/Michael/shuttle/recalled.ogg new file mode 100644 index 00000000000..b104ea561a8 Binary files /dev/null and b/Resources/Audio/Announcers/Michael/shuttle/recalled.ogg differ diff --git a/Resources/Audio/Announcers/Michael/unused/outbreak7.ogg b/Resources/Audio/Announcers/Michael/unused/outbreak7.ogg new file mode 100644 index 00000000000..fc584db60c4 Binary files /dev/null and b/Resources/Audio/Announcers/Michael/unused/outbreak7.ogg differ diff --git a/Resources/Audio/Announcers/Michael/unused/radiation.ogg b/Resources/Audio/Announcers/Michael/unused/radiation.ogg new file mode 100644 index 00000000000..7b7ca0c2b9e Binary files /dev/null and b/Resources/Audio/Announcers/Michael/unused/radiation.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/alerts/code_blue.ogg b/Resources/Audio/Announcers/NEIL/alerts/code_blue.ogg new file mode 100644 index 00000000000..48d9c6548b6 Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/alerts/code_blue.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/alerts/code_delta.ogg b/Resources/Audio/Announcers/NEIL/alerts/code_delta.ogg new file mode 100644 index 00000000000..70826719156 Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/alerts/code_delta.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/alerts/code_epsilon.ogg b/Resources/Audio/Announcers/NEIL/alerts/code_epsilon.ogg new file mode 100644 index 00000000000..a8db858b1af Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/alerts/code_epsilon.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/alerts/code_gamma.ogg b/Resources/Audio/Announcers/NEIL/alerts/code_gamma.ogg new file mode 100644 index 00000000000..3351acc2e0d Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/alerts/code_gamma.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/alerts/code_green.ogg b/Resources/Audio/Announcers/NEIL/alerts/code_green.ogg new file mode 100644 index 00000000000..3c0031833be Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/alerts/code_green.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/alerts/code_red.ogg b/Resources/Audio/Announcers/NEIL/alerts/code_red.ogg new file mode 100644 index 00000000000..209eb36ba11 Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/alerts/code_red.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/alerts/code_violet.ogg b/Resources/Audio/Announcers/NEIL/alerts/code_violet.ogg new file mode 100644 index 00000000000..c1681c1edb8 Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/alerts/code_violet.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/alerts/code_white.ogg b/Resources/Audio/Announcers/NEIL/alerts/code_white.ogg new file mode 100644 index 00000000000..24c942dfcb2 Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/alerts/code_white.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/alerts/code_yellow.ogg b/Resources/Audio/Announcers/NEIL/alerts/code_yellow.ogg new file mode 100644 index 00000000000..9139446d2b6 Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/alerts/code_yellow.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/comms/announce.ogg b/Resources/Audio/Announcers/NEIL/comms/announce.ogg new file mode 100644 index 00000000000..0ee0f36d56f Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/comms/announce.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/comms/attention.ogg b/Resources/Audio/Announcers/NEIL/comms/attention.ogg new file mode 100644 index 00000000000..310fad3ef63 Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/comms/attention.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/comms/welcome.ogg b/Resources/Audio/Announcers/NEIL/comms/welcome.ogg new file mode 100644 index 00000000000..00c8991276c Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/comms/welcome.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/events/bureaucratic_error.ogg b/Resources/Audio/Announcers/NEIL/events/bureaucratic_error.ogg new file mode 100644 index 00000000000..0cbafcf6276 Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/events/bureaucratic_error.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/events/gas_leak.ogg b/Resources/Audio/Announcers/NEIL/events/gas_leak.ogg new file mode 100644 index 00000000000..8efffd02c45 Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/events/gas_leak.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/events/kudzu.ogg b/Resources/Audio/Announcers/NEIL/events/kudzu.ogg new file mode 100644 index 00000000000..4ddd2f636bc Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/events/kudzu.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/events/meteors.ogg b/Resources/Audio/Announcers/NEIL/events/meteors.ogg new file mode 100644 index 00000000000..cf525441745 Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/events/meteors.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/events/noospheric_storm.ogg b/Resources/Audio/Announcers/NEIL/events/noospheric_storm.ogg new file mode 100644 index 00000000000..47b52f7cb47 Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/events/noospheric_storm.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/events/power_grid_check-complete.ogg b/Resources/Audio/Announcers/NEIL/events/power_grid_check-complete.ogg new file mode 100644 index 00000000000..961b50a5031 Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/events/power_grid_check-complete.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/events/power_grid_check.ogg b/Resources/Audio/Announcers/NEIL/events/power_grid_check.ogg new file mode 100644 index 00000000000..7d7a43825fe Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/events/power_grid_check.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/events/vent_clog.ogg b/Resources/Audio/Announcers/NEIL/events/vent_clog.ogg new file mode 100644 index 00000000000..90350f0e359 Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/events/vent_clog.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/fallback.ogg b/Resources/Audio/Announcers/NEIL/fallback.ogg new file mode 100644 index 00000000000..310fad3ef63 Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/fallback.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/shuttle/shuttlecalled.ogg b/Resources/Audio/Announcers/NEIL/shuttle/shuttlecalled.ogg new file mode 100644 index 00000000000..482bf133193 Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/shuttle/shuttlecalled.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/shuttle/shuttledock.ogg b/Resources/Audio/Announcers/NEIL/shuttle/shuttledock.ogg new file mode 100644 index 00000000000..0615536555b Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/shuttle/shuttledock.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/shuttle/shuttlerecalled.ogg b/Resources/Audio/Announcers/NEIL/shuttle/shuttlerecalled.ogg new file mode 100644 index 00000000000..5a198ca5fe4 Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/shuttle/shuttlerecalled.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/unused/outbreak7.ogg b/Resources/Audio/Announcers/NEIL/unused/outbreak7.ogg new file mode 100644 index 00000000000..91067960125 Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/unused/outbreak7.ogg differ diff --git a/Resources/Audio/Announcers/NEIL/unused/radiation.ogg b/Resources/Audio/Announcers/NEIL/unused/radiation.ogg new file mode 100644 index 00000000000..3ea2928c1d9 Binary files /dev/null and b/Resources/Audio/Announcers/NEIL/unused/radiation.ogg differ diff --git a/Resources/Audio/Announcers/VoxFem/comms/announce.ogg b/Resources/Audio/Announcers/VoxFem/comms/announce.ogg new file mode 100644 index 00000000000..0ee0f36d56f Binary files /dev/null and b/Resources/Audio/Announcers/VoxFem/comms/announce.ogg differ diff --git a/Resources/Audio/Announcers/VoxFem/comms/attention.ogg b/Resources/Audio/Announcers/VoxFem/comms/attention.ogg new file mode 100644 index 00000000000..912be4425eb Binary files /dev/null and b/Resources/Audio/Announcers/VoxFem/comms/attention.ogg differ diff --git a/Resources/Audio/Announcers/VoxFem/comms/command_report.ogg b/Resources/Audio/Announcers/VoxFem/comms/command_report.ogg new file mode 100644 index 00000000000..82e4ca425de Binary files /dev/null and b/Resources/Audio/Announcers/VoxFem/comms/command_report.ogg differ diff --git a/Resources/Audio/Announcers/VoxFem/comms/welcome.ogg b/Resources/Audio/Announcers/VoxFem/comms/welcome.ogg new file mode 100644 index 00000000000..c7013dcbd5f Binary files /dev/null and b/Resources/Audio/Announcers/VoxFem/comms/welcome.ogg differ diff --git a/Resources/Audio/Announcers/VoxFem/events/aliens.ogg b/Resources/Audio/Announcers/VoxFem/events/aliens.ogg new file mode 100644 index 00000000000..f7d1746247f Binary files /dev/null and b/Resources/Audio/Announcers/VoxFem/events/aliens.ogg differ diff --git a/Resources/Audio/Announcers/VoxFem/events/anomaly.ogg b/Resources/Audio/Announcers/VoxFem/events/anomaly.ogg new file mode 100644 index 00000000000..7680726f153 Binary files /dev/null and b/Resources/Audio/Announcers/VoxFem/events/anomaly.ogg differ diff --git a/Resources/Audio/Announcers/VoxFem/events/ion_storm.ogg b/Resources/Audio/Announcers/VoxFem/events/ion_storm.ogg new file mode 100644 index 00000000000..9f39713de6e Binary files /dev/null and b/Resources/Audio/Announcers/VoxFem/events/ion_storm.ogg differ diff --git a/Resources/Audio/Announcers/VoxFem/events/meteors.ogg b/Resources/Audio/Announcers/VoxFem/events/meteors.ogg new file mode 100644 index 00000000000..8f1c3aeacbb Binary files /dev/null and b/Resources/Audio/Announcers/VoxFem/events/meteors.ogg differ diff --git a/Resources/Audio/Announcers/VoxFem/events/power_grid_check-complete.ogg b/Resources/Audio/Announcers/VoxFem/events/power_grid_check-complete.ogg new file mode 100644 index 00000000000..9d18797d6ea Binary files /dev/null and b/Resources/Audio/Announcers/VoxFem/events/power_grid_check-complete.ogg differ diff --git a/Resources/Audio/Announcers/VoxFem/events/power_grid_check.ogg b/Resources/Audio/Announcers/VoxFem/events/power_grid_check.ogg new file mode 100644 index 00000000000..1c6377c9d8d Binary files /dev/null and b/Resources/Audio/Announcers/VoxFem/events/power_grid_check.ogg differ diff --git a/Resources/Audio/Announcers/VoxFem/fallback.ogg b/Resources/Audio/Announcers/VoxFem/fallback.ogg new file mode 100644 index 00000000000..912be4425eb Binary files /dev/null and b/Resources/Audio/Announcers/VoxFem/fallback.ogg differ diff --git a/Resources/Audio/Announcers/VoxFem/shuttle/shuttlecalled.ogg b/Resources/Audio/Announcers/VoxFem/shuttle/shuttlecalled.ogg new file mode 100644 index 00000000000..716bf824654 Binary files /dev/null and b/Resources/Audio/Announcers/VoxFem/shuttle/shuttlecalled.ogg differ diff --git a/Resources/Audio/Announcers/VoxFem/shuttle/shuttledock.ogg b/Resources/Audio/Announcers/VoxFem/shuttle/shuttledock.ogg new file mode 100644 index 00000000000..0f70bebc751 Binary files /dev/null and b/Resources/Audio/Announcers/VoxFem/shuttle/shuttledock.ogg differ diff --git a/Resources/Audio/Announcers/VoxFem/shuttle/shuttlerecalled.ogg b/Resources/Audio/Announcers/VoxFem/shuttle/shuttlerecalled.ogg new file mode 100644 index 00000000000..5f6db404b87 Binary files /dev/null and b/Resources/Audio/Announcers/VoxFem/shuttle/shuttlerecalled.ogg differ diff --git a/Resources/Audio/Announcers/VoxFem/unused/newai.ogg b/Resources/Audio/Announcers/VoxFem/unused/newai.ogg new file mode 100644 index 00000000000..35aba34564f Binary files /dev/null and b/Resources/Audio/Announcers/VoxFem/unused/newai.ogg differ diff --git a/Resources/Audio/Announcers/VoxFem/unused/outbreak7.ogg b/Resources/Audio/Announcers/VoxFem/unused/outbreak7.ogg new file mode 100644 index 00000000000..f21d4fca443 Binary files /dev/null and b/Resources/Audio/Announcers/VoxFem/unused/outbreak7.ogg differ diff --git a/Resources/Audio/Announcers/VoxFem/unused/radiation.ogg b/Resources/Audio/Announcers/VoxFem/unused/radiation.ogg new file mode 100644 index 00000000000..ef395af3101 Binary files /dev/null and b/Resources/Audio/Announcers/VoxFem/unused/radiation.ogg differ diff --git a/Resources/Audio/Effects/Shadowkin/Powers/darkswapoff.ogg b/Resources/Audio/Effects/Shadowkin/Powers/darkswapoff.ogg new file mode 100644 index 00000000000..61f331a68a1 Binary files /dev/null and b/Resources/Audio/Effects/Shadowkin/Powers/darkswapoff.ogg differ diff --git a/Resources/Audio/Effects/Shadowkin/Powers/darkswapon.ogg b/Resources/Audio/Effects/Shadowkin/Powers/darkswapon.ogg new file mode 100644 index 00000000000..deb6139934e Binary files /dev/null and b/Resources/Audio/Effects/Shadowkin/Powers/darkswapon.ogg differ diff --git a/Resources/Audio/Effects/Shadowkin/Powers/futuristic-teleport.ogg b/Resources/Audio/Effects/Shadowkin/Powers/futuristic-teleport.ogg new file mode 100644 index 00000000000..87aeb33fdd9 Binary files /dev/null and b/Resources/Audio/Effects/Shadowkin/Powers/futuristic-teleport.ogg differ diff --git a/Resources/Audio/Effects/Shadowkin/Powers/license.txt b/Resources/Audio/Effects/Shadowkin/Powers/license.txt new file mode 100644 index 00000000000..c77ea8eb098 --- /dev/null +++ b/Resources/Audio/Effects/Shadowkin/Powers/license.txt @@ -0,0 +1,4 @@ +darkswapon.ogg licensed under Pixabay Licence taken from https://pixabay.com/users/cristian_changing-30278997/ +darkswapoff.ogg licensed under Pixabay Licence taken from https://pixabay.com/users/cristian_changing-30278997/ +futuristic-teleport.ogg licensed under Pixabay Licence taken from https://pixabay.com/users/cristian_changing-30278997/ +teleport.ogg licensed under Pixabay Licence taken from https://pixabay.com/users/cristian_changing-30278997/ diff --git a/Resources/Audio/Effects/Shadowkin/Powers/teleport.ogg b/Resources/Audio/Effects/Shadowkin/Powers/teleport.ogg new file mode 100644 index 00000000000..3cca66b47cb Binary files /dev/null and b/Resources/Audio/Effects/Shadowkin/Powers/teleport.ogg differ diff --git a/Resources/Audio/Effects/closet_close.ogg b/Resources/Audio/Effects/closet_close.ogg new file mode 100644 index 00000000000..124f5d85f5e Binary files /dev/null and b/Resources/Audio/Effects/closet_close.ogg differ diff --git a/Resources/Audio/Effects/closet_open.ogg b/Resources/Audio/Effects/closet_open.ogg new file mode 100644 index 00000000000..86cbcea0d01 Binary files /dev/null and b/Resources/Audio/Effects/closet_open.ogg differ diff --git a/Resources/Audio/Effects/phasein.ogg b/Resources/Audio/Effects/phasein.ogg new file mode 100644 index 00000000000..8b74a7d42fd Binary files /dev/null and b/Resources/Audio/Effects/phasein.ogg differ diff --git a/Resources/Audio/Effects/podwoosh.ogg b/Resources/Audio/Effects/podwoosh.ogg new file mode 100644 index 00000000000..e6fd58c7fc2 Binary files /dev/null and b/Resources/Audio/Effects/podwoosh.ogg differ diff --git a/Resources/Audio/Effects/toggleoffcombat.ogg b/Resources/Audio/Effects/toggleoffcombat.ogg new file mode 100644 index 00000000000..98df1726e98 Binary files /dev/null and b/Resources/Audio/Effects/toggleoffcombat.ogg differ diff --git a/Resources/Audio/Effects/toggleoncombat.ogg b/Resources/Audio/Effects/toggleoncombat.ogg new file mode 100644 index 00000000000..7336b9cf0e1 Binary files /dev/null and b/Resources/Audio/Effects/toggleoncombat.ogg differ diff --git a/Resources/Audio/Items/Equip/toolbelt_equip.ogg b/Resources/Audio/Items/Equip/toolbelt_equip.ogg new file mode 100644 index 00000000000..0ef67a3fd6c Binary files /dev/null and b/Resources/Audio/Items/Equip/toolbelt_equip.ogg differ diff --git a/Resources/Audio/Items/Handling/ammobox_drop.ogg b/Resources/Audio/Items/Handling/ammobox_drop.ogg new file mode 100644 index 00000000000..13fce70fe3d Binary files /dev/null and b/Resources/Audio/Items/Handling/ammobox_drop.ogg differ diff --git a/Resources/Audio/Items/Handling/ammobox_pickup.ogg b/Resources/Audio/Items/Handling/ammobox_pickup.ogg new file mode 100644 index 00000000000..9532a7697b9 Binary files /dev/null and b/Resources/Audio/Items/Handling/ammobox_pickup.ogg differ diff --git a/Resources/Audio/Items/Handling/book_drop.ogg b/Resources/Audio/Items/Handling/book_drop.ogg new file mode 100644 index 00000000000..b492b665f59 Binary files /dev/null and b/Resources/Audio/Items/Handling/book_drop.ogg differ diff --git a/Resources/Audio/Items/Handling/book_pickup.ogg b/Resources/Audio/Items/Handling/book_pickup.ogg new file mode 100644 index 00000000000..120a4e4721a Binary files /dev/null and b/Resources/Audio/Items/Handling/book_pickup.ogg differ diff --git a/Resources/Audio/Items/Handling/cardboardbox_drop.ogg b/Resources/Audio/Items/Handling/cardboardbox_drop.ogg new file mode 100644 index 00000000000..7070ba1c342 Binary files /dev/null and b/Resources/Audio/Items/Handling/cardboardbox_drop.ogg differ diff --git a/Resources/Audio/Items/Handling/cardboardbox_pickup.ogg b/Resources/Audio/Items/Handling/cardboardbox_pickup.ogg new file mode 100644 index 00000000000..aa4e72129b0 Binary files /dev/null and b/Resources/Audio/Items/Handling/cardboardbox_pickup.ogg differ diff --git a/Resources/Audio/Items/Handling/cloth_drop.ogg b/Resources/Audio/Items/Handling/cloth_drop.ogg new file mode 100644 index 00000000000..5bf734caba0 Binary files /dev/null and b/Resources/Audio/Items/Handling/cloth_drop.ogg differ diff --git a/Resources/Audio/Items/Handling/cloth_pickup.ogg b/Resources/Audio/Items/Handling/cloth_pickup.ogg new file mode 100644 index 00000000000..f46988887d1 Binary files /dev/null and b/Resources/Audio/Items/Handling/cloth_pickup.ogg differ diff --git a/Resources/Audio/Items/Handling/component_drop.ogg b/Resources/Audio/Items/Handling/component_drop.ogg new file mode 100644 index 00000000000..95ba2591a31 Binary files /dev/null and b/Resources/Audio/Items/Handling/component_drop.ogg differ diff --git a/Resources/Audio/Items/Handling/component_pickup.ogg b/Resources/Audio/Items/Handling/component_pickup.ogg new file mode 100644 index 00000000000..fee7dd9d29f Binary files /dev/null and b/Resources/Audio/Items/Handling/component_pickup.ogg differ diff --git a/Resources/Audio/Items/Handling/crowbar_drop.ogg b/Resources/Audio/Items/Handling/crowbar_drop.ogg new file mode 100644 index 00000000000..77464110661 Binary files /dev/null and b/Resources/Audio/Items/Handling/crowbar_drop.ogg differ diff --git a/Resources/Audio/Items/Handling/crowbar_pickup.ogg b/Resources/Audio/Items/Handling/crowbar_pickup.ogg new file mode 100644 index 00000000000..79b276f8451 Binary files /dev/null and b/Resources/Audio/Items/Handling/crowbar_pickup.ogg differ diff --git a/Resources/Audio/Items/Handling/disk_drop.ogg b/Resources/Audio/Items/Handling/disk_drop.ogg new file mode 100644 index 00000000000..3174b88117f Binary files /dev/null and b/Resources/Audio/Items/Handling/disk_drop.ogg differ diff --git a/Resources/Audio/Items/Handling/disk_pickup.ogg b/Resources/Audio/Items/Handling/disk_pickup.ogg new file mode 100644 index 00000000000..8f67406a5fb Binary files /dev/null and b/Resources/Audio/Items/Handling/disk_pickup.ogg differ diff --git a/Resources/Audio/Items/Handling/drinkglass_drop.ogg b/Resources/Audio/Items/Handling/drinkglass_drop.ogg new file mode 100644 index 00000000000..43bb732db3d Binary files /dev/null and b/Resources/Audio/Items/Handling/drinkglass_drop.ogg differ diff --git a/Resources/Audio/Items/Handling/drinkglass_pickup.ogg b/Resources/Audio/Items/Handling/drinkglass_pickup.ogg new file mode 100644 index 00000000000..fcd1c7d3126 Binary files /dev/null and b/Resources/Audio/Items/Handling/drinkglass_pickup.ogg differ diff --git a/Resources/Audio/Items/Handling/matchbox_drop.ogg b/Resources/Audio/Items/Handling/matchbox_drop.ogg new file mode 100644 index 00000000000..8e4e276c9e1 Binary files /dev/null and b/Resources/Audio/Items/Handling/matchbox_drop.ogg differ diff --git a/Resources/Audio/Items/Handling/matchbox_pickup.ogg b/Resources/Audio/Items/Handling/matchbox_pickup.ogg new file mode 100644 index 00000000000..82c23410e11 Binary files /dev/null and b/Resources/Audio/Items/Handling/matchbox_pickup.ogg differ diff --git a/Resources/Audio/Items/Handling/multitool_drop.ogg b/Resources/Audio/Items/Handling/multitool_drop.ogg new file mode 100644 index 00000000000..67e0a41042c Binary files /dev/null and b/Resources/Audio/Items/Handling/multitool_drop.ogg differ diff --git a/Resources/Audio/Items/Handling/multitool_pickup.ogg b/Resources/Audio/Items/Handling/multitool_pickup.ogg new file mode 100644 index 00000000000..cbd598ce896 Binary files /dev/null and b/Resources/Audio/Items/Handling/multitool_pickup.ogg differ diff --git a/Resources/Audio/Items/Handling/paper_drop.ogg b/Resources/Audio/Items/Handling/paper_drop.ogg new file mode 100644 index 00000000000..27ce2b3d1a7 Binary files /dev/null and b/Resources/Audio/Items/Handling/paper_drop.ogg differ diff --git a/Resources/Audio/Items/Handling/paper_pickup.ogg b/Resources/Audio/Items/Handling/paper_pickup.ogg new file mode 100644 index 00000000000..55ae2b3d2db Binary files /dev/null and b/Resources/Audio/Items/Handling/paper_pickup.ogg differ diff --git a/Resources/Audio/Items/Handling/screwdriver_drop.ogg b/Resources/Audio/Items/Handling/screwdriver_drop.ogg new file mode 100644 index 00000000000..cca91f4dddd Binary files /dev/null and b/Resources/Audio/Items/Handling/screwdriver_drop.ogg differ diff --git a/Resources/Audio/Items/Handling/screwdriver_pickup.ogg b/Resources/Audio/Items/Handling/screwdriver_pickup.ogg new file mode 100644 index 00000000000..6f6b29ddfc9 Binary files /dev/null and b/Resources/Audio/Items/Handling/screwdriver_pickup.ogg differ diff --git a/Resources/Audio/Items/Handling/sword_sheath.ogg b/Resources/Audio/Items/Handling/sword_sheath.ogg new file mode 100644 index 00000000000..9e1d5cdc009 Binary files /dev/null and b/Resources/Audio/Items/Handling/sword_sheath.ogg differ diff --git a/Resources/Audio/Items/Handling/sword_unsheath.ogg b/Resources/Audio/Items/Handling/sword_unsheath.ogg new file mode 100644 index 00000000000..09867f5966a Binary files /dev/null and b/Resources/Audio/Items/Handling/sword_unsheath.ogg differ diff --git a/Resources/Audio/Items/Handling/toolbelt_drop.ogg b/Resources/Audio/Items/Handling/toolbelt_drop.ogg new file mode 100644 index 00000000000..2a3c4655c49 Binary files /dev/null and b/Resources/Audio/Items/Handling/toolbelt_drop.ogg differ diff --git a/Resources/Audio/Items/Handling/toolbelt_pickup.ogg b/Resources/Audio/Items/Handling/toolbelt_pickup.ogg new file mode 100644 index 00000000000..58e5d25979a Binary files /dev/null and b/Resources/Audio/Items/Handling/toolbelt_pickup.ogg differ diff --git a/Resources/Audio/Items/Handling/toolbox_drop.ogg b/Resources/Audio/Items/Handling/toolbox_drop.ogg new file mode 100644 index 00000000000..abf56946278 Binary files /dev/null and b/Resources/Audio/Items/Handling/toolbox_drop.ogg differ diff --git a/Resources/Audio/Items/Handling/toolbox_pickup.ogg b/Resources/Audio/Items/Handling/toolbox_pickup.ogg new file mode 100644 index 00000000000..01a4ab4b3fa Binary files /dev/null and b/Resources/Audio/Items/Handling/toolbox_pickup.ogg differ diff --git a/Resources/Audio/Items/Handling/welder_drop.ogg b/Resources/Audio/Items/Handling/welder_drop.ogg new file mode 100644 index 00000000000..58b722ad7a7 Binary files /dev/null and b/Resources/Audio/Items/Handling/welder_drop.ogg differ diff --git a/Resources/Audio/Items/Handling/welder_pickup.ogg b/Resources/Audio/Items/Handling/welder_pickup.ogg new file mode 100644 index 00000000000..da78b06b848 Binary files /dev/null and b/Resources/Audio/Items/Handling/welder_pickup.ogg differ diff --git a/Resources/Audio/Items/Handling/wirecutter_drop.ogg b/Resources/Audio/Items/Handling/wirecutter_drop.ogg new file mode 100644 index 00000000000..e099870fc7d Binary files /dev/null and b/Resources/Audio/Items/Handling/wirecutter_drop.ogg differ diff --git a/Resources/Audio/Items/Handling/wirecutter_pickup.ogg b/Resources/Audio/Items/Handling/wirecutter_pickup.ogg new file mode 100644 index 00000000000..078faaf4324 Binary files /dev/null and b/Resources/Audio/Items/Handling/wirecutter_pickup.ogg differ diff --git a/Resources/Audio/Items/Handling/wrench_drop.ogg b/Resources/Audio/Items/Handling/wrench_drop.ogg new file mode 100644 index 00000000000..86020bf822c Binary files /dev/null and b/Resources/Audio/Items/Handling/wrench_drop.ogg differ diff --git a/Resources/Audio/Items/Handling/wrench_pickup.ogg b/Resources/Audio/Items/Handling/wrench_pickup.ogg new file mode 100644 index 00000000000..860e0d70879 Binary files /dev/null and b/Resources/Audio/Items/Handling/wrench_pickup.ogg differ diff --git a/Resources/Audio/Items/Whistle/closet_close.ogg b/Resources/Audio/Items/Whistle/closet_close.ogg new file mode 100644 index 00000000000..124f5d85f5e Binary files /dev/null and b/Resources/Audio/Items/Whistle/closet_close.ogg differ diff --git a/Resources/Audio/Items/Whistle/closet_open.ogg b/Resources/Audio/Items/Whistle/closet_open.ogg new file mode 100644 index 00000000000..86cbcea0d01 Binary files /dev/null and b/Resources/Audio/Items/Whistle/closet_open.ogg differ diff --git a/Resources/Audio/Items/Whistle/phasein.ogg b/Resources/Audio/Items/Whistle/phasein.ogg new file mode 100644 index 00000000000..8b74a7d42fd Binary files /dev/null and b/Resources/Audio/Items/Whistle/phasein.ogg differ diff --git a/Resources/Audio/Items/Whistle/podwoosh.ogg b/Resources/Audio/Items/Whistle/podwoosh.ogg new file mode 100644 index 00000000000..e6fd58c7fc2 Binary files /dev/null and b/Resources/Audio/Items/Whistle/podwoosh.ogg differ diff --git a/Resources/Audio/Lobby/01 The Gamble.ogg b/Resources/Audio/Lobby/01 The Gamble.ogg new file mode 100644 index 00000000000..c1cfdd53850 Binary files /dev/null and b/Resources/Audio/Lobby/01 The Gamble.ogg differ diff --git a/Resources/Audio/Lobby/02 Guilty Pleasures.ogg b/Resources/Audio/Lobby/02 Guilty Pleasures.ogg new file mode 100644 index 00000000000..9a281d19485 Binary files /dev/null and b/Resources/Audio/Lobby/02 Guilty Pleasures.ogg differ diff --git a/Resources/Audio/Lobby/03 Jazzcuzzi.ogg b/Resources/Audio/Lobby/03 Jazzcuzzi.ogg new file mode 100644 index 00000000000..49e7a332050 Binary files /dev/null and b/Resources/Audio/Lobby/03 Jazzcuzzi.ogg differ diff --git a/Resources/Audio/Lobby/04 The Walk.ogg b/Resources/Audio/Lobby/04 The Walk.ogg new file mode 100644 index 00000000000..481b08e650f Binary files /dev/null and b/Resources/Audio/Lobby/04 The Walk.ogg differ diff --git a/Resources/Audio/Lobby/05 Velvet Bossa.ogg b/Resources/Audio/Lobby/05 Velvet Bossa.ogg new file mode 100644 index 00000000000..dcb639de436 Binary files /dev/null and b/Resources/Audio/Lobby/05 Velvet Bossa.ogg differ diff --git a/Resources/Audio/Lobby/06 Colors.ogg b/Resources/Audio/Lobby/06 Colors.ogg new file mode 100644 index 00000000000..83a8d3a3ee2 Binary files /dev/null and b/Resources/Audio/Lobby/06 Colors.ogg differ diff --git a/Resources/Audio/Lobby/07 Midnight Jam.ogg b/Resources/Audio/Lobby/07 Midnight Jam.ogg new file mode 100644 index 00000000000..18e4e8de8a1 Binary files /dev/null and b/Resources/Audio/Lobby/07 Midnight Jam.ogg differ diff --git a/Resources/Audio/Lobby/08 Miles Ahead.ogg b/Resources/Audio/Lobby/08 Miles Ahead.ogg new file mode 100644 index 00000000000..db632e77218 Binary files /dev/null and b/Resources/Audio/Lobby/08 Miles Ahead.ogg differ diff --git a/Resources/Audio/Lobby/09 Moody.ogg b/Resources/Audio/Lobby/09 Moody.ogg new file mode 100644 index 00000000000..29720317d21 Binary files /dev/null and b/Resources/Audio/Lobby/09 Moody.ogg differ diff --git a/Resources/Audio/Lobby/10 Flying Away.ogg b/Resources/Audio/Lobby/10 Flying Away.ogg new file mode 100644 index 00000000000..84bda9db8f7 Binary files /dev/null and b/Resources/Audio/Lobby/10 Flying Away.ogg differ diff --git a/Resources/Audio/Lobby/11 Take It Easy.ogg b/Resources/Audio/Lobby/11 Take It Easy.ogg new file mode 100644 index 00000000000..f305357554d Binary files /dev/null and b/Resources/Audio/Lobby/11 Take It Easy.ogg differ diff --git a/Resources/Audio/Lobby/attributions.yml b/Resources/Audio/Lobby/attributions.yml index e37196494fb..9e777c37d10 100644 --- a/Resources/Audio/Lobby/attributions.yml +++ b/Resources/Audio/Lobby/attributions.yml @@ -1,89 +1,4 @@ -- files: ["434387_Time_Lapse_of_Clouds.ogg"] - license: "CC-BY-3.0" - copyright: "==(Time Lapse of Clouds)== by Buoy" - source: "https://www.newgrounds.com/audio/listen/434387" - -- files: ["a_different_reality_lagoona_remix.xm.ogg"] - license: "CC-BY-4.0" - copyright: "A.D.R (Lagoona rmx) by Andreas Viklund" - source: "https://modarchive.org/index.php?request=view_by_moduleid&query=134786" - -- files: ["aggravated.it.ogg"] - license: "CC-BY-NC-SA-4.0" - copyright: "MEL -Aggravated Assault by melcom" - source: "https://modarchive.org/index.php?request=view_by_moduleid&query=176234" - -- files: ["autumnal_equinox.xm.ogg"] - license: "CC-BY-NC-4.0" - copyright: "Autumnal Equinox by lemonade" - source: "https://modarchive.org/index.php?request=view_by_moduleid&query=143993" - -- files: ["comet_haley.ogg"] +- files: ["01 The Gamble.ogg", "02 Guilty Pleasures.ogg", "03 Jazzcuzzi.ogg", "04 The Walk.ogg", "05 Velvet Bossa.ogg", "06 Colors.ogg", "07 Midnight Jam.ogg", "08 Miles Ahead.ogg", "09 Moody.ogg", "10 Flying Away.ogg", "11 Take It Easy.ogg"] license: "CC-BY-NC-SA-3.0" - copyright: "Comet Haley by Stellardrone. Converted from MP3 to OGG." - source: "https://freemusicarchive.org/music/Stellardrone/Light_Years_1227/07_Comet_Halley" - -- files: ["drozerix_-_alone.xm.ogg"] - license: "Custom" - copyright: "Alone by Drozerix" - source: "https://modarchive.org/index.php?request=view_by_moduleid&query=199968" - -- files: ["drozerix_-_leisurely_voice.xm.ogg"] - license: "Custom" - copyright: "Leisurely Voice by Drozerix" - source: "https://modarchive.org/index.php?request=view_by_moduleid&query=183837" - -- files: ["endless_space.ogg"] - license: "CC-BY-3.0" - copyright: "Endless Space by SolusLunes. Converted from MP3 to OGG." - source: "https://www.newgrounds.com/audio/listen/67583" - -- files: ["marhaba.ogg"] - license: "CC-BY-NC-SA-3.0" - copyright: "Marhaba by Ian Alex Mac. Converted from MP3 to OGG." - source: "https://freemusicarchive.org/music/Ian_Alex_Mac/Cues/Marhaba" - -- files: ["melcom-cyberpunk.it.ogg"] - license: "CC-BY-NC-SA-4.0" - copyright: "MEL -Cyberpunk by melcom" - source: "https://modarchive.org/index.php?request=view_by_moduleid&query=184215" - -- files: ["midori_-_conundrum_final.it.ogg"] - license: "CC-BY-NC-SA-4.0" - copyright: "Conundrum by Midori Mizuno" - source: "https://modarchive.org/index.php?request=view_by_moduleid&query=181705" - -- files: ["mod.flip-flap.ogg"] - license: "Custom" - copyright: "Flip Flap by X-ceed is licensed under a short but clear license (see flip-flap.txt in this directory) and is free for non-commercial use. It was converted from MOD to WAV using Schism Tracker, in 16 Bit, Non-Interpolated mode, no output equalizer settings, Ramp volume at start of sample enabled. From there it was converted to OGG Vorbis with `ffmpeg -i flip-flap.wav -q 2.9 flip-flap-renc.ogg` (quality scale chosen to match size of the OGG file being replaced). Non-interpolated mode was chosen as the module has a high enough sample rate to balance it out, but seems muffled in other interpolation modes. If 'Ramp volume at start of sample' is not enabled, a clicking phenomenon results." - source: "http://aminet.net/package/mods/xceed/Flipflap" - -- files: ["psirius_-_nights_of_orion.xm.ogg"] - license: "CC-BY-NC-SA-4.0" - copyright: "Nights of Orion by Psirius" - source: "https://modarchive.org/index.php?request=view_by_moduleid&query=184962" - -- files: ["psirius_-_nymphs_of_the_forest.mptm.ogg"] - license: "CC-BY-NC-SA-4.0" - copyright: "Nymphs of the forest by Psirius" - source: "https://modarchive.org/index.php?request=view_by_moduleid&query=185545" - -- files: ["hackers.ogg"] - license: "CC-BY-NC-SA-3.0" - copyright: "Hackers by Karl Casey @ White Bat Audio" - source: "https://www.youtube.com/watch?v=k8nHWwO1U2Q" - -- files: ["superposition.ogg"] - license: "CC-BY-NC-3.0" - copyright: "Superposition by Amie Waters" - source: "https://amiewaters.bandcamp.com/track/superposition-2" - -- files: ["every_light_is_blinking_at_once.ogg"] - license: "CC-BY-NC-SA-3.0" - copyright: "every light is blinking at once by Alexander Divine." - source: "https://soundcloud.com/alexanderdivine/every-light-is-blinking-at-once" - -- files: ["DOS=HIGH,_UMB.ogg"] - license: "Custom" - copyright: "DOS=HIGH, UMB by MASTER BOOT RECORD may be used non-commercially in the Delta-V fork of SS14. Converted from FLAC to OGG." - source: "https://masterbootrecord.bandcamp.com/album/c-edit-config-sys" + copyright: "All songs used are produced by Danya Vodovoz, royalty free." + source: "https://soundcloud.com/danyavodovoz" diff --git a/Resources/Audio/Machines/AI/borg_death.ogg b/Resources/Audio/Machines/AI/borg_death.ogg new file mode 100644 index 00000000000..9f6d1861904 Binary files /dev/null and b/Resources/Audio/Machines/AI/borg_death.ogg differ diff --git a/Resources/Audio/Machines/machine_vend.ogg b/Resources/Audio/Machines/machine_vend.ogg index 8f7c187d0c3..92867a1f3d3 100644 Binary files a/Resources/Audio/Machines/machine_vend.ogg and b/Resources/Audio/Machines/machine_vend.ogg differ diff --git a/Resources/Audio/Music/attributions.yml b/Resources/Audio/Music/attributions.yml new file mode 100644 index 00000000000..c1ed2f1027f --- /dev/null +++ b/Resources/Audio/Music/attributions.yml @@ -0,0 +1,4 @@ +- files: ["deadling.ogg"] + license: "CC-BY-3.0" + copyright: "Created by Bolgarich" + source: "https://youtu.be/q7_NFEeeEac" diff --git a/Resources/Audio/Music/deadline.ogg b/Resources/Audio/Music/deadline.ogg new file mode 100644 index 00000000000..6ab081fc236 Binary files /dev/null and b/Resources/Audio/Music/deadline.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Equip/toolbelt_equip.ogg b/Resources/Audio/SimpleStation14/Items/Equip/toolbelt_equip.ogg new file mode 100644 index 00000000000..0ef67a3fd6c Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Equip/toolbelt_equip.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/ammobox_drop.ogg b/Resources/Audio/SimpleStation14/Items/Handling/ammobox_drop.ogg new file mode 100644 index 00000000000..13fce70fe3d Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/ammobox_drop.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/ammobox_pickup.ogg b/Resources/Audio/SimpleStation14/Items/Handling/ammobox_pickup.ogg new file mode 100644 index 00000000000..9532a7697b9 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/ammobox_pickup.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/book_drop.ogg b/Resources/Audio/SimpleStation14/Items/Handling/book_drop.ogg new file mode 100644 index 00000000000..b492b665f59 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/book_drop.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/book_pickup.ogg b/Resources/Audio/SimpleStation14/Items/Handling/book_pickup.ogg new file mode 100644 index 00000000000..120a4e4721a Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/book_pickup.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/cardboardbox_drop.ogg b/Resources/Audio/SimpleStation14/Items/Handling/cardboardbox_drop.ogg new file mode 100644 index 00000000000..7070ba1c342 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/cardboardbox_drop.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/cardboardbox_pickup.ogg b/Resources/Audio/SimpleStation14/Items/Handling/cardboardbox_pickup.ogg new file mode 100644 index 00000000000..aa4e72129b0 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/cardboardbox_pickup.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/cloth_drop.ogg b/Resources/Audio/SimpleStation14/Items/Handling/cloth_drop.ogg new file mode 100644 index 00000000000..5bf734caba0 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/cloth_drop.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/cloth_pickup.ogg b/Resources/Audio/SimpleStation14/Items/Handling/cloth_pickup.ogg new file mode 100644 index 00000000000..f46988887d1 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/cloth_pickup.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/component_drop.ogg b/Resources/Audio/SimpleStation14/Items/Handling/component_drop.ogg new file mode 100644 index 00000000000..95ba2591a31 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/component_drop.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/component_pickup.ogg b/Resources/Audio/SimpleStation14/Items/Handling/component_pickup.ogg new file mode 100644 index 00000000000..fee7dd9d29f Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/component_pickup.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/crowbar_drop.ogg b/Resources/Audio/SimpleStation14/Items/Handling/crowbar_drop.ogg new file mode 100644 index 00000000000..77464110661 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/crowbar_drop.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/crowbar_pickup.ogg b/Resources/Audio/SimpleStation14/Items/Handling/crowbar_pickup.ogg new file mode 100644 index 00000000000..79b276f8451 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/crowbar_pickup.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/disk_drop.ogg b/Resources/Audio/SimpleStation14/Items/Handling/disk_drop.ogg new file mode 100644 index 00000000000..3174b88117f Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/disk_drop.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/disk_pickup.ogg b/Resources/Audio/SimpleStation14/Items/Handling/disk_pickup.ogg new file mode 100644 index 00000000000..8f67406a5fb Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/disk_pickup.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/drinkglass_drop.ogg b/Resources/Audio/SimpleStation14/Items/Handling/drinkglass_drop.ogg new file mode 100644 index 00000000000..43bb732db3d Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/drinkglass_drop.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/drinkglass_pickup.ogg b/Resources/Audio/SimpleStation14/Items/Handling/drinkglass_pickup.ogg new file mode 100644 index 00000000000..fcd1c7d3126 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/drinkglass_pickup.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/matchbox_drop.ogg b/Resources/Audio/SimpleStation14/Items/Handling/matchbox_drop.ogg new file mode 100644 index 00000000000..8e4e276c9e1 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/matchbox_drop.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/matchbox_pickup.ogg b/Resources/Audio/SimpleStation14/Items/Handling/matchbox_pickup.ogg new file mode 100644 index 00000000000..82c23410e11 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/matchbox_pickup.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/multitool_drop.ogg b/Resources/Audio/SimpleStation14/Items/Handling/multitool_drop.ogg new file mode 100644 index 00000000000..67e0a41042c Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/multitool_drop.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/multitool_pickup.ogg b/Resources/Audio/SimpleStation14/Items/Handling/multitool_pickup.ogg new file mode 100644 index 00000000000..cbd598ce896 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/multitool_pickup.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/paper_drop.ogg b/Resources/Audio/SimpleStation14/Items/Handling/paper_drop.ogg new file mode 100644 index 00000000000..27ce2b3d1a7 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/paper_drop.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/paper_pickup.ogg b/Resources/Audio/SimpleStation14/Items/Handling/paper_pickup.ogg new file mode 100644 index 00000000000..55ae2b3d2db Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/paper_pickup.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/screwdriver_drop.ogg b/Resources/Audio/SimpleStation14/Items/Handling/screwdriver_drop.ogg new file mode 100644 index 00000000000..cca91f4dddd Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/screwdriver_drop.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/screwdriver_pickup.ogg b/Resources/Audio/SimpleStation14/Items/Handling/screwdriver_pickup.ogg new file mode 100644 index 00000000000..6f6b29ddfc9 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/screwdriver_pickup.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/sword_sheath.ogg b/Resources/Audio/SimpleStation14/Items/Handling/sword_sheath.ogg new file mode 100644 index 00000000000..9e1d5cdc009 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/sword_sheath.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/sword_unsheath.ogg b/Resources/Audio/SimpleStation14/Items/Handling/sword_unsheath.ogg new file mode 100644 index 00000000000..09867f5966a Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/sword_unsheath.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/toolbelt_drop.ogg b/Resources/Audio/SimpleStation14/Items/Handling/toolbelt_drop.ogg new file mode 100644 index 00000000000..2a3c4655c49 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/toolbelt_drop.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/toolbelt_pickup.ogg b/Resources/Audio/SimpleStation14/Items/Handling/toolbelt_pickup.ogg new file mode 100644 index 00000000000..58e5d25979a Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/toolbelt_pickup.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/toolbox_drop.ogg b/Resources/Audio/SimpleStation14/Items/Handling/toolbox_drop.ogg new file mode 100644 index 00000000000..abf56946278 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/toolbox_drop.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/toolbox_pickup.ogg b/Resources/Audio/SimpleStation14/Items/Handling/toolbox_pickup.ogg new file mode 100644 index 00000000000..01a4ab4b3fa Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/toolbox_pickup.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/welder_drop.ogg b/Resources/Audio/SimpleStation14/Items/Handling/welder_drop.ogg new file mode 100644 index 00000000000..58b722ad7a7 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/welder_drop.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/welder_pickup.ogg b/Resources/Audio/SimpleStation14/Items/Handling/welder_pickup.ogg new file mode 100644 index 00000000000..da78b06b848 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/welder_pickup.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/wirecutter_drop.ogg b/Resources/Audio/SimpleStation14/Items/Handling/wirecutter_drop.ogg new file mode 100644 index 00000000000..e099870fc7d Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/wirecutter_drop.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/wirecutter_pickup.ogg b/Resources/Audio/SimpleStation14/Items/Handling/wirecutter_pickup.ogg new file mode 100644 index 00000000000..078faaf4324 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/wirecutter_pickup.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/wrench_drop.ogg b/Resources/Audio/SimpleStation14/Items/Handling/wrench_drop.ogg new file mode 100644 index 00000000000..86020bf822c Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/wrench_drop.ogg differ diff --git a/Resources/Audio/SimpleStation14/Items/Handling/wrench_pickup.ogg b/Resources/Audio/SimpleStation14/Items/Handling/wrench_pickup.ogg new file mode 100644 index 00000000000..860e0d70879 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Items/Handling/wrench_pickup.ogg differ diff --git a/Resources/Audio/SimpleStation14/Machines/machine_vend.ogg b/Resources/Audio/SimpleStation14/Machines/machine_vend.ogg new file mode 100644 index 00000000000..92867a1f3d3 Binary files /dev/null and b/Resources/Audio/SimpleStation14/Machines/machine_vend.ogg differ diff --git a/Resources/Audio/SimpleStation14/Weapons/Melee/banjohit.ogg b/Resources/Audio/SimpleStation14/Weapons/Melee/banjohit.ogg new file mode 100644 index 00000000000..06a86a535dd Binary files /dev/null and b/Resources/Audio/SimpleStation14/Weapons/Melee/banjohit.ogg differ diff --git a/Resources/Audio/SimpleStation14/Weapons/Melee/rapierhit.ogg b/Resources/Audio/SimpleStation14/Weapons/Melee/rapierhit.ogg new file mode 100644 index 00000000000..401fcf9677c Binary files /dev/null and b/Resources/Audio/SimpleStation14/Weapons/Melee/rapierhit.ogg differ diff --git a/Resources/Audio/Voice/Slime/slime_crackleslap.ogg b/Resources/Audio/Voice/Slime/slime_crackleslap.ogg new file mode 100644 index 00000000000..c9fcfbee448 Binary files /dev/null and b/Resources/Audio/Voice/Slime/slime_crackleslap.ogg differ diff --git a/Resources/Audio/Voice/Slime/slime_laugh_f1.ogg b/Resources/Audio/Voice/Slime/slime_laugh_f1.ogg new file mode 100644 index 00000000000..4b3b36810f3 Binary files /dev/null and b/Resources/Audio/Voice/Slime/slime_laugh_f1.ogg differ diff --git a/Resources/Audio/Voice/Slime/slime_laugh_m1.ogg b/Resources/Audio/Voice/Slime/slime_laugh_m1.ogg new file mode 100644 index 00000000000..7ad1ba95dae Binary files /dev/null and b/Resources/Audio/Voice/Slime/slime_laugh_m1.ogg differ diff --git a/Resources/Audio/Voice/Slime/slime_laugh_m2.ogg b/Resources/Audio/Voice/Slime/slime_laugh_m2.ogg new file mode 100644 index 00000000000..0d08e954523 Binary files /dev/null and b/Resources/Audio/Voice/Slime/slime_laugh_m2.ogg differ diff --git a/Resources/Audio/Voice/Slime/slime_schlorp.ogg b/Resources/Audio/Voice/Slime/slime_schlorp.ogg new file mode 100644 index 00000000000..f125fbc03b0 Binary files /dev/null and b/Resources/Audio/Voice/Slime/slime_schlorp.ogg differ diff --git a/Resources/Audio/Voice/Slime/slime_scream_f1.ogg b/Resources/Audio/Voice/Slime/slime_scream_f1.ogg new file mode 100644 index 00000000000..99f8e7f91fa Binary files /dev/null and b/Resources/Audio/Voice/Slime/slime_scream_f1.ogg differ diff --git a/Resources/Audio/Voice/Slime/slime_scream_f2.ogg b/Resources/Audio/Voice/Slime/slime_scream_f2.ogg new file mode 100644 index 00000000000..71ea5f4bdce Binary files /dev/null and b/Resources/Audio/Voice/Slime/slime_scream_f2.ogg differ diff --git a/Resources/Audio/Voice/Slime/slime_scream_m1.ogg b/Resources/Audio/Voice/Slime/slime_scream_m1.ogg new file mode 100644 index 00000000000..67f4734bcf4 Binary files /dev/null and b/Resources/Audio/Voice/Slime/slime_scream_m1.ogg differ diff --git a/Resources/Audio/Voice/Slime/slime_scream_m2.ogg b/Resources/Audio/Voice/Slime/slime_scream_m2.ogg new file mode 100644 index 00000000000..bc499bad782 Binary files /dev/null and b/Resources/Audio/Voice/Slime/slime_scream_m2.ogg differ diff --git a/Resources/Audio/Voice/Slime/slime_squish.ogg b/Resources/Audio/Voice/Slime/slime_squish.ogg index 60e118e217b..e7c3509c4d8 100644 Binary files a/Resources/Audio/Voice/Slime/slime_squish.ogg and b/Resources/Audio/Voice/Slime/slime_squish.ogg differ diff --git a/Resources/Audio/Weapons/Melee/banjohit.ogg b/Resources/Audio/Weapons/Melee/banjohit.ogg new file mode 100644 index 00000000000..06a86a535dd Binary files /dev/null and b/Resources/Audio/Weapons/Melee/banjohit.ogg differ diff --git a/Resources/Audio/Weapons/Melee/rapierhit.ogg b/Resources/Audio/Weapons/Melee/rapierhit.ogg new file mode 100644 index 00000000000..401fcf9677c Binary files /dev/null and b/Resources/Audio/Weapons/Melee/rapierhit.ogg differ diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 3d0a73d62df..230d26ef8f2 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -4367,3 +4367,179 @@ Entries: message: Added system id: 6146 time: '2024-07-06T00:19:35.0000000+00:00' +- author: Velcroboy + changes: + - type: Tweak + message: Changed asteroids to have more ore...and some danger + id: 6147 + time: '2024-07-08T07:03:39.0000000+00:00' +- author: FoxxoTrystan + changes: + - type: Add + message: Languages are now marked in the chat! + id: 6148 + time: '2024-07-09T19:01:38.0000000+00:00' +- author: Spatison + changes: + - type: Fix + message: Food and handcuffs can now be given + id: 6149 + time: '2024-07-09T19:32:11.0000000+00:00' +- author: FoxxoTrrystan + changes: + - type: Tweak + message: >- + Power Resprites! (New SMES, APC, Airlarm, Camera, Substation, LightTube, + Intercom, FireAlarm and Substation) + id: 6150 + time: '2024-07-09T19:37:03.0000000+00:00' +- author: CodedCrow + changes: + - type: Add + message: Added an Arachne plushie + id: 6151 + time: '2024-07-11T17:23:58.0000000+00:00' +- author: osjarw + changes: + - type: Add + message: Wallmount substation electronics can now be created at an autolathe. + id: 6152 + time: '2024-07-11T17:24:30.0000000+00:00' +- author: Mnemotechnician + changes: + - type: Tweak + message: 'Players can now vote on two more gamemodes: Traitors and Hellshift.' + id: 6153 + time: '2024-07-11T17:26:41.0000000+00:00' +- author: Mnemotechnician + changes: + - type: Add + message: >- + Added two new foreigner traits that make your character unable to speak + Galactic Common and give you a translator instead. + - type: Tweak + message: >- + Translators can now be equipped in the neck slot and display useful info + when examined. + id: 6154 + time: '2024-07-12T01:19:09.0000000+00:00' +- author: Mnemotechnician + changes: + - type: Fix + message: Foreigner traits now work correctly. + id: 6155 + time: '2024-07-12T17:46:37.0000000+00:00' +- author: WarMechanic + changes: + - type: Add + message: >- + Added the Heavyweight Drunk trait, which doubles your alcoholism + potential. + id: 6156 + time: '2024-07-12T19:02:15.0000000+00:00' +- author: DEATHB4DEFEAT + changes: + - type: Add + message: Added 4 new announcers that will randomly be selected every shift + id: 6157 + time: '2024-07-12T20:13:50.0000000+00:00' +- author: VMSolidus + changes: + - type: Add + message: 'Mass Contests have returned in a new reworked form. ' + - type: Add + message: >- + Weapon Recoil is now resisted by character mass. More massive characters + take less recoil, less massive characters take more recoil. + - type: Add + message: >- + Disarm and Shove actions are now modified by relative character mass. It + is easier to shove people around if you're bigger than them. + - type: Add + message: >- + Cablecuffs and Zipties are now easier to escape out of if you're + smaller. + id: 6158 + time: '2024-07-13T08:05:52.0000000+00:00' +- author: FoxxoTrystan + changes: + - type: Tweak + message: We got new ID Cards the old ones were soo tiny that they were lost. + id: 6159 + time: '2024-07-14T23:12:33.0000000+00:00' +- author: Mnemotechnician + changes: + - type: Tweak + message: >- + Shock collars can now be manufactured in the security techfab. They also + deal less damage and ignore insulated gloves. + id: 6160 + time: '2024-07-14T23:14:03.0000000+00:00' +- author: WarMechanic + changes: + - type: Fix + message: Fixed thieving trait not granting pocket vision + id: 6161 + time: '2024-07-16T17:41:42.0000000+00:00' +- author: VMSolidus + changes: + - type: Add + message: Many new sound effects have been implemented for items. + id: 6162 + time: '2024-07-16T17:52:03.0000000+00:00' +- author: gluesniffler + changes: + - type: Add + message: Added a new icon to the offer item interaction. + - type: Fix + message: Fixed typos in the offer item prompts. + id: 6163 + time: '2024-07-16T18:18:18.0000000+00:00' +- author: Mnemotechnician + changes: + - type: Add + message: You can now configure your zoom more precisely. + id: 6164 + time: '2024-07-16T18:18:57.0000000+00:00' +- author: dootythefrooty + changes: + - type: Add + message: Added Harpy Wings as a delicious dish. + id: 6165 + time: '2024-07-16T18:21:27.0000000+00:00' +- author: gluesniffler + changes: + - type: Add + message: Added an alert on the UI for when the user is walking or running. + id: 6166 + time: '2024-07-16T21:39:46.0000000+00:00' +- author: Mnemotechnician + changes: + - type: Add + message: >- + You can now lie down and stand up at will! The default keybind for it is + "R", but it can be changed in settings. + id: 6167 + time: '2024-07-18T02:33:16.0000000+00:00' +- author: VMSolidus + changes: + - type: Fix + message: >- + Harpies can no longer buy Loadout items that are impossible for them to + wear due to having digitigrade legs. + id: 6168 + time: '2024-07-18T02:34:52.0000000+00:00' +- author: Mnemotechnician + changes: + - type: Fix + message: Foreigner translator should now consume power, as intended. + id: 6169 + time: '2024-07-18T08:22:52.0000000+00:00' +- author: VMSolidus + changes: + - type: Add + message: >- + Atmospheric "Throws" are now calculated using object mass, and behave + accordingly. Tiny objects will shoot out of rooms quite fast! + id: 6170 + time: '2024-07-18T08:24:58.0000000+00:00' diff --git a/Resources/Changelog/Floof.yml b/Resources/Changelog/Floof.yml index 9dea83bdd9a..896abdd3e71 100644 --- a/Resources/Changelog/Floof.yml +++ b/Resources/Changelog/Floof.yml @@ -103,3 +103,67 @@ Entries: message: Arachnid has no slowdown on walking on webs. id: 14 time: '2024-07-03T01:27:16.0000000+00:00' +- author: Tilkku + changes: + - type: Add + message: Pomegranate Juice & Slices + - type: Tweak + message: Downsized pomegranate sprite + id: 15 + time: '2024-07-18T11:18:57.0000000+00:00' +- author: Shiro69420 + changes: + - type: Add + message: blood-red coder socks to things + id: 16 + time: '2024-07-19T07:13:32.0000000+00:00' +- author: Foxxotrystan + changes: + - type: Tweak + message: Upsteam Update. + id: 17 + time: '2024-07-19T09:56:48.0000000+00:00' +- author: FoxxoTrystan + changes: + - type: Remove + message: Removed Mass-Mind-Swap Event. + id: 18 + time: '2024-07-19T13:45:06.0000000+00:00' +- author: FoxxoTrystan/Fansana + changes: + - type: Add + message: Set up the Floof CDN. + id: 19 + time: '2024-07-19T13:45:06.0000000+00:00' +- author: Fansana + changes: + - type: Tweak + message: force Michael announcer + id: 20 + time: '2024-07-20T19:49:06.0000000+00:00' +- author: Fansana + changes: + - type: Fix + message: shuttle and alert announcements + id: 21 + time: '2024-07-22T04:29:24.0000000+00:00' +- author: SnowyFoxxo + changes: + - type: Tweak + message: >- + Added, tweaked or removed a few rules. Also finally should have a + modicum of formatting. + id: 22 + time: '2024-07-22T17:02:37.0000000+00:00' +- author: FoxxoTrystan + changes: + - type: Add + message: Sign Languages! + id: 23 + time: '2024-07-22T20:14:58.0000000+00:00' +- author: Tilkku + changes: + - type: Add + message: Added a new series of cocktails and new bottles to the booze'o'mat + id: 24 + time: '2024-07-22T20:15:08.0000000+00:00' diff --git a/Resources/Credits/GitHub.txt b/Resources/Credits/GitHub.txt index 84796a94662..0cf9c113634 100644 --- a/Resources/Credits/GitHub.txt +++ b/Resources/Credits/GitHub.txt @@ -1 +1 @@ -0x6273, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 4dplanner, 612git, 778b, Ablankmann, Acruid, actioninja, adamsong, Admiral-Obvious-001, Adrian16199, Aerocrux, Aexxie, africalimedrop, Agoichi, Ahion, AJCM-git, AjexRose, Alekshhh, AlexMorgan3817, AlmondFlour, AlphaQwerty, Altoids1, amylizzle, ancientpower, ArchPigeon, Arendian, arimah, Arteben, AruMoon, as334, AsikKEsel, asperger-sind, aspiringLich, avghdev, AzzyIsNotHere, BananaFlambe, BasedUser, BGare, BingoJohnson-zz, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, Boaz1111, BobdaBiscuit, brainfood1183, Brandon-Huu, Bribrooo, Bright0, brndd, BubblegumBlue, BYONDFuckery, c4llv07e, CaasGit, CakeQ, CaptainSqrBeard, Carbonhell, Carolyn3114, casperr04, CatTheSystem, Centronias, chairbender, Charlese2, Cheackraze, cheesePizza2, Chief-Engineer, chromiumboy, Chronophylos, clement-or, Clyybber, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, coolmankid12345, corentt, crazybrain23, creadth, CrigCrag, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, Daemon, daerSeebaer, dahnte, dakamakat, dakimasu, DamianX, DangerRevolution, daniel-cr, Darkenson, DawBla, dch-GH, Deahaka, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, deepdarkdepths, Delete69, deltanedas, DeltaV-Bot, DerbyX, DoctorBeard, DogZeroX, dontbetank, Doru991, DoubleRiceEddiedd, DrMelon, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, Dutch-VanDerLinde, Easypoller, eclips_e, EdenTheLiznerd, EEASAS, Efruit, ElectroSR, elthundercloud, Emisse, EmoGarbage404, Endecc, enumerate0, eoineoineoin, ERORR404V1, Errant-4, estacaoespacialpirata, exincore, exp111, Fahasor, FairlySadPanda, ficcialfaint, Fildrance, FillerVK, Fishfish458, Flareguy, FluffiestFloof, FluidRock, FoLoKe, fooberticus, Fortune117, FoxxoTrystan, freeman2651, Fromoriss, FungiFellow, GalacticChimp, gbasood, Geekyhobo, Genkail, geraeumig, Git-Nivrak, github-actions[bot], gituhabu, GNF54, Golinth, GoodWheatley, Gotimanga, graevy, GreyMario, Guess-My-Name, gusxyz, h3half, Hanzdegloker, Hardly3D, harikattar, Hebiman, Henry12116, HerCoyote23, Hmeister-real, HoofedEar, hord-brayden, hubismal, Hugal31, Hyenh, iacore, IamVelcroboy, icekot8, igorsaux, ike709, Illiux, Ilya246, IlyaElDunaev, Injazz, Insineer, IntegerTempest, Interrobang01, IProduceWidgets, ItsMeThom, j-giebel, Jackal298, Jackrost, jamessimo, janekvap, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JoeHammad1844, joelhed, JohnGinnane, johnku1, joshepvodka, jproads, Jrpl, juliangiebel, JustArt1m, JustCone14, JustinTether, JustinTrotter, KaiShibaa, kalane15, kalanosh, KEEYNy, Keikiru, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, KingFroozy, kira-er, Kit0vras, KittenColony, Kmc2000, Ko4ergaPunk, komunre, koteq, Krunklehorn, Kukutis96513, kxvvv, Lamrr, LankLTE, lapatison, Leander-0, leonardo-dabepis, LetterN, Level10Cybermancer, lever1209, LightVillet, liltenhead, LittleBuilderJane, Lomcastar, LordCarve, LordEclipse, LovelyLophi, LudwigVonChesterfield, Lukasz825700516, lunarcomets, luringens, lvvova1, lzimann, lzk228, M3739, MACMAN2003, Macoron, MagnusCrowe, ManelNavola, matthst, Matz05, MehimoNemo, MeltedPixel, MemeProof, Menshin, Mervill, metalgearsloth, mhamsterr, MilenVolf, Minty642, Mirino97, mirrorcult, misandrie, MishaUnity, MisterMecky, Mith-randalf, Moneyl, Moomoobeef, moony, Morb0, Mr0maks, musicmanvr, Myakot, Myctai, N3X15, Nairodian, Naive817, namespace-Memory, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, nmajask, nok-ko, Nopey, notafet, notquitehadouken, noudoit, noverd, nuke-haus, NULL882, OCOtheOmega, OctoRocket, OldDanceJacket, onoira, Owai-Seek, pali6, Pangogie, patrikturi, PaulRitter, Peptide90, peptron1, Phantom-Lily, PHCodes, PixelTheKermit, PJB3005, Plykiya, pofitlo, pointer-to-null, PolterTzi, PoorMansDreams, potato1234x, ProfanedBane, PrPleGoo, ps3moira, Psychpsyo, psykzz, PuroSlavKing, quatre, QuietlyWhisper, qwerltaz, Radosvik, Radrark, Rainbeon, Rainfey, Rane, ravage123321, rbertoche, Redict, RedlineTriad, RednoWCirabrab, RemberBM, RemieRichards, RemTim, rene-descartes2021, RiceMar1244, RieBi, Rinkashikachi, Rockdtben, rolfero, rosieposieeee, Saakra, Samsterious, SaphireLattice, ScalyChimp, scrato, Scribbles0, Serkket, SethLafuente, ShadowCommander, Shadowtheprotogen546, SignalWalker, SimpleStation14, Simyon264, SirDragooon, Sirionaut, siyengar04, Skarletto, Skrauz, Skyedra, SlamBamActionman, slarticodefast, Slava0135, Snowni, snowsignal, SonicHDC, SoulSloth, SpaceManiac, SpeltIncorrectyl, spoogemonster, ssdaniel24, Stealthbomber16, stellar-novas, StrawberryMoses, SweptWasTaken, Szunti, TadJohnson00, takemysoult, TaralGit, Tayrtahn, tday93, TekuNut, TemporalOroboros, tentekal, tgrkzus, thatrandomcanadianguy, TheArturZh, theashtronaut, thedraccx, themias, Theomund, theOperand, TheShuEd, TimrodDX, Titian3, tkdrg, tmtmtl30, tom-leys, tomasalves8, Tomeno, Tornado-Technology, tosatur, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, Tyler-IN, Tyzemol, UbaserB, UKNOWH, UnicornOnLSD, Uriende, UristMcDorf, Vaaankas, Varen, VasilisThePikachu, veliebm, Veritius, Verslebas, VigersRay, Visne, VMSolidus, volundr-, Voomra, Vordenburg, vulppine, waylon531, weaversam8, Willhelm53, wixoaGit, WlarusFromDaSpace, wrexbe, xRiriq, yathxyz, Ygg01, YotaXP, YuriyKiss, zach-hill, Zandario, Zap527, ZelteHonor, zerorulez, zionnBE, zlodo, ZNixian, ZoldorfTheWizard, Zumorica, Zymem +0x6273, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 4dplanner, 612git, 778b, Ablankmann, Acruid, actioninja, adamsong, Admiral-Obvious-001, Adrian16199, Aerocrux, Aexxie, africalimedrop, Agoichi, Ahion, AJCM-git, AjexRose, Alekshhh, AlexMorgan3817, AlmondFlour, AlphaQwerty, Altoids1, amylizzle, ancientpower, ArchPigeon, Arendian, arimah, Arteben, AruMoon, as334, AsikKEsel, asperger-sind, aspiringLich, avghdev, AzzyIsNotHere, BananaFlambe, BasedUser, BGare, BingoJohnson-zz, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, Boaz1111, BobdaBiscuit, brainfood1183, Brandon-Huu, Bribrooo, Bright0, brndd, BubblegumBlue, BYONDFuckery, c4llv07e, CaasGit, CakeQ, CaptainSqrBeard, Carbonhell, Carolyn3114, casperr04, CatTheSystem, Centronias, chairbender, Charlese2, Cheackraze, cheesePizza2, Chief-Engineer, chromiumboy, Chronophylos, clement-or, Clyybber, CodedCrow, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, coolmankid12345, corentt, crazybrain23, creadth, CrigCrag, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, Daemon, daerSeebaer, dahnte, dakamakat, dakimasu, DamianX, DangerRevolution, daniel-cr, Darkenson, DawBla, dch-GH, Deahaka, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, deepdarkdepths, Delete69, deltanedas, DeltaV-Bot, DerbyX, DoctorBeard, DogZeroX, dontbetank, Doru991, DoubleRiceEddiedd, DrMelon, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, Dutch-VanDerLinde, Easypoller, eclips_e, EdenTheLiznerd, EEASAS, Efruit, ElectroSR, elthundercloud, Emisse, EmoGarbage404, Endecc, enumerate0, eoineoineoin, ERORR404V1, Errant-4, estacaoespacialpirata, exincore, exp111, Fahasor, FairlySadPanda, ficcialfaint, Fildrance, FillerVK, Fishfish458, Flareguy, FluffiestFloof, FluidRock, FoLoKe, fooberticus, Fortune117, FoxxoTrystan, freeman2651, Fromoriss, FungiFellow, GalacticChimp, gbasood, Geekyhobo, Genkail, geraeumig, Git-Nivrak, github-actions[bot], gituhabu, GNF54, Golinth, GoodWheatley, Gotimanga, graevy, GreyMario, Guess-My-Name, gusxyz, h3half, Hanzdegloker, Hardly3D, harikattar, Hebiman, Henry12116, HerCoyote23, Hmeister-real, HoofedEar, hord-brayden, hubismal, Hugal31, Hyenh, iacore, IamVelcroboy, icekot8, igorsaux, ike709, Illiux, Ilya246, IlyaElDunaev, Injazz, Insineer, IntegerTempest, Interrobang01, IProduceWidgets, ItsMeThom, j-giebel, Jackal298, Jackrost, jamessimo, janekvap, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JoeHammad1844, joelhed, JohnGinnane, johnku1, joshepvodka, jproads, Jrpl, juliangiebel, JustArt1m, JustCone14, JustinTether, JustinTrotter, KaiShibaa, kalane15, kalanosh, KEEYNy, Keikiru, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, KingFroozy, kira-er, Kit0vras, KittenColony, Kmc2000, Ko4ergaPunk, komunre, koteq, Krunklehorn, Kukutis96513, kxvvv, Lamrr, LankLTE, lapatison, Leander-0, leonardo-dabepis, LetterN, Level10Cybermancer, lever1209, LightVillet, liltenhead, LittleBuilderJane, Lomcastar, LordCarve, LordEclipse, LovelyLophi, LudwigVonChesterfield, Lukasz825700516, lunarcomets, luringens, lvvova1, lzimann, lzk228, MACMAN2003, Macoron, MagnusCrowe, ManelNavola, Matz05, MehimoNemo, MeltedPixel, MemeProof, Menshin, Mervill, metalgearsloth, mhamsterr, MilenVolf, Minty642, Mirino97, mirrorcult, misandrie, MishaUnity, MisterMecky, Mith-randalf, Mnemotechnician, Moneyl, Moomoobeef, moony, Morb0, Mr0maks, musicmanvr, Myakot, Myctai, N3X15, Nairodian, Naive817, namespace-Memory, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, nmajask, nok-ko, notafet, notquitehadouken, noudoit, noverd, nuke-haus, NULL882, OCOtheOmega, OctoRocket, OldDanceJacket, onoira, Owai-Seek, pali6, Pangogie, patrikturi, PaulRitter, Peptide90, peptron1, Phantom-Lily, PHCodes, PixelTheKermit, PJB3005, Plykiya, pofitlo, pointer-to-null, PolterTzi, PoorMansDreams, potato1234x, ProfanedBane, PrPleGoo, ps3moira, Psychpsyo, psykzz, PuroSlavKing, quatre, QuietlyWhisper, qwerltaz, Radosvik, Radrark, Rainbeon, Rainfey, Rane, ravage123321, rbertoche, Redict, RedlineTriad, RednoWCirabrab, RemberBM, RemieRichards, RemTim, rene-descartes2021, RiceMar1244, RieBi, Rinkashikachi, Rockdtben, rolfero, rosieposieeee, Saakra, Samsterious, SaphireLattice, ScalyChimp, scrato, Scribbles0, Serkket, SethLafuente, ShadowCommander, Shadowtheprotogen546, SignalWalker, SimpleStation14, Simyon264, SirDragooon, Sirionaut, siyengar04, Skarletto, Skrauz, Skyedra, SlamBamActionman, slarticodefast, Slava0135, Snowni, snowsignal, SonicHDC, SoulSloth, SpaceManiac, SpeltIncorrectyl, spoogemonster, ssdaniel24, Stealthbomber16, stellar-novas, StrawberryMoses, SweptWasTaken, Szunti, TadJohnson00, takemysoult, TaralGit, Tayrtahn, tday93, TekuNut, TemporalOroboros, tentekal, tgrkzus, thatrandomcanadianguy, TheArturZh, theashtronaut, thedraccx, themias, Theomund, theOperand, TheShuEd, TimrodDX, Titian3, tkdrg, tmtmtl30, tom-leys, tomasalves8, Tomeno, Tornado-Technology, tosatur, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, Tyler-IN, Tyzemol, UbaserB, UKNOWH, UnicornOnLSD, Uriende, UristMcDorf, Vaaankas, Varen, VasilisThePikachu, veliebm, Veritius, Verslebas, VigersRay, Visne, VMSolidus, volundr-, Voomra, Vordenburg, vulppine, WarMechanic, waylon531, weaversam8, Willhelm53, wixoaGit, WlarusFromDaSpace, wrexbe, xRiriq, yathxyz, Ygg01, YotaXP, YuriyKiss, zach-hill, Zandario, Zap527, ZelteHonor, zerorulez, zionnBE, zlodo, ZNixian, ZoldorfTheWizard, Zumorica, Zymem diff --git a/Resources/Locale/en-US/Floof/flavors/flavor-profiles.ftl b/Resources/Locale/en-US/Floof/flavors/flavor-profiles.ftl new file mode 100644 index 00000000000..93d502c87a9 --- /dev/null +++ b/Resources/Locale/en-US/Floof/flavors/flavor-profiles.ftl @@ -0,0 +1,13 @@ +flavor-complex-anisette = like sweet anise +flavor-complex-blueballer = like fruit and unrequited love +flavor-complex-demonseed = metallic, sweet, and smooth +flavor-complex-doublecreamblaster = creamy and sweet +flavor-complex-emeraldswinger = fruity and colorful +flavor-complex-mariejulep = minty and spicy +flavor-complex-orgasmonthebeach = like a tart infection +flavor-complex-pompassion = fruity and like candy +flavor-complex-redrocket = incredibly sweet, like a rocket pop +flavor-complex-semenbomb = bitter and oleogustus +flavor-complex-semenhemorrhage = clumpy and sweet +flavor-complex-watermelonginjizz = bubbly and fruity +flavor-complex-yeolhandy = like oranges and solitude diff --git a/Resources/Locale/en-US/Floof/reagents/meta/consumable/drink/alcohol.ftl b/Resources/Locale/en-US/Floof/reagents/meta/consumable/drink/alcohol.ftl new file mode 100644 index 00000000000..8a3bf7faf5c --- /dev/null +++ b/Resources/Locale/en-US/Floof/reagents/meta/consumable/drink/alcohol.ftl @@ -0,0 +1,38 @@ +reagent-name-anisette = anisette +reagent-desc-anisette = Liquor made of anise and sugar, typically used as a sweeter form of absinthe. + +reagent-name-blueballer = blue baller +reagent-desc-blueballer = For those love-shy workers. + +reagent-name-demonseed = demon seed +reagent-desc-demonseed = Tastes like an actual demon's nethers. + +reagent-name-doublecreamblaster = double cream blaster +reagent-desc-doublecreamblaster = For twice the creaminess and twice the fun. + +reagent-name-emeraldswinger = emerald swinger +reagent-desc-emeraldswinger = A colorful cocktail, perfect for the platter at a sex party. + +reagent-name-mariejulep = marie julep +reagent-desc-mariejulep = A minty, sweet cocktail. For those who can't stomach their absinthe. + +reagent-name-orgasmonthebeach = orgasm on the beach +reagent-desc-orgasmonthebeach = A classic drink that tickles the pudendal nerve. + +reagent-name-pompassion = pom passion +reagent-desc-pompassion = An incredibly fruity drink, the smell so strong it could be a perfume. + +reagent-name-redrocket = red rocket +reagent-desc-redrocket = A sugary drink that would be very sought after in an apocalypse. Favored by canines. + +reagent-name-semenbomb = semen bomb +reagent-desc-semenbomb = A drink that will make one feel like they have a full stomach, one way or another. + +reagent-name-semenhemorrhage = semen hemorrhage +reagent-desc-semenhemorrhage = A succubi spin on a classic spooky shot. + +reagent-name-watermelonginjizz = watermelon gin jizz +reagent-desc-watermelonginjizz = Perfect for a luncheon on a warm sunny afternoon. + +reagent-name-yeolhandy = ye ol handy +reagent-desc-yeolhandy = The loner's choice, cold as their bed. diff --git a/Resources/Locale/en-US/Floof/store/uplink-catalog.ftl b/Resources/Locale/en-US/Floof/store/uplink-catalog.ftl new file mode 100644 index 00000000000..c80a39fb314 --- /dev/null +++ b/Resources/Locale/en-US/Floof/store/uplink-catalog.ftl @@ -0,0 +1,3 @@ +# Pointless +uplink-coder-socks-valid-name = Blood-red Coder Socks +uplink-coder-socks-valid-desc = These socks add onto your robustness by making you look breedable. Make trojans, not war. \ No newline at end of file diff --git a/Resources/Locale/en-US/administration/commands/stealthmin-command.ftl b/Resources/Locale/en-US/administration/commands/stealthmin-command.ftl new file mode 100644 index 00000000000..4fb5e521057 --- /dev/null +++ b/Resources/Locale/en-US/administration/commands/stealthmin-command.ftl @@ -0,0 +1,3 @@ +cmd-stealthmin-desc = Toggle whether others can see you in adminwho. +cmd-stealthmin-help = Usage: stealthmin\nUse stealthmin to toggle whether you appear in the output of the adminwho command. +cmd-stealthmin-no-console = You cannot use this command from the server console. diff --git a/Resources/Locale/en-US/administration/managers/admin-manager.ftl b/Resources/Locale/en-US/administration/managers/admin-manager.ftl index b1bbcc4c8c1..b70f550fc37 100644 --- a/Resources/Locale/en-US/administration/managers/admin-manager.ftl +++ b/Resources/Locale/en-US/administration/managers/admin-manager.ftl @@ -6,4 +6,8 @@ admin-manager-no-longer-admin-message = You are no longer an admin. admin-manager-admin-permissions-updated-message = Your admin permission have been updated. admin-manager-admin-logout-message = Admin logout: {$name} admin-manager-admin-login-message = Admin login: {$name} -admin-manager-admin-data-host-title = Host \ No newline at end of file +admin-manager-admin-data-host-title = Host +admin-manager-stealthed-message = You are now a hidden admin. +admin-manager-unstealthed-message = You are no longer hidden. +admin-manager-self-enable-stealth = {$stealthAdminName} is now hidden. +admin-manager-self-disable-stealth = {$exStealthAdminName} is no longer hidden. diff --git a/Resources/Locale/en-US/alerts/alerts.ftl b/Resources/Locale/en-US/alerts/alerts.ftl index 5f880e8dacd..ff2c0d9ee29 100644 --- a/Resources/Locale/en-US/alerts/alerts.ftl +++ b/Resources/Locale/en-US/alerts/alerts.ftl @@ -111,5 +111,8 @@ alerts-revenant-essence-desc = The power of souls. It sustains you and is used f alerts-revenant-corporeal-name = Corporeal alerts-revenant-corporeal-desc = You have manifested physically. People around you can see and hurt you. +alerts-walking-name = Walking +alerts-walking-desc = Indicates how fast you're moving. + alerts-offer-name = Offer alerts-offer-desc = Someone offers you an item. diff --git a/Resources/Locale/en-US/announcements/announcers/announcers.ftl b/Resources/Locale/en-US/announcements/announcers/announcers.ftl new file mode 100644 index 00000000000..d18857a38e2 --- /dev/null +++ b/Resources/Locale/en-US/announcements/announcers/announcers.ftl @@ -0,0 +1,5 @@ +announcer-Intern-name=Central Command +announcer-MedBot-name=Automated +announcer-Michael-name=Michael +announcer-NEIL-name=N.E.I.L. +announcer-VoxFem-name=Automated diff --git a/Resources/Locale/en-US/cargo/bounties.ftl b/Resources/Locale/en-US/cargo/bounties.ftl index 63c68de1053..b332517c70d 100644 --- a/Resources/Locale/en-US/cargo/bounties.ftl +++ b/Resources/Locale/en-US/cargo/bounties.ftl @@ -47,8 +47,24 @@ bounty-item-organs = Organ bounty-item-labeler = Hand labeler bounty-item-warm-cloth = Warm clothes bounty-item-battery = Battery -bounty-lasergun = Laser gun -bounty-food = Meat food +bounty-item-lasergun = Laser gun +bounty-item-food = Meat food +bounty-item-fruit = Fruit +bounty-item-vegetable = Vegetable +bounty-item-chili = Bowl of chili +bounty-item-rollerskates = Roller skates +bounty-item-bedsheet = Bedsheet +bounty-item-bandana = Bandana +bounty-item-steak = Steak +bounty-item-banana = Banana +bounty-item-beer = Beer +bounty-item-hi-viz-vest = Hi-viz vest +bounty-item-torch = Torch +bounty-item-medkit-box = Medkit box +bounty-item-cardboard-box = Cardboard box +bounty-item-wine = Wine bottle +bounty-item-cotton-boll = Cotton boll +bounty-item-microwave-machine-board = Microwave machine board bounty-description-artifact = NanoTrasen is in some hot water for stealing artifacts from non-spacefaring planets. Return one and we'll compensate you for it. bounty-description-baseball-bat = Baseball fever is going on at CentCom! Be a dear and ship them some baseball bats, so that management can live out their childhood dream. @@ -100,3 +116,19 @@ bounty-description-warm-cloth = The Unath construction crew freezes and is unabl bounty-description-battery = As the Arachnid settlement prepares for a solar flare, they are requesting a large shipment of power batteries. We're sending out a request for delivery. bounty-description-lasergun = The Salvage Caravan requests a large shipment of laser weapons to mop up a hive of xenomorphs. bounty-description-food = After the rat king invasion, a neighboring unathi station was left completely without food. A large meat food shipment is needed. +bounty-description-fruit = A heroic monkey helped the chaplain catch a troublemaker hiding in the chapel, and the crew wants to reward him for his good work. +bounty-description-vegetable = The new chef is a vegetarian, and botany can't keep up with their demands. We need some additional veggies to help keep things stocked. +bounty-description-chili = Today's the Centcomm Chili Cookoff, and, well, a few of us forgot to make some. Please help cover for us. +bounty-description-rollerskates = CentComm Security is proposing a new strategy for helping officers win foot pursuits. Send them a couple so they cna learn how bad an idea this is. +bounty-description-bedsheet = Someone in Atmos keeps turning down the heater, and we're all shivering in our beds. Please send us some extra sheets to stay warm. +bounty-description-bandana = Bzzzt... Transmission from prison planet OC-1001: We're... reorganizing our command structure. Send us some bandanas so we can tell gan- I mean, departments apart. +bounty-description-steak = The vegetarian cook is refusing to make us anything with meat, and the lizards are getting restless. Can you smuggle us a few steaks to keep them happy? +bounty-description-banana = Hi station! Botany won't gimme any more. They said slipping the HoS out an open airlock wasn't funny! Can you believe it? Help me out! HONK. +bounty-description-beer = Some nefarious agent has stolen every single drink in the bar. Yes, everything. Help tide us over until we can find them. +bounty-description-hi-viz-vest = The clown stole the AME controller and won't back. It's pretty dark in here. Some hi-viz vests would make seeing each other in the dark a little mroe bearable. +bounty-description-torch = The chef made all the monkeys and kobolds at once, and they rebelled and took over the cargo shuttle. They're demanding supplies and free passage to a jungle planet, and we're giving in to their demands. All they need now is a few torches. +bounty-description-medkit-box = CentComm is putting on a play set in a hospital, and needs some props. Just send us some empty medkit boxes, and the show will go on! +bounty-description-cardobard-box = "The Cardborgs Cometh" is a new play premiering tomorrow, and the costuming team is woefully unprepared. Send us some boxes to work with. +bounty-description-wine = The new librarian and the Quartermaster are falling head over heels for each other after she caught him disassembling the bookshelves for wood. Send a couple bottles of wine (Or cans, if you must) to help make the date go well. +bounty-description-cotton-boll = A massive swarm of mothroaches ate all the paper and cloth on the station. Send us some cotton to help keep our winged crewmembers fed. +bounty-description-microwave-machine-board = Mr. Giggles thought it'd be funny to stick forks in all the kitchen microwaves. Help us replace them before the chefs start making clown burgers. diff --git a/Resources/Locale/en-US/deltav/station-events/events/xeno-vent.ftl b/Resources/Locale/en-US/deltav/station-events/events/xeno-vent.ftl index eebfe1610f9..eb59c8e0a63 100644 --- a/Resources/Locale/en-US/deltav/station-events/events/xeno-vent.ftl +++ b/Resources/Locale/en-US/deltav/station-events/events/xeno-vent.ftl @@ -1 +1 @@ -station-event-xeno-vent-start-announcement = Confirmed sightings of hostile alien wildlife on the station. Personnel are advised to arm themselves, barricade doors, and defend themselves if necessary. Security is advised to eradicate the threat as soon as possible. +station-event-xeno-vents-announcement = Confirmed sightings of hostile alien wildlife on the station. Personnel are advised to arm themselves, barricade doors, and defend themselves if necessary. Security is advised to eradicate the threat as soon as possible. diff --git a/Resources/Locale/en-US/door-remote/door-remote.ftl b/Resources/Locale/en-US/door-remote/door-remote.ftl index bf2fc118619..2c4ccd08052 100644 --- a/Resources/Locale/en-US/door-remote/door-remote.ftl +++ b/Resources/Locale/en-US/door-remote/door-remote.ftl @@ -1,3 +1,12 @@ +## UI +door-remote-open-close-text = Opens and Closes Doors +door-remote-toggle-bolt-text = Toggles Bolts +door-remote-emergency-access-text = Toggles Emergency Access +door-remote-invalid-text = Invalid +door-remote-mode-label = Mode: [color=white]{$modeString}[/color] + +## Entity + door-remote-switch-state-open-close = You switch the remote to open and close doors door-remote-switch-state-toggle-bolts = You switch the remote to toggle bolts door-remote-switch-state-toggle-emergency-access = You switch the remote to toggle emergency access diff --git a/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl b/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl index f76d1c04784..23446b2b847 100644 --- a/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl +++ b/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl @@ -30,6 +30,7 @@ ui-options-ambience-volume = Ambience volume: ui-options-lobby-volume = Lobby & Round-end volume: ui-options-interface-volume = Interface volume: ui-options-ambience-max-sounds = Ambience simultaneous sounds: +ui-options-announcer-volume = Announcer volume: ui-options-lobby-music = Lobby & Round-end Music ui-options-restart-sounds = Round Restart Sounds ui-options-event-music = Event Music @@ -137,6 +138,7 @@ ui-options-function-swap-hands = Swap hands ui-options-function-move-stored-item = Move stored item ui-options-function-rotate-stored-item = Rotate stored item ui-options-function-offer-item = Offer something +ui-options-function-toggle-standing = Toggle standing ui-options-static-storage-ui = Lock storage window to hotbar ui-options-function-smart-equip-backpack = Smart-equip to backpack diff --git a/Resources/Locale/en-US/game-ticking/game-presets/preset-survival.ftl b/Resources/Locale/en-US/game-ticking/game-presets/preset-survival.ftl index 231733eabfb..0b8fa83ae8b 100644 --- a/Resources/Locale/en-US/game-ticking/game-presets/preset-survival.ftl +++ b/Resources/Locale/en-US/game-ticking/game-presets/preset-survival.ftl @@ -1,2 +1,5 @@ survival-title = Survival survival-description = No internal threats, but how long can the station survive increasingly chaotic and frequent events? + +hellshift-title = Hellshift +hellshift-description = The station rolled a "one" in a luck check. Can the crew make it to the end? diff --git a/Resources/Locale/en-US/game-ticking/game-ticker.ftl b/Resources/Locale/en-US/game-ticking/game-ticker.ftl index 9527ecb57d9..a8253dd9f35 100644 --- a/Resources/Locale/en-US/game-ticking/game-ticker.ftl +++ b/Resources/Locale/en-US/game-ticking/game-ticker.ftl @@ -25,6 +25,7 @@ game-ticker-get-info-preround-text = Hi and welcome to [color=white]Space Statio >[color=yellow]{$desc}[/color] game-ticker-no-map-selected = [color=yellow]Map not yet selected![/color] game-ticker-player-no-jobs-available-when-joining = When attempting to join to the game, no jobs were available. +game-ticker-welcome-to-the-station = Welcome to the station crew, enjoy your stay! # Displayed in chat to admins when a player joins player-join-message = Player {$name} joined. @@ -39,4 +40,4 @@ latejoin-arrivals-direction = A shuttle transferring you to your station will ar latejoin-arrivals-direction-time = A shuttle transferring you to your station will arrive in {$time}. preset-not-enough-ready-players = Can't start {$presetName}. Requires {$minimumPlayers} players but we have {$readyPlayersCount}. -preset-no-one-ready = Can't start {$presetName}. No players are ready. \ No newline at end of file +preset-no-one-ready = Can't start {$presetName}. No players are ready. diff --git a/Resources/Locale/en-US/interaction/offer-item-system.ftl b/Resources/Locale/en-US/interaction/offer-item-system.ftl index 718c94cb0e9..a0847afa308 100644 --- a/Resources/Locale/en-US/interaction/offer-item-system.ftl +++ b/Resources/Locale/en-US/interaction/offer-item-system.ftl @@ -2,12 +2,12 @@ offer-item-empty-hand = You don't have anything in your hand to give! offer-item-full-hand = Your hand isn't free to receive the item. -offer-item-try-give = You offer the {THE($item)} to {$target} -offer-item-try-give-target = {$user} offers you a {THE($item)} +offer-item-try-give = You offer {THE($item)} to {$target} +offer-item-try-give-target = {$user} offers you {THE($item)} offer-item-give = You handed {THE($item)} to {$target} offer-item-give-other = {$user} handed {THE($item)} to {$target} -offer-item-give-target = {$user} handed you a {THE($item)} +offer-item-give-target = {$user} handed you {THE($item)} offer-item-no-give = You stop offering {THE($item)} to {$target} -offer-item-no-give-target = {$user} is no longer offer a {THE($item)} to you +offer-item-no-give-target = {$user} is no longer offering {THE($item)} to you diff --git a/Resources/Locale/en-US/language/languages.ftl b/Resources/Locale/en-US/language/languages.ftl index fe4bb1df519..503fb711c09 100644 --- a/Resources/Locale/en-US/language/languages.ftl +++ b/Resources/Locale/en-US/language/languages.ftl @@ -4,6 +4,9 @@ language-Universal-description = What are you? language-GalacticCommon-name = Galactic common language-GalacticCommon-description = The standard Galatic language, most commonly used for inter-species communications and legal work. +language-SignLanguage-name = Sign Language +language-SignLanguage-description = The standard Galactic sign language, used by those that are unable to speak Galactic Common or at all. + language-Bubblish-name = Bubblish language-Bubblish-description = The language of Slimes. Being a mixture of bubbling noises and pops it's very difficult to speak for humans without the use of mechanical aids. diff --git a/Resources/Locale/en-US/language/translator.ftl b/Resources/Locale/en-US/language/translator.ftl index b2a1e9b2b8c..8070d03be29 100644 --- a/Resources/Locale/en-US/language/translator.ftl +++ b/Resources/Locale/en-US/language/translator.ftl @@ -1,8 +1,13 @@ translator-component-shutoff = The {$translator} shuts off. translator-component-turnon = The {$translator} turns on. -translator-enabled = It appears to be active. -translator-disabled = It appears to be disabled. translator-implanter-refuse = The {$implanter} has no effect on {$target}. translator-implanter-success = The {$implanter} successfully injected {$target}. translator-implanter-ready = This implanter appears to be ready to use. translator-implanter-used = This implanter seems empty. + +translator-examined-langs-understood = It can translate from: [color=green]{$languages}[/color]. +translator-examined-langs-spoken = It can translate to: [color=green]{$languages}[/color]. +translator-examined-requires-any = It requires you to know at least one of these languages: [color=yellow]{$languages}[/color]. +translator-examined-requires-all = It requires you to know all of these languages: [color=yellow]{$languages}[/color]. +translator-examined-enabled = It appears to be [color=green]active[/color]. +translator-examined-disabled = It appears to be [color=red]turned off[/color]. diff --git a/Resources/Locale/en-US/movement/laying.ftl b/Resources/Locale/en-US/movement/laying.ftl new file mode 100644 index 00000000000..f75061d6a75 --- /dev/null +++ b/Resources/Locale/en-US/movement/laying.ftl @@ -0,0 +1,7 @@ +laying-comp-lay-success-self = You lay down. +laying-comp-lay-success-other = {THE($entity)} lays down. +laying-comp-lay-fail-self = You can't lay down right now. + +laying-comp-stand-success-self = You stand up. +laying-comp-stand-success-other = {THE($entity)} stands up. +laying-comp-stand-fail-self = You can't stand up right now. diff --git a/Resources/Locale/en-US/reagents/meta/consumable/drink/juice.ftl b/Resources/Locale/en-US/reagents/meta/consumable/drink/juice.ftl index 3f968421d06..b50de6df2dd 100644 --- a/Resources/Locale/en-US/reagents/meta/consumable/drink/juice.ftl +++ b/Resources/Locale/en-US/reagents/meta/consumable/drink/juice.ftl @@ -27,6 +27,9 @@ reagent-desc-juice-orange = Both delicious AND rich in Vitamin C. What more do y reagent-name-juice-pineapple = pineapple juice reagent-desc-juice-pineapple = The delicious juice of a pineapple. +# Floofstation +reagent-name-juice-pomegranate = pomegranate juice +reagent-desc-juice-pomegranate = The sweet taste of pomegranate, minus the lust. reagent-name-juice-potato = potato juice reagent-desc-juice-potato = Juice of the potato. Bleh. diff --git a/Resources/Locale/en-US/station-events/events/anomaly-spawn.ftl b/Resources/Locale/en-US/station-events/events/anomaly-spawn.ftl index 0e4b5f6e39c..543bef949aa 100644 --- a/Resources/Locale/en-US/station-events/events/anomaly-spawn.ftl +++ b/Resources/Locale/en-US/station-events/events/anomaly-spawn.ftl @@ -1,7 +1,7 @@ -anomaly-spawn-event-announcement = Our readings have detected a dangerous interspacial anomaly. Please inform the research team of { $sighting }. +station-event-anomaly-spawn-announcement = Our readings have detected a dangerous interspacial anomaly. Please inform the research team of { $sighting }. anomaly-spawn-sighting-1 = low pulsating sounds heard throughout the station anomaly-spawn-sighting-2 = strange sources of light anomaly-spawn-sighting-3 = inexplicable shapes anomaly-spawn-sighting-4 = forms causing severe mental distress -anomaly-spawn-sighting-5 = strange effects on the local environment \ No newline at end of file +anomaly-spawn-sighting-5 = strange effects on the local environment diff --git a/Resources/Locale/en-US/station-events/events/bluespace-artifact.ftl b/Resources/Locale/en-US/station-events/events/bluespace-artifact.ftl index a2307d77b5d..59ea8a536b5 100644 --- a/Resources/Locale/en-US/station-events/events/bluespace-artifact.ftl +++ b/Resources/Locale/en-US/station-events/events/bluespace-artifact.ftl @@ -6,4 +6,4 @@ bluespace-artifact-sighting-3 = otherworldly structures bluespace-artifact-sighting-4 = incomprehensible alien objects bluespace-artifact-sighting-5 = unfamiliar objects in strange places bluespace-artifact-sighting-6 = unknown alien artifacts -bluespace-artifact-sighting-7 = explosions of light accompanied by weird sounds \ No newline at end of file +bluespace-artifact-sighting-7 = explosions of light accompanied by weird sounds diff --git a/Resources/Locale/en-US/station-events/events/cargo-gifts.ftl b/Resources/Locale/en-US/station-events/events/cargo-gifts.ftl index d669fbeff90..fd20459b5eb 100644 --- a/Resources/Locale/en-US/station-events/events/cargo-gifts.ftl +++ b/Resources/Locale/en-US/station-events/events/cargo-gifts.ftl @@ -10,14 +10,14 @@ cargo-gift-dest-janitor = Service Dept cargo-gift-dest-med = Medical Dept cargo-gift-dest-sec = Security Dept -cargo-gift-pizza-small = A small pizza party -cargo-gift-pizza-large = A large pizza party +cargo-gift-pizza-small = a small pizza party +cargo-gift-pizza-large = a large pizza party -cargo-gift-eng = Repair Materials -cargo-gift-vending = Vending machines refills -cargo-gift-cleaning = Cleaning equipment -cargo-gift-medical-supply = Medical supplies -cargo-gift-space-protection = Space Hazard Protection -cargo-gift-fire-protection = Fire Protection -cargo-gift-security-guns = Lethal Weapons -cargo-gift-security-riot = Riot Gear +cargo-gift-eng = repair Materials +cargo-gift-vending = vending machine refills +cargo-gift-cleaning = cleaning equipment +cargo-gift-medical-supply = medical supplies +cargo-gift-space-protection = space hazard protection +cargo-gift-fire-protection = fire protection +cargo-gift-security-guns = lethal weapons +cargo-gift-security-riot = riot gear diff --git a/Resources/Locale/en-US/station-events/events/gas-leak.ftl b/Resources/Locale/en-US/station-events/events/gas-leak.ftl index 18429fa58d8..230e886db47 100644 --- a/Resources/Locale/en-US/station-events/events/gas-leak.ftl +++ b/Resources/Locale/en-US/station-events/events/gas-leak.ftl @@ -1,2 +1,2 @@ -station-event-gas-leak-start-announcement = Attention crew, there is a gas leak on the station. We advise you to avoid the area and wear suit internals in the meantime. -station-event-gas-leak-end-announcement = The source of the gas leak has been fixed. Please be cautious around areas with gas remaining. +station-event-gas-leak-announcement = Attention crew, there is a gas leak on the station. We advise you to avoid the area and wear suit internals in the meantime. +station-event-gas-leak-complete-announcement = The source of the gas leak has been fixed. Please be cautious around areas with gas remaining. diff --git a/Resources/Locale/en-US/station-events/events/immovable-rod.ftl b/Resources/Locale/en-US/station-events/events/immovable-rod.ftl index 06abcc85c38..ff39923ecdd 100644 --- a/Resources/Locale/en-US/station-events/events/immovable-rod.ftl +++ b/Resources/Locale/en-US/station-events/events/immovable-rod.ftl @@ -1 +1 @@ -station-event-immovable-rod-start-announcement = High velocity unidentified object is on a collision course with the station. Impact imminent. +station-event-immovable-rod-announcement = High velocity unidentified object is on a collision course with the station. Impact imminent. diff --git a/Resources/Locale/en-US/station-events/events/ion-storm.ftl b/Resources/Locale/en-US/station-events/events/ion-storm.ftl index 28192d96637..10e8f190061 100644 --- a/Resources/Locale/en-US/station-events/events/ion-storm.ftl +++ b/Resources/Locale/en-US/station-events/events/ion-storm.ftl @@ -1,4 +1,4 @@ -station-event-ion-storm-start-announcement = Ion storm detected near the station. Please check all AI-controlled equipment for errors. +station-event-ion-storm-announcement = Ion storm detected near the station. Please check all AI-controlled equipment for errors. ion-storm-law-scrambled-number = [font="Monospace"][scramble rate=250 length={$length} chars="@@###$$&%!01"/][/font] diff --git a/Resources/Locale/en-US/station-events/events/kudzu-growth.ftl b/Resources/Locale/en-US/station-events/events/kudzu-growth.ftl index e0725deaf15..9ba4adb4a2d 100644 --- a/Resources/Locale/en-US/station-events/events/kudzu-growth.ftl +++ b/Resources/Locale/en-US/station-events/events/kudzu-growth.ftl @@ -1 +1 @@ -station-event-kudzu-growth-start-announcement = Attention crew, we have detected a Type 2 Biological Invader on-station, that poses potentially serious threat to crew productivity. We advise you to exterminate it. +station-event-kudzu-growth-announcement = Attention crew, we have detected a Type 2 Biological Invader on-station, that poses potentially serious threat to crew productivity. We advise you to exterminate it. diff --git a/Resources/Locale/en-US/station-events/events/meteor-swarm.ftl b/Resources/Locale/en-US/station-events/events/meteor-swarm.ftl index 6a96c560481..9066fb52121 100644 --- a/Resources/Locale/en-US/station-events/events/meteor-swarm.ftl +++ b/Resources/Locale/en-US/station-events/events/meteor-swarm.ftl @@ -1,2 +1,2 @@ -station-event-meteor-swarm-start-announcement = Meteors are on a collision course with the station. Brace for impact. -station-event-meteor-swarm-end-announcement = The meteor swarm has passed. Please return to your stations. +station-event-meteor-swarm-announcement = Meteors are on a collision course with the station. Brace for impact. +station-event-meteor-swarm-complete-announcement = The meteor swarm has passed. Please return to your stations. diff --git a/Resources/Locale/en-US/station-events/events/power-grid-check.ftl b/Resources/Locale/en-US/station-events/events/power-grid-check.ftl index b42dbd19db3..90ede6b9965 100644 --- a/Resources/Locale/en-US/station-events/events/power-grid-check.ftl +++ b/Resources/Locale/en-US/station-events/events/power-grid-check.ftl @@ -1,4 +1,4 @@ ## PowerGridCheck -station-event-power-grid-check-start-announcement = Abnormal activity detected in the station's powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration. -station-event-power-grid-check-end-announcement = Power has been restored to the station. We apologize for the inconvenience. \ No newline at end of file +station-event-power-grid-check-announcement = Abnormal activity detected in the station's powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration. +station-event-power-grid-check-complete-announcement = Power has been restored to the station. We apologize for the inconvenience. diff --git a/Resources/Locale/en-US/station-events/events/radiation-storm.ftl b/Resources/Locale/en-US/station-events/events/radiation-storm.ftl index c8f07c1b2ff..a3c5f48e84f 100644 --- a/Resources/Locale/en-US/station-events/events/radiation-storm.ftl +++ b/Resources/Locale/en-US/station-events/events/radiation-storm.ftl @@ -1,4 +1,4 @@ ## RadiationStorm -station-event-radiation-storm-start-announcement = High levels of radiation detected near the station. Evacuate any areas containing abnormal green energy fields. -station-event-radiation-storm-end-announcement = The radiation threat has passed. Please return to your workplaces. \ No newline at end of file +station-event-radiation-storm-announcement = High levels of radiation detected near the station. Evacuate any areas containing abnormal green energy fields. +station-event-radiation-storm-complete-announcement = The radiation threat has passed. Please return to your workplaces. diff --git a/Resources/Locale/en-US/station-events/events/solar-flare.ftl b/Resources/Locale/en-US/station-events/events/solar-flare.ftl index 5c88f82ded1..617b65739a8 100644 --- a/Resources/Locale/en-US/station-events/events/solar-flare.ftl +++ b/Resources/Locale/en-US/station-events/events/solar-flare.ftl @@ -1,2 +1,2 @@ -station-event-solar-flare-start-announcement = A solar flare has been detected near the station. Some communication channels may not function. -station-event-solar-flare-end-announcement = The solar flare ended. Communication channels no longer affected. +station-event-solar-flare-announcement = A solar flare has been detected near the station. Some communication channels may not function. +station-event-solar-flare-complete-announcement = The solar flare ended. Communication channels no longer affected. diff --git a/Resources/Locale/en-US/station-events/events/vent-clog.ftl b/Resources/Locale/en-US/station-events/events/vent-clog.ftl index f87f9e241b2..1d6ddd136b7 100644 --- a/Resources/Locale/en-US/station-events/events/vent-clog.ftl +++ b/Resources/Locale/en-US/station-events/events/vent-clog.ftl @@ -1 +1 @@ -station-event-vent-clog-start-announcement = The scrubbers network is experiencing a backpressure surge. Some ejection of contents may occur. +station-event-vent-clog-announcement = The scrubbers network is experiencing a backpressure surge. Some ejection of contents may occur. diff --git a/Resources/Locale/en-US/station-events/events/vent-critters.ftl b/Resources/Locale/en-US/station-events/events/vent-critters.ftl index 426f0c0ca1a..7c0103cd559 100644 --- a/Resources/Locale/en-US/station-events/events/vent-critters.ftl +++ b/Resources/Locale/en-US/station-events/events/vent-critters.ftl @@ -1 +1,4 @@ -station-event-vent-creatures-start-announcement = Attention. A large influx of unknown life forms have been detected residing within the station's ventilation systems. Please be rid of these creatures before it begins to affect productivity. +station-event-cockroach-migration-announcement = Attention. A large influx of unknown life forms have been detected residing within the station's ventilation systems. Please be rid of these creatures before it begins to affect productivity. +station-event-slimes-spawn-announcement = Attention. A large influx of unknown life forms have been detected residing within the station's ventilation systems. Please be rid of these creatures before it begins to affect productivity. +station-event-vent-critters-announcement = Attention. A large influx of unknown life forms have been detected residing within the station's ventilation systems. Please be rid of these creatures before it begins to affect productivity. +station-event-spider-spawn-announcement = Attention. A large influx of unknown life forms have been detected residing within the station's ventilation systems. Please be rid of these creatures before it begins to affect productivity. diff --git a/Resources/Locale/en-US/store/categories.ftl b/Resources/Locale/en-US/store/categories.ftl index 437fc03ae09..b6abc3e4288 100644 --- a/Resources/Locale/en-US/store/categories.ftl +++ b/Resources/Locale/en-US/store/categories.ftl @@ -12,6 +12,7 @@ store-category-implants = Implants store-category-job = Job store-category-armor = Armor store-category-pointless = Pointless +store-category-deception = Deception # Revenant store-category-abilities = Abilities diff --git a/Resources/Locale/en-US/store/uplink-catalog.ftl b/Resources/Locale/en-US/store/uplink-catalog.ftl index 4836a57d6b1..592cf59d2fe 100644 --- a/Resources/Locale/en-US/store/uplink-catalog.ftl +++ b/Resources/Locale/en-US/store/uplink-catalog.ftl @@ -109,6 +109,9 @@ uplink-holoclown-kit-desc = A joint venture between Cybersun and Honk.co. Contai uplink-holster-name = Shoulder Holster uplink-holster-desc = A deep shoulder holster capable of holding many types of ballistics. +uplink-chest-rig-name = Chest Rig +uplink-chest-rig-desc = Explosion-resistant tactical webbing used for holding traitor goods. + uplink-emag-name = Emag uplink-emag-desc = The business card of the syndicate, this sequencer is able to break open airlocks and tamper with a variety of station devices. Recharges automatically. diff --git a/Resources/Locale/en-US/traits/traits.ftl b/Resources/Locale/en-US/traits/traits.ftl index a23fd18f675..421dde27445 100644 --- a/Resources/Locale/en-US/traits/traits.ftl +++ b/Resources/Locale/en-US/traits/traits.ftl @@ -11,6 +11,9 @@ trait-description-Pacifist = You cannot attack or hurt any living beings. trait-name-LightweightDrunk = Lightweight Drunk trait-description-LightweightDrunk = Alcohol has a stronger effect on you +trait-name-HeavyweightDrunk = Heavyweight Drunk +trait-description-HeavyweightDrunk = Alcohols are afraid of you + trait-name-Muted = Muted trait-description-Muted = You can't speak @@ -59,3 +62,13 @@ trait-name-Thieving = Thieving trait-description-Thieving = You are deft with your hands, and talented at convincing people of their belongings. You can identify pocketed items, steal them quieter, and steal ~33% faster. + +trait-name-ForeignerLight = Foreigner (light) +trait-description-ForeignerLight = + You struggle to learn this station's primary language, and as such, cannot speak it. You can, however, comprehend what others say in that language. + To help you overcome this obstacle, you are equipped with a translator that helps you speak in this station's primary language. + +trait-name-Foreigner = Foreigner +trait-description-Foreigner = + For one reason or another you do not speak this station's primary language. + Instead, you have a translator issued to you that only you can use. diff --git a/Resources/Prototypes/Alerts/alerts.yml b/Resources/Prototypes/Alerts/alerts.yml index 24f34bc5182..75d4ca8a862 100644 --- a/Resources/Prototypes/Alerts/alerts.yml +++ b/Resources/Prototypes/Alerts/alerts.yml @@ -429,6 +429,18 @@ name: alerts-pacified-name description: alerts-pacified-desc +- type: alert + id: Walking + icons: + - sprite: /Textures/Interface/Alerts/walking.rsi + state: walking0 + - sprite: /Textures/Interface/Alerts/walking.rsi + state: walking1 + name: alerts-walking-name + description: alerts-walking-desc + minSeverity: 0 + maxSeverity: 1 + - type: alert id: Debug1 icons: diff --git a/Resources/Prototypes/Announcers/!randomAnnouncers.yml b/Resources/Prototypes/Announcers/!randomAnnouncers.yml new file mode 100644 index 00000000000..059c0295d44 --- /dev/null +++ b/Resources/Prototypes/Announcers/!randomAnnouncers.yml @@ -0,0 +1,8 @@ +- type: weightedRandom + id: RandomAnnouncers + weights: + Intern: 0 + MedBot: 0 + Michael: 1 + NEIL: 0 + VoxFem: 0 diff --git a/Resources/Prototypes/Announcers/intern.yml b/Resources/Prototypes/Announcers/intern.yml new file mode 100644 index 00000000000..0a1a4049b6d --- /dev/null +++ b/Resources/Prototypes/Announcers/intern.yml @@ -0,0 +1,134 @@ +- type: announcer + id: Intern + basePath: /Audio/Announcers/Intern + baseAudioParams: + volume: -7 + announcements: + # Communications + - id: announce # Communications console + path: comms/announce.ogg + # - id: attention # Generic alert sound # Should be different from fallback but it's very similar + # path: comms/attention.ogg + - id: commandReport # Station goal, Central Command messages, etc + collection: InternCommandReportAnnouncements + # - id: spawnAnnounceCaptain # Captain arrives on the station # TODO That system is annoyingly not modular + # path: comms/spawn_announce.ogg + # - id: war # Nuclear Operative declaration of war + # path: comms/war.ogg + # - id: nukeCodes # The station has been send nuclear activation codes + # path: comms/nuke_codes.ogg # Or command_report.ogg if you want + # - id: nukeArm # The nuke is active and ticking + # path: comms/nuke_arm.ogg + # - id: nukeDisarm # The nuke has been disarmed + # path: comms/nuke_disarm.ogg + - id: welcome # The shift has started + collection: InternWelcomeAnnouncements + + # Alert levels + # - id: alertGreen # Everything is fine + # path: alerts/green.ogg + # - id: alertBlue # Something is amiss + # path: alerts/blue.ogg + # - id: alertViolet # Viral infection or misc medical emergencies, listen to Medical + # path: alerts/violet.ogg + # - id: alertWhite # Glimmer is too high, listen to Epistemics + # path: alerts/white.ogg + # - id: alertYellow # The station is being largely damaged, listen to Engineering + # path: alerts/yellow.ogg + # - id: alertRed # Generic many things are bad, listen to Security + # path: alerts/red.ogg + # - id: alertGamma # There is a massive immediate threat to the station, listen to Central Command + # path: alerts/gamma.ogg + # - id: alertDelta # The station is being or about to be massively destroyed, run for your life + # path: alerts/delta.ogg + # - id: alertEpsilon # The station has been terminated, good luck survivors! + # path: alerts/epsilon.ogg + + # Events + ## Wizard's Den + ### Mid-Round Antagonists + # - id: ninjaHacking # A Ninja is hacking something + # path: comms/ninja_hacking.ogg + # - id: powerSinkExplosion # A power sink is about to overcharge and explode + # path: comms/powersink_explosion.ogg + ### Events + - id: anomalySpawn # An anomaly has spawned in a random place + path: events/anomaly.ogg + # - id: bluespaceArtifact # An artifact has spawned in a random place + # path: events/bluespace_artifact.ogg + # - id: bluespaceLocker # Two random lockers now share inventories + # path: events/bluespace_locker.ogg + # - id: breakerFlip # A few random APCs have been disabled, ask Engineering to fix them + # path: events/breaker_flip.ogg + # - id: bureaucraticError # Random jobs have been added, removed, or made infinite + # path: events/bureaucratic_error.ogg + # - id: clericalError # Random crew are removed from the manifest + # path: events/clerical_error.ogg + # - id: carpRift # A dragon's carp rift is active + # path: events/carp_rift.ogg + # - id: revenantSpawn # A revenant has spawned (by a prober?) + # path: events/revenant_spawn.ogg + # - id: gasLeak # A random gas is coming out of a random vent + # path: events/gas_leak.ogg + # - id: gasLeakComplete # Gas has stopped coming out of a vent + # path: events/gas_leak-complete.ogg + # - id: kudzuGrowth # Kudzu is growing in a random place + # path: events/kudzu_growth.ogg + - id: meteorSwarm # Meteors are flying at the station, stay away from windows + path: events/meteors.ogg + # - id: meteorSwarmComplete # Meteors have stopped flying at the station + # path: events/meteors-complete.ogg + # - id: mouseMigration # Several mice have appeared in a random place + # path: events/mouse_migration.ogg + # - id: cockroachMigration # Several cockroaches have appeared in a random place + # path: events/cockroach_migration.ogg + - id: powerGridCheck # The station's power is offline for some moments + path: events/power_grid_check.ogg + - id: powerGridCheckComplete # The station's power is online again + path: events/power_grid_check-complete.ogg + # - id: randomSentience # A random few animals have become sentient + # path: events/random_sentience.ogg + # - id: solarFlare # A solar flare is nearby, may mess with comms and electronics + # path: events/solar_flare.ogg + # - id: solarFlareComplete # The solar flare has passed + # path: events/solar_flare-complete.ogg + # - id: ventClog # A random reagent is coming out of a scrubber + # path: events/vent_clog.ogg + # - id: slimesSpawn # Some simple slimes are appearing in vents + # path: events/slimes_spawn.ogg + # - id: spiderSpawn # Some simple spiders are appearing in vents + # path: events/spider_spawn.ogg + # - id: immovableRodSpawn # The station is moving into an immovable rod, don't die or something, ask Engineering for help repairing it + # path: events/immovable_rod_spawn.ogg + - id: ionStorm # AI-controlled equipment are now weird, check their laws + path: events/ion_storm.ogg + ## Delta-V + - id: xenoVents # Xenomorphs are coming out of vents + path: events/aliens.ogg + ## NyanoTrasen + # - id: noosphericStorm # A large amount of glimmer has joined the station and made people psionic + # path: events/noospheric_storm.ogg + + # Shuttle + - id: shuttleCalled # The shuttle is on its way + path: shuttle/called.ogg + - id: shuttleRecalled # The shuttle is going back to Central Command + path: shuttle/recalled.ogg + - id: shuttleDock # The shuttle has arrived at the station + path: shuttle/dock.ogg + # - id: shuttleNearby # The shuttle couldn't dock, it's at a specified location + # path: shuttle/nearby.ogg + # - id: shuttleGoodLuck # The shuttle could not find its way to the station, good luck crew + # path: shuttle/good_luck.ogg + # - id: shuttleAuthAdded # One of few have added their acceptance to early launching + # path: shuttle/auth_added.ogg + # - id: shuttleAuthRevoked # One of few have revoked their acceptance to early launching + # path: shuttle/auth_revoked.ogg + # - id: shuttleAlmostLaunching # The shuttle will leave to FTL in 10 seconds + # path: shuttle/almost_launching.ogg + # - id: shuttleLeft # The shuttle has left the station + # path: shuttle/left.ogg + + # Fallback # REQUIRED + - id: fallback # Any announcement sent without a valid announcement on this announcer will use this + collection: InternAnnouncements diff --git a/Resources/Prototypes/Announcers/medbot.yml b/Resources/Prototypes/Announcers/medbot.yml new file mode 100644 index 00000000000..3b1fba49721 --- /dev/null +++ b/Resources/Prototypes/Announcers/medbot.yml @@ -0,0 +1,132 @@ +- type: announcer + id: MedBot + basePath: /Audio/Announcers/MedBot + announcements: + # Communications + - id: announce # Communications console + path: comms/announce.ogg + - id: attention # Generic alert sound # Should be different from fallback but it's very similar + path: comms/attention.ogg + - id: commandReport # Station goal, Central Command messages, etc + path: comms/command_report.ogg + # - id: spawnAnnounceCaptain # Captain arrives on the station # TODO That system is annoyingly not modular + # path: comms/spawn_announce.ogg + # - id: war # Nuclear Operative declaration of war + # path: comms/war.ogg + # - id: nukeCodes # The station has been send nuclear activation codes + # path: comms/nuke_codes.ogg # Or command_report.ogg if you want + # - id: nukeArm # The nuke is active and ticking + # path: comms/nuke_arm.ogg + # - id: nukeDisarm # The nuke has been disarmed + # path: comms/nuke_disarm.ogg + - id: welcome # The shift has started + path: comms/welcome.ogg + + # Alert levels + # - id: alertGreen # Everything is fine + # path: alerts/green.ogg + # - id: alertBlue # Something is amiss + # path: alerts/blue.ogg + # - id: alertViolet # Viral infection or misc medical emergencies, listen to Medical + # path: alerts/violet.ogg + # - id: alertWhite # Glimmer is too high, listen to Epistemics + # path: alerts/white.ogg + # - id: alertYellow # The station is being largely damaged, listen to Engineering + # path: alerts/yellow.ogg + # - id: alertRed # Generic many things are bad, listen to Security + # path: alerts/red.ogg + # - id: alertGamma # There is a massive immediate threat to the station, listen to Central Command + # path: alerts/gamma.ogg + # - id: alertDelta # The station is being or about to be massively destroyed, run for your life + # path: alerts/delta.ogg + # - id: alertEpsilon # The station has been terminated, good luck survivors! + # path: alerts/epsilon.ogg + + # Events + ## Wizard's Den + ### Mid-Round Antagonists + # - id: ninjaHacking # A Ninja is hacking something + # path: comms/ninja_hacking.ogg + # - id: powerSinkExplosion # A power sink is about to overcharge and explode + # path: comms/powersink_explosion.ogg + ### Events + - id: anomalySpawn # An anomaly has spawned in a random place + path: events/anomaly.ogg + # - id: bluespaceArtifact # An artifact has spawned in a random place + # path: events/bluespace_artifact.ogg + # - id: bluespaceLocker # Two random lockers now share inventories + # path: events/bluespace_locker.ogg + # - id: breakerFlip # A few random APCs have been disabled, ask Engineering to fix them + # path: events/breaker_flip.ogg + # - id: bureaucraticError # Random jobs have been added, removed, or made infinite + # path: events/bureaucratic_error.ogg + # - id: clericalError # Random crew are removed from the manifest + # path: events/clerical_error.ogg + # - id: carpRift # A dragon's carp rift is active + # path: events/carp_rift.ogg + # - id: revenantSpawn # A revenant has spawned (by a prober?) + # path: events/revenant_spawn.ogg + # - id: gasLeak # A random gas is coming out of a random vent + # path: events/gas_leak.ogg + # - id: gasLeakComplete # Gas has stopped coming out of a vent + # path: events/gas_leak-complete.ogg + # - id: kudzuGrowth # Kudzu is growing in a random place + # path: events/kudzu_growth.ogg + - id: meteorSwarm # Meteors are flying at the station, stay away from windows + path: events/meteors.ogg + # - id: meteorSwarmComplete # Meteors have stopped flying at the station + # path: events/meteors-complete.ogg + # - id: mouseMigration # Several mice have appeared in a random place + # path: events/mouse_migration.ogg + # - id: cockroachMigration # Several cockroaches have appeared in a random place + # path: events/cockroach_migration.ogg + - id: powerGridCheck # The station's power is offline for some moments + path: events/power_grid_check.ogg + - id: powerGridCheckComplete # The station's power is online again + path: events/power_grid_check-complete.ogg + # - id: randomSentience # A random few animals have become sentient + # path: events/random_sentience.ogg + # - id: solarFlare # A solar flare is nearby, may mess with comms and electronics + # path: events/solar_flare.ogg + # - id: solarFlareComplete # The solar flare has passed + # path: events/solar_flare-complete.ogg + # - id: ventClog # A random reagent is coming out of a scrubber + # path: events/vent_clog.ogg + # - id: slimesSpawn # Some simple slimes are appearing in vents + # path: events/slimes_spawn.ogg + # - id: spiderSpawn # Some simple spiders are appearing in vents + # path: events/spider_spawn.ogg + # - id: immovableRodSpawn # The station is moving into an immovable rod, don't die or something, ask Engineering for help repairing it + # path: events/immovable_rod_spawn.ogg + - id: ionStorm # AI-controlled equipment are now weird, check their laws + path: events/ion_storm.ogg + ## Delta-V + - id: xenoVents # Xenomorphs are coming out of vents + path: events/aliens.ogg + ## NyanoTrasen + # - id: noosphericStorm # A large amount of glimmer has joined the station and made people psionic + # path: events/noospheric_storm.ogg + + # Shuttle + - id: shuttleCalled # The shuttle is on its way + path: shuttle/called.ogg + - id: shuttleRecalled # The shuttle is going back to Central Command + path: shuttle/recalled.ogg + - id: shuttleDock # The shuttle has arrived at the station + path: shuttle/dock.ogg + # - id: shuttleNearby # The shuttle couldn't dock, it's at a specified location + # path: shuttle/nearby.ogg + # - id: shuttleGoodLuck # The shuttle could not find its way to the station, good luck crew + # path: shuttle/good_luck.ogg + # - id: shuttleAuthAdded # One of few have added their acceptance to early launching + # path: shuttle/auth_added.ogg + # - id: shuttleAuthRevoked # One of few have revoked their acceptance to early launching + # path: shuttle/auth_revoked.ogg + # - id: shuttleAlmostLaunching # The shuttle will leave to FTL in 10 seconds + # path: shuttle/almost_launching.ogg + # - id: shuttleLeft # The shuttle has left the station + # path: shuttle/left.ogg + + # Fallback # REQUIRED + - id: fallback # Any announcement sent without a valid announcement on this announcer will use this + path: fallback.ogg diff --git a/Resources/Prototypes/Announcers/michael.yml b/Resources/Prototypes/Announcers/michael.yml new file mode 100644 index 00000000000..adeb4f3b853 --- /dev/null +++ b/Resources/Prototypes/Announcers/michael.yml @@ -0,0 +1,134 @@ +- type: announcer + id: Michael + basePath: /Audio/Announcers/Michael + announcements: + # Communications + # - id: announce # Communications console + # path: comms/announce.ogg + - id: attention # Generic alert sound # Should be different from fallback but it's very similar + path: comms/attention.ogg + # - id: commandReport # Station goal, Central Command messages, etc + # path: comms/command_report.ogg + # - id: spawnAnnounceCaptain # Captain arrives on the station # TODO That system is annoyingly not modular + # path: comms/spawn_announce.ogg + # - id: war # Nuclear Operative declaration of war + # path: comms/war.ogg + # - id: nukeCodes # The station has been send nuclear activation codes + # path: comms/nuke_codes.ogg # Or command_report.ogg if you want + # - id: nukeArm # The nuke is active and ticking + # path: comms/nuke_arm.ogg + # - id: nukeDisarm # The nuke has been disarmed + # path: comms/nuke_disarm.ogg + - id: welcome # The shift has started + path: comms/welcome.ogg + + # Alert levels + - id: alertgreen # Everything is fine + path: alerts/green.ogg + - id: alertblue # Something is amiss + path: alerts/blue.ogg + - id: alertviolet # Viral infection or misc medical emergencies, listen to Medical + path: alerts/violet.ogg + - id: alertwhite # Glimmer is too high, listen to Epistemics + path: alerts/white.ogg + - id: alertyellow # The station is being largely damaged, listen to Engineering + path: alerts/yellow.ogg + - id: alertred # Generic many things are bad, listen to Security + path: alerts/red.ogg + - id: alertgamma # There is a massive immediate threat to the station, listen to Central Command + path: alerts/gamma.ogg + - id: alertdelta # The station is being or about to be massively destroyed, run for your life + path: alerts/delta.ogg + - id: alertepsilon # The station has been terminated, good luck survivors! + path: alerts/epsilon.ogg + audioParams: + volume: -3 + + # Events + ## Wizard's Den + ### Mid-Round Antagonists + # - id: ninjaHacking # A Ninja is hacking something + # path: comms/ninja_hacking.ogg + # - id: powerSinkExplosion # A power sink is about to overcharge and explode + # path: comms/powersink_explosion.ogg + ### Events + # - id: anomalySpawn # An anomaly has spawned in a random place + # path: events/anomaly.ogg + # - id: bluespaceArtifact # An artifact has spawned in a random place + # path: events/bluespace_artifact.ogg + # - id: bluespaceLocker # Two random lockers now share inventories + # path: events/bluespace_locker.ogg + # - id: breakerFlip # A few random APCs have been disabled, ask Engineering to fix them + # path: events/breaker_flip.ogg + - id: bureaucraticError # Random jobs have been added, removed, or made infinite + path: events/bureaucratic_error.ogg + # - id: clericalError # Random crew are removed from the manifest + # path: events/clerical_error.ogg + # - id: carpRift # A dragon's carp rift is active + # path: events/carp_rift.ogg + # - id: revenantSpawn # A revenant has spawned (by a prober?) + # path: events/revenant_spawn.ogg + - id: gasLeak # A random gas is coming out of a random vent + path: events/gas_leak.ogg + # - id: gasLeakComplete # Gas has stopped coming out of a vent + # path: events/gas_leak-complete.ogg + - id: kudzuGrowth # Kudzu is growing in a random place + path: events/kudzu_growth.ogg + - id: meteorSwarm # Meteors are flying at the station, stay away from windows + path: events/meteors.ogg + # - id: meteorSwarmComplete # Meteors have stopped flying at the station + # path: events/meteors-complete.ogg + # - id: mouseMigration # Several mice have appeared in a random place + # path: events/mouse_migration.ogg + # - id: cockroachMigration # Several cockroaches have appeared in a random place + # path: events/cockroach_migration.ogg + - id: powerGridCheck # The station's power is offline for some moments + path: events/power_grid_check.ogg + - id: powerGridCheckComplete # The station's power is online again + path: events/power_grid_check-complete.ogg + # - id: randomSentience # A random few animals have become sentient + # path: events/random_sentience.ogg + # - id: solarFlare # A solar flare is nearby, may mess with comms and electronics + # path: events/solar_flare.ogg + # - id: solarFlareComplete # The solar flare has passed + # path: events/solar_flare-complete.ogg + - id: ventClog # A random reagent is coming out of a scrubber + path: events/vent_clog.ogg + # - id: slimesSpawn # Some simple slimes are appearing in vents + # path: events/slimes_spawn.ogg + # - id: spiderSpawn # Some simple spiders are appearing in vents + # path: events/spider_spawn.ogg + # - id: immovableRodSpawn # The station is moving into an immovable rod, don't die or something, ask Engineering for help repairing it + # path: events/immovable_rod_spawn.ogg + # - id: ionStorm # AI-controlled equipment are now weird, check their laws + # path: events/ion_storm.ogg + ## Delta-V + - id: xenoVents # Xenomorphs are coming out of vents + path: events/aliens.ogg + ## NyanoTrasen + - id: noosphericStorm # A large amount of glimmer has joined the station and made people psionic + path: events/noospheric_storm.ogg + + # Shuttle + - id: shuttleCalled # The shuttle is on its way + path: shuttle/called.ogg + - id: shuttleRecalled # The shuttle is going back to Central Command + path: shuttle/recalled.ogg + - id: shuttleDock # The shuttle has arrived at the station + path: shuttle/dock.ogg + # - id: shuttleNearby # The shuttle couldn't dock, it's at a specified location + # path: shuttle/nearby.ogg + # - id: shuttleGoodLuck # The shuttle could not find its way to the station, good luck crew + # path: shuttle/good_luck.ogg + # - id: shuttleAuthAdded # One of few have added their acceptance to early launching + # path: shuttle/auth_added.ogg + # - id: shuttleAuthRevoked # One of few have revoked their acceptance to early launching + # path: shuttle/auth_revoked.ogg + # - id: shuttleAlmostLaunching # The shuttle will leave to FTL in 10 seconds + # path: shuttle/almost_launching.ogg + # - id: shuttleLeft # The shuttle has left the station + # path: shuttle/left.ogg + + # Fallback # REQUIRED + - id: fallback # Any announcement sent without a valid announcement on this announcer will use this + path: fallback.ogg diff --git a/Resources/Prototypes/Announcers/neil.yml b/Resources/Prototypes/Announcers/neil.yml new file mode 100644 index 00000000000..1db1828ed11 --- /dev/null +++ b/Resources/Prototypes/Announcers/neil.yml @@ -0,0 +1,134 @@ +- type: announcer + id: NEIL + basePath: /Audio/Announcers/NEIL + baseAudioParams: + volume: -3 + announcements: + # Communications + - id: announce # Communications console + path: comms/announce.ogg + - id: attention # Generic alert sound # Should be different from fallback but it's very similar + path: comms/attention.ogg + # - id: commandReport # Station goal, Central Command messages, etc + # path: comms/command_report.ogg + # - id: spawnAnnounceCaptain # Captain arrives on the station # TODO That system is annoyingly not modular + # path: comms/spawn_announce.ogg + # - id: war # Nuclear Operative declaration of war + # path: comms/war.ogg + # - id: nukeCodes # The station has been send nuclear activation codes + # path: comms/nuke_codes.ogg # Or command_report.ogg if you want + # - id: nukeArm # The nuke is active and ticking + # path: comms/nuke_arm.ogg + # - id: nukeDisarm # The nuke has been disarmed + # path: comms/nuke_disarm.ogg + - id: welcome # The shift has started + path: comms/welcome.ogg + + # Alert levels + - id: alertGreen # Everything is fine + path: alerts/green.ogg + - id: alertBlue # Something is amiss + path: alerts/blue.ogg + - id: alertViolet # Viral infection or misc medical emergencies, listen to Medical + path: alerts/violet.ogg + - id: alertWhite # Glimmer is too high, listen to Epistemics + path: alerts/white.ogg + - id: alertYellow # The station is being largely damaged, listen to Engineering + path: alerts/yellow.ogg + - id: alertRed # Generic many things are bad, listen to Security + path: alerts/red.ogg + - id: alertGamma # There is a massive immediate threat to the station, listen to Central Command + path: alerts/gamma.ogg + - id: alertDelta # The station is being or about to be massively destroyed, run for your life + path: alerts/delta.ogg + - id: alertEpsilon # The station has been terminated, good luck survivors! + path: alerts/epsilon.ogg + + # Events + ## Wizard's Den + ### Mid-Round Antagonists + # - id: ninjaHacking # A Ninja is hacking something + # path: comms/ninja_hacking.ogg + # - id: powerSinkExplosion # A power sink is about to overcharge and explode + # path: comms/powersink_explosion.ogg + ### Events + - id: anomalySpawn # An anomaly has spawned in a random place + path: events/anomaly.ogg + # - id: bluespaceArtifact # An artifact has spawned in a random place + # path: events/bluespace_artifact.ogg + # - id: bluespaceLocker # Two random lockers now share inventories + # path: events/bluespace_locker.ogg + - id: breakerFlip # A few random APCs have been disabled, ask Engineering to fix them + path: events/breaker_flip.ogg + - id: bureaucraticError # Random jobs have been added, removed, or made infinite + path: events/bureaucratic_error.ogg + # - id: clericalError # Random crew are removed from the manifest + # path: events/clerical_error.ogg + # - id: carpRift # A dragon's carp rift is active + # path: events/carp_rift.ogg + # - id: revenantSpawn # A revenant has spawned (by a prober?) + # path: events/revenant_spawn.ogg + - id: gasLeak # A random gas is coming out of a random vent + path: events/gas_leak.ogg + # - id: gasLeakComplete # Gas has stopped coming out of a vent + # path: events/gas_leak-complete.ogg + - id: kudzuGrowth # Kudzu is growing in a random place + path: events/kudzu_growth.ogg + - id: meteorSwarm # Meteors are flying at the station, stay away from windows + path: events/meteors.ogg + # - id: meteorSwarmComplete # Meteors have stopped flying at the station + # path: events/meteors-complete.ogg + # - id: mouseMigration # Several mice have appeared in a random place + # path: events/mouse_migration.ogg + # - id: cockroachMigration # Several cockroaches have appeared in a random place + # path: events/cockroach_migration.ogg + - id: powerGridCheck # The station's power is offline for some moments + path: events/power_grid_check.ogg + - id: powerGridCheckComplete # The station's power is online again + path: events/power_grid_check-complete.ogg + # - id: randomSentience # A random few animals have become sentient + # path: events/random_sentience.ogg + # - id: solarFlare # A solar flare is nearby, may mess with comms and electronics + # path: events/solar_flare.ogg + # - id: solarFlareComplete # The solar flare has passed + # path: events/solar_flare-complete.ogg + - id: ventClog # A random reagent is coming out of a scrubber + path: events/vent_clog.ogg + # - id: slimesSpawn # Some simple slimes are appearing in vents + # path: events/slimes_spawn.ogg + # - id: spiderSpawn # Some simple spiders are appearing in vents + # path: events/spider_spawn.ogg + # - id: immovableRodSpawn # The station is moving into an immovable rod, don't die or something, ask Engineering for help repairing it + # path: events/immovable_rod_spawn.ogg + - id: ionStorm # AI-controlled equipment are now weird, check their laws + path: events/ion_storm.ogg + ## Delta-V + # - id: xenoVents # Xenomorphs are coming out of vents + # path: events/xeno_vents.ogg + ## NyanoTrasen + - id: noosphericStorm # A large amount of glimmer has joined the station and made people psionic + path: events/noospheric_storm.ogg + + # Shuttle + - id: shuttleCalled # The shuttle is on its way + path: shuttle/called.ogg + - id: shuttleRecalled # The shuttle is going back to Central Command + path: shuttle/recalled.ogg + - id: shuttleDock # The shuttle has arrived at the station + path: shuttle/dock.ogg + # - id: shuttleNearby # The shuttle couldn't dock, it's at a specified location + # path: shuttle/nearby.ogg + # - id: shuttleGoodLuck # The shuttle could not find its way to the station, good luck crew + # path: shuttle/good_luck.ogg + # - id: shuttleAuthAdded # One of few have added their acceptance to early launching + # path: shuttle/auth_added.ogg + # - id: shuttleAuthRevoked # One of few have revoked their acceptance to early launching + # path: shuttle/auth_revoked.ogg + # - id: shuttleAlmostLaunching # The shuttle will leave to FTL in 10 seconds + # path: shuttle/almost_launching.ogg + # - id: shuttleLeft # The shuttle has left the station + # path: shuttle/left.ogg + + # Fallback # REQUIRED + - id: fallback # Any announcement sent without a valid announcement on this announcer will use this + path: fallback.ogg diff --git a/Resources/Prototypes/Announcers/template b/Resources/Prototypes/Announcers/template new file mode 100644 index 00000000000..8cd007956de --- /dev/null +++ b/Resources/Prototypes/Announcers/template @@ -0,0 +1,158 @@ +# This should be getting auto detected as YML if you're using VSCode +# If it's not, you can probably manually set the language mode to YML somehow +# Or just change the filename to `template.yml` temporarily +# The game will complain if I name it template.yaml in an attempt to not load it +# +# This file contains instructions for everything you can do with the announcer system +# This also contains every "needed" announcement for any new announcers and descriptions for what they are +# +# Avoid renaming announcement audio files to keep consistency between announcers for workspace searching +# Keep comments on specific announcements and follow this same formatting for every announcer +# If you don't have an announcement audio, comment the announcemt type instead of deleting it + +- type: announcer + id: Announcer # Localized as "announcer--name" in chat + basePath: /Audio/Codebase/Announcements/Announcer # Where to start looking for audio files + baseAudioParams: # Default audio parameters for all announcements, all options explained in the template announcement + volume: -7 # If this announcer is really loud, lower it to match the others' volume #? Default is 3 + announcements: # List of all announcements this announcer has audio for #! Comment out unused announcements, don't remove them + # Template, delete this in real announcer files + - id: template # Lowercase of the event ID, add "Complete" to the end for post-event announcements (endings) + ignoreBasePath: false # If true, it will ignore the basePath and use the path as is + path: template.ogg # Path to the file relative to basePath/, named with snake_case except for "-complete" + collection: AnnouncerTemplateAnnouncements # Collection of audios to randomly use for this, will ignore path if set #! Ignores basePath automatically + message: announcer-announcement-template # Localization key for the announcement message to use instead of the default one # NOTE this does not pass through previous loc args yet + audioParams: # Overrides baseAudioParams entirely for this specific announcement, numbers are all floats + volume: 3 # We don't want individual announcement volumes to vary too much, normalize them with this #? Default is 3 + pitch: 1 #? Default is 1 + playOffsetSeconds: 0 # How many seconds into the audio to start from #? Default is 0 + variation: 0 # Probably wouldn't sound very good unless very low, 0.15 or less is normally used #? Default is 0 + + # Communications + - id: announce # Communications console + path: comms/announce.ogg + - id: attention # Generic alert sound # Should be different from fallback but it's very similar + path: comms/attention.ogg + - id: commandReport # Station goal, Central Command messages, etc + path: comms/command_report.ogg + - id: spawnAnnounce # Captain join # TODO That system is annoyingly not modular + path: comms/spawn_announce.ogg + - id: war # Nuclear Operative declaration of war + path: comms/war.ogg + - id: nukeCodes # The station has been send nuclear activation codes + path: comms/nuke_codes.ogg # Or command_report.ogg if you want + - id: nukeArm # The nuke is active and ticking + path: comms/nuke_arm.ogg + - id: nukeDisarm # The nuke has been disarmed + path: comms/nuke_disarm.ogg + - id: welcome # The shift has started + path: comms/welcome.ogg + + # Alert levels + - id: alertGreen # Everything is fine + path: alerts/green.ogg + - id: alertBlue # Something is amiss + path: alerts/blue.ogg + - id: alertViolet # Viral infection or misc medical emergencies, listen to Medical + path: alerts/violet.ogg + - id: alertWhite # Glimmer is too high, listen to Epistemics + path: alerts/white.ogg + - id: alertYellow # The station is being largely damaged, listen to Engineering + path: alerts/yellow.ogg + - id: alertRed # Generic many things are bad, listen to Security + path: alerts/red.ogg + - id: alertGamma # There is a massive immediate threat to the station, listen to Central Command + path: alerts/gamma.ogg + - id: alertDelta # The station is being or about to be massively destroyed, run for your life + path: alerts/delta.ogg + - id: alertEpsilon # The station has been terminated, good luck survivors! + path: alerts/epsilon.ogg + + # Events + ## Wizard's Den + ### Mid-Round Antagonists + - id: ninjaHacking # A Ninja is hacking something + path: comms/ninja_hacking.ogg + - id: powersinkExplosion # A power sink is about to overcharge and explode + path: comms/powersink_explosion.ogg + ### Events + - id: anomalySpawn # An anomaly has spawned in a random place + path: events/anomaly.ogg + - id: bluespaceArtifact # An artifact has spawned in a random place + path: events/bluespace_artifact.ogg + - id: bluespaceLocker # Two random lockers now share inventories + path: events/bluespace_locker.ogg + - id: breakerFlip # A few random APCs have been disabled, ask Engineering to fix them + path: events/breaker_flip.ogg + - id: bureaucraticError # Random jobs have been added, removed, or made infinite + path: events/bureaucratic_error.ogg + - id: clericalError # Random crew are removed from the manifest + path: events/clerical_error.ogg + - id: carpRift # A dragon's carp rift is active + path: events/carp_rift.ogg + - id: revenantSpawn # A revenant has spawned (by a prober?) + path: events/revenant_spawn.ogg + - id: gasLeak # A random gas is coming out of a random vent + path: events/gas_leak.ogg + - id: gasLeakComplete # Gas has stopped coming out of a vent + path: events/gas_leak-complete.ogg + - id: kudzuGrowth # Kudzu is growing in a random place + path: events/kudzu_growth.ogg + - id: meteorSwarm # Meteors are flying at the station, stay away from windows + path: events/meteors.ogg + - id: meteorSwarmComplete # Meteors have stopped flying at the station + path: events/meteors-complete.ogg + - id: mouseMigration # Several mice have appeared in a random place + path: events/mouse_migration.ogg + - id: cockroachMigration # Several cockroaches have appeared in a random place + path: events/cockroach_migration.ogg + - id: powerGridCheck # The station's power is offline for some moments + path: events/power_grid_check.ogg + - id: powerGridCheckComplete # The station's power is online again + path: events/power_grid_check-complete.ogg + - id: randomSentience # A random few animals have become sentient + path: events/random_sentience.ogg + - id: solarFlare # A solar flare is nearby, may mess with comms and electronics + path: events/solar_flare.ogg + - id: solarFlareComplete # The solar flare has passed + path: events/solar_flare-complete.ogg + - id: ventClog # A random reagent is coming out of a scrubber + path: events/vent_clog.ogg + - id: slimesSpawn # Some simple slimes are appearing in vents + path: events/slimes_spawn.ogg + - id: spiderSpawn # Some simple spiders are appearing in vents + path: events/spider_spawn.ogg + - id: immovableRodSpawn # The station is moving into an immovable rod, don't die or something, ask Engineering for help repairing it + path: events/immovable_rod_spawn.ogg + - id: ionStorm # AI-controlled equipment are now weird, check their laws + path: events/ion_storm.ogg + ## Delta-V + - id: xenoVents # Xenomorphs are coming out of vents + path: events/xeno_vents.ogg + ## NyanoTrasen + - id: noosphericStorm # A large amount of glimmer has joined the station and made people psionic + path: events/noospheric_storm.ogg + + # Shuttle + - id: shuttleCalled # The shuttle is on its way + path: shuttle/called.ogg + - id: shuttleRecalled # The shuttle is going back to Central Command + path: shuttle/recalled.ogg + - id: shuttleDock # The shuttle has arrived at the station + path: shuttle/dock.ogg + - id: shuttleNearby # The shuttle couldn't dock, it's at a specified location + path: shuttle/nearby.ogg + - id: shuttleGoodLuck # The shuttle could not find its way to the station, good luck crew + path: shuttle/good_luck.ogg + - id: shuttleAuthAdded # One of few have added their acceptance to early launching + path: shuttle/auth_added.ogg + - id: shuttleAuthRevoked # One of few have revoked their acceptance to early launching + path: shuttle/auth_revoked.ogg + - id: shuttleAlmostLaunching # The shuttle will leave to FTL in 10 seconds + path: shuttle/almost_launching.ogg + - id: shuttleLeft # The shuttle has left the station + path: shuttle/left.ogg + + # Fallback # REQUIRED + - id: fallback # Any announcement sent without a valid announcement on this announcer will use this + path: fallback.ogg diff --git a/Resources/Prototypes/Announcers/voxfem.yml b/Resources/Prototypes/Announcers/voxfem.yml new file mode 100644 index 00000000000..bcf518e0a2c --- /dev/null +++ b/Resources/Prototypes/Announcers/voxfem.yml @@ -0,0 +1,132 @@ +- type: announcer + id: VoxFem + basePath: /Audio/Announcers/VoxFem + announcements: + # Communications + - id: announce # Communications console + path: comms/announce.ogg + - id: attention # Generic alert sound # Should be different from fallback but it's very similar + path: comms/attention.ogg + - id: commandReport # Station goal, Central Command messages, etc + path: comms/command_report.ogg + # - id: spawnAnnounceCaptain # Captain arrives on the station # TODO That system is annoyingly not modular + # path: comms/spawn_announce.ogg + # - id: war # Nuclear Operative declaration of war + # path: comms/war.ogg + # - id: nukeCodes # The station has been send nuclear activation codes + # path: comms/nuke_codes.ogg # Or command_report.ogg if you want + # - id: nukeArm # The nuke is active and ticking + # path: comms/nuke_arm.ogg + # - id: nukeDisarm # The nuke has been disarmed + # path: comms/nuke_disarm.ogg + - id: welcome # The shift has started + path: comms/welcome.ogg + + # Alert levels + # - id: alertGreen # Everything is fine + # path: alerts/green.ogg + # - id: alertBlue # Something is amiss + # path: alerts/blue.ogg + # - id: alertViolet # Viral infection or misc medical emergencies, listen to Medical + # path: alerts/violet.ogg + # - id: alertWhite # Glimmer is too high, listen to Epistemics + # path: alerts/white.ogg + # - id: alertYellow # The station is being largely damaged, listen to Engineering + # path: alerts/yellow.ogg + # - id: alertRed # Generic many things are bad, listen to Security + # path: alerts/red.ogg + # - id: alertGamma # There is a massive immediate threat to the station, listen to Central Command + # path: alerts/gamma.ogg + # - id: alertDelta # The station is being or about to be massively destroyed, run for your life + # path: alerts/delta.ogg + # - id: alertEpsilon # The station has been terminated, good luck survivors! + # path: alerts/epsilon.ogg + + # Events + ## Wizard's Den + ### Mid-Round Antagonists + - id: ninjaHacking # A Ninja is hacking something + path: comms/ninja_hacking.ogg + - id: powerSinkExplosion # A power sink is about to overcharge and explode + path: comms/powersink_explosion.ogg + ### Events + # - id: anomalySpawn # An anomaly has spawned in a random place + # path: events/anomaly.ogg + # - id: bluespaceArtifact # An artifact has spawned in a random place + # path: events/bluespace_artifact.ogg + # - id: bluespaceLocker # Two random lockers now share inventories + # path: events/bluespace_locker.ogg + # - id: breakerFlip # A few random APCs have been disabled, ask Engineering to fix them + # path: events/breaker_flip.ogg + # - id: bureaucraticError # Random jobs have been added, removed, or made infinite + # path: events/bureaucratic_error.ogg + # - id: clericalError # Random crew are removed from the manifest + # path: events/clerical_error.ogg + # - id: carpRift # A dragon's carp rift is active + # path: events/carp_rift.ogg + # - id: revenantSpawn # A revenant has spawned (by a prober?) + # path: events/revenant_spawn.ogg + # - id: gasLeak # A random gas is coming out of a random vent + # path: events/gas_leak.ogg + # - id: gasLeakComplete # Gas has stopped coming out of a vent + # path: events/gas_leak-complete.ogg + # - id: kudzuGrowth # Kudzu is growing in a random place + # path: events/kudzu_growth.ogg + - id: meteorSwarm # Meteors are flying at the station, stay away from windows + path: events/meteors.ogg + # - id: meteorSwarmComplete # Meteors have stopped flying at the station + # path: events/meteors-complete.ogg + # - id: mouseMigration # Several mice have appeared in a random place + # path: events/mouse_migration.ogg + # - id: cockroachMigration # Several cockroaches have appeared in a random place + # path: events/cockroach_migration.ogg + - id: powerGridCheck # The station's power is offline for some moments + path: events/power_grid_check.ogg + - id: powerGridCheckComplete # The station's power is online again + path: events/power_grid_check-complete.ogg + # - id: randomSentience # A random few animals have become sentient + # path: events/random_sentience.ogg + # - id: solarFlare # A solar flare is nearby, may mess with comms and electronics + # path: events/solar_flare.ogg + # - id: solarFlareComplete # The solar flare has passed + # path: events/solar_flare-complete.ogg + # - id: ventClog # A random reagent is coming out of a scrubber + # path: events/vent_clog.ogg + # - id: slimesSpawn # Some simple slimes are appearing in vents + # path: events/slimes_spawn.ogg + # - id: spiderSpawn # Some simple spiders are appearing in vents + # path: events/spider_spawn.ogg + # - id: immovableRodSpawn # The station is moving into an immovable rod, don't die or something, ask Engineering for help repairing it + # path: events/immovable_rod_spawn.ogg + - id: ionStorm # AI-controlled equipment are now weird, check their laws + path: events/ion_storm.ogg + ## Delta-V + - id: xenoVents # Xenomorphs are coming out of vents + path: events/aliens.ogg + ## NyanoTrasen + # - id: noosphericStorm # A large amount of glimmer has joined the station and made people psionic + # path: events/noospheric_storm.ogg + + # Shuttle + - id: shuttleCalled # The shuttle is on its way + path: shuttle/called.ogg + - id: shuttleRecalled # The shuttle is going back to Central Command + path: shuttle/recalled.ogg + - id: shuttleDock # The shuttle has arrived at the station + path: shuttle/dock.ogg + # - id: shuttleNearby # The shuttle couldn't dock, it's at a specified location + # path: shuttle/nearby.ogg + # - id: shuttleGoodLuck # The shuttle could not find its way to the station, good luck crew + # path: shuttle/good_luck.ogg + # - id: shuttleAuthAdded # One of few have added their acceptance to early launching + # path: shuttle/auth_added.ogg + # - id: shuttleAuthRevoked # One of few have revoked their acceptance to early launching + # path: shuttle/auth_revoked.ogg + # - id: shuttleAlmostLaunching # The shuttle will leave to FTL in 10 seconds + # path: shuttle/almost_launching.ogg + # - id: shuttleLeft # The shuttle has left the station + # path: shuttle/left.ogg + + # Fallback # REQUIRED + - id: fallback # Any announcement sent without a valid announcement on this announcer will use this + path: fallback.ogg diff --git a/Resources/Prototypes/Catalog/Bounties/bounties.yml b/Resources/Prototypes/Catalog/Bounties/bounties.yml index 62a3a4162f3..c8c35aabfe4 100644 --- a/Resources/Prototypes/Catalog/Bounties/bounties.yml +++ b/Resources/Prototypes/Catalog/Bounties/bounties.yml @@ -347,11 +347,11 @@ - type: cargoBounty id: BountyRadio - reward: 7500 + reward: 6500 description: bounty-description-radio entries: - name: bounty-item-radio - amount: 12 + amount: 7 whitelist: components: - Headset @@ -536,7 +536,7 @@ description: bounty-description-lasergun idPrefix: IV entries: - - name: bounty-lasergun + - name: bounty-item-lasergun amount: 6 whitelist: components: @@ -548,8 +548,185 @@ description: bounty-description-food idPrefix: UNTH entries: - - name: bounty-food + - name: bounty-item-food amount: 30 whitelist: tags: - Meat + +- type: cargoBounty + id: BountyFruit + reward: 5000 + description: bounty-description-fruit + entries: + - name: bounty-item-fruit + amount: 12 + whitelist: + tags: + - Fruit + +- type: cargoBounty + id: BountyVegetable + reward: 6000 + description: bounty-description-vegetable + entries: + - name: bounty-item-vegetable + amount: 14 + whitelist: + tags: + - Vegetable + +- type: cargoBounty + id: BountyChili + reward: 5555 + description: bounty-description-chili + entries: + - name: bounty-item-chili + amount: 3 + whitelist: + tags: + - ChiliBowl + +- type: cargoBounty + id: BountyRollerskates + reward: 6500 + description: bounty-description-rollerskates + entries: + - name: bounty-item-rollerskates + amount: 2 + whitelist: + components: + - Skates + +- type: cargoBounty + id: BountyBedsheet + reward: 4100 + description: bounty-description-bedsheet + entries: + - name: bounty-item-bedsheet + amount: 5 + whitelist: + tags: + - Bedsheet + +- type: cargoBounty + id: BountyBandana + reward: 4000 + description: bounty-description-bandana + entries: + - name: bounty-item-bandana + amount: 7 + whitelist: + tags: + - Bandana + +- type: cargoBounty + id: BountySteak + reward: 3200 + description: bounty-description-steak + entries: + - name: bounty-item-steak + amount: 4 + whitelist: + tags: + - Steak + +- type: cargoBounty + id: BountyBanana + reward: 6009 + description: bounty-description-banana + entries: + - name: bounty-item-banana + amount: 9 + whitelist: + tags: + - Banana + +- type: cargoBounty + id: BountyBeer + reward: 3100 + description: bounty-description-beer + entries: + - name: bounty-item-beer + amount: 6 + whitelist: + tags: + - Beer + +- type: cargoBounty + id: BountyHiVizVest + reward: 3030 + description: bounty-description-hi-viz-vest + entries: + - name: bounty-item-hi-viz-vest + amount: 3 + whitelist: + tags: + - HiViz + +- type: cargoBounty + id: BountyTorch + reward: 2220 + description: bounty-description-torch + entries: + - name: bounty-item-torch + amount: 6 + whitelist: + tags: + - Torch + +- type: cargoBounty + id: BountyMedkitBox + reward: 2300 + description: bounty-description-medkit-box + entries: + - name: bounty-item-medkit-box + amount: 4 + whitelist: + tags: + - Medkit + +- type: cargoBounty + id: BountyCardboardBox + reward: 1500 + description: bounty-description-cardobard-box + entries: + - name: bounty-item-cardboard-box + amount: 12 + whitelist: + tags: + - BoxCardboard + +- type: cargoBounty + id: BountyWine + reward: 3000 + description: bounty-description-wine + entries: + - name: bounty-item-wine + amount: 2 + whitelist: + tags: + - Wine + +- type: cargoBounty + id: BountyCottonBoll + reward: 8600 + description: bounty-description-cotton-boll + entries: + - name: bounty-item-cotton-boll + amount: 9 + whitelist: + tags: + - CottonBoll + +- type: cargoBounty + id: BountyMicrowaveMachineBoard + reward: 4000 + description: bounty-description-microwave-machine-board + entries: + - name: bounty-item-microwave-machine-board + amount: 2 + whitelist: + tags: + - MicrowaveMachineBoard + diff --git a/Resources/Prototypes/Catalog/Fills/Boxes/general.yml b/Resources/Prototypes/Catalog/Fills/Boxes/general.yml index 7840602362f..e4181d27a21 100644 --- a/Resources/Prototypes/Catalog/Fills/Boxes/general.yml +++ b/Resources/Prototypes/Catalog/Fills/Boxes/general.yml @@ -14,6 +14,15 @@ - 0,0,2,2 - type: Sprite state: box + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/cardboardbox_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/cardboardbox_drop.ogg + - type: EmitSoundOnLand + sound: /Audio/SimpleStation14/Items/Handling/cardboardbox_drop.ogg + - type: Tag + tags: + - BoxCardboard - type: entity name: mousetrap box diff --git a/Resources/Prototypes/Catalog/Fills/Crates/fun.yml b/Resources/Prototypes/Catalog/Fills/Crates/fun.yml index cc5e3b1d174..26d0f47315f 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/fun.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/fun.yml @@ -30,6 +30,7 @@ amount: 2 - id: PlushieArachind - id: PlushiePenguin + - id: PlushieArachne - type: entity id: CrateFunLizardPlushieBulk diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/boozeomat.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/boozeomat.yml index bde9293f2af..91f1727ef00 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/boozeomat.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/boozeomat.yml @@ -9,12 +9,14 @@ DrinkShaker: 5 CustomDrinkJug: 2 #to allow for custom drinks in the soda/booze dispensers DrinkAbsintheBottleFull: 2 + DrinkAnisetteBottleFull: 2 # Floofstation DrinkAleBottleFull: 5 DrinkBeerBottleFull: 5 DrinkBlueCuracaoBottleFull: 2 DrinkCognacBottleFull: 4 DrinkColaBottleFull: 4 DrinkCreamCarton: 5 + DrinkCumBottleFull: 1 # Floofstation DrinkGinBottleFull: 3 DrinkGildlagerBottleFull: 2 #if champagne gets less because its premium, then gildlager should match this and have two DrinkGrenadineBottleFull: 2 diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml index 328ace7ba15..63a748e082d 100644 --- a/Resources/Prototypes/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/Catalog/uplink_catalog.yml @@ -265,16 +265,6 @@ tags: - NukeOpsUplink -- type: listing - id: UplinkSyndicateBombFake - name: uplink-exploding-syndicate-bomb-fake-name - description: uplink-exploding-syndicate-bomb-fake-desc - productEntity: SyndicateBombFake - cost: - Telecrystal: 4 - categories: - - UplinkExplosives - - type: listing id: UplinkClusterGrenade name: uplink-cluster-grenade-name @@ -787,7 +777,19 @@ cost: Telecrystal: 6 categories: - - UplinkBundles + - UplinkBundles + +- type: listing + id: UplinkSyndicateBombFake + name: uplink-exploding-syndicate-bomb-fake-name + description: uplink-exploding-syndicate-bomb-fake-desc + productEntity: SyndicateBombFake + cost: + Telecrystal: 4 + categories: + - UplinkDeception + +# Disruption - type: listing id: UplinkAmmoBundle @@ -1239,6 +1241,16 @@ # Armor +- type: listing + id: UplinkChestRig + name: uplink-chest-rig-name + description: uplink-chest-rig-desc + productEntity: ClothingBeltMilitaryWebbing + cost: + Telecrystal: 1 + categories: + - UplinkArmor + - type: listing id: UplinkChameleon name: uplink-chameleon-name diff --git a/Resources/Prototypes/DeltaV/Catalog/VendingMachines/Inventories/pride.yml b/Resources/Prototypes/DeltaV/Catalog/VendingMachines/Inventories/pride.yml index 9e1de27fa4b..28d2fbc1af2 100644 --- a/Resources/Prototypes/DeltaV/Catalog/VendingMachines/Inventories/pride.yml +++ b/Resources/Prototypes/DeltaV/Catalog/VendingMachines/Inventories/pride.yml @@ -26,4 +26,7 @@ BedsheetRainbow: 2 ClothingUniformColorRainbow: 2 ClothingUnderSocksCoder: 1 - ClothingUnderSocksBee: 1 \ No newline at end of file + ClothingUnderSocksBee: 1 + emaggedInventory: + # 3 for more friends! + ClothingUnderSocksCoderValid: 3 # Floofstation \ No newline at end of file diff --git a/Resources/Prototypes/DeltaV/Entities/Clothing/Uniforms/jumpsuits.yml b/Resources/Prototypes/DeltaV/Entities/Clothing/Uniforms/jumpsuits.yml index f3fdeabd107..99021b47e42 100644 --- a/Resources/Prototypes/DeltaV/Entities/Clothing/Uniforms/jumpsuits.yml +++ b/Resources/Prototypes/DeltaV/Entities/Clothing/Uniforms/jumpsuits.yml @@ -234,7 +234,7 @@ sprite: DeltaV/Clothing/Uniforms/Jumpsuit/centcom_officer.rsi - type: entity - parent: ClothingUniformBase + parent: ClothingUniformSkirtBase id: ClothingUniformJumpsuitKilt name: kilt description: A fine bit o' garb for the lad an' lasses. @@ -253,4 +253,4 @@ - type: Sprite sprite: DeltaV/Clothing/Uniforms/Jumpsuit/chemshirtsuit.rsi - type: Clothing - sprite: DeltaV/Clothing/Uniforms/Jumpsuit/chemshirtsuit.rsi \ No newline at end of file + sprite: DeltaV/Clothing/Uniforms/Jumpsuit/chemshirtsuit.rsi diff --git a/Resources/Prototypes/DeltaV/Entities/Markers/Spawners/Random/miningrock.yml b/Resources/Prototypes/DeltaV/Entities/Markers/Spawners/Random/miningrock.yml index f4aef8284b8..204901d8bda 100644 --- a/Resources/Prototypes/DeltaV/Entities/Markers/Spawners/Random/miningrock.yml +++ b/Resources/Prototypes/DeltaV/Entities/Markers/Spawners/Random/miningrock.yml @@ -17,14 +17,17 @@ - Barricade - MountainRockMining - MountainRock - - RandomCrystalSpawner + - RandomStalagmiteOrCrystal - RandomWallRockSpawner - RandomBasaltRockSpawner + - AsteroidRockOreCrab + - RandomWoodenStructure rareChance: 0.15 - type: entity name: Crystal Spawner id: RandomCrystalSpawner + suffix: 100% parent: MarkerBase components: - type: Sprite @@ -81,4 +84,19 @@ - WallRockBasaltTin - WallRockBasaltUranium - WallRockBasaltArtifactFragment -#Might add chance for no crystal later?? + +- type: entity + id: RandomWoodenStructure + name: wooden wall or support spawner + parent: MarkerBase + components: + - type: Sprite + layers: + - state: red + - sprite: Objects/Decoration/mines.rsi + state: support_wall_broken + - type: RandomSpawner + prototypes: + - RandomWoodenWall + - RandomWoodenSupport + chance: 0.9 diff --git a/Resources/Prototypes/DeltaV/Entities/Structures/Walls/mountain.yml b/Resources/Prototypes/DeltaV/Entities/Structures/Walls/mountain.yml index 43d56751716..575687336ad 100644 --- a/Resources/Prototypes/DeltaV/Entities/Structures/Walls/mountain.yml +++ b/Resources/Prototypes/DeltaV/Entities/Structures/Walls/mountain.yml @@ -69,7 +69,7 @@ id: MountainRock parent: BaseStructure name: mountain rock - suffix: un-mineable + suffix: Un-mineable description: A craggy mountain wall. It is too hard to mine. components: - type: Sprite @@ -107,7 +107,7 @@ id: AsteroidAltRockMining parent: AsteroidAltRock name: asteroid rock - suffix: higher ore yield + suffix: Higher Ore Yield description: A rocky asteroid. components: - type: Gatherable @@ -117,3 +117,14 @@ - type: OreVein oreChance: 0.33 oreRarityPrototypeId: RandomOreDistributionStandard + +- type: entity + id: AsteroidRockOreCrab + parent: AsteroidAltRock + name: asteroid rock + suffix: Ore Crab + description: A rocky asteroid. + components: + - type: OreVein + oreChance: 0.33 + oreRarityPrototypeId: OreCrab diff --git a/Resources/Prototypes/DeltaV/GameRules/events.yml b/Resources/Prototypes/DeltaV/GameRules/events.yml index 9391756492b..9a2b9a4569d 100644 --- a/Resources/Prototypes/DeltaV/GameRules/events.yml +++ b/Resources/Prototypes/DeltaV/GameRules/events.yml @@ -4,9 +4,7 @@ noSpawn: true components: - type: StationEvent - startAnnouncement: station-event-xeno-vent-start-announcement - startAudio: - path: /Audio/Announcements/aliens.ogg + startAnnouncement: true earliestStart: 20 minimumPlayers: 15 weight: 1 diff --git a/Resources/Prototypes/DeltaV/SoundCollections/harpy.yml b/Resources/Prototypes/DeltaV/SoundCollections/harpy.yml index d9a3fd92173..68133faac09 100644 --- a/Resources/Prototypes/DeltaV/SoundCollections/harpy.yml +++ b/Resources/Prototypes/DeltaV/SoundCollections/harpy.yml @@ -19,6 +19,10 @@ - /Audio/Voice/Moth/moth_scream.ogg - /Audio/Voice/Skeleton/skeleton_scream.ogg - /Audio/Voice/Reptilian/reptilian_scream.ogg + - /Audio/Voice/Slime/slime_scream_m1.ogg + - /Audio/Voice/Slime/slime_scream_m2.ogg + - /Audio/Voice/Slime/slime_scream_f1.ogg + - /Audio/Voice/Slime/slime_scream_f2.ogg - type: soundCollection id: HarpyLaugh @@ -32,6 +36,9 @@ - /Audio/Animals/lizard_happy.ogg - /Audio/Animals/ferret_happy.ogg - /Audio/Voice/Moth/moth_laugh.ogg + - /Audio/Voice/Slime/slime_laugh_m1.ogg + - /Audio/Voice/Slime/slime_laugh_m2.ogg + - /Audio/Voice/Slime/slime_laugh_f1.ogg - type: soundCollection id: HarpyHisses @@ -217,7 +224,7 @@ - type: soundCollection id: HarpyChitter - files: + files: - /Audio/Voice/Moth/moth_chitter.ogg - /Audio/Machines/circuitprinter.ogg - /Audio/Machines/diagnoser_printing.ogg @@ -226,18 +233,18 @@ - type: soundCollection id: HarpySqueak - files: + files: - /Audio/Voice/Moth/moth_squeak.ogg - /Audio/Animals/mouse_squeak.ogg - type: soundCollection id: HarpyCaws - files: + files: - /Audio/DeltaV/Voice/Harpy/caw1.ogg - type: soundCollection id: HarpyChirps - files: + files: - /Audio/DeltaV/Voice/Harpy/chirp1.ogg - /Audio/Voice/Talk/pai.ogg - /Audio/Voice/Talk/pai_ask.ogg diff --git a/Resources/Prototypes/Entities/Clothing/Belt/base_clothingbelt.yml b/Resources/Prototypes/Entities/Clothing/Belt/base_clothingbelt.yml index 2f904d3438c..50b1596c725 100644 --- a/Resources/Prototypes/Entities/Clothing/Belt/base_clothingbelt.yml +++ b/Resources/Prototypes/Entities/Clothing/Belt/base_clothingbelt.yml @@ -10,11 +10,22 @@ - type: Clothing slots: [belt] quickEquip: false + equipSound: + path: /Audio/SimpleStation14/Items/Equip/toolbelt_equip.ogg + clothingVisuals: + belt2: #there should be a cleaner way to do this tbh + - state: equipped-BELT - type: PhysicalComposition materialComposition: Cloth: 50 - type: StaticPrice price: 25 + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/toolbelt_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/toolbelt_drop.ogg + - type: EmitSoundOnLand + sound: /Audio/SimpleStation14/Items/Handling/toolbelt_drop.ogg - type: entity abstract: true diff --git a/Resources/Prototypes/Entities/Clothing/Belt/belts.yml b/Resources/Prototypes/Entities/Clothing/Belt/belts.yml index e6c08bf90b9..d90945a7eba 100644 --- a/Resources/Prototypes/Entities/Clothing/Belt/belts.yml +++ b/Resources/Prototypes/Entities/Clothing/Belt/belts.yml @@ -514,6 +514,8 @@ name: Sabre insertVerbText: sheath-insert-verb ejectVerbText: sheath-eject-verb + insertSound: /Audio/SimpleStation14/Items/Handling/sword_sheath.ogg + ejectSound: /Audio/SimpleStation14/Items/Handling/sword_unsheath.ogg whitelist: tags: - CaptainSabre diff --git a/Resources/Prototypes/Entities/Clothing/Head/bandanas.yml b/Resources/Prototypes/Entities/Clothing/Head/bandanas.yml index 8ee6479ee65..51a56f1f1d6 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/bandanas.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/bandanas.yml @@ -20,6 +20,9 @@ - state: icon_mask map: [ "unfoldedLayer" ] visible: false + - type: Tag + tags: + - Bandana - type: entity parent: [ClothingHeadBandBase, ClothingMaskBandBlack] @@ -69,4 +72,4 @@ - type: entity parent: [ClothingHeadBandBase, ClothingMaskBandBrown] id: ClothingHeadBandBrown - name: brown bandana \ No newline at end of file + name: brown bandana diff --git a/Resources/Prototypes/Entities/Clothing/Masks/bandanas.yml b/Resources/Prototypes/Entities/Clothing/Masks/bandanas.yml index 2d65e67982f..246b47b8003 100644 --- a/Resources/Prototypes/Entities/Clothing/Masks/bandanas.yml +++ b/Resources/Prototypes/Entities/Clothing/Masks/bandanas.yml @@ -24,6 +24,7 @@ visible: false - type: Tag tags: + - Bandana - HidesNose - type: entity diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml index f49f5f4804b..b867abfeed3 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml @@ -63,6 +63,9 @@ sprite: Clothing/OuterClothing/Vests/hazard.rsi - type: Clothing sprite: Clothing/OuterClothing/Vests/hazard.rsi + - type: Tag + tags: + - HiViz #(Bartender) vest - type: entity diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/boots.yml b/Resources/Prototypes/Entities/Clothing/Shoes/boots.yml index 241fc45352a..fdc49dc0616 100644 --- a/Resources/Prototypes/Entities/Clothing/Shoes/boots.yml +++ b/Resources/Prototypes/Entities/Clothing/Shoes/boots.yml @@ -202,7 +202,7 @@ - type: FootstepModifier footstepSoundCollection: collection: FootstepSpurs - + - type: entity parent: ClothingShoesBootsCowboyBrown id: ClothingShoesBootsCowboyBlack @@ -212,7 +212,7 @@ sprite: Clothing/Shoes/Boots/cowboybootsblack.rsi - type: Clothing sprite: Clothing/Shoes/Boots/cowboybootsblack.rsi - + - type: entity parent: ClothingShoesBootsCowboyBrown id: ClothingShoesBootsCowboyWhite @@ -222,7 +222,7 @@ sprite: Clothing/Shoes/Boots/cowboybootswhite.rsi - type: Clothing sprite: Clothing/Shoes/Boots/cowboybootswhite.rsi - + - type: entity parent: ClothingShoesBootsCowboyBrown id: ClothingShoesBootsCowboyFancy @@ -231,4 +231,4 @@ - type: Sprite sprite: Clothing/Shoes/Boots/cowboybootsfancy.rsi - type: Clothing - sprite: Clothing/Shoes/Boots/cowboybootsfancy.rsi \ No newline at end of file + sprite: Clothing/Shoes/Boots/cowboybootsfancy.rsi diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/base_clothinguniforms.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/base_clothinguniforms.yml index de9875b3ad6..9c896786c26 100644 --- a/Resources/Prototypes/Entities/Clothing/Uniforms/base_clothinguniforms.yml +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/base_clothinguniforms.yml @@ -50,6 +50,12 @@ - type: WirelessNetworkConnection range: 1200 - type: StationLimitedNetwork + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/cloth_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/cloth_drop.ogg + - type: EmitSoundOnLand + sound: /Audio/SimpleStation14/Items/Handling/cloth_drop.ogg - type: entity abstract: true diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/misc_roles.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/misc_roles.yml index 55ffe34b532..a8147ef7820 100644 --- a/Resources/Prototypes/Entities/Clothing/Uniforms/misc_roles.yml +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/misc_roles.yml @@ -1,5 +1,5 @@ - type: entity - parent: ClothingUniformBase + parent: ClothingUniformSkirtBase id: UniformShortsRed name: boxing shorts description: These are shorts, not boxers. @@ -10,7 +10,7 @@ sprite: Clothing/Uniforms/Shorts/Color/red.rsi - type: entity - parent: ClothingUniformBase + parent: ClothingUniformSkirtBase id: UniformShortsRedWithTop name: boxing shorts with top description: These are shorts, not boxers. diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/drinks_bottles.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/drinks_bottles.yml index 3f7a35e6f1d..e8f45295551 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/drinks_bottles.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/drinks_bottles.yml @@ -15,6 +15,7 @@ #small item prototypes: - DrinkAbsintheBottleFull + - DrinkAnisetteBottleFull # Floofstation - DrinkBlueCuracaoBottleFull - DrinkCognacBottleFull - DrinkGrenadineBottleFull diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/drinks_glass.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/drinks_glass.yml index 11042146689..cb9cb1399ad 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/drinks_glass.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/drinks_glass.yml @@ -26,6 +26,7 @@ - DrinkBeerglass - DrinkBerryJuice - DrinkBlackRussianGlass + - DrinkBlueBallerGlass # Floofstaion - DrinkBlueCuracaoGlass - DrinkBloodyMaryGlass - DrinkBooger @@ -66,9 +67,12 @@ - DrinkMilkshake - DrinkMojito - DrinkNTCahors + - DrinkOrgasmOnTheBeachGlass # Floofstation - DrinkPatronGlass + - DrinkPomPassionGlass # Floofstation - DrinkPoscaGlass - DrinkRedMeadGlass + - DrinkRedRocketGlass # Floofstation - DrinkRewriter - DrinkRootBeerFloatGlass - DrinkRumGlass @@ -85,10 +89,12 @@ - DrinkVodkaMartiniGlass - DrinkVodkaTonicGlass - DrinkWatermelonJuice + - DrinkWatermelonGinJizzGlass # Floofstaion - DrinkWhiskeyColaGlass - DrinkWhiskeySodaGlass - DrinkWhiteRussianGlass - DrinkWineGlass + - DrinkYeOlHandyGlass - DrinkShakeBlue - DrinkShakeWhite - DrinkTheMartinez diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/toy.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/toy.yml index eba1e300edf..d12b85cde41 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/Random/toy.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/toy.yml @@ -36,6 +36,7 @@ - PlushieMoth - PlushieMothRandom # Nyanotrasen Random Moth Plushies - PlushieArachind + - PlushieArachne chance: 0.5 offset: 0.2 diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml index 196abcfab76..a75be106f3c 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml @@ -220,6 +220,7 @@ understands: - GalacticCommon - RobotTalk + - type: CanWalk - type: entity id: BaseBorgChassisNT diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index ec917607abc..9bdfacb81ab 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -23,7 +23,7 @@ shape: !type:PhysShapeCircle radius: 0.25 - density: 10 + density: 0.8 mask: - FlyingMobMask layer: @@ -89,7 +89,7 @@ shape: !type:PhysShapeCircle radius: 0.1 - density: 30 + density: 0.1 mask: - FlyingMobMask layer: @@ -346,7 +346,7 @@ shape: !type:PhysShapeCircle radius: 0.2 - density: 100 + density: 0.0007 mask: - SmallMobMask layer: @@ -450,7 +450,7 @@ shape: !type:PhysShapeCircle radius: 0.2 - density: 120 + density: 0.007 mask: - SmallMobMask layer: @@ -1309,6 +1309,7 @@ tags: - VimPilot - DoorBumpOpener + - type: CanWalk - type: entity name: monkey @@ -1580,7 +1581,7 @@ shape: !type:PhysShapeCircle radius: 0.2 - density: 100 + density: 0.76 mask: - SmallMobMask layer: @@ -2539,7 +2540,7 @@ shape: !type:PhysShapeCircle radius: 0.35 - density: 50 #They actually are pretty light, I looked it up + density: 16.66 mask: - MobMask layer: @@ -2622,7 +2623,7 @@ shape: !type:PhysShapeCircle radius: 0.35 - density: 50 + density: 25.5 mask: - MobMask layer: @@ -2777,7 +2778,7 @@ shape: !type:PhysShapeCircle radius: 0.35 - density: 15 + density: 9 mask: - MobMask layer: @@ -2930,6 +2931,17 @@ Base: caracal_flop Dead: Base: caracal_dead + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeCircle + radius: 0.35 + density: 30 + mask: + - MobMask + layer: + - MobLayer - type: entity name: kitten @@ -2965,6 +2977,17 @@ thresholds: 0: Alive 25: Dead + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeCircle + radius: 0.35 + density: 2 + mask: + - MobMask + layer: + - MobLayer - type: entity name: sloth @@ -3051,7 +3074,7 @@ shape: !type:PhysShapeCircle radius: 0.35 - density: 5 + density: 4 mask: - MobMask layer: @@ -3128,7 +3151,7 @@ shape: !type:PhysShapeCircle radius: 0.2 - density: 120 + density: 0.8 mask: - SmallMobMask layer: @@ -3252,7 +3275,7 @@ shape: !type:PhysShapeCircle radius: 0.35 - density: 250 + density: 750 mask: - MobMask layer: @@ -3329,7 +3352,7 @@ shape: !type:PhysShapeCircle radius: 0.35 - density: 100 # High, because wood is heavy. + density: 15 mask: - MobMask layer: diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml b/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml index fda467cb32d..a310d3ee2be 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml @@ -304,6 +304,7 @@ amplification: 1 psychicFeedback: - "reagent-slime-feedback" + - type: CanWalk - type: entity name: Reagent Slime Spawner diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml b/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml index 42da84323f6..db594873fe3 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml @@ -126,6 +126,7 @@ understands: - GalacticCommon - Mouse + - type: CanWalk - type: entity id: MobRatKingBuff diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml b/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml index c4d88e80705..690a4c5d291 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml @@ -128,6 +128,7 @@ speechSounds: Slime - type: TypingIndicator proto: slime + - type: CanWalk - type: entity name: blue slime diff --git a/Resources/Prototypes/Entities/Mobs/Species/base.yml b/Resources/Prototypes/Entities/Mobs/Species/base.yml index eeb6dfc852c..1b9e9674f44 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/base.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/base.yml @@ -229,6 +229,7 @@ - CanPilot - FootstepSound - DoorBumpOpener + - type: CanWalk - type: entity save: false @@ -310,6 +311,7 @@ - type: FireVisuals alternateState: Standing - type: OfferItem + - type: LayingDown - type: entity save: false diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml index 0602fcf8f9d..17e2a4df5ee 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml @@ -33,6 +33,12 @@ interfaces: - key: enum.TransferAmountUiKey.Key type: TransferAmountBoundUserInterface + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/drinkglass_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/drinkglass_drop.ogg + - type: EmitSoundOnLand + sound: /Audio/SimpleStation14/Items/Handling/drinkglass_drop.ogg - type: entity parent: DrinkBase @@ -369,6 +375,9 @@ - type: Icon sprite: Objects/Consumable/Drinks/beerglass.rsi state: icon + - type: Tag + tags: + - Beer - type: entity parent: DrinkGlass @@ -943,6 +952,9 @@ - type: Icon sprite: Objects/Consumable/Drinks/iced_beerglass.rsi state: icon + - type: Tag + tags: + - Beer - type: entity parent: DrinkGlass diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_bottles.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_bottles.yml index 07828ff5ba5..face999df82 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_bottles.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_bottles.yml @@ -355,6 +355,9 @@ - type: Sprite sprite: Objects/Consumable/Drinks/pwinebottle.rsi - type: Sealable + - type: Tag + tags: + - Wine - type: entity parent: [DrinkBottleVisualsAll, DrinkBottleGlassBaseFull] @@ -501,6 +504,9 @@ - type: Sprite sprite: Objects/Consumable/Drinks/winebottle.rsi - type: Sealable + - type: Tag + tags: + - Wine # Small Bottles @@ -523,6 +529,9 @@ sprite: Objects/Consumable/Drinks/beer.rsi - type: Openable closeable: false + - type: Tag + tags: + - Beer - type: entity parent: [DrinkBottleVisualsAll, DrinkBottleGlassBaseFull] @@ -543,6 +552,9 @@ sprite: Objects/Consumable/Drinks/beer.rsi - type: Openable closeable: false + - type: Tag + tags: + - Beer - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml index f8ada34e648..e488fb26eec 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml @@ -62,6 +62,12 @@ - type: Tag tags: - DrinkCan + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/drinkglass_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/drinkglass_drop.ogg + - type: EmitSoundOnLand + sound: /Audio/SimpleStation14/Items/Handling/drinkglass_drop.ogg - type: entity parent: DrinkCanBaseFull @@ -182,6 +188,9 @@ sprite: Objects/Consumable/Drinks/rootbeer.rsi - type: Item sprite: Objects/Consumable/Drinks/rootbeer.rsi + - type: Tag + tags: + - Beer - type: entity parent: DrinkCanBaseFull @@ -480,6 +489,9 @@ sprite: Objects/Consumable/Drinks/beer_can.rsi - type: Item sprite: Objects/Consumable/Drinks/beer_can.rsi + - type: Tag + tags: + - Beer - type: entity parent: DrinkCanBaseFull @@ -499,6 +511,9 @@ sprite: Objects/Consumable/Drinks/wine_can.rsi - type: Item sprite: Objects/Consumable/Drinks/wine_can.rsi + - type: Tag + tags: + - Wine #Floof - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cups.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cups.yml index 4fc2e170d5b..c4693c6a719 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cups.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cups.yml @@ -37,6 +37,12 @@ damage: types: Blunt: 0 + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/drinkglass_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/drinkglass_drop.ogg + - type: EmitSoundOnLand + sound: /Audio/SimpleStation14/Items/Handling/drinkglass_drop.ogg - type: entity parent: DrinkBaseCup diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml index c80398e3496..9a523c997b9 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml @@ -31,6 +31,12 @@ - type: PhysicalComposition materialComposition: Steel: 50 + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/drinkglass_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/drinkglass_drop.ogg + - type: EmitSoundOnLand + sound: /Audio/SimpleStation14/Items/Handling/drinkglass_drop.ogg - type: entity parent: DrinkGlassBase diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml index 86bc34f3c8b..3cf2e77e8b6 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml @@ -136,6 +136,12 @@ materialComposition: Cardboard: 20 - type: SpaceGarbage + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/drinkglass_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/drinkglass_drop.ogg + - type: EmitSoundOnLand + sound: /Audio/SimpleStation14/Items/Handling/drinkglass_drop.ogg - type: entity name: base empty bottle @@ -303,7 +309,6 @@ - type: Sprite sprite: Objects/Consumable/TrashDrinks/winebottle_empty.rsi - - type: entity name: lime juice carton parent: DrinkCartonBaseEmpty @@ -347,6 +352,10 @@ components: - type: Sprite sprite: Objects/Consumable/Drinks/milk.rsi + - type: SolutionContainerManager + solutions: + drink: + maxVol: 100 - type: entity name: soy milk carton diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pie.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pie.yml index fe888595847..8cd1c5dfab6 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pie.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pie.yml @@ -156,6 +156,8 @@ path: /Audio/Weapons/Guns/Empty/empty.ogg ejectSound: path: /Audio/Weapons/Guns/Empty/empty.ogg + swap: false + disableEject: true - type: Tag tags: - Fruit diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/meals.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/meals.yml index 5fbfe9c09b2..74277cf7ff4 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/meals.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/meals.yml @@ -609,3 +609,24 @@ Quantity: 4 - ReagentId: Vitamin Quantity: 4 + +- type: entity + name: harpy wings + parent: FoodMealBase + id: FoodHarpyWings + description: It's a bit stringy. + components: + - type: FlavorProfile + flavors: + - chicken + - type: Sprite + state: harpywings + - type: SolutionContainerManager + solutions: + food: + maxVol: 25 + reagents: + - ReagentId: Nutriment + Quantity: 13 + - ReagentId: Protein + Quantity: 7 diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml index 85de407988b..58af9cf3bd8 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml @@ -718,6 +718,7 @@ tags: - Cooked - Meat + - Steak - type: Sprite layers: - state: plain-cooked @@ -774,6 +775,7 @@ tags: - Cooked - Meat + - Steak - type: Sprite layers: - state: product-cooked @@ -942,6 +944,7 @@ tags: - Cooked - Meat + - Steak - type: Sprite layers: - state: goliath-cooked @@ -971,6 +974,7 @@ tags: - Cooked - Meat + - Steak - type: Sprite layers: - state: rouny-cooked @@ -996,6 +1000,7 @@ tags: - Cooked - Meat + - Steak - type: Sprite layers: - state: lizard-cooked diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml index 8eb36c71b51..e3e3f6681f8 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml @@ -124,6 +124,9 @@ sprite: Objects/Specific/Hydroponics/laughin_pea.rsi - type: Produce seedId: laughinPea + - type: Tag + tags: + - Vegetable - type: entity name: tower-cap log @@ -258,6 +261,7 @@ - type: Tag tags: - Fruit + - Banana - type: entity name: mimana @@ -413,6 +417,7 @@ - type: Tag tags: - Carrot + - Vegetable - type: SolutionContainerManager solutions: food: @@ -458,6 +463,9 @@ sprite: Objects/Specific/Hydroponics/cabbage.rsi - type: Produce seedId: cabbage + - type: Tag + tags: + - Vegetable - type: entity name: garlic @@ -483,6 +491,9 @@ sprite: Objects/Specific/Hydroponics/garlic.rsi - type: Produce seedId: garlic + - type: Tag + tags: + - Vegetable - type: entity name: lemon @@ -658,6 +669,8 @@ - type: Tag tags: - Potato + - Vegetable + - type: entity name: tomato @@ -712,6 +725,7 @@ - type: Tag tags: - Fruit + - Vegetable - type: entity name: blue tomato @@ -756,6 +770,7 @@ - type: Tag tags: - Fruit + - Vegetable - type: entity name: blood tomato @@ -798,6 +813,7 @@ - type: Tag tags: - Fruit # Fuck you they're a fruit + - Vegetable - type: entity name: eggplant @@ -824,6 +840,7 @@ - type: Tag tags: - Fruit + - Vegetable - type: entity name: apple @@ -912,6 +929,7 @@ - type: Tag tags: - Corn + - Vegetable - type: Sprite sprite: Objects/Specific/Hydroponics/corn.rsi - type: Produce @@ -974,6 +992,9 @@ - type: SliceableFood count: 5 slice: FoodOnionSlice + - type: Tag + tags: + - Vegetable - type: entity name: red onion @@ -1002,6 +1023,9 @@ - type: SliceableFood count: 5 slice: FoodOnionRedSlice + - type: Tag + tags: + - Vegetable - type: entity name: chanterelle cluster @@ -1019,6 +1043,9 @@ sprite: Objects/Specific/Hydroponics/chanterelle.rsi - type: Produce seedId: chanterelle + - type: Tag + tags: + - Vegetable # Slices @@ -1129,6 +1156,9 @@ sprite: Objects/Specific/Hydroponics/chili.rsi - type: Produce seedId: chili + - type: Tag + tags: + - Vegetable - type: entity name: chilly pepper @@ -1180,6 +1210,9 @@ seedId: aloe - type: Extractable grindableSolutionName: food + - type: Tag + tags: + - Vegetable - type: entity name: poppy @@ -1459,6 +1492,9 @@ reagents: - ReagentId: MilkSoy Quantity: 5 + - type: Tag + tags: + - Vegetable - type: entity name: spaceman's trumpet @@ -1512,6 +1548,9 @@ reagents: - ReagentId: CarpoToxin Quantity: 2 + - type: Tag + tags: + - Vegetable - type: entity name: watermelon @@ -1604,9 +1643,6 @@ reagents: - ReagentId: JuiceWatermelon Quantity: 4 - - type: Tag - tags: - - Fruit - type: entity name: grapes @@ -1635,6 +1671,9 @@ reagents: - ReagentId: JuiceGrape Quantity: 10 + - type: Tag + tags: + - Fruit - type: entity name: berries @@ -1707,7 +1746,6 @@ tags: - Recyclable - Trash - - Fruit - type: SolutionContainerManager solutions: food: @@ -1746,6 +1784,9 @@ sprite: Objects/Specific/Hydroponics/pea.rsi - type: Produce seedId: pea + - type: Tag + tags: + - Vegetable - type: entity name: pumpkin @@ -1794,6 +1835,7 @@ - type: Tag tags: - Fruit + - Vegetable - type: entity name: cotton boll @@ -1822,8 +1864,9 @@ - type: Tag tags: - ClothMade + - CottonBoll -- type: entity # Floofttation +- type: entity # Floofstation name: pomegranate parent: FoodProduceBase id: FoodPomegranate @@ -1847,7 +1890,43 @@ - type: Produce seedId: pomegranate - type: Extractable - grindableSolutionName: food + juiceSolution: + reagents: + - ReagentId: JuicePomegranate + Quantity: 20 + - type: SliceableFood + count: 2 + slice: FoodPomegranateSlice + - type: Tag + tags: + - Fruit + +- type: entity # Floofstation + name: pomegranate slice + parent: ProduceSliceBase + id: FoodPomegranateSlice + description: A delicious, sweet fruit, believed to have special properties. + components: + - type: FlavorProfile + flavors: + - sweet + - spooky + - type: Sprite + sprite: Floof/Objects/Specific/Hydroponics/pomegranate.rsi + - type: SolutionContainerManager + solutions: + food: + maxVol: 20 + reagents: + - ReagentId: Pomelustine + Quantity: 15 + - ReagentId: Nutriment + Quantity: 5 + - type: Extractable + juiceSolution: + reagents: + - ReagentId: JuicePomegranate + Quantity: 10 - type: Tag tags: - Fruit diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/soup.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/soup.yml index 3b080e843b4..6b96f3bcb36 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/soup.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/soup.yml @@ -806,6 +806,10 @@ Quantity: 4 - ReagentId: Allicin Quantity: 3 + - type: Tag + tags: + - ChiliBowl + - type: entity name: cold chili @@ -830,6 +834,9 @@ Quantity: 8 - ReagentId: Vitamin Quantity: 4 + - type: Tag + tags: + - ChiliBowl - type: entity name: chili con carnival @@ -860,6 +867,9 @@ Quantity: 4 - ReagentId: Allicin Quantity: 3 + - type: Tag + tags: + - ChiliBowl - type: entity name: monkey's delight diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml index c2a1fe6e7dc..4cd8a850993 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml @@ -1175,9 +1175,9 @@ materialRequirements: Glass: 2 Cable: 2 - - type: ReverseEngineering # Nyano - recipes: - - MicrowaveMachineCircuitboard + - type: Tag + tags: + - MicrowaveMachineBoard - type: entity id: FatExtractorMachineCircuitboard @@ -1433,7 +1433,7 @@ materialRequirements: Steel: 5 CableHV: 5 - + - type: entity id: ShuttleGunPerforatorCircuitboard parent: BaseMachineCircuitboard @@ -1450,7 +1450,7 @@ materialRequirements: Steel: 10 CableHV: 5 - + - type: entity id: ShuttleGunFriendshipCircuitboard parent: BaseMachineCircuitboard @@ -1466,8 +1466,8 @@ Manipulator: 2 materialRequirements: Steel: 7 - CableHV: 5 - + CableHV: 5 + - type: entity id: ShuttleGunDusterCircuitboard parent: BaseMachineCircuitboard @@ -1485,7 +1485,7 @@ Steel: 10 CableHV: 5 Uranium: 2 - + - type: entity id: ShuttleGunKineticCircuitboard parent: BaseMachineCircuitboard @@ -1502,4 +1502,3 @@ materialRequirements: Steel: 5 CableHV: 2 - \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Devices/translators.yml b/Resources/Prototypes/Entities/Objects/Devices/translators.yml index 445cd7a90a6..5a605122244 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/translators.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/translators.yml @@ -1,5 +1,6 @@ +# Translator that doesn't need power to work - type: entity - abstract: true + noSpawn: true id: TranslatorUnpowered parent: BaseItem name: translator @@ -23,31 +24,44 @@ False: { visible: false } - type: HandheldTranslator enabled: false + - type: Clothing # To allow equipping translators on the neck slot + slots: [neck] + equipDelay: 0.3 + unequipDelay: 0.3 + quickEquip: false # Would conflict +# Base translator that uses a power cell. Starts with an empty slot. - type: entity - abstract: true - id: Translator + noSpawn: true + id: TranslatorPoweredBase parent: [ TranslatorUnpowered, PowerCellSlotMediumItem ] - suffix: Powered components: - type: PowerCellDraw drawRate: 1 - -- type: entity - abstract: true - id: TranslatorEmpty - parent: Translator - suffix: Empty - components: - type: ItemSlots slots: cell_slot: name: power-cell-slot-component-slot-name-default +# Normal translator with medium power cell in it +- type: entity + noSpawn: true + id: Translator + parent: [ PowerCellSlotMediumItem, TranslatorPoweredBase ] + suffix: Powered + +# Normal translator with a high power cell and special appearance +- type: entity + noSpawn: true + id: TranslatorForeigner + parent: [ PowerCellSlotHighItem, TranslatorPoweredBase ] + name: foreigner's translator + description: A special-issue translator that helps foreigner's speak and understand this station's primary language. + - type: entity id: CanilunztTranslator - parent: [ TranslatorEmpty ] + parent: [ TranslatorPoweredBase ] name: Canilunzt translator description: Translates speech between Canilunzt and Galactic Common, allowing your local yeepers to communicate with the locals and vice versa! components: @@ -64,7 +78,7 @@ - type: entity id: BubblishTranslator - parent: [ TranslatorEmpty ] + parent: [ TranslatorPoweredBase ] name: Bubblish translator description: Translates speech between Bubblish and Galactic Common, helping communicate with slimes and slime people. components: @@ -81,7 +95,7 @@ - type: entity id: NekomimeticTranslator - parent: [ TranslatorEmpty ] + parent: [ TranslatorPoweredBase ] name: Nekomimetic translator description: Translates speech between Nekomimetic and Galactic Common, enabling you to communicate with your pet cats. components: @@ -98,7 +112,7 @@ - type: entity id: DraconicTranslator - parent: [ TranslatorEmpty ] + parent: [ TranslatorPoweredBase ] name: Draconic translator description: Translates speech between Draconic and Galactic Common, making it easier to understand your local Uniathi. components: @@ -115,7 +129,7 @@ - type: entity id: SolCommonTranslator - parent: [ TranslatorEmpty ] + parent: [ TranslatorPoweredBase ] name: Sol Common translator description: Translates speech between Sol Common and Galactic Common. Like a true Earthman! components: @@ -132,7 +146,7 @@ - type: entity id: RootSpeakTranslator - parent: [ TranslatorEmpty ] + parent: [ TranslatorPoweredBase ] name: RootSpeak translator description: Translates speech between RootSpeak and Galactic Common. You may now speak for the trees. components: @@ -149,7 +163,7 @@ - type: entity id: MofficTranslator - parent: [ TranslatorEmpty ] + parent: [ TranslatorPoweredBase ] name: Moffic translator description: Translates speech between Moffic and Galactic Common, helping you understand the buzzes of your pet mothroach! components: @@ -166,7 +180,7 @@ - type: entity id: XenoTranslator - parent: [ TranslatorEmpty ] + parent: [ TranslatorPoweredBase ] name: Xeno translator description: Translates speech between Xeno and Galactic Common. This will probably not help you survive an encounter, though. components: @@ -182,7 +196,7 @@ - type: entity id: AnimalTranslator - parent: [ TranslatorEmpty ] + parent: [ TranslatorPoweredBase ] name: Animal translator description: Translates all the cutes noises that most animals make into a more understandable form! components: diff --git a/Resources/Prototypes/Entities/Objects/Fun/Instruments/instruments_string.yml b/Resources/Prototypes/Entities/Objects/Fun/Instruments/instruments_string.yml index 7224efa9e02..fab8b56b06f 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/Instruments/instruments_string.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/Instruments/instruments_string.yml @@ -183,6 +183,13 @@ - type: Tag tags: - StringInstrument + - type: MeleeWeapon + soundHit: + path: /Audio/SimpleStation14/Weapons/Melee/banjohit.ogg + damage: + types: + Blunt: 7 + bluntStaminaDamageFactor: 1.5 - type: entity parent: BaseHandheldInstrument diff --git a/Resources/Prototypes/Entities/Objects/Fun/toys.yml b/Resources/Prototypes/Entities/Objects/Fun/toys.yml index 67c6e1194b7..9ced5539417 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/toys.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/toys.yml @@ -750,6 +750,34 @@ sound: path: /Audio/Voice/Human/malescream_5.ogg +- type: entity + parent: BasePlushie + id: PlushieArachne + name: Arachne plushie + description: A plushie of an Arachne, a half human, half spider creature. Why does it look familiar? + components: + - type: Sprite + state: plushie_arachne + - type: EmitSoundOnUse + sound: + path: /Audio/Voice/Human/womanlaugh.ogg + - type: EmitSoundOnLand + sound: + path: /Audio/Voice/Human/female_sigh.ogg + - type: EmitSoundOnActivate + sound: + path: /Audio/Voice/Human/womanlaugh.ogg + - type: Food + requiresSpecialDigestion: true + useSound: + path: /Audio/Voice/Human/femalescream_4.ogg + - type: MeleeWeapon + soundHit: + path: /Audio/Voice/Human/femalescream_2.ogg + - type: EmitSoundOnTrigger + sound: + path: /Audio/Voice/Human/femalescream_5.ogg + - type: entity parent: BasePlushie id: PlushieMoth @@ -1432,6 +1460,9 @@ reagents: - ReagentId: Nothing Quantity: 100 + - type: Tag + tags: + - Banana - type: entity parent: DrinkBase diff --git a/Resources/Prototypes/Entities/Objects/Magic/books.yml b/Resources/Prototypes/Entities/Objects/Magic/books.yml index 89acd9e7dab..4d1c585e4b8 100644 --- a/Resources/Prototypes/Entities/Objects/Magic/books.yml +++ b/Resources/Prototypes/Entities/Objects/Magic/books.yml @@ -12,6 +12,12 @@ - type: Tag tags: - Spellbook + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/book_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/book_drop.ogg + - type: EmitSoundOnLand + sound: /Audio/SimpleStation14/Items/Handling/book_drop.ogg - type: entity id: SpawnSpellbook diff --git a/Resources/Prototypes/Entities/Objects/Misc/bedsheets.yml b/Resources/Prototypes/Entities/Objects/Misc/bedsheets.yml index 209d0b8cc2d..0b9f00be65c 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/bedsheets.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/bedsheets.yml @@ -20,6 +20,9 @@ - neck - type: StaticPrice price: 100 + - type: Tag + tags: + - Bedsheet - type: entity id: BedsheetBlack diff --git a/Resources/Prototypes/Entities/Objects/Misc/books.yml b/Resources/Prototypes/Entities/Objects/Misc/books.yml index ab6beb70af1..635f0888a1b 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/books.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/books.yml @@ -25,6 +25,12 @@ backgroundImagePath: "/Textures/Interface/Paper/paper_background_book.svg.96dpi.png" backgroundPatchMargin: 23.0, 16.0, 14.0, 15.0 contentMargin: 20.0, 20.0, 20.0, 20.0 + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/book_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/book_drop.ogg + - type: EmitSoundOnLand + sound: /Audio/SimpleStation14/Items/Handling/book_drop.ogg - type: entity id: BookSpaceEncyclopedia diff --git a/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml b/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml index e389bc6b378..f4b4f4c96cd 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml @@ -22,6 +22,12 @@ - HighRiskItem - type: StealTarget stealGroup: NukeDisk + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/disk_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/disk_drop.ogg + - type: EmitSoundOnLand + sound: /Audio/SimpleStation14/Items/Handling/disk_drop.ogg - type: entity name: nuclear authentication disk @@ -35,3 +41,9 @@ state: icon - type: StaticPrice price: 1 # it's worth even less than normal items. Perfection. + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/disk_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/disk_drop.ogg + - type: EmitSoundOnLand + sound: /Audio/SimpleStation14/Items/Handling/disk_drop.ogg diff --git a/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml b/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml index e1e422bbc7d..e1bbbb27e2f 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml @@ -52,6 +52,7 @@ path: /Audio/Items/Handcuffs/rope_breakout.ogg startBreakoutSound: path: /Audio/Items/Handcuffs/rope_takeoff.ogg + uncuffEasierWhenLarge: true - type: Construction graph: makeshifthandcuffs node: cuffscable @@ -93,6 +94,7 @@ path: /Audio/Items/Handcuffs/rope_breakout.ogg startBreakoutSound: path: /Audio/Items/Handcuffs/rope_takeoff.ogg + uncuffEasierWhenLarge: true - type: Sprite sprite: Objects/Misc/zipties.rsi state: cuff diff --git a/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml b/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml index 0b86677a8e5..f797ad5cead 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml @@ -35,7 +35,11 @@ - type: Sprite layers: - state: default - - state: idpassenger + - state: department + color: "#878787" + - state: subdepartment + color: "#878787" + - state: passenger - type: PresetIdCard job: Passenger @@ -49,7 +53,11 @@ - type: Sprite layers: - state: default - - state: idintern-tech + - state: department + color: "#F39F27" + - state: subdepartment + color: "#F39F27" + - state: assistant - type: entity parent: PassengerIDCard @@ -61,7 +69,11 @@ - type: Sprite layers: - state: default - - state: idintern-med + - state: department + color: "#5B97BC" + - state: subdepartment + color: "#5B97BC" + - state: assistant - type: entity parent: PassengerIDCard @@ -73,7 +85,11 @@ - type: Sprite layers: - state: default - - state: idintern-sci + - state: department + color: "#C96DBF" + - state: subdepartment + color: "#C96DBF" + - state: assistant - type: entity parent: PassengerIDCard @@ -85,7 +101,11 @@ - type: Sprite layers: - state: default - - state: idintern-cadet + - state: department + color: "#CB0000" + - state: subdepartment + color: "#CB0000" + - state: assistant - type: entity parent: PassengerIDCard @@ -97,7 +117,11 @@ - type: Sprite layers: - state: default - - state: idintern-service + - state: department + color: "#58C800" + - state: subdepartment + color: "#58C800" + - state: assistant - type: entity parent: IDCardStandard @@ -107,7 +131,11 @@ - type: Sprite layers: - state: gold - - state: idcaptain + - state: departmenthead + color: "#1B67A5" + - state: subdepartment + color: "#1B67A5" + - state: captain - type: Item heldPrefix: gold - type: PresetIdCard @@ -128,7 +156,11 @@ - type: Sprite layers: - state: default - - state: idsecurityofficer + - state: department + color: "#CB0000" + - state: subdepartment + color: "#CB0000" + - state: securityofficer - type: PresetIdCard job: SecurityOfficer @@ -137,12 +169,16 @@ id: WardenIDCard name: warden ID card components: - - type: Sprite - layers: - - state: default - - state: idwarden - - type: PresetIdCard - job: Warden + - type: Sprite + layers: + - state: default + - state: department + color: "#CB0000" + - state: subdepartment + color: "#CB0000" + - state: warden + - type: PresetIdCard + job: Warden - type: entity parent: IDCardStandard @@ -152,7 +188,11 @@ - type: Sprite layers: - state: default - - state: idstationengineer + - state: department + color: "#F39F27" + - state: subdepartment + color: "#F39F27" + - state: stationengineer - type: PresetIdCard job: StationEngineer @@ -164,7 +204,11 @@ - type: Sprite layers: - state: default - - state: idmedicaldoctor + - state: department + color: "#5B97BC" + - state: subdepartment + color: "#5B97BC" + - state: medicaldoctor - type: PresetIdCard job: MedicalDoctor @@ -176,7 +220,11 @@ - type: Sprite layers: - state: default - - state: idparamedic + - state: department + color: "#5B97BC" + - state: subdepartment + color: "#5B97BC" + - state: paramedic - type: PresetIdCard job: Paramedic @@ -188,7 +236,11 @@ - type: Sprite layers: - state: default - - state: idchemist + - state: department + color: "#5B97BC" + - state: subdepartment + color: "#5B97BC" + - state: chemist - type: PresetIdCard job: Chemist @@ -200,7 +252,11 @@ - type: Sprite layers: - state: default - - state: idcargotechnician + - state: department + color: "#B18644" + - state: subdepartment + color: "#B18644" + - state: cargotechnician - type: PresetIdCard job: CargoTechnician @@ -212,7 +268,11 @@ - type: Sprite layers: - state: default - - state: idshaftminer + - state: department + color: "#B18644" + - state: subdepartment + color: "#C96DBF" + - state: shaftminer - type: PresetIdCard job: SalvageSpecialist @@ -221,14 +281,18 @@ id: QuartermasterIDCard name: logistics officer ID card # DeltaV - Logistics Department replacing Cargo components: - - type: Sprite - layers: - - state: silver - - state: idquartermaster - - type: Item - heldPrefix: silver - - type: PresetIdCard - job: Quartermaster + - type: Sprite + layers: + - state: silver + - state: departmenthead + color: "#1B67A5" + - state: subdepartment + color: "#B18644" + - state: cargotechnician + - type: Item + heldPrefix: silver + - type: PresetIdCard + job: Quartermaster - type: entity parent: IDCardStandard @@ -238,7 +302,11 @@ - type: Sprite layers: - state: default - - state: idscientist + - state: department + color: "#C96DBF" + - state: subdepartment + color: "#C96DBF" + - state: scientist - type: PresetIdCard job: Scientist @@ -249,8 +317,12 @@ components: - type: Sprite layers: - - state: default - - state: idclown + - state: rainbow + - state: department + color: "#FF00FF" + - state: subdepartment + color: "#58C800" + - state: clown - type: PresetIdCard job: Clown @@ -262,7 +334,10 @@ - type: Sprite layers: - state: default - - state: idmime + - state: department + color: "#878787" + - state: subdepartment + - state: mime - type: PresetIdCard job: Mime @@ -271,11 +346,14 @@ id: ChaplainIDCard name: chaplain ID card components: - - type: Sprite - layers: - - state: default - - sprite: DeltaV/Objects/Misc/id_cards.rsi # DeltaV - Give Chaplain ID Epistemics colors - state: idchaplain + - type: Sprite + layers: + - state: default + - state: department + color: "#C96DBF" + - state: subdepartment + color: "#58C800" + - state: chaplain - type: PresetIdCard job: Chaplain @@ -287,7 +365,11 @@ - type: Sprite layers: - state: default - - state: idjanitor + - state: department + color: "#58C800" + - state: subdepartment + color: "#58C800" + - state: janitor - type: PresetIdCard job: Janitor @@ -299,22 +381,22 @@ - type: Sprite layers: - state: default - - state: idbartender + - state: department + color: "#58C800" + - state: subdepartment + color: "#58C800" + - state: bartender - type: PresetIdCard job: Bartender - type: entity - parent: IDCardStandard + parent: BartenderIDCard id: PunPunIDCard name: pun pun ID card components: - - type: Sprite - layers: - - state: default - - state: idbartender - - type: PresetIdCard - job: Bartender - name: Pun Pun + - type: PresetIdCard + job: Bartender + name: Pun Pun - type: entity parent: IDCardStandard @@ -324,7 +406,11 @@ - type: Sprite layers: - state: default - - state: idcook + - state: department + color: "#58C800" + - state: subdepartment + color: "#58C800" + - state: cook - type: PresetIdCard job: Chef @@ -333,36 +419,48 @@ id: BotanistIDCard name: botanist ID card components: - - type: Sprite - layers: - - state: default - - state: idbotanist - - type: PresetIdCard - job: Botanist + - type: Sprite + layers: + - state: default + - state: department + color: "#58C800" + - state: subdepartment + color: "#58C800" + - state: botanist + - type: PresetIdCard + job: Botanist - type: entity parent: IDCardStandard id: LibrarianIDCard name: librarian ID card components: - - type: Sprite - layers: - - state: default - - state: idcurator - - type: PresetIdCard - job: Librarian + - type: Sprite + layers: + - state: default + - state: department + color: "#58C800" + - state: subdepartment + color: "#58C800" + - state: curator + - type: PresetIdCard + job: Librarian - type: entity parent: IDCardStandard id: LawyerIDCard name: lawyer ID card components: - - type: Sprite - layers: - - state: default - - state: idlawyer - - type: PresetIdCard - job: Lawyer + - type: Sprite + layers: + - state: default + - state: department + color: "#878787" + - state: subdepartment + color: "#CB0000" + - state: lawyer + - type: PresetIdCard + job: Lawyer - type: entity parent: IDCardStandard @@ -372,7 +470,11 @@ - type: Sprite layers: - state: silver - - state: idheadofpersonnel + - state: departmenthead + color: "#1B67A5" + - state: subdepartment + color: "#58C800" + - state: headofpersonnel - type: Item heldPrefix: silver - type: PresetIdCard @@ -386,7 +488,11 @@ - type: Sprite layers: - state: silver - - state: idchiefengineer + - state: departmenthead + color: "#1B67A5" + - state: subdepartment + color: "#F39F27" + - state: stationengineer - type: Item heldPrefix: silver - type: PresetIdCard @@ -400,7 +506,11 @@ - type: Sprite layers: - state: silver - - state: idchiefmedicalofficer + - state: departmenthead + color: "#1B67A5" + - state: subdepartment + color: "#5B97BC" + - state: medicaldoctor - type: Item heldPrefix: silver - type: PresetIdCard @@ -414,7 +524,11 @@ - type: Sprite layers: - state: silver - - state: idresearchdirector + - state: departmenthead + color: "#1B67A5" + - state: subdepartment + color: "#C96DBF" + - state: scientist - type: Item heldPrefix: silver - type: PresetIdCard @@ -428,7 +542,11 @@ - type: Sprite layers: - state: silver - - state: idheadofsecurity + - state: departmenthead + color: "#1B67A5" + - state: subdepartment + color: "#CB0000" + - state: securityofficer - type: Item heldPrefix: silver - type: PresetIdCard @@ -442,7 +560,11 @@ - type: Sprite layers: - state: default - - state: idbrigmedic + - state: department + color: "#CB0000" + - state: subdepartment + color: "#5B97BC" + - state: medicaldoctor - type: PresetIdCard # Delta V - Brigmedic, see Prototypes/DeltaV/Roles/Jobs/Security/brigmedic.yml job: Brigmedic @@ -454,7 +576,11 @@ - type: Sprite layers: - state: centcom - - state: idcentcom + - state: departmenthead + color: "#1B67A5" + - state: subdepartment + color: "#1B67A5" + - state: cc - type: Item heldPrefix: blue - type: IdCard @@ -473,8 +599,12 @@ components: - type: Sprite layers: - - state: gold - - state: ert_commander + - state: centcom + - state: departmenthead + color: "#1B67A5" + - state: subdepartment + color: "#1B67A5" + - state: captain - type: IdCard jobTitle: ERT Company Commander - type: Item @@ -487,8 +617,12 @@ components: - type: Sprite layers: - - state: gold - - state: ert_chaplain # we have the sprite for the id but dont have chaplain ERT equipment for now. + - state: centcom + - state: departmenthead + color: "#1B67A5" + - state: subdepartment + color: "#C96DBF" + - state: chaplain - type: IdCard jobTitle: ERT Soul Officer - type: Item @@ -501,8 +635,12 @@ components: - type: Sprite layers: - - state: gold - - state: ert_engineer + - state: centcom + - state: departmenthead + color: "#1B67A5" + - state: subdepartment + color: "#F39F27" + - state: stationengineer - type: IdCard jobTitle: ERT Field Engineer @@ -513,8 +651,12 @@ components: - type: Sprite layers: - - state: gold - - state: ert_janitor + - state: centcom + - state: departmenthead + color: "#1B67A5" + - state: subdepartment + color: "#58C800" + - state: janitor - type: IdCard jobTitle: ERT Custodian @@ -525,8 +667,12 @@ components: - type: Sprite layers: - - state: gold - - state: ert_medic + - state: centcom + - state: departmenthead + color: "#1B67A5" + - state: subdepartment + color: "#5B97BC" + - state: medicaldoctor - type: IdCard jobTitle: ERT Medical Doctor @@ -537,8 +683,12 @@ components: - type: Sprite layers: - - state: gold - - state: ert_security + - state: centcom + - state: departmenthead + color: "#1B67A5" + - state: subdepartment + color: "#CB0000" + - state: securityofficer - type: IdCard jobTitle: ERT Field Officer @@ -551,7 +701,11 @@ - type: Sprite layers: - state: centcom - - state: idcentcom + - state: departmenthead + color: "#1B67A5" + - state: subdepartment + color: "#1B67A5" + - state: cc - type: Item heldPrefix: blue - type: IdCard @@ -565,12 +719,16 @@ id: MusicianIDCard name: musician ID card components: - - type: Sprite - layers: - - state: default - - state: idmusician - - type: PresetIdCard - job: Musician + - type: Sprite + layers: + - state: default + - state: department + color: "#878787" + - state: subdepartment + color: "#878787" + - state: musician + - type: PresetIdCard + job: Musician - type: entity parent: CentcomIDCard @@ -580,6 +738,11 @@ - type: Sprite layers: - state: centcom + - state: departmenthead + color: "#CB0000" + - state: subdepartment + color: "#CB0000" + - state: death - type: Item heldPrefix: blue - type: IdCard @@ -600,7 +763,11 @@ - type: Sprite layers: - state: default - - state: idpassenger + - state: department + color: "#878787" + - state: subdepartment + color: "#878787" + - state: passenger - type: AgentIDCard icons: # TODO figure out a better way of doing this. @@ -691,8 +858,12 @@ components: - type: Sprite layers: - - state: orange - - state: idatmospherictechnician + - state: default + - state: department + color: "#F39F27" + - state: subdepartment + color: "#F39F27" + - state: atmospherictechnician - type: PresetIdCard job: AtmosphericTechnician @@ -703,7 +874,12 @@ components: - type: Sprite layers: - - state: syndie + - state: black + - state: department + color: "#CB0000" + - state: subdepartment + color: "#CB0000" + - state: syndicate - type: Access tags: - NuclearOperative @@ -716,7 +892,12 @@ components: - type: Sprite layers: - - state: pirate + - state: black + - state: department + color: "#878787" + - state: subdepartment + color: "#878787" + - state: death - type: Access tags: - NuclearOperative @@ -730,7 +911,11 @@ - type: Sprite layers: - state: default - - state: idpsychologist + - state: department + color: "#5B97BC" + - state: subdepartment + color: "#5B97BC" + - state: psychologist - type: PresetIdCard job: Psychologist @@ -742,7 +927,11 @@ - type: Sprite layers: - state: default - - state: idreporter + - state: department + color: "#58C800" + - state: subdepartment + color: "#58C800" + - state: headofpersonnel - type: PresetIdCard job: Reporter @@ -754,7 +943,11 @@ - type: Sprite layers: - state: default - - state: idboxer + - state: department + color: "#878787" + - state: subdepartment + color: "#878787" + - state: boxer - type: PresetIdCard job: Boxer @@ -766,7 +959,11 @@ - type: Sprite layers: - state: default - - state: idzookeeper + - state: department + color: "#58C800" + - state: subdepartment + color: "#58C800" + - state: zookeeper - type: PresetIdCard job: Zookeeper @@ -778,7 +975,11 @@ - type: Sprite layers: - state: default - - state: iddetective + - state: department + color: "#CB0000" + - state: subdepartment + color: "#CB0000" + - state: detective - type: PresetIdCard job: Detective @@ -791,6 +992,11 @@ - type: Sprite layers: - state: centcom + - state: departmenthead + color: "#CB0000" + - state: subdepartment + color: "#CB0000" + - state: cc - type: Item heldPrefix: blue - type: IdCard @@ -804,8 +1010,13 @@ components: - type: Sprite layers: - - state: default - - state: idcluwne + - state: rainbow + - state: department + color: "#5DC574" + - state: subdepartment + color: "#5DC574" + - state: clown + color: "#7C0A0A" - type: IdCard jobTitle: Cluwne - type: Unremoveable @@ -818,7 +1029,11 @@ - type: Sprite layers: - state: default - - state: idseniorengineer + - state: department + color: "#F39F27" + - state: subdepartment + color: "#F39F27" + - state: senior - type: PresetIdCard job: SeniorEngineer @@ -830,7 +1045,11 @@ - type: Sprite layers: - state: default - - state: idseniorresearcher + - state: department + color: "#C96DBF" + - state: subdepartment + color: "#C96DBF" + - state: senior - type: PresetIdCard job: SeniorResearcher @@ -842,7 +1061,11 @@ - type: Sprite layers: - state: default - - state: idseniorphysician + - state: department + color: "#5B97BC" + - state: subdepartment + color: "#5B97BC" + - state: senior - type: PresetIdCard job: SeniorPhysician @@ -854,6 +1077,10 @@ - type: Sprite layers: - state: default - - state: idseniorofficer + - state: department + color: "#CB0000" + - state: subdepartment + color: "#CB0000" + - state: senior - type: PresetIdCard job: SeniorOfficer diff --git a/Resources/Prototypes/Entities/Objects/Misc/machine_parts.yml b/Resources/Prototypes/Entities/Objects/Misc/machine_parts.yml index 592f8be693b..341acb52f0b 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/machine_parts.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/machine_parts.yml @@ -7,8 +7,17 @@ components: - type: Sprite sprite: Objects/Misc/stock_parts.rsi + scale: 0.8, 0.8 - type: Item size: Tiny + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/component_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/component_drop.ogg + - type: EmitSoundOnLand + sound: /Audio/SimpleStation14/Items/Handling/component_drop.ogg + +# Rating 1 - type: entity id: CapacitorStockPart diff --git a/Resources/Prototypes/Entities/Objects/Misc/paper.yml b/Resources/Prototypes/Entities/Objects/Misc/paper.yml index c1a5d9a1bfd..1767a956c8c 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/paper.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/paper.yml @@ -70,6 +70,12 @@ reagents: - ReagentId: Fiber Quantity: 1 + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/paper_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/paper_drop.ogg + - type: EmitSoundOnLand + sound: /Audio/SimpleStation14/Items/Handling/paper_drop.ogg - type: entity name: paper scrap diff --git a/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml b/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml index 748ab123185..5a8726ff5ce 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml @@ -52,6 +52,12 @@ - Book - type: StealTarget stealGroup: Bible + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/book_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/book_drop.ogg + - type: EmitSoundOnLand + sound: /Audio/SimpleStation14/Items/Handling/book_drop.ogg - type: entity parent: Bible diff --git a/Resources/Prototypes/Entities/Objects/Specific/Mech/mechs.yml b/Resources/Prototypes/Entities/Objects/Specific/Mech/mechs.yml index 5a2587ff710..ffa4e7ade7a 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Mech/mechs.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Mech/mechs.yml @@ -95,6 +95,7 @@ - type: GuideHelp guides: - Robotics + - type: CanWalk - type: entity id: MechRipley diff --git a/Resources/Prototypes/Entities/Objects/Specific/Research/disk.yml b/Resources/Prototypes/Entities/Objects/Specific/Research/disk.yml index 0cb605cee64..fa1b75530b6 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Research/disk.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Research/disk.yml @@ -11,6 +11,12 @@ - type: GuideHelp guides: - Science + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/disk_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/disk_drop.ogg + - type: EmitSoundOnLand + sound: /Audio/SimpleStation14/Items/Handling/disk_drop.ogg - type: entity parent: ResearchDisk @@ -69,3 +75,9 @@ components: - type: TechnologyDisk tierWeightPrototype: RareTechDiskTierWeights + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/disk_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/disk_drop.ogg + - type: EmitSoundOnLand + sound: /Audio/SimpleStation14/Items/Handling/disk_drop.ogg diff --git a/Resources/Prototypes/Entities/Objects/Tools/matches.yml b/Resources/Prototypes/Entities/Objects/Tools/matches.yml index e8601fcf355..561e478d93a 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/matches.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/matches.yml @@ -59,6 +59,10 @@ id: Matchbox description: A small box of Almost But Not Quite Plasma Premium Matches. components: + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/matchbox_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/matchbox_drop.ogg - type: EmitSoundOnLand sound: path: /Audio/Items/matchbox_drop.ogg diff --git a/Resources/Prototypes/Entities/Objects/Tools/toolbox.yml b/Resources/Prototypes/Entities/Objects/Tools/toolbox.yml index 667d8559971..eee102bfbd7 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/toolbox.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/toolbox.yml @@ -7,6 +7,10 @@ layers: - map: [ base ] state: icon + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/toolbox_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/toolbox_drop.ogg - type: EmitSoundOnLand sound: path: /Audio/Items/toolbox_drop.ogg diff --git a/Resources/Prototypes/Entities/Objects/Tools/tools.yml b/Resources/Prototypes/Entities/Objects/Tools/tools.yml index f1bf2ff98e7..04afa1a3778 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/tools.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/tools.yml @@ -4,6 +4,10 @@ id: Wirecutter description: This kills the wire. components: + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/wirecutter_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/wirecutter_drop.ogg - type: EmitSoundOnLand sound: path: /Audio/Items/wirecutter_drop.ogg @@ -50,6 +54,10 @@ id: Screwdriver description: Industrial grade torque in a small screwdriving package. components: + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/screwdriver_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/screwdriver_drop.ogg - type: EmitSoundOnLand sound: path: /Audio/Items/screwdriver_drop.ogg @@ -94,6 +102,10 @@ id: Wrench description: 'A common tool for assembly and disassembly. Remember: righty tighty, lefty loosey.' components: + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/wrench_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/wrench_drop.ogg - type: EmitSoundOnLand sound: path: /Audio/Items/wrench_drop.ogg @@ -133,6 +145,10 @@ id: Crowbar description: A multipurpose tool to pry open doors and fight interdimensional invaders. components: + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/crowbar_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/crowbar_drop.ogg - type: EmitSoundOnLand sound: path: /Audio/Items/crowbar_drop.ogg @@ -191,6 +207,10 @@ id: Multitool description: An advanced tool to copy, store, and send electrical pulses and signals through wires and machines components: + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/multitool_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/multitool_drop.ogg - type: EmitSoundOnLand sound: path: /Audio/Items/multitool_drop.ogg diff --git a/Resources/Prototypes/Entities/Objects/Tools/welders.yml b/Resources/Prototypes/Entities/Objects/Tools/welders.yml index 9bf3f2e2cb9..e141f35caeb 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/welders.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/welders.yml @@ -4,6 +4,10 @@ id: Welder description: "Melts anything as long as it's fueled, don't forget your eye protection!" components: + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/welder_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/welder_drop.ogg - type: EmitSoundOnLand sound: path: /Audio/Items/welder_drop.ogg diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml index 4aff7363a45..630354f23d9 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml @@ -117,3 +117,6 @@ - id: TrashBananaPeelExplosive sound: path: /Audio/Effects/unwrap.ogg + - type: Tag + tags: + - Banana diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/base_ammo.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/base_ammo.yml new file mode 100644 index 00000000000..eceec8ac3e8 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/base_ammo.yml @@ -0,0 +1,11 @@ +- type: entity + abstract: true + parent: BaseItem + id: BaseMagazineBox + components: + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/ammobox_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/ammobox_drop.ogg + - type: EmitSoundOnLand + sound: /Audio/SimpleStation14/Items/Handling/ammobox_drop.ogg diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/caseless_rifle.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/caseless_rifle.yml index 063268d8b53..f1550cf9a8f 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/caseless_rifle.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/caseless_rifle.yml @@ -1,6 +1,6 @@ - type: entity abstract: true - parent: BaseItem + parent: BaseMagazineBox id: BaseMagazineBoxCaselessRifle name: ammunition box (.25 caseless) components: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/light_rifle.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/light_rifle.yml index 0670e376360..22eeeff859d 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/light_rifle.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/light_rifle.yml @@ -1,6 +1,6 @@ - type: entity abstract: true - parent: BaseItem + parent: BaseMagazineBox id: BaseMagazineBoxLightRifle name: ammunition box (.30 rifle) components: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/magnum.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/magnum.yml index 65f6bff00eb..c304f0af111 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/magnum.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/magnum.yml @@ -1,6 +1,6 @@ - type: entity abstract: true - parent: BaseItem + parent: BaseMagazineBox id: BaseMagazineBoxMagnum components: - type: BallisticAmmoProvider diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/pistol.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/pistol.yml index 9f6a8e8257d..b78551b99bd 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/pistol.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/pistol.yml @@ -1,6 +1,6 @@ - type: entity abstract: true - parent: BaseItem + parent: BaseMagazineBox id: BaseMagazineBoxPistol name: ammunition box (.35 auto) components: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/rifle.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/rifle.yml index c321b77d10b..8e6c79dfe57 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/rifle.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/rifle.yml @@ -1,6 +1,6 @@ - type: entity abstract: true - parent: BaseItem + parent: BaseMagazineBox id: BaseMagazineBoxRifle components: - type: BallisticAmmoProvider diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/toy.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/toy.yml index 11649f3db3c..a3b1855a746 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/toy.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/toy.yml @@ -1,6 +1,6 @@ - type: entity abstract: true - parent: BaseItem + parent: BaseMagazineBox id: BoxDonkSoftBase name: foamdart box components: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml index 426be1386a9..17e31e5893c 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml @@ -11,11 +11,11 @@ - type: MeleeWeapon wideAnimationRotation: -135 attackRate: 1.5 + soundHit: + path: /Audio/SimpleStation14/Weapons/Melee/rapierhit.ogg damage: types: Slash: 17 #cmon, it has to be at least BETTER than the rest. - soundHit: - path: /Audio/Weapons/bladeslice.ogg - type: Reflect enabled: true reflectProb: .5 @@ -43,11 +43,11 @@ state: icon - type: MeleeWeapon wideAnimationRotation: -135 + soundHit: + path: /Audio/SimpleStation14/Weapons/Melee/rapierhit.ogg damage: types: Slash: 15 - soundHit: - path: /Audio/Weapons/bladeslice.ogg - type: Item size: Normal sprite: DeltaV/Objects/Weapons/Melee/katana.rsi #DeltaV diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index 6b478a646e6..b340f68e5cb 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -158,6 +158,7 @@ - APCElectronics - SMESMachineCircuitboard - SubstationMachineCircuitboard + - WallmountSubstationElectronics - CellRechargerCircuitboard - BorgChargerCircuitboard - WeaponCapacitorRechargerCircuitboard @@ -743,7 +744,7 @@ - ShellShotgunPractice - WeaponLaserCarbinePractice - WeaponDisablerPractice - - ShockCollar # Nyanotrasen - Shock Collar + - ShockCollar # DeltaV - .38 special ammo - Add various .38 special ammo to security techfab - MagazineBoxSpecial - MagazineBoxSpecialPractice diff --git a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml index 2c4fccb8b3e..c90d42b42cc 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml @@ -111,6 +111,8 @@ understands: - GalacticCommon - RobotTalk + - type: VendingMachine + soundVend: /Audio/SimpleStation14/Machines/machine_vend.ogg - type: entity parent: VendingMachine diff --git a/Resources/Prototypes/Entities/Structures/Power/substation.yml b/Resources/Prototypes/Entities/Structures/Power/substation.yml index 94de12be185..04c83bd991e 100644 --- a/Resources/Prototypes/Entities/Structures/Power/substation.yml +++ b/Resources/Prototypes/Entities/Structures/Power/substation.yml @@ -244,6 +244,16 @@ - type: Battery maxCharge: 2000000 startingCharge: 2000000 + - type: ContainerFill + containers: + board: [ WallmountSubstationElectronics ] + capacitor: [ CapacitorStockPart ] + powercell: [ PowerCellSmall ] + - type: ContainerContainer + containers: + board: !type:Container + capacitor: !type:Container + powercell: !type:Container # Construction Frame - type: entity diff --git a/Resources/Prototypes/Entities/Structures/Storage/Closets/base_structureclosets.yml b/Resources/Prototypes/Entities/Structures/Storage/Closets/base_structureclosets.yml index 0ef99b9f47e..23b1efdf535 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Closets/base_structureclosets.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Closets/base_structureclosets.yml @@ -48,6 +48,10 @@ layer: - MachineLayer - type: EntityStorage + closeSound: + path: /Audio/Effects/closet_close.ogg + openSound: + path: /Audio/Effects/closet_open.ogg - type: ContainerContainer containers: entity_storage: !type:Container diff --git a/Resources/Prototypes/Floof/Catalog/uplink_catalog.yml b/Resources/Prototypes/Floof/Catalog/uplink_catalog.yml new file mode 100644 index 00000000000..741be24908f --- /dev/null +++ b/Resources/Prototypes/Floof/Catalog/uplink_catalog.yml @@ -0,0 +1,10 @@ +- type: listing + id: UplinkSocksCoderValid + name: uplink-coder-socks-valid-name + description: uplink-coder-socks-valid-desc + productEntity: ClothingUnderSocksCoderValid + cost: + Telecrystal: 1 + categories: + - UplinkPointless + \ No newline at end of file diff --git a/Resources/Prototypes/Floof/Entities/Clothing/Under/under.yml b/Resources/Prototypes/Floof/Entities/Clothing/Under/under.yml new file mode 100644 index 00000000000..9222edade62 --- /dev/null +++ b/Resources/Prototypes/Floof/Entities/Clothing/Under/under.yml @@ -0,0 +1,10 @@ +- type: entity + parent: ClothingShoesBase + id: ClothingUnderSocksCoderValid + name: blood-red coder socks + description: "It's time to code maliciously while petting a syndicat!!! :3 :3" + components: + - type: Sprite + sprite: Floof/Clothing/Under/Socks/codervalid.rsi + - type: Clothing + sprite: Floof/Clothing/Under/Socks/codervalid.rsi diff --git a/Resources/Prototypes/Floof/Entities/Clothing/Uniforms/misc.yml b/Resources/Prototypes/FloofStation/Entities/Clothing/Uniforms/misc.yml similarity index 100% rename from Resources/Prototypes/Floof/Entities/Clothing/Uniforms/misc.yml rename to Resources/Prototypes/FloofStation/Entities/Clothing/Uniforms/misc.yml diff --git a/Resources/Prototypes/FloofStation/Entities/Objects/Consumable/Drinks/drinks.yml b/Resources/Prototypes/FloofStation/Entities/Objects/Consumable/Drinks/drinks.yml new file mode 100644 index 00000000000..36ab0210f4f --- /dev/null +++ b/Resources/Prototypes/FloofStation/Entities/Objects/Consumable/Drinks/drinks.yml @@ -0,0 +1,192 @@ +- type: entity + parent: DrinkGlass + id: DrinkBlueBallerGlass + suffix: blue baller + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: BlueBaller + Quantity: 30 + - type: Icon + sprite: Floof/Objects/Consumable/Drinks/blueballer.rsi + state: icon + +- type: entity + parent: DrinkGlass + id: DrinkDemonSeedGlass + suffix: demon seed + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: DemonSeed + Quantity: 30 + - type: Icon + sprite: Floof/Objects/Consumable/Drinks/demonseed.rsi + state: icon + +- type: entity + parent: DrinkGlass + id: DrinkDoubleCreamBlasterGlass + suffix: double cream blaster + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: DoubleCreamBlaster + Quantity: 30 + - type: Icon + sprite: Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi + state: icon + +- type: entity + parent: DrinkGlass + id: DrinkEmeraldSwingerGlass + suffix: emerald swinger + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: EmeraldSwinger + Quantity: 30 + - type: Icon + sprite: Floof/Objects/Consumable/Drinks/emeraldswinger.rsi + state: icon + +- type: entity + parent: DrinkGlass + id: DrinkMarieJulepGlass + suffix: marie julep + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: MarieJulep + Quantity: 30 + - type: Icon + sprite: Floof/Objects/Consumable/Drinks/mariejulep.rsi + state: icon + +- type: entity + parent: DrinkGlass + id: DrinkOrgasmOnTheBeachGlass + suffix: orgasm on the beach + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: OrgasmOnTheBeach + Quantity: 30 + - type: Icon + sprite: Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi + state: icon + +- type: entity + parent: DrinkGlass + id: DrinkPomPassionGlass + suffix: pom passion + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: PomPassion + Quantity: 30 + - type: Icon + sprite: Floof/Objects/Consumable/Drinks/pompassion.rsi + state: icon + +- type: entity + parent: DrinkGlass + id: DrinkRedRocketGlass + suffix: red rocket + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: RedRocket + Quantity: 30 + - type: Icon + sprite: Floof/Objects/Consumable/Drinks/redrocket.rsi + state: icon + +- type: entity + parent: DrinkGlass + id: DrinkSemenBombGlass + suffix: semen bomb + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: SemenBomb + Quantity: 30 + - type: Icon + sprite: Floof/Objects/Consumable/Drinks/semenbomb.rsi + state: icon + +- type: entity + parent: DrinkGlass + id: DrinkSemenHemorrhageGlass + suffix: semen hemorrhage + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: SemenHemorrhage + Quantity: 30 + - type: Icon + sprite: Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi + state: icon + +- type: entity + parent: DrinkGlass + id: DrinkWatermelonGinJizzGlass + suffix: watermelon gin jizz + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: WatermelonGinJizz + Quantity: 30 + - type: Icon + sprite: Floof/Objects/Consumable/Drinks/watermelonginjizz.rsi + state: icon + +- type: entity + parent: DrinkGlass + id: DrinkYeOlHandyGlass + suffix: ye' ol' handy + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: YeOlHandy + Quantity: 30 + - type: Icon + sprite: Floof/Objects/Consumable/Drinks/yeolhandy.rsi + state: icon + diff --git a/Resources/Prototypes/FloofStation/Entities/Objects/Consumable/Drinks/drinks_bottles.yml b/Resources/Prototypes/FloofStation/Entities/Objects/Consumable/Drinks/drinks_bottles.yml new file mode 100644 index 00000000000..73a532828f6 --- /dev/null +++ b/Resources/Prototypes/FloofStation/Entities/Objects/Consumable/Drinks/drinks_bottles.yml @@ -0,0 +1,35 @@ +- type: entity + parent: [DrinkBottleVisualsOpenable, DrinkBottleGlassBaseFull] + id: DrinkAnisetteBottleFull + name: anisette bottle + description: Liquor made of anise and sugar, typically used as a sweeter form of absinthe. + components: + - type: SolutionContainerManager + solutions: + drink: + reagents: + - ReagentId: Anisette + Quantity: 100 + - type: Label + currentLabel: anisette + - type: Sprite + sprite: Floof/Objects/Consumable/Drinks/anisettebottle.rsi + - type: Sealable + +- type: entity + parent: [DrinkBottleVisualsOpenable, DrinkBottleGlassBaseFull] + id: DrinkCumBottleFull + name: bottle'o'cum + description: Straight nard nectar. Ethically sourced. + components: + - type: SolutionContainerManager + solutions: + drink: + reagents: + - ReagentId: Cum + Quantity: 100 + - type: Label + currentLabel: bottle'o'cum + - type: Sprite + sprite: Floof/Objects/Consumable/Drinks/bottleocum.rsi + - type: Sealable diff --git a/Resources/Prototypes/FloofStation/Flavors/flavors.yml b/Resources/Prototypes/FloofStation/Flavors/flavors.yml index e9a75f2231f..330885df76d 100644 --- a/Resources/Prototypes/FloofStation/Flavors/flavors.yml +++ b/Resources/Prototypes/FloofStation/Flavors/flavors.yml @@ -1,4 +1,70 @@ +- type: flavor + id: anisette + flavorType: Complex + description: flavor-complex-anisette + +- type: flavor + id: blueballer + flavorType: Complex + description: flavor-complex-blueballer + +- type: flavor + id: demonseed + flavorType: Complex + description: flavor-complex-demonseed + +- type: flavor + id: doublecreamblaster + flavorType: Complex + description: flavor-complex-doublecreamblaster + +- type: flavor + id: emeraldswinger + flavorType: Complex + description: flavor-complex-emeraldswinger + +# Cum - type: flavor id: nikkonectar flavorType: Complex description: flavor-complex-nikkonectar + +- type: flavor + id: mariejulep + flavorType: Complex + description: flavor-complex-mariejulep + +- type: flavor + id: orgasmonthebeach + flavorType: Complex + description: flavor-complex-orgasmonthebeach + +- type: flavor + id: pompassion + flavorType: Complex + description: flavor-complex-pompassion + +- type: flavor + id: redrocket + flavorType: Complex + description: flavor-complex-redrocket + +- type: flavor + id: semenbomb + flavorType: Complex + description: flavor-complex-semenbomb + +- type: flavor + id: semenhemorrhage + flavorType: Complex + description: flavor-complex-semenhemorrhage + +- type: flavor + id: watermelonginjizz + flavorType: Complex + description: flavor-complex-watermelonginjizz + +- type: flavor + id: yeolhandy + flavorType: Complex + description: flavor-complex-yeolhandy diff --git a/Resources/Prototypes/Floof/Loadouts/uniform.yml b/Resources/Prototypes/FloofStation/Loadouts/uniform.yml similarity index 100% rename from Resources/Prototypes/Floof/Loadouts/uniform.yml rename to Resources/Prototypes/FloofStation/Loadouts/uniform.yml diff --git a/Resources/Prototypes/FloofStation/Reagents/Consumable/Drink/alcohol.yml b/Resources/Prototypes/FloofStation/Reagents/Consumable/Drink/alcohol.yml new file mode 100644 index 00000000000..6bec6b41a25 --- /dev/null +++ b/Resources/Prototypes/FloofStation/Reagents/Consumable/Drink/alcohol.yml @@ -0,0 +1,287 @@ +- type: reagent + id: Anisette + name: reagent-name-anisette + parent: BaseAlcohol + desc: reagent-desc-anisette + physicalDesc: reagent-physical-desc-strong-smelling + flavor: anisette + color: "#f9f8c6" + +- type: reagent + id: BlueBaller + name: reagent-name-blueballer + parent: BaseAlcohol + desc: reagent-desc-blueballer + physicalDesc: reagent-physical-desc-tropical + flavor: blueballer + color: "#88065b" + metamorphicSprite: + sprite: Floof/Objects/Consumable/Drinks/blueballer.rsi + state: icon_empty + metamorphicMaxFillLevels: 5 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + metabolisms: + Drink: + effects: + - !type:SatiateThirst + factor: 2 + - !type:AdjustReagent + reagent: Ethanol + amount: 0.06 + - !type:AdjustReagent + reagent: Pomelustine + amount: 0.5 + +- type: reagent + id: DemonSeed + name: reagent-name-demonseed + parent: BaseAlcohol + desc: reagent-desc-demonseed + physicalDesc: reagent-physical-desc-gloopy + flavor: demonseed + color: "#301637" + metamorphicSprite: + sprite: Floof/Objects/Consumable/Drinks/demonseed.rsi + state: icon_empty + metamorphicMaxFillLevels: 5 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + metabolisms: + Drink: + effects: + - !type:SatiateThirst + factor: 2 + - !type:AdjustReagent + reagent: Ethanol + amount: 0.07 + - !type:AdjustReagent + reagent: Pomelustine + amount: 1 + +- type: reagent + id: DoubleCreamBlaster + name: reagent-name-doublecreamblaster + parent: BaseAlcohol + desc: reagent-desc-doublecreamblaster + physicalDesc: reagent-physical-desc-fizzy-and-creamy + flavor: doublecreamblaster + color: "#532104" + metamorphicSprite: + sprite: Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi + state: icon_empty + metamorphicMaxFillLevels: 5 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + metabolisms: + Drink: + effects: + - !type:SatiateThirst + factor: 3 + +- type: reagent + id: EmeraldSwinger + name: reagent-name-emeraldswinger + parent: BaseAlcohol + desc: reagent-desc-emeraldswinger + physicalDesc: reagent-physical-desc-buzzy + flavor: emeraldswinger + color: "#50c878" + metamorphicSprite: + sprite: Floof/Objects/Consumable/Drinks/emeraldswinger.rsi + state: icon_empty + metamorphicMaxFillLevels: 5 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + metabolisms: + Drink: + effects: + - !type:SatiateThirst + factor: 2 + - !type:AdjustReagent + reagent: Ethanol + amount: 0.04 + +- type: reagent + id: MarieJulep + name: reagent-name-mariejulep + parent: BaseAlcohol + desc: reagent-desc-mariejulep + physicalDesc: reagent-physical-desc-refreshing + flavor: mariejulep + color: "#f3eaaf" + metamorphicSprite: + sprite: Floof/Objects/Consumable/Drinks/mariejulep.rsi + state: icon_empty + metamorphicMaxFillLevels: 3 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + metabolisms: + Drink: + effects: + - !type:SatiateThirst + factor: 2 + - !type:AdjustReagent + reagent: Ethanol + amount: 0.06 + +- type: reagent + id: OrgasmOnTheBeach + name: reagent-name-orgasmonthebeach + parent: BaseAlcohol + desc: reagent-desc-orgasmonthebeach + physicalDesc: reagent-physical-desc-tart + flavor: orgasmonthebeach + color: "#b5693a" + metamorphicSprite: + sprite: Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi + state: icon_empty + metamorphicMaxFillLevels: 5 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + metabolisms: + Drink: + effects: + - !type:SatiateThirst + factor: 2 + - !type:AdjustReagent + reagent: Ethanol + amount: 0.05 + +- type: reagent + id: PomPassion + name: reagent-name-pompassion + parent: BaseAlcohol + desc: reagent-desc-pompassion + physicalDesc: reagent-physical-desc-sugary + flavor: pompassion + color: "#9c0101" + metamorphicSprite: + sprite: Floof/Objects/Consumable/Drinks/pompassion.rsi + state: icon_empty + metamorphicMaxFillLevels: 3 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + metabolisms: + Drink: + effects: + - !type:SatiateThirst + factor: 2 + - !type:AdjustReagent + reagent: Ethanol + amount: 0.03 + +- type: reagent + id: RedRocket + name: reagent-name-redrocket + parent: BaseAlcohol + desc: reagent-desc-redrocket + physicalDesc: reagent-physical-desc-saucey + flavor: redrocket + color: "#ba3b3d" + metamorphicSprite: + sprite: Floof/Objects/Consumable/Drinks/redrocket.rsi + state: icon_empty + metamorphicMaxFillLevels: 5 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + metabolisms: + Drink: + effects: + - !type:SatiateThirst + factor: 2 + - !type:AdjustReagent + reagent: Ethanol + amount: 0.06 + +- type: reagent + id: SemenBomb + name: reagent-name-semenbomb + parent: BaseAlcohol + desc: reagent-desc-semenbomb + physicalDesc: reagent-physical-desc-foamy + flavor: semenbomb + color: "#fbb117" + metamorphicSprite: + sprite: Floof/Objects/Consumable/Drinks/semenbomb.rsi + state: icon_empty + metamorphicMaxFillLevels: 5 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + metabolisms: + Drink: + effects: + - !type:SatiateThirst + factor: 2 + - !type:AdjustReagent + reagent: Ethanol + amount: 0.04 + +- type: reagent + id: SemenHemorrhage + name: reagent-name-semenhemorrhage + parent: BaseAlcohol + desc: reagent-desc-semenhemorrhage + physicalDesc: reagent-physical-desc-heterogeneous + flavor: semenhemorrhage + color: "#c83341" + metamorphicSprite: + sprite: Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi + state: icon_empty + metamorphicMaxFillLevels: 5 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + metabolisms: + Drink: + effects: + - !type:SatiateThirst + factor: 2 + - !type:AdjustReagent + reagent: Ethanol + amount: 0.03 + +- type: reagent + id: WatermelonGinJizz + name: reagent-name-watermelonginjizz + parent: BaseAlcohol + desc: reagent-desc-watermelonginjizz + physicalDesc: reagent-physical-desc-fizzy + flavor: watermelonginjizz + color: "#c79081" + metamorphicSprite: + sprite: Floof/Objects/Consumable/Drinks/watermelonginjizz.rsi + state: icon_empty + metamorphicMaxFillLevels: 3 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + metabolisms: + Drink: + effects: + - !type:SatiateThirst + factor: 2 + - !type:AdjustReagent + reagent: Ethanol + amount: 0.07 + +- type: reagent + id: YeOlHandy + name: reagent-name-yeolhandy + parent: BaseAlcohol + desc: reagent-desc-yeolhandy + physicalDesc: reagent-physical-desc-soothing + flavor: yeolhandy + color: "#d29062" + metamorphicSprite: + sprite: Floof/Objects/Consumable/Drinks/yeolhandy.rsi + state: icon_empty + metamorphicMaxFillLevels: 5 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + metabolisms: + Drink: + effects: + - !type:SatiateThirst + factor: 2 + - !type:AdjustReagent + reagent: Ethanol + amount: 0.05 diff --git a/Resources/Prototypes/FloofStation/Reagents/Consumable/Drink/juice.yml b/Resources/Prototypes/FloofStation/Reagents/Consumable/Drink/juice.yml new file mode 100644 index 00000000000..2ec00d72e8e --- /dev/null +++ b/Resources/Prototypes/FloofStation/Reagents/Consumable/Drink/juice.yml @@ -0,0 +1,8 @@ +- type: reagent + id: JuicePomegranate + name: reagent-name-juice-pomegranate + parent: BaseJuice + desc: reagent-desc-juice-pomegranate + physicalDesc: reagent-physical-desc-sticky + flavor: sweet + color: "#660C21" \ No newline at end of file diff --git a/Resources/Prototypes/FloofStation/Reactions/chemicals.yml b/Resources/Prototypes/FloofStation/Recipes/Reactions/chemicals.yml similarity index 100% rename from Resources/Prototypes/FloofStation/Reactions/chemicals.yml rename to Resources/Prototypes/FloofStation/Recipes/Reactions/chemicals.yml diff --git a/Resources/Prototypes/FloofStation/Recipes/Reactions/drinks.yml b/Resources/Prototypes/FloofStation/Recipes/Reactions/drinks.yml new file mode 100644 index 00000000000..ec1ef2d3036 --- /dev/null +++ b/Resources/Prototypes/FloofStation/Recipes/Reactions/drinks.yml @@ -0,0 +1,154 @@ +- type: reaction + id: BlueBaller + reactants: + BlueCuracao: + amount: 1 + JuiceWatermelon: + amount: 1 + Pomelustine: + amount: 1 + products: + BlueBaller: 3 + +- type: reaction + id: DemonSeed + reactants: + Blood: + amount: 2 + Cum: + amount: 1 + Pomelustine: + amount: 2 + Vodka: + amount: 1 + products: + DemonSeed: 6 + +- type: reaction + id: DoubleCreamBlaster + reactants: + Cream: + amount: 1 + Cum: + amount: 1 + RootBeer: + amount: 1 + products: + DoubleCreamBlaster: 3 + + +- type: reaction + id: EmeraldSwinger + reactants: + JuiceGrape: + amount: 2 + MelonLiquor: + amount: 2 + JuicePomegranate: + amount: 1 + products: + EmeraldSwinger: 5 + +- type: reaction + id: MarieJulep + reactants: + Anisette: + amount: 1 + Gin: + amount: 1 + JuiceLime: + amount: 1 + Sugar: + amount: 1 + products: + MarieJulep: 4 + +- type: reaction + id: OrgasmOnTheBeach + reactants: + Cum: + amount: 1 + JuiceOrange: + amount: 2 + JuiceWatermelon: + amount: 2 + Vodka: + amount: 1 + products: + OrgasmOnTheBeach: 5 + +- type: reaction + id: PomPassion + reactants: + BlueCuracao: + amount: 1 + Grenadine: + amount: 1 + JuicePomegranate: + amount: 1 + products: + PomPassion: 3 + +- type: reaction + id: RedRocket + reactants: + Grenadine: + amount: 2 + JuicePomegranate: + amount: 1 + Rum: + amount: 1 + JuiceWatermelon: + amount: 2 + products: + RedRocket: 6 + +- type: reaction + id: SemenBomb + reactants: + Beer: + amount: 2 + Cum: + amount: 1 + products: + SemenBomb: 3 + +- type: reaction + id: SemenHemorrhage + reactants: + Cum: + amount: 1 + Grenadine: + amount: 1 + JuiceApple: + amount: 2 + products: + SemenHemorrhage: 5 + +- type: reaction + id: WatermelonGinJizz + reactants: + Cum: + amount: 1 + JuiceWatermelon: + amount: 2 + SodaWater: + amount: 1 + Vodka: + amount: 1 + products: + WatermelonGinJizz: 5 + +- type: reaction + id: YeOlHandy + reactants: + Ice: + amount: 1 + JuiceOrange: + amount: 2 + JuicePomegranate: + amount: 1 + Whiskey: + amount: 1 + products: + YeOlHandy: 5 diff --git a/Resources/Prototypes/FloofStation/Reactions/medicine.yml b/Resources/Prototypes/FloofStation/Recipes/Reactions/medicine.yml similarity index 100% rename from Resources/Prototypes/FloofStation/Reactions/medicine.yml rename to Resources/Prototypes/FloofStation/Recipes/Reactions/medicine.yml diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml index 00ad5f54ea9..f4936f51f50 100644 --- a/Resources/Prototypes/GameRules/events.yml +++ b/Resources/Prototypes/GameRules/events.yml @@ -49,7 +49,7 @@ noSpawn: true components: - type: StationEvent - startAnnouncement: station-event-bureaucratic-error-announcement + startAnnouncement: true minimumPlayers: 25 weight: 5 duration: 1 @@ -61,7 +61,7 @@ noSpawn: true components: - type: StationEvent - startAnnouncement: station-event-clerical-error-announcement + startAnnouncement: true minimumPlayers: 15 weight: 5 duration: 1 @@ -134,10 +134,8 @@ noSpawn: true components: - type: StationEvent - startAnnouncement: station-event-gas-leak-start-announcement - startAudio: - path: /Audio/Announcements/gas_leak.ogg # DeltaV - custom announcer - endAnnouncement: station-event-gas-leak-end-announcement + startAnnouncement: true + endAnnouncement: true earliestStart: 10 minimumPlayers: 5 weight: 10 @@ -166,12 +164,8 @@ earliestStart: 30 weight: 7.5 minimumPlayers: 10 #Enough to hopefully have at least one engineering guy - startAnnouncement: station-event-meteor-swarm-start-announcement - endAnnouncement: station-event-meteor-swarm-end-announcement - startAudio: - path: /Audio/Announcements/meteors.ogg - params: - volume: -4 + startAnnouncement: true + endAnnouncement: true duration: null #ending is handled by MeteorSwarmRule startDelay: 30 - type: MeteorSwarmRule @@ -182,9 +176,7 @@ noSpawn: true components: - type: StationEvent - startAnnouncement: station-event-vent-creatures-start-announcement - startAudio: - path: /Audio/Announcements/attention.ogg + startAnnouncement: true startDelay: 10 earliestStart: 30 minimumPlayers: 35 @@ -210,9 +202,7 @@ noSpawn: true components: - type: StationEvent - startAnnouncement: station-event-vent-creatures-start-announcement - startAudio: - path: /Audio/Announcements/attention.ogg + startAnnouncement: true startDelay: 10 weight: 5 duration: 50 @@ -230,12 +220,8 @@ components: - type: StationEvent weight: 10 - startAnnouncement: station-event-power-grid-check-start-announcement - endAnnouncement: station-event-power-grid-check-end-announcement - startAudio: - path: /Audio/Announcements/power_off.ogg - params: - volume: -4 + startAnnouncement: true + endAnnouncement: true startDelay: 24 duration: 60 maxDuration: 120 @@ -249,8 +235,6 @@ # - type: StationEvent # weight: 10 # duration: 1 -# startAudio: -# path: /Audio/Announcements/attention.ogg # - type: RandomSentienceRule - type: entity @@ -260,10 +244,8 @@ components: - type: StationEvent weight: 10 - startAnnouncement: station-event-solar-flare-start-announcement - endAnnouncement: station-event-solar-flare-end-announcement - startAudio: - path: /Audio/Announcements/attention.ogg + startAnnouncement: true + endAnnouncement: true duration: 120 maxDuration: 240 - type: SolarFlareRule @@ -301,9 +283,7 @@ noSpawn: true components: - type: StationEvent - startAnnouncement: station-event-vent-clog-start-announcement - startAudio: - path: /Audio/Announcements/ventclog.ogg # DeltaV - custom announcer + startAnnouncement: true earliestStart: 15 minimumPlayers: 15 weight: 5 @@ -317,9 +297,7 @@ noSpawn: true components: - type: StationEvent - startAnnouncement: station-event-vent-creatures-start-announcement - startAudio: - path: /Audio/Announcements/attention.ogg + startAnnouncement: true startDelay: 10 earliestStart: 15 minimumPlayers: 15 @@ -340,9 +318,7 @@ noSpawn: true components: - type: StationEvent - startAnnouncement: station-event-vent-creatures-start-announcement - startAudio: - path: /Audio/Announcements/attention.ogg + startAnnouncement: true startDelay: 10 earliestStart: 20 minimumPlayers: 15 @@ -363,9 +339,7 @@ noSpawn: true components: - type: StationEvent - startAnnouncement: station-event-vent-creatures-start-announcement - startAudio: - path: /Audio/Announcements/attention.ogg + startAnnouncement: true startDelay: 10 earliestStart: 20 minimumPlayers: 15 @@ -382,9 +356,7 @@ # noSpawn: true # components: # - type: StationEvent -# startAnnouncement: station-event-vent-creatures-start-announcement -# startAudio: -# path: /Audio/Announcements/attention.ogg +# startAnnouncement: true # startDelay: 10 # earliestStart: 20 # minimumPlayers: 15 @@ -447,9 +419,7 @@ # noSpawn: true # components: # - type: StationEvent -# startAnnouncement: station-event-immovable-rod-start-announcement -# startAudio: -# path: /Audio/Announcements/attention.ogg +# startAnnouncement: true # weight: 5 # duration: 1 # earliestStart: 45 diff --git a/Resources/Prototypes/GameRules/roundstart.yml b/Resources/Prototypes/GameRules/roundstart.yml index 9ed1889154d..8e518ab2f18 100644 --- a/Resources/Prototypes/GameRules/roundstart.yml +++ b/Resources/Prototypes/GameRules/roundstart.yml @@ -132,6 +132,16 @@ components: - type: RampingStationEventScheduler +- type: entity + id: HellshiftStationEventScheduler + parent: BaseGameRule + noSpawn: true + components: + - type: RampingStationEventScheduler + chaosModifier: 4 # By default, one event each 30-10 seconds after two hours. Changing CVars will cause this to deviate. + startingChaosRatio: 0.025 # Starts as slow as survival, but quickly ramps up + shiftLengthModifier: 2.5 + # variation passes - type: entity id: BasicRoundstartVariation diff --git a/Resources/Prototypes/Language/languages.yml b/Resources/Prototypes/Language/languages.yml index 9187b49ab1d..8848c037228 100644 --- a/Resources/Prototypes/Language/languages.yml +++ b/Resources/Prototypes/Language/languages.yml @@ -35,6 +35,15 @@ - nah - wah +- type: language + id: SignLanguage + signLanguage: true + obfuscation: + !type:ReplacementObfuscation + replacement: + - "language-signlanguage-1" + - "language-signlanguage-2" + # Spoken by slimes. - type: language id: Bubblish diff --git a/Resources/Prototypes/Loadouts/Jobs/engineering.yml b/Resources/Prototypes/Loadouts/Jobs/engineering.yml index 44ef2262bc5..d91814e34d1 100644 --- a/Resources/Prototypes/Loadouts/Jobs/engineering.yml +++ b/Resources/Prototypes/Loadouts/Jobs/engineering.yml @@ -4,6 +4,9 @@ cost: 2 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - StationEngineer @@ -49,6 +52,9 @@ cost: 2 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - StationEngineer diff --git a/Resources/Prototypes/Loadouts/Jobs/medical.yml b/Resources/Prototypes/Loadouts/Jobs/medical.yml index 6dcce11d09f..e9e6aa04231 100644 --- a/Resources/Prototypes/Loadouts/Jobs/medical.yml +++ b/Resources/Prototypes/Loadouts/Jobs/medical.yml @@ -47,6 +47,9 @@ cost: 2 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - MedicalDoctor @@ -62,6 +65,9 @@ cost: 2 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - MedicalDoctor @@ -77,6 +83,9 @@ cost: 2 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - MedicalDoctor @@ -92,6 +101,9 @@ cost: 2 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - MedicalDoctor @@ -107,6 +119,9 @@ cost: 2 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - MedicalDoctor @@ -122,6 +137,9 @@ cost: 2 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - MedicalDoctor @@ -137,6 +155,9 @@ cost: 3 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - MedicalDoctor @@ -188,6 +209,9 @@ cost: 2 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Paramedic @@ -236,6 +260,9 @@ cost: 2 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - MedicalDoctor diff --git a/Resources/Prototypes/Loadouts/Jobs/science.yml b/Resources/Prototypes/Loadouts/Jobs/science.yml index b9c815a15b0..e281b51d036 100644 --- a/Resources/Prototypes/Loadouts/Jobs/science.yml +++ b/Resources/Prototypes/Loadouts/Jobs/science.yml @@ -19,6 +19,9 @@ cost: 2 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Scientist diff --git a/Resources/Prototypes/Loadouts/Jobs/security.yml b/Resources/Prototypes/Loadouts/Jobs/security.yml index e6a6693ec18..29e1850db51 100644 --- a/Resources/Prototypes/Loadouts/Jobs/security.yml +++ b/Resources/Prototypes/Loadouts/Jobs/security.yml @@ -5,6 +5,9 @@ cost: 1 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - SecurityOfficer @@ -19,6 +22,9 @@ cost: 1 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - SecurityOfficer @@ -85,6 +91,9 @@ cost: 2 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - SecurityOfficer @@ -109,6 +118,9 @@ cost: 2 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Warden @@ -121,6 +133,9 @@ cost: 2 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Warden @@ -181,6 +196,9 @@ cost: 2 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Detective @@ -196,6 +214,9 @@ cost: 1 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Detective @@ -224,6 +245,9 @@ category: Jobs cost: 1 requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Detective diff --git a/Resources/Prototypes/Loadouts/Jobs/service.yml b/Resources/Prototypes/Loadouts/Jobs/service.yml index 63b6bf22d04..507b75412e3 100644 --- a/Resources/Prototypes/Loadouts/Jobs/service.yml +++ b/Resources/Prototypes/Loadouts/Jobs/service.yml @@ -84,6 +84,9 @@ cost: 2 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Lawyer @@ -108,6 +111,9 @@ cost: 2 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Lawyer @@ -132,6 +138,9 @@ cost: 2 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Lawyer @@ -156,6 +165,9 @@ cost: 2 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Lawyer @@ -193,6 +205,9 @@ cost: 2 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Reporter diff --git a/Resources/Prototypes/Loadouts/shoes.yml b/Resources/Prototypes/Loadouts/shoes.yml index 3c2e21e631b..0f493cc5431 100644 --- a/Resources/Prototypes/Loadouts/shoes.yml +++ b/Resources/Prototypes/Loadouts/shoes.yml @@ -4,6 +4,10 @@ category: Shoes cost: 1 exclusive: true + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy items: - ClothingShoesColorBlack @@ -12,6 +16,10 @@ category: Shoes cost: 1 exclusive: true + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy items: - ClothingShoesColorBlue @@ -20,6 +28,10 @@ category: Shoes cost: 1 exclusive: true + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy items: - ClothingShoesColorBrown @@ -28,6 +40,10 @@ category: Shoes cost: 1 exclusive: true + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy items: - ClothingShoesColorGreen @@ -36,6 +52,10 @@ category: Shoes cost: 1 exclusive: true + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy items: - ClothingShoesColorOrange @@ -44,6 +64,10 @@ category: Shoes cost: 1 exclusive: true + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy items: - ClothingShoesColorPurple @@ -52,6 +76,10 @@ category: Shoes cost: 1 exclusive: true + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy items: - ClothingShoesColorRed @@ -60,6 +88,10 @@ category: Shoes cost: 1 exclusive: true + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy items: - ClothingShoesColorWhite @@ -68,6 +100,10 @@ category: Shoes cost: 1 exclusive: true + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy items: - ClothingShoesColorYellow @@ -76,6 +112,10 @@ category: Shoes cost: 1 exclusive: true + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy items: - ClothingShoesGeta @@ -85,6 +125,10 @@ category: Shoes cost: 1 exclusive: true + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy items: - ClothingShoesBootsWork @@ -93,6 +137,10 @@ category: Shoes cost: 2 exclusive: true + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy items: - ClothingShoesBootsLaceup @@ -101,6 +149,10 @@ category: Shoes cost: 1 exclusive: true + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy items: - ClothingShoesBootsWinter @@ -109,6 +161,10 @@ category: Shoes cost: 2 exclusive: true + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy items: - ClothingShoesBootsCowboyBrown @@ -117,6 +173,10 @@ category: Shoes cost: 2 exclusive: true + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy items: - ClothingShoesBootsCowboyBlack @@ -125,6 +185,10 @@ category: Shoes cost: 2 exclusive: true + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy items: - ClothingShoesBootsCowboyWhite @@ -133,6 +197,10 @@ category: Shoes cost: 2 exclusive: true + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy items: - ClothingShoesBootsCowboyFancy @@ -145,6 +213,9 @@ items: - ClothingShoeSlippersDuck requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Clown @@ -154,6 +225,10 @@ category: Shoes cost: 1 exclusive: true + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy items: - ClothingShoesLeather @@ -162,5 +237,9 @@ category: Shoes cost: 1 exclusive: true + requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy items: - ClothingShoesMiscWhite diff --git a/Resources/Prototypes/Loadouts/uniform.yml b/Resources/Prototypes/Loadouts/uniform.yml index 20c5b42c7c2..c6838b97d33 100644 --- a/Resources/Prototypes/Loadouts/uniform.yml +++ b/Resources/Prototypes/Loadouts/uniform.yml @@ -4,6 +4,9 @@ cost: 2 exclusive: true requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Passenger @@ -20,6 +23,9 @@ items: - ClothingUniformJumpsuitColorBlack requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Passenger @@ -44,6 +50,9 @@ items: - ClothingUniformJumpsuitColorBlue requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Passenger @@ -68,6 +77,9 @@ items: - ClothingUniformJumpsuitColorGreen requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Passenger @@ -92,6 +104,9 @@ items: - ClothingUniformJumpsuitColorOrange requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Passenger @@ -116,6 +131,9 @@ items: - ClothingUniformJumpsuitColorPink requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Passenger @@ -140,6 +158,9 @@ items: - ClothingUniformJumpsuitColorRed requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Passenger @@ -164,6 +185,9 @@ items: - ClothingUniformJumpsuitColorWhite requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Passenger @@ -188,6 +212,9 @@ items: - ClothingUniformJumpsuitColorYellow requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Passenger @@ -212,6 +239,9 @@ items: - ClothingUniformJumpsuitColorDarkBlue requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Passenger @@ -236,6 +266,9 @@ items: - ClothingUniformJumpsuitColorTeal requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Passenger @@ -260,6 +293,9 @@ items: - ClothingUniformJumpsuitColorPurple requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Passenger @@ -284,6 +320,9 @@ items: - ClothingUniformJumpsuitColorDarkGreen requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Passenger @@ -308,6 +347,9 @@ items: - ClothingUniformJumpsuitColorLightBrown requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Passenger @@ -332,6 +374,9 @@ items: - ClothingUniformJumpsuitColorBrown requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Passenger @@ -356,6 +401,9 @@ items: - ClothingUniformJumpsuitColorMaroon requirements: + - !type:CharacterSpeciesRequirement + inverted: true + species: Harpy - !type:CharacterJobRequirement jobs: - Passenger diff --git a/Resources/Prototypes/Nyanotrasen/Catalog/Cargo/cargo_epistemics.yml b/Resources/Prototypes/Nyanotrasen/Catalog/Cargo/cargo_epistemics.yml index 4610c0f68c8..d7d0b665381 100644 --- a/Resources/Prototypes/Nyanotrasen/Catalog/Cargo/cargo_epistemics.yml +++ b/Resources/Prototypes/Nyanotrasen/Catalog/Cargo/cargo_epistemics.yml @@ -4,6 +4,6 @@ sprite: Nyanotrasen/Objects/Consumable/Drinks/flaskholywater.rsi state: icon product: CrateHolyWaterKit - cost: 1000 + cost: 3000 category: Epistemics group: market diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Uniforms/costumes.yml b/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Uniforms/costumes.yml index c82dbffae86..0ef1a5a85a3 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Uniforms/costumes.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Uniforms/costumes.yml @@ -54,7 +54,7 @@ sprite: Nyanotrasen/Clothing/Uniforms/Costume/maid.rsi - type: entity - parent: ClothingUniformBase + parent: ClothingUniformSkirtBase id: ClothingCostumeBunnySuit name: bunny suit description: Ready to go with stockings and a bow tie. @@ -89,10 +89,10 @@ sprite: Nyanotrasen/Clothing/Uniforms/Jumpskirt/Decorskirt.rsi - type: entity - parent: ClothingUniformBase + parent: ClothingUniformSkirtBase id: ClothingCostumeNaota name: turquoise hoodie and shorts - description: A hoodie with a small kangaroo pouch. + description: A hoodie with a small kangaroo pouch. components: - type: Sprite sprite: Nyanotrasen/Clothing/Uniforms/Costume/naota.rsi @@ -113,7 +113,7 @@ femaleMask: NoMask - type: entity - parent: ClothingUniformBase + parent: ClothingUniformSkirtBase id: ClothingUniformDressRed name: red dress description: A voluminous, fancy red dress. @@ -125,7 +125,7 @@ femaleMask: NoMask - type: entity - parent: ClothingUniformBase + parent: ClothingUniformSkirtBase id: ClothingUniformSwimsuitBlue name: blue swimsuit description: A form-fitting, hydrodynamic blue swimsuit. @@ -358,7 +358,7 @@ femaleMask: NoMask - type: entity - parent: ClothingUniformBase + parent: ClothingUniformSkirtBase id: ClothingUniformMNKUnderGarment name: MNK under garment description: MNK ensured comfort for the important bits. @@ -369,7 +369,7 @@ sprite: Nyanotrasen/Clothing/Misc/under_garments.rsi - type: entity - parent: ClothingUniformBase + parent: ClothingUniformSkirtBase id: ClothingUniformMNKGymBra name: MNK gym bra description: Maximum performance with MNK sweat blockers. @@ -381,7 +381,7 @@ femaleMask: NoMask - type: entity - parent: ClothingUniformBase + parent: ClothingUniformSkirtBase id: ClothingUniformMNKDressBlack name: MNK black dress description: A sleek black dress sporting a MNK window. @@ -405,7 +405,7 @@ femaleMask: NoMask - type: entity - parent: ClothingUniformBase + parent: ClothingUniformSkirtBase id: ClothingUniformMNKBlackShoulder name: MNK exposed shoulders description: A MNK outfit with exposed shoulders. diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Books/hyperlinks.yml b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Books/hyperlinks.yml new file mode 100644 index 00000000000..03426729d98 --- /dev/null +++ b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Books/hyperlinks.yml @@ -0,0 +1,204 @@ +- type: entity + parent: BaseItem + id: BaseHyperlinkBook + abstract: true + components: + - type: Sprite + sprite: Objects/Misc/books.rsi + - type: Tag + tags: + - Book + - type: EmitSoundOnPickup + sound: /Audio/SimpleStation14/Items/Handling/book_pickup.ogg + - type: EmitSoundOnDrop + sound: /Audio/SimpleStation14/Items/Handling/book_drop.ogg + - type: EmitSoundOnLand + sound: /Audio/SimpleStation14/Items/Handling/book_drop.ogg + +- type: entity + parent: BaseHyperlinkBook + id: HyperlinkBookSpaceLaw + name: space law + description: A big book of laws for space courts. + components: + - type: Sprite + layers: + - state: book_space_law +# - type: HyperlinkBook +# url: https://wiki.nyanotrasen.moe/view/Space_Law + +- type: entity + parent: BaseHyperlinkBook + id: HyperlinkBookSupernanny + name: book of unsanctioned space punishments + description: The ravings of a madman. + components: + - type: Sprite + layers: + - state: book_space_law +# - type: HyperlinkBook +# url: https://supernannyfanon.fandom.com/wiki/Category:Discipline_Techniques + +#- type: entity +# parent: BaseHyperlinkBook +# id: HyperlinkBookGlimmer +# suffix: GuidebookBook +# name: A Layman's Guide to the Mind +# description: A guide on psionics. +# components: +# - type: Sprite +# sprite: SimpleStation14/Objects/Misc/books.rsi +# layers: +# - state: book_psionics +# - type: HyperlinkBook +# url: https://wiki.nyanotrasen.moe/view/Glimmer +# - type: GuidebookBook +# guides: +# - Psionics +# - AltarsGolemancy + +- type: entity + parent: BaseHyperlinkBook + id: HyperlinkBookChemistry + name: chemical recipe book + description: A list of chemical recipes. + components: + - type: Sprite + layers: + - state: book_chemistry +# - type: HyperlinkBook +# url: https://wiki.nyanotrasen.moe/view/Chemistry + +- type: entity + parent: BaseHyperlinkBook + id: HyperlinkBookBartending + name: bartender's guide + description: A list of drink recipes. + components: + - type: Sprite + layers: + - state: book_bar +# - type: HyperlinkBook +# url: https://wiki.nyanotrasen.moe/view/Drinks + +- type: entity + parent: BaseHyperlinkBook + id: HyperlinkBookCooking + name: cookbook + description: A list of food recipes. + components: + - type: Sprite + layers: + - state: book_cooking +# - type: HyperlinkBook +# url: https://wiki.nyanotrasen.moe/view/Cooking + +- type: entity + parent: BaseHyperlinkBook + id: HyperlinkBookBotany + name: botanical field guide + description: A guide to plants. + components: + - type: Sprite + layers: + - state: book_hydroponics_pod_people +# - type: HyperlinkBook +# url: https://wiki.nyanotrasen.moe/view/Hydroponics + +- type: entity + parent: BaseHyperlinkBook + id: HyperlinkBookShuttle + name: guide to shuttle construction + description: A guide to building shuttles. + components: + - type: Sprite + layers: + - state: book_engineering +# - type: HyperlinkBook +# url: https://wiki.nyanotrasen.moe/view/Shuttle_Construction + +- type: entity + parent: BaseHyperlinkBook + id: HyperlinkBookAlerts + suffix: GuidebookBook + name: What to do When Things are Blowing Up + description: Procedure for when and why each alert should be put in effect, and what to do. + components: + - type: Sprite + layers: + - state: book_nuclear + # - type: HyperlinkBook + # url: https://wiki.nyanotrasen.moe/view/Alert_Procedure +# - type: GuidebookBook +# guides: +# - CommonAlerts +# - SpecificAlerts +# - CentCommAlerts + +- type: entity + parent: BaseHyperlinkBook + id: HyperlinkBookProcedure + suffix: GuidebookBook + name: standard operating procedure + description: A guide to normal station function. + components: + - type: Sprite + layers: + - state: book_particle_accelerator + # - type: HyperlinkBook + # url: https://wiki.nyanotrasen.moe/view/Standard_Operating_Procedure +# - type: GuidebookBook +# guides: +# - StandardOperatingProcedure + +- type: entity + parent: BaseHyperlinkBook + id: HyperlinkBookPower + name: guide to power + description: A guide to powering the station. + components: + - type: Sprite + layers: + - state: book_engineering2 +# - type: HyperlinkBook +# url: https://wiki.nyanotrasen.moe/view/Power + +- type: entity + parent: BaseHyperlinkBook + id: HyperlinkBookMedical + name: guide to medical + description: A guide to the medical department. + components: + - type: Sprite + layers: + - state: book_infections +# - type: HyperlinkBook +# url: https://wiki.nyanotrasen.moe/view/Medical + +- type: entity + parent: BaseHyperlinkBook + id: HyperlinkBookHacking + name: guide to hacking + description: For emergency use only. + components: + - type: Sprite + layers: + - state: book_hacking +# - type: HyperlinkBook +# url: https://wiki.nyanotrasen.moe/view/Hacking + +- type: entity + parent: BaseHyperlinkBook + id: HyperlinkBookAtmos + suffix: GuidebookBook + name: How to Make Gas Hot + description: A guide on Atmospherics. Make sure to grab the thrilling sequal; What to do When Gas Hot. + components: + - type: Sprite + layers: + - state: book_engineering2 + # - type: HyperlinkBook + # url: https://wiki.nyanotrasen.moe/view/Atmospheric_Science +# - type: GuidebookBook +# guides: +# - Atmospherics diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/Misc/identification_cards.yml b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/Misc/identification_cards.yml index ff9b3f8f2a0..94efc40530c 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/Misc/identification_cards.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/Misc/identification_cards.yml @@ -5,9 +5,12 @@ components: - type: Sprite layers: - - state: orange - - sprite: DeltaV/Objects/Misc/id_cards.rsi - state: nyanoprisoner + - state: prisoner + - state: department + color: "#292929" + - state: subdepartment + color: "#A54900" + - state: warden - type: PresetIdCard job: Prisoner @@ -18,9 +21,12 @@ components: - type: Sprite layers: - - state: orange - - sprite: DeltaV/Objects/Misc/id_cards.rsi - state: nyanogladiator + - state: default + - state: department + color: "#878787" + - state: subdepartment + color: "#878787" + - state: gladiator - type: PresetIdCard job: Gladiator @@ -32,8 +38,11 @@ - type: Sprite layers: - state: default - - sprite: DeltaV/Objects/Misc/id_cards.rsi - state: nyanoprisonguard + - state: department + color: "#CB0000" + - state: subdepartment + color: "#CB0000" + - state: prisonguard - type: PresetIdCard job: PrisonGuard @@ -45,8 +54,11 @@ - type: Sprite layers: - state: default - - sprite: DeltaV/Objects/Misc/id_cards.rsi - state: nyanomailcarrier + - state: department + color: "#B18644" + - state: subdepartment + color: "#B18644" + - state: mailcarrier - type: PresetIdCard job: MailCarrier @@ -59,8 +71,11 @@ - type: Sprite layers: - state: default - - sprite: DeltaV/Objects/Misc/id_cards.rsi - state: nyanomartialartist + - state: department + color: "#878787" + - state: subdepartment + color: "#878787" + - state: martialartist - type: PresetIdCard job: MartialArtist @@ -69,10 +84,13 @@ id: ForensicMantisIDCard name: psionic mantis ID card # DeltaV - Rename Forensic Mantis to Psionic Mantis components: - - type: Sprite - layers: - - state: default - - sprite: DeltaV/Objects/Misc/id_cards.rsi - state: nyanomantis - - type: PresetIdCard - job: ForensicMantis + - type: Sprite + layers: + - state: default + - state: department + color: "#C96DBF" + - state: subdepartment + color: "#C96DBF" + - state: detective + - type: PresetIdCard + job: ForensicMantis diff --git a/Resources/Prototypes/Nyanotrasen/GameRules/events.yml b/Resources/Prototypes/Nyanotrasen/GameRules/events.yml index decdcfdda26..52be5200d44 100644 --- a/Resources/Prototypes/Nyanotrasen/GameRules/events.yml +++ b/Resources/Prototypes/Nyanotrasen/GameRules/events.yml @@ -5,9 +5,7 @@ noSpawn: true components: - type: StationEvent - startAnnouncement: station-event-noospheric-storm-announcement - startAudio: - path: /Audio/Announcements/noosphericstorm.ogg + startAnnouncement: true weight: 5 earliestStart: 15 - type: NoosphericStormRule @@ -94,16 +92,16 @@ glimmerBurnUpper: 40 - type: PsionicCatGotYourTongueRule -- type: entity - id: MassMindSwap - parent: BaseGlimmerEvent - noSpawn: true - components: - - type: GlimmerEvent - minimumGlimmer: 900 - glimmerBurnLower: 50 - glimmerBurnUpper: 110 - - type: MassMindSwapRule +# - type: entity # Floofstation - Never this again please! +# id: MassMindSwap +# parent: BaseGlimmerEvent +# noSpawn: true +# components: +# - type: GlimmerEvent +# minimumGlimmer: 900 +# glimmerBurnLower: 50 +# glimmerBurnUpper: 110 +# - type: MassMindSwapRule #- type: entity # id: GlimmerWispSpawn diff --git a/Resources/Prototypes/Objectives/ninja.yml b/Resources/Prototypes/Objectives/ninja.yml index b6c3d553df0..0495be29355 100644 --- a/Resources/Prototypes/Objectives/ninja.yml +++ b/Resources/Prototypes/Objectives/ninja.yml @@ -39,8 +39,8 @@ sprite: Structures/Machines/server.rsi state: server - type: NumberObjective - min: 5 - max: 10 + min: 9 + max: 13 title: objective-condition-steal-research-title - type: StealResearchCondition diff --git a/Resources/Prototypes/Objectives/stealTargetGroups.yml b/Resources/Prototypes/Objectives/stealTargetGroups.yml index 006c061666b..11e503d7940 100644 --- a/Resources/Prototypes/Objectives/stealTargetGroups.yml +++ b/Resources/Prototypes/Objectives/stealTargetGroups.yml @@ -55,13 +55,13 @@ sprite: sprite: Objects/Consumable/Food/meat.rsi state: corgi - # + - type: stealTargetGroup id: CaptainIDCard name: captain ID card sprite: sprite: Objects/Misc/id_cards.rsi - state: ert_commander #no one will know the difference. + state: gold - type: stealTargetGroup id: JetpackCaptainFilled diff --git a/Resources/Prototypes/Procedural/biome_templates.yml b/Resources/Prototypes/Procedural/biome_templates.yml index 88979316443..425bcd824ab 100644 --- a/Resources/Prototypes/Procedural/biome_templates.yml +++ b/Resources/Prototypes/Procedural/biome_templates.yml @@ -620,7 +620,7 @@ allowedTiles: - FloorAsteroidSand entities: - - AsteroidRock + - RandomRockSpawner #Delta V - Makes Asteroids Great-ish Again - !type:BiomeTileLayer threshold: -1.0 tile: FloorAsteroidSand diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/utilities/wallmount_substation.yml b/Resources/Prototypes/Recipes/Construction/Graphs/utilities/wallmount_substation.yml index 381871f94af..7e4087b20a2 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/utilities/wallmount_substation.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/utilities/wallmount_substation.yml @@ -26,7 +26,13 @@ steps: - material: Cable amount: 5 - doAfter: 2 + doAfter: 0.5 + - material: CableMV + amount: 5 + doAfter: 0.5 + - material: CableHV + amount: 5 + doAfter: 0.5 - tool: Screwing doAfter: 2 @@ -41,12 +47,34 @@ icon: sprite: "Objects/Misc/module.rsi" state: "charger_APC" - doAfter: 1 + doAfter: 0.5 + - anyTags: + - PowerCell + - PowerCellSmall + store: powercell + name: a powercell + icon: + sprite: "Objects/Power/power_cells.rsi" + state: "medium" + doAfter: 0.5 + - tag: CapacitorStockPart + name: a capacitor + store: capacitor + icon: + sprite: "Objects/Misc/stock_parts.rsi" + state: "capacitor" + doAfter: 0.5 - to: frame completed: - !type:GivePrototype prototype: CableApcStack1 amount: 5 + - !type:GivePrototype + prototype: CableMVStack1 + amount: 5 + - !type:GivePrototype + prototype: CableHVStack1 + amount: 5 steps: - tool: Cutting doAfter: 1 diff --git a/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml b/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml index a5620fd8efe..2f280f6e46d 100644 --- a/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml +++ b/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml @@ -1423,6 +1423,15 @@ FoodSnackChocolateBar: 2 FoodEgg: 3 +- type: microwaveMealRecipe + id: RecipeHarpyWings + name: harpy wings recipe + result: FoodHarpyWings + time: 15 + solids: + LeftLegHarpy: 1 + RightLegHarpy: 1 + #Donks i guess - type: microwaveMealRecipe id: RecipeWarmDonkpocket diff --git a/Resources/Prototypes/Recipes/Lathes/electronics.yml b/Resources/Prototypes/Recipes/Lathes/electronics.yml index f0c59a0bdf9..b6184272dc0 100644 --- a/Resources/Prototypes/Recipes/Lathes/electronics.yml +++ b/Resources/Prototypes/Recipes/Lathes/electronics.yml @@ -604,7 +604,7 @@ completetime: 4 materials: Steel: 50 - Glass: 350 + Glass: 450 - type: latheRecipe id: SMESMachineCircuitboard diff --git a/Resources/Prototypes/SoundCollections/Announcers/intern.yml b/Resources/Prototypes/SoundCollections/Announcers/intern.yml new file mode 100644 index 00000000000..46172713dc8 --- /dev/null +++ b/Resources/Prototypes/SoundCollections/Announcers/intern.yml @@ -0,0 +1,34 @@ +- type: soundCollection + id: InternAnnouncements + files: + - /Audio/Announcers/Intern/comms/announce/1.ogg + - /Audio/Announcers/Intern/comms/announce/2.ogg + - /Audio/Announcers/Intern/comms/announce/3.ogg + - /Audio/Announcers/Intern/comms/announce/4.ogg + - /Audio/Announcers/Intern/comms/announce/5.ogg + - /Audio/Announcers/Intern/comms/announce/6.ogg + - /Audio/Announcers/Intern/comms/announce/7.ogg + - /Audio/Announcers/Intern/comms/announce/8.ogg + - /Audio/Announcers/Intern/comms/announce/9.ogg + - /Audio/Announcers/Intern/comms/announce/10.ogg + - /Audio/Announcers/Intern/comms/announce/11.ogg + - /Audio/Announcers/Intern/comms/announce/12.ogg + - /Audio/Announcers/Intern/comms/announce/13.ogg + - /Audio/Announcers/Intern/comms/announce/14.ogg + +- type: soundCollection + id: InternCommandReportAnnouncements + files: + - /Audio/Announcers/Intern/comms/commandReport/1.ogg + - /Audio/Announcers/Intern/comms/commandReport/2.ogg + - /Audio/Announcers/Intern/comms/commandReport/3.ogg + +- type: soundCollection + id: InternWelcomeAnnouncements + files: + - /Audio/Announcers/Intern/comms/welcome/1.ogg + - /Audio/Announcers/Intern/comms/welcome/2.ogg + - /Audio/Announcers/Intern/comms/welcome/3.ogg + - /Audio/Announcers/Intern/comms/welcome/4.ogg + - /Audio/Announcers/Intern/comms/welcome/5.ogg + - /Audio/Announcers/Intern/comms/welcome/6.ogg diff --git a/Resources/Prototypes/SoundCollections/screams.yml b/Resources/Prototypes/SoundCollections/screams.yml index 46965712b0e..518bbf72bb7 100644 --- a/Resources/Prototypes/SoundCollections/screams.yml +++ b/Resources/Prototypes/SoundCollections/screams.yml @@ -30,3 +30,41 @@ - /Audio/Voice/Cluwne/cluwnelaugh1.ogg - /Audio/Voice/Cluwne/cluwnelaugh2.ogg - /Audio/Voice/Cluwne/cluwnelaugh3.ogg + +- type: soundCollection + id: SlimeMaleLaughs + files: + - /Audio/Voice/Slime/slime_laugh_m1.ogg + - /Audio/Voice/Slime/slime_laugh_m2.ogg + +- type: soundCollection + id: SlimeFemaleLaughs + files: + - /Audio/Voice/Slime/slime_laugh_f1.ogg + +- type: soundCollection + id: SlimeUnisexLaughs + files: + - /Audio/Voice/Slime/slime_laugh_m1.ogg + - /Audio/Voice/Slime/slime_laugh_m2.ogg + - /Audio/Voice/Slime/slime_laugh_f1.ogg + +- type: soundCollection + id: SlimeMaleScreams + files: + - /Audio/Voice/Slime/slime_scream_m1.ogg + - /Audio/Voice/Slime/slime_scream_m2.ogg + +- type: soundCollection + id: SlimeFemaleScreams + files: + - /Audio/Voice/Slime/slime_scream_f1.ogg + - /Audio/Voice/Slime/slime_scream_f2.ogg + +- type: soundCollection + id: SlimeUnisexScreams + files: + - /Audio/Voice/Slime/slime_scream_m1.ogg + - /Audio/Voice/Slime/slime_scream_m2.ogg + - /Audio/Voice/Slime/slime_scream_f1.ogg + - /Audio/Voice/Slime/slime_scream_f2.ogg diff --git a/Resources/Prototypes/Store/categories.yml b/Resources/Prototypes/Store/categories.yml index c16972c8a31..11f8d509af3 100644 --- a/Resources/Prototypes/Store/categories.yml +++ b/Resources/Prototypes/Store/categories.yml @@ -63,6 +63,11 @@ name: store-category-pointless priority: 9 +- type: storeCategory + id: UplinkDeception + name: store-category-deception + priority: 10 + #revenant - type: storeCategory id: RevenantAbilities diff --git a/Resources/Prototypes/Tiles/floors.yml b/Resources/Prototypes/Tiles/floors.yml index b5ca240d5ca..2abaab63fb0 100644 --- a/Resources/Prototypes/Tiles/floors.yml +++ b/Resources/Prototypes/Tiles/floors.yml @@ -15,6 +15,7 @@ collection: FootstepFloor itemDrop: FloorTileItemSteel heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorSteelCheckerLight @@ -33,6 +34,7 @@ collection: FootstepFloor itemDrop: FloorTileItemSteelCheckerLight heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorSteelCheckerDark @@ -51,6 +53,7 @@ collection: FootstepFloor itemDrop: FloorTileItemSteelCheckerDark heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorSteelMini @@ -69,6 +72,7 @@ collection: FootstepFloor itemDrop: FloorTileItemSteel heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorSteelPavement @@ -87,6 +91,7 @@ collection: FootstepFloor itemDrop: FloorTileItemSteel heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorSteelDiagonal @@ -105,6 +110,7 @@ collection: FootstepFloor itemDrop: FloorTileItemSteel heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorSteelOffset @@ -117,6 +123,7 @@ collection: FootstepFloor itemDrop: FloorTileItemSteel heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorSteelMono @@ -135,6 +142,7 @@ collection: FootstepTile itemDrop: FloorTileItemSteel heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorSteelPavementVertical @@ -153,6 +161,7 @@ collection: FootstepTile itemDrop: FloorTileItemSteel heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorSteelHerringbone @@ -171,6 +180,7 @@ collection: FootstepTile itemDrop: FloorTileItemSteel heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorSteelDiagonalMini @@ -189,6 +199,7 @@ collection: FootstepTile itemDrop: FloorTileItemSteel heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorBrassFilled @@ -201,6 +212,7 @@ collection: FootstepHull itemDrop: FloorTileItemBrassFilled heatCapacity: 10000 + tileRipResistance: 220 - type: tile id: FloorBrassReebe @@ -213,6 +225,7 @@ collection: FootstepHull itemDrop: FloorTileItemBrassReebe heatCapacity: 10000 + tileRipResistance: 220 - type: tile id: FloorPlastic @@ -231,6 +244,7 @@ collection: FootstepFloor itemDrop: FloorTileItemSteel heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorWood @@ -251,6 +265,7 @@ collection: BarestepWood itemDrop: FloorTileItemWood heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorWhite @@ -269,6 +284,7 @@ collection: FootstepTile itemDrop: FloorTileItemWhite heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorWhiteMini @@ -287,6 +303,7 @@ collection: FootstepTile itemDrop: FloorTileItemWhite heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorWhitePavement @@ -305,6 +322,7 @@ collection: FootstepTile itemDrop: FloorTileItemWhite heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorWhiteDiagonal @@ -323,6 +341,7 @@ collection: FootstepTile itemDrop: FloorTileItemWhite heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorWhiteOffset @@ -335,6 +354,7 @@ collection: FootstepTile itemDrop: FloorTileItemWhite heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorWhiteMono @@ -353,6 +373,7 @@ collection: FootstepTile itemDrop: FloorTileItemWhite heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorWhitePavementVertical @@ -371,6 +392,7 @@ collection: FootstepTile itemDrop: FloorTileItemWhite heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorWhiteHerringbone @@ -389,6 +411,7 @@ collection: FootstepTile itemDrop: FloorTileItemWhite heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorWhiteDiagonalMini @@ -407,6 +430,7 @@ collection: FootstepTile itemDrop: FloorTileItemWhite heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorWhitePlastic @@ -425,6 +449,7 @@ collection: FootstepTile itemDrop: FloorTileItemWhite heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorDark @@ -443,6 +468,7 @@ collection: FootstepTile itemDrop: FloorTileItemDark heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorDarkMini @@ -461,6 +487,7 @@ collection: FootstepTile itemDrop: FloorTileItemDark heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorDarkPavement @@ -479,6 +506,7 @@ collection: FootstepTile itemDrop: FloorTileItemDark heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorDarkDiagonal @@ -497,6 +525,7 @@ collection: FootstepTile itemDrop: FloorTileItemDark heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorDarkOffset @@ -509,6 +538,7 @@ collection: FootstepTile itemDrop: FloorTileItemDark heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorDarkMono @@ -527,6 +557,7 @@ collection: FootstepTile itemDrop: FloorTileItemDark heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorDarkPavementVertical @@ -545,6 +576,7 @@ collection: FootstepTile itemDrop: FloorTileItemDark heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorDarkHerringbone @@ -563,6 +595,7 @@ collection: FootstepTile itemDrop: FloorTileItemDark heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorDarkDiagonalMini @@ -581,6 +614,7 @@ collection: FootstepTile itemDrop: FloorTileItemDark heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorDarkPlastic @@ -599,6 +633,7 @@ collection: FootstepTile itemDrop: FloorTileItemDark heatCapacity: 10000 + tileRipResistance: 50 - type: tile id: FloorTechMaint @@ -611,6 +646,7 @@ collection: FootstepHull itemDrop: FloorTileItemTechmaint heatCapacity: 10000 + tileRipResistance: 250 - type: tile id: FloorReinforced @@ -623,6 +659,7 @@ collection: FootstepHull itemDrop: FloorTileItemReinforced heatCapacity: 10000 + reinforced: true - type: tile id: FloorMono @@ -635,6 +672,7 @@ collection: FootstepTile itemDrop: FloorTileItemMono heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorLino @@ -647,6 +685,7 @@ collection: FootstepTile itemDrop: FloorTileItemLino heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorSteelDirty @@ -659,6 +698,7 @@ collection: FootstepPlating itemDrop: FloorTileItemDirty heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorElevatorShaft @@ -671,6 +711,7 @@ collection: FootstepHull itemDrop: FloorTileItemElevatorShaft heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorMetalDiamond @@ -683,6 +724,7 @@ collection: FootstepHull itemDrop: FloorTileItemMetalDiamond heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorRockVault @@ -695,6 +737,7 @@ collection: FootstepAsteroid itemDrop: FloorTileItemRockVault heatCapacity: 10000 + tileRipResistance: 400 - type: tile id: FloorBlue @@ -707,6 +750,7 @@ collection: FootstepTile itemDrop: FloorTileItemBlue heatCapacity: 10000 + tileRipResistance: 50 - type: tile id: FloorSteelLime @@ -725,6 +769,7 @@ collection: FootstepFloor itemDrop: FloorTileItemLime heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorMining @@ -737,6 +782,7 @@ collection: FootstepTile itemDrop: FloorTileItemMining heatCapacity: 10000 + tileRipResistance: 250 - type: tile id: FloorMiningDark @@ -749,6 +795,7 @@ collection: FootstepTile itemDrop: FloorTileItemMiningDark heatCapacity: 10000 + tileRipResistance: 250 - type: tile id: FloorMiningLight @@ -761,6 +808,7 @@ collection: FootstepTile itemDrop: FloorTileItemMiningLight heatCapacity: 10000 + tileRipResistance: 250 # Departamental - type: tile @@ -774,6 +822,7 @@ collection: FootstepHull itemDrop: FloorTileItemFreezer heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorShowroom @@ -786,6 +835,7 @@ collection: FootstepFloor itemDrop: FloorTileItemShowroom heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorHydro @@ -798,6 +848,7 @@ collection: FootstepFloor itemDrop: FloorTileItemHydro heatCapacity: 10000 + tileRipResistance: 50 - type: tile id: FloorBar @@ -816,6 +867,7 @@ collection: FootstepFloor itemDrop: FloorTileItemBar heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorClown @@ -828,6 +880,7 @@ collection: FootstepFloor itemDrop: FloorTileItemClown heatCapacity: 10000 + tileRipResistance: 50 - type: tile id: FloorMime @@ -840,6 +893,7 @@ collection: FootstepFloor itemDrop: FloorTileItemMime heatCapacity: 10000 + tileRipResistance: 50 - type: tile id: FloorKitchen @@ -852,6 +906,7 @@ collection: FootstepTile itemDrop: FloorTileItemKitchen heatCapacity: 10000 + tileRipResistance: 50 - type: tile id: FloorLaundry @@ -864,6 +919,7 @@ collection: FootstepTile itemDrop: FloorTileItemLaundry heatCapacity: 10000 + tileRipResistance: 50 - type: tile id: FloorSteelDamaged @@ -883,6 +939,7 @@ collection: FootstepFloor itemDrop: FloorTileItemSteel #This should probably be made null when it becomes possible to make it such, in SS13 prying destroyed tiles wouldn't give you anything. heatCapacity: 10000 + tileRipResistance: 175 - type: tile id: FloorSteelBurnt @@ -899,6 +956,7 @@ collection: FootstepFloor itemDrop: FloorTileItemSteel #Same case as FloorSteelDamaged, make it null when possible heatCapacity: 10000 + tileRipResistance: 175 # Concrete @@ -920,6 +978,7 @@ itemDrop: FloorTileItemConcrete heatCapacity: 10000 weather: true + tileRipResistance: 300 - type: tile id: FloorConcreteMono @@ -939,6 +998,7 @@ itemDrop: FloorTileItemConcrete heatCapacity: 10000 weather: true + tileRipResistance: 300 - type: tile id: FloorConcreteSmooth @@ -958,6 +1018,7 @@ itemDrop: FloorTileItemConcrete heatCapacity: 10000 weather: true + tileRipResistance: 300 - type: tile id: FloorGrayConcrete @@ -977,6 +1038,7 @@ itemDrop: FloorTileItemGrayConcrete heatCapacity: 10000 weather: true + tileRipResistance: 300 - type: tile id: FloorGrayConcreteMono @@ -996,6 +1058,7 @@ itemDrop: FloorTileItemGrayConcrete heatCapacity: 10000 weather: true + tileRipResistance: 300 - type: tile id: FloorGrayConcreteSmooth @@ -1015,6 +1078,7 @@ itemDrop: FloorTileItemGrayConcrete heatCapacity: 10000 weather: true + tileRipResistance: 300 - type: tile id: FloorOldConcrete @@ -1034,6 +1098,7 @@ itemDrop: FloorTileItemOldConcrete heatCapacity: 10000 weather: true + tileRipResistance: 300 - type: tile id: FloorOldConcreteMono @@ -1053,6 +1118,7 @@ itemDrop: FloorTileItemOldConcrete heatCapacity: 10000 weather: true + tileRipResistance: 300 - type: tile id: FloorOldConcreteSmooth @@ -1072,6 +1138,7 @@ itemDrop: FloorTileItemOldConcrete heatCapacity: 10000 weather: true + tileRipResistance: 300 # Carpets (non smoothing) - type: tile @@ -1088,6 +1155,7 @@ friction: 0.25 itemDrop: FloorTileItemArcadeBlue heatCapacity: 10000 + tileRipResistance: 75 - type: tile id: FloorArcadeBlue2 @@ -1103,6 +1171,7 @@ friction: 0.25 itemDrop: FloorTileItemArcadeBlue2 heatCapacity: 10000 + tileRipResistance: 75 - type: tile id: FloorArcadeRed @@ -1118,6 +1187,7 @@ friction: 0.25 itemDrop: FloorTileItemArcadeRed heatCapacity: 10000 + tileRipResistance: 75 - type: tile id: FloorEighties @@ -1133,6 +1203,7 @@ friction: 0.25 itemDrop: FloorTileItemEighties heatCapacity: 10000 + tileRipResistance: 75 - type: tile id: FloorCarpetClown @@ -1148,6 +1219,7 @@ friction: 0.25 itemDrop: FloorTileItemCarpetClown heatCapacity: 10000 + tileRipResistance: 75 - type: tile id: FloorCarpetOffice @@ -1163,6 +1235,7 @@ friction: 0.25 itemDrop: FloorTileItemCarpetOffice heatCapacity: 10000 + tileRipResistance: 75 - type: tile id: FloorBoxing @@ -1182,6 +1255,7 @@ friction: 0.25 itemDrop: FloorTileItemBoxing heatCapacity: 10000 + tileRipResistance: 50 - type: tile id: FloorGym @@ -1201,6 +1275,7 @@ friction: 0.25 itemDrop: FloorTileItemGym heatCapacity: 10000 + tileRipResistance: 50 # Shuttle - type: tile @@ -1214,6 +1289,7 @@ collection: FootstepFloor itemDrop: FloorTileItemShuttleWhite heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorShuttleGrey @@ -1226,6 +1302,7 @@ collection: FootstepFloor itemDrop: FloorTileItemShuttleGrey heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorShuttleBlack @@ -1238,6 +1315,7 @@ collection: FootstepFloor itemDrop: FloorTileItemShuttleBlack heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorShuttleBlue @@ -1250,6 +1328,7 @@ collection: FootstepFloor itemDrop: FloorTileItemShuttleBlue heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorShuttleOrange @@ -1262,6 +1341,7 @@ collection: FootstepFloor itemDrop: FloorTileItemShuttleOrange heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorShuttlePurple @@ -1274,6 +1354,7 @@ collection: FootstepFloor itemDrop: FloorTileItemShuttlePurple heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorShuttleRed @@ -1286,6 +1367,7 @@ collection: FootstepFloor itemDrop: FloorTileItemShuttleRed heatCapacity: 10000 + tileRipResistance: 4500 # Materials @@ -1300,6 +1382,7 @@ collection: FootstepTile itemDrop: FloorTileItemGold heatCapacity: 10000 + tileRipResistance: 600 - type: tile id: FloorSilver @@ -1312,6 +1395,7 @@ collection: FootstepTile itemDrop: FloorTileItemSilver heatCapacity: 10000 + tileRipResistance: 500 - type: tile id: FloorGlass @@ -1330,6 +1414,7 @@ collection: FootstepTile itemDrop: SheetGlass1 heatCapacity: 10000 + tileRipResistance: 150 - type: tile id: FloorRGlass @@ -1348,6 +1433,7 @@ collection: FootstepTile itemDrop: SheetRGlass1 heatCapacity: 10000 + tileRipResistance: 175 # Circuits - type: tile @@ -1361,6 +1447,7 @@ collection: FootstepHull itemDrop: FloorTileItemGCircuit heatCapacity: 10000 + tileRipResistance: 225 - type: tile id: FloorBlueCircuit @@ -1373,6 +1460,7 @@ collection: FootstepHull itemDrop: FloorTileItemBCircuit heatCapacity: 10000 + tileRipResistance: 225 # Terrain - type: tile @@ -1666,6 +1754,7 @@ itemDrop: FloorTileItemFlesh friction: 0.05 #slippy heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorTechMaint2 @@ -1678,6 +1767,7 @@ collection: FootstepHull itemDrop: FloorTileItemSteelMaint heatCapacity: 10000 + tileRipResistance: 225 - type: tile id: FloorTechMaint3 @@ -1696,6 +1786,7 @@ collection: FootstepHull itemDrop: FloorTileItemGratingMaint heatCapacity: 10000 + tileRipResistance: 225 - type: tile id: FloorWoodTile @@ -1716,6 +1807,7 @@ collection: BarestepWood itemDrop: FloorTileItemWoodPattern heatCapacity: 10000 + tileRipResistance: 75 - type: tile id: FloorBrokenWood @@ -1739,6 +1831,7 @@ collection: BarestepWood itemDrop: MaterialWoodPlank1 heatCapacity: 10000 + tileRipResistance: 60 - type: tile id: FloorWebTile @@ -1753,6 +1846,7 @@ collection: BarestepCarpet itemDrop: FloorTileItemWeb heatCapacity: 10000 + tileRipResistance: 30 - type: tile id: FloorChromite @@ -1784,6 +1878,7 @@ collection: FootstepHull itemDrop: FloorTileItemSteel #probably should not be normally obtainable, but the game shits itself and dies when you try to put null here heatCapacity: 10000 + tileRipResistance: 500 - type: tile id: FloorHullReinforced @@ -1796,6 +1891,7 @@ itemDrop: FloorTileItemSteel heatCapacity: 100000 #/tg/ has this set as "INFINITY." I don't know if that exists here so I've just added an extra 0 indestructible: true + reinforced: true - type: tile id: FloorReinforcedHardened @@ -1806,6 +1902,7 @@ footstepSounds: collection: FootstepHull itemDrop: FloorTileItemReinforced #same case as FloorHull + reinforced: true # Faux sci tiles @@ -1837,6 +1934,7 @@ collection: FootstepGrass itemDrop: FloorTileItemAstroGrass heatCapacity: 10000 + tileRipResistance: 50 - type: tile id: FloorMowedAstroGrass @@ -1846,6 +1944,7 @@ isSubfloor: false deconstructTools: [ Cutting ] itemDrop: FloorTileItemMowedAstroGrass + tileRipResistance: 50 - type: tile id: FloorJungleAstroGrass @@ -1855,6 +1954,7 @@ isSubfloor: false deconstructTools: [ Cutting ] itemDrop: FloorTileItemJungleAstroGrass + tileRipResistance: 50 # Ice - type: tile @@ -1870,6 +1970,7 @@ mobFrictionNoInput: 0.05 mobAcceleration: 2 itemDrop: FloorTileItemAstroIce + tileRipResistance: 50 - type: tile id: FloorAstroSnow @@ -1879,6 +1980,7 @@ isSubfloor: false deconstructTools: [ Prying ] itemDrop: FloorTileItemAstroSnow + tileRipResistance: 50 - type: tile id: FloorWoodLarge @@ -1899,3 +2001,4 @@ collection: BarestepWood itemDrop: FloorTileItemWoodLarge heatCapacity: 10000 + tileRipResistance: 100 diff --git a/Resources/Prototypes/Traits/inconveniences.yml b/Resources/Prototypes/Traits/inconveniences.yml index dcf53d9ab7f..fee312593da 100644 --- a/Resources/Prototypes/Traits/inconveniences.yml +++ b/Resources/Prototypes/Traits/inconveniences.yml @@ -7,6 +7,10 @@ jobs: - Borg - MedicalBorg + - !type:CharacterTraitRequirement + inverted: true + traits: + - HeavyweightDrunk components: - type: LightweightDrunk boozeStrengthMultiplier: 2 @@ -26,3 +30,26 @@ fourRandomProb: 0 threeRandomProb: 0 cutRandomProb: 0 + +- type: trait + id: ForeignerLight + category: Mental + points: 1 + requirements: + - !type:TraitGroupExclusionRequirement + prototypes: [ Foreigner ] + components: + - type: ForeignerTrait + cantUnderstand: false # Allows to understand + baseTranslator: TranslatorForeigner + +- type: trait + id: Foreigner + category: Mental + points: 2 + requirements: # TODO: Add a requirement to know at least 1 non-gc language + - !type:TraitGroupExclusionRequirement + prototypes: [ ForeignerLight ] + components: + - type: ForeignerTrait + baseTranslator: TranslatorForeigner diff --git a/Resources/Prototypes/Traits/skills.yml b/Resources/Prototypes/Traits/skills.yml index 6175834c1fc..988307f58e4 100644 --- a/Resources/Prototypes/Traits/skills.yml +++ b/Resources/Prototypes/Traits/skills.yml @@ -1,3 +1,21 @@ +- type: trait + id: HeavyweightDrunk + category: Physical + points: -2 + requirements: + - !type:CharacterJobRequirement + inverted: true + jobs: + - Borg + - MedicalBorg + - !type:CharacterTraitRequirement + inverted: true + traits: + - LightweightDrunk + components: + - type: LightweightDrunk + boozeStrengthMultiplier: 0.5 + - type: trait id: Thieving category: Physical diff --git a/Resources/Prototypes/Voice/speech_emote_sounds.yml b/Resources/Prototypes/Voice/speech_emote_sounds.yml index 01fabbadf30..a4588952a88 100644 --- a/Resources/Prototypes/Voice/speech_emote_sounds.yml +++ b/Resources/Prototypes/Voice/speech_emote_sounds.yml @@ -95,9 +95,9 @@ Squish: collection: Squishes Scream: - collection: MaleScreams + collection: SlimeMaleScreams Laugh: - collection: MaleLaugh + collection: SlimeMaleLaughs Sneeze: collection: MaleSneezes Cough: @@ -133,9 +133,9 @@ Squish: collection: Squishes Scream: - collection: FemaleScreams + collection: SlimeFemaleScreams Laugh: - collection: FemaleLaugh + collection: SlimeFemaleLaughs Sneeze: collection: FemaleSneezes Cough: diff --git a/Resources/Prototypes/game_presets.yml b/Resources/Prototypes/game_presets.yml index e99b51f82cd..7d7169bf10a 100644 --- a/Resources/Prototypes/game_presets.yml +++ b/Resources/Prototypes/game_presets.yml @@ -9,6 +9,17 @@ - RampingStationEventScheduler - BasicRoundstartVariation +- type: gamePreset + id: SurvivalHellshift + alias: + - hellshift + showInVote: true + name: hellshift-title + description: hellshift-description + rules: + - HellshiftStationEventScheduler + - BasicRoundstartVariation + - type: gamePreset id: AllAtOnce name: all-at-once-title @@ -90,7 +101,7 @@ - traitor name: traitor-title description: traitor-description - showInVote: false + showInVote: true rules: - Traitor - SubGamemodesRule diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index c6a0ab3f8fd..231326e5b11 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -31,18 +31,30 @@ - type: Tag id: Balloon +- type: Tag + id: Banana + - type: Tag id: BananaPeel +- type: Tag + id: Bandana + - type: Tag id: BaseballBat - type: Tag id: BBQsauce +- type: Tag + id: Bedsheet + - type: Tag id: Bee +- type: Tag + id: Beer + - type: Tag id: BikeHorn @@ -202,6 +214,9 @@ - type: Tag id: Bottle +- type: Tag + id: BoxCardboard + - type: Tag id: BoxHug @@ -347,6 +362,9 @@ - type: Tag id: ChemDispensable # container that can go into the chem dispenser +- type: Tag + id: ChiliBowl + - type: Tag id: Cigarette @@ -383,11 +401,14 @@ - type: Tag id: CluwneHorn -- type: Tag #Ohioans die happy +- type: Tag + id: Coldsauce + +- type: Tag id: Corn - type: Tag - id: Coldsauce + id: CottonBoll - type: Tag id: Cow @@ -677,6 +698,9 @@ - type: Tag id: HighSecDoor +- type: Tag + id: HiViz + - type: Tag id: Hoe @@ -764,9 +788,6 @@ - type: Tag id: MacroBomb -- type: Tag - id: MicroBomb - - type: Tag id: MimeBelt @@ -847,6 +868,12 @@ - type: Tag id: Metal +- type: Tag + id: MicroBomb + +- type: Tag + id: MicrowaveMachineBoard + - type: Tag id: MindShield @@ -1142,6 +1169,9 @@ - type: Tag id: StationMapElectronics +- type: Tag + id: Steak + - type: Tag id: SubdermalImplant @@ -1211,6 +1241,9 @@ - type: Tag id: UraniumGlassShard +- type: Tag + id: Vegetable + - type: Tag id: VimPilot @@ -1250,6 +1283,9 @@ - type: Tag id: Window +- type: Tag + id: Wine + - type: Tag id: WizardWand # that evil vvizard vvand diff --git a/Resources/ServerInfo/Rules.txt b/Resources/ServerInfo/Rules.txt index 07f10fbdc2c..0100849b4a6 100644 --- a/Resources/ServerInfo/Rules.txt +++ b/Resources/ServerInfo/Rules.txt @@ -1,381 +1,177 @@ Floof Station Server Rules -WARNING: You must be at least 18 years of age to play on Floof Station. -Any users suspected of being under the age of 18 WILL be removed. +[color=#ff0000]WARNING: You MUST be at least 18 years of age to play on Floof Station.[/color] +[color=#ff0000]Any user suspected of being under the age of 18 WILL be removed until they are of age.[/color] -Intentionally disconnecting, responding with hostility, or refusing to respond when an admin privately -messages you in-game will be met with an appeal-only ban. Additionally, abusing the AHelp relay by -flooding it with garbage, checking for admins before stating a problem (ex: "hello?", "any admins?"), -using it as a chatroom, or sending messages of no substance will result in your removal. -All AHelp messages are relayed to the Floof Station Discord. +[color=#ffff00]Intentionally disconnecting, responding with hostility, or refusing to respond when an admin privately messages you in-game will be met with an appeal-only ban. Additionally, abusing the AHelp relay by flooding it with garbage, checking for admins before stating a problem (ex: "hello?", "any admins?"), using it as a chatroom, or sending messages of no substance will result in your removal.[/color] +[color=#ffff00]All AHelp messages are relayed to the Floof Station Discord.[/color] -The usage of any third-party applications/scripts/client modifications or any other applicable software -to gain an advantage, avoid intended game/server mechanics, or to harm server infrastructure is strictly -prohibited, as is the abuse of glitches, exploits and bugs. Any and all instances of this will be met -with an appeal-only ban. -Please use the #bug-reports channel on the Discord to report any issues you find in-game. +[color=#ffff00]The usage of any third-party applications/scripts/client modifications or any other applicable software to gain an advantage, avoid intended game/server mechanics, or to harm server infrastructure is strictlyprohibited, as is the abuse of glitches, exploits and bugs. Any and all instances of this will be met with an appeal-only ban.[/color] +[color=#ffff00]Please use the #bug-reports channel on the Discord to report any issues you find in-game.[/color] -Attempting to evade bans is strictly forbidden, and will result in the ban being automatically -converted to appeal-only. -Multi-keying (the simultaneous use of multiple accounts at one time) is also forbidden, -and will be met with a ban of all the accounts involved. +[color=#ffff00]Attempting to evade bans is strictly forbidden, and will result in the ban being automatically converted to appeal-only.[/color] +[color=#ffff00]Multi-keying (the simultaneous use of multiple accounts at one time) is also forbidden, and will be met with a ban of all the accounts involved.[/color] -If you have any questions about these rules, please use the admin help menu by hitting F1 in-game -or clicking the "AHelp" button in the lobby. +[color=#ffff00]If you have any questions about these rules, please use the admin help menu by hitting F1 in-game, or clicking the "AHelp" button in the lobby.[/color] -Community Rules -1. All of these rules apply as they are intended. Every example of a rule break cannot be defined as +[color=#ff0000]Community Rules[/color] + +[color=#a4885c]1.[/color] All of these rules apply as they are intended. Every example of a rule break cannot be defined as written, therefore, enforcement of the rules is subject to staff interpretation of the rule's intention. Any extended discussion regarding interpretation of the rules should be avoided in the AHelp menu and can be instead pursued within the Floof Station Discord in the #help channel. -2. Floof Station is an English-based community; use English as your primary method of +[color=#a4885c]2.[/color] Floof Station is an English-based community; use English as your primary method of communication within the game. -3. Erotic Roleplay (ERP), erotic content, and 18+ sexual content are allowed, so long all parties +[color=#a4885c]3.[/color] Erotic Roleplay (ERP), erotic content, and 18+ sexual content are allowed, so long all parties involved consent to it. For more information about this, consult the ERP guidelines and rules in the Game Server Rules section at point 8. -4. Be civil: - -A. Do not spam or advertise on our server. - -B. Do not flame and do not be toxic. - -C. Be respectful towards other members, avoid making others uncomfortable, and most important of all, -do not be an asshole. - -D. We have a zero tolerance policy for racism, sexism, homophobia, violence, threats, hate speech, -slurs, and other forms of bigotry, discrimination, and harassment. Slurs and terms that use real or -implied mental or physical disability to mock or denigrate members or their in-game characters are -also strictly prohibited. Failure to comply with this rule will result in community removal. - -Game Server Rules - -1. Follow the server expectations: - -A. If you are banned from a role or department, you may not play that role. This includes seeking or -accepting promotions into roles you are banned from. - -B. Do not make yourself a major problem/annoyance/disruption for the crew while not being an -antagonist (i.e. self-antagging). Intentionally hindering the station as a crew-aligned character is -strictly against our rules. And so is making other players’ lives hell for your own amusement, so, do -not be an asshole, and let everybody else enjoy the game too. - -C. Department strikes (e.g. cargonia and any variation thereof), riots, cults, and any other type of -similar largely disruptive behavior are to be roleplayed excellently and require explicit -administrator pre-approval. - -D. Clowns, Mimes, and other "prankster" roles do not get an exemption from the above, and should -not use their job as an excuse to be a major disturbance. -E. AFK (a.k.a. SSD) and catatonic players are considered to have the same rights as any other -crewmate. - -F. If a player is dead and catatonic (not SSD), they are not required to be revived and should be -stored in the morgue. You should not biomass grind dead and catatonic crew unless in an -emergency. - -G. If a player is alive and catatonic, they may be brought to their relevant department or cryostorage -as necessary. - -H. For the sake of privacy and respect towards the other members of the community, by reason -of the nature of the server, and by motive of potential metagaming, livestreaming rounds is strictly forbidden. - -I. It is strictly forbidden to record players engaged in private activities without their consent, -and even more so to share it without their consent. - -J. Ghosting or playing with the intent of, and the act itself of "exposing" or shaming players by sharing content -or information of their presence or activities in this server elsewhere, is strictly forbidden. - -2. Follow metagaming guidelines: - -A. Do not use the Emote channel to bypass an inability to speak. This includes examples like "I’m -friendly," "oh weird I can’t speak," or "mimes a flashlight". - -B. Additionally, use of the emote channel to simulate character death rattles or other game -mechanics is prohibited. - -C. Use the local-out-of-character (LOOC) and global out-of-character (OOC) channels properly. -Don’t speak of in-character matters in those channels unless you’re asking questions related to ingame concepts. - -D. Do not use in-character channels to bypass a lack of ability to use OOC/LOOC chats (e.g. "Huh, -wonder where the captain went? OOC He probably left to get dinner lol"). - -E. Do not engage in meta-communications (i.e. using external channels to communicate with other -players in the same game). - -F. Discussion about the current round is allowed on the Floof Station Discord server (albeit discouraged -for the purpose of MRP). However, acting on information gained by this method is strictly forbidden. - -G. You are allowed to have knowledge of past experiences and prior shifts, and players are allowed -to have in-character relationships (friends, enemies, or otherwise). - -H. Antagonists in previous rounds must not be treated differently due to their prior antagonist status. -Notwithstanding, confession of crimes committed in a prior shift are still admissible in court. - -I. For the sake of continuity, your character will never have permanently died in previous rounds -(unless you wish to roleplay this concept out). - -J. Do not "antag roll." This is the act of joining rounds for the purpose of seeing if you have -received an antagonist role, and leaving soon after if not. - -K. Act like an actual person on board of a space station, and don’t use text speech or emoticons -when speaking in character. - -3. Follow the new-life rules: - -A. If a player dies and is brought back by way of cloning or borging, they forget the last five -minutes leading up to their death and cannot describe who or what killed them. - -B. Players that are revived by using a defibrillator can only recall vague details about their death, -such as "Someone shot me" or "I was set ablaze" but they cannot recall details beyond that. Please -report players who break this rule. - -C. In either case, characters do not have any knowledge of what happened while they were dead -(i.e. ghosted/observing), and are forbidden from acting on information gained during death. - -4. Follow naming conventions: -Don't make obvious references, don’t make obvious puns or plays on words, and try to be creative -by picking a believable and fitting name and/or surname. Leeway is given to theatrical roles such as -the clown, boxer, and mime; these roles are allowed stage names with some freedom. - -5. Follow roleplay guidelines: - -A. Your character is a separate entity from you, the player. Your character's actions, feelings, and -knowledge in-game should be based solely on the character's experiences rather than your own as -the player. - -B. Do not escalate situations needlessly. Very few things are deserving of a fight to the death, or the -loss of life of somebody. Brawls and self defense are permitted, but do not put someone in critical -state without a very valid roleplay reason to it. - -C. If a fight results in someone being critically injured, seek medical help for them - and if they die, -do not destroy or otherwise hide their body. This falls under self-antagonistic behavior. - -D. D. Pest ghost roles such as mice are always fair game for attacking. Do not grief crew-aligned ghost -roles such as familiars or pets without provocation. - -E. Some awakened pest roles (e.g. sentient mothroach) may be considered crew pets and fall under -this rule. - -F. Non-security personnel should not seek to kill or detain unrelated threats, unless they themselves -or other crew in the direct vicinity are in current, immediate danger from it. Crew may neutralize -threats when they present themselves or if they are relevant to the crew member in question, but are -not to pursue them if and once routed from their current area. - -G. Certain severe emergencies may make it reasonable for normal crew to defend themselves and -their station, such as nuclear operatives, a zombie outbreak, space dragon attack, or any other -critical situation, thus rendering the previous rule temporary null. - -H. By picking the prisoner role, you have chosen to roleplay as a prisoner, NOT an antagonist, -and should not act so in any capacity. While you may be allowed to escape, you must receive -admin approval to do so, and ideally you should only seek to do so with excellent reasoning -and roleplay (e.g. abusive security personnel or badly damaged permanent brig). +[color=#a4885c]4. Be civil:[/color] +[color=#a4885c]4.1[/color] Do not spam or advertise in our server. +[color=#a4885c]4.2[/color] Do not flame and do not be toxic. +[color=#a4885c]4.3[/color] Be polite and respectful towards other members, and avoid making others uneasy or uncomfortable. +[color=#a4885c]4.4[/color] DO NOT BE AN ASSHOLE. Do not intentionally make the round worse for other people for your own amusement. +For example: repeatedly and persistently harassing a character, being an intense nuisance to the quiet of the station, or causing substantial damage through vandalism. +[color=#a4885c]4.5[/color] We have a zero tolerance policy for any form of bigotry, discrimination, toxicity, and harassment. Failure to comply with this rule will result in community removal. +Slurs and terms used to mock or denigrate players or their in-game characters in a discriminatory, hateful manner, are also strictly prohibited. +[color=#a4885c]4.6[/color] For anything else that is not specifically covered by our rules: use common sense and common decency. + +[color=#ff0000]Game Server Rules[/color] + +[color=#a4885c]1. Follow the server expectations:[/color] +[color=#a4885c]1.1[/color] If you are banned from a role or department, you may not play that role. This includes seeking or accepting promotions into roles you are banned from. +[color=#a4885c]1.2[/color] Do not make yourself a major problem, annoyance or disruption for the crew while not being an antagonist (i.e. self-antagging). Intentionally hindering the station as a crew-aligned character is strictly against our rules. +[color=#a4885c]1.3[/color] Department strikes (e.g. cargonia and any variation thereof), riots, cults, and any other type of similar largely disruptive behavior are to be roleplayed excellently and require explicit administrator pre-approval. +[color=#a4885c]1.4[/color] Clowns, Mimes, and other "prankster" roles do not get an exemption from the above, and should NOT use their job as an excuse to be a major disturbance. +[color=#a4885c]1.5[/color] AFK (a.k.a. SSD) and catatonic players are considered to have the same rights as any other crewmate. +[color=#a4885c]1.6[/color] If a player is dead and catatonic (not SSD), they are not required to be revived and should be stored in the morgue. +You should not biomass grind dead and catatonic crew, unless the body belongs to a person who got cloned (thus, recycling is allowed), or during an emergency. +[color=#a4885c]1.7[/color] If a player is alive and catatonic, they may be brought to their relevant department or cryostorage as necessary. +[color=#a4885c]1.8[/color] For the sake of privacy and respect towards the other members of the community, by reason of the nature of the server, and by motive of potential metagaming, livestreaming rounds is strictly forbidden. +[color=#a4885c]1.9[/color] It is strictly forbidden to record players engaged in private activities without their consent, and even more so to share it without their consent. +[color=#a4885c]1.10[/color] Ghosting or playing with the intent of, and the act itself of "exposing" or shaming players by sharing content or information of their presence or activities in this server elsewhere, is strictly forbidden. + +[color=#ff0000]2. Follow metagaming guidelines:[/color] +[color=#a4885c]2.1[/color] Do not use the Emote channel to bypass an inability to speak. +[color=#a4885c]2.2[/color] Use of the emote channel to simulate character death rattles or other game mechanics is prohibited. +[color=#a4885c]2.3[/color] Use the local-out-of-character (LOOC) and global out-of-character (OOC) channels properly. +Don’t speak of in-character matters in those channels unless you’re asking questions related to ingame concepts +[color=#a4885c]2.4[/color] Do not use in-character channels to bypass a lack of ability to use OOC/LOOC chats (e.g. "Huh, wonder where the captain went? OOC He probably left to get dinner lol"). +[color=#a4885c]2.5[/color] Do not use any information gained by meta-communication (i.e. using external channels to communicate with other players in the same game) to your advantage. +[color=#a4885c]2.6[/color] Discussion about the current round is allowed on the Floof Station Discord server (albeit discouraged for the purpose of MRP). However, acting on information gained by this method is strictly forbidden. +[color=#a4885c]2.7[/color] You are allowed to have knowledge of past experiences and prior shifts, and players are allowed to have in-character relationships (friends, enemies, or otherwise). +However, it is still forbidden to break any rule on the basis of friendships and hostilities (such as self-antagging by killing or harassing someone for no reason, or not providing service to another department because someone you don't like either works there or is at the head of it) +[color=#a4885c]2.8[/color] Antagonists in previous rounds must not be treated differently due to their prior antagonist status. Notwithstanding, confession of crimes committed in a prior shift are still admissible in court. +[color=#a4885c]2.9[/color] For the sake of continuity, your character will never have permanently died in previous rounds (unless you wish to roleplay this concept out). +[color=#a4885c]2.10[/color] Do NOT "antag roll." This is the act of joining rounds for the purpose of seeing if you have received an antagonist role, and leaving soon after if not. +[color=#a4885c]2.11[/color] Act like an actual person on board of a space station, and don’t use text speech or emoticons when speaking in character. + +[color=#ff0000]3. Follow the new-life rules:[/color] +[color=#a4885c]3.1[/color] If a player dies and is brought back by way of cloning or borging, they forget the last five minutes leading up to their death and cannot describe who or what killed them. +[color=#a4885c]3.2[/color] Players that are revived by using a defibrillator can only recall vague details about their death, such as "Someone shot me" or "I was set ablaze" but they cannot recall details beyond that. Please report players who break this rule. +[color=#a4885c]3.3[/color] In either case, characters do not have any knowledge of what happened while they were dead (i.e. ghosted/observing), and are forbidden from acting on information gained during death. + +[color=#ff0000]4. Follow naming conventions:[/color] +[color=#a4885c]4.1[/color] Don't make cringy or lame references, don’t make obvious puns or plays on words, and try to be creative by picking a believable and fitting name and/or surname. Leeway is given to theatrical roles such as the clown, boxer, and mime; these roles are allowed stage names with some freedom. +[color=#a4885c]4.2[/color] If you are using a title, DO NOT attempt to use it to gain unfair gameplay advantages (such as, pretending to be a Centcomm officer, or some role/job you are not). + +[color=#ff0000]5. Follow roleplay guidelines:[/color] +[color=#a4885c]5.1[/color] Your character is a separate entity from you, the player. Your character's actions, feelings, and knowledge in-game should be based solely on the character's experiences rather than your own as the player. +[color=#a4885c]5.2[/color] Do not escalate situations needlessly. Very few things are deserving of a fight to the death, or the loss of life of somebody. Brawls and self defense are permitted, but do NOT put someone in critical state without a VERY valid reason to it (roleplay-based or not). +[color=#a4885c]5.3[/color] If a fight results in someone being critically injured, seek medical help for them - and if they die, do not destroy or otherwise hide their body. This falls under self-antagonistic behavior. +[color=#a4885c]5.4[/color] Do NOT grief, attack or kill crew-aligned ghost roles such as familiars or station pets without a valid motive or provocation. Pest ghost roles such as mice however, are always fair game for attacking. +[color=#a4885c]5.5[/color] Some awakened pest roles (e.g. sentient mothroach) may be considered crew pets and fall under this rule. +[color=#a4885c]5.6[/color] Respect other people's consent, dignity and boundaries. If somebody asks you to stop bothering them LOOC, do so. If someone keeps bothering you despite telling them off LOOC, please AHelp it. +[color=#a4885c]5.7[/color] Non-security personnel should not seek to kill or detain unrelated threats, unless they themselves or other crew in the direct vicinity are in current, immediate danger from it. Crew may neutralize threats when they present themselves or if they are relevant to the crew member in question, but are not to pursue them if and once routed from their current area. +[color=#a4885c]5.8[/color] Certain severe emergencies or antagonist roles allow for normal crew to actively defend station and attempt to kill or subdue the antagonist. Such as: nuclear operatives, a zombie outbreak, a space dragon attack, or any other critical situation (such as all Command or/and Security being dead) requiring the crew to take matters in their own hands. +[color=#a4885c]5.9[/color] By picking the prisoner role, you have chosen to roleplay as a prisoner, NOT an antagonist, and should not act so in any capacity. While you may be allowed to escape, you must receive admin approval to do so, and ideally you should only seek to do so with excellent reasoning and roleplay (e.g. abusive security personnel or badly damaged permanent brig). Lack of administrator response does not constitute approval. - -6. Follow powergaming guidelines: - -A. Don't rush for or prepare equipment unrelated to your job for no purpose other than to have it -without valid reason. - -B. A medical doctor does not need insulated gloves, the Head of Personnel does not need a gun, and -the Captain does not need an assault rifle. If you, in your given role, require an item that does not -fall within your job’s usual parameters, have a valid gameplay or roleplay reason to obtain and keep -it. - -C. Manufacturing weapons, bombs, or deadly poisons before you know of any reason you would -need them for (or without an excellent roleplay reason to it) is powergaming behavior. - -D. Hiding Traitor objective items or preemptively securing them with higher security than usually -required or than would make logical sense violates our powergaming and roleplay guidelines. - -E. Do not, under any circumstances, hide the nuclear fission explosive, authentication disk, or other -sensitive items in an impossible to see/access location. - -F. While it is allowed for the crew to know the details around antagonist functions (traitor items -being such, PDAs having uplinks, listening posts existing, etc.), Security is strictly forbidden from -acting on that information without extremely valid reason and suspicion, and it is always to presume -innocence until proven contrary. For example, it is to be avoided to check PDAs, implants and -headsets unless the person is strongly suspected to be a syndicate agent, and there is evidence to -back this up. - -7. Follow end-of-round (EOR) rules: - -A. Significant end-of-round grief (EORG) is not allowed. This includes attacking, destroying, -polluting, and severely injuring without reason both at and on the way to Central Command. - -B. Explosives and strategies with capacity for high collateral damage should not be used on or -around the evacuation shuttle. - -8. Follow ERP guidelines and rules: - -A. Be very mindful of In Character and Out of Character consent, as they are not the same thing. -Whilst a player may agree for their character to be subjected to a nonconsensual act, engaging -in ERP with someone against their OOC consent is strictly forbidden. +[color=#a4885c]5.10[/color] Try to avoid engaging in public roleplay (both verbal or/and in action) that may make other people overly uneasy or uncomfortable, unless you got very valid gameplay or roleplay reasons to it. Public meant as in: any radio channel (including the telepath channel), out loud speech or overt actions in actual public physical locations, or doing so on camera. +While it may make sometimes for amazing roleplay, not everybody may have the sensitivity to be able to hear your character recanting some dark, depressing tale or to see them doing something inherently twisted or disturbing. You can find more on this in the ERP Rules and Guidelines section. + +[color=#ff0000]6. Follow powergaming guidelines:[/color] +[color=#a4885c]6.1[/color] Don't rush for or prepare equipment unrelated to your job for no purpose other than to have it without valid reason. +[color=#a4885c]6.2[/color] A medical doctor does not need insulated gloves, the Head of Personnel does not need a gun, and the Captain does not need an assault rifle. If you, in your given role, require an item that does not fall within your job’s usual parameters, have a VERY valid gameplay or roleplay reason to obtain and keep it. +[color=#a4885c]6.3[/color] Manufacturing weapons, bombs, or deadly poisons before you know of any reason you would need them for (or without an excellent roleplay reason to it) is powergaming behavior. +[color=#a4885c]6.4[/color] Hiding Traitor objective items, or preemptively securing them with higher security than usually required or than would make logical sense, violates our powergaming and roleplay guidelines. +[color=#a4885c]6.5[/color] Do NOT, under any circumstances, hide the nuclear fission explosive, authentication disk, or other sensitive items in an impossible to see/access location. +[color=#a4885c]6.6[/color] While it is allowed for the crew to know the details around the various antagonist functions (traitor items being such, PDAs having uplinks, listening posts existing, etc.), Security is strictly forbidden from acting on that information without valid reason and suspicion, and it is always to presume innocence until proven guilty. +For example, it is to be avoided to check PDAs, implants and headsets unless the person is strongly suspected to be a syndicate agent, and there is evidence to back this up. + +[color=#ff0000]7. Follow end-of-round (EOR) rules:[/color] +[color=#a4885c]7.1[/color] End-of-round-griefing (EORG) is not allowed. This includes but is not limited to attacking, destroying, polluting, killing, and severely injuring without reason both at and on the way to Central Command. +[color=#a4885c]7.2[/color] Explosives and strategies with capacity for high collateral damage should not be used on or around the evacuation shuttle. + +[color=#ff0000]8. Follow ERP guidelines and rules:[/color] +[color=#a4885c]8.1[/color] Be very mindful of In Character and Out of Character consent, as they are NOT the same thing. Whilst a player may agree for their character to be subjected to a nonconsensual act, engaging in ERP with someone against their OOC consent is strictly forbidden. +This applies both to actual player characters, and ghost role characters, people and creatures. If your OOC consent is not respected, immediately contact an administrator or moderator. - -B. Keep in mind mind that by performing actions without IC consent, you are not immune to and will -be opening yourself to IC punishment. Expect to be apprehended, prosecuted and sentenced to the -full extent of space law, if found or known to have committed the crime you did. - -C. For the sake of freedom of roleplay and ERP in particular, extreme acts such as killing, -severely maiming, nonconning, abuse, or even round removal are allowed, so long that all the -participants consented OOC. -Ideally, if this is done with IC consent, have a form signed by all parties involved, where you -state consent to the action, and have it stamped by a lawyer or the HoP. This is advised in order -to avoid potential IC and OOC trouble from people who might be led to believe that they are -witnessing a potential, major rulebreak or OOC/IC consent violation. - -D. Try to make abundantly clear in your consent menu essential information such as whether you -want to engage in ERP or not, your limits and preferences, your OOC consent to nonconsensual -acts, your OOC or/and IC consent to extreme acts such as death or maiming, and so on so forth. -This is especially important to allow people to understand at a quick glance whether what they -are witnessing is a potential, major rulebreak or OOC/IC consent violation, or not. - -E. DO NOT use ERP as bait, unless done with OOC consent of all parties involved. Much as it would -be very believable and make for some amazing roleplay for an Agent to try and seduce a target into -the bedroom to then murder them in cold blood on the spot or kidnap them, priority is given to the -fun, comfort and enjoyment of all players. - -F. Ideally, ERP should not take priority over job responsibilities, especially for Command -and Security roles during a crisis; but for the sake of roleplay, so long it is roleplayed -well enough and there is no urgency, leeway is given. - -G. Roleplaying a character as underage is strictly forbidden. - - - -Command, Security, and Antagonist Rules: - -1. Follow Command and Security Guidelines: - -A. Security and Command roles are expected to know and perform their jobs to the best of their -ability. These roles often heavily impact the round and require more careful and conscientious -roleplay. As such, their roleplay quality is held to a much higher standard, especially in the -event a player was to play a character in such a role committing a crime or being disruptive. -If you cannot meet these requirements, do not take these roles. - -B. Both departments are required to read and follow Floof Station Space Law, Standard Operating -Procedure, Alert Procedure, and Company Policy to the best of their ability. - -C. Abusing your position or using it to make arbitrary or obviously malicious choices to the -detriment of the entire station and/or its inhabitants is prohibited, without beyond excellent roleplay -reason to it, and especially without administrator permission. - -D. Some leeway is given to Security and Command roles doings things such as committing a crime, -slacking, or being irresponsible can be given and consented in favor of freedom of roleplay and fun, -so long the player is ready to be met with the very serious in-character consequences to those actions, -so long it’s roleplayed exceptionally well, and so long what’s being done is not too disruptive or -harmful in nature to other players. - -E. Because of this last rule, an aggravating exemplary factor should be considered when sentencing or -applying IC punishment to a Security or Command role, in reason of them not acting appropriately to the -expected standards of their role. - -F. If you need to leave the round, please notify administrators via AHelp menu and notify your -fellow crew via departmental radio. If you have the capability to do so, ensure that you return your -items as necessary and seek cryostorage if you are not planning on returning. - -G. Do not hire random crew to be your bodyguard(s) or promote random crewmembers to -Command positions at random. If you require bodyguards or security details, talk to your Security -department. If you need new Command staff, talk to the personnel in that related department. - -H. Security should try to use non-lethals and arrest criminals, unless given extreme circumstances, -such as but not limited to: lethal force being used against them, their life or that of an innocent -being in immediate danger, no other reasonable option being available at the moment to detain an -unreasonably dangerous threat, or when facing off against station-destroying antagonists (nuclear -operatives, zombies, dragons, etc.). - -I. Security may choose to confiscate dangerous items (weapons, firearms) as well as items used to -commit crimes or items that could prove to be problematic when in possession of the detainee -(tools, insulated gloves, etc.), so long that there is an extremely valid, strong reason and suspicion -that such items will be used maliciously, or evidence that they have been used to commit a crime. - -J. When lethal force is used by Security, they are expected when and if possible to patch up the -critical condition detained individual back to health, or even to life in the event of death, by cloning -or defibbing. - -K. Punishment should be proportional to the crime committed and the danger posed by the criminal. -You can not execute somebody just for trespassing or stealing an item, but a provable Syndicate Agent -going loud and round removing somebody, should absolutely warrant an execution. - -L. Brig times should generally not exceed 20 minutes unless the crime is permabriggable, and -permabrigging is to be done exclusively for antagonists and exceptional cases (usually, -unreasonably dangerous individuals). - -M. Executions and Do Not Revive orders can only be carried out for capital crimes, and are to be used -sparingly as last resorts, or in the most extreme of situations and crimes. For example, when the detained -individual is proven beyond any reasonable doubt to be an unreasonably hard to contain, major threat to the -station and its inhabitants. Or when an Agent chooses to go loud, kill and round remove somebody. -The criminal should always be tried first, and executed or/and given a DNR order later. However, if this is -proven to be something impossible or too dangerous to carry out, such as during a crisis situation, or -if the crime is deemed particularly heinous and the criminal provably guilty beyond any reasonable doubt, -trial can be skipped. - -N. Do not mindbreak others against their will solely because they have psionic powers. Only do so -when the individual is either a proven antagonist (and even then, it is strongly encouraged not to do -so unless absolutely necessary, such as them having a power that makes their containment -exceedingly difficult), or proven to be misusing their powers to the detriment of the safety of the -station. - -2. Follow antagonist guidelines: -A. Antagonists exist to move the round forward and make things interesting and fun for everyone -involved. The point is not to “greentext” or win over people by pulling every meta trick in the book. -The real victory, is in achieving your goals in a fun, interesting, or unique way. As such, “play to -win” gameplay void of any roleplay aspect is not only heavily discouraged, but may also lead to -negative notes or even suspensions, if deemed to be causing a negative impact on the community -and be detrimental to everybody’s fun. The same of course, is to be applied to roles in opposition to -antagonists, such as Security and Command. We are all here to roleplay, relax and have fun, not to -have a competition on who’s the best or the most “robust”. The objectives are meant to me a means to -an end, a way to craft and tell a compelling narrative, a fun story for the shift. - -B. The damage that antagonists can cause MUST be proportional to their objectives, and contribute -towards achieving them in some way. If you are concerned as to whether or not what you're about to -do is allowed, feel free to AHelp and ask an admin for clarification. Lack of administrator response -does not constitute approval. - -C. Stealth and pacifism are heavily encouraged and to be considered preferable wherever and -whenever applicable. - -D. Round removal is strictly forbidden, outside of situations reasonably demanding it (such as for -example, getting rid of a kill objective, or getting rid of an unreasonably dangerous, hard to contain -threat), or obvious unintended accidents. - -E. Antagonists exist not only as a role for your character but also as a game mechanic. Seek to push -forward the round through your antagonistic actions, rather than grind it to halt in pursuit of your -objectives. - -F. Other antagonists are not necessarily your friends. Other agents, mercenaries, and possibly even -space dragons are free agents that you may negotiate with at your own risk. Just because both Nukies -and Agents are on the same team, they don't necessarily have to collaborate, having different goals. - -G. Heavily damaging/spacing or camping arrivals/evac/cryo, unnecessarily extending the round, -and behavior that calls the round to an end prematurely - as well as other lame behaviors - are -strictly forbidden for all antags. - -H. As a non- or partially-sentient antagonist, you are expected to have only a limited understanding -of space stations and their mechanics. Slimes, zombies, and spiders should not be targeting the -gravity generator or the AME, nor should they be unnecessarily spacing the station. - -I. Ghost roles have their own independent rules that must be followed, in addition to the already -established antagonist guidelines, for antagonist ghost roles, and the general game server rules for -non-antagonist ones. As a rule of thumb for ghost roles in general though: do not be overly disruptive -and a detriment to the fun. You may go on a rampage and kill a lot of people as a dragon because that -is what you are meant to do, or sow a bit of chaos as a skeleton. But do not go out of your way as a -mouse or Pun Pun to disturb people's privacy and ERP, or to persistently harass and annoy people -or break things for no reason. - -J. Neutral ghost roles (such as skeletons or sentient artifacts), while having the freedom of being -either friendly or hostile (and until or unless proven the latter, crew is expected to be friendly -in return), in reason of not having a defined set of objectives, are expected not to go too overboard -if choosing to be hostile. You can be a nuisance, but don't murderbone or cause mass station damage. - -K. Hostile ghost roles, while do also have the liberty of being friendly if they so wished or desired, -if deemed too big of a potential threat by the station inhabitants, they can be terminated at any time -they see fit. Although, it is strongly encouraged for the crew to act hostile with reason (for example: -a rat king who agreed to not have more than 3 rats beginning to create more); and for such ghost roles -not to powergame by acting friendly one moment, and hostile the next, the moment a great opportunity -presents itself. Furthermore, though roleplaying a creature as one would be expecting it to behave is -also strongly encouraged, due to their inherent nature of often having as a main objective to kill as -many things as possible, few of the core antagonist guidelines are a bit relaxed (specifically and in -particular those relating to killing). +[color=#a4885c]8.2[/color] Extreme acts such as killing, severely maiming, nonconning, abuse, or even round removal are allowed, so long that all the participants consented OOC. +Ideally, if this is done with IC consent, have a form signed by all parties involved, where you state consent to the action, and have it stamped by a lawyer or the HoP. +This is advised in order to avoid potential IC and OOC trouble from people who might be led to believe that they are witnessing a potential, major rulebreak or OOC/IC consent violation. +[color=#a4885c]8.3[/color] Keep in mind that by performing actions without IC consent (or actions that go against space law), you are not immune to and will be opening yourself to IC punishment. Expect to be potentially apprehended, prosecuted and sentenced to the full extent of the law, if found to have committed the crime you did. +[color=#a4885c]8.4[/color] Try to make ABUNDANTLY clear in your consent menu essential information such as whether you are interested in ERP or not, your limits and preferences, your OOC stance on nonconsensual acts towards your character, your OOC or/and IC stance on extreme acts such as death or maiming, and so on so forth. +This is especially important to allow people to understand at a quick glance whether what they are witnessing is a potential, major rulebreak or OOC/IC consent violation, or not. +[color=#a4885c]8.5[/color] DO NOT use ERP as bait, unless done with OOC consent of all parties involved. Much as it would be very believable and make for some amazing roleplay for an Agent to try and seduce a target into the bedroom to then murder them in cold blood on the spot or kidnap them, priority is given to the fun, comfort and enjoyment of all players. +[color=#a4885c]8.6[/color] Do not hog a role or a job if you do not plan to at least engage in a few of its activities and basic responsibilities in the first place. This goes especially for Command and Security roles and jobs, and especially during a crisis or emergency. +If your intent is exclusively to ERP, then take a role or a job that won't potentially lead to the station being unable to function properly. You can slack and go MiA now and then, but ideally, ERP should not take priority over basic job responsibilities and during emergencies. +To be more specific, this meaning: do not go missing from minute one, not even bother to answer radio calls, only to pop back up when the emergency shuttle arrives. And ideally, if an emergency comes up, try to go and help, if the nature of the emergency is related to your job or role. +However, so long it is roleplayed well enough and there is no immediate urgency, leeway is given (so long you are ready to face the IC consequences to this). Much larger leeway is given during Extended and Greenshift rounds, due to their nature of being meant specifically for people to relax and get off. +[color=#a4885c]8.7[/color] Do not spam or pollute radio channels (including the telepath channel) with smut. +Mind you, this does NOT mean that you are not allowed to speak or discuss of such. Just, that it should not become a cringy spamfest of people shitposting/hornyposting. +Or in other words: try not to turn them into the equivalent of a bathroom stall. Have at least a minimum bit of decency and respect towards other people. +[color=#a4885c]8.8[/color] Continuing from the previous rule: do not go overboard with hornyposting about a specific person, if said person does not have access to the channel they are being spoken about in, and if you don't have OOC consent from said person to do so. +Pushing it too far, can easily result in what is effectively sexual harassment, and be something very degradading, objectifying and humiliating to the person. +[color=#a4885c]8.9[/color] Do not engage in nor discuss of particularly extreme or out there sexual fetishes in public. +Public meant as in: any radio channel (including the telepath channel), out loud speech or overt actions in actual public physical locations, or doing so on camera. +What you like to do in the privacy of your bedroom is your business and prerogative. But do not force other people into having to witness or hear of something exceptionally outrageous that would turn the stomach of any ordinary person, or at the very least make them extremely uncomfortable. +Or in other words: respect other people's boundaries and tastes. +[color=#a4885c]8.10[/color] On the other hand, do not kinkshame somebody for something that they might be into, no matter how extreme. Unless of course, they are into being kinkshamed, or you are doing so in a playful, jokey, friendly manner for banter. +Again, respect other people's boundaries and tastes. +[color=#a4885c]8.11[/color] Use the subtle - command if you are engaging in ERP involving extreme kinks. The regular emote * action can be heard through walls. While this normally does not pose a major issue, unless you mind your privacy, it can become one if you are potentially exposing passerbys to your very unusual, outlandish fetishes. +[color=#a4885c]8.12[/color] Roleplaying a character as underage is strictly forbidden. So is speech of such activity. +[color=#a4885c]8.13[/color] Engaging in ERP with a feral, nonsentient creature (one that is not being player controlled), is forbidden. So is speech of such activity. + +[color=#ff0000]Command, Security, and Antagonist Rules:[/color] + +[color=#ff0000]1. Follow Command and Security Guidelines:[/color] +[color=#a4885c]1.1[/color] Security and Command roles are expected to know and perform their jobs to the best of their ability, and to have extensive knowledge in regards to the duties, management and operations of their departments. These roles often heavily impact the round and require careful and conscientious roleplay. +As such, their roleplay quality is held to a much higher standard, especially in the event a player was to play a character in such a role committing a crime or being disruptive. +If you cannot meet these requirements, do NOT take these roles. +[color=#a4885c]1.2[/color] Both Security and Command are required to read and follow Floof Station Space Law, Standard Operating Procedure, Alert Procedure, and Company Policy to the best of their ability. +[color=#a4885c]1.3[/color] Abusing your position or using it to make arbitrary or obviously malicious choices to the detriment of the entire station and/or its inhabitants is prohibited, without beyond excellent roleplay reason to it, and especially without administrator permission. +[color=#a4885c]1.4[/color] Some leeway is given to Security and Command roles doings things such as committing a crime, slacking, or being irresponsible, so long that the player is ready to be met with the very serious in-character consequences to such actions, so long it’s roleplayed exceptionally well, and so long what’s being done is not too disruptive or harmful in nature to other players. +[color=#a4885c]1.5[/color] Because of this last rule, an aggravating exemplary factor should be considered when sentencing or applying IC punishment to a Security or Command role, in reason of them not acting appropriately to the expected IC standards of their role. +[color=#a4885c]1.6[/color] If you need to leave the round, please notify administrators via the AHelp menu and notify your fellow crew via departmental radio. If you have the capability to do so, ensure that you return your items as necessary and seek cryostorage if you are not planning on returning. +[color=#a4885c]1.7[/color] Do not hire random crew to be your bodyguard(s) or promote random crewmembers to Command positions at random. If you require bodyguards or security details, talk to the Security department. If you need new Command staff, talk to the personnel in that related department. +[color=#a4885c]1.8[/color] Security should always try to use non-lethals and arrest criminals, unless given extreme circumstances, such as but not limited to: lethal force being used against them, their life or that of an innocent being in immediate danger, no other reasonable option being available at the moment to detain an unreasonably dangerous threat, or when facing off against station-destroying antagonists (nuclear operatives, zombies, dragons, etc.). +[color=#a4885c]1.9[/color] Security may choose to confiscate dangerous items (weapons, firearms) as well as items used to commit crimes or items that could prove to be problematic when in possession of the detainee (tools, insulated gloves, etc.), so long that there is a valid, strong reason and suspicion that such items will be used maliciously, or evidence that they have been used to commit a crime. +[color=#a4885c]1.10[/color] When lethal force is used by Security, they are expected when and if possible to patch up the critical condition detained individual back to health, or even to life in the event of death, by cloning or defibbing. +[color=#a4885c]1.11[/color] Punishment should be proportional to the crime committed and the danger posed by the criminal. You cannot execute somebody just for trespassing or stealing an item, but a provable Syndicate Agent going loud and round removing somebody, should absolutely warrant an execution. +[color=#a4885c]1.12[/color] Brig times should generally not exceed 20 minutes unless the crime is permabriggable, and permabrigging is to be done exclusively for proven antagonists and exceptional cases (usually, unreasonably dangerous individuals). +[color=#a4885c]1.13[/color] Executions and Do Not Revive orders can only be carried out for capital crimes, and are to be used sparingly as last resorts, or in the most extreme of situations and crimes. For example, when the detained individual is proven beyond any reasonable doubt to be an unreasonably hard to contain or/and major threat to the station and its inhabitants. +The criminal should always be tried first, and executed or/and given a DNR order later. However, if this is proven to be something impossible or too dangerous to carry out, such as during a crisis situation, or if the crime is deemed particularly heinous and the criminal provably guilty beyond any reasonable doubt, trial can be skipped. +[color=#a4885c]1.14[/color] Do not mindbreak others against their will solely because they have psionic powers. Only do so when the individual is either a proven antagonist (and even then, it is strongly encouraged not to do so unless absolutely necessary, such as them having a power that makes their containment exceedingly difficult), or proven to be misusing their powers to the detriment of the safety of the station. + +[color=#ff0000]2. Follow antagonist guidelines:[/color] +[color=#a4885c]2.1[/color] Antagonists exist to move the round forward and make things interesting and fun for everyone involved. The point is NOT to “greentext” or win over people by pulling every meta trick in the book. The real victory, is in achieving your goals in a fun, interesting, or unique way. As such, “play to win” gameplay void of any roleplay aspect is not only heavily discouraged, but may also lead to negative notes or even suspensions, if deemed to be causing a negative impact on the community and be detrimental to everybody’s fun. +The same of course, is to be applied to roles in opposition to antagonists, such as Security and Command. +We are all here to roleplay, relax and have fun, not to have a competition on who’s the best or the most “robust”. The objectives are meant to me a means to an end, a way to craft and tell a compelling narrative, a fun story for the shift. +[color=#a4885c]2.2[/color] The damage that antagonists can cause MUST be proportional to their objectives, and contribute towards achieving them in some way. +Round ending levels of damage (plasma/tritium/frezon flooding, atmospherics distro sabotage, singuloose and teslaloose, mass spacing, mass murder, sabotaging or destroying power in an irreparable or extremely difficult to repair manner, etc.) are rarely if ever proportional to most of antagonist objectives (some exceptions for example being nuclear operatives, dragons, or zombies), and rarely anywhere remotely fun. Thus, they should be avoided, unless you got some EXTREMELY good justification and explanation. +If you are concerned as to whether or not what you're about to do is allowed, feel free to AHelp and ask an admin for clarification. Lack of administrator response does not constitute approval. +[color=#a4885c]2.3[/color] Stealth and pacifism are heavily encouraged and to be considered preferable wherever and whenever applicable. If you can get rid of a person without having to round remove them, or obtain an item without having to destroy an entire part of the station, please consider doing so. +[color=#a4885c]2.4[/color] Round removal is strictly forbidden, outside of situations reasonably demanding it (such as for example, getting rid of a kill objective, or getting rid of an unreasonably dangerous, hard to contain threat), or obvious unintended accidents. +[color=#a4885c]2.5[/color] Antagonists exist not only as a role for your character, but also as a game mechanic. Seek to push forward the round and create a narrative through your antagonistic actions, rather than grind it to halt in pursuit of your objectives and providing zero roleplay to your actions. +[color=#a4885c]2.6[/color] Other antagonists are not necessarily your friends. Other agents, ninjas, and possibly even space dragons are free agents that you may negotiate with at your own risk. Just because both Nuclear Operatives and Syndicate Agents are on the same team, they don't necessarily have to collaborate, having different goals and instructions. +However of course, do keep in mind that not all antagonist roles can be (easily) reasoned with, such as zombies or cults. +[color=#a4885c]2.7[/color] Heavily damaging/spacing or camping arrivals/evac/cryo, unnecessarily extending the round, and actions that call the round to an end prematurely (as well as other lame behaviors), are strictly forbidden. +[color=#a4885c]2.8[/color] As a non-sentient or partially sentient antagonist, you are expected to have only a limited understanding of space stations and their mechanics. Slimes, zombies, and spiders should not be targeting the gravity generator or the AME, nor should they be unnecessarily spacing the station. +[color=#a4885c]2.9[/color] Ghost roles have their own independent rules that must be followed, in addition to the already established antagonist guidelines for antagonist ghost roles, and the general game server rules for non-antagonist ones. +As a rule of thumb for ghost roles in general though: do not be overly disruptive and a detriment to the fun. You may go on a rampage and kill a lot of people as a dragon because that is what you are meant to do, or sow a bit of chaos as a skeleton. But do not go out of your way as a mouse or Pun Pun to disturb people's privacy and ERP, or to persistently harass and annoy people or break things for no reason. +[color=#a4885c]2.10[/color] Neutral ghost roles (such as skeletons or sentient artifacts), while having the freedom of being either friendly or hostile (and until or unless proven the latter, crew is expected to be friendly in return), in reason of not having a defined set of objectives, are expected not to go too overboard if choosing to be hostile, and limit themselves to being just a nuisance at worst. +[color=#a4885c]2.11[/color] Hostile ghost roles, while do also have the liberty of being friendly if they so wished or desired, if deemed too big of a potential threat by the station inhabitants, can be terminated at any time the crew sees fit. +However, it is strongly encouraged for the crew to act hostile within reason; and for such ghost roles not to powergame by acting friendly one minute, and be hostile the next, the moment a great opportunity presents itself. +Furthermore, though roleplaying a creature as one would be expecting it to behave is also strongly encouraged, due to the inherent nature of such roles often having as a main objective to kill as many living things as possible, certain core antagonist guidelines are a bit relaxed (specifically and in particular those relating to killing). diff --git a/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/idchaplain.png b/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/idchaplain.png deleted file mode 100644 index d27ec5bbfdb..00000000000 Binary files a/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/idchaplain.png and /dev/null differ diff --git a/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/meta.json b/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/meta.json deleted file mode 100644 index 521c6e58fa7..00000000000 --- a/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/meta.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/d917f4c2a088419d5c3aec7656b7ff8cebd1822e | nyanoprisonguard, nyanogladiator, nyanomartialartist made by Floofers", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "idchaplain" - }, - { - "name": "nyanogladiator" - }, - { - "name": "nyanoprisonguard" - }, - { - "name": "nyanoprisoner" - }, - { - "name": "nyanomailcarrier" - }, - { - "name": "nyanomartialartist" - }, - { - "name": "nyanomantis" - } - ] -} diff --git a/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/nyanogladiator.png b/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/nyanogladiator.png deleted file mode 100644 index 17f3ea2aae1..00000000000 Binary files a/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/nyanogladiator.png and /dev/null differ diff --git a/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/nyanomailcarrier.png b/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/nyanomailcarrier.png deleted file mode 100644 index ba7a3d4dcdd..00000000000 Binary files a/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/nyanomailcarrier.png and /dev/null differ diff --git a/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/nyanomantis.png b/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/nyanomantis.png deleted file mode 100644 index f80e175ec33..00000000000 Binary files a/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/nyanomantis.png and /dev/null differ diff --git a/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/nyanomartialartist.png b/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/nyanomartialartist.png deleted file mode 100644 index 1f7862d0922..00000000000 Binary files a/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/nyanomartialartist.png and /dev/null differ diff --git a/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/nyanoprisoner.png b/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/nyanoprisoner.png deleted file mode 100644 index 96c8f4d9825..00000000000 Binary files a/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/nyanoprisoner.png and /dev/null differ diff --git a/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/nyanoprisonguard.png b/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/nyanoprisonguard.png deleted file mode 100644 index 0539dd50da6..00000000000 Binary files a/Resources/Textures/DeltaV/Objects/Misc/id_cards.rsi/nyanoprisonguard.png and /dev/null differ diff --git a/Resources/Textures/Floof/Clothing/Under/Socks/codervalid.rsi/equipped-FEET.png b/Resources/Textures/Floof/Clothing/Under/Socks/codervalid.rsi/equipped-FEET.png new file mode 100644 index 00000000000..e59c6092724 Binary files /dev/null and b/Resources/Textures/Floof/Clothing/Under/Socks/codervalid.rsi/equipped-FEET.png differ diff --git a/Resources/Textures/Floof/Clothing/Under/Socks/codervalid.rsi/icon.png b/Resources/Textures/Floof/Clothing/Under/Socks/codervalid.rsi/icon.png new file mode 100644 index 00000000000..06ae1ae1ec3 Binary files /dev/null and b/Resources/Textures/Floof/Clothing/Under/Socks/codervalid.rsi/icon.png differ diff --git a/Resources/Textures/Floof/Clothing/Under/Socks/codervalid.rsi/meta.json b/Resources/Textures/Floof/Clothing/Under/Socks/codervalid.rsi/meta.json new file mode 100644 index 00000000000..e07d455bc0e --- /dev/null +++ b/Resources/Textures/Floof/Clothing/Under/Socks/codervalid.rsi/meta.json @@ -0,0 +1,18 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Based from tgstation at commit https://github.com/tgstation/tgstation/commit/c838ba21dae97db345e0113f99596decd1d66039, edited by SkullBunny", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-FEET", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/anisettebottle.rsi/icon.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/anisettebottle.rsi/icon.png new file mode 100644 index 00000000000..f06427ff2ed Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/anisettebottle.rsi/icon.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/anisettebottle.rsi/icon_open.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/anisettebottle.rsi/icon_open.png new file mode 100644 index 00000000000..59b5313c63c Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/anisettebottle.rsi/icon_open.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/anisettebottle.rsi/meta.json b/Resources/Textures/Floof/Objects/Consumable/Drinks/anisettebottle.rsi/meta.json new file mode 100644 index 00000000000..a08ad100c64 --- /dev/null +++ b/Resources/Textures/Floof/Objects/Consumable/Drinks/anisettebottle.rsi/meta.json @@ -0,0 +1,17 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "dakodragon, DiscordID: 56038550335922176", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_open" + } + ] +} diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/fill-1.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/fill-1.png new file mode 100644 index 00000000000..21f29d33826 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/fill-1.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/fill-2.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/fill-2.png new file mode 100644 index 00000000000..75f9f08820a Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/fill-2.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/fill-3.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/fill-3.png new file mode 100644 index 00000000000..f5dc781b75d Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/fill-3.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/fill-4.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/fill-4.png new file mode 100644 index 00000000000..fef1e7bc4ea Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/fill-4.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/fill-5.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/fill-5.png new file mode 100644 index 00000000000..dca5caeb945 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/fill-5.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/icon.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/icon.png new file mode 100644 index 00000000000..14f1773a43e Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/icon.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/icon_empty.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/icon_empty.png new file mode 100644 index 00000000000..8bb86d0d3e3 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/icon_empty.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/meta.json b/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/meta.json new file mode 100644 index 00000000000..a81de107c0a --- /dev/null +++ b/Resources/Textures/Floof/Objects/Consumable/Drinks/blueballer.rsi/meta.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-3.0", + "copyright": "dakodragon, DiscordID: 56038550335922176", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + } + ] +} diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/bottleocum.rsi/icon.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/bottleocum.rsi/icon.png new file mode 100644 index 00000000000..9dc6dadaa86 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/bottleocum.rsi/icon.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/bottleocum.rsi/icon_open.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/bottleocum.rsi/icon_open.png new file mode 100644 index 00000000000..950960fe051 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/bottleocum.rsi/icon_open.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/bottleocum.rsi/meta.json b/Resources/Textures/Floof/Objects/Consumable/Drinks/bottleocum.rsi/meta.json new file mode 100644 index 00000000000..a08ad100c64 --- /dev/null +++ b/Resources/Textures/Floof/Objects/Consumable/Drinks/bottleocum.rsi/meta.json @@ -0,0 +1,17 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "dakodragon, DiscordID: 56038550335922176", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_open" + } + ] +} diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/fill-1.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/fill-1.png new file mode 100644 index 00000000000..41fe40ec28d Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/fill-1.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/fill-2.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/fill-2.png new file mode 100644 index 00000000000..fff6c237884 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/fill-2.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/fill-3.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/fill-3.png new file mode 100644 index 00000000000..b3c8bf8fc27 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/fill-3.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/fill-4.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/fill-4.png new file mode 100644 index 00000000000..3ce2d070ecc Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/fill-4.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/fill-5.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/fill-5.png new file mode 100644 index 00000000000..c098cd035a2 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/fill-5.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/icon.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/icon.png new file mode 100644 index 00000000000..66c3a92b5ea Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/icon.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/icon_empty.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/icon_empty.png new file mode 100644 index 00000000000..89c4357af63 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/icon_empty.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/meta.json b/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/meta.json new file mode 100644 index 00000000000..a81de107c0a --- /dev/null +++ b/Resources/Textures/Floof/Objects/Consumable/Drinks/demonseed.rsi/meta.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-3.0", + "copyright": "dakodragon, DiscordID: 56038550335922176", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + } + ] +} diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/fill-1.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/fill-1.png new file mode 100644 index 00000000000..f4a5f7b6e14 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/fill-1.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/fill-2.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/fill-2.png new file mode 100644 index 00000000000..d6ef0c42c1a Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/fill-2.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/fill-3.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/fill-3.png new file mode 100644 index 00000000000..3b80b95a7ac Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/fill-3.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/fill-4.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/fill-4.png new file mode 100644 index 00000000000..6845cc8df99 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/fill-4.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/fill-5.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/fill-5.png new file mode 100644 index 00000000000..edb35a78a9a Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/fill-5.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/icon.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/icon.png new file mode 100644 index 00000000000..c12e307ab5f Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/icon.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/icon_empty.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/icon_empty.png new file mode 100644 index 00000000000..874800db7aa Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/icon_empty.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/meta.json b/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/meta.json new file mode 100644 index 00000000000..a81de107c0a --- /dev/null +++ b/Resources/Textures/Floof/Objects/Consumable/Drinks/doublecreamblaster.rsi/meta.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-3.0", + "copyright": "dakodragon, DiscordID: 56038550335922176", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + } + ] +} diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/fill-1.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/fill-1.png new file mode 100644 index 00000000000..14e76ff5c20 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/fill-1.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/fill-2.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/fill-2.png new file mode 100644 index 00000000000..5336c7dbebf Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/fill-2.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/fill-3.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/fill-3.png new file mode 100644 index 00000000000..e749d85d7c4 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/fill-3.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/fill-4.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/fill-4.png new file mode 100644 index 00000000000..b6e5636ebaa Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/fill-4.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/fill-5.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/fill-5.png new file mode 100644 index 00000000000..f4a720898f0 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/fill-5.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/icon.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/icon.png new file mode 100644 index 00000000000..6cf8ff7e8fb Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/icon.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/icon_empty.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/icon_empty.png new file mode 100644 index 00000000000..4601d6d347b Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/icon_empty.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/meta.json b/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/meta.json new file mode 100644 index 00000000000..a81de107c0a --- /dev/null +++ b/Resources/Textures/Floof/Objects/Consumable/Drinks/emeraldswinger.rsi/meta.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-3.0", + "copyright": "dakodragon, DiscordID: 56038550335922176", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + } + ] +} diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/mariejulep.rsi/fill-1.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/mariejulep.rsi/fill-1.png new file mode 100644 index 00000000000..6e0adac88a1 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/mariejulep.rsi/fill-1.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/mariejulep.rsi/fill-2.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/mariejulep.rsi/fill-2.png new file mode 100644 index 00000000000..9247dc67746 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/mariejulep.rsi/fill-2.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/mariejulep.rsi/fill-3.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/mariejulep.rsi/fill-3.png new file mode 100644 index 00000000000..b3e30bfbbea Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/mariejulep.rsi/fill-3.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/mariejulep.rsi/icon.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/mariejulep.rsi/icon.png new file mode 100644 index 00000000000..b830ca3a407 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/mariejulep.rsi/icon.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/mariejulep.rsi/icon_empty.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/mariejulep.rsi/icon_empty.png new file mode 100644 index 00000000000..487f00c16bc Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/mariejulep.rsi/icon_empty.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/mariejulep.rsi/meta.json b/Resources/Textures/Floof/Objects/Consumable/Drinks/mariejulep.rsi/meta.json new file mode 100644 index 00000000000..2ebdcd6df65 --- /dev/null +++ b/Resources/Textures/Floof/Objects/Consumable/Drinks/mariejulep.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-3.0", + "copyright": "dakodragon, DiscordID: 56038550335922176", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + } + ] +} diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/fill-1.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/fill-1.png new file mode 100644 index 00000000000..379ae7da114 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/fill-1.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/fill-2.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/fill-2.png new file mode 100644 index 00000000000..dcdda7bcc8b Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/fill-2.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/fill-3.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/fill-3.png new file mode 100644 index 00000000000..5a15d0811db Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/fill-3.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/fill-4.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/fill-4.png new file mode 100644 index 00000000000..fb98998a7af Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/fill-4.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/fill-5.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/fill-5.png new file mode 100644 index 00000000000..767c149af17 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/fill-5.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/icon.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/icon.png new file mode 100644 index 00000000000..5378e66a68e Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/icon.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/icon_empty.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/icon_empty.png new file mode 100644 index 00000000000..eec347b73db Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/icon_empty.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/meta.json b/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/meta.json new file mode 100644 index 00000000000..a81de107c0a --- /dev/null +++ b/Resources/Textures/Floof/Objects/Consumable/Drinks/orgasmonthebeach.rsi/meta.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-3.0", + "copyright": "dakodragon, DiscordID: 56038550335922176", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + } + ] +} diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/pompassion.rsi/fill-1.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/pompassion.rsi/fill-1.png new file mode 100644 index 00000000000..6fa3a4e3a31 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/pompassion.rsi/fill-1.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/pompassion.rsi/fill-2.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/pompassion.rsi/fill-2.png new file mode 100644 index 00000000000..ee8dec2d9e2 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/pompassion.rsi/fill-2.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/pompassion.rsi/fill-3.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/pompassion.rsi/fill-3.png new file mode 100644 index 00000000000..0dcb57b9edc Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/pompassion.rsi/fill-3.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/pompassion.rsi/icon.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/pompassion.rsi/icon.png new file mode 100644 index 00000000000..4826f35e0b6 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/pompassion.rsi/icon.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/pompassion.rsi/icon_empty.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/pompassion.rsi/icon_empty.png new file mode 100644 index 00000000000..e733a1c0676 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/pompassion.rsi/icon_empty.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/pompassion.rsi/meta.json b/Resources/Textures/Floof/Objects/Consumable/Drinks/pompassion.rsi/meta.json new file mode 100644 index 00000000000..2ebdcd6df65 --- /dev/null +++ b/Resources/Textures/Floof/Objects/Consumable/Drinks/pompassion.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-3.0", + "copyright": "dakodragon, DiscordID: 56038550335922176", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + } + ] +} diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/fill-1.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/fill-1.png new file mode 100644 index 00000000000..97c2d8fa5ec Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/fill-1.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/fill-2.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/fill-2.png new file mode 100644 index 00000000000..b921bd6b8c2 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/fill-2.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/fill-3.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/fill-3.png new file mode 100644 index 00000000000..4277739c556 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/fill-3.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/fill-4.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/fill-4.png new file mode 100644 index 00000000000..3f23335fa63 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/fill-4.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/fill-5.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/fill-5.png new file mode 100644 index 00000000000..2dc305d78e1 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/fill-5.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/icon.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/icon.png new file mode 100644 index 00000000000..6eca02a3d16 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/icon.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/icon_empty.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/icon_empty.png new file mode 100644 index 00000000000..9a804ea42c0 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/icon_empty.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/meta.json b/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/meta.json new file mode 100644 index 00000000000..a81de107c0a --- /dev/null +++ b/Resources/Textures/Floof/Objects/Consumable/Drinks/redrocket.rsi/meta.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-3.0", + "copyright": "dakodragon, DiscordID: 56038550335922176", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + } + ] +} diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/fill-1.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/fill-1.png new file mode 100644 index 00000000000..a8e391ad497 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/fill-1.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/fill-2.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/fill-2.png new file mode 100644 index 00000000000..cf8af85c5e4 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/fill-2.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/fill-3.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/fill-3.png new file mode 100644 index 00000000000..22bb5e66fe9 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/fill-3.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/fill-4.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/fill-4.png new file mode 100644 index 00000000000..d207e97d9f0 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/fill-4.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/fill-5.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/fill-5.png new file mode 100644 index 00000000000..d07397a4f63 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/fill-5.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/icon.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/icon.png new file mode 100644 index 00000000000..fbf4eda3ae2 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/icon.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/icon_empty.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/icon_empty.png new file mode 100644 index 00000000000..4c7eef2df84 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/icon_empty.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/meta.json b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/meta.json new file mode 100644 index 00000000000..a81de107c0a --- /dev/null +++ b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenbomb.rsi/meta.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-3.0", + "copyright": "dakodragon, DiscordID: 56038550335922176", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + } + ] +} diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/fill-1.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/fill-1.png new file mode 100644 index 00000000000..d5bc16bf65b Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/fill-1.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/fill-2.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/fill-2.png new file mode 100644 index 00000000000..87e01cd71d9 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/fill-2.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/fill-3.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/fill-3.png new file mode 100644 index 00000000000..c9deed71468 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/fill-3.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/fill-4.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/fill-4.png new file mode 100644 index 00000000000..64827b70470 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/fill-4.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/fill-5.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/fill-5.png new file mode 100644 index 00000000000..8692c413711 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/fill-5.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/icon.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/icon.png new file mode 100644 index 00000000000..51d3fd92aec Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/icon.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/icon_empty.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/icon_empty.png new file mode 100644 index 00000000000..ed648daf97a Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/icon_empty.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/meta.json b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/meta.json new file mode 100644 index 00000000000..a81de107c0a --- /dev/null +++ b/Resources/Textures/Floof/Objects/Consumable/Drinks/semenhemorrhage.rsi/meta.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-3.0", + "copyright": "dakodragon, DiscordID: 56038550335922176", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + } + ] +} diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/watermelonginjizz.rsi/fill-1.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/watermelonginjizz.rsi/fill-1.png new file mode 100644 index 00000000000..4583ccbe01f Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/watermelonginjizz.rsi/fill-1.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/watermelonginjizz.rsi/fill-2.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/watermelonginjizz.rsi/fill-2.png new file mode 100644 index 00000000000..bcab66db818 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/watermelonginjizz.rsi/fill-2.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/watermelonginjizz.rsi/fill-3.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/watermelonginjizz.rsi/fill-3.png new file mode 100644 index 00000000000..16d2ca6ef53 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/watermelonginjizz.rsi/fill-3.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/watermelonginjizz.rsi/icon.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/watermelonginjizz.rsi/icon.png new file mode 100644 index 00000000000..fd8e720f910 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/watermelonginjizz.rsi/icon.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/watermelonginjizz.rsi/icon_empty.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/watermelonginjizz.rsi/icon_empty.png new file mode 100644 index 00000000000..4f9b9869081 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/watermelonginjizz.rsi/icon_empty.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/watermelonginjizz.rsi/meta.json b/Resources/Textures/Floof/Objects/Consumable/Drinks/watermelonginjizz.rsi/meta.json new file mode 100644 index 00000000000..2ebdcd6df65 --- /dev/null +++ b/Resources/Textures/Floof/Objects/Consumable/Drinks/watermelonginjizz.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-3.0", + "copyright": "dakodragon, DiscordID: 56038550335922176", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + } + ] +} diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/fill-1.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/fill-1.png new file mode 100644 index 00000000000..4ffc3e6eee9 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/fill-1.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/fill-2.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/fill-2.png new file mode 100644 index 00000000000..16d25ce8ee1 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/fill-2.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/fill-3.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/fill-3.png new file mode 100644 index 00000000000..699e3e79d29 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/fill-3.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/fill-4.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/fill-4.png new file mode 100644 index 00000000000..879478a2e26 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/fill-4.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/fill-5.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/fill-5.png new file mode 100644 index 00000000000..751bd9249d0 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/fill-5.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/icon.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/icon.png new file mode 100644 index 00000000000..72815d81296 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/icon.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/icon_empty.png b/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/icon_empty.png new file mode 100644 index 00000000000..3c6d9fcd65e Binary files /dev/null and b/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/icon_empty.png differ diff --git a/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/meta.json b/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/meta.json new file mode 100644 index 00000000000..a81de107c0a --- /dev/null +++ b/Resources/Textures/Floof/Objects/Consumable/Drinks/yeolhandy.rsi/meta.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-3.0", + "copyright": "dakodragon, DiscordID: 56038550335922176", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + } + ] +} diff --git a/Resources/Textures/Floof/Objects/Specific/Hydroponics/pomegranate.rsi/meta.json b/Resources/Textures/Floof/Objects/Specific/Hydroponics/pomegranate.rsi/meta.json index 775f8df408f..37753c03847 100644 --- a/Resources/Textures/Floof/Objects/Specific/Hydroponics/pomegranate.rsi/meta.json +++ b/Resources/Textures/Floof/Objects/Specific/Hydroponics/pomegranate.rsi/meta.json @@ -17,7 +17,10 @@ "name": "produce" }, { - "name": "seed" + "name": "seed" + }, + { + "name": "slice" }, { "name": "stage-1" diff --git a/Resources/Textures/Floof/Objects/Specific/Hydroponics/pomegranate.rsi/produce.png b/Resources/Textures/Floof/Objects/Specific/Hydroponics/pomegranate.rsi/produce.png index a947a6149b9..d25f16048e3 100644 Binary files a/Resources/Textures/Floof/Objects/Specific/Hydroponics/pomegranate.rsi/produce.png and b/Resources/Textures/Floof/Objects/Specific/Hydroponics/pomegranate.rsi/produce.png differ diff --git a/Resources/Textures/Floof/Objects/Specific/Hydroponics/pomegranate.rsi/slice.png b/Resources/Textures/Floof/Objects/Specific/Hydroponics/pomegranate.rsi/slice.png new file mode 100644 index 00000000000..d2c6918b883 Binary files /dev/null and b/Resources/Textures/Floof/Objects/Specific/Hydroponics/pomegranate.rsi/slice.png differ diff --git a/Resources/Textures/Interface/Alerts/offer_item.rsi/meta.json b/Resources/Textures/Interface/Alerts/offer_item.rsi/meta.json index 6b8580b7dc3..9b5f9361314 100644 --- a/Resources/Textures/Interface/Alerts/offer_item.rsi/meta.json +++ b/Resources/Textures/Interface/Alerts/offer_item.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/ss220-space/Paradise/blob/master220/icons/mob/screen_alert.dmi", + "copyright": "Original icon taken from https://github.com/ss220-space/Paradise/blob/master220/icons/mob/screen_alert.dmi, modified by Mocho", "size": { "x": 32, "y": 32 diff --git a/Resources/Textures/Interface/Alerts/offer_item.rsi/offer_item.png b/Resources/Textures/Interface/Alerts/offer_item.rsi/offer_item.png index ce39fa92299..44ac380ddb1 100644 Binary files a/Resources/Textures/Interface/Alerts/offer_item.rsi/offer_item.png and b/Resources/Textures/Interface/Alerts/offer_item.rsi/offer_item.png differ diff --git a/Resources/Textures/Interface/Alerts/walking.rsi/meta.json b/Resources/Textures/Interface/Alerts/walking.rsi/meta.json new file mode 100644 index 00000000000..d328b01a45f --- /dev/null +++ b/Resources/Textures/Interface/Alerts/walking.rsi/meta.json @@ -0,0 +1,17 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Walking/Running icons modified by Mocho, original taken from /tg/station https://github.com/tgstation/tgstation/pull/52691/commits/6a1261187c108c8f151c99ebfa567bd1ec34044c", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "walking0" + }, + { + "name": "walking1" + } + ] +} diff --git a/Resources/Textures/Interface/Alerts/walking.rsi/walking0.png b/Resources/Textures/Interface/Alerts/walking.rsi/walking0.png new file mode 100644 index 00000000000..1d1f048fb91 Binary files /dev/null and b/Resources/Textures/Interface/Alerts/walking.rsi/walking0.png differ diff --git a/Resources/Textures/Interface/Alerts/walking.rsi/walking1.png b/Resources/Textures/Interface/Alerts/walking.rsi/walking1.png new file mode 100644 index 00000000000..3980ee73b5d Binary files /dev/null and b/Resources/Textures/Interface/Alerts/walking.rsi/walking1.png differ diff --git a/Resources/Textures/Objects/Consumable/Food/meals.rsi/harpywings.png b/Resources/Textures/Objects/Consumable/Food/meals.rsi/harpywings.png new file mode 100644 index 00000000000..e355802a95a Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Food/meals.rsi/harpywings.png differ diff --git a/Resources/Textures/Objects/Consumable/Food/meals.rsi/meta.json b/Resources/Textures/Objects/Consumable/Food/meals.rsi/meta.json index e3fa26223a2..320257ad198 100644 --- a/Resources/Textures/Objects/Consumable/Food/meals.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Food/meals.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/c6e3401f2e7e1e55c57060cdf956a98ef1fefc24, taco from https://github.com/ss220-space/Paradise/commit/6c9bd827610433093a79d814b96bd50f9cf12eec, corn in butter from im_kreks", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/c6e3401f2e7e1e55c57060cdf956a98ef1fefc24, taco from https://github.com/ss220-space/Paradise/commit/6c9bd827610433093a79d814b96bd50f9cf12eec, corn in butter from im_kreks, harpywings from dootythefrooty", "size": { "x": 32, "y": 32 @@ -150,6 +150,9 @@ }, { "name": "corn-in-butter" + }, + { + "name": "harpywings" } ] } diff --git a/Resources/Textures/Objects/Fun/toys.rsi/meta.json b/Resources/Textures/Objects/Fun/toys.rsi/meta.json index fc92a479367..cae7880e414 100644 --- a/Resources/Textures/Objects/Fun/toys.rsi/meta.json +++ b/Resources/Textures/Objects/Fun/toys.rsi/meta.json @@ -104,6 +104,9 @@ { "name": "plushie_diona" }, + { + "name": "plushie_arachne" + }, { "name": "plushie_human" }, diff --git a/Resources/Textures/Objects/Fun/toys.rsi/plushie_arachne.png b/Resources/Textures/Objects/Fun/toys.rsi/plushie_arachne.png new file mode 100644 index 00000000000..4f72c31ddf6 Binary files /dev/null and b/Resources/Textures/Objects/Fun/toys.rsi/plushie_arachne.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/assistant.png b/Resources/Textures/Objects/Misc/id_cards.rsi/assistant.png new file mode 100644 index 00000000000..a3e83280f72 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/assistant.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/atmospherictechnician.png b/Resources/Textures/Objects/Misc/id_cards.rsi/atmospherictechnician.png new file mode 100644 index 00000000000..99e10c276d7 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/atmospherictechnician.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/bartender.png b/Resources/Textures/Objects/Misc/id_cards.rsi/bartender.png new file mode 100644 index 00000000000..24a1b62fe24 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/bartender.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/black.png b/Resources/Textures/Objects/Misc/id_cards.rsi/black.png new file mode 100644 index 00000000000..6958c6d4490 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/black.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/botanist.png b/Resources/Textures/Objects/Misc/id_cards.rsi/botanist.png new file mode 100644 index 00000000000..4d62c18a60a Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/botanist.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/boxer.png b/Resources/Textures/Objects/Misc/id_cards.rsi/boxer.png new file mode 100644 index 00000000000..90b9165c049 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/boxer.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/captain.png b/Resources/Textures/Objects/Misc/id_cards.rsi/captain.png new file mode 100644 index 00000000000..72ec0038427 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/captain.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/cargotechnician.png b/Resources/Textures/Objects/Misc/id_cards.rsi/cargotechnician.png new file mode 100644 index 00000000000..7f5fba10169 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/cargotechnician.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/carp.png b/Resources/Textures/Objects/Misc/id_cards.rsi/carp.png new file mode 100644 index 00000000000..1ef99e1cef6 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/carp.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/cc.png b/Resources/Textures/Objects/Misc/id_cards.rsi/cc.png new file mode 100644 index 00000000000..9a28b7780c6 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/cc.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/centcom.png b/Resources/Textures/Objects/Misc/id_cards.rsi/centcom.png index ff1e293183c..3ed8b4045a7 100644 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/centcom.png and b/Resources/Textures/Objects/Misc/id_cards.rsi/centcom.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/chaplain.png b/Resources/Textures/Objects/Misc/id_cards.rsi/chaplain.png new file mode 100644 index 00000000000..1e134c3911b Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/chaplain.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/chemist.png b/Resources/Textures/Objects/Misc/id_cards.rsi/chemist.png new file mode 100644 index 00000000000..11a34b3f053 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/chemist.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/clown.png b/Resources/Textures/Objects/Misc/id_cards.rsi/clown.png new file mode 100644 index 00000000000..24dea8a6d00 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/clown.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/cook.png b/Resources/Textures/Objects/Misc/id_cards.rsi/cook.png new file mode 100644 index 00000000000..8a4e8c15d1e Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/cook.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/curator.png b/Resources/Textures/Objects/Misc/id_cards.rsi/curator.png new file mode 100644 index 00000000000..534150e6de3 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/curator.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/death.png b/Resources/Textures/Objects/Misc/id_cards.rsi/death.png new file mode 100644 index 00000000000..c2190596169 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/death.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/default.png b/Resources/Textures/Objects/Misc/id_cards.rsi/default.png index 95b3d54c270..a7142e353ea 100644 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/default.png and b/Resources/Textures/Objects/Misc/id_cards.rsi/default.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/department.png b/Resources/Textures/Objects/Misc/id_cards.rsi/department.png new file mode 100644 index 00000000000..001c8d75f5e Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/department.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/departmenthead.png b/Resources/Textures/Objects/Misc/id_cards.rsi/departmenthead.png new file mode 100644 index 00000000000..09f48fbb838 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/departmenthead.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/detective.png b/Resources/Textures/Objects/Misc/id_cards.rsi/detective.png new file mode 100644 index 00000000000..8e21d3539c4 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/detective.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/ert_chaplain.png b/Resources/Textures/Objects/Misc/id_cards.rsi/ert_chaplain.png deleted file mode 100644 index 624bb4864db..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/ert_chaplain.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/ert_commander.png b/Resources/Textures/Objects/Misc/id_cards.rsi/ert_commander.png deleted file mode 100644 index d9c8b6e261d..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/ert_commander.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/ert_engineer.png b/Resources/Textures/Objects/Misc/id_cards.rsi/ert_engineer.png deleted file mode 100644 index a7c8b683556..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/ert_engineer.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/ert_janitor.png b/Resources/Textures/Objects/Misc/id_cards.rsi/ert_janitor.png deleted file mode 100644 index afbe56e5f0d..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/ert_janitor.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/ert_medic.png b/Resources/Textures/Objects/Misc/id_cards.rsi/ert_medic.png deleted file mode 100644 index 6fe2ce6698f..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/ert_medic.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/ert_security.png b/Resources/Textures/Objects/Misc/id_cards.rsi/ert_security.png deleted file mode 100644 index 6bb3134b557..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/ert_security.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/flame.png b/Resources/Textures/Objects/Misc/id_cards.rsi/flame.png new file mode 100644 index 00000000000..014c98322aa Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/flame.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/geneticist.png b/Resources/Textures/Objects/Misc/id_cards.rsi/geneticist.png new file mode 100644 index 00000000000..0980bb306c3 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/geneticist.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/gladiator.png b/Resources/Textures/Objects/Misc/id_cards.rsi/gladiator.png new file mode 100644 index 00000000000..407a927b6a4 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/gladiator.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/gold.png b/Resources/Textures/Objects/Misc/id_cards.rsi/gold.png index bb20387315c..859a9ec99cf 100644 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/gold.png and b/Resources/Textures/Objects/Misc/id_cards.rsi/gold.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/headofpersonnel.png b/Resources/Textures/Objects/Misc/id_cards.rsi/headofpersonnel.png new file mode 100644 index 00000000000..d0b4235c816 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/headofpersonnel.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idatmospherictechnician.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idatmospherictechnician.png deleted file mode 100644 index 3bd5446a3bc..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idatmospherictechnician.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idbartender.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idbartender.png deleted file mode 100644 index 435ea39ad6a..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idbartender.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idbotanist.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idbotanist.png deleted file mode 100644 index f5dfdb86629..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idbotanist.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idboxer.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idboxer.png deleted file mode 100644 index 0c2b5298e5f..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idboxer.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idbrigmedic.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idbrigmedic.png deleted file mode 100644 index 1f64eb4845a..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idbrigmedic.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idcaptain.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idcaptain.png deleted file mode 100644 index e59e7c3d042..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idcaptain.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idcargotechnician.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idcargotechnician.png deleted file mode 100644 index cfa0a35dcc5..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idcargotechnician.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idcentcom.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idcentcom.png deleted file mode 100644 index 25b7017a708..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idcentcom.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idchaplain.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idchaplain.png deleted file mode 100644 index e10e3c82a6e..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idchaplain.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idchemist.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idchemist.png deleted file mode 100644 index 2dba29c2060..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idchemist.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idchiefengineer.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idchiefengineer.png deleted file mode 100644 index f105b4f88ad..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idchiefengineer.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idchiefmedicalofficer.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idchiefmedicalofficer.png deleted file mode 100644 index 82a608a9a1a..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idchiefmedicalofficer.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idclown.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idclown.png deleted file mode 100644 index e0372020448..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idclown.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idcluwne.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idcluwne.png deleted file mode 100644 index d57a7e3d416..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idcluwne.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idcook.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idcook.png deleted file mode 100644 index 09527688a46..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idcook.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idcurator.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idcurator.png deleted file mode 100644 index cd01dc77702..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idcurator.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/iddetective.png b/Resources/Textures/Objects/Misc/id_cards.rsi/iddetective.png deleted file mode 100644 index 3b749d582a5..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/iddetective.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idgeneticist.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idgeneticist.png deleted file mode 100644 index 1303135aa5a..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idgeneticist.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idheadofpersonnel.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idheadofpersonnel.png deleted file mode 100644 index be72e37e574..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idheadofpersonnel.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idheadofsecurity.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idheadofsecurity.png deleted file mode 100644 index bb03adc665c..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idheadofsecurity.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idintern-cadet.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idintern-cadet.png deleted file mode 100644 index cebf46fade2..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idintern-cadet.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idintern-med.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idintern-med.png deleted file mode 100644 index 15c7cde5e86..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idintern-med.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idintern-sci.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idintern-sci.png deleted file mode 100644 index de676944766..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idintern-sci.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idintern-service.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idintern-service.png deleted file mode 100644 index 5fc1f43c05b..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idintern-service.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idintern-tech.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idintern-tech.png deleted file mode 100644 index f7ed302b23a..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idintern-tech.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idjanitor.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idjanitor.png deleted file mode 100644 index 320c3885e7e..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idjanitor.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idlawyer.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idlawyer.png deleted file mode 100644 index b86f437aee1..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idlawyer.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idmedicaldoctor.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idmedicaldoctor.png deleted file mode 100644 index 9e390bb606f..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idmedicaldoctor.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idmime.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idmime.png deleted file mode 100644 index b917612dae2..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idmime.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idmusician.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idmusician.png deleted file mode 100644 index b51dfaaab8e..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idmusician.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idparamedic.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idparamedic.png deleted file mode 100644 index 1881839e965..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idparamedic.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idpassenger.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idpassenger.png deleted file mode 100644 index 88866eb1693..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idpassenger.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idprisoner.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idprisoner.png deleted file mode 100644 index f9337a37c53..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idprisoner.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idpsychologist.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idpsychologist.png deleted file mode 100644 index 038a5321d4b..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idpsychologist.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idquartermaster.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idquartermaster.png deleted file mode 100644 index bfdd0678724..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idquartermaster.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idreporter.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idreporter.png deleted file mode 100644 index e4ea4f95882..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idreporter.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idresearchdirector.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idresearchdirector.png deleted file mode 100644 index fdb1fd2648b..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idresearchdirector.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idroboticist.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idroboticist.png deleted file mode 100644 index a9d6c5facd5..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idroboticist.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idscientist.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idscientist.png deleted file mode 100644 index 893346a9c90..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idscientist.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idsecurityofficer.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idsecurityofficer.png deleted file mode 100644 index 6456d644396..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idsecurityofficer.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idseniorengineer.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idseniorengineer.png deleted file mode 100644 index 73c8b6d00fe..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idseniorengineer.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idseniorofficer.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idseniorofficer.png deleted file mode 100644 index f3a87d6fa4b..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idseniorofficer.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idseniorphysician.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idseniorphysician.png deleted file mode 100644 index 2d00cf7a164..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idseniorphysician.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idseniorresearcher.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idseniorresearcher.png deleted file mode 100644 index 47a2ccb7485..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idseniorresearcher.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idshaftminer.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idshaftminer.png deleted file mode 100644 index c232dd439d4..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idshaftminer.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idstationengineer.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idstationengineer.png deleted file mode 100644 index 2e046fbacdd..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idstationengineer.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idunknown.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idunknown.png deleted file mode 100644 index bc792fe1a17..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idunknown.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idvirologist.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idvirologist.png deleted file mode 100644 index 1d4b2f2d474..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idvirologist.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idwarden.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idwarden.png deleted file mode 100644 index 0b4086478ca..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idwarden.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/idzookeeper.png b/Resources/Textures/Objects/Misc/id_cards.rsi/idzookeeper.png deleted file mode 100644 index c24212aab8d..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/idzookeeper.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/janitor.png b/Resources/Textures/Objects/Misc/id_cards.rsi/janitor.png new file mode 100644 index 00000000000..19eb0d52482 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/janitor.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/lawyer.png b/Resources/Textures/Objects/Misc/id_cards.rsi/lawyer.png new file mode 100644 index 00000000000..973bbf66e1e Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/lawyer.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/mailcarrier.png b/Resources/Textures/Objects/Misc/id_cards.rsi/mailcarrier.png new file mode 100644 index 00000000000..db33a5ead4c Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/mailcarrier.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/martialartist.png b/Resources/Textures/Objects/Misc/id_cards.rsi/martialartist.png new file mode 100644 index 00000000000..e49e4478429 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/martialartist.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/medicaldoctor.png b/Resources/Textures/Objects/Misc/id_cards.rsi/medicaldoctor.png new file mode 100644 index 00000000000..92832dcaad6 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/medicaldoctor.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/meta.json b/Resources/Textures/Objects/Misc/id_cards.rsi/meta.json index a84c76a46c9..eeed695ca3c 100644 --- a/Resources/Textures/Objects/Misc/id_cards.rsi/meta.json +++ b/Resources/Textures/Objects/Misc/id_cards.rsi/meta.json @@ -1,261 +1,204 @@ { - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/d917f4c2a088419d5c3aec7656b7ff8cebd1822e idcluwne made by brainfood1183 (github) for ss14, idbrigmedic made by PuroSlavKing (Github), pirate made by brainfood1183 (github)", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "default" - }, - { - "name": "centcom" - }, - { - "name": "ert_chaplain" - }, - { - "name": "ert_commander" - }, - { - "name": "ert_engineer" - }, - { - "name": "ert_janitor" - }, - { - "name": "ert_medic" - }, - { - "name": "ert_security" - }, - { - "name": "gold" - }, - { - "name": "idpassenger" - }, - { - "name": "idatmospherictechnician" - }, - { - "name": "idbartender" - }, - { - "name": "idbotanist" - }, - { - "name": "idboxer" - }, - { - "name": "idcaptain" - }, - { - "name": "idcargotechnician" - }, - { - "name": "idcentcom" - }, - { - "name": "idchaplain" - }, - { - "name": "idchemist" - }, - { - "name": "idchiefengineer" - }, - { - "name": "idchiefmedicalofficer" - }, - { - "name": "idclown" - }, - { - "name": "idcook" - }, - { - "name": "idcurator" - }, - { - "name": "iddetective" - }, - { - "name": "idgeneticist" - }, - { - "name": "idheadofpersonnel" - }, - { - "name": "idheadofsecurity" - }, - { - "name": "idbrigmedic" - }, - { - "name": "idjanitor" - }, - { - "name": "idlawyer" - }, - { - "name": "idmedicaldoctor" - }, - { - "name": "idmime" - }, - { - "name": "idparamedic" - }, - { - "name": "idpsychologist" - }, - { - "name": "idreporter" - }, - { - "name": "idprisoner" - }, - { - "name": "idquartermaster" - }, - { - "name": "idresearchdirector" - }, - { - "name": "idroboticist" - }, - { - "name": "idscientist" - }, - { - "name": "idsecurityofficer" - }, - { - "name": "idshaftminer" - }, - { - "name": "idstationengineer" - }, - { - "name": "idunknown" - }, - { - "name": "idvirologist" - }, - { - "name": "idwarden" - }, - { - "name": "idmusician" - }, - { - "name": "idzookeeper" - }, - { - "name": "idintern-sci" - }, - { - "name": "idintern-cadet" - }, - { - "name": "idintern-med" - }, - { - "name": "idintern-service" - }, - { - "name": "idintern-tech" - }, - { - "name": "orange" - }, - { - "name": "pirate" - }, - { - "name": "prisoner_001" - }, - { - "name": "prisoner_002" - }, - { - "name": "prisoner_003" - }, - { - "name": "prisoner_004" - }, - { - "name": "prisoner_005" - }, - { - "name": "prisoner_006" - }, - { - "name": "prisoner_007" - }, - { - "name": "silver" - }, - { - "name": "syndie" - }, - { - "name": "idcluwne" - }, - { - "name": "idseniorengineer" - }, - { - "name": "idseniorresearcher" - }, - { - "name": "idseniorphysician" - }, - { - "name": "idseniorofficer" - }, - { - "name": "gold-inhand-left", - "directions": 4 - }, - { - "name": "gold-inhand-right", - "directions": 4 - }, - { - "name": "default-inhand-left", - "directions": 4 - }, - { - "name": "default-inhand-right", - "directions": 4 - }, - { - "name": "silver-inhand-left", - "directions": 4 - }, - { - "name": "silver-inhand-right", - "directions": 4 - }, - { - "name": "orange-inhand-left", - "directions": 4 - }, - { - "name": "orange-inhand-right", - "directions": 4 - }, - { - "name": "blue-inhand-left", - "directions": 4 - }, - { - "name": "blue-inhand-right", - "directions": 4 - } - ] + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/tgstation/tgstation // Icon Edit by FoxxoTrystan", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "default" + }, + { + "name": "centcom" + }, + { + "name": "gold" + }, + { + "name": "silver" + }, + { + "name": "rainbow" + }, + { + "name": "prisoner" + }, + { + "name": "flame" + }, + { + "name": "rpg" + }, + { + "name": "carp" + }, + { + "name": "black" + }, + { + "name": "department" + }, + { + "name": "departmenthead" + }, + { + "name": "subdepartment" + }, + { + "name": "captain" + }, + { + "name": "passenger" + }, + { + "name": "assistant" + }, + { + "name": "securityofficer" + }, + { + "name": "warden" + }, + { + "name": "stationengineer" + }, + { + "name": "medicaldoctor" + }, + { + "name": "paramedic" + }, + { + "name": "chemist" + }, + { + "name": "cargotechnician" + }, + { + "name": "shaftminer" + }, + { + "name": "scientist" + }, + { + "name": "clown" + }, + { + "name": "mime" + }, + { + "name": "chaplain" + }, + { + "name": "janitor" + }, + { + "name": "bartender" + }, + { + "name": "cook" + }, + { + "name": "botanist" + }, + { + "name": "curator" + }, + { + "name": "lawyer" + }, + { + "name": "headofpersonnel" + }, + { + "name": "cc" + }, + { + "name": "musician" + }, + { + "name": "death" + }, + { + "name": "roboticist" + }, + { + "name": "atmospherictechnician" + }, + { + "name": "syndicate" + }, + { + "name": "geneticist" + }, + { + "name": "zookeeper" + }, + { + "name": "detective" + }, + { + "name": "senior" + }, + { + "name": "mailcarrier" + }, + { + "name": "prisonguard" + }, + { + "name": "psychologist" + }, + { + "name": "boxer" + }, + { + "name": "gladiator" + }, + { + "name": "martialartist" + }, + { + "name": "gold-inhand-left", + "directions": 4 + }, + { + "name": "gold-inhand-right", + "directions": 4 + }, + { + "name": "default-inhand-left", + "directions": 4 + }, + { + "name": "default-inhand-right", + "directions": 4 + }, + { + "name": "silver-inhand-left", + "directions": 4 + }, + { + "name": "silver-inhand-right", + "directions": 4 + }, + { + "name": "orange-inhand-left", + "directions": 4 + }, + { + "name": "orange-inhand-right", + "directions": 4 + }, + { + "name": "blue-inhand-left", + "directions": 4 + }, + { + "name": "blue-inhand-right", + "directions": 4 + } + ] } diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/mime.png b/Resources/Textures/Objects/Misc/id_cards.rsi/mime.png new file mode 100644 index 00000000000..8368027151f Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/mime.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/musician.png b/Resources/Textures/Objects/Misc/id_cards.rsi/musician.png new file mode 100644 index 00000000000..1f1df6370ce Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/musician.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/orange.png b/Resources/Textures/Objects/Misc/id_cards.rsi/orange.png deleted file mode 100644 index a44da608ec0..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/orange.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/paramedic.png b/Resources/Textures/Objects/Misc/id_cards.rsi/paramedic.png new file mode 100644 index 00000000000..d1f48a111d3 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/paramedic.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/passenger.png b/Resources/Textures/Objects/Misc/id_cards.rsi/passenger.png new file mode 100644 index 00000000000..9f04507a9c5 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/passenger.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/pirate.png b/Resources/Textures/Objects/Misc/id_cards.rsi/pirate.png deleted file mode 100644 index d5670a71aa1..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/pirate.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner.png b/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner.png new file mode 100644 index 00000000000..ad8052cc01b Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner_001.png b/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner_001.png deleted file mode 100644 index 67dd3e88622..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner_001.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner_002.png b/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner_002.png deleted file mode 100644 index 004677ba4ab..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner_002.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner_003.png b/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner_003.png deleted file mode 100644 index 23c998f1507..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner_003.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner_004.png b/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner_004.png deleted file mode 100644 index c6e31412cc7..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner_004.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner_005.png b/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner_005.png deleted file mode 100644 index d1d29bb0558..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner_005.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner_006.png b/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner_006.png deleted file mode 100644 index 8b2305d7587..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner_006.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner_007.png b/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner_007.png deleted file mode 100644 index a5041faa88b..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/prisoner_007.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/prisonguard.png b/Resources/Textures/Objects/Misc/id_cards.rsi/prisonguard.png new file mode 100644 index 00000000000..f8570b2595c Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/prisonguard.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/psychologist.png b/Resources/Textures/Objects/Misc/id_cards.rsi/psychologist.png new file mode 100644 index 00000000000..d7d24d69470 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/psychologist.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/rainbow.png b/Resources/Textures/Objects/Misc/id_cards.rsi/rainbow.png new file mode 100644 index 00000000000..a0ccc1758c8 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/rainbow.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/roboticist.png b/Resources/Textures/Objects/Misc/id_cards.rsi/roboticist.png new file mode 100644 index 00000000000..ea7bda6c41e Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/roboticist.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/rpg.png b/Resources/Textures/Objects/Misc/id_cards.rsi/rpg.png new file mode 100644 index 00000000000..f6aa05e158b Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/rpg.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/scientist.png b/Resources/Textures/Objects/Misc/id_cards.rsi/scientist.png new file mode 100644 index 00000000000..7942e128b03 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/scientist.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/securityofficer.png b/Resources/Textures/Objects/Misc/id_cards.rsi/securityofficer.png new file mode 100644 index 00000000000..fffc7d2a065 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/securityofficer.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/senior.png b/Resources/Textures/Objects/Misc/id_cards.rsi/senior.png new file mode 100644 index 00000000000..28729bd5626 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/senior.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/shaftminer.png b/Resources/Textures/Objects/Misc/id_cards.rsi/shaftminer.png new file mode 100644 index 00000000000..4b42f5bbb67 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/shaftminer.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/silver.png b/Resources/Textures/Objects/Misc/id_cards.rsi/silver.png index b13153a246e..81d9626a727 100644 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/silver.png and b/Resources/Textures/Objects/Misc/id_cards.rsi/silver.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/stationengineer.png b/Resources/Textures/Objects/Misc/id_cards.rsi/stationengineer.png new file mode 100644 index 00000000000..c04b4761ea8 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/stationengineer.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/subdepartment.png b/Resources/Textures/Objects/Misc/id_cards.rsi/subdepartment.png new file mode 100644 index 00000000000..cc1547cbf73 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/subdepartment.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/syndicate.png b/Resources/Textures/Objects/Misc/id_cards.rsi/syndicate.png new file mode 100644 index 00000000000..5ed1c8ffe54 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/syndicate.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/syndie.png b/Resources/Textures/Objects/Misc/id_cards.rsi/syndie.png deleted file mode 100644 index 3d5cc6e384f..00000000000 Binary files a/Resources/Textures/Objects/Misc/id_cards.rsi/syndie.png and /dev/null differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/warden.png b/Resources/Textures/Objects/Misc/id_cards.rsi/warden.png new file mode 100644 index 00000000000..754ac67a883 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/warden.png differ diff --git a/Resources/Textures/Objects/Misc/id_cards.rsi/zookeeper.png b/Resources/Textures/Objects/Misc/id_cards.rsi/zookeeper.png new file mode 100644 index 00000000000..29b8dbca067 Binary files /dev/null and b/Resources/Textures/Objects/Misc/id_cards.rsi/zookeeper.png differ diff --git a/Resources/Textures/Objects/Tools/emag.rsi/icon.png b/Resources/Textures/Objects/Tools/emag.rsi/icon.png index 61c283cfd01..912fd6be821 100644 Binary files a/Resources/Textures/Objects/Tools/emag.rsi/icon.png and b/Resources/Textures/Objects/Tools/emag.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Tools/emag.rsi/meta.json b/Resources/Textures/Objects/Tools/emag.rsi/meta.json index 66fc62d663d..d90e37eb584 100644 --- a/Resources/Textures/Objects/Tools/emag.rsi/meta.json +++ b/Resources/Textures/Objects/Tools/emag.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation wiki at https://tgstation13.org/wiki/File:Emag.png, inhand sprites modified from tgstation at commit https://github.com/tgstation/tgstation/commit/d917f4c2a088419d5c3aec7656b7ff8cebd1822e", + "copyright": "Taken from https://github.com/tgstation/tgstation", "size": { "x": 32, "y": 32 @@ -16,7 +16,17 @@ "directions": 4 }, { - "name": "icon" + "name": "icon", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] } ] } diff --git a/Resources/Textures/Structures/Power/apc.rsi/base.png b/Resources/Textures/Structures/Power/apc.rsi/base.png index 2b42c54935a..ea2f17c062f 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/base.png and b/Resources/Textures/Structures/Power/apc.rsi/base.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/broken.png b/Resources/Textures/Structures/Power/apc.rsi/broken.png index 092694c371f..4bcd2475cdf 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/broken.png and b/Resources/Textures/Structures/Power/apc.rsi/broken.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel0-auto_off.png b/Resources/Textures/Structures/Power/apc.rsi/channel0-auto_off.png index ba84b7d6db5..0d181878fcf 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel0-auto_off.png and b/Resources/Textures/Structures/Power/apc.rsi/channel0-auto_off.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel0-auto_on.png b/Resources/Textures/Structures/Power/apc.rsi/channel0-auto_on.png index 6cce72f795f..c7a0d87ccc3 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel0-auto_on.png and b/Resources/Textures/Structures/Power/apc.rsi/channel0-auto_on.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel0-manual_off.png b/Resources/Textures/Structures/Power/apc.rsi/channel0-manual_off.png index 61ae057d508..4be0bbfb0bc 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel0-manual_off.png and b/Resources/Textures/Structures/Power/apc.rsi/channel0-manual_off.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel0-manual_on.png b/Resources/Textures/Structures/Power/apc.rsi/channel0-manual_on.png index 6cc48bd1a55..720dc4976ab 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel0-manual_on.png and b/Resources/Textures/Structures/Power/apc.rsi/channel0-manual_on.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel1-auto_off.png b/Resources/Textures/Structures/Power/apc.rsi/channel1-auto_off.png index b31bed6c6ba..7f0a13a7a4c 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel1-auto_off.png and b/Resources/Textures/Structures/Power/apc.rsi/channel1-auto_off.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel1-auto_on.png b/Resources/Textures/Structures/Power/apc.rsi/channel1-auto_on.png index 959a05cde08..87191be5207 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel1-auto_on.png and b/Resources/Textures/Structures/Power/apc.rsi/channel1-auto_on.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel1-manual_off.png b/Resources/Textures/Structures/Power/apc.rsi/channel1-manual_off.png index 3bb505ecb86..031213f74ad 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel1-manual_off.png and b/Resources/Textures/Structures/Power/apc.rsi/channel1-manual_off.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel1-manual_on.png b/Resources/Textures/Structures/Power/apc.rsi/channel1-manual_on.png index bd8b013310c..ac5f1c1befe 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel1-manual_on.png and b/Resources/Textures/Structures/Power/apc.rsi/channel1-manual_on.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel2-auto_off.png b/Resources/Textures/Structures/Power/apc.rsi/channel2-auto_off.png index 0cca8602208..ff8522d2c5a 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel2-auto_off.png and b/Resources/Textures/Structures/Power/apc.rsi/channel2-auto_off.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel2-auto_on.png b/Resources/Textures/Structures/Power/apc.rsi/channel2-auto_on.png index 56802dc0437..4e04387ed3d 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel2-auto_on.png and b/Resources/Textures/Structures/Power/apc.rsi/channel2-auto_on.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel2-manual_off.png b/Resources/Textures/Structures/Power/apc.rsi/channel2-manual_off.png index 5ac134cb54b..2f9802281e0 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel2-manual_off.png and b/Resources/Textures/Structures/Power/apc.rsi/channel2-manual_off.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel2-manual_on.png b/Resources/Textures/Structures/Power/apc.rsi/channel2-manual_on.png index 5ebec4feeeb..fb9e2180bb6 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel2-manual_on.png and b/Resources/Textures/Structures/Power/apc.rsi/channel2-manual_on.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/display-charging.png b/Resources/Textures/Structures/Power/apc.rsi/display-charging.png index 67e3b3df19b..d5e356d943e 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/display-charging.png and b/Resources/Textures/Structures/Power/apc.rsi/display-charging.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/display-full.png b/Resources/Textures/Structures/Power/apc.rsi/display-full.png index 1739853e2b7..4a9bd7ed643 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/display-full.png and b/Resources/Textures/Structures/Power/apc.rsi/display-full.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/display-lack.png b/Resources/Textures/Structures/Power/apc.rsi/display-lack.png index c4c103eeb96..d1d2df4858d 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/display-lack.png and b/Resources/Textures/Structures/Power/apc.rsi/display-lack.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/display-remote.png b/Resources/Textures/Structures/Power/apc.rsi/display-remote.png index be343a987b0..07265ab67de 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/display-remote.png and b/Resources/Textures/Structures/Power/apc.rsi/display-remote.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/emag-unlit.png b/Resources/Textures/Structures/Power/apc.rsi/emag-unlit.png index 2713c5506a2..77c2518e63d 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/emag-unlit.png and b/Resources/Textures/Structures/Power/apc.rsi/emag-unlit.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/frame.png b/Resources/Textures/Structures/Power/apc.rsi/frame.png index 7d3529f63f5..e4c9c1b31cf 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/frame.png and b/Resources/Textures/Structures/Power/apc.rsi/frame.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/meta.json b/Resources/Textures/Structures/Power/apc.rsi/meta.json index 82f78ccb875..867e5ce0ffd 100644 --- a/Resources/Textures/Structures/Power/apc.rsi/meta.json +++ b/Resources/Textures/Structures/Power/apc.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/9c7d509354ee030300f63c701da63c17928c3b3b and modified by Swept", + "copyright": "Taken from TauCetiClassic at commit https://github.com/TauCetiStation/TauCetiClassic/commit/fca7f2a0f9154c0c6c4efc2f8f58441fb9b34759", "size": { "x": 32, "y": 32 diff --git a/Resources/Textures/Structures/Power/apc.rsi/sparks-unlit.png b/Resources/Textures/Structures/Power/apc.rsi/sparks-unlit.png index 212fcb78bf8..f442757bea6 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/sparks-unlit.png and b/Resources/Textures/Structures/Power/apc.rsi/sparks-unlit.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/static.png b/Resources/Textures/Structures/Power/apc.rsi/static.png index 43089d0d811..a7137ec2f3a 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/static.png and b/Resources/Textures/Structures/Power/apc.rsi/static.png differ diff --git a/Resources/Textures/Structures/Power/power.rsi/meta.json b/Resources/Textures/Structures/Power/power.rsi/meta.json index 773a2b5a3e7..027655dd356 100644 --- a/Resources/Textures/Structures/Power/power.rsi/meta.json +++ b/Resources/Textures/Structures/Power/power.rsi/meta.json @@ -5,7 +5,7 @@ "y": 32 }, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation", + "copyright": "Taken from tgstation/paradise", "states": [ { "name": "eightdirwire" diff --git a/Resources/Textures/Structures/Power/power.rsi/storage.png b/Resources/Textures/Structures/Power/power.rsi/storage.png index 5f42ce89bc2..71e7cf91956 100644 Binary files a/Resources/Textures/Structures/Power/power.rsi/storage.png and b/Resources/Textures/Structures/Power/power.rsi/storage.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/meta.json b/Resources/Textures/Structures/Power/smes.rsi/meta.json index 2ca8d1fb226..4b4193ec726 100644 --- a/Resources/Textures/Structures/Power/smes.rsi/meta.json +++ b/Resources/Textures/Structures/Power/smes.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/9c7d509354ee030300f63c701da63c17928c3b3b and modified by Swept", + "copyright": "Taken from Paradise at https://github.com/McRamon/Paradise/blob/b727162ed9dead12de42be5c5b04872934a474e1/icons/obj/power.dmi", "size": { "x": 32, "y": 32 @@ -9,33 +9,9 @@ "states": [ { "name": "smes" - }, - { - "name": "static" - }, - { - "name": "smes-open" - }, - { - "name": "smes-oc0" }, { - "name": "smes-oc1", - "delays": [ - [ - 0.5, - 0.5 - ] - ] - }, - { - "name": "smes-oc2", - "delays": [ - [ - 0.5, - 0.5 - ] - ] + "name": "static" }, { "name": "smes-og1", @@ -62,16 +38,50 @@ "name": "smes-op0" }, { - "name": "smes-op1", + "name": "smes-op1" + }, + { + "name": "smes-op2" + }, + { + "name": "smes-oc1", "delays": [ [ - 1, - 1 + 0.3, + 0.3 ] ] }, { - "name": "smes-op2" + "name": "smes-oc2", + "delays": [ + [ + 0.3, + 0.3 + ] + ] + }, + { + "name": "smes-oc0", + "delays": [ + [ + 0.5, + 0.3 + ] + ] + }, + { + "name": "smes-open", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] } ] } diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-oc0.png b/Resources/Textures/Structures/Power/smes.rsi/smes-oc0.png index 5579432d3fe..9d62074f1d8 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-oc0.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-oc0.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-oc1.png b/Resources/Textures/Structures/Power/smes.rsi/smes-oc1.png index d624672613b..10f4c4678ed 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-oc1.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-oc1.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-oc2.png b/Resources/Textures/Structures/Power/smes.rsi/smes-oc2.png index d624672613b..10f4c4678ed 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-oc2.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-oc2.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-og1.png b/Resources/Textures/Structures/Power/smes.rsi/smes-og1.png index c65f011a070..472b013ce71 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-og1.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-og1.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-og2.png b/Resources/Textures/Structures/Power/smes.rsi/smes-og2.png index 00237504051..c2d3dbbc46e 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-og2.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-og2.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-og3.png b/Resources/Textures/Structures/Power/smes.rsi/smes-og3.png index 51df688e4a8..263d8e98f78 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-og3.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-og3.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-og4.png b/Resources/Textures/Structures/Power/smes.rsi/smes-og4.png index ceb3db1bc31..e31794f5c70 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-og4.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-og4.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-og5.png b/Resources/Textures/Structures/Power/smes.rsi/smes-og5.png index e6c0c8a2eac..26955f70a16 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-og5.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-og5.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-op0.png b/Resources/Textures/Structures/Power/smes.rsi/smes-op0.png index 573b5c404ff..ab0ae9e1145 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-op0.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-op0.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-op1.png b/Resources/Textures/Structures/Power/smes.rsi/smes-op1.png index f5c8e104894..58d8dbf1f5c 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-op1.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-op1.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-op2.png b/Resources/Textures/Structures/Power/smes.rsi/smes-op2.png index af560237f17..58d8dbf1f5c 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-op2.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-op2.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-open.png b/Resources/Textures/Structures/Power/smes.rsi/smes-open.png index 472e3fd7201..03868889f61 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-open.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-open.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes.png b/Resources/Textures/Structures/Power/smes.rsi/smes.png index ecfbc4cd58f..71e7cf91956 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes.png and b/Resources/Textures/Structures/Power/smes.rsi/smes.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/static.png b/Resources/Textures/Structures/Power/smes.rsi/static.png index 3e52b6c43e4..0fcc42db544 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/static.png and b/Resources/Textures/Structures/Power/smes.rsi/static.png differ diff --git a/Resources/Textures/Structures/Power/substation.rsi/charging.png b/Resources/Textures/Structures/Power/substation.rsi/charging.png index 538dc2b7a84..fdf01dbe8de 100644 Binary files a/Resources/Textures/Structures/Power/substation.rsi/charging.png and b/Resources/Textures/Structures/Power/substation.rsi/charging.png differ diff --git a/Resources/Textures/Structures/Power/substation.rsi/dead.png b/Resources/Textures/Structures/Power/substation.rsi/dead.png index 9fbff744ca7..ba6f81f1a1a 100644 Binary files a/Resources/Textures/Structures/Power/substation.rsi/dead.png and b/Resources/Textures/Structures/Power/substation.rsi/dead.png differ diff --git a/Resources/Textures/Structures/Power/substation.rsi/full.png b/Resources/Textures/Structures/Power/substation.rsi/full.png index d1797426699..42a670ff234 100644 Binary files a/Resources/Textures/Structures/Power/substation.rsi/full.png and b/Resources/Textures/Structures/Power/substation.rsi/full.png differ diff --git a/Resources/Textures/Structures/Power/substation.rsi/meta.json b/Resources/Textures/Structures/Power/substation.rsi/meta.json index 0125458641c..a2ade57116e 100644 --- a/Resources/Textures/Structures/Power/substation.rsi/meta.json +++ b/Resources/Textures/Structures/Power/substation.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Drawn by Ubaser.", + "copyright": "Taken from cev-eris at commit https://github.com/discordia-space/CEV-Eris/commit/b63634bc17efe2f09cf06ef0e9a90d24d37f6203, wall modified by Peptide90", "size": { "x": 32, "y": 32 diff --git a/Resources/Textures/Structures/Power/substation.rsi/screen.png b/Resources/Textures/Structures/Power/substation.rsi/screen.png index 60c922c53f6..c28bcbcedae 100644 Binary files a/Resources/Textures/Structures/Power/substation.rsi/screen.png and b/Resources/Textures/Structures/Power/substation.rsi/screen.png differ diff --git a/Resources/Textures/Structures/Power/substation.rsi/substation.png b/Resources/Textures/Structures/Power/substation.rsi/substation.png index b9d1eb18d8f..45524ad8b11 100644 Binary files a/Resources/Textures/Structures/Power/substation.rsi/substation.png and b/Resources/Textures/Structures/Power/substation.rsi/substation.png differ diff --git a/Resources/Textures/Structures/Power/substation.rsi/substation_static.png b/Resources/Textures/Structures/Power/substation.rsi/substation_static.png index 9d5b8598f4b..2a1de1a0661 100644 Binary files a/Resources/Textures/Structures/Power/substation.rsi/substation_static.png and b/Resources/Textures/Structures/Power/substation.rsi/substation_static.png differ diff --git a/Resources/Textures/Structures/Power/substation.rsi/substation_wall.png b/Resources/Textures/Structures/Power/substation.rsi/substation_wall.png index 155ced7128a..8e8ae3fe3c2 100644 Binary files a/Resources/Textures/Structures/Power/substation.rsi/substation_wall.png and b/Resources/Textures/Structures/Power/substation.rsi/substation_wall.png differ diff --git a/Resources/Textures/Structures/Power/substation.rsi/substation_wall_static.png b/Resources/Textures/Structures/Power/substation.rsi/substation_wall_static.png index e810e6a5a4a..ee24ff45e68 100644 Binary files a/Resources/Textures/Structures/Power/substation.rsi/substation_wall_static.png and b/Resources/Textures/Structures/Power/substation.rsi/substation_wall_static.png differ diff --git a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/base.png b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/base.png index 02e8764173f..0a2e1ae76b9 100644 Binary files a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/base.png and b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/base.png differ diff --git a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/broken.png b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/broken.png index 9d10428af8d..1565cdc86d7 100644 Binary files a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/broken.png and b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/broken.png differ diff --git a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/burned.png b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/burned.png index 160db7c5cbb..7e14e2c2b39 100644 Binary files a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/burned.png and b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/burned.png differ diff --git a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/empty.png b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/empty.png index 0f8f9478bd8..5ead53beb0e 100644 Binary files a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/empty.png and b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/empty.png differ diff --git a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/glow.png b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/glow.png index e1258d83dc3..50cc6725c71 100644 Binary files a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/glow.png and b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/glow.png differ diff --git a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/meta.json b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/meta.json index 4b8aa5fa2f0..be5f4a804b1 100644 --- a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/meta.json +++ b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/meta.json @@ -1,11 +1,11 @@ { "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/c6e3401f2e7e1e55c57060cdf956a98ef1fefc24", "size": { "x": 32, "y": 32 }, + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/discordia-space/CEV-Eris/blob/2b969adc2dfd3e9621bf3597c5cbffeb3ac8c9f0/icons/obj/lighting.dmi", "states": [ { "name": "broken", @@ -16,14 +16,14 @@ "directions": 4 }, { - "name": "base", + "name": "empty", "directions": 4 }, { - "name": "empty", + "name": "base", "directions": 4 }, - { + { "name": "glow", "directions": 4 } diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm0.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm0.png index 3b714153de9..fdc9376d67f 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm0.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm0.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm1.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm1.png index e7a23014888..d371695e129 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm1.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm1.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm2.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm2.png index 716536cfcb2..9d8640f85b0 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm2.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm2.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_b1.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_b1.png index fc185734afd..5fbc157750b 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_b1.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_b1.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_b2.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_b2.png index 0cdb0466062..38b22ccd815 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_b2.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_b2.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_bitem.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_bitem.png index 192c589f26c..6f1292bb058 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_bitem.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_bitem.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarmp.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarmp.png index 793babbbe6a..0b3192122be 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarmp.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarmp.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarmx.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarmx.png index 0f3e60bc0e8..61ecb87ff48 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarmx.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarmx.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire0.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire0.png index aa9559b7dce..278e5cf03b2 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire0.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire0.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_0.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_0.png index 39d4e989710..621410d043e 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_0.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_0.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_1.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_1.png index 765fdc6e594..fb775d3098b 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_1.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_1.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_3.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_3.png index ad74165ec40..71b96f2130d 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_3.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_3.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b0.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b0.png index cc554c73944..cfe596102d2 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b0.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b0.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b1.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b1.png index f732817d47e..1a620adc144 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b1.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b1.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b2.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b2.png index d862c40a4bc..c199a7ff31e 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b2.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b2.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_bitem.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_bitem.png index cc2a57c4956..5be7e11fc85 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_bitem.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_bitem.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_emagged.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_emagged.png index 310bb89d41b..bafb4249565 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_emagged.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_emagged.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_off.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_off.png index 8695c8a35dc..3eb61db8b6c 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_off.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_off.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_on.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_on.png index a98566070e5..ce3697456ff 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_on.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_on.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/firex.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/firex.png index 5ac3fad6af8..dd31be02f80 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/firex.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/firex.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/meta.json b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/meta.json index 62e0a281bf0..7484be2ffed 100644 --- a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/meta.json +++ b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/meta.json @@ -1,48 +1,20 @@ { "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from TauCetiClassic at commit https://github.com/TauCetiStation/TauCetiClassic/commit/b7ac5798ae0d411b0cdeaf7efbc4ac86d24b4634, fire_emagged.png edited by github:Morb0", "size": { "x": 32, "y": 32 }, - "copyright": "Taken from tgstation", - "license": "CC-BY-SA-3.0", "states": [ { "name": "alarm0", "directions": 4, "delays": [ - [ - 0.5, - 0.1, - 0.1, - 1.0, - 0.2, - 0.1 - ], - [ - 0.5, - 0.1, - 0.1, - 1.0, - 0.2, - 0.1 - ], - [ - 0.5, - 0.1, - 0.1, - 1.0, - 0.2, - 0.1 - ], - [ - 0.5, - 0.1, - 0.1, - 1.0, - 0.2, - 0.1 - ] + [2.8, 2.8], + [2.8, 2.8], + [2.8, 2.8], + [2.8, 2.8] ] }, { @@ -50,20 +22,20 @@ "directions": 4, "delays": [ [ - 0.5, - 0.5 + 0.6, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2, 0.2, 0.2, 0.6, 0.6, 0.6 ], [ - 0.5, - 0.5 + 0.6, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2, 0.2, 0.2, 0.6, 0.6, 0.6 ], [ - 0.5, - 0.5 + 0.6, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2, 0.2, 0.2, 0.6, 0.6, 0.6 ], [ - 0.5, - 0.5 + 0.6, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2, 0.2, 0.2, 0.6, 0.6, 0.6 ] ] }, @@ -72,20 +44,20 @@ "directions": 4, "delays": [ [ - 0.5, - 0.5 + 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.4, 0.4, 0.4, + 0.4, 0.4 ], [ - 0.5, - 0.5 + 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.4, 0.4, 0.4, + 0.4, 0.4 ], [ - 0.5, - 0.5 + 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.4, 0.4, 0.4, + 0.4, 0.4 ], [ - 0.5, - 0.5 + 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.4, 0.4, 0.4, + 0.4, 0.4 ] ] }, @@ -98,7 +70,8 @@ "directions": 4 }, { - "name": "alarm_bitem" + "name": "alarm_bitem", + "directions": 1 }, { "name": "alarmp", @@ -109,17 +82,14 @@ "directions": 4 }, { - "name": "auth_off" + "name": "auth_off", + "directions": 1, + "delays": [[1]] }, { "name": "auth_on", "directions": 1, - "delays": [ - [ - 0.1, - 0.1 - ] - ] + "delays": [[0.1, 0.1]] }, { "name": "fire0", @@ -137,44 +107,20 @@ "name": "fire_2", "directions": 4, "delays": [ - [ - 0.5, - 0.5 - ], - [ - 0.5, - 0.5 - ], - [ - 0.5, - 0.5 - ], - [ - 0.5, - 0.5 - ] + [0.5, 0.5], + [0.5, 0.5], + [0.5, 0.5], + [0.5, 0.5] ] }, { "name": "fire_3", "directions": 4, "delays": [ - [ - 0.5, - 0.5 - ], - [ - 0.5, - 0.5 - ], - [ - 0.5, - 0.5 - ], - [ - 0.5, - 0.5 - ] + [0.3, 0.3], + [0.3, 0.3], + [0.3, 0.3], + [0.3, 0.3] ] }, { @@ -190,67 +136,21 @@ "directions": 4 }, { - "name": "fire_bitem" + "name": "fire_bitem", + "directions": 1 }, { - "name": "fire_detected", + "name": "fire_emagged", "directions": 4, "delays": [ - [ - 0.4, - 0.4 - ], - [ - 0.4, - 0.4 - ], - [ - 0.4, - 0.4 - ], - [ - 0.4, - 0.4 - ] + [0.3, 0.3], + [0.3, 0.3], + [0.3, 0.3], + [0.3, 0.3] ] }, { - "name": "fire_emagged", - "directions": 4, - "delays": [ - [ - 0.5, - 0.5, - 0.3, - 0.5, - 0.2, - 0.5 - ], - [ - 0.5, - 0.5, - 0.3, - 0.5, - 0.2, - 0.5 - ], - [ - 0.5, - 0.5, - 0.3, - 0.5, - 0.2, - 0.5 - ], - [ - 0.5, - 0.5, - 0.3, - 0.5, - 0.2, - 0.5 - ] - ] + "name": "fire_detected" }, { "name": "fire_off", @@ -260,27 +160,14 @@ "name": "fire_on", "directions": 4, "delays": [ - [ - 0.5, - 0.5 - ], - [ - 0.5, - 0.5 - ], - [ - 0.5, - 0.5 - ], - [ - 0.5, - 0.5 - ] + [0.2, 0.2, 0.2, 0.2, 0.2, 0.2], + [0.2, 0.2, 0.2, 0.2, 0.2, 0.2], + [0.2, 0.2, 0.2, 0.2, 0.2, 0.2], + [0.2, 0.2, 0.2, 0.2, 0.2, 0.2] ] }, { - "name": "fire_overlay", - "directions": 4 + "name": "fire_overlay" }, { "name": "firex", diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/camera.png b/Resources/Textures/Structures/Wallmounts/camera.rsi/camera.png index 19481d55a0d..f3054b57ed3 100644 Binary files a/Resources/Textures/Structures/Wallmounts/camera.rsi/camera.png and b/Resources/Textures/Structures/Wallmounts/camera.rsi/camera.png differ diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_assembly.png b/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_assembly.png index 44d8460f5fc..404e4dad197 100644 Binary files a/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_assembly.png and b/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_assembly.png differ diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_emp.png b/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_emp.png index 6a7c1a24c51..59c7f453ebc 100644 Binary files a/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_emp.png and b/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_emp.png differ diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_in_use.png b/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_in_use.png index 42a6a6e098e..3ed85a4a6b2 100644 Binary files a/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_in_use.png and b/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_in_use.png differ diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_off.png b/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_off.png index 7fa16ed3fdd..487a2602aa5 100644 Binary files a/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_off.png and b/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_off.png differ diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/cameracase.png b/Resources/Textures/Structures/Wallmounts/camera.rsi/cameracase.png index ac3f200d1fe..f93042f15f2 100644 Binary files a/Resources/Textures/Structures/Wallmounts/camera.rsi/cameracase.png and b/Resources/Textures/Structures/Wallmounts/camera.rsi/cameracase.png differ diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/meta.json b/Resources/Textures/Structures/Wallmounts/camera.rsi/meta.json index b8cedc6db63..95d2b24378e 100644 --- a/Resources/Textures/Structures/Wallmounts/camera.rsi/meta.json +++ b/Resources/Textures/Structures/Wallmounts/camera.rsi/meta.json @@ -1,73 +1,490 @@ { - "version": 1, - "size": { - "x": 32, - "y": 32 + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from TauCetiClassic at commit https://github.com/TauCetiStation/TauCetiClassic/commit/f878e95210d81e1328b023feb96ec0d0b6113d8c", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "camera", + "directions": 8, + "delays": [ + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25, + 0.25 + ] + ] }, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from /tg/station at https://github.com/tgstation/tgstation/commit/6bfe3b2e4fcbcdac9159dc4f0327a82ddf05ba7bi", - "states": [ - { - "name": "camera", - "directions": 1, - "delays": [ - [ 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3 ] - ] - }, - { - "name": "camera_assembly", - "directions": 1 - }, - { - "name": "camera_emp", - "directions": 1, - "delays": [ - [ 0.2, 0.2, 0.1, 0.1 ] - ] - }, - { - "name": "camera_in_use", - "directions": 1, - "delays": [ - [ 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3 ] - ] - }, - { - "name": "camera_off", - "directions": 1 - }, - { - "name": "cameracase", - "directions": 1 - }, - { - "name": "xraycamera", - "directions": 1, - "delays": [ - [ 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3 ] - ] - }, - { - "name": "xraycamera_assembly", - "directions": 1 - }, - { - "name": "xraycamera_emp", - "directions": 1, - "delays": [ - [ 0.2, 0.2, 0.1, 0.1 ] - ] - }, - { - "name": "xraycamera_in_use", - "directions": 1, - "delays": [ - [ 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3 ] - ] - }, - { - "name": "xraycamera_off", - "directions": 1 - } - ] -} \ No newline at end of file + { + "name": "camera_in_use", + "directions": 8, + "delays": [ + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ] + ] + }, + { + "name": "camera_off", + "directions": 8 + }, + { + "name": "camera_emp", + "directions": 8, + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "camera_assembly", + "directions": 8 + }, + { + "name": "xraycamera", + "directions": 8, + "delays": [ + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ] + ] + }, + { + "name": "xraycamera_emp", + "directions": 8, + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "xraycamera_off", + "directions": 8 + }, + { + "name": "xraycamera_assembly", + "directions": 8 + }, + { + "name": "cameracase" + }, + { + "name": "xraycamera_in_use", + "directions": 8, + "delays": [ + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ] + ] + } + ] +} diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera.png b/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera.png index 31d9892d9f6..b543be5d7b3 100644 Binary files a/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera.png and b/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera.png differ diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_assembly.png b/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_assembly.png index d2f690d3c11..5dfddb08f7d 100644 Binary files a/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_assembly.png and b/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_assembly.png differ diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_emp.png b/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_emp.png index af6f3e2ceca..434dbd575b6 100644 Binary files a/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_emp.png and b/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_emp.png differ diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_in_use.png b/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_in_use.png index 96dc134c7f2..dadc30eba7c 100644 Binary files a/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_in_use.png and b/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_in_use.png differ diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_off.png b/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_off.png index 9b8a1aed798..487a2602aa5 100644 Binary files a/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_off.png and b/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_off.png differ diff --git a/Resources/Textures/Structures/Wallmounts/intercom.rsi/base.png b/Resources/Textures/Structures/Wallmounts/intercom.rsi/base.png index 787af3f5387..7ddea57eded 100644 Binary files a/Resources/Textures/Structures/Wallmounts/intercom.rsi/base.png and b/Resources/Textures/Structures/Wallmounts/intercom.rsi/base.png differ diff --git a/Resources/Textures/Structures/Wallmounts/intercom.rsi/broadcasting.png b/Resources/Textures/Structures/Wallmounts/intercom.rsi/broadcasting.png index 0566c70e35c..fb01e708619 100644 Binary files a/Resources/Textures/Structures/Wallmounts/intercom.rsi/broadcasting.png and b/Resources/Textures/Structures/Wallmounts/intercom.rsi/broadcasting.png differ diff --git a/Resources/Textures/Structures/Wallmounts/intercom.rsi/build.png b/Resources/Textures/Structures/Wallmounts/intercom.rsi/build.png index cfd5d5fffa0..21fc9a1bad5 100644 Binary files a/Resources/Textures/Structures/Wallmounts/intercom.rsi/build.png and b/Resources/Textures/Structures/Wallmounts/intercom.rsi/build.png differ diff --git a/Resources/Textures/Structures/Wallmounts/intercom.rsi/meta.json b/Resources/Textures/Structures/Wallmounts/intercom.rsi/meta.json index f5a9d7b89c2..d4440c99a04 100644 --- a/Resources/Textures/Structures/Wallmounts/intercom.rsi/meta.json +++ b/Resources/Textures/Structures/Wallmounts/intercom.rsi/meta.json @@ -5,7 +5,7 @@ "y": 32 }, "license": "CC-BY-SA-3.0", - "copyright": "Taken from /tg/station at https://github.com/tgstation/tgstation/commit/6bfe3b2e4fcbcdac9159dc4f0327a82ddf05ba7bi", + "copyright": "Taken from https://github.com/Skyrat-SS13/Skyrat-tg/blob/6e7197f550aac62a165c0a8c6b0835de19342623/modular_skyrat/modules/aesthetics/intercom/icons/intercom.dmi & build state from DenLemp#2965", "states": [ { "name": "base", diff --git a/Resources/Textures/Structures/Wallmounts/intercom.rsi/unshaded.png b/Resources/Textures/Structures/Wallmounts/intercom.rsi/unshaded.png index 7b0bb630722..9c4c3f199e6 100644 Binary files a/Resources/Textures/Structures/Wallmounts/intercom.rsi/unshaded.png and b/Resources/Textures/Structures/Wallmounts/intercom.rsi/unshaded.png differ diff --git a/Resources/keybinds.yml b/Resources/keybinds.yml index 22130f60832..39de62dbf60 100644 --- a/Resources/keybinds.yml +++ b/Resources/keybinds.yml @@ -258,6 +258,9 @@ binds: - function: OfferItem type: State key: F +- function: ToggleStanding + type: State + key: R - function: ShowDebugConsole type: State key: Tilde diff --git a/RobustToolbox b/RobustToolbox index 25bbb21dc86..eb638099999 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit 25bbb21dc868b4e0b43b6d28e899710891b35868 +Subproject commit eb638099999dce3a43d90772ca976ae010d649c0 diff --git a/SpaceStation14.sln b/SpaceStation14.sln index e0cb455a6db..bcd013b5981 100644 --- a/SpaceStation14.sln +++ b/SpaceStation14.sln @@ -62,7 +62,6 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{806ED41A-411B-4B3B-BEB6-DEC6DCA4C205}" ProjectSection(SolutionItems) = preProject Tools\generate_hashes.ps1 = Tools\generate_hashes.ps1 - Tools\gen_build_info.py = Tools\gen_build_info.py EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Robust.Shared.Scripting", "RobustToolbox\Robust.Shared.Scripting\Robust.Shared.Scripting.csproj", "{41B450C0-A361-4CD7-8121-7072B8995CFC}" diff --git a/Tools/gen_build_info.py b/Tools/gen_build_info.py deleted file mode 100755 index 83717bebed1..00000000000 --- a/Tools/gen_build_info.py +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/env python3 - -# Generates build info and injects it into the server zip files. - -import codecs -import hashlib -import io -import json -import os -import subprocess -from zipfile import ZipFile, ZIP_DEFLATED - -FILE = "SS14.Client.zip" - -SERVER_FILES = [ - "SS14.Server_linux-x64.zip", - "SS14.Server_linux-arm64.zip", - "SS14.Server_win-x64.zip", - "SS14.Server_osx-x64.zip" -] - -VERSION = os.environ['GITHUB_SHA'] -FORK_ID = "floofstation" -BUILD_URL = f"https://builds.delta-v.org/{{FORK_ID}}/builds/{{FORK_VERSION}}/{FILE}" -MANIFEST_URL = f"https://cdn.delta-v.org/version/{{FORK_VERSION}}/manifest" -MANIFEST_DOWNLOAD_URL = f"https://cdn.delta-v.org/version/{{FORK_VERSION}}/download" - -def main() -> None: - client_file = os.path.join("release", FILE) - manifest = generate_build_json(client_file) - - for server in SERVER_FILES: - inject_manifest(os.path.join("release", server), manifest) - - -def inject_manifest(zip_path: str, manifest: str) -> None: - with ZipFile(zip_path, "a", compression=ZIP_DEFLATED) as z: - z.writestr("build.json", manifest) - - -def generate_build_json(file: str) -> str: - # Env variables set by Jenkins. - - hash = sha256_file(file) - engine_version = get_engine_version() - manifest_hash = generate_manifest_hash(file) - - return json.dumps({ - "download": BUILD_URL, - "hash": hash, - "version": VERSION, - "fork_id": FORK_ID, - "engine_version": engine_version, - "manifest_url": MANIFEST_URL, - "manifest_download_url": MANIFEST_DOWNLOAD_URL, - "manifest_hash": manifest_hash - }) - -def generate_manifest_hash(file: str) -> str: - zip = ZipFile(file) - infos = zip.infolist() - infos.sort(key=lambda i: i.filename) - - bytesIO = io.BytesIO() - writer = codecs.getwriter("UTF-8")(bytesIO) - writer.write("Robust Content Manifest 1\n") - - for info in infos: - if info.filename[-1] == "/": - continue - - bytes = zip.read(info) - hash = hashlib.blake2b(bytes, digest_size=32).hexdigest().upper() - writer.write(f"{hash} {info.filename}\n") - - manifestHash = hashlib.blake2b(bytesIO.getbuffer(), digest_size=32) - - return manifestHash.hexdigest().upper() - -def get_engine_version() -> str: - proc = subprocess.run(["git", "describe","--tags", "--abbrev=0"], stdout=subprocess.PIPE, cwd="RobustToolbox", check=True, encoding="UTF-8") - tag = proc.stdout.strip() - assert tag.startswith("v") - return tag[1:] # Cut off v prefix. - - -def sha256_file(path: str) -> str: - with open(path, "rb") as f: - h = hashlib.sha256() - for b in iter(lambda: f.read(4096), b""): - h.update(b) - - return h.hexdigest() - -if __name__ == '__main__': - main() diff --git a/Tools/publish_github_artifact.py b/Tools/publish_github_artifact.py new file mode 100755 index 00000000000..867c40f0949 --- /dev/null +++ b/Tools/publish_github_artifact.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 + +import requests +import os +import subprocess + +GITHUB_TOKEN = os.environ["GITHUB_TOKEN"] +PUBLISH_TOKEN = os.environ["PUBLISH_TOKEN"] +ARTIFACT_ID = os.environ["ARTIFACT_ID"] +GITHUB_REPOSITORY = os.environ["GITHUB_REPOSITORY"] +VERSION = os.environ['GITHUB_SHA'] + +# +# CONFIGURATION PARAMETERS +# Forks should change these to publish to their own infrastructure. +# +ROBUST_CDN_URL = "http://floofstation.com:27690/" +FORK_ID = "floofstation-main" + +def main(): + print("Fetching artifact URL from API...") + artifact_url = get_artifact_url() + print(f"Artifact URL is {artifact_url}, publishing to Robust.Cdn") + + data = { + "version": VERSION, + "engineVersion": get_engine_version(), + "archive": artifact_url + } + headers = { + "Authorization": f"Bearer {PUBLISH_TOKEN}", + "Content-Type": "application/json" + } + resp = requests.post(f"{ROBUST_CDN_URL}fork/{FORK_ID}/publish", json=data, headers=headers) + resp.raise_for_status() + print("Publish succeeded!") + +def get_artifact_url() -> str: + headers = { + "Authorization": f"Bearer {GITHUB_TOKEN}", + "X-GitHub-Api-Version": "2022-11-28" + } + resp = requests.get(f"https://api.github.com/repos/{GITHUB_REPOSITORY}/actions/artifacts/{ARTIFACT_ID}/zip", allow_redirects=False, headers=headers) + resp.raise_for_status() + + return resp.headers["Location"] + +def get_engine_version() -> str: + proc = subprocess.run(["git", "describe","--tags", "--abbrev=0"], stdout=subprocess.PIPE, cwd="RobustToolbox", check=True, encoding="UTF-8") + tag = proc.stdout.strip() + assert tag.startswith("v") + return tag[1:] # Cut off v prefix. + + +if __name__ == '__main__': + main()