diff --git a/BuildFiles/Linux/SS14.Launcher b/BuildFiles/Linux/SS14.Launcher
new file mode 100755
index 0000000000..96d0722021
--- /dev/null
+++ b/BuildFiles/Linux/SS14.Launcher
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+cd "$(dirname "$0")"
+
+exec mono bin/SS14.Launcher.exe
diff --git a/BuildFiles/Mac/Space Station 14 Launcher.app/Contents/Info.plist b/BuildFiles/Mac/Space Station 14 Launcher.app/Contents/Info.plist
new file mode 100644
index 0000000000..d5e34b0787
--- /dev/null
+++ b/BuildFiles/Mac/Space Station 14 Launcher.app/Contents/Info.plist
@@ -0,0 +1,20 @@
+
+
+
+
+ CFBundleName
+ SS14L
+ CFBundleDisplayName
+ Space Station 14 Launcher
+ CFBundleExecutable
+ SS14
+
+ CFBundleIconFile
+ ss14
+
+
diff --git a/BuildFiles/Mac/Space Station 14 Launcher.app/Contents/MacOS/SS14 b/BuildFiles/Mac/Space Station 14 Launcher.app/Contents/MacOS/SS14
new file mode 100755
index 0000000000..57abef5dc5
--- /dev/null
+++ b/BuildFiles/Mac/Space Station 14 Launcher.app/Contents/MacOS/SS14
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# cd to file containing script or something?
+BASEDIR=$(dirname "$0")
+echo "$BASEDIR"
+cd "$BASEDIR"
+
+exec /Library/Frameworks/Mono.framework/Versions/Current/Commands/mono ../Resources/SS14.Launcher.exe
diff --git a/BuildFiles/Mac/Space Station 14 Launcher.app/Contents/Resources/ss14.icns b/BuildFiles/Mac/Space Station 14 Launcher.app/Contents/Resources/ss14.icns
new file mode 100644
index 0000000000..ea22dc64c7
Binary files /dev/null and b/BuildFiles/Mac/Space Station 14 Launcher.app/Contents/Resources/ss14.icns differ
diff --git a/BuildFiles/Windows/launch.bat b/BuildFiles/Windows/launch.bat
deleted file mode 100644
index 12fea13879..0000000000
--- a/BuildFiles/Windows/launch.bat
+++ /dev/null
@@ -1 +0,0 @@
-call Godot\godot.windows.tools.64.mono.exe --path SS14.Client.Godot
diff --git a/BuildFiles/Windows/run_me.bat b/BuildFiles/Windows/run_me.bat
new file mode 100644
index 0000000000..9b35a18cbe
--- /dev/null
+++ b/BuildFiles/Windows/run_me.bat
@@ -0,0 +1 @@
+call bin\SS14.Launcher.exe
diff --git a/Content.Client/Chat/ChatManager.cs b/Content.Client/Chat/ChatManager.cs
index a596184cd7..585f61862f 100644
--- a/Content.Client/Chat/ChatManager.cs
+++ b/Content.Client/Chat/ChatManager.cs
@@ -1,23 +1,49 @@
using System.Collections.Generic;
using Content.Client.Interfaces.Chat;
using Content.Shared.Chat;
+using Robust.Client;
using Robust.Client.Console;
+using Robust.Client.Interfaces.Graphics.ClientEye;
+using Robust.Client.Interfaces.UserInterface;
+using Robust.Client.UserInterface;
+using Robust.Client.UserInterface.Controls;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
-using Robust.Client.UserInterface.Controls;
namespace Content.Client.Chat
{
internal sealed class ChatManager : IChatManager
{
+ ///
+ /// The max amount of chars allowed to fit in a single speech bubble.
+ ///
+ private const int SingleBubbleCharLimit = 100;
+
+ ///
+ /// Base queue delay each speech bubble has.
+ ///
+ private const float BubbleDelayBase = 0.2f;
+
+ ///
+ /// Factor multiplied by speech bubble char length to add to delay.
+ ///
+ private const float BubbleDelayFactor = 0.8f / SingleBubbleCharLimit;
+
+ ///
+ /// The max amount of speech bubbles over a single entity at once.
+ ///
+ private const int SpeechBubbleCap = 4;
+
private const char ConCmdSlash = '/';
private const char OOCAlias = '[';
private const char MeAlias = '@';
- public List filteredHistory = new List();
+ private readonly List filteredHistory = new List();
// Filter Button States
private bool _allState;
@@ -30,13 +56,76 @@ namespace Content.Client.Chat
#pragma warning disable 649
[Dependency] private readonly IClientNetManager _netManager;
[Dependency] private readonly IClientConsole _console;
+ [Dependency] private readonly IEntityManager _entityManager;
+ [Dependency] private readonly IEyeManager _eyeManager;
+ [Dependency] private readonly IUserInterfaceManager _userInterfaceManager;
#pragma warning restore 649
private ChatBox _currentChatBox;
+ private Control _speechBubbleRoot;
+
+ ///
+ /// Speech bubbles that are currently visible on screen.
+ /// We track them to push them up when new ones get added.
+ ///
+ private readonly Dictionary> _activeSpeechBubbles =
+ new Dictionary>();
+
+ ///
+ /// Speech bubbles that are to-be-sent because of the "rate limit" they have.
+ ///
+ private readonly Dictionary _queuedSpeechBubbles
+ = new Dictionary();
public void Initialize()
{
_netManager.RegisterNetMessage(MsgChatMessage.NAME, _onChatMessage);
+
+ _speechBubbleRoot = new Control
+ {
+ MouseFilter = Control.MouseFilterMode.Ignore
+ };
+ _speechBubbleRoot.SetAnchorPreset(Control.LayoutPreset.Wide);
+ _userInterfaceManager.StateRoot.AddChild(_speechBubbleRoot);
+ _speechBubbleRoot.SetPositionFirst();
+ }
+
+ public void FrameUpdate(RenderFrameEventArgs delta)
+ {
+ // Update queued speech bubbles.
+ if (_queuedSpeechBubbles.Count == 0)
+ {
+ return;
+ }
+
+ foreach (var (entityUid, queueData) in _queuedSpeechBubbles.ShallowClone())
+ {
+ if (!_entityManager.TryGetEntity(entityUid, out var entity))
+ {
+ _queuedSpeechBubbles.Remove(entityUid);
+ continue;
+ }
+
+ queueData.TimeLeft -= delta.Elapsed;
+ if (queueData.TimeLeft > 0)
+ {
+ continue;
+ }
+
+ if (queueData.MessageQueue.Count == 0)
+ {
+ _queuedSpeechBubbles.Remove(entityUid);
+ continue;
+ }
+
+ var msg = queueData.MessageQueue.Dequeue();
+
+ queueData.TimeLeft += BubbleDelayBase + msg.Length * BubbleDelayFactor;
+
+ // We keep the queue around while it has 0 items. This allows us to keep the timer.
+ // When the timer hits 0 and there's no messages left, THEN we can clear it up.
+ CreateSpeechBubble(entity, msg);
+ }
}
public void SetChatBox(ChatBox chatBox)
@@ -60,6 +149,19 @@ namespace Content.Client.Chat
_currentChatBox.OOCButton.Pressed = !_oocState;
}
+ public void RemoveSpeechBubble(EntityUid entityUid, SpeechBubble bubble)
+ {
+ bubble.Dispose();
+
+ var list = _activeSpeechBubbles[entityUid];
+ list.Remove(bubble);
+
+ if (list.Count == 0)
+ {
+ _activeSpeechBubbles.Remove(entityUid);
+ }
+ }
+
private void WriteChatMessage(StoredChatMessage message)
{
Logger.Debug($"{message.Channel}: {message.Message}");
@@ -88,7 +190,6 @@ namespace Content.Client.Chat
}
_currentChatBox?.AddLine(messageText, message.Channel, color);
-
}
private void _onChatBoxTextSubmitted(ChatBox chatBox, string text)
@@ -185,15 +286,126 @@ namespace Content.Client.Chat
Logger.Debug($"{msg.Channel}: {msg.Message}");
// Log all incoming chat to repopulate when filter is un-toggled
- StoredChatMessage storedMessage = new StoredChatMessage(msg);
+ var storedMessage = new StoredChatMessage(msg);
filteredHistory.Add(storedMessage);
WriteChatMessage(storedMessage);
+
+ // Local messages that have an entity attached get a speech bubble.
+ if (msg.Channel == ChatChannel.Local && msg.SenderEntity != default)
+ {
+ AddSpeechBubble(msg);
+ }
+ }
+
+ private void AddSpeechBubble(MsgChatMessage msg)
+ {
+ if (!_entityManager.TryGetEntity(msg.SenderEntity, out var entity))
+ {
+ Logger.WarningS("chat", "Got local chat message with invalid sender entity: {0}", msg.SenderEntity);
+ return;
+ }
+
+ // Split message into words separated by spaces.
+ var words = msg.Message.Split(' ');
+ var messages = new List();
+ var currentBuffer = new List();
+
+ // Really shoddy way to approximate word length.
+ // Yes, I am aware of all the crimes here.
+ // TODO: Improve this to use actual glyph width etc..
+ var currentWordLength = 0;
+ foreach (var word in words)
+ {
+ // +1 for the space.
+ currentWordLength += word.Length + 1;
+
+ if (currentWordLength > SingleBubbleCharLimit)
+ {
+ // Too long for the current speech bubble, flush it.
+ messages.Add(string.Join(" ", currentBuffer));
+ currentBuffer.Clear();
+
+ currentWordLength = word.Length;
+
+ if (currentWordLength > SingleBubbleCharLimit)
+ {
+ // Word is STILL too long.
+ // Truncate it with an ellipse.
+ messages.Add($"{word.Substring(0, SingleBubbleCharLimit - 3)}...");
+ currentWordLength = 0;
+ continue;
+ }
+ }
+
+ currentBuffer.Add(word);
+ }
+
+ if (currentBuffer.Count != 0)
+ {
+ // Don't forget the last bubble.
+ messages.Add(string.Join(" ", currentBuffer));
+ }
+
+ foreach (var message in messages)
+ {
+ EnqueueSpeechBubble(entity, message);
+ }
+ }
+
+ private void EnqueueSpeechBubble(IEntity entity, string contents)
+ {
+ if (!_queuedSpeechBubbles.TryGetValue(entity.Uid, out var queueData))
+ {
+ queueData = new SpeechBubbleQueueData();
+ _queuedSpeechBubbles.Add(entity.Uid, queueData);
+ }
+
+ queueData.MessageQueue.Enqueue(contents);
+ }
+
+ private void CreateSpeechBubble(IEntity entity, string contents)
+ {
+ var bubble = new SpeechBubble(contents, entity, _eyeManager, this);
+
+ if (_activeSpeechBubbles.TryGetValue(entity.Uid, out var existing))
+ {
+ // Push up existing bubbles above the mob's head.
+ foreach (var existingBubble in existing)
+ {
+ existingBubble.VerticalOffset += bubble.ContentHeight;
+ }
+ }
+ else
+ {
+ existing = new List();
+ _activeSpeechBubbles.Add(entity.Uid, existing);
+ }
+
+ existing.Add(bubble);
+ _speechBubbleRoot.AddChild(bubble);
+
+ if (existing.Count > SpeechBubbleCap)
+ {
+ // Get the oldest to start fading fast.
+ var last = existing[0];
+ last.FadeNow();
+ }
}
private bool IsFiltered(ChatChannel channel)
{
- // _ALLstate works as inverter.
+ // _allState works as inverter.
return _allState ^ _filteredChannels.HasFlag(channel);
}
+
+ private sealed class SpeechBubbleQueueData
+ {
+ ///
+ /// Time left until the next speech bubble can appear.
+ ///
+ public float TimeLeft { get; set; }
+
+ public Queue MessageQueue { get; } = new Queue();
+ }
}
}
diff --git a/Content.Client/Chat/SpeechBubble.cs b/Content.Client/Chat/SpeechBubble.cs
new file mode 100644
index 0000000000..0815e283b7
--- /dev/null
+++ b/Content.Client/Chat/SpeechBubble.cs
@@ -0,0 +1,137 @@
+using Content.Client.Interfaces.Chat;
+using Robust.Client;
+using Robust.Client.Interfaces.Graphics.ClientEye;
+using Robust.Client.UserInterface;
+using Robust.Client.UserInterface.Controls;
+using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.Maths;
+using Robust.Shared.Timers;
+
+namespace Content.Client.Chat
+{
+ public class SpeechBubble : Control
+ {
+ ///
+ /// The total time a speech bubble stays on screen.
+ ///
+ private const float TotalTime = 4;
+
+ ///
+ /// The amount of time at the end of the bubble's life at which it starts fading.
+ ///
+ private const float FadeTime = 0.25f;
+
+ ///
+ /// The distance in world space to offset the speech bubble from the center of the entity.
+ /// i.e. greater -> higher above the mob's head.
+ ///
+ private const float EntityVerticalOffset = 0.5f;
+
+ private readonly IEyeManager _eyeManager;
+ private readonly IEntity _senderEntity;
+ private readonly IChatManager _chatManager;
+
+ private Control _panel;
+
+ private float _timeLeft = TotalTime;
+
+ public float VerticalOffset { get; set; }
+ private float _verticalOffsetAchieved;
+
+ public float ContentHeight { get; }
+
+ public SpeechBubble(string text, IEntity senderEntity, IEyeManager eyeManager, IChatManager chatManager)
+ {
+ _chatManager = chatManager;
+ _senderEntity = senderEntity;
+ _eyeManager = eyeManager;
+
+ MouseFilter = MouseFilterMode.Ignore;
+ // Use text clipping so new messages don't overlap old ones being pushed up.
+ RectClipContent = true;
+
+ var label = new RichTextLabel
+ {
+ MaxWidth = 256,
+ MouseFilter = MouseFilterMode.Ignore
+ };
+ label.SetMessage(text);
+
+ _panel = new PanelContainer
+ {
+ StyleClasses = { "tooltipBox" },
+ Children = { label },
+ MouseFilter = MouseFilterMode.Ignore,
+ ModulateSelfOverride = Color.White.WithAlpha(0.75f)
+ };
+
+ AddChild(_panel);
+
+ _panel.Size = _panel.CombinedMinimumSize;
+ ContentHeight = _panel.Height;
+ Size = (_panel.Width, 0);
+ _verticalOffsetAchieved = -ContentHeight;
+ }
+
+ protected override void FrameUpdate(RenderFrameEventArgs args)
+ {
+ base.FrameUpdate(args);
+
+ _timeLeft -= args.Elapsed;
+
+ if (_timeLeft <= FadeTime)
+ {
+ // Update alpha if we're fading.
+ Modulate = Color.White.WithAlpha(_timeLeft / FadeTime);
+ }
+
+ if (_senderEntity.Deleted || _timeLeft <= 0)
+ {
+ // Timer spawn to prevent concurrent modification exception.
+ Timer.Spawn(0, Die);
+ return;
+ }
+
+ // Lerp to our new vertical offset if it's been modified.
+ if (FloatMath.CloseTo(_verticalOffsetAchieved - VerticalOffset, 0, 0.1))
+ {
+ _verticalOffsetAchieved = VerticalOffset;
+ }
+ else
+ {
+ _verticalOffsetAchieved = FloatMath.Lerp(_verticalOffsetAchieved, VerticalOffset, 10 * args.Elapsed);
+ }
+
+ var worldPos = _senderEntity.Transform.WorldPosition;
+ worldPos += (0, EntityVerticalOffset);
+
+ var lowerCenter = _eyeManager.WorldToScreen(worldPos) / UIScale;
+ var screenPos = lowerCenter - (Width / 2, ContentHeight + _verticalOffsetAchieved);
+ Position = screenPos;
+
+ var height = (lowerCenter.Y - screenPos.Y).Clamp(0, ContentHeight);
+ Size = (Size.X, height);
+ }
+
+ private void Die()
+ {
+ if (Disposed)
+ {
+ return;
+ }
+
+ _chatManager.RemoveSpeechBubble(_senderEntity.Uid, this);
+ }
+
+ ///
+ /// Causes the speech bubble to start fading IMMEDIATELY.
+ ///
+ public void FadeNow()
+ {
+ if (_timeLeft > FadeTime)
+ {
+ _timeLeft = FadeTime;
+ }
+ }
+ }
+}
diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs
index 0a04e76ce2..bf830edbae 100644
--- a/Content.Client/EntryPoint.cs
+++ b/Content.Client/EntryPoint.cs
@@ -1,44 +1,27 @@
-using Content.Client.GameObjects;
+using System;
+using Content.Client.Chat;
using Content.Client.GameObjects.Components.Actor;
-using Content.Client.GameObjects.Components.Clothing;
-using Content.Client.GameObjects.Components.Construction;
-using Content.Client.GameObjects.Components.Power;
-using Content.Client.GameObjects.Components.IconSmoothing;
-using Content.Client.GameObjects.Components.Storage;
-using Content.Client.GameObjects.Components.Weapons.Ranged;
using Content.Client.GameTicking;
using Content.Client.Input;
using Content.Client.Interfaces;
-using Content.Client.Interfaces.GameObjects;
+using Content.Client.Interfaces.Chat;
using Content.Client.Interfaces.Parallax;
using Content.Client.Parallax;
+using Content.Client.UserInterface;
+using Content.Shared.GameObjects.Components.Chemistry;
+using Content.Shared.GameObjects.Components.Markers;
+using Content.Shared.GameObjects.Components.Research;
using Content.Shared.Interfaces;
using Robust.Client;
using Robust.Client.Interfaces;
using Robust.Client.Interfaces.Graphics.Overlays;
using Robust.Client.Interfaces.Input;
+using Robust.Client.Interfaces.UserInterface;
using Robust.Client.Player;
using Robust.Shared.ContentPack;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
-using System;
-using Content.Client.Chat;
-using Content.Client.GameObjects.Components;
-using Content.Client.GameObjects.Components.Mobs;
-using Content.Client.GameObjects.Components.Movement;
-using Content.Client.GameObjects.Components.Research;
-using Content.Client.GameObjects.Components.Sound;
-using Content.Client.Interfaces.Chat;
-using Content.Client.UserInterface;
-using Content.Shared.GameObjects.Components.Markers;
-using Content.Shared.GameObjects.Components.Materials;
-using Content.Shared.GameObjects.Components.Mobs;
-using Content.Shared.GameObjects.Components.Movement;
-using Content.Shared.GameObjects.Components.Research;
-using Robust.Client.Interfaces.State;
-using Robust.Client.Interfaces.UserInterface;
-using Robust.Client.State.States;
namespace Content.Client
{
@@ -54,110 +37,74 @@ namespace Content.Client
var factory = IoCManager.Resolve();
var prototypes = IoCManager.Resolve();
- factory.RegisterIgnore("Interactable");
- factory.RegisterIgnore("Destructible");
- factory.RegisterIgnore("Temperature");
- factory.RegisterIgnore("PowerTransfer");
- factory.RegisterIgnore("PowerNode");
- factory.RegisterIgnore("PowerProvider");
- factory.RegisterIgnore("PowerDevice");
- factory.RegisterIgnore("PowerStorage");
- factory.RegisterIgnore("PowerGenerator");
+ factory.DoAutoRegistrations();
- factory.RegisterIgnore("Explosive");
- factory.RegisterIgnore("OnUseTimerTrigger");
+ var registerIgnore = new[]
+ {
+ "Interactable",
+ "Destructible",
+ "Temperature",
+ "PowerTransfer",
+ "PowerNode",
+ "PowerProvider",
+ "PowerDevice",
+ "PowerStorage",
+ "PowerGenerator",
+ "Explosive",
+ "OnUseTimerTrigger",
+ "ToolboxElectricalFill",
+ "ToolLockerFill",
+ "EmitSoundOnUse",
+ "FootstepModifier",
+ "HeatResistance",
+ "CombatMode",
+ "Teleportable",
+ "ItemTeleporter",
+ "Portal",
+ "EntityStorage",
+ "PlaceableSurface",
+ "Wirecutter",
+ "Screwdriver",
+ "Multitool",
+ "Welder",
+ "Wrench",
+ "Crowbar",
+ "HitscanWeapon",
+ "ProjectileWeapon",
+ "Projectile",
+ "MeleeWeapon",
+ "Storeable",
+ "Stack",
+ "Dice",
+ "Construction",
+ "Apc",
+ "Door",
+ "PoweredLight",
+ "Smes",
+ "Powercell",
+ "HandheldLight",
+ "LightBulb",
+ "Healing",
+ "Catwalk",
+ "BallisticMagazine",
+ "BallisticMagazineWeapon",
+ "BallisticBullet",
+ "HitscanWeaponCapacitor",
+ "PowerCell",
+ "AiController",
+ "PlayerInputMover",
+ };
- factory.RegisterIgnore("ToolboxElectricalFill");
- factory.RegisterIgnore("ToolLockerFill");
-
- factory.RegisterIgnore("EmitSoundOnUse");
- factory.RegisterIgnore("FootstepModifier");
-
- factory.RegisterIgnore("HeatResistance");
- factory.RegisterIgnore("CombatMode");
-
- factory.RegisterIgnore("Teleportable");
- factory.RegisterIgnore("ItemTeleporter");
- factory.RegisterIgnore("Portal");
-
- factory.RegisterIgnore("EntityStorage");
- factory.RegisterIgnore("PlaceableSurface");
-
- factory.RegisterIgnore("Wirecutter");
- factory.RegisterIgnore("Screwdriver");
- factory.RegisterIgnore("Multitool");
- factory.RegisterIgnore("Welder");
- factory.RegisterIgnore("Wrench");
- factory.RegisterIgnore("Crowbar");
- factory.Register();
- factory.RegisterIgnore("HitscanWeapon");
- factory.RegisterIgnore("ProjectileWeapon");
- factory.RegisterIgnore("Projectile");
- factory.RegisterIgnore("MeleeWeapon");
-
- factory.RegisterIgnore("Storeable");
-
- factory.RegisterIgnore("Stack");
-
- factory.RegisterIgnore("Dice");
-
- factory.Register();
- factory.RegisterReference();
- factory.Register();
- factory.Register();
- factory.Register();
- factory.Register();
- factory.Register();
- factory.Register();
- factory.Register();
- factory.Register();
- factory.Register();
- factory.Register();
- factory.Register();
- factory.Register();
- factory.RegisterReference();
-
- factory.RegisterReference();
-
- factory.Register();
- factory.Register();
-
- factory.RegisterIgnore("Construction");
- factory.RegisterIgnore("Apc");
- factory.RegisterIgnore("Door");
- factory.RegisterIgnore("PoweredLight");
- factory.RegisterIgnore("Smes");
- factory.RegisterIgnore("Powercell");
- factory.RegisterIgnore("HandheldLight");
- factory.RegisterIgnore("LightBulb");
- factory.RegisterIgnore("Healing");
- factory.RegisterIgnore("Catwalk");
- factory.RegisterIgnore("BallisticMagazine");
- factory.RegisterIgnore("BallisticMagazineWeapon");
- factory.RegisterIgnore("BallisticBullet");
- factory.RegisterIgnore("HitscanWeaponCapacitor");
-
- prototypes.RegisterIgnore("material");
-
- factory.RegisterIgnore("PowerCell");
-
- factory.Register();
+ foreach (var ignoreName in registerIgnore)
+ {
+ factory.RegisterIgnore(ignoreName);
+ }
factory.Register();
- factory.Register();
+ factory.Register();
+ factory.Register();
- factory.RegisterReference();
-
- factory.Register();
- factory.RegisterReference();
-
- factory.Register();
-
- factory.RegisterIgnore("AiController");
- factory.RegisterIgnore("PlayerInputMover");
-
- factory.Register();
- factory.Register();
+ prototypes.RegisterIgnore("material");
IoCManager.Register();
IoCManager.Register();
@@ -186,6 +133,7 @@ namespace Content.Client
_escapeMenuOwner.Initialize();
}
+
///
/// Subscribe events to the player manager after the player manager is set up
///
@@ -238,6 +186,7 @@ namespace Content.Client
var renderFrameEventArgs = new RenderFrameEventArgs(frameTime);
IoCManager.Resolve().FrameUpdate(renderFrameEventArgs);
IoCManager.Resolve().FrameUpdate(renderFrameEventArgs);
+ IoCManager.Resolve().FrameUpdate(renderFrameEventArgs);
break;
}
}
diff --git a/Content.Client/GameObjects/Components/Actor/CharacterInfoComponent.cs b/Content.Client/GameObjects/Components/Actor/CharacterInfoComponent.cs
index aa8faec6c3..18b939d90b 100644
--- a/Content.Client/GameObjects/Components/Actor/CharacterInfoComponent.cs
+++ b/Content.Client/GameObjects/Components/Actor/CharacterInfoComponent.cs
@@ -10,6 +10,7 @@ using Robust.Shared.Localization;
namespace Content.Client.GameObjects.Components.Actor
{
+ [RegisterComponent]
public sealed class CharacterInfoComponent : Component, ICharacterUI
{
private CharacterInfoControl _control;
diff --git a/Content.Client/GameObjects/Components/Actor/CharacterInterface.cs b/Content.Client/GameObjects/Components/Actor/CharacterInterface.cs
index fe2d2a5063..b468e9ffdc 100644
--- a/Content.Client/GameObjects/Components/Actor/CharacterInterface.cs
+++ b/Content.Client/GameObjects/Components/Actor/CharacterInterface.cs
@@ -18,6 +18,7 @@ namespace Content.Client.GameObjects.Components.Actor
/// A semi-abstract component which gets added to entities upon attachment and collects all character
/// user interfaces into a single window and keybind for the user
///
+ [RegisterComponent]
public class CharacterInterface : Component
{
public override string Name => "Character Interface Component";
diff --git a/Content.Client/GameObjects/Components/Clothing/ClothingComponent.cs b/Content.Client/GameObjects/Components/Clothing/ClothingComponent.cs
index 8a9eb99b9d..57ffb68a17 100644
--- a/Content.Client/GameObjects/Components/Clothing/ClothingComponent.cs
+++ b/Content.Client/GameObjects/Components/Clothing/ClothingComponent.cs
@@ -1,13 +1,15 @@
-using Content.Shared.GameObjects;
+using System;
+using Content.Shared.GameObjects;
using Content.Shared.GameObjects.Components.Inventory;
using Content.Shared.GameObjects.Components.Items;
using Robust.Client.Graphics;
using Robust.Shared.GameObjects;
using Robust.Shared.ViewVariables;
-using System;
namespace Content.Client.GameObjects.Components.Clothing
{
+ [RegisterComponent]
+ [ComponentReference(typeof(ItemComponent))]
public class ClothingComponent : ItemComponent
{
public override string Name => "Clothing";
diff --git a/Content.Client/GameObjects/Components/Construction/ConstructionGhostComponent.cs b/Content.Client/GameObjects/Components/Construction/ConstructionGhostComponent.cs
index 1f9a0f1531..6abd5846a5 100644
--- a/Content.Client/GameObjects/Components/Construction/ConstructionGhostComponent.cs
+++ b/Content.Client/GameObjects/Components/Construction/ConstructionGhostComponent.cs
@@ -6,6 +6,7 @@ using Robust.Shared.ViewVariables;
namespace Content.Client.GameObjects.Components.Construction
{
+ [RegisterComponent]
public class ConstructionGhostComponent : Component
{
public override string Name => "ConstructionGhost";
diff --git a/Content.Client/GameObjects/Components/Construction/ConstructorComponent.cs b/Content.Client/GameObjects/Components/Construction/ConstructorComponent.cs
index 9d948a8498..f5b5edaf34 100644
--- a/Content.Client/GameObjects/Components/Construction/ConstructorComponent.cs
+++ b/Content.Client/GameObjects/Components/Construction/ConstructorComponent.cs
@@ -15,6 +15,7 @@ using Robust.Shared.Maths;
namespace Content.Client.GameObjects.Components.Construction
{
+ [RegisterComponent]
public class ConstructorComponent : SharedConstructorComponent
{
#pragma warning disable 649
diff --git a/Content.Client/GameObjects/Components/DamageableComponent.cs b/Content.Client/GameObjects/Components/DamageableComponent.cs
index 311f89e80c..bde34e4d96 100644
--- a/Content.Client/GameObjects/Components/DamageableComponent.cs
+++ b/Content.Client/GameObjects/Components/DamageableComponent.cs
@@ -1,6 +1,6 @@
-using Content.Shared.GameObjects;
+using System.Collections.Generic;
+using Content.Shared.GameObjects;
using Robust.Shared.GameObjects;
-using System.Collections.Generic;
namespace Content.Client.GameObjects
{
@@ -8,6 +8,7 @@ namespace Content.Client.GameObjects
/// Fuck I really hate doing this
/// TODO: make sure the client only gets damageable component on the clientside entity for its player mob
///
+ [RegisterComponent]
public class DamageableComponent : SharedDamageableComponent
{
///
diff --git a/Content.Client/GameObjects/Components/HUD/Inventory/ClientInventoryComponent.cs b/Content.Client/GameObjects/Components/HUD/Inventory/ClientInventoryComponent.cs
index 58456557f9..bc3b6c039b 100644
--- a/Content.Client/GameObjects/Components/HUD/Inventory/ClientInventoryComponent.cs
+++ b/Content.Client/GameObjects/Components/HUD/Inventory/ClientInventoryComponent.cs
@@ -21,6 +21,7 @@ namespace Content.Client.GameObjects
///
/// A character UI which shows items the user has equipped within his inventory
///
+ [RegisterComponent]
public class ClientInventoryComponent : SharedInventoryComponent
{
private readonly Dictionary _slots = new Dictionary();
diff --git a/Content.Client/GameObjects/Components/IconSmoothing/IconSmoothComponent.cs b/Content.Client/GameObjects/Components/IconSmoothing/IconSmoothComponent.cs
index 6b510ff8bd..6abe1145a7 100644
--- a/Content.Client/GameObjects/Components/IconSmoothing/IconSmoothComponent.cs
+++ b/Content.Client/GameObjects/Components/IconSmoothing/IconSmoothComponent.cs
@@ -1,10 +1,14 @@
-using System.Diagnostics.CodeAnalysis;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using Content.Client.GameObjects.EntitySystems;
using JetBrains.Annotations;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Transform;
+using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Map;
+using Robust.Shared.Maths;
using Robust.Shared.Serialization;
using static Robust.Client.GameObjects.SpriteComponent;
@@ -21,7 +25,8 @@ namespace Content.Client.GameObjects.Components.IconSmoothing
/// To use, set base equal to the prefix of the corner states in the sprite base RSI.
/// Any objects with the same key will connect.
///
- public sealed class IconSmoothComponent : Component
+ [RegisterComponent]
+ public class IconSmoothComponent : Component
{
private string _smoothKey;
private string _stateBase;
@@ -76,9 +81,9 @@ namespace Content.Client.GameObjects.Components.IconSmoothing
SnapGrid.OnPositionChanged += SnapGridOnPositionChanged;
Owner.EntityManager.RaiseEvent(Owner, new IconSmoothDirtyEvent(null, SnapGrid.Offset, Mode));
- var state0 = $"{StateBase}0";
if (Mode == IconSmoothingMode.Corners)
{
+ var state0 = $"{StateBase}0";
Sprite.LayerMapSet(CornerLayers.SE, Sprite.AddLayerState(state0));
Sprite.LayerSetDirOffset(CornerLayers.SE, DirectionOffset.None);
Sprite.LayerMapSet(CornerLayers.NE, Sprite.AddLayerState(state0));
@@ -90,6 +95,107 @@ namespace Content.Client.GameObjects.Components.IconSmoothing
}
}
+ internal virtual void CalculateNewSprite()
+ {
+ switch (Mode)
+ {
+ case IconSmoothingMode.Corners:
+ CalculateNewSpriteCorers();
+ break;
+
+ case IconSmoothingMode.CardinalFlags:
+ CalculateNewSpriteCardinal();
+ break;
+
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ }
+
+ private void CalculateNewSpriteCardinal()
+ {
+ var dirs = CardinalConnectDirs.None;
+
+ if (MatchingEntity(SnapGrid.GetInDir(Direction.North)))
+ dirs |= CardinalConnectDirs.North;
+ if (MatchingEntity(SnapGrid.GetInDir(Direction.South)))
+ dirs |= CardinalConnectDirs.South;
+ if (MatchingEntity(SnapGrid.GetInDir(Direction.East)))
+ dirs |= CardinalConnectDirs.East;
+ if (MatchingEntity(SnapGrid.GetInDir(Direction.West)))
+ dirs |= CardinalConnectDirs.West;
+
+ Sprite.LayerSetState(0, $"{StateBase}{(int) dirs}");
+ }
+
+ private void CalculateNewSpriteCorers()
+ {
+ var n = MatchingEntity(SnapGrid.GetInDir(Direction.North));
+ var ne = MatchingEntity(SnapGrid.GetInDir(Direction.NorthEast));
+ var e = MatchingEntity(SnapGrid.GetInDir(Direction.East));
+ var se = MatchingEntity(SnapGrid.GetInDir(Direction.SouthEast));
+ var s = MatchingEntity(SnapGrid.GetInDir(Direction.South));
+ var sw = MatchingEntity(SnapGrid.GetInDir(Direction.SouthWest));
+ var w = MatchingEntity(SnapGrid.GetInDir(Direction.West));
+ var nw = MatchingEntity(SnapGrid.GetInDir(Direction.NorthWest));
+
+ // ReSharper disable InconsistentNaming
+ var cornerNE = CornerFill.None;
+ var cornerSE = CornerFill.None;
+ var cornerSW = CornerFill.None;
+ var cornerNW = CornerFill.None;
+ // ReSharper restore InconsistentNaming
+
+ if (n)
+ {
+ cornerNE |= CornerFill.CounterClockwise;
+ cornerNW |= CornerFill.Clockwise;
+ }
+
+ if (ne)
+ {
+ cornerNE |= CornerFill.Diagonal;
+ }
+
+ if (e)
+ {
+ cornerNE |= CornerFill.Clockwise;
+ cornerSE |= CornerFill.CounterClockwise;
+ }
+
+ if (se)
+ {
+ cornerSE |= CornerFill.Diagonal;
+ }
+
+ if (s)
+ {
+ cornerSE |= CornerFill.Clockwise;
+ cornerSW |= CornerFill.CounterClockwise;
+ }
+
+ if (sw)
+ {
+ cornerSW |= CornerFill.Diagonal;
+ }
+
+ if (w)
+ {
+ cornerSW |= CornerFill.Clockwise;
+ cornerNW |= CornerFill.CounterClockwise;
+ }
+
+ if (nw)
+ {
+ cornerNW |= CornerFill.Diagonal;
+ }
+
+ Sprite.LayerSetState(CornerLayers.NE, $"{StateBase}{(int) cornerNE}");
+ Sprite.LayerSetState(CornerLayers.SE, $"{StateBase}{(int) cornerSE}");
+ Sprite.LayerSetState(CornerLayers.SW, $"{StateBase}{(int) cornerSW}");
+ Sprite.LayerSetState(CornerLayers.NW, $"{StateBase}{(int) cornerNW}");
+ }
+
public override void Shutdown()
{
SnapGrid.OnPositionChanged -= SnapGridOnPositionChanged;
@@ -104,6 +210,52 @@ namespace Content.Client.GameObjects.Components.IconSmoothing
_lastPosition = (Owner.Transform.GridID, SnapGrid.Position);
}
+ [System.Diagnostics.Contracts.Pure]
+ protected bool MatchingEntity(IEnumerable candidates)
+ {
+ foreach (var entity in candidates)
+ {
+ if (!entity.TryGetComponent(out IconSmoothComponent other))
+ {
+ continue;
+ }
+
+ if (other.SmoothKey == SmoothKey)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ [Flags]
+ private enum CardinalConnectDirs : byte
+ {
+ None = 0,
+ North = 1,
+ South = 2,
+ East = 4,
+ West = 8
+ }
+
+ [Flags]
+ public enum CornerFill : byte
+ {
+ // These values are pulled from Baystation12.
+ // I'm too lazy to convert the state names.
+ None = 0,
+
+ // The cardinal tile counter-clockwise of this corner is filled.
+ CounterClockwise = 1,
+
+ // The diagonal tile in the direction of this corner.
+ Diagonal = 2,
+
+ // The cardinal tile clockwise of this corner is filled.
+ Clockwise = 4,
+ }
+
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum CornerLayers
{
diff --git a/Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs b/Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs
index 62158c0e0d..4e0899724c 100644
--- a/Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs
+++ b/Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs
@@ -15,6 +15,8 @@ using Robust.Shared.ViewVariables;
namespace Content.Client.GameObjects
{
+ [RegisterComponent]
+ [ComponentReference(typeof(IHandsComponent))]
public class HandsComponent : SharedHandsComponent, IHandsComponent
{
private HandsGui _gui;
diff --git a/Content.Client/GameObjects/Components/Items/ItemComponent.cs b/Content.Client/GameObjects/Components/Items/ItemComponent.cs
index 574f25b50d..80eed4d948 100644
--- a/Content.Client/GameObjects/Components/Items/ItemComponent.cs
+++ b/Content.Client/GameObjects/Components/Items/ItemComponent.cs
@@ -1,4 +1,5 @@
-using Content.Shared.GameObjects;
+using System;
+using Content.Shared.GameObjects;
using Content.Shared.GameObjects.Components.Items;
using Robust.Client.Graphics;
using Robust.Client.Interfaces.ResourceManagement;
@@ -9,10 +10,10 @@ using Robust.Shared.IoC;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
-using System;
namespace Content.Client.GameObjects
{
+ [RegisterComponent]
public class ItemComponent : Component
{
public override string Name => "Item";
diff --git a/Content.Client/GameObjects/Components/LowWallComponent.cs b/Content.Client/GameObjects/Components/LowWallComponent.cs
new file mode 100644
index 0000000000..c183beb568
--- /dev/null
+++ b/Content.Client/GameObjects/Components/LowWallComponent.cs
@@ -0,0 +1,209 @@
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using Content.Client.GameObjects.Components.IconSmoothing;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.Maths;
+using static Robust.Client.GameObjects.SpriteComponent;
+
+namespace Content.Client.GameObjects.Components
+{
+ // TODO: Over layers should be placed ABOVE the window itself too.
+ // This is gonna require a client entity & parenting,
+ // so IsMapTransform being naive is gonna be a problem.
+
+ ///
+ /// Override of icon smoothing to handle the specific complexities of low walls.
+ ///
+ [RegisterComponent]
+ [ComponentReference(typeof(IconSmoothComponent))]
+ public class LowWallComponent : IconSmoothComponent
+ {
+ public override string Name => "LowWall";
+
+ public CornerFill LastCornerNE { get; private set; }
+ public CornerFill LastCornerSE { get; private set; }
+ public CornerFill LastCornerSW { get; private set; }
+ public CornerFill LastCornerNW { get; private set; }
+
+ public override void Startup()
+ {
+ base.Startup();
+
+ var overState0 = $"{StateBase}over_0";
+ Sprite.LayerMapSet(OverCornerLayers.SE, Sprite.AddLayerState(overState0));
+ Sprite.LayerSetDirOffset(OverCornerLayers.SE, DirectionOffset.None);
+ Sprite.LayerMapSet(OverCornerLayers.NE, Sprite.AddLayerState(overState0));
+ Sprite.LayerSetDirOffset(OverCornerLayers.NE, DirectionOffset.CounterClockwise);
+ Sprite.LayerMapSet(OverCornerLayers.NW, Sprite.AddLayerState(overState0));
+ Sprite.LayerSetDirOffset(OverCornerLayers.NW, DirectionOffset.Flip);
+ Sprite.LayerMapSet(OverCornerLayers.SW, Sprite.AddLayerState(overState0));
+ Sprite.LayerSetDirOffset(OverCornerLayers.SW, DirectionOffset.Clockwise);
+ }
+
+ internal override void CalculateNewSprite()
+ {
+ base.CalculateNewSprite();
+
+ var (n, nl) = MatchingWall(SnapGrid.GetInDir(Direction.North));
+ var (ne, nel) = MatchingWall(SnapGrid.GetInDir(Direction.NorthEast));
+ var (e, el) = MatchingWall(SnapGrid.GetInDir(Direction.East));
+ var (se, sel) = MatchingWall(SnapGrid.GetInDir(Direction.SouthEast));
+ var (s, sl) = MatchingWall(SnapGrid.GetInDir(Direction.South));
+ var (sw, swl) = MatchingWall(SnapGrid.GetInDir(Direction.SouthWest));
+ var (w, wl) = MatchingWall(SnapGrid.GetInDir(Direction.West));
+ var (nw, nwl) = MatchingWall(SnapGrid.GetInDir(Direction.NorthWest));
+
+ // ReSharper disable InconsistentNaming
+ var cornerNE = CornerFill.None;
+ var cornerSE = CornerFill.None;
+ var cornerSW = CornerFill.None;
+ var cornerNW = CornerFill.None;
+
+ var lowCornerNE = CornerFill.None;
+ var lowCornerSE = CornerFill.None;
+ var lowCornerSW = CornerFill.None;
+ var lowCornerNW = CornerFill.None;
+ // ReSharper restore InconsistentNaming
+
+ if (n)
+ {
+ cornerNE |= CornerFill.CounterClockwise;
+ cornerNW |= CornerFill.Clockwise;
+
+ if (!nl)
+ {
+ lowCornerNE |= CornerFill.CounterClockwise;
+ lowCornerNW |= CornerFill.Clockwise;
+ }
+ }
+
+ if (ne)
+ {
+ cornerNE |= CornerFill.Diagonal;
+
+ if (!nel && (nl || el || n && e))
+ {
+ lowCornerNE |= CornerFill.Diagonal;
+ }
+ }
+
+ if (e)
+ {
+ cornerNE |= CornerFill.Clockwise;
+ cornerSE |= CornerFill.CounterClockwise;
+
+ if (!el)
+ {
+ lowCornerNE |= CornerFill.Clockwise;
+ lowCornerSE |= CornerFill.CounterClockwise;
+ }
+ }
+
+ if (se)
+ {
+ cornerSE |= CornerFill.Diagonal;
+
+ if (!sel && (sl || el || s && e))
+ {
+ lowCornerSE |= CornerFill.Diagonal;
+ }
+ }
+
+ if (s)
+ {
+ cornerSE |= CornerFill.Clockwise;
+ cornerSW |= CornerFill.CounterClockwise;
+
+ if (!sl)
+ {
+ lowCornerSE |= CornerFill.Clockwise;
+ lowCornerSW |= CornerFill.CounterClockwise;
+ }
+ }
+
+ if (sw)
+ {
+ cornerSW |= CornerFill.Diagonal;
+
+ if (!swl && (sl || wl || s && w))
+ {
+ lowCornerSW |= CornerFill.Diagonal;
+ }
+ }
+
+ if (w)
+ {
+ cornerSW |= CornerFill.Clockwise;
+ cornerNW |= CornerFill.CounterClockwise;
+
+ if (!wl)
+ {
+ lowCornerSW |= CornerFill.Clockwise;
+ lowCornerNW |= CornerFill.CounterClockwise;
+ }
+ }
+
+ if (nw)
+ {
+ cornerNW |= CornerFill.Diagonal;
+
+ if (!nwl && (nl || wl || n && w))
+ {
+ lowCornerNW |= CornerFill.Diagonal;
+ }
+ }
+
+ Sprite.LayerSetState(CornerLayers.NE, $"{StateBase}{(int) cornerNE}");
+ Sprite.LayerSetState(CornerLayers.SE, $"{StateBase}{(int) cornerSE}");
+ Sprite.LayerSetState(CornerLayers.SW, $"{StateBase}{(int) cornerSW}");
+ Sprite.LayerSetState(CornerLayers.NW, $"{StateBase}{(int) cornerNW}");
+
+ Sprite.LayerSetState(OverCornerLayers.NE, $"{StateBase}over_{(int) lowCornerNE}");
+ Sprite.LayerSetState(OverCornerLayers.SE, $"{StateBase}over_{(int) lowCornerSE}");
+ Sprite.LayerSetState(OverCornerLayers.SW, $"{StateBase}over_{(int) lowCornerSW}");
+ Sprite.LayerSetState(OverCornerLayers.NW, $"{StateBase}over_{(int) lowCornerNW}");
+
+ LastCornerNE = cornerNE;
+ LastCornerSE = cornerSE;
+ LastCornerSW = cornerSW;
+ LastCornerNW = cornerNW;
+
+ foreach (var entity in SnapGrid.GetLocal())
+ {
+ if (entity.TryGetComponent(out WindowComponent window))
+ {
+ window.UpdateSprite();
+ }
+ }
+ }
+
+ [System.Diagnostics.Contracts.Pure]
+ private (bool connected, bool lowWall) MatchingWall(IEnumerable candidates)
+ {
+ foreach (var entity in candidates)
+ {
+ if (!entity.TryGetComponent(out IconSmoothComponent other))
+ {
+ continue;
+ }
+
+ if (other.SmoothKey == SmoothKey)
+ {
+ return (true, other is LowWallComponent);
+ }
+ }
+
+ return (false, false);
+ }
+
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ private enum OverCornerLayers
+ {
+ SE,
+ NE,
+ NW,
+ SW,
+ }
+ }
+}
diff --git a/Content.Client/GameObjects/Components/Mobs/CameraRecoilComponent.cs b/Content.Client/GameObjects/Components/Mobs/CameraRecoilComponent.cs
index 6745d2a271..92a8b6f87e 100644
--- a/Content.Client/GameObjects/Components/Mobs/CameraRecoilComponent.cs
+++ b/Content.Client/GameObjects/Components/Mobs/CameraRecoilComponent.cs
@@ -8,6 +8,8 @@ using Robust.Shared.Maths;
namespace Content.Client.GameObjects.Components.Mobs
{
+ [RegisterComponent]
+ [ComponentReference(typeof(SharedCameraRecoilComponent))]
public sealed class CameraRecoilComponent : SharedCameraRecoilComponent
{
// Maximum rate of magnitude restore towards 0 kick.
diff --git a/Content.Client/GameObjects/Components/Mobs/SpeciesUI.cs b/Content.Client/GameObjects/Components/Mobs/SpeciesUI.cs
index c590245f90..2999ede1bf 100644
--- a/Content.Client/GameObjects/Components/Mobs/SpeciesUI.cs
+++ b/Content.Client/GameObjects/Components/Mobs/SpeciesUI.cs
@@ -1,31 +1,31 @@
-using Content.Client.GameObjects.Components.Actor;
-using Content.Client.GameObjects.Components.Mobs;
+using System.Collections.Generic;
+using Content.Client.GameObjects.Components.Actor;
using Content.Client.Graphics.Overlays;
+using Content.Client.UserInterface;
+using Content.Client.Utility;
using Content.Shared.GameObjects;
+using Content.Shared.GameObjects.Components.Mobs;
using Robust.Client.GameObjects;
+using Robust.Client.Graphics;
+using Robust.Client.Graphics.Overlays;
using Robust.Client.Interfaces.Graphics.Overlays;
using Robust.Client.Interfaces.ResourceManagement;
+using Robust.Client.Interfaces.UserInterface;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.GameObjects;
+using Robust.Shared.GameObjects.Components.Renderable;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
-using System.Collections.Generic;
-using Content.Client.UserInterface;
-using Content.Client.Utility;
-using Content.Shared.GameObjects.Components.Mobs;
-using Robust.Client.Graphics;
-using Robust.Client.Graphics.Overlays;
-using Robust.Client.Interfaces.UserInterface;
-using Robust.Shared.GameObjects.Components.Renderable;
namespace Content.Client.GameObjects
{
///
/// A character UI component which shows the current damage state of the mob (living/dead)
///
+ [RegisterComponent]
public class SpeciesUI : SharedSpeciesComponent//, ICharacterUI
{
private StatusEffectsUI _ui;
diff --git a/Content.Client/GameObjects/Components/Power/PowerDebugTool.cs b/Content.Client/GameObjects/Components/Power/PowerDebugTool.cs
index d36d3be317..21e7452068 100644
--- a/Content.Client/GameObjects/Components/Power/PowerDebugTool.cs
+++ b/Content.Client/GameObjects/Components/Power/PowerDebugTool.cs
@@ -1,14 +1,13 @@
using Content.Shared.GameObjects.Components.Power;
-using Robust.Client.Interfaces.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
-using Robust.Shared.IoC;
namespace Content.Client.GameObjects.Components.Power
{
+ [RegisterComponent]
public class PowerDebugTool : SharedPowerDebugTool
{
SS14Window LastWindow;
diff --git a/Content.Client/GameObjects/Components/Research/LatheDatabaseComponent.cs b/Content.Client/GameObjects/Components/Research/LatheDatabaseComponent.cs
index b40d96319d..962948e7e8 100644
--- a/Content.Client/GameObjects/Components/Research/LatheDatabaseComponent.cs
+++ b/Content.Client/GameObjects/Components/Research/LatheDatabaseComponent.cs
@@ -1,13 +1,13 @@
using Content.Shared.GameObjects.Components.Research;
using Content.Shared.Research;
using Robust.Shared.GameObjects;
-using Robust.Shared.Interfaces.GameObjects;
-using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
namespace Content.Client.GameObjects.Components.Research
{
+ [RegisterComponent]
+ [ComponentReference(typeof(SharedLatheDatabaseComponent))]
public class LatheDatabaseComponent : SharedLatheDatabaseComponent
{
#pragma warning disable CS0649
diff --git a/Content.Client/GameObjects/Components/Research/MaterialStorageComponent.cs b/Content.Client/GameObjects/Components/Research/MaterialStorageComponent.cs
index de32c6f55c..62dfd8c18d 100644
--- a/Content.Client/GameObjects/Components/Research/MaterialStorageComponent.cs
+++ b/Content.Client/GameObjects/Components/Research/MaterialStorageComponent.cs
@@ -2,11 +2,11 @@ using System;
using System.Collections.Generic;
using Content.Shared.GameObjects.Components.Research;
using Robust.Shared.GameObjects;
-using Robust.Shared.Interfaces.GameObjects;
-using Robust.Shared.Interfaces.Network;
namespace Content.Client.GameObjects.Components.Research
{
+ [RegisterComponent]
+ [ComponentReference(typeof(SharedMaterialStorageComponent))]
public class MaterialStorageComponent : SharedMaterialStorageComponent
{
protected override Dictionary Storage { get; set; } = new Dictionary();
diff --git a/Content.Client/GameObjects/Components/Sound/SoundComponent.cs b/Content.Client/GameObjects/Components/Sound/SoundComponent.cs
index e8a47f1643..cfed2998ee 100644
--- a/Content.Client/GameObjects/Components/Sound/SoundComponent.cs
+++ b/Content.Client/GameObjects/Components/Sound/SoundComponent.cs
@@ -5,14 +5,13 @@ using Robust.Client.GameObjects.EntitySystems;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
-using Robust.Shared.Interfaces.Timers;
using Robust.Shared.IoC;
-using Robust.Shared.Log;
using Robust.Shared.Serialization;
using Robust.Shared.Timers;
namespace Content.Client.GameObjects.Components.Sound
{
+ [RegisterComponent]
public class SoundComponent : SharedSoundComponent
{
private readonly List _schedules = new List();
diff --git a/Content.Client/GameObjects/Components/Storage/ClientStorageComponent.cs b/Content.Client/GameObjects/Components/Storage/ClientStorageComponent.cs
index 1227ab5c63..ad8501cc64 100644
--- a/Content.Client/GameObjects/Components/Storage/ClientStorageComponent.cs
+++ b/Content.Client/GameObjects/Components/Storage/ClientStorageComponent.cs
@@ -1,4 +1,6 @@
-using Content.Shared.GameObjects.Components.Storage;
+using System;
+using System.Collections.Generic;
+using Content.Shared.GameObjects.Components.Storage;
using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
@@ -7,19 +9,15 @@ using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
-using Robust.Shared.Utility;
-using System;
-using System.Collections.Generic;
-using Robust.Client.Interfaces.Graphics;
using Robust.Shared.Maths;
using Robust.Shared.Serialization;
-using Robust.Shared.ViewVariables;
namespace Content.Client.GameObjects.Components.Storage
{
///
/// Client version of item storage containers, contains a UI which displays stored entities and their size
///
+ [RegisterComponent]
public class ClientStorageComponent : SharedStorageComponent
{
private Dictionary StoredEntities { get; set; } = new Dictionary();
@@ -118,7 +116,6 @@ namespace Content.Client.GameObjects.Components.Storage
base.Initialize();
Title = "Storage Item";
- Visible = false;
RectClipContent = true;
VSplitContainer = new VBoxContainer("VSplitContainer");
diff --git a/Content.Client/GameObjects/Components/SubFloorHideComponent.cs b/Content.Client/GameObjects/Components/SubFloorHideComponent.cs
index 45d6c366d0..b5cabd00dd 100644
--- a/Content.Client/GameObjects/Components/SubFloorHideComponent.cs
+++ b/Content.Client/GameObjects/Components/SubFloorHideComponent.cs
@@ -10,6 +10,7 @@ namespace Content.Client.GameObjects.Components
/// is not a sub floor (plating).
///
///
+ [RegisterComponent]
public sealed class SubFloorHideComponent : Component
{
private SnapGridComponent _snapGridComponent;
diff --git a/Content.Client/GameObjects/Components/Weapons/Ranged/ClientRangedWeaponComponent.cs b/Content.Client/GameObjects/Components/Weapons/Ranged/ClientRangedWeaponComponent.cs
index 3c7c76c5e4..291e05e4c1 100644
--- a/Content.Client/GameObjects/Components/Weapons/Ranged/ClientRangedWeaponComponent.cs
+++ b/Content.Client/GameObjects/Components/Weapons/Ranged/ClientRangedWeaponComponent.cs
@@ -1,12 +1,13 @@
using System;
using Content.Shared.GameObjects.Components.Weapons.Ranged;
+using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.IoC;
-using Robust.Shared.Log;
using Robust.Shared.Map;
namespace Content.Client.GameObjects.Components.Weapons.Ranged
{
+ [RegisterComponent]
public sealed class ClientRangedWeaponComponent : SharedRangedWeaponComponent
{
private TimeSpan _lastFireTime;
diff --git a/Content.Client/GameObjects/Components/WindowComponent.cs b/Content.Client/GameObjects/Components/WindowComponent.cs
new file mode 100644
index 0000000000..f4ae19448f
--- /dev/null
+++ b/Content.Client/GameObjects/Components/WindowComponent.cs
@@ -0,0 +1,92 @@
+using Content.Client.GameObjects.EntitySystems;
+using Robust.Client.GameObjects;
+using Robust.Client.Interfaces.GameObjects.Components;
+using Robust.Shared.GameObjects;
+using Robust.Shared.GameObjects.Components.Transform;
+using Robust.Shared.Serialization;
+using static Content.Client.GameObjects.Components.IconSmoothing.IconSmoothComponent;
+
+namespace Content.Client.GameObjects.Components
+{
+ [RegisterComponent]
+ public sealed class WindowComponent : Component
+ {
+ public override string Name => "Window";
+
+ private string _stateBase;
+ private ISpriteComponent _sprite;
+ private SnapGridComponent _snapGrid;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ _sprite = Owner.GetComponent();
+ _snapGrid = Owner.GetComponent();
+ }
+
+ public override void Startup()
+ {
+ base.Startup();
+
+ _snapGrid.OnPositionChanged += SnapGridOnPositionChanged;
+ Owner.EntityManager.RaiseEvent(Owner, new WindowSmoothDirtyEvent());
+
+ var state0 = $"{_stateBase}0";
+ _sprite.LayerMapSet(CornerLayers.SE, _sprite.AddLayerState(state0));
+ _sprite.LayerSetDirOffset(CornerLayers.SE, SpriteComponent.DirectionOffset.None);
+ _sprite.LayerMapSet(CornerLayers.NE, _sprite.AddLayerState(state0));
+ _sprite.LayerSetDirOffset(CornerLayers.NE, SpriteComponent.DirectionOffset.CounterClockwise);
+ _sprite.LayerMapSet(CornerLayers.NW, _sprite.AddLayerState(state0));
+ _sprite.LayerSetDirOffset(CornerLayers.NW, SpriteComponent.DirectionOffset.Flip);
+ _sprite.LayerMapSet(CornerLayers.SW, _sprite.AddLayerState(state0));
+ _sprite.LayerSetDirOffset(CornerLayers.SW, SpriteComponent.DirectionOffset.Clockwise);
+ }
+
+ public override void Shutdown()
+ {
+ _snapGrid.OnPositionChanged -= SnapGridOnPositionChanged;
+
+ base.Shutdown();
+ }
+
+ private void SnapGridOnPositionChanged()
+ {
+ Owner.EntityManager.RaiseEvent(Owner, new WindowSmoothDirtyEvent());
+ }
+
+ public void UpdateSprite()
+ {
+ var lowWall = FindLowWall();
+ if (lowWall == null)
+ {
+ return;
+ }
+
+ _sprite.LayerSetState(CornerLayers.NE, $"{_stateBase}{(int) lowWall.LastCornerNE}");
+ _sprite.LayerSetState(CornerLayers.SE, $"{_stateBase}{(int) lowWall.LastCornerSE}");
+ _sprite.LayerSetState(CornerLayers.SW, $"{_stateBase}{(int) lowWall.LastCornerSW}");
+ _sprite.LayerSetState(CornerLayers.NW, $"{_stateBase}{(int) lowWall.LastCornerNW}");
+ }
+
+ private LowWallComponent FindLowWall()
+ {
+ foreach (var entity in _snapGrid.GetLocal())
+ {
+ if (entity.TryGetComponent(out LowWallComponent lowWall))
+ {
+ return lowWall;
+ }
+ }
+
+ return null;
+ }
+
+ public override void ExposeData(ObjectSerializer serializer)
+ {
+ base.ExposeData(serializer);
+
+ serializer.DataField(ref _stateBase, "base", null);
+ }
+ }
+}
diff --git a/Content.Client/GameObjects/EntitySystems/IconSmoothSystem.cs b/Content.Client/GameObjects/EntitySystems/IconSmoothSystem.cs
index b210804f00..9b7851360a 100644
--- a/Content.Client/GameObjects/EntitySystems/IconSmoothSystem.cs
+++ b/Content.Client/GameObjects/EntitySystems/IconSmoothSystem.cs
@@ -1,9 +1,7 @@
-using System;
using System.Collections.Generic;
using System.Linq;
using Content.Client.GameObjects.Components.IconSmoothing;
using JetBrains.Annotations;
-using Robust.Client.Interfaces.GameObjects.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Transform;
using Robust.Shared.GameObjects.Systems;
@@ -132,157 +130,10 @@ namespace Content.Client.GameObjects.EntitySystems
return;
}
- var sprite = smoothing.Sprite;
- var snapGrid = smoothing.SnapGrid;
-
- switch (smoothing.Mode)
- {
- case IconSmoothingMode.Corners:
- _calculateNewSpriteCorers(smoothing, snapGrid, sprite);
- break;
-
- case IconSmoothingMode.CardinalFlags:
- _calculateNewSpriteCardinal(smoothing, snapGrid, sprite);
- break;
-
- default:
- throw new ArgumentOutOfRangeException();
- }
+ smoothing.CalculateNewSprite();
smoothing.UpdateGeneration = _generation;
}
-
- private static void _calculateNewSpriteCardinal(IconSmoothComponent smoothing, SnapGridComponent snapGrid,
- ISpriteComponent sprite)
- {
- var dirs = CardinalConnectDirs.None;
-
- if (MatchingEntity(smoothing, snapGrid.GetInDir(Direction.North)))
- dirs |= CardinalConnectDirs.North;
- if (MatchingEntity(smoothing, snapGrid.GetInDir(Direction.South)))
- dirs |= CardinalConnectDirs.South;
- if (MatchingEntity(smoothing, snapGrid.GetInDir(Direction.East)))
- dirs |= CardinalConnectDirs.East;
- if (MatchingEntity(smoothing, snapGrid.GetInDir(Direction.West)))
- dirs |= CardinalConnectDirs.West;
-
- sprite.LayerSetState(0, $"{smoothing.StateBase}{(int) dirs}");
- }
-
- private static void _calculateNewSpriteCorers(IconSmoothComponent smoothing, SnapGridComponent snapGrid,
- ISpriteComponent sprite)
- {
- var n = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.North));
- var ne = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.NorthEast));
- var e = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.East));
- var se = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.SouthEast));
- var s = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.South));
- var sw = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.SouthWest));
- var w = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.West));
- var nw = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.NorthWest));
-
- // ReSharper disable InconsistentNaming
- var cornerNE = CornerFill.None;
- var cornerSE = CornerFill.None;
- var cornerSW = CornerFill.None;
- var cornerNW = CornerFill.None;
- // ReSharper restore InconsistentNaming
-
- if (n)
- {
- cornerNE |= CornerFill.CounterClockwise;
- cornerNW |= CornerFill.Clockwise;
- }
-
- if (ne)
- {
- cornerNE |= CornerFill.Diagonal;
- }
-
- if (e)
- {
- cornerNE |= CornerFill.Clockwise;
- cornerSE |= CornerFill.CounterClockwise;
- }
-
- if (se)
- {
- cornerSE |= CornerFill.Diagonal;
- }
-
- if (s)
- {
- cornerSE |= CornerFill.Clockwise;
- cornerSW |= CornerFill.CounterClockwise;
- }
-
- if (sw)
- {
- cornerSW |= CornerFill.Diagonal;
- }
-
- if (w)
- {
- cornerSW |= CornerFill.Clockwise;
- cornerNW |= CornerFill.CounterClockwise;
- }
-
- if (nw)
- {
- cornerNW |= CornerFill.Diagonal;
- }
-
- sprite.LayerSetState(IconSmoothComponent.CornerLayers.NE, $"{smoothing.StateBase}{(int) cornerNE}");
- sprite.LayerSetState(IconSmoothComponent.CornerLayers.SE, $"{smoothing.StateBase}{(int) cornerSE}");
- sprite.LayerSetState(IconSmoothComponent.CornerLayers.SW, $"{smoothing.StateBase}{(int) cornerSW}");
- sprite.LayerSetState(IconSmoothComponent.CornerLayers.NW, $"{smoothing.StateBase}{(int) cornerNW}");
- }
-
- [System.Diagnostics.Contracts.Pure]
- private static bool MatchingEntity(IconSmoothComponent source, IEnumerable candidates)
- {
- foreach (var entity in candidates)
- {
- if (!entity.TryGetComponent(out IconSmoothComponent other))
- {
- return false;
- }
-
- if (other.SmoothKey == source.SmoothKey)
- {
- return true;
- }
- }
-
- return false;
- }
-
- [Flags]
- private enum CardinalConnectDirs : byte
- {
- None = 0,
- North = 1,
- South = 2,
- East = 4,
- West = 8
- }
-
- [Flags]
- private enum CornerFill : byte
- {
- // These values are pulled from Baystation12.
- // I'm too lazy to convert the state names.
- None = 0,
-
- // The cardinal tile counter-clockwise of this corner is filled.
- CounterClockwise = 1,
-
- // The diagonal tile in the direction of this corner.
- Diagonal = 2,
-
- // The cardinal tile clockwise of this corner is filled.
- Clockwise = 4,
- }
}
///
diff --git a/Content.Client/GameObjects/EntitySystems/WindowSystem.cs b/Content.Client/GameObjects/EntitySystems/WindowSystem.cs
new file mode 100644
index 0000000000..73b33afb10
--- /dev/null
+++ b/Content.Client/GameObjects/EntitySystems/WindowSystem.cs
@@ -0,0 +1,51 @@
+using System.Collections.Generic;
+using Content.Client.GameObjects.Components;
+using Content.Client.GameObjects.Components.IconSmoothing;
+using JetBrains.Annotations;
+using Robust.Shared.GameObjects;
+using Robust.Shared.GameObjects.Components.Transform;
+using Robust.Shared.GameObjects.Systems;
+using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.Map;
+
+namespace Content.Client.GameObjects.EntitySystems
+{
+ [UsedImplicitly]
+ public sealed class WindowSystem : EntitySystem
+ {
+ private readonly Queue _dirtyEntities = new Queue();
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeEvent(HandleDirtyEvent);
+ }
+
+ private void HandleDirtyEvent(object sender, WindowSmoothDirtyEvent ev)
+ {
+ if (sender is IEntity senderEnt && senderEnt.HasComponent())
+ {
+ _dirtyEntities.Enqueue(senderEnt);
+ }
+ }
+
+ public override void FrameUpdate(float frameTime)
+ {
+ base.FrameUpdate(frameTime);
+
+ // Performance: This could be spread over multiple updates, or made parallel.
+ while (_dirtyEntities.Count > 0)
+ {
+ _dirtyEntities.Dequeue().GetComponent().UpdateSprite();
+ }
+ }
+ }
+
+ ///
+ /// Event raised by a when it needs to be recalculated.
+ ///
+ public sealed class WindowSmoothDirtyEvent : EntitySystemMessage
+ {
+ }
+}
diff --git a/Content.Client/GameTicking/ClientGameTicker.cs b/Content.Client/GameTicking/ClientGameTicker.cs
index 2092c78424..bab225f1e9 100644
--- a/Content.Client/GameTicking/ClientGameTicker.cs
+++ b/Content.Client/GameTicking/ClientGameTicker.cs
@@ -91,6 +91,7 @@ namespace Content.Client.GameTicking
_lobby = null;
_gameChat?.Dispose();
_gameChat = null;
+ _gameHud.RootControl.Orphan();
}
public void FrameUpdate(RenderFrameEventArgs renderFrameEventArgs)
@@ -171,7 +172,7 @@ namespace Content.Client.GameTicking
_gameChat = null;
}
- _gameHud.RootControl.Parent?.RemoveChild(_gameHud.RootControl);
+ _gameHud.RootControl.Orphan();
_tickerState = TickerState.InLobby;
diff --git a/Content.Client/Interfaces/Chat/IChatManager.cs b/Content.Client/Interfaces/Chat/IChatManager.cs
index 41123d318a..989d044136 100644
--- a/Content.Client/Interfaces/Chat/IChatManager.cs
+++ b/Content.Client/Interfaces/Chat/IChatManager.cs
@@ -1,4 +1,6 @@
using Content.Client.Chat;
+using Robust.Client;
+using Robust.Shared.GameObjects;
namespace Content.Client.Interfaces.Chat
{
@@ -6,6 +8,10 @@ namespace Content.Client.Interfaces.Chat
{
void Initialize();
+ void FrameUpdate(RenderFrameEventArgs delta);
+
void SetChatBox(ChatBox chatBox);
+
+ void RemoveSpeechBubble(EntityUid entityUid, SpeechBubble bubble);
}
}
diff --git a/Content.Client/Parallax/ParallaxManager.cs b/Content.Client/Parallax/ParallaxManager.cs
index 74d18d0f47..f534472456 100644
--- a/Content.Client/Parallax/ParallaxManager.cs
+++ b/Content.Client/Parallax/ParallaxManager.cs
@@ -3,8 +3,6 @@ using System.IO;
using System.Threading.Tasks;
using Content.Client.Interfaces.Parallax;
using Nett;
-using SixLabors.ImageSharp;
-using SixLabors.Primitives;
using Robust.Client.Graphics;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Shared.Interfaces.Configuration;
@@ -12,6 +10,8 @@ using Robust.Shared.Interfaces.Log;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Utility;
+using SixLabors.ImageSharp;
+using SixLabors.Primitives;
namespace Content.Client.Parallax
{
@@ -39,7 +39,7 @@ namespace Content.Client.Parallax
return;
}
- MemoryStream configStream = null;
+ Stream configStream = null;
string contents;
TomlTable table;
try
diff --git a/Content.Client/UserInterface/NanoStyle.cs b/Content.Client/UserInterface/NanoStyle.cs
index 8ccab3bb5a..d9c7cba7b6 100644
--- a/Content.Client/UserInterface/NanoStyle.cs
+++ b/Content.Client/UserInterface/NanoStyle.cs
@@ -371,6 +371,11 @@ namespace Content.Client.UserInterface
new StyleProperty(PanelContainer.StylePropertyPanel, tooltipBox)
}),
+ new StyleRule(new SelectorElement(typeof(PanelContainer), new []{"tooltipBox"}, null, null), new[]
+ {
+ new StyleProperty(PanelContainer.StylePropertyPanel, tooltipBox)
+ }),
+
// Entity tooltip
new StyleRule(
new SelectorElement(typeof(PanelContainer), new[] {ExamineSystem.StyleClassEntityTooltip}, null,
diff --git a/Content.IntegrationTests/Content.IntegrationTests.csproj b/Content.IntegrationTests/Content.IntegrationTests.csproj
index 368600ff66..77e30e5314 100644
--- a/Content.IntegrationTests/Content.IntegrationTests.csproj
+++ b/Content.IntegrationTests/Content.IntegrationTests.csproj
@@ -28,5 +28,5 @@
..\RobustToolbox\Tools\
-
+
diff --git a/Content.Server/Chat/ChatManager.cs b/Content.Server/Chat/ChatManager.cs
index e07d2a401e..cc67d3a26c 100644
--- a/Content.Server/Chat/ChatManager.cs
+++ b/Content.Server/Chat/ChatManager.cs
@@ -1,13 +1,10 @@
using System.Linq;
-using System.Net.Http;
using Content.Server.Interfaces;
using Content.Server.Interfaces.Chat;
using Content.Shared.Chat;
using Robust.Server.Interfaces.Player;
-using Robust.Shared.Interfaces.Configuration;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
-using Robust.Shared.Interfaces.Resources;
using Robust.Shared.IoC;
namespace Content.Server.Chat
@@ -57,6 +54,7 @@ namespace Content.Server.Chat
msg.Channel = ChatChannel.Local;
msg.Message = message;
msg.MessageWrap = $"{source.Name} says, \"{{0}}\"";
+ msg.SenderEntity = source.Uid;
_netManager.ServerSendToMany(msg, clients.ToList());
}
diff --git a/Content.Server/EntryPoint.cs b/Content.Server/EntryPoint.cs
index 612d1633a4..04f1e61272 100644
--- a/Content.Server/EntryPoint.cs
+++ b/Content.Server/EntryPoint.cs
@@ -1,71 +1,22 @@
using Content.Server.Chat;
-using Content.Server.GameObjects;
-using Content.Server.GameObjects.Components;
-using Content.Server.GameObjects.Components.Power;
-using Content.Server.GameObjects.Components.Interactable.Tools;
-using Content.Server.Interfaces.GameObjects;
-using Content.Server.Placement;
-using Robust.Server;
-using Robust.Server.Interfaces;
-using Robust.Server.Interfaces.Maps;
-using Robust.Server.Interfaces.Player;
-using Robust.Server.Player;
-using Robust.Shared.Console;
-using Robust.Shared.ContentPack;
-using Robust.Shared.Enums;
-using Robust.Shared.Interfaces.GameObjects;
-using Robust.Shared.Interfaces.Map;
-using Robust.Shared.Interfaces.Timers;
-using Robust.Shared.IoC;
-using Robust.Shared.Log;
-using Robust.Shared.Map;
-using Robust.Shared.Timers;
-using Robust.Shared.Interfaces.Timing;
-using Robust.Shared.Maths;
-using Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan;
-using Content.Server.GameObjects.Components.Weapon.Ranged.Projectile;
-using Content.Server.GameObjects.Components.Projectiles;
-using Content.Server.GameObjects.Components.Weapon.Melee;
-using Content.Server.GameObjects.Components.Stack;
-using Content.Server.GameObjects.Components.Construction;
-using Content.Server.GameObjects.Components.Mobs;
-using Content.Server.GameObjects.EntitySystems;
-using Content.Server.Mobs;
-using Content.Server.Players;
-using Content.Server.GameObjects.Components.Interactable;
-using Content.Server.GameObjects.Components.Markers;
-using Content.Server.GameObjects.Components.Sound;
-using Content.Server.GameObjects.Components.Weapon.Ranged;
using Content.Server.GameTicking;
using Content.Server.Interfaces;
-using Content.Server.Interfaces.GameTicking;
-using Content.Shared.GameObjects.Components.Materials;
-using Content.Shared.GameObjects.Components.Inventory;
-using Content.Shared.GameObjects.Components.Markers;
-using Content.Shared.GameObjects.Components.Mobs;
-using Content.Shared.Interfaces;
-using Robust.Server.Interfaces.ServerStatus;
-using Robust.Shared.Timing;
-using Content.Server.GameObjects.Components.Destructible;
-using Content.Server.GameObjects.Components.Items.Storage;
-using Content.Server.GameObjects.Components.Items.Storage.Fill;
-using Content.Server.GameObjects.Components.Movement;
using Content.Server.Interfaces.Chat;
-using Content.Server.Interfaces.GameObjects.Components.Movement;
-using Content.Server.GameObjects.Components.Research;
-using Content.Shared.GameObjects.Components.Research;
+using Content.Server.Interfaces.GameTicking;
+using Content.Shared.Interfaces;
+using Robust.Server.Interfaces.Player;
+using Robust.Shared.ContentPack;
+using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Log;
-using Content.Server.GameObjects.Components.Explosive;
-using Content.Server.GameObjects.Components.Items;
-using Content.Server.GameObjects.Components.Triggers;
-using Content.Shared.GameObjects.Components.Movement;
+using Robust.Shared.IoC;
+using Robust.Shared.Log;
+using Robust.Shared.Timing;
namespace Content.Server
{
public class EntryPoint : GameServer
{
private IGameTicker _gameTicker;
- private IMoMMILink _mommiLink;
private StatusShell _statusShell;
///
@@ -75,127 +26,22 @@ namespace Content.Server
var factory = IoCManager.Resolve();
- factory.Register();
- factory.RegisterReference();
+ factory.DoAutoRegistrations();
- factory.Register();
+ var registerIgnore = new[]
+ {
+ "ConstructionGhost",
+ "IconSmooth",
+ "SubFloorHide",
+ "LowWall",
+ "Window",
+ "CharacterInfo"
+ };
- factory.Register();
- factory.Register();
- factory.RegisterReference();
- factory.Register();
- factory.RegisterReference();
- factory.RegisterReference();
- factory.Register();
-
- factory.Register();
- factory.Register();
- factory.Register();
- factory.Register();
- factory.RegisterReference();
-
- //Power Components
- factory.Register();
- factory.Register();
- factory.RegisterReference();
- factory.Register();
- factory.Register();
- factory.RegisterReference();
- factory.Register();
- factory.RegisterReference();
- factory.Register();
- factory.Register();
- factory.Register();
-
- //Tools
- factory.Register();
- factory.Register();
- factory.Register();
- factory.Register();
- factory.Register();
- factory.Register();
-
- factory.Register();
- factory.Register();
- factory.Register();
- factory.Register();
- factory.Register();
- factory.Register();
-
- factory.Register();
- factory.Register();
-
- factory.Register();
-
- factory.Register();
- factory.RegisterReference();
- factory.RegisterReference();
- factory.Register();
- factory.RegisterReference();
- factory.RegisterReference();
-
- factory.Register();
- factory.Register();
-
- factory.Register();
- factory.Register();
- factory.Register();
- factory.Register();
- factory.RegisterReference();
- factory.Register();
- factory.Register();
- factory.Register();
- factory.RegisterReference();
-
- factory.Register();
- factory.Register();
- factory.RegisterIgnore("ConstructionGhost");
-
- factory.Register();
- factory.Register();
- factory.Register();
-
- factory.Register();
- factory.RegisterReference();
-
- factory.Register();
- factory.RegisterReference();
- factory.Register();
-
- factory.RegisterReference();
-
- factory.Register();
- factory.Register();
-
- factory.Register();
-
- factory.Register();
- factory.RegisterReference();
-
- factory.RegisterIgnore("IconSmooth");
- factory.RegisterIgnore("SubFloorHide");
-
- factory.Register();
- factory.RegisterReference();
-
- factory.Register();
- factory.Register();
- factory.Register();
- factory.Register();
-
- factory.Register();
-
- factory.Register();
-
- factory.Register();
- factory.Register();
-
- factory.Register();
- factory.Register();
-
- factory.Register();
-
- factory.Register();
+ foreach (var ignoreName in registerIgnore)
+ {
+ factory.RegisterIgnore(ignoreName);
+ }
IoCManager.Register();
IoCManager.Register();
@@ -214,8 +60,6 @@ namespace Content.Server
IoCManager.Resolve().Initialize();
IoCManager.Resolve().Initialize();
- _mommiLink = IoCManager.Resolve();
-
var playerManager = IoCManager.Resolve();
_statusShell = new StatusShell();
diff --git a/Content.Server/GameObjects/Components/CatwalkComponent.cs b/Content.Server/GameObjects/Components/CatwalkComponent.cs
index 4e1769b210..4027c5045d 100644
--- a/Content.Server/GameObjects/Components/CatwalkComponent.cs
+++ b/Content.Server/GameObjects/Components/CatwalkComponent.cs
@@ -5,6 +5,7 @@ namespace Content.Server.GameObjects.Components
///
/// Literally just a marker component for footsteps for now.
///
+ [RegisterComponent]
public sealed class CatwalkComponent : Component
{
public override string Name => "Catwalk";
diff --git a/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs b/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs
new file mode 100644
index 0000000000..7398bd83c6
--- /dev/null
+++ b/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs
@@ -0,0 +1,142 @@
+using System;
+using Content.Shared.Chemistry;
+using Content.Shared.GameObjects;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Interfaces.GameObjects;
+
+namespace Content.Server.GameObjects.Components.Chemistry
+{
+ ///
+ /// Shared ECS component that manages a liquid solution of reagents.
+ ///
+ [RegisterComponent]
+ internal class SolutionComponent : Shared.GameObjects.Components.Chemistry.SolutionComponent
+ {
+ ///
+ /// Transfers solution from the held container to the target container.
+ ///
+ [Verb]
+ private sealed class FillTargetVerb : Verb
+ {
+ protected override string GetText(IEntity user, SolutionComponent component)
+ {
+ if(!user.TryGetComponent(out var hands))
+ return "";
+
+ if(hands.GetActiveHand == null)
+ return "";
+
+ var heldEntityName = hands.GetActiveHand.Owner?.Prototype?.Name ?? "- ";
+ var myName = component.Owner.Prototype?.Name ?? "
- ";
+
+ return $"Transfer liquid from [{heldEntityName}] to [{myName}].";
+ }
+
+ protected override VerbVisibility GetVisibility(IEntity user, SolutionComponent component)
+ {
+ if (user.TryGetComponent(out var hands))
+ {
+ if (hands.GetActiveHand != null)
+ {
+ if (hands.GetActiveHand.Owner.TryGetComponent(out var solution))
+ {
+ if ((solution.Capabilities & SolutionCaps.PourOut) != 0 && (component.Capabilities & SolutionCaps.PourIn) != 0)
+ return VerbVisibility.Visible;
+ }
+ }
+ }
+
+ return VerbVisibility.Invisible;
+ }
+
+ protected override void Activate(IEntity user, SolutionComponent component)
+ {
+ if (!user.TryGetComponent(out var hands))
+ return;
+
+ if (hands.GetActiveHand == null)
+ return;
+
+ if (!hands.GetActiveHand.Owner.TryGetComponent(out var handSolutionComp))
+ return;
+
+ if ((handSolutionComp.Capabilities & SolutionCaps.PourOut) == 0 || (component.Capabilities & SolutionCaps.PourIn) == 0)
+ return;
+
+ var transferQuantity = Math.Min(component.MaxVolume - component.CurrentVolume, handSolutionComp.CurrentVolume);
+ transferQuantity = Math.Min(transferQuantity, 10);
+
+ // nothing to transfer
+ if (transferQuantity <= 0)
+ return;
+
+ var transferSolution = handSolutionComp.SplitSolution(transferQuantity);
+ component.TryAddSolution(transferSolution);
+
+ }
+ }
+
+ ///
+ /// Transfers solution from a target container to the held container.
+ ///
+ [Verb]
+ private sealed class EmptyTargetVerb : Verb
+ {
+ protected override string GetText(IEntity user, SolutionComponent component)
+ {
+ if (!user.TryGetComponent(out var hands))
+ return "";
+
+ if (hands.GetActiveHand == null)
+ return "";
+
+ var heldEntityName = hands.GetActiveHand.Owner?.Prototype?.Name ?? "
- ";
+ var myName = component.Owner.Prototype?.Name ?? "
- ";
+
+ return $"Transfer liquid from [{myName}] to [{heldEntityName}].";
+ }
+
+ protected override VerbVisibility GetVisibility(IEntity user, SolutionComponent component)
+ {
+ if (user.TryGetComponent(out var hands))
+ {
+ if (hands.GetActiveHand != null)
+ {
+ if (hands.GetActiveHand.Owner.TryGetComponent(out var solution))
+ {
+ if ((solution.Capabilities & SolutionCaps.PourIn) != 0 && (component.Capabilities & SolutionCaps.PourOut) != 0)
+ return VerbVisibility.Visible;
+ }
+ }
+ }
+
+ return VerbVisibility.Invisible;
+ }
+
+ protected override void Activate(IEntity user, SolutionComponent component)
+ {
+ if (!user.TryGetComponent(out var hands))
+ return;
+
+ if (hands.GetActiveHand == null)
+ return;
+
+ if(!hands.GetActiveHand.Owner.TryGetComponent(out var handSolutionComp))
+ return;
+
+ if ((handSolutionComp.Capabilities & SolutionCaps.PourIn) == 0 || (component.Capabilities & SolutionCaps.PourOut) == 0)
+ return;
+
+ var transferQuantity = Math.Min(handSolutionComp.MaxVolume - handSolutionComp.CurrentVolume, component.CurrentVolume);
+ transferQuantity = Math.Min(transferQuantity, 10);
+
+ // pulling from an empty container, pointless to continue
+ if (transferQuantity <= 0)
+ return;
+
+ var transferSolution = component.SplitSolution(transferQuantity);
+ handSolutionComp.TryAddSolution(transferSolution);
+ }
+ }
+ }
+}
diff --git a/Content.Server/GameObjects/Components/Construction/ConstructionComponent.cs b/Content.Server/GameObjects/Components/Construction/ConstructionComponent.cs
index 4e35820fd6..86e64d2b5c 100644
--- a/Content.Server/GameObjects/Components/Construction/ConstructionComponent.cs
+++ b/Content.Server/GameObjects/Components/Construction/ConstructionComponent.cs
@@ -17,6 +17,7 @@ using static Content.Shared.Construction.ConstructionStepTool;
namespace Content.Server.GameObjects.Components.Construction
{
+ [RegisterComponent]
public class ConstructionComponent : Component, IAttackBy
{
public override string Name => "Construction";
diff --git a/Content.Server/GameObjects/Components/Construction/ConstructorComponent.cs b/Content.Server/GameObjects/Components/Construction/ConstructorComponent.cs
index 2c58b26c14..8f13d8cf23 100644
--- a/Content.Server/GameObjects/Components/Construction/ConstructorComponent.cs
+++ b/Content.Server/GameObjects/Components/Construction/ConstructorComponent.cs
@@ -3,13 +3,11 @@ using Content.Server.GameObjects.Components.Stack;
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.Construction;
using Content.Shared.GameObjects.Components.Construction;
-using Robust.Server.GameObjects;
using Robust.Server.GameObjects.EntitySystems;
using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.GameObjects;
-using Robust.Shared.Interfaces.Map;
using Robust.Shared.Interfaces.GameObjects;
-using Robust.Shared.Interfaces.GameObjects.Components;
+using Robust.Shared.Interfaces.Map;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.Map;
@@ -18,6 +16,7 @@ using Robust.Shared.Prototypes;
namespace Content.Server.GameObjects.Components.Construction
{
+ [RegisterComponent]
public class ConstructorComponent : SharedConstructorComponent
{
#pragma warning disable 649
diff --git a/Content.Server/GameObjects/Components/Damage/DamageableComponent.cs b/Content.Server/GameObjects/Components/Damage/DamageableComponent.cs
index 52b3c663c2..46909bf75f 100644
--- a/Content.Server/GameObjects/Components/Damage/DamageableComponent.cs
+++ b/Content.Server/GameObjects/Components/Damage/DamageableComponent.cs
@@ -1,12 +1,9 @@
-using Content.Server.Interfaces.GameObjects;
-using System;
+using System;
using System.Collections.Generic;
-using Robust.Shared.Maths;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Utility;
-using YamlDotNet.RepresentationModel;
using Content.Server.Interfaces;
+using Content.Server.Interfaces.GameObjects;
using Content.Shared.GameObjects;
+using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
@@ -18,6 +15,7 @@ namespace Content.Server.GameObjects
/// A component that handles receiving damage and healing,
/// as well as informing other components of it.
///
+ [RegisterComponent]
public class DamageableComponent : SharedDamageableComponent, IDamageableComponent
{
///
diff --git a/Content.Server/GameObjects/Components/Damage/DestructibleComponent.cs b/Content.Server/GameObjects/Components/Damage/DestructibleComponent.cs
index daa1355754..d5efd91802 100644
--- a/Content.Server/GameObjects/Components/Damage/DestructibleComponent.cs
+++ b/Content.Server/GameObjects/Components/Damage/DestructibleComponent.cs
@@ -1,21 +1,21 @@
using System;
using System.Collections.Generic;
+using Content.Server.GameObjects.EntitySystems;
+using Content.Server.Interfaces;
+using Content.Shared.GameObjects;
using Robust.Shared.GameObjects;
-using Robust.Shared.Serialization;
-using Robust.Shared.ViewVariables;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
-using Robust.Shared.Log;
using Robust.Shared.Maths;
-using Content.Server.Interfaces;
-using Content.Server.GameObjects.EntitySystems;
-using Content.Shared.GameObjects;
+using Robust.Shared.Serialization;
+using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Destructible
{
///
/// Deletes the entity once a certain damage threshold has been reached.
///
+ [RegisterComponent]
public class DestructibleComponent : Component, IOnDamageBehavior, IDestroyAct, IExAct
{
#pragma warning disable 649
@@ -63,7 +63,7 @@ namespace Content.Server.GameObjects.Components.Destructible
///
void IOnDamageBehavior.OnDamageThresholdPassed(object obj, DamageThresholdPassedEventArgs e)
- {
+ {
if (e.Passed && e.DamageThreshold == Threshold && destroyed == false)
{
destroyed = true;
diff --git a/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs b/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs
index 6f9957d617..3ddee7f3bf 100644
--- a/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs
+++ b/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs
@@ -10,6 +10,8 @@ using Robust.Shared.Timers;
namespace Content.Server.GameObjects
{
+ [RegisterComponent]
+ [ComponentReference(typeof(IActivate))]
public class ServerDoorComponent : Component, IActivate
{
public override string Name => "Door";
diff --git a/Content.Server/GameObjects/Components/Explosion/ExplosiveComponent.cs b/Content.Server/GameObjects/Components/Explosion/ExplosiveComponent.cs
index a5e401efd6..656ccd4c5a 100644
--- a/Content.Server/GameObjects/Components/Explosion/ExplosiveComponent.cs
+++ b/Content.Server/GameObjects/Components/Explosion/ExplosiveComponent.cs
@@ -1,28 +1,27 @@
using System;
using System.Linq;
-using System.Collections.Generic;
using Content.Server.GameObjects.Components.Mobs;
-using Robust.Server.Interfaces.GameObjects;
+using Content.Server.GameObjects.EntitySystems;
+using Content.Shared.Maps;
using Robust.Server.GameObjects.EntitySystems;
-using Robust.Shared.GameObjects.EntitySystemMessages;
+using Robust.Server.Interfaces.GameObjects;
+using Robust.Server.Interfaces.Player;
using Robust.Shared.GameObjects;
-using Robust.Shared.Interfaces.Timing;
-using Robust.Shared.Interfaces.Map;
+using Robust.Shared.GameObjects.EntitySystemMessages;
using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.Interfaces.Map;
+using Robust.Shared.Interfaces.Timing;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Serialization;
-using Content.Server.GameObjects.EntitySystems;
-using Content.Shared.GameObjects;
-using Content.Shared.Maps;
-using Robust.Server.Interfaces.Player;
namespace Content.Server.GameObjects.Components.Explosive
{
+ [RegisterComponent]
public class ExplosiveComponent : Component, ITimerTrigger, IDestroyAct
{
-#pragma warning disable 649
+#pragma warning disable 649
[Dependency] private readonly ITileDefinitionManager _tileDefinitionManager;
[Dependency] private readonly IMapManager _mapManager;
[Dependency] private readonly IServerEntityManager _serverEntityManager;
@@ -66,7 +65,7 @@ namespace Content.Server.GameObjects.Components.Explosive
if (distanceFromEntity < DevastationRange)
{
severity = ExplosionSeverity.Destruction;
- }
+ }
else if (distanceFromEntity < HeavyImpactRange)
{
severity = ExplosionSeverity.Heavy;
diff --git a/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs b/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs
index baf092315f..0f71bd3b92 100644
--- a/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs
+++ b/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs
@@ -5,8 +5,8 @@ using Content.Shared.GameObjects;
using Robust.Server.GameObjects.Components.Container;
using Robust.Server.Interfaces.Player;
using Robust.Shared.GameObjects;
-using Robust.Shared.Interfaces.GameObjects.Components;
using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.Interfaces.GameObjects.Components;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.Utility;
@@ -16,6 +16,7 @@ using static Content.Shared.GameObjects.SharedInventoryComponent.ClientInventory
namespace Content.Server.GameObjects
{
+ [RegisterComponent]
public class InventoryComponent : SharedInventoryComponent
{
[ViewVariables]
diff --git a/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs b/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs
index a2477d2d2a..7b42e79451 100644
--- a/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs
+++ b/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs
@@ -3,16 +3,12 @@ using System.Collections.Generic;
using Content.Server.GameObjects.EntitySystems;
using Content.Server.Interfaces.GameObjects;
using Content.Shared.GameObjects;
-using Content.Shared.Input;
-using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Server.GameObjects.Components.Container;
using Robust.Server.GameObjects.EntitySystemMessages;
using Robust.Server.Interfaces.Player;
using Robust.Shared.GameObjects;
-using Robust.Shared.Input;
using Robust.Shared.Interfaces.GameObjects;
-using Robust.Shared.Interfaces.GameObjects.Components;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.Log;
@@ -24,6 +20,8 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects
{
+ [RegisterComponent]
+ [ComponentReference(typeof(IHandsComponent))]
public class HandsComponent : SharedHandsComponent, IHandsComponent
{
#pragma warning disable 649
diff --git a/Content.Server/GameObjects/Components/Healing/HealingComponent.cs b/Content.Server/GameObjects/Components/Healing/HealingComponent.cs
index 82b5420fe6..5fb3bdc7cc 100644
--- a/Content.Server/GameObjects/Components/Healing/HealingComponent.cs
+++ b/Content.Server/GameObjects/Components/Healing/HealingComponent.cs
@@ -1,21 +1,12 @@
-using System;
-using Content.Server.GameObjects.Components.Stack;
-using Robust.Shared.GameObjects;
+using Content.Server.GameObjects.Components.Stack;
using Content.Server.GameObjects.EntitySystems;
-using Robust.Shared.Interfaces.GameObjects;
-using Robust.Shared.Map;
-using Robust.Shared.IoC;
-using Robust.Server.GameObjects;
-using Robust.Shared.Maths;
-using Robust.Server.Interfaces.GameObjects;
-using Robust.Shared.Interfaces.Timing;
-using Robust.Shared.GameObjects.EntitySystemMessages;
-using Robust.Shared.Serialization;
-using Robust.Shared.Interfaces.GameObjects.Components;
using Content.Shared.GameObjects;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization;
namespace Content.Server.GameObjects.Components.Weapon.Melee
{
+ [RegisterComponent]
public class HealingComponent : Component, IAfterAttack, IUse
{
public override string Name => "Healing";
diff --git a/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs b/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs
index e827658d2b..8f7817f775 100644
--- a/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs
+++ b/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs
@@ -1,11 +1,11 @@
using Content.Server.GameObjects.Components.Power;
+using Content.Server.GameObjects.Components.Sound;
using Content.Server.GameObjects.EntitySystems;
using Content.Server.Interfaces.GameObjects;
using Content.Shared.GameObjects;
using Robust.Server.GameObjects;
using Robust.Server.GameObjects.Components.Container;
using Robust.Server.Interfaces.GameObjects;
-using Robust.Shared.Enums;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Utility;
@@ -16,6 +16,7 @@ namespace Content.Server.GameObjects.Components.Interactable
///
/// Component that represents a handheld lightsource which can be toggled on and off.
///
+ [RegisterComponent]
internal class HandheldLightComponent : Component, IUse, IExamine, IAttackBy, IMapInit
{
public const float Wattage = 10;
@@ -50,9 +51,20 @@ namespace Content.Server.GameObjects.Components.Interactable
if (Cell != null) return false;
- eventArgs.User.GetComponent().Drop(eventArgs.AttackWith, _cellContainer);
+ var handsComponent = eventArgs.User.GetComponent();
+
+ if (!handsComponent.Drop(eventArgs.AttackWith, _cellContainer))
+ {
+ return false;
+ }
+
+ if (Owner.TryGetComponent(out SoundComponent soundComponent))
+ {
+ soundComponent.Play("/Audio/items/weapons/pistol_magin.ogg");
+ }
+
+ return true;
- return _cellContainer.Insert(eventArgs.AttackWith);
}
void IExamine.Examine(FormattedMessage message)
@@ -85,17 +97,14 @@ namespace Content.Server.GameObjects.Components.Interactable
/// True if the light's status was toggled, false otherwise.
public bool ToggleStatus()
{
- // Update the activation state.
- Activated = !Activated;
-
// Update sprite and light states to match the activation.
if (Activated)
{
- SetState(LightState.On);
+ TurnOff();
}
else
{
- SetState(LightState.Off);
+ TurnOn();
}
// Toggle always succeeds.
@@ -104,34 +113,66 @@ namespace Content.Server.GameObjects.Components.Interactable
public void TurnOff()
{
- if (!Activated) return;
+ if (!Activated)
+ {
+ return;
+ }
- SetState(LightState.Off);
+ SetState(false);
Activated = false;
+
+ if (Owner.TryGetComponent(out SoundComponent soundComponent))
+ {
+ soundComponent.Play("/Audio/items/flashlight_toggle.ogg");
+ }
}
public void TurnOn()
{
- if (Activated) return;
+ if (Activated)
+ {
+ return;
+ }
var cell = Cell;
- if (cell == null) return;
+ SoundComponent soundComponent;
+ if (cell == null)
+ {
+ if (Owner.TryGetComponent(out soundComponent))
+ {
+ soundComponent.Play("/Audio/machines/button.ogg");
+ }
+ return;
+ }
// To prevent having to worry about frame time in here.
// Let's just say you need a whole second of charge before you can turn it on.
// Simple enough.
- if (cell.AvailableCharge(1) < Wattage) return;
+ if (cell.AvailableCharge(1) < Wattage)
+ {
+ if (Owner.TryGetComponent(out soundComponent))
+ {
+ soundComponent.Play("/Audio/machines/button.ogg");
+ }
+ return;
+ }
- SetState(LightState.On);
+ Activated = true;
+ SetState(true);
+
+ if (Owner.TryGetComponent(out soundComponent))
+ {
+ soundComponent.Play("/Audio/items/flashlight_toggle.ogg");
+ }
}
- private void SetState(LightState newState)
+ private void SetState(bool on)
{
- _spriteComponent.LayerSetVisible(1, newState == LightState.On);
- _pointLight.State = newState;
+ _spriteComponent.LayerSetVisible(1, on);
+ _pointLight.Enabled = on;
if (_clothingComponent != null)
{
- _clothingComponent.ClothingEquippedPrefix = newState.ToString();
+ _clothingComponent.ClothingEquippedPrefix = on ? "On" : "Off";
}
}
@@ -145,15 +186,32 @@ namespace Content.Server.GameObjects.Components.Interactable
private void EjectCell(IEntity user)
{
- if (Cell == null) return;
+ if (Cell == null)
+ {
+ return;
+ }
var cell = Cell;
- if (!_cellContainer.Remove(cell.Owner)) return;
+ if (!_cellContainer.Remove(cell.Owner))
+ {
+ return;
+ }
- if (!user.TryGetComponent(out HandsComponent hands)
- || !hands.PutInHand(cell.Owner.GetComponent()))
+ if (!user.TryGetComponent(out HandsComponent hands))
+ {
+ return;
+ }
+
+ if (!hands.PutInHand(cell.Owner.GetComponent()))
+ {
cell.Owner.Transform.GridPosition = user.Transform.GridPosition;
+ }
+
+ if (Owner.TryGetComponent(out SoundComponent soundComponent))
+ {
+ soundComponent.Play("/Audio/items/weapons/pistol_magout.ogg");
+ }
}
[Verb]
diff --git a/Content.Server/GameObjects/Components/Interactable/Tools/CrowbarComponent.cs b/Content.Server/GameObjects/Components/Interactable/Tools/CrowbarComponent.cs
index 3b7c0af218..2f61ad57ed 100644
--- a/Content.Server/GameObjects/Components/Interactable/Tools/CrowbarComponent.cs
+++ b/Content.Server/GameObjects/Components/Interactable/Tools/CrowbarComponent.cs
@@ -1,6 +1,7 @@
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.Maps;
using Robust.Server.GameObjects.EntitySystems;
+using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC;
@@ -8,6 +9,7 @@ using Robust.Shared.Map;
namespace Content.Server.GameObjects.Components.Interactable.Tools
{
+ [RegisterComponent]
public class CrowbarComponent : ToolComponent, IAfterAttack
{
#pragma warning disable 649
diff --git a/Content.Server/GameObjects/Components/Interactable/Tools/MultitoolComponent.cs b/Content.Server/GameObjects/Components/Interactable/Tools/MultitoolComponent.cs
index 92f1972962..7493374f57 100644
--- a/Content.Server/GameObjects/Components/Interactable/Tools/MultitoolComponent.cs
+++ b/Content.Server/GameObjects/Components/Interactable/Tools/MultitoolComponent.cs
@@ -1,10 +1,13 @@
-namespace Content.Server.GameObjects.Components.Interactable.Tools
+using Robust.Shared.GameObjects;
+
+namespace Content.Server.GameObjects.Components.Interactable.Tools
{
///
/// Tool used for interfacing/hacking into configurable computers
///
+ [RegisterComponent]
public class MultitoolComponent : ToolComponent
{
public override string Name => "Multitool";
}
-}
\ No newline at end of file
+}
diff --git a/Content.Server/GameObjects/Components/Interactable/Tools/ScrewdriverComponent.cs b/Content.Server/GameObjects/Components/Interactable/Tools/ScrewdriverComponent.cs
index 9095a3b2c8..8f69c1b2c7 100644
--- a/Content.Server/GameObjects/Components/Interactable/Tools/ScrewdriverComponent.cs
+++ b/Content.Server/GameObjects/Components/Interactable/Tools/ScrewdriverComponent.cs
@@ -1,5 +1,8 @@
-namespace Content.Server.GameObjects.Components.Interactable.Tools
+using Robust.Shared.GameObjects;
+
+namespace Content.Server.GameObjects.Components.Interactable.Tools
{
+ [RegisterComponent]
public class ScrewdriverComponent : ToolComponent
{
///
@@ -7,4 +10,4 @@
///
public override string Name => "Screwdriver";
}
-}
\ No newline at end of file
+}
diff --git a/Content.Server/GameObjects/Components/Interactable/Tools/WelderComponent.cs b/Content.Server/GameObjects/Components/Interactable/Tools/WelderComponent.cs
index cb1e6597b7..a7de418d8f 100644
--- a/Content.Server/GameObjects/Components/Interactable/Tools/WelderComponent.cs
+++ b/Content.Server/GameObjects/Components/Interactable/Tools/WelderComponent.cs
@@ -1,12 +1,10 @@
using System;
-using System.Text;
-using Robust.Shared.Interfaces.GameObjects;
-using Robust.Shared.Utility;
-using YamlDotNet.RepresentationModel;
-using Robust.Server.GameObjects;
using Content.Server.GameObjects.EntitySystems;
+using Robust.Server.GameObjects;
+using Robust.Shared.GameObjects;
using Robust.Shared.Maths;
using Robust.Shared.Serialization;
+using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Interactable.Tools
@@ -14,6 +12,7 @@ namespace Content.Server.GameObjects.Components.Interactable.Tools
///
/// Tool used to weld metal together, light things on fire, or melt into constituent parts
///
+ [RegisterComponent]
class WelderComponent : ToolComponent, EntitySystems.IUse, EntitySystems.IExamine
{
SpriteComponent spriteComponent;
diff --git a/Content.Server/GameObjects/Components/Interactable/Tools/WirecutterComponent.cs b/Content.Server/GameObjects/Components/Interactable/Tools/WirecutterComponent.cs
index 8f7edaa0d3..bc7568c381 100644
--- a/Content.Server/GameObjects/Components/Interactable/Tools/WirecutterComponent.cs
+++ b/Content.Server/GameObjects/Components/Interactable/Tools/WirecutterComponent.cs
@@ -1,10 +1,13 @@
-namespace Content.Server.GameObjects.Components.Interactable.Tools
+using Robust.Shared.GameObjects;
+
+namespace Content.Server.GameObjects.Components.Interactable.Tools
{
///
/// Tool that can be used for some cutting interactions such as wires or hacking
///
+ [RegisterComponent]
public class WirecutterComponent : ToolComponent
{
public override string Name => "Wirecutter";
}
-}
\ No newline at end of file
+}
diff --git a/Content.Server/GameObjects/Components/Interactable/Tools/WrenchComponent.cs b/Content.Server/GameObjects/Components/Interactable/Tools/WrenchComponent.cs
index 1b69b39ee9..8bb24680d9 100644
--- a/Content.Server/GameObjects/Components/Interactable/Tools/WrenchComponent.cs
+++ b/Content.Server/GameObjects/Components/Interactable/Tools/WrenchComponent.cs
@@ -1,10 +1,13 @@
-namespace Content.Server.GameObjects.Components.Interactable.Tools
+using Robust.Shared.GameObjects;
+
+namespace Content.Server.GameObjects.Components.Interactable.Tools
{
///
/// Wrenches bolts, and interacts with things that have been bolted
///
+ [RegisterComponent]
public class WrenchComponent : ToolComponent
{
public override string Name => "Wrench";
}
-}
\ No newline at end of file
+}
diff --git a/Content.Server/GameObjects/Components/Items/Clothing/ClothingComponent.cs b/Content.Server/GameObjects/Components/Items/Clothing/ClothingComponent.cs
index 6235e24ee0..4a216d5b12 100644
--- a/Content.Server/GameObjects/Components/Items/Clothing/ClothingComponent.cs
+++ b/Content.Server/GameObjects/Components/Items/Clothing/ClothingComponent.cs
@@ -1,15 +1,18 @@
+using System;
+using System.Collections.Generic;
+using Content.Server.GameObjects.EntitySystems;
using Content.Shared.GameObjects;
using Content.Shared.GameObjects.Components.Items;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;
-using System;
-using System.Collections.Generic;
-using Content.Server.GameObjects.EntitySystems;
using Robust.Shared.Utility;
using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines;
namespace Content.Server.GameObjects
{
+ [RegisterComponent]
+ [ComponentReference(typeof(ItemComponent))]
+ [ComponentReference(typeof(StoreableComponent))]
public class ClothingComponent : ItemComponent, IUse
{
public override string Name => "Clothing";
diff --git a/Content.Server/GameObjects/Components/Items/DiceComponent.cs b/Content.Server/GameObjects/Components/Items/DiceComponent.cs
index 78915e44de..ef9b10afb2 100644
--- a/Content.Server/GameObjects/Components/Items/DiceComponent.cs
+++ b/Content.Server/GameObjects/Components/Items/DiceComponent.cs
@@ -6,7 +6,6 @@ using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
-using Robust.Shared.Log;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
@@ -15,6 +14,7 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Items
{
+ [RegisterComponent]
public class DiceComponent : Component, IActivate, IUse, ILand, IExamine
{
#pragma warning disable 649
diff --git a/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs
index 327c8a089d..7ea736315b 100644
--- a/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs
+++ b/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs
@@ -1,4 +1,9 @@
-using Content.Server.GameObjects.EntitySystems;
+using System.Linq;
+using Content.Server.GameObjects.Components.Items.Storage;
+using Content.Server.GameObjects.Components.Sound;
+using Content.Server.GameObjects.EntitySystems;
+using Content.Shared.GameObjects.Components.Storage;
+using Robust.Server.GameObjects;
using Robust.Server.GameObjects.Components.Container;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
@@ -7,13 +12,12 @@ using Robust.Shared.Interfaces.Network;
using Robust.Shared.Maths;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
-using System.Linq;
-using Content.Server.GameObjects.Components.Items.Storage;
-using Content.Shared.GameObjects.Components.Storage;
-using Robust.Server.GameObjects;
namespace Content.Server.GameObjects.Components
{
+ [RegisterComponent]
+ [ComponentReference(typeof(IActivate))]
+ [ComponentReference(typeof(IStorageComponent))]
public class EntityStorageComponent : Component, IActivate, IStorageComponent
{
public override string Name => "EntityStorage";
@@ -70,7 +74,12 @@ namespace Content.Server.GameObjects.Components
break;
}
}
+
ModifyComponents();
+ if (Owner.TryGetComponent(out SoundComponent soundComponent))
+ {
+ soundComponent.Play("/Audio/machines/closetclose.ogg");
+ }
}
private void OpenStorage()
@@ -78,10 +87,14 @@ namespace Content.Server.GameObjects.Components
Open = true;
EmptyContents();
ModifyComponents();
+ if (Owner.TryGetComponent(out SoundComponent soundComponent))
+ {
+ soundComponent.Play("/Audio/machines/closetopen.ogg");
+ }
}
private void ModifyComponents()
- {
+ {
if (Owner.TryGetComponent(out var collidableComponent))
{
collidableComponent.CollisionEnabled = IsCollidableWhenOpen || !Open;
diff --git a/Content.Server/GameObjects/Components/Items/Storage/Fill/ToolLockerFillComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/Fill/ToolLockerFillComponent.cs
index 7071481fa1..d84e55d2f8 100644
--- a/Content.Server/GameObjects/Components/Items/Storage/Fill/ToolLockerFillComponent.cs
+++ b/Content.Server/GameObjects/Components/Items/Storage/Fill/ToolLockerFillComponent.cs
@@ -7,6 +7,7 @@ using Robust.Shared.Maths;
namespace Content.Server.GameObjects.Components.Items.Storage.Fill
{
+ [RegisterComponent]
internal sealed class ToolLockerFillComponent : Component, IMapInit
{
public override string Name => "ToolLockerFill";
diff --git a/Content.Server/GameObjects/Components/Items/Storage/Fill/ToolboxElectricalFillComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/Fill/ToolboxElectricalFillComponent.cs
index 40161e7c88..95227b7141 100644
--- a/Content.Server/GameObjects/Components/Items/Storage/Fill/ToolboxElectricalFillComponent.cs
+++ b/Content.Server/GameObjects/Components/Items/Storage/Fill/ToolboxElectricalFillComponent.cs
@@ -7,6 +7,7 @@ using Robust.Shared.Maths;
namespace Content.Server.GameObjects.Components.Items.Storage.Fill
{
+ [RegisterComponent]
internal sealed class ToolboxElectricalFillComponent : Component, IMapInit
{
public override string Name => "ToolboxElectricalFill";
diff --git a/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs
index 85f1668b5f..a5d61d955d 100644
--- a/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs
+++ b/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs
@@ -1,17 +1,18 @@
-using Content.Server.Interfaces.GameObjects;
-using Robust.Server.Interfaces.GameObjects;
-using Content.Shared.GameObjects;
-using Robust.Shared.Interfaces.GameObjects;
+using System;
using Content.Server.GameObjects.EntitySystems;
-using Robust.Shared.GameObjects;
-using System;
+using Content.Server.Interfaces.GameObjects;
+using Content.Shared.GameObjects;
using Content.Shared.GameObjects.Components.Items;
-using Content.Server.GameObjects.Components;
using Robust.Server.GameObjects;
+using Robust.Server.Interfaces.GameObjects;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Maths;
namespace Content.Server.GameObjects
{
+ [RegisterComponent]
+ [ComponentReference(typeof(StoreableComponent))]
public class ItemComponent : StoreableComponent, IAttackHand
{
public override string Name => "Item";
diff --git a/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs
index 49b3ec9550..b50a8b9ff4 100644
--- a/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs
+++ b/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs
@@ -1,32 +1,33 @@
-using System.Linq;
+using System.Collections.Generic;
+using System.Linq;
+using Content.Server.GameObjects.Components;
+using Content.Server.GameObjects.Components.Items.Storage;
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.GameObjects.Components.Storage;
+using Content.Shared.Interfaces;
using Robust.Server.GameObjects;
using Robust.Server.GameObjects.Components.Container;
+using Robust.Server.GameObjects.EntitySystemMessages;
using Robust.Server.Interfaces.Player;
using Robust.Server.Player;
using Robust.Shared.Enums;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.GameObjects.Components;
+using Robust.Shared.Interfaces.Map;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Serialization;
-using System.Collections.Generic;
-using Content.Shared.Interfaces;
-using Robust.Shared.GameObjects.EntitySystemMessages;
-using Robust.Shared.Interfaces.Map;
-using Robust.Shared.ViewVariables;
-using Content.Server.GameObjects.Components;
-using Content.Server.GameObjects.Components.Items.Storage;
-using Robust.Server.GameObjects.EntitySystemMessages;
namespace Content.Server.GameObjects
{
///
/// Storage component for containing entities within this one, matches a UI on the client which shows stored entities
///
+ [RegisterComponent]
+ [ComponentReference(typeof(IActivate))]
+ [ComponentReference(typeof(IStorageComponent))]
public class ServerStorageComponent : SharedStorageComponent, IAttackBy, IUse, IActivate, IStorageComponent, IDestroyAct
{
#pragma warning disable 649
@@ -150,7 +151,7 @@ namespace Content.Server.GameObjects
{
return false;
}
-
+
//Check that we can drop the item from our hands first otherwise we obviously cant put it inside
if (CanInsert(hands.GetActiveHand.Owner) && hands.Drop(hands.ActiveIndex))
{
diff --git a/Content.Server/GameObjects/Components/Items/Storage/StoreableComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/StoreableComponent.cs
index b800fc58fa..7f25245112 100644
--- a/Content.Server/GameObjects/Components/Items/Storage/StoreableComponent.cs
+++ b/Content.Server/GameObjects/Components/Items/Storage/StoreableComponent.cs
@@ -3,6 +3,7 @@ using Robust.Shared.Serialization;
namespace Content.Server.GameObjects
{
+ [RegisterComponent]
public class StoreableComponent : Component
{
public override string Name => "Storeable";
diff --git a/Content.Server/GameObjects/Components/Markers/SpawnPointComponent.cs b/Content.Server/GameObjects/Components/Markers/SpawnPointComponent.cs
index 318931dbd8..7c8ea4f4e4 100644
--- a/Content.Server/GameObjects/Components/Markers/SpawnPointComponent.cs
+++ b/Content.Server/GameObjects/Components/Markers/SpawnPointComponent.cs
@@ -1,4 +1,3 @@
-using System;
using Content.Shared.GameObjects.Components.Markers;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;
@@ -6,6 +5,8 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Markers
{
+ [RegisterComponent]
+ [ComponentReference(typeof(SharedSpawnPointComponent))]
public sealed class SpawnPointComponent : SharedSpawnPointComponent
{
private SpawnPointType _spawnType;
diff --git a/Content.Server/GameObjects/Components/Mobs/CameraRecoilComponent.cs b/Content.Server/GameObjects/Components/Mobs/CameraRecoilComponent.cs
index ce2c3e76ed..42fc2fba63 100644
--- a/Content.Server/GameObjects/Components/Mobs/CameraRecoilComponent.cs
+++ b/Content.Server/GameObjects/Components/Mobs/CameraRecoilComponent.cs
@@ -1,8 +1,11 @@
using Content.Shared.GameObjects.Components.Mobs;
+using Robust.Shared.GameObjects;
using Robust.Shared.Maths;
namespace Content.Server.GameObjects.Components.Mobs
{
+ [RegisterComponent]
+ [ComponentReference(typeof(SharedCameraRecoilComponent))]
public sealed class CameraRecoilComponent : SharedCameraRecoilComponent
{
public override void Kick(Vector2 recoil)
diff --git a/Content.Server/GameObjects/Components/Mobs/CombatModeComponent.cs b/Content.Server/GameObjects/Components/Mobs/CombatModeComponent.cs
index 3b962f03d7..d5078ec107 100644
--- a/Content.Server/GameObjects/Components/Mobs/CombatModeComponent.cs
+++ b/Content.Server/GameObjects/Components/Mobs/CombatModeComponent.cs
@@ -8,6 +8,7 @@ namespace Content.Server.GameObjects.Components.Mobs
/// This is used to differentiate between regular item interactions or
/// using *everything* as a weapon.
///
+ [RegisterComponent]
public sealed class CombatModeComponent : Component
{
public override string Name => "CombatMode";
diff --git a/Content.Server/GameObjects/Components/Mobs/HeatResistanceComponent.cs b/Content.Server/GameObjects/Components/Mobs/HeatResistanceComponent.cs
index 193d215d9a..8d3283fe25 100644
--- a/Content.Server/GameObjects/Components/Mobs/HeatResistanceComponent.cs
+++ b/Content.Server/GameObjects/Components/Mobs/HeatResistanceComponent.cs
@@ -1,9 +1,10 @@
using System;
-using Robust.Shared.GameObjects;
using Content.Shared.GameObjects.Components.Inventory;
+using Robust.Shared.GameObjects;
namespace Content.Server.GameObjects
{
+ [RegisterComponent]
public class HeatResistanceComponent : Component
{
public override string Name => "HeatResistance";
diff --git a/Content.Server/GameObjects/Components/Mobs/MindComponent.cs b/Content.Server/GameObjects/Components/Mobs/MindComponent.cs
index 061d2d5315..882d827969 100644
--- a/Content.Server/GameObjects/Components/Mobs/MindComponent.cs
+++ b/Content.Server/GameObjects/Components/Mobs/MindComponent.cs
@@ -1,14 +1,6 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Content.Server.Mobs;
-using Robust.Server.GameObjects;
+using Content.Server.Mobs;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
-using Robust.Shared.Interfaces.Network;
-using Robust.Shared.Log;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Mobs
@@ -16,6 +8,7 @@ namespace Content.Server.GameObjects.Components.Mobs
///
/// Stores a on a mob.
///
+ [RegisterComponent]
public class MindComponent : Component
{
///
diff --git a/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs b/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs
index 86029362a9..f703d53cea 100644
--- a/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs
+++ b/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs
@@ -12,6 +12,7 @@ using Robust.Shared.Serialization;
namespace Content.Server.GameObjects
{
+ [RegisterComponent]
public class SpeciesComponent : SharedSpeciesComponent, IActionBlocker, IOnDamageBehavior, IExAct
{
///
diff --git a/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs b/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs
index 1c0647e244..686b097f46 100644
--- a/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs
+++ b/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs
@@ -5,6 +5,7 @@ using Robust.Shared.Serialization;
namespace Content.Server.GameObjects.Components.Movement
{
+ [RegisterComponent]
public class AiControllerComponent : Component, IMoverComponent
{
private string _logicName;
diff --git a/Content.Server/GameObjects/Components/Movement/PlayerInputMoverComponent.cs b/Content.Server/GameObjects/Components/Movement/PlayerInputMoverComponent.cs
index 645463a437..889a0d08ac 100644
--- a/Content.Server/GameObjects/Components/Movement/PlayerInputMoverComponent.cs
+++ b/Content.Server/GameObjects/Components/Movement/PlayerInputMoverComponent.cs
@@ -12,6 +12,8 @@ namespace Content.Server.GameObjects.Components.Movement
///
/// Moves the entity based on input from a KeyBindingInputComponent.
///
+ [RegisterComponent]
+ [ComponentReference(typeof(IMoverComponent))]
public class PlayerInputMoverComponent : Component, IMoverComponent
{
private bool _movingUp;
diff --git a/Content.Server/GameObjects/Components/Movement/ServerPortalComponent.cs b/Content.Server/GameObjects/Components/Movement/ServerPortalComponent.cs
index 70eb876a8e..f76a8aea58 100644
--- a/Content.Server/GameObjects/Components/Movement/ServerPortalComponent.cs
+++ b/Content.Server/GameObjects/Components/Movement/ServerPortalComponent.cs
@@ -4,6 +4,7 @@ using Content.Shared.GameObjects.Components.Movement;
using Robust.Server.GameObjects;
using Robust.Server.GameObjects.EntitySystems;
using Robust.Server.Interfaces.GameObjects;
+using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Serialization;
@@ -12,6 +13,7 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Movement
{
+ [RegisterComponent]
public class ServerPortalComponent : SharedPortalComponent
{
#pragma warning disable 649
diff --git a/Content.Server/GameObjects/Components/Movement/ServerTeleporterComponent.cs b/Content.Server/GameObjects/Components/Movement/ServerTeleporterComponent.cs
index 78d97a2125..fca5b45b79 100644
--- a/Content.Server/GameObjects/Components/Movement/ServerTeleporterComponent.cs
+++ b/Content.Server/GameObjects/Components/Movement/ServerTeleporterComponent.cs
@@ -9,7 +9,6 @@ using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC;
-using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Serialization;
@@ -19,6 +18,7 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Movement
{
+ [RegisterComponent]
public class ServerTeleporterComponent : Component, IAfterAttack
{
#pragma warning disable 649
diff --git a/Content.Server/GameObjects/Components/Movement/TeleportableComponent.cs b/Content.Server/GameObjects/Components/Movement/TeleportableComponent.cs
index f5f0701ca4..a20b672cc9 100644
--- a/Content.Server/GameObjects/Components/Movement/TeleportableComponent.cs
+++ b/Content.Server/GameObjects/Components/Movement/TeleportableComponent.cs
@@ -1,8 +1,8 @@
using Robust.Shared.GameObjects;
-using Robust.Shared.Log;
namespace Content.Server.GameObjects.Components.Movement
{
+ [RegisterComponent]
public class TeleportableComponent : Component
{
public override string Name => "Teleportable";
diff --git a/Content.Server/GameObjects/Components/PlaceableSurfaceComponent.cs b/Content.Server/GameObjects/Components/PlaceableSurfaceComponent.cs
index 7d8a624f1a..c27c5874ec 100644
--- a/Content.Server/GameObjects/Components/PlaceableSurfaceComponent.cs
+++ b/Content.Server/GameObjects/Components/PlaceableSurfaceComponent.cs
@@ -4,6 +4,7 @@ using Robust.Shared.Serialization;
namespace Content.Server.GameObjects.Components
{
+ [RegisterComponent]
public class PlaceableSurfaceComponent : Component, IAttackBy
{
public override string Name => "PlaceableSurface";
diff --git a/Content.Server/GameObjects/Components/Power/ApcComponent.cs b/Content.Server/GameObjects/Components/Power/ApcComponent.cs
index 62206488fb..3e0b233f27 100644
--- a/Content.Server/GameObjects/Components/Power/ApcComponent.cs
+++ b/Content.Server/GameObjects/Components/Power/ApcComponent.cs
@@ -3,15 +3,15 @@ using Content.Server.GameObjects.EntitySystems;
using Content.Shared.GameObjects.Components.Power;
using Robust.Server.GameObjects;
using Robust.Server.GameObjects.Components.UserInterface;
-using Robust.Server.GameObjects.EntitySystems;
using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.Audio;
+using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.UserInterface;
-using Robust.Shared.Interfaces.GameObjects;
-using Robust.Shared.IoC;
namespace Content.Server.GameObjects.Components.Power
{
+ [RegisterComponent]
+ [ComponentReference(typeof(IActivate))]
public sealed class ApcComponent : SharedApcComponent, IActivate
{
PowerStorageComponent Storage;
diff --git a/Content.Server/GameObjects/Components/Power/LightBulbComponent.cs b/Content.Server/GameObjects/Components/Power/LightBulbComponent.cs
index 11cdb8cb42..9316dd6be9 100644
--- a/Content.Server/GameObjects/Components/Power/LightBulbComponent.cs
+++ b/Content.Server/GameObjects/Components/Power/LightBulbComponent.cs
@@ -1,9 +1,9 @@
using System;
+using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Maths;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
-using SpriteComponent = Robust.Server.GameObjects.SpriteComponent;
namespace Content.Server.GameObjects.Components.Power
{
@@ -23,6 +23,7 @@ namespace Content.Server.GameObjects.Components.Power
///
/// Component that represents a light bulb. Can be broken, or burned, which turns them mostly useless.
///
+ [RegisterComponent]
public class LightBulbComponent : Component
{
diff --git a/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs b/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs
index 5c25236961..fdaaf412be 100644
--- a/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs
+++ b/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs
@@ -1,8 +1,11 @@
using Content.Shared.GameObjects.Components.Power;
using Robust.Server.GameObjects;
+using Robust.Shared.GameObjects;
namespace Content.Server.GameObjects.Components.Power
{
+ [RegisterComponent]
+ [ComponentReference(typeof(PowerStorageComponent))]
public class PowerCellComponent : PowerStorageComponent
{
public override string Name => "PowerCell";
diff --git a/Content.Server/GameObjects/Components/Power/PowerDebugTool.cs b/Content.Server/GameObjects/Components/Power/PowerDebugTool.cs
index ef06753a2a..47d744180a 100644
--- a/Content.Server/GameObjects/Components/Power/PowerDebugTool.cs
+++ b/Content.Server/GameObjects/Components/Power/PowerDebugTool.cs
@@ -3,12 +3,13 @@ using System.Text;
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.GameObjects.Components.Power;
using Robust.Server.Interfaces.GameObjects;
+using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.GameObjects.Components;
-using Robust.Shared.Map;
namespace Content.Server.GameObjects.Components.Power
{
+ [RegisterComponent]
public class PowerDebugTool : SharedPowerDebugTool, IAfterAttack
{
void IAfterAttack.AfterAttack(AfterAttackEventArgs eventArgs)
diff --git a/Content.Server/GameObjects/Components/Power/PowerDevice.cs b/Content.Server/GameObjects/Components/Power/PowerDevice.cs
index 53a28dea75..f93930cc6c 100644
--- a/Content.Server/GameObjects/Components/Power/PowerDevice.cs
+++ b/Content.Server/GameObjects/Components/Power/PowerDevice.cs
@@ -1,22 +1,19 @@
-using Content.Server.GameObjects.EntitySystems;
-using Robust.Server.GameObjects;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Interfaces.GameObjects;
-using Robust.Shared.Interfaces.GameObjects.Components;
-using Robust.Shared.IoC;
-using Robust.Shared.Serialization;
-using Robust.Shared.Utility;
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
+using Content.Server.GameObjects.EntitySystems;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Interfaces.GameObjects.Components;
+using Robust.Shared.Serialization;
+using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
-using YamlDotNet.RepresentationModel;
namespace Content.Server.GameObjects.Components.Power
{
///
/// Component that requires power to function
///
+ [RegisterComponent]
public class PowerDeviceComponent : Component, EntitySystems.IExamine
{
public override string Name => "PowerDevice";
diff --git a/Content.Server/GameObjects/Components/Power/PowerGeneratorComponent.cs b/Content.Server/GameObjects/Components/Power/PowerGeneratorComponent.cs
index c469974411..c2ac6203a6 100644
--- a/Content.Server/GameObjects/Components/Power/PowerGeneratorComponent.cs
+++ b/Content.Server/GameObjects/Components/Power/PowerGeneratorComponent.cs
@@ -1,18 +1,13 @@
using Robust.Shared.GameObjects;
-using Robust.Shared.Interfaces.GameObjects;
-using Robust.Shared.IoC;
-using Robust.Shared.Log;
using Robust.Shared.Serialization;
-using Robust.Shared.Utility;
-using System;
using Robust.Shared.ViewVariables;
-using YamlDotNet.RepresentationModel;
namespace Content.Server.GameObjects.Components.Power
{
///
/// Component that creates power and supplies it to the powernet
///
+ [RegisterComponent]
public class PowerGeneratorComponent : Component
{
public override string Name => "PowerGenerator";
diff --git a/Content.Server/GameObjects/Components/Power/PowerNodeComponent.cs b/Content.Server/GameObjects/Components/Power/PowerNodeComponent.cs
index 7a4bbb39e9..e44ee1d910 100644
--- a/Content.Server/GameObjects/Components/Power/PowerNodeComponent.cs
+++ b/Content.Server/GameObjects/Components/Power/PowerNodeComponent.cs
@@ -1,10 +1,9 @@
-using Robust.Server.GameObjects;
+using System;
+using System.Linq;
using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects.Components;
using Robust.Shared.IoC;
-using System;
-using System.Linq;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Power
@@ -12,6 +11,7 @@ namespace Content.Server.GameObjects.Components.Power
///
/// Component that connects to the powernet
///
+ [RegisterComponent]
public class PowerNodeComponent : Component
{
public override string Name => "PowerNode";
diff --git a/Content.Server/GameObjects/Components/Power/PowerProviderComponent.cs b/Content.Server/GameObjects/Components/Power/PowerProviderComponent.cs
index 78ff050583..3d91440636 100644
--- a/Content.Server/GameObjects/Components/Power/PowerProviderComponent.cs
+++ b/Content.Server/GameObjects/Components/Power/PowerProviderComponent.cs
@@ -1,22 +1,20 @@
-using Robust.Server.GameObjects;
+using System.Collections.Generic;
+using System.Linq;
using Robust.Server.Interfaces.GameObjects;
-using Robust.Shared.Interfaces.GameObjects;
+using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects.Components;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Serialization;
-using Robust.Shared.Utility;
-using System;
-using System.Collections.Generic;
-using System.Linq;
using Robust.Shared.ViewVariables;
-using YamlDotNet.RepresentationModel;
namespace Content.Server.GameObjects.Components.Power
{
///
/// Component that wirelessly connects and powers devices, connects to powernet via node and can be combined with internal storage component
///
+ [RegisterComponent]
+ [ComponentReference(typeof(PowerDeviceComponent))]
public class PowerProviderComponent : PowerDeviceComponent
{
public override string Name => "PowerProvider";
diff --git a/Content.Server/GameObjects/Components/Power/PowerStorageNetComponent.cs b/Content.Server/GameObjects/Components/Power/PowerStorageNetComponent.cs
index 6b8ad3cd97..e2e661dbb9 100644
--- a/Content.Server/GameObjects/Components/Power/PowerStorageNetComponent.cs
+++ b/Content.Server/GameObjects/Components/Power/PowerStorageNetComponent.cs
@@ -1,3 +1,4 @@
+using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
@@ -6,6 +7,8 @@ namespace Content.Server.GameObjects.Components.Power
///
/// Feeds energy from the powernet and may have the ability to supply back into it
///
+ [RegisterComponent]
+ [ComponentReference(typeof(PowerStorageComponent))]
public class PowerStorageNetComponent : PowerStorageComponent
{
public override string Name => "PowerStorage";
diff --git a/Content.Server/GameObjects/Components/Power/PowerTransferComponent.cs b/Content.Server/GameObjects/Components/Power/PowerTransferComponent.cs
index cd0588c5b9..79771febfa 100644
--- a/Content.Server/GameObjects/Components/Power/PowerTransferComponent.cs
+++ b/Content.Server/GameObjects/Components/Power/PowerTransferComponent.cs
@@ -1,20 +1,18 @@
-using Content.Server.GameObjects.EntitySystems;
-using Robust.Server.GameObjects;
+using System.Linq;
+using Content.Server.GameObjects.Components.Interactable.Tools;
+using Content.Server.GameObjects.EntitySystems;
using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
-using System.Linq;
-using Robust.Shared.Interfaces.GameObjects;
-using Content.Server.GameObjects.Components.Interactable.Tools;
using Robust.Shared.Interfaces.GameObjects.Components;
+using Robust.Shared.IoC;
using Robust.Shared.ViewVariables;
-using System;
namespace Content.Server.GameObjects.Components.Power
{
///
/// Component to transfer power to nearby components, can create powernets and connect to nodes
///
+ [RegisterComponent]
public class PowerTransferComponent : Component, IAttackBy
{
public override string Name => "PowerTransfer";
diff --git a/Content.Server/GameObjects/Components/Power/PoweredLightComponent.cs b/Content.Server/GameObjects/Components/Power/PoweredLightComponent.cs
index c78e7067ad..5804722fc0 100644
--- a/Content.Server/GameObjects/Components/Power/PoweredLightComponent.cs
+++ b/Content.Server/GameObjects/Components/Power/PoweredLightComponent.cs
@@ -5,7 +5,6 @@ using Content.Shared.GameObjects;
using Robust.Server.GameObjects;
using Robust.Server.GameObjects.Components.Container;
using Robust.Shared.Audio;
-using Robust.Shared.Enums;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Timing;
@@ -18,6 +17,7 @@ namespace Content.Server.GameObjects.Components.Power
///
/// Component that represents a wall light. It has a light bulb that can be replaced when broken.
///
+ [RegisterComponent]
public class PoweredLightComponent : Component, IAttackHand, IAttackBy
{
public override string Name => "PoweredLight";
@@ -68,7 +68,7 @@ namespace Content.Server.GameObjects.Components.Power
bool CanBurn(int heatResistance)
{
- return _lightState == LightState.On && heatResistance < LightBulb.BurningTemperature;
+ return _lightState && heatResistance < LightBulb.BurningTemperature;
}
void Burn()
@@ -135,8 +135,8 @@ namespace Content.Server.GameObjects.Components.Power
UpdateLight();
}
- private LightState _lightState => Owner.GetComponent().State;
-
+ private bool _lightState => Owner.GetComponent().Enabled;
+
///
/// Updates the light's power drain, sprite and actual light state.
///
@@ -149,7 +149,7 @@ namespace Content.Server.GameObjects.Components.Power
{
device.Load = 0;
sprite.LayerSetState(0, "empty");
- light.State = LightState.Off;
+ light.Enabled = false;
return;
}
@@ -160,7 +160,7 @@ namespace Content.Server.GameObjects.Components.Power
if (device.Powered)
{
sprite.LayerSetState(0, "on");
- light.State = LightState.On;
+ light.Enabled = true;
light.Color = LightBulb.Color;
var time = IoCManager.Resolve().CurTime;
if (time > _lastThunk + _thunkDelay)
@@ -172,18 +172,18 @@ namespace Content.Server.GameObjects.Components.Power
else
{
sprite.LayerSetState(0, "off");
- light.State = LightState.Off;
+ light.Enabled = false;
}
break;
case LightBulbState.Broken:
device.Load = 0;
sprite.LayerSetState(0, "broken");
- light.State = LightState.Off;
+ light.Enabled = false;
break;
case LightBulbState.Burned:
device.Load = 0;
sprite.LayerSetState(0, "burned");
- light.State = LightState.Off;
+ light.Enabled = false;
break;
}
}
diff --git a/Content.Server/GameObjects/Components/Power/SmesComponent.cs b/Content.Server/GameObjects/Components/Power/SmesComponent.cs
index 9576980b79..eba642ef27 100644
--- a/Content.Server/GameObjects/Components/Power/SmesComponent.cs
+++ b/Content.Server/GameObjects/Components/Power/SmesComponent.cs
@@ -1,5 +1,4 @@
-using System;
-using Content.Shared.GameObjects.Components.Power;
+using Content.Shared.GameObjects.Components.Power;
using Content.Shared.Utility;
using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
@@ -11,6 +10,7 @@ namespace Content.Server.GameObjects.Components.Power
/// This is operations that are specific to the SMES, like UI and visuals.
/// Code interfacing with the powernet is handled in .
///
+ [RegisterComponent]
public class SmesComponent : Component
{
public override string Name => "Smes";
diff --git a/Content.Server/GameObjects/Components/Projectiles/ProjectileComponent.cs b/Content.Server/GameObjects/Components/Projectiles/ProjectileComponent.cs
index eb21642190..48051aa31d 100644
--- a/Content.Server/GameObjects/Components/Projectiles/ProjectileComponent.cs
+++ b/Content.Server/GameObjects/Components/Projectiles/ProjectileComponent.cs
@@ -1,14 +1,15 @@
using System.Collections.Generic;
+using Content.Server.GameObjects.Components.Mobs;
+using Content.Shared.GameObjects;
using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
-using Robust.Shared.Interfaces.Physics;
using Robust.Shared.Interfaces.GameObjects.Components;
-using Content.Server.GameObjects.Components.Mobs;
-using Content.Shared.GameObjects;
+using Robust.Shared.Interfaces.Physics;
namespace Content.Server.GameObjects.Components.Projectiles
{
+ [RegisterComponent]
public class ProjectileComponent : Component, ICollideSpecial, ICollideBehavior
{
public override string Name => "Projectile";
diff --git a/Content.Server/GameObjects/Components/Projectiles/ThrownItemComponent.cs b/Content.Server/GameObjects/Components/Projectiles/ThrownItemComponent.cs
index dd1f1198e6..4d3e716150 100644
--- a/Content.Server/GameObjects/Components/Projectiles/ThrownItemComponent.cs
+++ b/Content.Server/GameObjects/Components/Projectiles/ThrownItemComponent.cs
@@ -11,6 +11,7 @@ using Robust.Shared.IoC;
namespace Content.Server.GameObjects.Components
{
+ [RegisterComponent]
class ThrownItemComponent : ProjectileComponent, ICollideBehavior
{
#pragma warning disable 649
diff --git a/Content.Server/GameObjects/Components/Research/LatheComponent.cs b/Content.Server/GameObjects/Components/Research/LatheComponent.cs
index 437a89fbd0..dad97a3d91 100644
--- a/Content.Server/GameObjects/Components/Research/LatheComponent.cs
+++ b/Content.Server/GameObjects/Components/Research/LatheComponent.cs
@@ -6,15 +6,16 @@ using Content.Shared.GameObjects.Components.Research;
using Content.Shared.Research;
using Robust.Server.GameObjects.Components.UserInterface;
using Robust.Server.Interfaces.GameObjects;
+using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.UserInterface;
-using Robust.Shared.IoC;
-using Robust.Shared.Prototypes;
using Robust.Shared.Timers;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Research
{
+ [RegisterComponent]
+ [ComponentReference(typeof(IActivate))]
public class LatheComponent : SharedLatheComponent, IAttackBy, IActivate
{
public const int VolumePerSheet = 3750;
diff --git a/Content.Server/GameObjects/Components/Research/LatheDatabaseComponent.cs b/Content.Server/GameObjects/Components/Research/LatheDatabaseComponent.cs
index f6fcb395d5..d43d5e052f 100644
--- a/Content.Server/GameObjects/Components/Research/LatheDatabaseComponent.cs
+++ b/Content.Server/GameObjects/Components/Research/LatheDatabaseComponent.cs
@@ -1,4 +1,3 @@
-using System.Collections.Generic;
using Content.Shared.GameObjects.Components.Research;
using Content.Shared.Research;
using Robust.Shared.GameObjects;
@@ -6,6 +5,8 @@ using Robust.Shared.Serialization;
namespace Content.Server.GameObjects.Components.Research
{
+ [RegisterComponent]
+ [ComponentReference(typeof(SharedLatheDatabaseComponent))]
public class LatheDatabaseComponent : SharedLatheDatabaseComponent
{
///
diff --git a/Content.Server/GameObjects/Components/Research/MaterialStorageComponent.cs b/Content.Server/GameObjects/Components/Research/MaterialStorageComponent.cs
index 2d1d22f061..47c3958cd4 100644
--- a/Content.Server/GameObjects/Components/Research/MaterialStorageComponent.cs
+++ b/Content.Server/GameObjects/Components/Research/MaterialStorageComponent.cs
@@ -1,11 +1,12 @@
using System.Collections.Generic;
using Content.Shared.GameObjects.Components.Research;
using Robust.Shared.GameObjects;
-using Robust.Shared.Interfaces.Network;
using Robust.Shared.Serialization;
namespace Content.Server.GameObjects.Components.Research
{
+ [RegisterComponent]
+ [ComponentReference(typeof(SharedMaterialStorageComponent))]
public class MaterialStorageComponent : SharedMaterialStorageComponent
{
protected override Dictionary Storage { get; set; } = new Dictionary();
diff --git a/Content.Server/GameObjects/Components/Sound/EmitSoundOnUseComponent].cs b/Content.Server/GameObjects/Components/Sound/EmitSoundOnUseComponent].cs
index 05b6383eb5..96059435a7 100644
--- a/Content.Server/GameObjects/Components/Sound/EmitSoundOnUseComponent].cs
+++ b/Content.Server/GameObjects/Components/Sound/EmitSoundOnUseComponent].cs
@@ -1,29 +1,18 @@
-using System;
-using System.Collections.Generic;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Log;
-using Robust.Shared.Utility;
-using YamlDotNet.RepresentationModel;
-using Content.Server.Interfaces;
-using Content.Shared.GameObjects;
-using Robust.Shared.Serialization;
-using Robust.Shared.ViewVariables;
-using Content.Server.GameObjects.EntitySystems;
-using Robust.Server.GameObjects.EntitySystems;
-using Content.Shared.Audio;
-using Robust.Shared.Prototypes;
-using Robust.Shared.IoC;
+using Content.Server.GameObjects.EntitySystems;
using Robust.Shared.Audio;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization;
namespace Content.Server.GameObjects.Components.Sound
{
///
/// Simple sound emitter that emits sound on use in hand
///
+ [RegisterComponent]
public class EmitSoundOnUseComponent : Component, IUse
{
///
- ///
+ ///
public override string Name => "EmitSoundOnUse";
public string _soundName;
diff --git a/Content.Server/GameObjects/Components/Sound/FootstepModifierComponent.cs b/Content.Server/GameObjects/Components/Sound/FootstepModifierComponent.cs
index f7ed7e3aa4..1cf60c0bc5 100644
--- a/Content.Server/GameObjects/Components/Sound/FootstepModifierComponent.cs
+++ b/Content.Server/GameObjects/Components/Sound/FootstepModifierComponent.cs
@@ -1,33 +1,25 @@
using System;
-using System.Collections.Generic;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Log;
-using Robust.Shared.Utility;
-using YamlDotNet.RepresentationModel;
-using Content.Server.Interfaces;
-using Content.Shared.GameObjects;
-using Robust.Shared.Serialization;
-using Robust.Shared.ViewVariables;
-using Content.Server.GameObjects.EntitySystems;
-using Robust.Server.GameObjects.EntitySystems;
using Content.Shared.Audio;
-using Robust.Shared.Prototypes;
+using Robust.Shared.Audio;
+using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
-using Robust.Shared.Audio;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization;
namespace Content.Server.GameObjects.Components.Sound
{
///
/// Changes footstep sound
///
+ [RegisterComponent]
public class FootstepModifierComponent : Component
{
#pragma warning disable 649
[Dependency] private readonly IPrototypeManager _prototypeManager;
#pragma warning restore 649
///
- ///
+ ///
private Random _footstepRandom;
public override string Name => "FootstepModifier";
diff --git a/Content.Server/GameObjects/Components/Sound/SoundComponent.cs b/Content.Server/GameObjects/Components/Sound/SoundComponent.cs
index 9a136031ea..975d90abbc 100644
--- a/Content.Server/GameObjects/Components/Sound/SoundComponent.cs
+++ b/Content.Server/GameObjects/Components/Sound/SoundComponent.cs
@@ -1,16 +1,11 @@
-using System.Collections.Generic;
using Content.Shared.GameObjects.Components.Sound;
-using Robust.Server.GameObjects.EntitySystems;
using Robust.Shared.Audio;
using Robust.Shared.GameObjects;
-using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
-using Robust.Shared.Log;
-using Robust.Shared.Map;
-using Robust.Shared.Serialization;
namespace Content.Server.GameObjects.Components.Sound
{
+ [RegisterComponent]
public class SoundComponent : SharedSoundComponent
{
///
diff --git a/Content.Server/GameObjects/Components/Stack/StackComponent.cs b/Content.Server/GameObjects/Components/Stack/StackComponent.cs
index c3cdc59077..40fbf6eb83 100644
--- a/Content.Server/GameObjects/Components/Stack/StackComponent.cs
+++ b/Content.Server/GameObjects/Components/Stack/StackComponent.cs
@@ -10,6 +10,7 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Stack
{
// TODO: Naming and presentation and such could use some improvement.
+ [RegisterComponent]
public class StackComponent : Component, IAttackBy, IExamine
{
private const string SerializationCache = "stack";
diff --git a/Content.Server/GameObjects/Components/Temperature/TemperatureComponent.cs b/Content.Server/GameObjects/Components/Temperature/TemperatureComponent.cs
index 811b102a65..5ab4fbbe4b 100644
--- a/Content.Server/GameObjects/Components/Temperature/TemperatureComponent.cs
+++ b/Content.Server/GameObjects/Components/Temperature/TemperatureComponent.cs
@@ -1,10 +1,8 @@
-using Content.Server.Interfaces.GameObjects;
-using Content.Shared.Maths;
-using System;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Utility;
-using YamlDotNet.RepresentationModel;
+using System;
+using Content.Server.Interfaces.GameObjects;
using Content.Shared.GameObjects;
+using Content.Shared.Maths;
+using Robust.Shared.GameObjects;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
@@ -15,6 +13,7 @@ namespace Content.Server.GameObjects
/// informing others of the current temperature,
/// and taking fire damage from high temperature.
///
+ [RegisterComponent]
public class TemperatureComponent : Component, ITemperatureComponent
{
///
diff --git a/Content.Server/GameObjects/Components/Trigger/TimerTrigger/OnUseTimerTriggerComponent.cs b/Content.Server/GameObjects/Components/Trigger/TimerTrigger/OnUseTimerTriggerComponent.cs
index b41bd35bbd..19d77f4ad7 100644
--- a/Content.Server/GameObjects/Components/Trigger/TimerTrigger/OnUseTimerTriggerComponent.cs
+++ b/Content.Server/GameObjects/Components/Trigger/TimerTrigger/OnUseTimerTriggerComponent.cs
@@ -1,14 +1,15 @@
using System;
+using Content.Server.GameObjects.EntitySystems;
+using Content.Shared.GameObjects.Components.Triggers;
using Robust.Server.GameObjects;
+using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Serialization;
-using Robust.Shared.GameObjects;
-using Content.Server.GameObjects.EntitySystems;
-using Content.Shared.GameObjects.Components.Triggers;
namespace Content.Server.GameObjects.Components.Triggers
{
+ [RegisterComponent]
public class OnUseTimerTriggerComponent : Component, IUse
{
#pragma warning disable 649
@@ -28,7 +29,7 @@ namespace Content.Server.GameObjects.Components.Triggers
public override void Initialize()
{
- base.Initialize();
+ base.Initialize();
}
bool IUse.UseEntity(UseEntityEventArgs eventArgs)
@@ -41,4 +42,4 @@ namespace Content.Server.GameObjects.Components.Triggers
return true;
}
}
-}
\ No newline at end of file
+}
diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs
index e37772a956..6f9cb85961 100644
--- a/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs
+++ b/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs
@@ -1,14 +1,15 @@
-using Robust.Shared.GameObjects;
-using Content.Server.GameObjects.EntitySystems;
+using Content.Server.GameObjects.EntitySystems;
+using Content.Shared.GameObjects;
+using Robust.Server.Interfaces.GameObjects;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
-using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.Serialization;
-using Content.Shared.GameObjects;
-using Robust.Shared.Interfaces.Map;
namespace Content.Server.GameObjects.Components.Weapon.Melee
{
+ [RegisterComponent]
public class MeleeWeaponComponent : Component, IAttack
{
#pragma warning disable 649
diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponCapacitorComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponCapacitorComponent.cs
index 6a58ff3a46..5df47f000b 100644
--- a/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponCapacitorComponent.cs
+++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponCapacitorComponent.cs
@@ -1,11 +1,13 @@
using System;
-using Content.Shared.GameObjects.Components.Power;
using Content.Server.GameObjects.Components.Power;
-using Robust.Shared.Serialization;
+using Content.Shared.GameObjects.Components.Power;
using Robust.Server.GameObjects;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization;
namespace Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan
{
+ [RegisterComponent]
public class HitscanWeaponCapacitorComponent : PowerCellComponent
{
private AppearanceComponent _appearance;
diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponComponent.cs
index b5cb365b9b..1d4998b3ea 100644
--- a/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponComponent.cs
+++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponComponent.cs
@@ -1,6 +1,13 @@
-using Content.Shared.GameObjects;
+using System;
+using Content.Server.GameObjects.Components.Power;
+using Content.Server.GameObjects.Components.Sound;
+using Content.Server.GameObjects.EntitySystems;
+using Content.Shared.GameObjects;
+using Content.Shared.Interfaces;
+using Content.Shared.Physics;
using Robust.Server.GameObjects.EntitySystems;
using Robust.Shared.Audio;
+using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.EntitySystemMessages;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Physics;
@@ -10,16 +17,10 @@ using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Serialization;
-using System;
-using Content.Server.GameObjects.Components.Sound;
-using Robust.Shared.GameObjects;
-using Content.Server.GameObjects.EntitySystems;
-using Content.Server.GameObjects.Components.Power;
-using Content.Shared.Interfaces;
-using Content.Shared.Physics;
namespace Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan
{
+ [RegisterComponent]
public class HitscanWeaponComponent : Component, IAttackBy
{
private const float MaxLength = 20;
diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticBulletComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticBulletComponent.cs
index adbacdd85a..93176615a1 100644
--- a/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticBulletComponent.cs
+++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticBulletComponent.cs
@@ -3,6 +3,7 @@ using Robust.Shared.Serialization;
namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile
{
+ [RegisterComponent]
public class BallisticBulletComponent : Component
{
public override string Name => "BallisticBullet";
diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticMagazineComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticMagazineComponent.cs
index 4ee7e2a16a..8595fbf30b 100644
--- a/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticMagazineComponent.cs
+++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticMagazineComponent.cs
@@ -11,6 +11,7 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile
{
+ [RegisterComponent]
public class BallisticMagazineComponent : Component, IMapInit
{
public override string Name => "BallisticMagazine";
diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticMagazineWeaponComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticMagazineWeaponComponent.cs
index ff56a12062..7b6dccfe06 100644
--- a/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticMagazineWeaponComponent.cs
+++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticMagazineWeaponComponent.cs
@@ -8,6 +8,7 @@ using Robust.Server.GameObjects;
using Robust.Server.GameObjects.Components.Container;
using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.Audio;
+using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Maths;
using Robust.Shared.Serialization;
@@ -16,6 +17,7 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile
{
+ [RegisterComponent]
public class BallisticMagazineWeaponComponent : BallisticWeaponComponent, IUse, IAttackBy, IMapInit
{
public override string Name => "BallisticMagazineWeapon";
diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/RangedWeapon.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/RangedWeapon.cs
index 0c82bd11cc..fe03f74eb8 100644
--- a/Content.Server/GameObjects/Components/Weapon/Ranged/RangedWeapon.cs
+++ b/Content.Server/GameObjects/Components/Weapon/Ranged/RangedWeapon.cs
@@ -1,18 +1,17 @@
using System;
-using Robust.Shared.GameObjects;
-using Content.Server.GameObjects.EntitySystems;
using Content.Shared.GameObjects.Components.Weapons.Ranged;
using Robust.Server.Interfaces.Player;
+using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.IoC;
-using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Timers;
namespace Content.Server.GameObjects.Components.Weapon.Ranged
{
+ [RegisterComponent]
public sealed class RangedWeaponComponent : SharedRangedWeaponComponent
{
private TimeSpan _lastFireTime;
diff --git a/Content.Shared/Chemistry/ReagentPrototype.cs b/Content.Shared/Chemistry/ReagentPrototype.cs
new file mode 100644
index 0000000000..b123489a2b
--- /dev/null
+++ b/Content.Shared/Chemistry/ReagentPrototype.cs
@@ -0,0 +1,25 @@
+using Robust.Shared.Maths;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Utility;
+using YamlDotNet.RepresentationModel;
+
+namespace Content.Shared.Chemistry
+{
+ [Prototype("reagent")]
+ public class ReagentPrototype : IPrototype, IIndexedPrototype
+ {
+ public string ID { get; private set; }
+ public string Name { get; private set; }
+ public string Description { get; private set; }
+ public Color SubstanceColor { get; private set; }
+
+ public void LoadFrom(YamlMappingNode mapping)
+ {
+ ID = mapping.GetNode("id").AsString();
+ Name = mapping.GetNode("name").ToString();
+ Description = mapping.GetNode("desc").ToString();
+
+ SubstanceColor = mapping.TryGetNode("color", out var colorNode) ? colorNode.AsHexColor(Color.White) : Color.White;
+ }
+ }
+}
diff --git a/Content.Shared/Chemistry/Solution.cs b/Content.Shared/Chemistry/Solution.cs
new file mode 100644
index 0000000000..472503b4df
--- /dev/null
+++ b/Content.Shared/Chemistry/Solution.cs
@@ -0,0 +1,273 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using Robust.Shared.Interfaces.Serialization;
+using Robust.Shared.Serialization;
+using Robust.Shared.Utility;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Shared.Chemistry
+{
+ ///
+ /// A solution of reagents.
+ ///
+ public class Solution : IExposeData, IEnumerable
+ {
+ // Most objects on the station hold only 1 or 2 reagents
+ [ViewVariables]
+ private List _contents = new List(2);
+
+ ///
+ /// The calculated total volume of all reagents in the solution (ex. Total volume of liquid in beaker).
+ ///
+ [ViewVariables]
+ public int TotalVolume { get; private set; }
+
+ ///
+ /// Constructs an empty solution (ex. an empty beaker).
+ ///
+ public Solution() { }
+
+ ///
+ /// Constructs a solution containing 100% of a reagent (ex. A beaker of pure water).
+ ///
+ /// The prototype ID of the reagent to add.
+ /// The quantity in milli-units.
+ public Solution(string reagentId, int quantity)
+ {
+ AddReagent(reagentId, quantity);
+ }
+
+ ///
+ public void ExposeData(ObjectSerializer serializer)
+ {
+ serializer.DataField(ref _contents, "reagents", new List());
+
+ if (serializer.Reading)
+ {
+ TotalVolume = 0;
+ foreach (var reagent in _contents)
+ {
+ TotalVolume += reagent.Quantity;
+ }
+ }
+ }
+
+ ///
+ /// Adds a given quantity of a reagent directly into the solution.
+ ///
+ /// The prototype ID of the reagent to add.
+ /// The quantity in milli-units.
+ public void AddReagent(string reagentId, int quantity)
+ {
+ if(quantity <= 0)
+ return;
+
+ for (var i = 0; i < _contents.Count; i++)
+ {
+ var reagent = _contents[i];
+ if (reagent.ReagentId != reagentId)
+ continue;
+
+ _contents[i] = new ReagentQuantity(reagentId, reagent.Quantity + quantity);
+ TotalVolume += quantity;
+ return;
+ }
+
+ _contents.Add(new ReagentQuantity(reagentId, quantity));
+ TotalVolume += quantity;
+ }
+
+ ///
+ /// Returns the amount of a single reagent inside the solution.
+ ///
+ /// The prototype ID of the reagent to add.
+ /// The quantity in milli-units.
+ public int GetReagentQuantity(string reagentId)
+ {
+ for (var i = 0; i < _contents.Count; i++)
+ {
+ if (_contents[i].ReagentId == reagentId)
+ return _contents[i].Quantity;
+ }
+
+ return 0;
+ }
+
+ public void RemoveReagent(string reagentId, int quantity)
+ {
+ if(quantity <= 0)
+ return;
+
+ for (var i = 0; i < _contents.Count; i++)
+ {
+ var reagent = _contents[i];
+ if(reagent.ReagentId != reagentId)
+ continue;
+
+ var curQuantity = reagent.Quantity;
+
+ var newQuantity = curQuantity - quantity;
+ if (newQuantity <= 0)
+ {
+ _contents.RemoveSwap(i);
+ TotalVolume -= curQuantity;
+ }
+ else
+ {
+ _contents[i] = new ReagentQuantity(reagentId, newQuantity);
+ TotalVolume -= quantity;
+ }
+
+ return;
+ }
+ }
+
+ public void RemoveSolution(int quantity)
+ {
+ if(quantity <=0)
+ return;
+
+ var ratio = (float)(TotalVolume - quantity) / TotalVolume;
+
+ if (ratio <= 0)
+ {
+ RemoveAllSolution();
+ return;
+ }
+
+ for (var i = 0; i < _contents.Count; i++)
+ {
+ var reagent = _contents[i];
+ var oldQuantity = reagent.Quantity;
+
+ // quantity taken is always a little greedy, so fractional quantities get rounded up to the nearest
+ // whole unit. This should prevent little bits of chemical remaining because of float rounding errors.
+ var newQuantity = (int)Math.Floor(oldQuantity * ratio);
+
+ _contents[i] = new ReagentQuantity(reagent.ReagentId, newQuantity);
+ }
+
+ TotalVolume = (int)Math.Floor(TotalVolume * ratio);
+ }
+
+ public void RemoveAllSolution()
+ {
+ _contents.Clear();
+ TotalVolume = 0;
+ }
+
+ public Solution SplitSolution(int quantity)
+ {
+ if (quantity <= 0)
+ return new Solution();
+
+ Solution newSolution;
+
+ if (quantity >= TotalVolume)
+ {
+ newSolution = Clone();
+ RemoveAllSolution();
+ return newSolution;
+ }
+
+ newSolution = new Solution();
+ var newTotalVolume = 0;
+ var ratio = (float)(TotalVolume - quantity) / TotalVolume;
+
+ for (var i = 0; i < _contents.Count; i++)
+ {
+ var reagent = _contents[i];
+
+ var newQuantity = (int)Math.Floor(reagent.Quantity * ratio);
+ var splitQuantity = reagent.Quantity - newQuantity;
+
+ _contents[i] = new ReagentQuantity(reagent.ReagentId, newQuantity);
+ newSolution._contents.Add(new ReagentQuantity(reagent.ReagentId, splitQuantity));
+ newTotalVolume += splitQuantity;
+ }
+
+ TotalVolume = (int)Math.Floor(TotalVolume * ratio);
+ newSolution.TotalVolume = newTotalVolume;
+
+ return newSolution;
+ }
+
+ public void AddSolution(Solution otherSolution)
+ {
+ for (var i = 0; i < otherSolution._contents.Count; i++)
+ {
+ var otherReagent = otherSolution._contents[i];
+
+ var found = false;
+ for (var j = 0; j < _contents.Count; j++)
+ {
+ var reagent = _contents[j];
+ if (reagent.ReagentId == otherReagent.ReagentId)
+ {
+ found = true;
+ _contents[j] = new ReagentQuantity(reagent.ReagentId, reagent.Quantity + otherReagent.Quantity);
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ _contents.Add(new ReagentQuantity(otherReagent.ReagentId, otherReagent.Quantity));
+ }
+ }
+
+ TotalVolume += otherSolution.TotalVolume;
+ }
+
+ public Solution Clone()
+ {
+ var volume = 0;
+ var newSolution = new Solution();
+
+ for (var i = 0; i < _contents.Count; i++)
+ {
+ var reagent = _contents[i];
+ newSolution._contents.Add(reagent);
+ volume += reagent.Quantity;
+ }
+
+ newSolution.TotalVolume = volume;
+ return newSolution;
+ }
+
+ [Serializable, NetSerializable]
+ public readonly struct ReagentQuantity
+ {
+ public readonly string ReagentId;
+ public readonly int Quantity;
+
+ public ReagentQuantity(string reagentId, int quantity)
+ {
+ ReagentId = reagentId;
+ Quantity = quantity;
+ }
+
+ [ExcludeFromCodeCoverage]
+ public override string ToString()
+ {
+ return $"{ReagentId}:{Quantity}";
+ }
+ }
+
+ #region Enumeration
+
+ public IEnumerator GetEnumerator()
+ {
+ return _contents.GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ #endregion
+ }
+}
diff --git a/Content.Shared/Chemistry/SolutionCaps.cs b/Content.Shared/Chemistry/SolutionCaps.cs
new file mode 100644
index 0000000000..c5e4edf193
--- /dev/null
+++ b/Content.Shared/Chemistry/SolutionCaps.cs
@@ -0,0 +1,21 @@
+using System;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Chemistry
+{
+ ///
+ /// These are the defined capabilities of a container of a solution.
+ ///
+ [Flags]
+ [Serializable, NetSerializable]
+ public enum SolutionCaps
+ {
+ None = 0,
+
+ PourIn = 1,
+ PourOut = 2,
+
+ Injector = 4,
+ Injectable = 8,
+ }
+}
diff --git a/Content.Shared/GameObjects/Components/Chemistry/SolutionComponent.cs b/Content.Shared/GameObjects/Components/Chemistry/SolutionComponent.cs
new file mode 100644
index 0000000000..5ec42b038f
--- /dev/null
+++ b/Content.Shared/GameObjects/Components/Chemistry/SolutionComponent.cs
@@ -0,0 +1,166 @@
+using System;
+using Content.Shared.Chemistry;
+using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
+using Robust.Shared.Maths;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Shared.GameObjects.Components.Chemistry
+{
+ public class SolutionComponent : Component
+ {
+#pragma warning disable 649
+ [Dependency] private readonly IPrototypeManager _prototypeManager;
+#pragma warning restore 649
+
+ [ViewVariables]
+ private Solution _containedSolution;
+ private int _maxVolume;
+ private SolutionCaps _capabilities;
+
+ ///
+ /// The maximum volume of the container.
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ public int MaxVolume
+ {
+ get => _maxVolume;
+ set => _maxVolume = value; // Note that the contents won't spill out if the capacity is reduced.
+ }
+
+ ///
+ /// The total volume of all the of the reagents in the container.
+ ///
+ [ViewVariables]
+ public int CurrentVolume => _containedSolution.TotalVolume;
+
+ ///
+ /// The current blended color of all the reagents in the container.
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ public Color SubstanceColor { get; private set; }
+
+ ///
+ /// The current capabilities of this container (is the top open to pour? can I inject it into another object?).
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ public SolutionCaps Capabilities
+ {
+ get => _capabilities;
+ set => _capabilities = value;
+ }
+
+ ///
+ public override string Name => "Solution";
+
+ ///
+ public sealed override uint? NetID => ContentNetIDs.SOLUTION;
+
+ ///
+ public sealed override Type StateType => typeof(SolutionComponentState);
+
+ ///
+ public override void ExposeData(ObjectSerializer serializer)
+ {
+ base.ExposeData(serializer);
+
+ serializer.DataField(ref _maxVolume, "maxVol", 0);
+ serializer.DataField(ref _containedSolution, "contents", new Solution());
+ serializer.DataField(ref _capabilities, "caps", SolutionCaps.None);
+ }
+
+ public override void Startup()
+ {
+ base.Startup();
+
+ RecalculateColor();
+ }
+
+ public override void Shutdown()
+ {
+ base.Shutdown();
+
+ _containedSolution.RemoveAllSolution();
+ _containedSolution = new Solution();
+ }
+
+ public bool TryAddReagent(string reagentId, int quantity, out int acceptedQuantity)
+ {
+ throw new NotImplementedException();
+ }
+
+ public bool TryAddSolution(Solution solution)
+ {
+ if (solution.TotalVolume > (_maxVolume - _containedSolution.TotalVolume))
+ return false;
+
+ _containedSolution.AddSolution(solution);
+ RecalculateColor();
+ return true;
+ }
+
+ public Solution SplitSolution(int quantity)
+ {
+ return _containedSolution.SplitSolution(quantity);
+ }
+
+ private void RecalculateColor()
+ {
+ if(_containedSolution.TotalVolume == 0)
+ SubstanceColor = Color.White;
+
+ Color mixColor = default;
+ float runningTotalQuantity = 0;
+
+ foreach (var reagent in _containedSolution)
+ {
+ runningTotalQuantity += reagent.Quantity;
+
+ if(!_prototypeManager.TryIndex(reagent.ReagentId, out ReagentPrototype proto))
+ continue;
+
+ if (mixColor == default)
+ mixColor = proto.SubstanceColor;
+
+ mixColor = BlendRGB(mixColor, proto.SubstanceColor, reagent.Quantity / runningTotalQuantity);
+ }
+ }
+
+ private Color BlendRGB(Color rgb1, Color rgb2, float amount)
+ {
+ var r = (float)Math.Round(rgb1.R + (rgb2.R - rgb1.R) * amount, 1);
+ var g = (float)Math.Round(rgb1.G + (rgb2.G - rgb1.G) * amount, 1);
+ var b = (float)Math.Round(rgb1.B + (rgb2.B - rgb1.B) * amount, 1);
+ var alpha = (float)Math.Round(rgb1.A + (rgb2.A - rgb1.A) * amount, 1);
+
+ return new Color(r, g, b, alpha);
+ }
+
+ ///
+ public override ComponentState GetComponentState()
+ {
+ return new SolutionComponentState();
+ }
+
+ ///
+ public override void HandleComponentState(ComponentState curState, ComponentState nextState)
+ {
+ base.HandleComponentState(curState, nextState);
+
+ if(curState == null)
+ return;
+
+ var compState = (SolutionComponentState)curState;
+
+ //TODO: Make me work!
+ }
+
+ [Serializable, NetSerializable]
+ public class SolutionComponentState : ComponentState
+ {
+ public SolutionComponentState() : base(ContentNetIDs.SOLUTION) { }
+ }
+ }
+}
diff --git a/Content.Shared/GameObjects/Components/Materials/MaterialComponent.cs b/Content.Shared/GameObjects/Components/Materials/MaterialComponent.cs
index 2514c9cdfc..63e07d9b16 100644
--- a/Content.Shared/GameObjects/Components/Materials/MaterialComponent.cs
+++ b/Content.Shared/GameObjects/Components/Materials/MaterialComponent.cs
@@ -14,6 +14,7 @@ namespace Content.Shared.GameObjects.Components.Materials
/// Component to store data such as "this object is made out of steel".
/// This is not a storage system for say smelteries.
///
+ [RegisterComponent]
public class MaterialComponent : Component
{
public const string SerializationCache = "mat";
diff --git a/Content.Shared/GameObjects/Components/Mobs/ExaminerComponent.cs b/Content.Shared/GameObjects/Components/Mobs/ExaminerComponent.cs
index 536a4f573a..9d3f01becf 100644
--- a/Content.Shared/GameObjects/Components/Mobs/ExaminerComponent.cs
+++ b/Content.Shared/GameObjects/Components/Mobs/ExaminerComponent.cs
@@ -7,6 +7,7 @@ namespace Content.Shared.GameObjects.Components.Mobs
///
/// Component required for a player to be able to examine things.
///
+ [RegisterComponent]
public sealed class ExaminerComponent : Component
{
public override string Name => "Examiner";
diff --git a/Content.Shared/GameObjects/ContentNetIDs.cs b/Content.Shared/GameObjects/ContentNetIDs.cs
index a2b54f0dff..166a0cdb0e 100644
--- a/Content.Shared/GameObjects/ContentNetIDs.cs
+++ b/Content.Shared/GameObjects/ContentNetIDs.cs
@@ -7,6 +7,7 @@
public const uint DESTRUCTIBLE = 1001;
public const uint TEMPERATURE = 1002;
public const uint HANDS = 1003;
+ public const uint SOLUTION = 1004;
public const uint STORAGE = 1005;
public const uint INVENTORY = 1006;
public const uint POWER_DEBUG_TOOL = 1007;
diff --git a/Content.Shared/GameObjects/Verb.cs b/Content.Shared/GameObjects/Verb.cs
index 7bc38b4dc3..4fd3fe288b 100644
--- a/Content.Shared/GameObjects/Verb.cs
+++ b/Content.Shared/GameObjects/Verb.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Reflection;
using JetBrains.Annotations;
using Robust.Shared.Interfaces.GameObjects;
@@ -116,7 +117,7 @@ namespace Content.Shared.GameObjects
foreach (var component in entity.GetComponentInstances())
{
var type = component.GetType();
- foreach (var nestedType in type.GetNestedTypes())
+ foreach (var nestedType in type.GetNestedTypes(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static))
{
if (!typeof(Verb).IsAssignableFrom(nestedType) || nestedType.IsAbstract)
{
diff --git a/Content.Tests/Shared/Chemistry/ReagentPrototype_Tests.cs b/Content.Tests/Shared/Chemistry/ReagentPrototype_Tests.cs
new file mode 100644
index 0000000000..d78a67178c
--- /dev/null
+++ b/Content.Tests/Shared/Chemistry/ReagentPrototype_Tests.cs
@@ -0,0 +1,42 @@
+using System.IO;
+using Content.Shared.Chemistry;
+using NUnit.Framework;
+using Robust.Shared.Maths;
+using Robust.Shared.Utility;
+using YamlDotNet.RepresentationModel;
+
+namespace Content.Tests.Shared.Chemistry
+{
+ [TestFixture, Parallelizable, TestOf(typeof(ReagentPrototype))]
+ public class ReagentPrototype_Tests
+ {
+ [Test]
+ public void DeserializeReagentPrototype()
+ {
+ using (TextReader stream = new StringReader(YamlReagentPrototype))
+ {
+ var yamlStream = new YamlStream();
+ yamlStream.Load(stream);
+ var document = yamlStream.Documents[0];
+ var rootNode = (YamlSequenceNode)document.RootNode;
+ var proto = (YamlMappingNode)rootNode[0];
+
+ var defType = proto.GetNode("type").AsString();
+ var newReagent = new ReagentPrototype();
+ newReagent.LoadFrom(proto);
+
+ Assert.That(defType, Is.EqualTo("reagent"));
+ Assert.That(newReagent.ID, Is.EqualTo("chem.H2"));
+ Assert.That(newReagent.Name, Is.EqualTo("Hydrogen"));
+ Assert.That(newReagent.Description, Is.EqualTo("A light, flammable gas."));
+ Assert.That(newReagent.SubstanceColor, Is.EqualTo(Color.Teal));
+ }
+ }
+
+ private const string YamlReagentPrototype = @"- type: reagent
+ id: chem.H2
+ name: Hydrogen
+ desc: A light, flammable gas.
+ color: " + "\"#008080\"";
+ }
+}
diff --git a/Content.Tests/Shared/Chemistry/Solution_Tests.cs b/Content.Tests/Shared/Chemistry/Solution_Tests.cs
new file mode 100644
index 0000000000..d78dc39a2f
--- /dev/null
+++ b/Content.Tests/Shared/Chemistry/Solution_Tests.cs
@@ -0,0 +1,251 @@
+using Content.Shared.Chemistry;
+using NUnit.Framework;
+
+namespace Content.Tests.Shared.Chemistry
+{
+ [TestFixture, Parallelizable, TestOf(typeof(Solution))]
+ public class Solution_Tests
+ {
+ [Test]
+ public void AddReagentAndGetSolution()
+ {
+ var solution = new Solution();
+ solution.AddReagent("water", 1000);
+ var quantity = solution.GetReagentQuantity("water");
+
+ Assert.That(quantity, Is.EqualTo(1000));
+ }
+
+ [Test]
+ public void ConstructorAddReagent()
+ {
+ var solution = new Solution("water", 1000);
+ var quantity = solution.GetReagentQuantity("water");
+
+ Assert.That(quantity, Is.EqualTo(1000));
+ }
+
+ [Test]
+ public void NonExistingReagentReturnsZero()
+ {
+ var solution = new Solution();
+ var quantity = solution.GetReagentQuantity("water");
+
+ Assert.That(quantity, Is.EqualTo(0));
+ }
+
+ [Test]
+ public void AddLessThanZeroReagentReturnsZero()
+ {
+ var solution = new Solution("water", -1000);
+ var quantity = solution.GetReagentQuantity("water");
+
+ Assert.That(quantity, Is.EqualTo(0));
+ }
+
+ [Test]
+ public void AddingReagentsSumsProperly()
+ {
+ var solution = new Solution();
+ solution.AddReagent("water", 1000);
+ solution.AddReagent("water", 2000);
+ var quantity = solution.GetReagentQuantity("water");
+
+ Assert.That(quantity, Is.EqualTo(3000));
+ }
+
+ [Test]
+ public void ReagentQuantitiesStayUnique()
+ {
+ var solution = new Solution();
+ solution.AddReagent("water", 1000);
+ solution.AddReagent("fire", 2000);
+
+ Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(1000));
+ Assert.That(solution.GetReagentQuantity("fire"), Is.EqualTo(2000));
+ }
+
+ [Test]
+ public void TotalVolumeIsCorrect()
+ {
+ var solution = new Solution();
+ solution.AddReagent("water", 1000);
+ solution.AddReagent("fire", 2000);
+
+ Assert.That(solution.TotalVolume, Is.EqualTo(3000));
+ }
+
+ [Test]
+ public void CloningSolutionIsCorrect()
+ {
+ var solution = new Solution();
+ solution.AddReagent("water", 1000);
+ solution.AddReagent("fire", 2000);
+
+ var newSolution = solution.Clone();
+
+ Assert.That(newSolution.GetReagentQuantity("water"), Is.EqualTo(1000));
+ Assert.That(newSolution.GetReagentQuantity("fire"), Is.EqualTo(2000));
+ Assert.That(newSolution.TotalVolume, Is.EqualTo(3000));
+ }
+
+ [Test]
+ public void RemoveSolutionRecalculatesProperly()
+ {
+ var solution = new Solution();
+ solution.AddReagent("water", 1000);
+ solution.AddReagent("fire", 2000);
+
+ solution.RemoveReagent("water", 500);
+
+ Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(500));
+ Assert.That(solution.GetReagentQuantity("fire"), Is.EqualTo(2000));
+ Assert.That(solution.TotalVolume, Is.EqualTo(2500));
+ }
+
+ [Test]
+ public void RemoveLessThanOneQuantityDoesNothing()
+ {
+ var solution = new Solution("water", 100);
+
+ solution.RemoveReagent("water", -100);
+
+ Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(100));
+ Assert.That(solution.TotalVolume, Is.EqualTo(100));
+ }
+
+ [Test]
+ public void RemoveMoreThanTotalRemovesAllReagent()
+ {
+ var solution = new Solution("water", 100);
+
+ solution.RemoveReagent("water", 1000);
+
+ Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(0));
+ Assert.That(solution.TotalVolume, Is.EqualTo(0));
+ }
+
+ [Test]
+ public void RemoveNonExistReagentDoesNothing()
+ {
+ var solution = new Solution("water", 100);
+
+ solution.RemoveReagent("fire", 1000);
+
+ Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(100));
+ Assert.That(solution.TotalVolume, Is.EqualTo(100));
+ }
+
+ [Test]
+ public void RemoveSolution()
+ {
+ var solution = new Solution("water", 700);
+
+ solution.RemoveSolution(500);
+
+ Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(200));
+ Assert.That(solution.TotalVolume, Is.EqualTo(200));
+ }
+
+ [Test]
+ public void RemoveSolutionMoreThanTotalRemovesAll()
+ {
+ var solution = new Solution("water", 800);
+
+ solution.RemoveSolution(1000);
+
+ Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(0));
+ Assert.That(solution.TotalVolume, Is.EqualTo(0));
+ }
+
+ [Test]
+ public void RemoveSolutionRatioPreserved()
+ {
+ var solution = new Solution();
+ solution.AddReagent("water", 1000);
+ solution.AddReagent("fire", 2000);
+
+ solution.RemoveSolution(1500);
+
+ Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(500));
+ Assert.That(solution.GetReagentQuantity("fire"), Is.EqualTo(1000));
+ Assert.That(solution.TotalVolume, Is.EqualTo(1500));
+ }
+
+ [Test]
+ public void RemoveSolutionLessThanOneDoesNothing()
+ {
+ var solution = new Solution("water", 800);
+
+ solution.RemoveSolution(-200);
+
+ Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(800));
+ Assert.That(solution.TotalVolume, Is.EqualTo(800));
+ }
+
+ [Test]
+ public void SplitSolution()
+ {
+ var solution = new Solution();
+ solution.AddReagent("water", 1000);
+ solution.AddReagent("fire", 2000);
+
+ var splitSolution = solution.SplitSolution(750);
+
+ Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(750));
+ Assert.That(solution.GetReagentQuantity("fire"), Is.EqualTo(1500));
+ Assert.That(solution.TotalVolume, Is.EqualTo(2250));
+
+ Assert.That(splitSolution.GetReagentQuantity("water"), Is.EqualTo(250));
+ Assert.That(splitSolution.GetReagentQuantity("fire"), Is.EqualTo(500));
+ Assert.That(splitSolution.TotalVolume, Is.EqualTo(750));
+ }
+
+ [Test]
+ public void SplitSolutionMoreThanTotalRemovesAll()
+ {
+ var solution = new Solution("water", 800);
+
+ var splitSolution = solution.SplitSolution(1000);
+
+ Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(0));
+ Assert.That(solution.TotalVolume, Is.EqualTo(0));
+
+ Assert.That(splitSolution.GetReagentQuantity("water"), Is.EqualTo(800));
+ Assert.That(splitSolution.TotalVolume, Is.EqualTo(800));
+ }
+
+ [Test]
+ public void SplitSolutionLessThanOneDoesNothing()
+ {
+ var solution = new Solution("water", 800);
+
+ var splitSolution = solution.SplitSolution(-200);
+
+ Assert.That(solution.GetReagentQuantity("water"), Is.EqualTo(800));
+ Assert.That(solution.TotalVolume, Is.EqualTo(800));
+
+ Assert.That(splitSolution.GetReagentQuantity("water"), Is.EqualTo(0));
+ Assert.That(splitSolution.TotalVolume, Is.EqualTo(0));
+ }
+
+ [Test]
+ public void AddSolution()
+ {
+ var solutionOne = new Solution();
+ solutionOne.AddReagent("water", 1000);
+ solutionOne.AddReagent("fire", 2000);
+
+ var solutionTwo = new Solution();
+ solutionTwo.AddReagent("water", 500);
+ solutionTwo.AddReagent("earth", 1000);
+
+ solutionOne.AddSolution(solutionTwo);
+
+ Assert.That(solutionOne.GetReagentQuantity("water"), Is.EqualTo(1500));
+ Assert.That(solutionOne.GetReagentQuantity("fire"), Is.EqualTo(2000));
+ Assert.That(solutionOne.GetReagentQuantity("earth"), Is.EqualTo(1000));
+ Assert.That(solutionOne.TotalVolume, Is.EqualTo(4500));
+ }
+ }
+}
diff --git a/Resources/Audio/items/flashlight_toggle.ogg b/Resources/Audio/items/flashlight_toggle.ogg
new file mode 100644
index 0000000000..7839e1f035
Binary files /dev/null and b/Resources/Audio/items/flashlight_toggle.ogg differ
diff --git a/Resources/Audio/items/weapons/pistol_cock.ogg b/Resources/Audio/items/weapons/pistol_cock.ogg
new file mode 100644
index 0000000000..ff2512af27
Binary files /dev/null and b/Resources/Audio/items/weapons/pistol_cock.ogg differ
diff --git a/Resources/Audio/items/weapons/pistol_magin.ogg b/Resources/Audio/items/weapons/pistol_magin.ogg
new file mode 100644
index 0000000000..c442f8b162
Binary files /dev/null and b/Resources/Audio/items/weapons/pistol_magin.ogg differ
diff --git a/Resources/Audio/items/weapons/pistol_magout.ogg b/Resources/Audio/items/weapons/pistol_magout.ogg
new file mode 100644
index 0000000000..334d1a12f2
Binary files /dev/null and b/Resources/Audio/items/weapons/pistol_magout.ogg differ
diff --git a/Resources/Audio/items/weapons/sources.txt b/Resources/Audio/items/weapons/sources.txt
index 5e7f1a1173..03628c6ca9 100644
--- a/Resources/Audio/items/weapons/sources.txt
+++ b/Resources/Audio/items/weapons/sources.txt
@@ -5,3 +5,6 @@ smg_empty_alarm.ogg: https://github.com/discordia-space/CEV-Eris/blob/fbde37a864
casingfall1.ogg: https://github.com/discordia-space/CEV-Eris/blob/fbde37a8647a82587d363da999a94cf02c2e128c/sound/weapons/guns/misc/casingfall1.ogg
casingfall2.ogg: https://github.com/discordia-space/CEV-Eris/blob/fbde37a8647a82587d363da999a94cf02c2e128c/sound/weapons/guns/misc/casingfall2.ogg
casingfall3.ogg: https://github.com/discordia-space/CEV-Eris/blob/fbde37a8647a82587d363da999a94cf02c2e128c/sound/weapons/guns/misc/casingfall3.ogg
+pistol_cock.ogg: https://github.com/discordia-space/CEV-Eris/blob/c0293684320e7b70cbcac932b8dddeee35f3a51f/sound/weapons/guns/interact/pistol_cock.ogg
+pistol_magin.ogg: https://github.com/discordia-space/CEV-Eris/blob/c0293684320e7b70cbcac932b8dddeee35f3a51f/sound/weapons/guns/interact/pistol_magin.ogg
+pistol_magout.ogg: https://github.com/discordia-space/CEV-Eris/blob/c0293684320e7b70cbcac932b8dddeee35f3a51f/sound/weapons/guns/interact/pistol_magout.ogg
diff --git a/Resources/Audio/machines/button.ogg b/Resources/Audio/machines/button.ogg
new file mode 100644
index 0000000000..79b458317a
Binary files /dev/null and b/Resources/Audio/machines/button.ogg differ
diff --git a/Resources/Audio/machines/closetclose.ogg b/Resources/Audio/machines/closetclose.ogg
new file mode 100644
index 0000000000..b1e3c23294
Binary files /dev/null and b/Resources/Audio/machines/closetclose.ogg differ
diff --git a/Resources/Audio/machines/closetopen.ogg b/Resources/Audio/machines/closetopen.ogg
new file mode 100644
index 0000000000..1ee1b0de5c
Binary files /dev/null and b/Resources/Audio/machines/closetopen.ogg differ
diff --git a/Resources/Audio/machines/light_tube_on.ogg b/Resources/Audio/machines/light_tube_on.ogg
index 195e1f9572..deeffa7339 100644
Binary files a/Resources/Audio/machines/light_tube_on.ogg and b/Resources/Audio/machines/light_tube_on.ogg differ
diff --git a/Resources/Fonts/Animal Silence.otf b/Resources/Fonts/Animal Silence.otf
new file mode 100644
index 0000000000..a923bd099d
Binary files /dev/null and b/Resources/Fonts/Animal Silence.otf differ
diff --git a/Resources/Prototypes/Entities/Chemistry.yml b/Resources/Prototypes/Entities/Chemistry.yml
new file mode 100644
index 0000000000..bd7048b73f
--- /dev/null
+++ b/Resources/Prototypes/Entities/Chemistry.yml
@@ -0,0 +1,8 @@
+- type: entity
+ parent: BaseItem
+ id: ReagentItem
+ name: "Reagent Item"
+ abstract: true
+ components:
+ - type: Solution
+ maxVol: 5
\ No newline at end of file
diff --git a/Resources/Prototypes/Entities/Items.yml b/Resources/Prototypes/Entities/Items.yml
deleted file mode 100644
index 137b2ad6d1..0000000000
--- a/Resources/Prototypes/Entities/Items.yml
+++ /dev/null
@@ -1,156 +0,0 @@
-- type: entity
- name: "Item"
- id: BaseItem
- components:
- - type: Item
- Size: 5
- - type: Clickable
- - type: BoundingBox
- aabb: "-0.25,-0.25,0.25,0.25"
- - type: Collidable
- mask: 5
- layer: 8
- IsScrapingFloor: true
- - type: Physics
- mass: 5
- - type: Sprite
- drawdepth: Items
-
-- type: entity
- name: "Emergency Toolbox With Handle"
- parent: BaseItem
- id: RedToolboxItem
- description: A shiny red and robust container
- components:
- - type: Sprite
- texture: Objects/toolbox_r.png
- - type: Icon
- texture: Objects/toolbox_r.png
- - type: Storage
- Capacity: 60
- - type: Item
- Size: 9999
-
-- type: entity
- name: "Mechanical Toolbox With Handle"
- parent: BaseItem
- id: BlueToolboxItem
- description: A blue box, not the kind you're thinking of
- components:
- - type: Sprite
- texture: Objects/Toolbox_b.png
- - type: Icon
- texture: Objects/Toolbox_b.png
- - type: Storage
- Capacity: 60
- - type: Item
- Size: 9999
-
-- type: entity
- name: Electrical Toolbox
- parent: BaseItem
- id: YellowToolboxItem
- description: A toolbox typically stocked with electrical gear
- components:
- - type: Sprite
- texture: Objects/Toolbox_y.png
- - type: Icon
- texture: Objects/Toolbox_y.png
- - type: Storage
- Capacity: 60
- - type: Item
- Size: 9999
-
-- type: entity
- id: YellowToolboxItemFilled
- name: Electrical Toolbox (Filled)
- parent: YellowToolboxItem
- components:
- - type: ToolboxElectricalFill
-
-- type: entity
- name: "Extra-Grip™ Mop"
- parent: BaseItem
- id: MopItem
- description: A mop that cant be stopped, viscera cleanup detail awaits
- components:
- - type: Sprite
- texture: Objects/mop.png
- - type: Icon
- texture: Objects/mop.png
- - type: Item
- Size: 10
-
-- type: entity
- name: "Fire Extinguisher"
- parent: BaseItem
- id: fire_extinguisher
- description: Extinguishes fires.
- components:
- - type: Sprite
- texture: Objects/fire_extinguisher.png
- - type: Icon
- texture: Objects/fire_extinguisher.png
- - type: Item
- Size: 10
-
-#handheld lights
-- type: entity
- name: "Flashlight"
- parent: BaseItem
- id: FlashlightLantern
- description: They light the way to freedom
- components:
- - type: HandheldLight
- - type: Sprite
- sprite: Objects/lantern.rsi
- layers:
- - state: lantern_off
- - state: HandheldLightOnOverlay
- shader: unshaded
- visible: false
- - type: Icon
- sprite: Objects/lantern.rsi
- state: lantern_off
- - type: PointLight
- state: Off
-
-- type: entity
- name: Bike Horn
- parent: BaseItem
- id: BikeHorn
- description: A horn off of a bicycle.
- components:
- - type: Sprite
- sprite: Objects/bikehorn.rsi
- state: icon
-
- - type: Icon
- sprite: Objects/bikehorn.rsi
- state: icon
-
- - type: Item
- Size: 5
- sprite: Objects/bikehorn.rsi
-
- - type: Sound
- - type: EmitSoundOnUse
- sound: /Audio/items/bikehorn.ogg
-
-- type: entity
- name: Table Parts
- parent: BaseItem
- id: TableParts
- description: Parts of a table.
- components:
- - type: Sprite
- sprite: Objects/table_parts.rsi
- state: icon
-
- - type: Icon
- sprite: Objects/table_parts.rsi
- state: icon
-
- - type: Item
- Size: 25
- sprite: Objects/table_parts.rsi
diff --git a/Resources/Prototypes/Entities/Janitor.yml b/Resources/Prototypes/Entities/Janitor.yml
new file mode 100644
index 0000000000..b5f799b554
--- /dev/null
+++ b/Resources/Prototypes/Entities/Janitor.yml
@@ -0,0 +1,46 @@
+- type: entity
+ parent: ReagentItem
+ name: "Extra-Grip™ Mop"
+ id: MopItem
+ description: A mop that cant be stopped, viscera cleanup detail awaits.
+ components:
+ - type: Sprite
+ texture: Objects/mop.png
+ - type: Icon
+ texture: Objects/mop.png
+ - type: Item
+ Size: 10
+ - type: Solution
+ maxVol: 10
+ caps: 1
+
+- type: entity
+ parent: ReagentItem
+ name: Mop Bucket
+ id: MopBucket
+ description: Holds water and the tears of the janitor.
+ components:
+ - type: Sprite
+ texture: Objects/mopbucket.png
+ - type: Icon
+ texture: Objects/mopbucket.png
+ - type: Clickable
+ - type: BoundingBox
+ - type: Solution
+ maxVol: 500
+ caps: 3
+
+- type: entity
+ parent: ReagentItem
+ name: Bucket
+ id: Bucket
+ description: "It's a bucket."
+ components:
+ - type: Sprite
+ texture: Objects/bucket.png
+ - type: Icon
+ texture: Objects/bucket.png
+ - type: Solution
+ maxVol: 500
+ caps: 3
+
\ No newline at end of file
diff --git a/Resources/Prototypes/Entities/PoweredLighting.yml b/Resources/Prototypes/Entities/PoweredLighting.yml
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/Resources/Prototypes/Entities/Projectiles.yml b/Resources/Prototypes/Entities/Projectiles.yml
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/Resources/Prototypes/Entities/Door.yml b/Resources/Prototypes/Entities/buildings/airlock_base.yml
similarity index 61%
rename from Resources/Prototypes/Entities/Door.yml
rename to Resources/Prototypes/Entities/buildings/airlock_base.yml
index 69914433bc..7ee129c9d5 100644
--- a/Resources/Prototypes/Entities/Door.yml
+++ b/Resources/Prototypes/Entities/buildings/airlock_base.yml
@@ -36,31 +36,3 @@
placement:
mode: SnapgridBorder
-
-- type: entity
- parent: airlock
- id: airlock_external
- name: External Airlock
- components:
- - type: Sprite
- sprite: Buildings/airlock_external.rsi
-
- - type: Icon
- sprite: Buildings/airlock_external.rsi
-
- - type: Appearance
- visuals:
- - type: AirlockVisualizer2D
- open_sound: /Audio/machines/airlock_ext_open.ogg
- close_sound: /Audio/machines/airlock_ext_close.ogg
-
-- type: entity
- parent: airlock
- id: airlock_engineering
- name: Engineering Airlock
- components:
- - type: Sprite
- sprite: Buildings/airlock_engineering.rsi
-
- - type: Icon
- sprite: Buildings/airlock_engineering.rsi
diff --git a/Resources/Prototypes/Entities/buildings/airlock_types.yml b/Resources/Prototypes/Entities/buildings/airlock_types.yml
new file mode 100644
index 0000000000..c2e7548bfa
--- /dev/null
+++ b/Resources/Prototypes/Entities/buildings/airlock_types.yml
@@ -0,0 +1,27 @@
+- type: entity
+ parent: airlock
+ id: airlock_external
+ name: External Airlock
+ components:
+ - type: Sprite
+ sprite: Buildings/airlock_external.rsi
+
+ - type: Icon
+ sprite: Buildings/airlock_external.rsi
+
+ - type: Appearance
+ visuals:
+ - type: AirlockVisualizer2D
+ open_sound: /Audio/machines/airlock_ext_open.ogg
+ close_sound: /Audio/machines/airlock_ext_close.ogg
+
+- type: entity
+ parent: airlock
+ id: airlock_engineering
+ name: Engineering Airlock
+ components:
+ - type: Sprite
+ sprite: Buildings/airlock_engineering.rsi
+
+ - type: Icon
+ sprite: Buildings/airlock_engineering.rsi
diff --git a/Resources/Prototypes/Entities/catwalk.yml b/Resources/Prototypes/Entities/buildings/catwalk.yml
similarity index 100%
rename from Resources/Prototypes/Entities/catwalk.yml
rename to Resources/Prototypes/Entities/buildings/catwalk.yml
diff --git a/Resources/Prototypes/Entities/Container.yml b/Resources/Prototypes/Entities/buildings/fuel_tank.yml
similarity index 56%
rename from Resources/Prototypes/Entities/Container.yml
rename to Resources/Prototypes/Entities/buildings/fuel_tank.yml
index 483b6f568a..d4a6605fef 100644
--- a/Resources/Prototypes/Entities/Container.yml
+++ b/Resources/Prototypes/Entities/buildings/fuel_tank.yml
@@ -1,32 +1,3 @@
-- type: entity
- id: crate_generic
- name: Crate
- description: A large container for items.
- components:
- - type: Sprite
- sprite: Buildings/crate.rsi
- layers:
- - state: crate
- - state: crate_door
-
- - type: Icon
- sprite: Buildings/crate.rsi
- state: crate
-
- - type: Clickable
- - type: BoundingBox
- - type: Collidable
- - type: Storage
- Capacity: 60
-
- - type: Damageable
- - type: Destructible
- thresholdvalue: 100
-
- placement:
- snap:
- - Wall
-
- type: entity
id: weldtank
name: Fueltank
@@ -58,4 +29,4 @@
placement:
snap:
- - Wall
\ No newline at end of file
+ - Wall
diff --git a/Resources/Prototypes/Entities/girder.yml b/Resources/Prototypes/Entities/buildings/girder.yml
similarity index 100%
rename from Resources/Prototypes/Entities/girder.yml
rename to Resources/Prototypes/Entities/buildings/girder.yml
diff --git a/Resources/Prototypes/Entities/Lathe.yml b/Resources/Prototypes/Entities/buildings/lathe.yml
similarity index 100%
rename from Resources/Prototypes/Entities/Lathe.yml
rename to Resources/Prototypes/Entities/buildings/lathe.yml
diff --git a/Resources/Prototypes/Entities/Lights.yml b/Resources/Prototypes/Entities/buildings/lighting.yml
similarity index 51%
rename from Resources/Prototypes/Entities/Lights.yml
rename to Resources/Prototypes/Entities/buildings/lighting.yml
index ce44c3087d..f9679aa2b3 100644
--- a/Resources/Prototypes/Entities/Lights.yml
+++ b/Resources/Prototypes/Entities/buildings/lighting.yml
@@ -16,7 +16,7 @@
- type: PointLight
radius: 8
energy: 1.2
- offset: "0, -16"
+ #offset: "0, -16"
color: "#DCDCC6"
placement:
@@ -39,14 +39,14 @@
state: off
- type: PointLight
- state: Off
+ enabled: false
- type: PowerDevice
priority: Low
- type: PoweredLight
bulb: Tube
-
+
- type: entity
name: Small Light
id: poweredsmalllight
@@ -64,7 +64,7 @@
- type: PointLight
energy: 1.0
- state: Off
+ enabled: false
- type: PowerDevice
priority: Low
@@ -72,58 +72,3 @@
- type: PoweredLight
bulb: Bulb
-- type: entity
- parent: BaseItem
- name: BaseLightbulb
- id: BaseLightbulb
- components:
- - type: LightBulb
-
-- type: entity
- parent: BaseLightbulb
- name: Light Tube
- id: LightTube
- components:
- - type: LightBulb
- bulb: Tube
-
- - type: Sprite
- sprite: Objects/light_tube.rsi
- state: normal
-
- - type: Icon
- sprite: Objects/light_tube.rsi
- state: normal
-
-- type: entity
- parent: BaseLightbulb
- name: LED Light Tube
- id: LedLightTube
- components:
- - type: LightBulb
- bulb: Tube
- color: "#EEEEFF"
- BurningTemperature: 350
- PowerUse: 9
- - type: Sprite
- sprite: Objects/light_tube.rsi
- state: normal
- - type: Icon
- sprite: Objects/light_tube.rsi
- state: normal
-
-- type: entity
- parent: BaseLightbulb
- name: Light Bulb
- id: LightBulb
- components:
- - type: LightBulb
- bulb: Bulb
-
- - type: Sprite
- sprite: Objects/light_bulb.rsi
- state: normal
-
- - type: Icon
- sprite: Objects/light_bulb.rsi
- state: normal
\ No newline at end of file
diff --git a/Resources/Prototypes/Entities/buildings/low_wall.yml b/Resources/Prototypes/Entities/buildings/low_wall.yml
new file mode 100644
index 0000000000..7394d08de8
--- /dev/null
+++ b/Resources/Prototypes/Entities/buildings/low_wall.yml
@@ -0,0 +1,32 @@
+- type: entity
+ id: low_wall
+ name: Low Wall
+ description: Goes up to about your waist.
+ components:
+ - type: Clickable
+ - type: Sprite
+ netsync: false
+ color: "#71797a"
+ drawdepth: Walls
+ sprite: Buildings/low_wall.rsi
+
+ - type: Icon
+ sprite: Buildings/low_wall.rsi
+ state: metal
+
+ - type: BoundingBox
+ - type: Collidable
+ - type: Damageable
+ - type: Destructible
+ thresholdvalue: 100
+
+ - type: SnapGrid
+ offset: Center
+
+ - type: LowWall
+ key: walls
+ base: metal_
+
+ placement:
+ snap:
+ - Wall
diff --git a/Resources/Prototypes/Entities/Power.yml b/Resources/Prototypes/Entities/buildings/power.yml
similarity index 100%
rename from Resources/Prototypes/Entities/Power.yml
rename to Resources/Prototypes/Entities/buildings/power.yml
diff --git a/Resources/Prototypes/Entities/buildings/storage/closet_base.yml b/Resources/Prototypes/Entities/buildings/storage/closet_base.yml
new file mode 100644
index 0000000000..6223c880e5
--- /dev/null
+++ b/Resources/Prototypes/Entities/buildings/storage/closet_base.yml
@@ -0,0 +1,41 @@
+- type: entity
+ id: locker_generic
+ name: Locker
+ description: A standard-issue Nanotrasen storage unit.
+ components:
+ - type: Sprite
+ netsync: false
+ sprite: Buildings/closet.rsi
+ layers:
+ - state: generic
+ - state: generic_door
+ map: ["enum.StorageVisualLayers.Door"]
+
+ - type: Icon
+ sprite: Buildings/closet.rsi
+ state: generic_door
+
+ - type: Clickable
+ - type: BoundingBox
+ aabb: "-0.5,-0.25,0.5,0.25"
+ - type: Collidable
+ mask: 3
+ IsScrapingFloor: true
+ - type: Physics
+ mass: 25
+ Anchored: false
+ - type: EntityStorage
+ - type: PlaceableSurface
+ - type: Damageable
+ - type: Destructible
+ thresholdvalue: 100
+ - type: Appearance
+ visuals:
+ - type: StorageVisualizer2D
+ state_open: generic_open
+ state_closed: generic_door
+ - type: Sound
+
+ placement:
+ snap:
+ - Wall
diff --git a/Resources/Prototypes/Entities/buildings/storage/closet_types.yml b/Resources/Prototypes/Entities/buildings/storage/closet_types.yml
new file mode 100644
index 0000000000..744ac26b17
--- /dev/null
+++ b/Resources/Prototypes/Entities/buildings/storage/closet_types.yml
@@ -0,0 +1,90 @@
+- type: entity
+ id: locker_tool
+ name: Tool Locker
+ parent: locker_generic
+ components:
+ - type: Sprite
+ sprite: Buildings/closet.rsi
+ layers:
+ - state: eng
+ - state: eng_tool_door
+ map: ["enum.StorageVisualLayers.Door"]
+
+ - type: Appearance
+ visuals:
+ - type: StorageVisualizer2D
+ state_open: eng_open
+ state_closed: eng_tool_door
+
+ - type: Icon
+ state: eng_tool_door
+
+- type: entity
+ id: locker_tool_filled
+ name: Tool Locker (Filled)
+ parent: locker_tool
+ components:
+ - type: ToolLockerFill
+
+- type: entity
+ id: locker_electrical_supplies
+ name: Electrical Supplies Locker
+ parent: locker_generic
+ components:
+ - type: Sprite
+ sprite: Buildings/closet.rsi
+ layers:
+ - state: eng
+ - state: eng_elec_door
+ map: ["enum.StorageVisualLayers.Door"]
+
+ - type: Appearance
+ visuals:
+ - type: StorageVisualizer2D
+ state_open: eng_open
+ state_closed: eng_elec_door
+
+ - type: Icon
+ state: eng_elec_door
+
+- type: entity
+ id: locker_welding_supplies
+ name: Welding Supplies Locker
+ parent: locker_generic
+ components:
+ - type: Sprite
+ sprite: Buildings/closet.rsi
+ layers:
+ - state: eng
+ - state: eng_weld_door
+ map: ["enum.StorageVisualLayers.Door"]
+
+ - type: Appearance
+ visuals:
+ - type: StorageVisualizer2D
+ state_open: eng_open
+ state_closed: eng_weld_door
+
+ - type: Icon
+ state: eng_weld_door
+
+- type: entity
+ id: locker_radiation_suit
+ name: Radiation Suit Locker
+ parent: locker_generic
+ components:
+ - type: Sprite
+ sprite: Buildings/closet.rsi
+ layers:
+ - state: eng
+ - state: eng_rad_door
+ map: ["enum.StorageVisualLayers.Door"]
+
+ - type: Appearance
+ visuals:
+ - type: StorageVisualizer2D
+ state_open: eng_open
+ state_closed: eng_rad_door
+
+ - type: Icon
+ state: eng_rad_door
diff --git a/Resources/Prototypes/Entities/buildings/storage/crate_base.yml b/Resources/Prototypes/Entities/buildings/storage/crate_base.yml
new file mode 100644
index 0000000000..7de66823e1
--- /dev/null
+++ b/Resources/Prototypes/Entities/buildings/storage/crate_base.yml
@@ -0,0 +1,41 @@
+- type: entity
+ id: crate_generic
+ name: Crate
+ description: A large container for items.
+ components:
+ - type: Sprite
+ netsync: false
+ sprite: Buildings/crate.rsi
+ layers:
+ - state: crate
+ - state: crate_door
+ map: ["enum.StorageVisualLayers.Door"]
+
+ - type: Icon
+ sprite: Buildings/crate.rsi
+ state: crate
+
+ - type: Clickable
+ - type: BoundingBox
+ aabb: -0.4, -0.4, 0.4, 0.4
+
+ - type: Physics
+ mass: 25
+ Anchored: false
+
+ - type: Collidable
+ - type: EntityStorage
+ Capacity: 60
+ - type: PlaceableSurface
+
+ - type: Damageable
+ - type: Destructible
+ thresholdvalue: 100
+
+ - type: Appearance
+ visuals:
+ - type: StorageVisualizer2D
+ state_open: crate_open
+ state_closed: crate_door
+
+ - type: Sound
diff --git a/Resources/Prototypes/Entities/buildings/storage/crate_types.yml b/Resources/Prototypes/Entities/buildings/storage/crate_types.yml
new file mode 100644
index 0000000000..6f4238d1fa
--- /dev/null
+++ b/Resources/Prototypes/Entities/buildings/storage/crate_types.yml
@@ -0,0 +1,120 @@
+- type: entity
+ id: crate_plastic
+ name: Plastic Crate
+ parent: crate_generic
+ components:
+ - type: Sprite
+ layers:
+ - state: plasticcrate
+ - state: plasticcrate_door
+ map: ["enum.StorageVisualLayers.Door"]
+
+ - type: Appearance
+ visuals:
+ - type: StorageVisualizer2D
+ state_open: plasticcrate_open
+ state_closed: plasticcrate_door
+
+ - type: Icon
+ state: plasticcrate
+
+- type: entity
+ id: crate_freezer
+ name: Freezer
+ parent: crate_generic
+ components:
+ - type: Sprite
+ layers:
+ - state: freezer
+ - state: freezer_door
+ map: ["enum.StorageVisualLayers.Door"]
+
+ - type: Appearance
+ visuals:
+ - type: StorageVisualizer2D
+ state_open: freezer_open
+ state_closed: freezer_door
+
+ - type: Icon
+ state: freezer
+
+- type: entity
+ id: crate_hydroponics
+ name: Hydroponics Crate
+ parent: crate_generic
+ components:
+ - type: Sprite
+ layers:
+ - state: hydrocrate
+ - state: hydrocrate_door
+ map: ["enum.StorageVisualLayers.Door"]
+
+ - type: Appearance
+ visuals:
+ - type: StorageVisualizer2D
+ state_open: hydrocrate_open
+ state_closed: hydrocrate_door
+
+ - type: Icon
+ state: hydrocrate
+
+- type: entity
+ id: crate_medical
+ name: Medical Crate
+ parent: crate_generic
+ components:
+ - type: Sprite
+ layers:
+ - state: medicalcrate
+ - state: medicalcrate_door
+ map: ["enum.StorageVisualLayers.Door"]
+
+ - type: Appearance
+ visuals:
+ - type: StorageVisualizer2D
+ state_open: medicalcrate_open
+ state_closed: medicalcrate_door
+
+ - type: Icon
+ state: medicalcrate
+
+- type: entity
+ id: crate_radiation
+ name: Radiation Gear Crate
+ description: Is not actually lead lined. Do not store your plutonium in this.
+ parent: crate_generic
+ components:
+ - type: Sprite
+ layers:
+ - state: radiationcrate
+ - state: radiationcrate_door
+ map: ["enum.StorageVisualLayers.Door"]
+
+ - type: Appearance
+ visuals:
+ - type: StorageVisualizer2D
+ state_open: radiationcrate_open
+ state_closed: radiationcrate_door
+
+ - type: Icon
+ state: radiationcrate
+
+- type: entity
+ id: crate_internals
+ name: Internals Crate
+ parent: crate_generic
+ components:
+ - type: Sprite
+ layers:
+ - state: o2crate
+ - state: o2crate_door
+ map: ["enum.StorageVisualLayers.Door"]
+
+ - type: Appearance
+ visuals:
+ - type: StorageVisualizer2D
+ state_open: o2crate_open
+ state_closed: o2crate_door
+
+ - type: Icon
+ state: o2crate
diff --git a/Resources/Prototypes/Entities/table.yml b/Resources/Prototypes/Entities/buildings/table.yml
similarity index 100%
rename from Resources/Prototypes/Entities/table.yml
rename to Resources/Prototypes/Entities/buildings/table.yml
diff --git a/Resources/Prototypes/Entities/Turret.yml b/Resources/Prototypes/Entities/buildings/turret.yml
similarity index 100%
rename from Resources/Prototypes/Entities/Turret.yml
rename to Resources/Prototypes/Entities/buildings/turret.yml
diff --git a/Resources/Prototypes/Entities/walls.yml b/Resources/Prototypes/Entities/buildings/walls.yml
similarity index 82%
rename from Resources/Prototypes/Entities/walls.yml
rename to Resources/Prototypes/Entities/buildings/walls.yml
index 3f571b595c..1d76d42830 100644
--- a/Resources/Prototypes/Entities/walls.yml
+++ b/Resources/Prototypes/Entities/buildings/walls.yml
@@ -5,7 +5,7 @@
- type: Clickable
- type: Sprite
netsync: false
- color: "#636769"
+ color: "#71797a"
drawdepth: Walls
sprite: Buildings/wall.rsi
@@ -23,10 +23,10 @@
sizeX: 32
sizeY: 32
- type: SnapGrid
- offset: Edge
+ offset: Center
- type: IconSmooth
- key: walls. Seriously, just a wall. Nothing extraordinary here.
+ key: walls
base: solid
placement:
diff --git a/Resources/Prototypes/Entities/buildings/windows.yml b/Resources/Prototypes/Entities/buildings/windows.yml
new file mode 100644
index 0000000000..550b606c84
--- /dev/null
+++ b/Resources/Prototypes/Entities/buildings/windows.yml
@@ -0,0 +1,30 @@
+- type: entity
+ id: window
+ name: Window
+ description: Don't smudge up the glass down there.
+ components:
+ - type: Clickable
+ - type: Sprite
+ netsync: false
+ drawdepth: WallTops
+ sprite: Buildings/window.rsi
+
+ - type: Icon
+ sprite: Buildings/window.rsi
+ state: window0
+
+ - type: BoundingBox
+ - type: Collidable
+ - type: Damageable
+ - type: Destructible
+ thresholdvalue: 100
+
+ - type: SnapGrid
+ offset: Center
+
+ - type: Window
+ base: window
+
+ placement:
+ snap:
+ - Wall
diff --git a/Resources/Prototypes/Entities/closet.yml b/Resources/Prototypes/Entities/closet.yml
deleted file mode 100644
index dd68a6f66a..0000000000
--- a/Resources/Prototypes/Entities/closet.yml
+++ /dev/null
@@ -1,130 +0,0 @@
-- type: entity
- id: locker_generic
- name: Locker
- description: A standard-issue Nanotrasen storage unit.
- components:
- - type: Sprite
- sprite: Buildings/closet.rsi
- layers:
- - state: generic
- - state: generic_door
- map: ["enum.StorageVisualLayers.Door"]
-
- - type: Icon
- sprite: Buildings/closet.rsi
- state: generic_door
-
- - type: Clickable
- - type: BoundingBox
- aabb: "-0.5,-0.25,0.5,0.25"
- - type: Collidable
- mask: 3
- IsScrapingFloor: true
- - type: Physics
- mass: 25
- Anchored: false
- - type: EntityStorage
- - type: PlaceableSurface
- - type: Damageable
- - type: Destructible
- thresholdvalue: 100
- - type: Appearance
- visuals:
- - type: StorageVisualizer2D
- state_open: generic_open
- state_closed: generic_door
-
- placement:
- snap:
- - Wall
-
-- type: entity
- id: locker_tool
- name: Tool Locker
- parent: locker_generic
- components:
- - type: Sprite
- sprite: Buildings/closet.rsi
- layers:
- - state: eng
- - state: eng_tool_door
- map: ["enum.StorageVisualLayers.Door"]
-
- - type: Appearance
- visuals:
- - type: StorageVisualizer2D
- state_open: eng_open
- state_closed: eng_tool_door
-
- - type: Icon
- state: eng_tool_door
-
-- type: entity
- id: locker_tool_filled
- name: Tool Locker (Filled)
- parent: locker_tool
- components:
- - type: ToolLockerFill
-
-- type: entity
- id: locker_electrical_supplies
- name: Electrical Supplies Locker
- parent: locker_generic
- components:
- - type: Sprite
- sprite: Buildings/closet.rsi
- layers:
- - state: eng
- - state: eng_elec_door
- map: ["enum.StorageVisualLayers.Door"]
-
- - type: Appearance
- visuals:
- - type: StorageVisualizer2D
- state_open: eng_open
- state_closed: eng_elec_door
-
- - type: Icon
- state: eng_elec_door
-
-- type: entity
- id: locker_welding_supplies
- name: Welding Supplies Locker
- parent: locker_generic
- components:
- - type: Sprite
- sprite: Buildings/closet.rsi
- layers:
- - state: eng
- - state: eng_weld_door
- map: ["enum.StorageVisualLayers.Door"]
-
- - type: Appearance
- visuals:
- - type: StorageVisualizer2D
- state_open: eng_open
- state_closed: eng_weld_door
-
- - type: Icon
- state: eng_weld_door
-
-- type: entity
- id: locker_radiation_suit
- name: Radiation Suit Locker
- parent: locker_generic
- components:
- - type: Sprite
- sprite: Buildings/closet.rsi
- layers:
- - state: eng
- - state: eng_rad_door
- map: ["enum.StorageVisualLayers.Door"]
-
- - type: Appearance
- visuals:
- - type: StorageVisualizer2D
- state_open: eng_open
- state_closed: eng_rad_door
-
- - type: Icon
- state: eng_rad_door
diff --git a/Resources/Prototypes/Entities/items/bike_horn.yml b/Resources/Prototypes/Entities/items/bike_horn.yml
new file mode 100644
index 0000000000..f5f8c1fa34
--- /dev/null
+++ b/Resources/Prototypes/Entities/items/bike_horn.yml
@@ -0,0 +1,21 @@
+- type: entity
+ name: Bike Horn
+ parent: BaseItem
+ id: BikeHorn
+ description: A horn off of a bicycle.
+ components:
+ - type: Sprite
+ sprite: Objects/bikehorn.rsi
+ state: icon
+
+ - type: Icon
+ sprite: Objects/bikehorn.rsi
+ state: icon
+
+ - type: Item
+ Size: 5
+ sprite: Objects/bikehorn.rsi
+
+ - type: Sound
+ - type: EmitSoundOnUse
+ sound: /Audio/items/bikehorn.ogg
diff --git a/Resources/Prototypes/Entities/Clothing/IDs.yml b/Resources/Prototypes/Entities/items/clothing/IDs.yml
similarity index 100%
rename from Resources/Prototypes/Entities/Clothing/IDs.yml
rename to Resources/Prototypes/Entities/items/clothing/IDs.yml
diff --git a/Resources/Prototypes/Entities/Clothing/backpacks.yml b/Resources/Prototypes/Entities/items/clothing/backpacks.yml
similarity index 100%
rename from Resources/Prototypes/Entities/Clothing/backpacks.yml
rename to Resources/Prototypes/Entities/items/clothing/backpacks.yml
diff --git a/Resources/Prototypes/Entities/Clothing/belts.yml b/Resources/Prototypes/Entities/items/clothing/belts.yml
similarity index 100%
rename from Resources/Prototypes/Entities/Clothing/belts.yml
rename to Resources/Prototypes/Entities/items/clothing/belts.yml
diff --git a/Resources/Prototypes/Entities/Clothing.yml b/Resources/Prototypes/Entities/items/clothing/clothing_base.yml
similarity index 100%
rename from Resources/Prototypes/Entities/Clothing.yml
rename to Resources/Prototypes/Entities/items/clothing/clothing_base.yml
diff --git a/Resources/Prototypes/Entities/Clothing/ears.yml b/Resources/Prototypes/Entities/items/clothing/ears.yml
similarity index 100%
rename from Resources/Prototypes/Entities/Clothing/ears.yml
rename to Resources/Prototypes/Entities/items/clothing/ears.yml
diff --git a/Resources/Prototypes/Entities/Clothing/eyes.yml b/Resources/Prototypes/Entities/items/clothing/eyes.yml
similarity index 100%
rename from Resources/Prototypes/Entities/Clothing/eyes.yml
rename to Resources/Prototypes/Entities/items/clothing/eyes.yml
diff --git a/Resources/Prototypes/Entities/Clothing/gloves.yml b/Resources/Prototypes/Entities/items/clothing/gloves.yml
similarity index 100%
rename from Resources/Prototypes/Entities/Clothing/gloves.yml
rename to Resources/Prototypes/Entities/items/clothing/gloves.yml
diff --git a/Resources/Prototypes/Entities/Clothing/helmets.yml b/Resources/Prototypes/Entities/items/clothing/helmets.yml
similarity index 95%
rename from Resources/Prototypes/Entities/Clothing/helmets.yml
rename to Resources/Prototypes/Entities/items/clothing/helmets.yml
index 056bb679f2..092e487d4a 100644
--- a/Resources/Prototypes/Entities/Clothing/helmets.yml
+++ b/Resources/Prototypes/Entities/items/clothing/helmets.yml
@@ -38,7 +38,7 @@
components:
- type: HandheldLight
- type: PointLight
- state: Off
+ enabled: false
- type: Sprite
sprite: Clothing/helmet_engineering.rsi
layers:
@@ -52,4 +52,4 @@
- type: Clothing
Slots:
- head
- sprite: Clothing/helmet_engineering.rsi
\ No newline at end of file
+ sprite: Clothing/helmet_engineering.rsi
diff --git a/Resources/Prototypes/Entities/Clothing/masks.yml b/Resources/Prototypes/Entities/items/clothing/masks.yml
similarity index 100%
rename from Resources/Prototypes/Entities/Clothing/masks.yml
rename to Resources/Prototypes/Entities/items/clothing/masks.yml
diff --git a/Resources/Prototypes/Entities/Clothing/shoes.yml b/Resources/Prototypes/Entities/items/clothing/shoes.yml
similarity index 100%
rename from Resources/Prototypes/Entities/Clothing/shoes.yml
rename to Resources/Prototypes/Entities/items/clothing/shoes.yml
diff --git a/Resources/Prototypes/Entities/Clothing/suits.yml b/Resources/Prototypes/Entities/items/clothing/suits.yml
similarity index 100%
rename from Resources/Prototypes/Entities/Clothing/suits.yml
rename to Resources/Prototypes/Entities/items/clothing/suits.yml
diff --git a/Resources/Prototypes/Entities/Clothing/uniforms.yml b/Resources/Prototypes/Entities/items/clothing/uniforms.yml
similarity index 100%
rename from Resources/Prototypes/Entities/Clothing/uniforms.yml
rename to Resources/Prototypes/Entities/items/clothing/uniforms.yml
diff --git a/Resources/Prototypes/Entities/Dice.yml b/Resources/Prototypes/Entities/items/dice.yml
similarity index 100%
rename from Resources/Prototypes/Entities/Dice.yml
rename to Resources/Prototypes/Entities/items/dice.yml
diff --git a/Resources/Prototypes/Entities/Explosives.yml b/Resources/Prototypes/Entities/items/explosives.yml
similarity index 100%
rename from Resources/Prototypes/Entities/Explosives.yml
rename to Resources/Prototypes/Entities/items/explosives.yml
diff --git a/Resources/Prototypes/Entities/items/fire_extinguisher.yml b/Resources/Prototypes/Entities/items/fire_extinguisher.yml
new file mode 100644
index 0000000000..4a8a847631
--- /dev/null
+++ b/Resources/Prototypes/Entities/items/fire_extinguisher.yml
@@ -0,0 +1,12 @@
+- type: entity
+ name: Fire Extinguisher
+ parent: BaseItem
+ id: fire_extinguisher
+ description: Extinguishes fires.
+ components:
+ - type: Sprite
+ texture: Objects/fire_extinguisher.png
+ - type: Icon
+ texture: Objects/fire_extinguisher.png
+ - type: Item
+ Size: 10
diff --git a/Resources/Prototypes/Entities/items/flashlight.yml b/Resources/Prototypes/Entities/items/flashlight.yml
new file mode 100644
index 0000000000..886dd4cf51
--- /dev/null
+++ b/Resources/Prototypes/Entities/items/flashlight.yml
@@ -0,0 +1,20 @@
+- type: entity
+ name: Flashlight
+ parent: BaseItem
+ id: FlashlightLantern
+ description: They light the way to freedom
+ components:
+ - type: HandheldLight
+ - type: Sprite
+ sprite: Objects/lantern.rsi
+ layers:
+ - state: lantern_off
+ - state: HandheldLightOnOverlay
+ shader: unshaded
+ visible: false
+ - type: Icon
+ sprite: Objects/lantern.rsi
+ state: lantern_off
+ - type: PointLight
+ enabled: false
+ - type: Sound
diff --git a/Resources/Prototypes/Entities/items/item_base.yml b/Resources/Prototypes/Entities/items/item_base.yml
new file mode 100644
index 0000000000..b5be445067
--- /dev/null
+++ b/Resources/Prototypes/Entities/items/item_base.yml
@@ -0,0 +1,17 @@
+- type: entity
+ name: "Item"
+ id: BaseItem
+ components:
+ - type: Item
+ Size: 5
+ - type: Clickable
+ - type: BoundingBox
+ aabb: "-0.25,-0.25,0.25,0.25"
+ - type: Collidable
+ mask: 5
+ layer: 8
+ IsScrapingFloor: true
+ - type: Physics
+ mass: 5
+ - type: Sprite
+ drawdepth: Items
diff --git a/Resources/Prototypes/Entities/items/light_bulb.yml b/Resources/Prototypes/Entities/items/light_bulb.yml
new file mode 100644
index 0000000000..fb6dadc64a
--- /dev/null
+++ b/Resources/Prototypes/Entities/items/light_bulb.yml
@@ -0,0 +1,56 @@
+- type: entity
+ parent: BaseLightbulb
+ name: Light Bulb
+ id: LightBulb
+ components:
+ - type: LightBulb
+ bulb: Bulb
+
+ - type: Sprite
+ sprite: Objects/light_bulb.rsi
+ state: normal
+
+ - type: Icon
+ sprite: Objects/light_bulb.rsi
+ state: normal
+
+- type: entity
+ parent: BaseItem
+ name: BaseLightbulb
+ id: BaseLightbulb
+ components:
+ - type: LightBulb
+
+- type: entity
+ parent: BaseLightbulb
+ name: Light Tube
+ id: LightTube
+ components:
+ - type: LightBulb
+ bulb: Tube
+
+ - type: Sprite
+ sprite: Objects/light_tube.rsi
+ state: normal
+
+ - type: Icon
+ sprite: Objects/light_tube.rsi
+ state: normal
+
+- type: entity
+ parent: BaseLightbulb
+ name: LED Light Tube
+ id: LedLightTube
+ components:
+ - type: LightBulb
+ bulb: Tube
+ color: "#EEEEFF"
+ BurningTemperature: 350
+ PowerUse: 9
+ - type: Sprite
+ sprite: Objects/light_tube.rsi
+ state: normal
+ - type: Icon
+ sprite: Objects/light_tube.rsi
+ state: normal
+
diff --git a/Resources/Prototypes/Entities/Materials.yml b/Resources/Prototypes/Entities/items/materials.yml
similarity index 100%
rename from Resources/Prototypes/Entities/Materials.yml
rename to Resources/Prototypes/Entities/items/materials.yml
diff --git a/Resources/Prototypes/Entities/Medical.yml b/Resources/Prototypes/Entities/items/medical.yml
similarity index 100%
rename from Resources/Prototypes/Entities/Medical.yml
rename to Resources/Prototypes/Entities/items/medical.yml
diff --git a/Resources/Prototypes/Entities/powercells.yml b/Resources/Prototypes/Entities/items/powercells.yml
similarity index 100%
rename from Resources/Prototypes/Entities/powercells.yml
rename to Resources/Prototypes/Entities/items/powercells.yml
diff --git a/Resources/Prototypes/Entities/items/table_parts.yml b/Resources/Prototypes/Entities/items/table_parts.yml
new file mode 100644
index 0000000000..88a59b2705
--- /dev/null
+++ b/Resources/Prototypes/Entities/items/table_parts.yml
@@ -0,0 +1,17 @@
+- type: entity
+ name: Table Parts
+ parent: BaseItem
+ id: TableParts
+ description: Parts of a table.
+ components:
+ - type: Sprite
+ sprite: Objects/table_parts.rsi
+ state: icon
+
+ - type: Icon
+ sprite: Objects/table_parts.rsi
+ state: icon
+
+ - type: Item
+ Size: 25
+ sprite: Objects/table_parts.rsi
diff --git a/Resources/Prototypes/Entities/Teleporters.yml b/Resources/Prototypes/Entities/items/teleporters.yml
similarity index 100%
rename from Resources/Prototypes/Entities/Teleporters.yml
rename to Resources/Prototypes/Entities/items/teleporters.yml
diff --git a/Resources/Prototypes/Entities/items/toolbox.yml b/Resources/Prototypes/Entities/items/toolbox.yml
new file mode 100644
index 0000000000..8516602a9c
--- /dev/null
+++ b/Resources/Prototypes/Entities/items/toolbox.yml
@@ -0,0 +1,51 @@
+- type: entity
+ name: Emergency Toolbox
+ parent: BaseItem
+ id: RedToolboxItem
+ description: A shiny red and robust container
+ components:
+ - type: Sprite
+ texture: Objects/toolbox_r.png
+ - type: Icon
+ texture: Objects/toolbox_r.png
+ - type: Storage
+ Capacity: 60
+ - type: Item
+ Size: 9999
+
+- type: entity
+ name: Mechanical Toolbox
+ parent: BaseItem
+ id: BlueToolboxItem
+ description: A blue box, not the kind you're thinking of
+ components:
+ - type: Sprite
+ texture: Objects/Toolbox_b.png
+ - type: Icon
+ texture: Objects/Toolbox_b.png
+ - type: Storage
+ Capacity: 60
+ - type: Item
+ Size: 9999
+
+- type: entity
+ name: Electrical Toolbox
+ parent: BaseItem
+ id: YellowToolboxItem
+ description: A toolbox typically stocked with electrical gear
+ components:
+ - type: Sprite
+ texture: Objects/Toolbox_y.png
+ - type: Icon
+ texture: Objects/Toolbox_y.png
+ - type: Storage
+ Capacity: 60
+ - type: Item
+ Size: 9999
+
+- type: entity
+ id: YellowToolboxItemFilled
+ name: Electrical Toolbox (Filled)
+ parent: YellowToolboxItem
+ components:
+ - type: ToolboxElectricalFill
diff --git a/Resources/Prototypes/Entities/Tools.yml b/Resources/Prototypes/Entities/items/tools.yml
similarity index 100%
rename from Resources/Prototypes/Entities/Tools.yml
rename to Resources/Prototypes/Entities/items/tools.yml
diff --git a/Resources/Prototypes/Entities/weapons/ammunition.yml b/Resources/Prototypes/Entities/items/weapons/ammunition.yml
similarity index 100%
rename from Resources/Prototypes/Entities/weapons/ammunition.yml
rename to Resources/Prototypes/Entities/items/weapons/ammunition.yml
diff --git a/Resources/Prototypes/Entities/weapons/guns.yml b/Resources/Prototypes/Entities/items/weapons/guns.yml
similarity index 100%
rename from Resources/Prototypes/Entities/weapons/guns.yml
rename to Resources/Prototypes/Entities/items/weapons/guns.yml
diff --git a/Resources/Prototypes/Entities/weapons/laserguns.yml b/Resources/Prototypes/Entities/items/weapons/laserguns.yml
similarity index 100%
rename from Resources/Prototypes/Entities/weapons/laserguns.yml
rename to Resources/Prototypes/Entities/items/weapons/laserguns.yml
diff --git a/Resources/Prototypes/Entities/weapons/projectiles.yml b/Resources/Prototypes/Entities/items/weapons/projectiles.yml
similarity index 100%
rename from Resources/Prototypes/Entities/weapons/projectiles.yml
rename to Resources/Prototypes/Entities/items/weapons/projectiles.yml
diff --git a/Resources/Prototypes/Entities/Weapons.yml b/Resources/Prototypes/Entities/items/weapons/spear.yml
similarity index 100%
rename from Resources/Prototypes/Entities/Weapons.yml
rename to Resources/Prototypes/Entities/items/weapons/spear.yml
diff --git a/Resources/Prototypes/Entities/Construction.yml b/Resources/Prototypes/Entities/markers/construction_ghost.yml
similarity index 100%
rename from Resources/Prototypes/Entities/Construction.yml
rename to Resources/Prototypes/Entities/markers/construction_ghost.yml
diff --git a/Resources/Prototypes/Entities/mobs/adminghost.yml b/Resources/Prototypes/Entities/mobs/adminghost.yml
new file mode 100644
index 0000000000..736f388b67
--- /dev/null
+++ b/Resources/Prototypes/Entities/mobs/adminghost.yml
@@ -0,0 +1,4 @@
+- type: entity
+ parent: MobObserver
+ save: false
+ id: AdminObserver
diff --git a/Resources/Prototypes/Entities/Mobs.yml b/Resources/Prototypes/Entities/mobs/human.yml
similarity index 78%
rename from Resources/Prototypes/Entities/Mobs.yml
rename to Resources/Prototypes/Entities/mobs/human.yml
index 5d5d58865f..fc390c9609 100644
--- a/Resources/Prototypes/Entities/Mobs.yml
+++ b/Resources/Prototypes/Entities/mobs/human.yml
@@ -69,26 +69,3 @@
- type: Examiner
- type: CharacterInfo
-- type: entity
- id: MobObserver
- name: Observer
- save: false
- description: Boo!
- components:
- - type: Physics
- mass: 5
- - type: Eye
- zoom: 0.5, 0.5
- - type: BoundingBox
- aabb: "-0.5,-0.25,-0.05,0.25"
- - type: Input
- context: "ghost"
- - type: Examiner
- DoRangeCheck: false
-
-
-- type: entity
- parent: MobObserver
- save: false
- id: AdminObserver
-
diff --git a/Resources/Prototypes/Entities/mobs/observer.yml b/Resources/Prototypes/Entities/mobs/observer.yml
new file mode 100644
index 0000000000..28cbf23009
--- /dev/null
+++ b/Resources/Prototypes/Entities/mobs/observer.yml
@@ -0,0 +1,16 @@
+- type: entity
+ id: MobObserver
+ name: Observer
+ save: false
+ description: Boo!
+ components:
+ - type: Physics
+ mass: 5
+ - type: Eye
+ zoom: 0.5, 0.5
+ - type: BoundingBox
+ aabb: "-0.5,-0.25,-0.05,0.25"
+ - type: Input
+ context: "ghost"
+ - type: Examiner
+ DoRangeCheck: false
diff --git a/Resources/Prototypes/Entities/water_tank.yml b/Resources/Prototypes/Entities/water_tank.yml
new file mode 100644
index 0000000000..27b1620c11
--- /dev/null
+++ b/Resources/Prototypes/Entities/water_tank.yml
@@ -0,0 +1,46 @@
+- type: entity
+ parent: ReagentItem
+ id: watertank
+ name: Water Tank
+ description: "A water tank. It is used to store high amounts of water."
+ components:
+ - type: Sprite
+ texture: Buildings/watertank.png
+
+ - type: Icon
+ texture: Buildings/watertank.png
+
+ - type: Clickable
+ - type: BoundingBox
+ aabb: "-0.5,-0.25,0.5,0.25"
+ - type: Collidable
+ mask: 3
+ layer: 1
+ IsScrapingFloor: true
+ - type: Physics
+ mass: 15
+ Anchored: false
+
+ - type: Damageable
+ - type: Destructible
+ thresholdvalue: 10
+
+ - type: Solution
+ maxVol: 1500
+ caps: 3
+
+
+ placement:
+ snap:
+ - Wall
+
+- type: entity
+ parent: watertank
+ id: watertank_full
+ components:
+ - type: Solution
+ contents:
+ reagents:
+ - ReagentId: chem.H2O
+ Quantity: 1500
+
\ No newline at end of file
diff --git a/Resources/Prototypes/Reagents/chemicals.yml b/Resources/Prototypes/Reagents/chemicals.yml
new file mode 100644
index 0000000000..f698560651
--- /dev/null
+++ b/Resources/Prototypes/Reagents/chemicals.yml
@@ -0,0 +1,9 @@
+- type: reagent
+ id: chem.H2SO4
+ name: Sulfuric Acid
+ desc: A highly corrosive, oily, colorless liquid.
+
+- type: reagent
+ id: chem.H2O
+ name: Water
+ desc: A tasty colorless liquid.
\ No newline at end of file
diff --git a/Resources/Prototypes/Reagents/elements.yml b/Resources/Prototypes/Reagents/elements.yml
new file mode 100644
index 0000000000..461a9c4d0a
--- /dev/null
+++ b/Resources/Prototypes/Reagents/elements.yml
@@ -0,0 +1,16 @@
+- type: reagent
+ id: chem.H2
+ name: Hydrogen
+ desc: A light, flammable gas.
+
+- type: reagent
+ id: chem.O2
+ name: Oxygen
+ desc: An oxidizing, colorless gas.
+
+- type: reagent
+ id: chem.S8
+ name: Sulfur
+ desc: A yellow, crystalline solid.
+ color: "#FFFACD"
+
\ No newline at end of file
diff --git a/Resources/Textures/Buildings/crate.rsi/crate.png b/Resources/Textures/Buildings/crate.rsi/crate.png
index c6a11f9f6a..09ceade5d2 100644
Binary files a/Resources/Textures/Buildings/crate.rsi/crate.png and b/Resources/Textures/Buildings/crate.rsi/crate.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/crate_door.png b/Resources/Textures/Buildings/crate.rsi/crate_door.png
index a191869066..c0546d988e 100644
Binary files a/Resources/Textures/Buildings/crate.rsi/crate_door.png and b/Resources/Textures/Buildings/crate.rsi/crate_door.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/crate_open.png b/Resources/Textures/Buildings/crate.rsi/crate_open.png
index abafc09751..05c811e36f 100644
Binary files a/Resources/Textures/Buildings/crate.rsi/crate_open.png and b/Resources/Textures/Buildings/crate.rsi/crate_open.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/freezer.png b/Resources/Textures/Buildings/crate.rsi/freezer.png
new file mode 100644
index 0000000000..90c0d5715e
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/freezer.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/freezer_door.png b/Resources/Textures/Buildings/crate.rsi/freezer_door.png
new file mode 100644
index 0000000000..a03690e115
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/freezer_door.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/freezer_open.png b/Resources/Textures/Buildings/crate.rsi/freezer_open.png
new file mode 100644
index 0000000000..0ab9fd3996
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/freezer_open.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/hydrocrate.png b/Resources/Textures/Buildings/crate.rsi/hydrocrate.png
new file mode 100644
index 0000000000..8f717bb2f9
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/hydrocrate.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/hydrocrate_door.png b/Resources/Textures/Buildings/crate.rsi/hydrocrate_door.png
new file mode 100644
index 0000000000..b6d9ca8cf8
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/hydrocrate_door.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/hydrocrate_open.png b/Resources/Textures/Buildings/crate.rsi/hydrocrate_open.png
new file mode 100644
index 0000000000..05c811e36f
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/hydrocrate_open.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/hydrosecurecrate.png b/Resources/Textures/Buildings/crate.rsi/hydrosecurecrate.png
new file mode 100644
index 0000000000..e555d8cd8c
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/hydrosecurecrate.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/hydrosecurecrate_door.png b/Resources/Textures/Buildings/crate.rsi/hydrosecurecrate_door.png
new file mode 100644
index 0000000000..4ea9cf39e1
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/hydrosecurecrate_door.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/hydrosecurecrate_open.png b/Resources/Textures/Buildings/crate.rsi/hydrosecurecrate_open.png
new file mode 100644
index 0000000000..05c811e36f
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/hydrosecurecrate_open.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/lock_locked.png b/Resources/Textures/Buildings/crate.rsi/lock_locked.png
new file mode 100644
index 0000000000..e2fde877e8
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/lock_locked.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/lock_off.png b/Resources/Textures/Buildings/crate.rsi/lock_off.png
new file mode 100644
index 0000000000..783088854b
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/lock_off.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/lock_unlocked.png b/Resources/Textures/Buildings/crate.rsi/lock_unlocked.png
new file mode 100644
index 0000000000..83175cbb8e
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/lock_unlocked.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/medicalcrate.png b/Resources/Textures/Buildings/crate.rsi/medicalcrate.png
new file mode 100644
index 0000000000..cfc42cc577
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/medicalcrate.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/medicalcrate_door.png b/Resources/Textures/Buildings/crate.rsi/medicalcrate_door.png
new file mode 100644
index 0000000000..1ad547beb9
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/medicalcrate_door.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/medicalcrate_open.png b/Resources/Textures/Buildings/crate.rsi/medicalcrate_open.png
new file mode 100644
index 0000000000..0ab9fd3996
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/medicalcrate_open.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/meta.json b/Resources/Textures/Buildings/crate.rsi/meta.json
index e8fa1c03c2..4afb51c966 100644
--- a/Resources/Textures/Buildings/crate.rsi/meta.json
+++ b/Resources/Textures/Buildings/crate.rsi/meta.json
@@ -7,6 +7,31 @@
"y": 32
},
"states": [
+ {
+ "name": "lock_locked",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "lock_off",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "lock_unlocked",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "sparking",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [[0.1,0.1,0.1,0.1,0.1,0.1]]
+ },
{
"name": "crate",
"select": [],
@@ -24,6 +49,204 @@
"select": [],
"flags": {},
"directions": 1
+ },
+ {
+ "name": "freezer",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "freezer_door",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "freezer_open",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "hydrocrate",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "hydrocrate_door",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "hydrocrate_open",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "hydrosecurecrate",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "hydrosecurecrate_door",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "hydrosecurecrate_open",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "medicalcrate",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "medicalcrate_door",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "medicalcrate_open",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "o2crate",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "o2crate_door",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "o2crate_open",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "plasmacrate",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "plasmacrate_door",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "plasmacrate_open",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "plasticcrate",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "plasticcrate_door",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "plasticcrate_open",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "radiationcrate",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "radiationcrate_door",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "radiationcrate_open",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "secgearcrate",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "secgearcrate_door",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "secgearcrate_open",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "securecrate",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "securecrate_door",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "securecrate_open",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "weaponcrate",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "weaponcrate_door",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "weaponcrate_open",
+ "select": [],
+ "flags": {},
+ "directions": 1
}
]
-}
\ No newline at end of file
+}
diff --git a/Resources/Textures/Buildings/crate.rsi/o2crate.png b/Resources/Textures/Buildings/crate.rsi/o2crate.png
new file mode 100644
index 0000000000..29b9eb3733
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/o2crate.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/o2crate_door.png b/Resources/Textures/Buildings/crate.rsi/o2crate_door.png
new file mode 100644
index 0000000000..4de2c8a77f
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/o2crate_door.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/o2crate_open.png b/Resources/Textures/Buildings/crate.rsi/o2crate_open.png
new file mode 100644
index 0000000000..0cd6312d06
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/o2crate_open.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/plasmacrate.png b/Resources/Textures/Buildings/crate.rsi/plasmacrate.png
new file mode 100644
index 0000000000..86bc320023
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/plasmacrate.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/plasmacrate_door.png b/Resources/Textures/Buildings/crate.rsi/plasmacrate_door.png
new file mode 100644
index 0000000000..0f0727d4b3
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/plasmacrate_door.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/plasmacrate_open.png b/Resources/Textures/Buildings/crate.rsi/plasmacrate_open.png
new file mode 100644
index 0000000000..1a194dad10
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/plasmacrate_open.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/plasticcrate.png b/Resources/Textures/Buildings/crate.rsi/plasticcrate.png
new file mode 100644
index 0000000000..90c0d5715e
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/plasticcrate.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/plasticcrate_door.png b/Resources/Textures/Buildings/crate.rsi/plasticcrate_door.png
new file mode 100644
index 0000000000..a03690e115
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/plasticcrate_door.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/plasticcrate_open.png b/Resources/Textures/Buildings/crate.rsi/plasticcrate_open.png
new file mode 100644
index 0000000000..0ab9fd3996
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/plasticcrate_open.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/radiationcrate.png b/Resources/Textures/Buildings/crate.rsi/radiationcrate.png
new file mode 100644
index 0000000000..1ed466469c
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/radiationcrate.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/radiationcrate_door.png b/Resources/Textures/Buildings/crate.rsi/radiationcrate_door.png
new file mode 100644
index 0000000000..1551bc09fc
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/radiationcrate_door.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/radiationcrate_open.png b/Resources/Textures/Buildings/crate.rsi/radiationcrate_open.png
new file mode 100644
index 0000000000..0ab9fd3996
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/radiationcrate_open.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/secgearcrate.png b/Resources/Textures/Buildings/crate.rsi/secgearcrate.png
new file mode 100644
index 0000000000..66b98656e5
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/secgearcrate.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/secgearcrate_door.png b/Resources/Textures/Buildings/crate.rsi/secgearcrate_door.png
new file mode 100644
index 0000000000..1949650bbc
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/secgearcrate_door.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/secgearcrate_open.png b/Resources/Textures/Buildings/crate.rsi/secgearcrate_open.png
new file mode 100644
index 0000000000..b284819fc3
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/secgearcrate_open.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/securecrate.png b/Resources/Textures/Buildings/crate.rsi/securecrate.png
new file mode 100644
index 0000000000..d30acc782c
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/securecrate.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/securecrate_door.png b/Resources/Textures/Buildings/crate.rsi/securecrate_door.png
new file mode 100644
index 0000000000..90b4c7ebe6
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/securecrate_door.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/securecrate_open.png b/Resources/Textures/Buildings/crate.rsi/securecrate_open.png
new file mode 100644
index 0000000000..05c811e36f
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/securecrate_open.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/sparking.png b/Resources/Textures/Buildings/crate.rsi/sparking.png
new file mode 100644
index 0000000000..87b78b9b46
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/sparking.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/weaponcrate.png b/Resources/Textures/Buildings/crate.rsi/weaponcrate.png
new file mode 100644
index 0000000000..94e4da9d28
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/weaponcrate.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/weaponcrate_door.png b/Resources/Textures/Buildings/crate.rsi/weaponcrate_door.png
new file mode 100644
index 0000000000..2141125b11
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/weaponcrate_door.png differ
diff --git a/Resources/Textures/Buildings/crate.rsi/weaponcrate_open.png b/Resources/Textures/Buildings/crate.rsi/weaponcrate_open.png
new file mode 100644
index 0000000000..fc2255b59a
Binary files /dev/null and b/Resources/Textures/Buildings/crate.rsi/weaponcrate_open.png differ
diff --git a/Resources/Textures/Buildings/low_wall.rsi/meta.json b/Resources/Textures/Buildings/low_wall.rsi/meta.json
new file mode 100644
index 0000000000..13c05547ff
--- /dev/null
+++ b/Resources/Textures/Buildings/low_wall.rsi/meta.json
@@ -0,0 +1 @@
+{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "Taken from https://github.com/discordia-space/CEV-Eris/blob/b503939d31b23c025ddb936b75e0a265d85154c5/icons/obj/structures/low_wall.dmi", "states": [{"name": "metal", "directions": 1, "delays": [[1.0]]}, {"name": "metal_0", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_1", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_2", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_3", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_4", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_5", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_6", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_7", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_over_0", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_over_1", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_over_2", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_over_3", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_over_4", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_over_5", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_over_6", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "metal_over_7", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}]}
\ No newline at end of file
diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal.png b/Resources/Textures/Buildings/low_wall.rsi/metal.png
new file mode 100644
index 0000000000..21a1e3e059
Binary files /dev/null and b/Resources/Textures/Buildings/low_wall.rsi/metal.png differ
diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal_0.png b/Resources/Textures/Buildings/low_wall.rsi/metal_0.png
new file mode 100644
index 0000000000..e1498c7536
Binary files /dev/null and b/Resources/Textures/Buildings/low_wall.rsi/metal_0.png differ
diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal_1.png b/Resources/Textures/Buildings/low_wall.rsi/metal_1.png
new file mode 100644
index 0000000000..8ed2f0b192
Binary files /dev/null and b/Resources/Textures/Buildings/low_wall.rsi/metal_1.png differ
diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal_2.png b/Resources/Textures/Buildings/low_wall.rsi/metal_2.png
new file mode 100644
index 0000000000..e1498c7536
Binary files /dev/null and b/Resources/Textures/Buildings/low_wall.rsi/metal_2.png differ
diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal_3.png b/Resources/Textures/Buildings/low_wall.rsi/metal_3.png
new file mode 100644
index 0000000000..8ed2f0b192
Binary files /dev/null and b/Resources/Textures/Buildings/low_wall.rsi/metal_3.png differ
diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal_4.png b/Resources/Textures/Buildings/low_wall.rsi/metal_4.png
new file mode 100644
index 0000000000..bb544bf0cb
Binary files /dev/null and b/Resources/Textures/Buildings/low_wall.rsi/metal_4.png differ
diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal_5.png b/Resources/Textures/Buildings/low_wall.rsi/metal_5.png
new file mode 100644
index 0000000000..c59b2bab9d
Binary files /dev/null and b/Resources/Textures/Buildings/low_wall.rsi/metal_5.png differ
diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal_6.png b/Resources/Textures/Buildings/low_wall.rsi/metal_6.png
new file mode 100644
index 0000000000..bb544bf0cb
Binary files /dev/null and b/Resources/Textures/Buildings/low_wall.rsi/metal_6.png differ
diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal_7.png b/Resources/Textures/Buildings/low_wall.rsi/metal_7.png
new file mode 100644
index 0000000000..4acb40b3b2
Binary files /dev/null and b/Resources/Textures/Buildings/low_wall.rsi/metal_7.png differ
diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal_over_0.png b/Resources/Textures/Buildings/low_wall.rsi/metal_over_0.png
new file mode 100644
index 0000000000..0858c19f05
Binary files /dev/null and b/Resources/Textures/Buildings/low_wall.rsi/metal_over_0.png differ
diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal_over_1.png b/Resources/Textures/Buildings/low_wall.rsi/metal_over_1.png
new file mode 100644
index 0000000000..6390841edd
Binary files /dev/null and b/Resources/Textures/Buildings/low_wall.rsi/metal_over_1.png differ
diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal_over_2.png b/Resources/Textures/Buildings/low_wall.rsi/metal_over_2.png
new file mode 100644
index 0000000000..0858c19f05
Binary files /dev/null and b/Resources/Textures/Buildings/low_wall.rsi/metal_over_2.png differ
diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal_over_3.png b/Resources/Textures/Buildings/low_wall.rsi/metal_over_3.png
new file mode 100644
index 0000000000..b487006f41
Binary files /dev/null and b/Resources/Textures/Buildings/low_wall.rsi/metal_over_3.png differ
diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal_over_4.png b/Resources/Textures/Buildings/low_wall.rsi/metal_over_4.png
new file mode 100644
index 0000000000..fdf7f77302
Binary files /dev/null and b/Resources/Textures/Buildings/low_wall.rsi/metal_over_4.png differ
diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal_over_5.png b/Resources/Textures/Buildings/low_wall.rsi/metal_over_5.png
new file mode 100644
index 0000000000..8527bd051a
Binary files /dev/null and b/Resources/Textures/Buildings/low_wall.rsi/metal_over_5.png differ
diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal_over_6.png b/Resources/Textures/Buildings/low_wall.rsi/metal_over_6.png
new file mode 100644
index 0000000000..ff8e3ed9ff
Binary files /dev/null and b/Resources/Textures/Buildings/low_wall.rsi/metal_over_6.png differ
diff --git a/Resources/Textures/Buildings/low_wall.rsi/metal_over_7.png b/Resources/Textures/Buildings/low_wall.rsi/metal_over_7.png
new file mode 100644
index 0000000000..3ca5afe7ba
Binary files /dev/null and b/Resources/Textures/Buildings/low_wall.rsi/metal_over_7.png differ
diff --git a/Resources/Textures/Buildings/rwindow.rsi/meta.json b/Resources/Textures/Buildings/rwindow.rsi/meta.json
new file mode 100644
index 0000000000..e45955bc22
--- /dev/null
+++ b/Resources/Textures/Buildings/rwindow.rsi/meta.json
@@ -0,0 +1 @@
+{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "Taken from https://github.com/discordia-space/CEV-Eris/blob/c0293684320e7b70cbcac932b8dddeee35f3a51f/icons/obj/structures/windows.dmi", "states": [{"name": "rwindow0", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "rwindow1", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "rwindow2", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "rwindow3", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "rwindow4", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "rwindow5", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "rwindow6", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "rwindow7", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}]}
\ No newline at end of file
diff --git a/Resources/Textures/Buildings/rwindow.rsi/rwindow0.png b/Resources/Textures/Buildings/rwindow.rsi/rwindow0.png
new file mode 100644
index 0000000000..e0c71ee394
Binary files /dev/null and b/Resources/Textures/Buildings/rwindow.rsi/rwindow0.png differ
diff --git a/Resources/Textures/Buildings/rwindow.rsi/rwindow1.png b/Resources/Textures/Buildings/rwindow.rsi/rwindow1.png
new file mode 100644
index 0000000000..8789d79385
Binary files /dev/null and b/Resources/Textures/Buildings/rwindow.rsi/rwindow1.png differ
diff --git a/Resources/Textures/Buildings/rwindow.rsi/rwindow2.png b/Resources/Textures/Buildings/rwindow.rsi/rwindow2.png
new file mode 100644
index 0000000000..e0c71ee394
Binary files /dev/null and b/Resources/Textures/Buildings/rwindow.rsi/rwindow2.png differ
diff --git a/Resources/Textures/Buildings/rwindow.rsi/rwindow3.png b/Resources/Textures/Buildings/rwindow.rsi/rwindow3.png
new file mode 100644
index 0000000000..8789d79385
Binary files /dev/null and b/Resources/Textures/Buildings/rwindow.rsi/rwindow3.png differ
diff --git a/Resources/Textures/Buildings/rwindow.rsi/rwindow4.png b/Resources/Textures/Buildings/rwindow.rsi/rwindow4.png
new file mode 100644
index 0000000000..5545fa5d9e
Binary files /dev/null and b/Resources/Textures/Buildings/rwindow.rsi/rwindow4.png differ
diff --git a/Resources/Textures/Buildings/rwindow.rsi/rwindow5.png b/Resources/Textures/Buildings/rwindow.rsi/rwindow5.png
new file mode 100644
index 0000000000..155e2d2a94
Binary files /dev/null and b/Resources/Textures/Buildings/rwindow.rsi/rwindow5.png differ
diff --git a/Resources/Textures/Buildings/rwindow.rsi/rwindow6.png b/Resources/Textures/Buildings/rwindow.rsi/rwindow6.png
new file mode 100644
index 0000000000..5545fa5d9e
Binary files /dev/null and b/Resources/Textures/Buildings/rwindow.rsi/rwindow6.png differ
diff --git a/Resources/Textures/Buildings/rwindow.rsi/rwindow7.png b/Resources/Textures/Buildings/rwindow.rsi/rwindow7.png
new file mode 100644
index 0000000000..ce4a98b3b5
Binary files /dev/null and b/Resources/Textures/Buildings/rwindow.rsi/rwindow7.png differ
diff --git a/Resources/Textures/Buildings/wall.rsi/full.png b/Resources/Textures/Buildings/wall.rsi/full.png
index 21a102bb3a..ff0bdc22d7 100644
Binary files a/Resources/Textures/Buildings/wall.rsi/full.png and b/Resources/Textures/Buildings/wall.rsi/full.png differ
diff --git a/Resources/Textures/Buildings/wall.rsi/solid0.png b/Resources/Textures/Buildings/wall.rsi/solid0.png
index 3a809c3b5f..48d8a534c7 100644
Binary files a/Resources/Textures/Buildings/wall.rsi/solid0.png and b/Resources/Textures/Buildings/wall.rsi/solid0.png differ
diff --git a/Resources/Textures/Buildings/wall.rsi/solid1.png b/Resources/Textures/Buildings/wall.rsi/solid1.png
index b7dcaf9459..a04f2ea6b4 100644
Binary files a/Resources/Textures/Buildings/wall.rsi/solid1.png and b/Resources/Textures/Buildings/wall.rsi/solid1.png differ
diff --git a/Resources/Textures/Buildings/wall.rsi/solid2.png b/Resources/Textures/Buildings/wall.rsi/solid2.png
index 3a809c3b5f..48d8a534c7 100644
Binary files a/Resources/Textures/Buildings/wall.rsi/solid2.png and b/Resources/Textures/Buildings/wall.rsi/solid2.png differ
diff --git a/Resources/Textures/Buildings/wall.rsi/solid3.png b/Resources/Textures/Buildings/wall.rsi/solid3.png
index b7dcaf9459..a04f2ea6b4 100644
Binary files a/Resources/Textures/Buildings/wall.rsi/solid3.png and b/Resources/Textures/Buildings/wall.rsi/solid3.png differ
diff --git a/Resources/Textures/Buildings/wall.rsi/solid4.png b/Resources/Textures/Buildings/wall.rsi/solid4.png
index 940e571456..6fc90a4154 100644
Binary files a/Resources/Textures/Buildings/wall.rsi/solid4.png and b/Resources/Textures/Buildings/wall.rsi/solid4.png differ
diff --git a/Resources/Textures/Buildings/wall.rsi/solid5.png b/Resources/Textures/Buildings/wall.rsi/solid5.png
index 5c69be5b41..bb0d903bab 100644
Binary files a/Resources/Textures/Buildings/wall.rsi/solid5.png and b/Resources/Textures/Buildings/wall.rsi/solid5.png differ
diff --git a/Resources/Textures/Buildings/wall.rsi/solid6.png b/Resources/Textures/Buildings/wall.rsi/solid6.png
index 940e571456..6fc90a4154 100644
Binary files a/Resources/Textures/Buildings/wall.rsi/solid6.png and b/Resources/Textures/Buildings/wall.rsi/solid6.png differ
diff --git a/Resources/Textures/Buildings/wall.rsi/solid7.png b/Resources/Textures/Buildings/wall.rsi/solid7.png
index 5ee21983bc..5ad40cae4c 100644
Binary files a/Resources/Textures/Buildings/wall.rsi/solid7.png and b/Resources/Textures/Buildings/wall.rsi/solid7.png differ
diff --git a/Resources/Textures/Buildings/watertank.png b/Resources/Textures/Buildings/watertank.png
new file mode 100644
index 0000000000..56ee09de24
Binary files /dev/null and b/Resources/Textures/Buildings/watertank.png differ
diff --git a/Resources/Textures/Buildings/window.rsi/meta.json b/Resources/Textures/Buildings/window.rsi/meta.json
new file mode 100644
index 0000000000..bb6a983f12
--- /dev/null
+++ b/Resources/Textures/Buildings/window.rsi/meta.json
@@ -0,0 +1 @@
+{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "Taken from https://github.com/discordia-space/CEV-Eris/blob/c0293684320e7b70cbcac932b8dddeee35f3a51f/icons/obj/structures/windows.dmi", "states": [{"name": "window0", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "window1", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "window2", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "window3", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "window4", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "window5", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "window6", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "window7", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}]}
\ No newline at end of file
diff --git a/Resources/Textures/Buildings/window.rsi/window0.png b/Resources/Textures/Buildings/window.rsi/window0.png
new file mode 100644
index 0000000000..bc0a3c2731
Binary files /dev/null and b/Resources/Textures/Buildings/window.rsi/window0.png differ
diff --git a/Resources/Textures/Buildings/window.rsi/window1.png b/Resources/Textures/Buildings/window.rsi/window1.png
new file mode 100644
index 0000000000..274b4bbb5e
Binary files /dev/null and b/Resources/Textures/Buildings/window.rsi/window1.png differ
diff --git a/Resources/Textures/Buildings/window.rsi/window2.png b/Resources/Textures/Buildings/window.rsi/window2.png
new file mode 100644
index 0000000000..bc0a3c2731
Binary files /dev/null and b/Resources/Textures/Buildings/window.rsi/window2.png differ
diff --git a/Resources/Textures/Buildings/window.rsi/window3.png b/Resources/Textures/Buildings/window.rsi/window3.png
new file mode 100644
index 0000000000..274b4bbb5e
Binary files /dev/null and b/Resources/Textures/Buildings/window.rsi/window3.png differ
diff --git a/Resources/Textures/Buildings/window.rsi/window4.png b/Resources/Textures/Buildings/window.rsi/window4.png
new file mode 100644
index 0000000000..f7bdfb316f
Binary files /dev/null and b/Resources/Textures/Buildings/window.rsi/window4.png differ
diff --git a/Resources/Textures/Buildings/window.rsi/window5.png b/Resources/Textures/Buildings/window.rsi/window5.png
new file mode 100644
index 0000000000..cb440e5fc2
Binary files /dev/null and b/Resources/Textures/Buildings/window.rsi/window5.png differ
diff --git a/Resources/Textures/Buildings/window.rsi/window6.png b/Resources/Textures/Buildings/window.rsi/window6.png
new file mode 100644
index 0000000000..f7bdfb316f
Binary files /dev/null and b/Resources/Textures/Buildings/window.rsi/window6.png differ
diff --git a/Resources/Textures/Buildings/window.rsi/window7.png b/Resources/Textures/Buildings/window.rsi/window7.png
new file mode 100644
index 0000000000..58a2d6a215
Binary files /dev/null and b/Resources/Textures/Buildings/window.rsi/window7.png differ
diff --git a/Resources/Textures/Objects/bucket.png b/Resources/Textures/Objects/bucket.png
new file mode 100644
index 0000000000..e4510dbe16
Binary files /dev/null and b/Resources/Textures/Objects/bucket.png differ
diff --git a/Resources/Textures/Objects/bucket_water.png b/Resources/Textures/Objects/bucket_water.png
new file mode 100644
index 0000000000..5f97bfaa5e
Binary files /dev/null and b/Resources/Textures/Objects/bucket_water.png differ
diff --git a/Resources/Textures/Objects/lantern.rsi/HandheldLightOnOverlay.png b/Resources/Textures/Objects/lantern.rsi/HandheldLightOnOverlay.png
index b08e42294f..dc69a9359b 100644
Binary files a/Resources/Textures/Objects/lantern.rsi/HandheldLightOnOverlay.png and b/Resources/Textures/Objects/lantern.rsi/HandheldLightOnOverlay.png differ
diff --git a/Resources/Textures/Objects/mopbucket.png b/Resources/Textures/Objects/mopbucket.png
new file mode 100644
index 0000000000..91e5829d07
Binary files /dev/null and b/Resources/Textures/Objects/mopbucket.png differ
diff --git a/Resources/Textures/Objects/mopbucket_water.png b/Resources/Textures/Objects/mopbucket_water.png
new file mode 100644
index 0000000000..9fae1353e1
Binary files /dev/null and b/Resources/Textures/Objects/mopbucket_water.png differ
diff --git a/RobustToolbox b/RobustToolbox
index 83c738e423..85a4375905 160000
--- a/RobustToolbox
+++ b/RobustToolbox
@@ -1 +1 @@
-Subproject commit 83c738e4231aa4e1bb941d98fed2f761859eaa38
+Subproject commit 85a4375905e37a218f77a54525563c4410e53305
diff --git a/SS14.Launcher/Helpers.cs b/SS14.Launcher/Helpers.cs
new file mode 100644
index 0000000000..e9b74dd5dd
--- /dev/null
+++ b/SS14.Launcher/Helpers.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Buffers;
+using System.IO;
+using System.IO.Compression;
+using System.Net.Http;
+using System.Threading.Tasks;
+
+namespace SS14.Launcher
+{
+ internal static class Helpers
+ {
+ public static void ExtractZipToDirectory(string directory, Stream zipStream)
+ {
+ using (var zipArchive = new ZipArchive(zipStream))
+ {
+ zipArchive.ExtractToDirectory(directory);
+ }
+ }
+
+ public static void ClearDirectory(string directory)
+ {
+ var dirInfo = new DirectoryInfo(directory);
+ foreach (var fileInfo in dirInfo.EnumerateFiles())
+ {
+ fileInfo.Delete();
+ }
+
+ foreach (var childDirInfo in dirInfo.EnumerateDirectories())
+ {
+ childDirInfo.Delete(true);
+ }
+ }
+
+ public static async Task DownloadToFile(this HttpClient client, Uri uri, string filePath,
+ Action progress = null)
+ {
+ await Task.Run(async () =>
+ {
+ using (var response = await client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead))
+ {
+ response.EnsureSuccessStatusCode();
+
+ using (var contentStream = await response.Content.ReadAsStreamAsync())
+ using (var fileStream = File.OpenWrite(filePath))
+ {
+ var totalLength = response.Content.Headers.ContentLength;
+ if (totalLength.HasValue)
+ {
+ progress?.Invoke(0);
+ }
+
+ var totalRead = 0L;
+ var reads = 0L;
+ const int bufferLength = 8192;
+ var buffer = ArrayPool.Shared.Rent(bufferLength);
+ var isMoreToRead = true;
+
+ do
+ {
+ var read = await contentStream.ReadAsync(buffer, 0, bufferLength);
+ if (read == 0)
+ {
+ isMoreToRead = false;
+ }
+ else
+ {
+ await fileStream.WriteAsync(buffer, 0, read);
+
+ reads += 1;
+ totalRead += read;
+ if (totalLength.HasValue && reads % 20 == 0)
+ {
+ progress?.Invoke(totalRead / (float) totalLength.Value);
+ }
+ }
+ } while (isMoreToRead);
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/SS14.Launcher/JenkinsData.cs b/SS14.Launcher/JenkinsData.cs
new file mode 100644
index 0000000000..3b133ab9a7
--- /dev/null
+++ b/SS14.Launcher/JenkinsData.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace SS14.Launcher
+{
+#pragma warning disable 649
+ [Serializable]
+ internal class JenkinsJobInfo
+ {
+ public JenkinsBuildRef LastSuccessfulBuild;
+ }
+
+ [Serializable]
+ internal class JenkinsBuildRef
+ {
+ public int Number;
+ public string Url;
+ }
+#pragma warning restore 649
+}
diff --git a/SS14.Launcher/Program.cs b/SS14.Launcher/Program.cs
new file mode 100644
index 0000000000..deb6056020
--- /dev/null
+++ b/SS14.Launcher/Program.cs
@@ -0,0 +1,398 @@
+using System;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Net.Http;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+using Content.Client.UserInterface;
+using Content.Client.Utility;
+using JetBrains.Annotations;
+using Newtonsoft.Json;
+using Robust.Client.Graphics.Drawing;
+using Robust.Client.Interfaces;
+using Robust.Client.Interfaces.ResourceManagement;
+using Robust.Client.Interfaces.UserInterface;
+using Robust.Client.UserInterface;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.Utility;
+using Robust.Lite;
+using Robust.Shared.Asynchronous;
+using Robust.Shared.IoC;
+using Robust.Shared.Localization;
+using Robust.Shared.Log;
+using Robust.Shared.Maths;
+using Robust.Shared.Utility;
+using static Robust.Client.UserInterface.Control;
+
+namespace SS14.Launcher
+{
+ internal class Program
+ {
+ private const string JenkinsBaseUrl = "https://builds.spacestation14.io/jenkins";
+ private const string JenkinsJobName = "SS14 Content";
+ private const string CurrentLauncherVersion = "1";
+
+ private readonly HttpClient _httpClient;
+ private string _dataDir;
+
+ private LauncherInterface _interface;
+ private string ClientBin => Path.Combine(_dataDir, "client_bin");
+
+#pragma warning disable 649
+ [Dependency] private readonly ILocalizationManager _loc;
+ [Dependency] private readonly ITaskManager _taskManager;
+ [Dependency] private readonly IUriOpener _uriOpener;
+ [Dependency] private readonly IUserInterfaceManager _userInterfaceManager;
+ [Dependency] private readonly IGameController _gameController;
+#pragma warning restore 649
+
+ public static void Main(string[] args)
+ {
+ LiteLoader.Run(() => new Program().Run(), new InitialWindowParameters
+ {
+ Size = (500, 250),
+ WindowTitle = "SS14 Launcher"
+ });
+ }
+
+ private Program()
+ {
+ IoCManager.InjectDependencies(this);
+
+ _httpClient = new HttpClient();
+ _httpClient.DefaultRequestHeaders.Add("User-Agent", $"SS14.Launcher v{CurrentLauncherVersion}");
+ }
+
+ private async void Run()
+ {
+ _dataDir = Path.Combine(UserDataDir.GetUserDataDir(), "launcher");
+
+ _userInterfaceManager.Stylesheet = new NanoStyle().Stylesheet;
+
+ _interface = new LauncherInterface
+ {
+ ProgressBarVisible = false
+ };
+
+ _interface.StatusLabel.Text = _loc.GetString("Checking for launcher update..");
+ _userInterfaceManager.StateRoot.AddChild(_interface.RootControl);
+
+ try
+ {
+ var needsUpdate = await NeedLauncherUpdate();
+ if (needsUpdate)
+ {
+ _interface.StatusLabel.Text = _loc.GetString("This launcher is out of date.");
+ _interface.LaunchButton.Text = _loc.GetString("Download update.");
+ _interface.LaunchButton.OnPressed +=
+ _ => _uriOpener.OpenUri("https://spacestation14.io/about/nightlies/");
+ _interface.LaunchButton.Disabled = false;
+ return;
+ }
+
+ await RunUpdate();
+
+ _interface.StatusLabel.Text = _loc.GetString("Ready!");
+ _interface.LaunchButton.Disabled = false;
+ _interface.LaunchButton.OnPressed += _ =>
+ {
+ LaunchClient();
+ _gameController.Shutdown();
+ };
+ }
+ catch (Exception e)
+ {
+ Logger.ErrorS("launcher", "Exception while trying to run updates:\n{0}", e);
+ _interface.ProgressBarVisible = false;
+ _interface.StatusLabel.Text =
+ _loc.GetString("An error occured.\nMake sure you can access builds.spacestation14.io");
+ }
+ }
+
+ private async Task NeedLauncherUpdate()
+ {
+ var launcherVersionUri =
+ new Uri($"{JenkinsBaseUrl}/userContent/current_launcher_version.txt");
+ var versionRequest = await _httpClient.GetAsync(launcherVersionUri);
+ versionRequest.EnsureSuccessStatusCode();
+ return CurrentLauncherVersion != (await versionRequest.Content.ReadAsStringAsync()).Trim();
+ }
+
+ private async Task RunUpdate()
+ {
+ _interface.StatusLabel.Text = _loc.GetString("Checking for client update..");
+
+ Logger.InfoS("launcher", "Checking for update...");
+
+ var jobUri = new Uri($"{JenkinsBaseUrl}/job/{Uri.EscapeUriString(JenkinsJobName)}/api/json");
+ var jobDataResponse = await _httpClient.GetAsync(jobUri);
+ if (!jobDataResponse.IsSuccessStatusCode)
+ {
+ throw new Exception($"Got bad status code {jobDataResponse.StatusCode} from Jenkins.");
+ }
+
+ var jobInfo = JsonConvert.DeserializeObject(
+ await jobDataResponse.Content.ReadAsStringAsync());
+ var latestBuildNumber = jobInfo.LastSuccessfulBuild.Number;
+
+ var versionFile = Path.Combine(_dataDir, "current_build");
+ bool needUpdate;
+ if (File.Exists(versionFile))
+ {
+ var buildNumber = int.Parse(File.ReadAllText(versionFile, EncodingHelpers.UTF8),
+ CultureInfo.InvariantCulture);
+ needUpdate = buildNumber != latestBuildNumber;
+ if (needUpdate)
+ {
+ Logger.InfoS("launcher", "Current version ({0}) is out of date, updating to {1}.", buildNumber,
+ latestBuildNumber);
+ }
+ }
+ else
+ {
+ Logger.InfoS("launcher", "As it turns out, we don't have any version yet. Time to update.");
+ // Version file doesn't exist, assume first run or whatever.
+ needUpdate = true;
+ }
+
+ if (!needUpdate)
+ {
+ Logger.InfoS("launcher", "No update needed!");
+ return;
+ }
+
+ _interface.StatusLabel.Text = _loc.GetString("Downloading client update..");
+ _interface.ProgressBarVisible = true;
+ var binPath = Path.Combine(_dataDir, "client_bin");
+
+ await Task.Run(() =>
+ {
+ if (!Directory.Exists(binPath))
+ {
+ Directory.CreateDirectory(binPath);
+ }
+ else
+ {
+ Helpers.ClearDirectory(binPath);
+ }
+ });
+
+ // We download the artifact to a temporary file on disk.
+ // This is to avoid having to load the entire thing into memory.
+ // (.NET's zip code loads it into a memory stream if the stream you give it doesn't support seeking.)
+ // (this makes a lot of sense due to how the zip file format works.)
+ var tmpFile = await _downloadArtifactToTempFile(latestBuildNumber, GetBuildFilename());
+ _interface.StatusLabel.Text = _loc.GetString("Extracting update..");
+ _interface.ProgressBarVisible = false;
+
+ await Task.Run(() =>
+ {
+ using (var file = File.OpenRead(tmpFile))
+ {
+ Helpers.ExtractZipToDirectory(binPath, file);
+ }
+
+ File.Delete(tmpFile);
+ });
+
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ {
+ // .NET's zip extraction system doesn't seem to preserve +x.
+ // Technically can't blame it because there's no "official" way to store that,
+ // since zip files are DOS-centric.
+
+ // Manually chmod +x the App bundle then.
+ var process = Process.Start(new ProcessStartInfo
+ {
+ FileName = "chmod",
+ Arguments = $"+x '{Path.Combine("Space Station 14.app", "Contents", "MacOS", "SS14")}'",
+ WorkingDirectory = binPath,
+ });
+ process?.WaitForExit();
+ }
+
+ // Write version to disk.
+ File.WriteAllText(versionFile, latestBuildNumber.ToString(CultureInfo.InvariantCulture),
+ EncodingHelpers.UTF8);
+
+ Logger.InfoS("launcher", "Update done!");
+ }
+
+ private async Task _downloadArtifactToTempFile(int buildNumber, string fileName)
+ {
+ var artifactUri
+ = new Uri(
+ $"{JenkinsBaseUrl}/job/{Uri.EscapeUriString(JenkinsJobName)}/{buildNumber}/artifact/release/{Uri.EscapeUriString(fileName)}");
+
+ var tmpFile = Path.GetTempFileName();
+ Logger.InfoS("launcher", tmpFile);
+ await _httpClient.DownloadToFile(artifactUri, tmpFile, f => _taskManager.RunOnMainThread(() =>
+ {
+ _interface.ProgressBarVisible = true;
+ _interface.ProgressBar.Value = f;
+ }));
+
+ return tmpFile;
+ }
+
+ private void LaunchClient()
+ {
+ var binPath = ClientBin;
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ var process = new Process
+ {
+ StartInfo = new ProcessStartInfo
+ {
+ FileName = "mono",
+ Arguments = "Robust.Client.exe",
+ WorkingDirectory = binPath,
+ UseShellExecute = false,
+ },
+ };
+ process.Start();
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ Process.Start(new ProcessStartInfo
+ {
+ FileName = Path.Combine(binPath, "Robust.Client.exe"),
+ });
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ {
+ // TODO: does this cause macOS to make a security warning?
+ // If it does we'll have to manually launch the contents, which is simple enough.
+ Process.Start(new ProcessStartInfo
+ {
+ FileName = "open",
+ Arguments = "'Space Station 14.app'",
+ WorkingDirectory = binPath,
+ });
+ }
+ else
+ {
+ throw new NotSupportedException("Unsupported platform.");
+ }
+ }
+
+
+ [Pure]
+ private static string GetBuildFilename()
+ {
+ string platform;
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ platform = "Windows";
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ platform = "Linux";
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ {
+ platform = "macOS";
+ }
+ else
+ {
+ throw new NotSupportedException("Unsupported platform.");
+ }
+
+ return $"SS14.Client_{platform}_x64.zip";
+ }
+
+
+ private class LauncherInterface
+ {
+#pragma warning disable 649
+ [Dependency] private readonly IResourceCache _resourceCache;
+ [Dependency] private readonly ILocalizationManager _loc;
+ [Dependency] private readonly IUriOpener _uriOpener;
+ private bool _progressBarVisible;
+#pragma warning restore 649
+
+ public Control RootControl { get; }
+ public Label StatusLabel { get; }
+ public ProgressBar ProgressBar { get; }
+ public Button LaunchButton { get; }
+
+ public bool ProgressBarVisible
+ {
+ get => _progressBarVisible;
+ set
+ {
+ _progressBarVisible = value;
+ ProgressBar.Visible = value;
+ StatusLabel.SizeFlagsHorizontal = value ? SizeFlags.Fill : SizeFlags.FillExpand;
+ }
+ }
+
+ public LauncherInterface()
+ {
+ IoCManager.InjectDependencies(this);
+
+ Button visitWebsiteButton;
+
+ RootControl = new PanelContainer
+ {
+ PanelOverride = new StyleBoxFlat
+ {
+ BackgroundColor = Color.FromHex("#20202a"),
+ ContentMarginLeftOverride = 4,
+ ContentMarginRightOverride = 4,
+ ContentMarginBottomOverride = 4,
+ ContentMarginTopOverride = 4
+ },
+ Children =
+ {
+ new VBoxContainer
+ {
+ Children =
+ {
+ new Label
+ {
+ Text = _loc.GetString("Space Station 14"),
+ FontOverride = _resourceCache.GetFont("/Fonts/Animal Silence.otf", 40),
+ SizeFlagsHorizontal = SizeFlags.ShrinkCenter
+ },
+
+ (visitWebsiteButton = new Button
+ {
+ SizeFlagsHorizontal = SizeFlags.ShrinkCenter,
+ SizeFlagsVertical = SizeFlags.Expand | SizeFlags.ShrinkCenter,
+ Text = _loc.GetString("Visit website")
+ }),
+
+ new HBoxContainer
+ {
+ SizeFlagsVertical = SizeFlags.ShrinkEnd,
+ SeparationOverride = 5,
+ Children =
+ {
+ (StatusLabel = new Label()),
+ (ProgressBar = new ProgressBar
+ {
+ SizeFlagsHorizontal = SizeFlags.FillExpand,
+ MinValue = 0,
+ MaxValue = 1
+ }),
+ (LaunchButton = new Button
+ {
+ Disabled = true,
+ Text = _loc.GetString("Launch!")
+ })
+ }
+ }
+ }
+ }
+ }
+ };
+
+ visitWebsiteButton.OnPressed += _ => _uriOpener.OpenUri("https://spacestation14.io");
+
+ RootControl.SetAnchorPreset(LayoutPreset.Wide);
+ }
+ }
+ }
+}
diff --git a/SS14.Launcher/SS14.Launcher.csproj b/SS14.Launcher/SS14.Launcher.csproj
new file mode 100644
index 0000000000..408c7bcc82
--- /dev/null
+++ b/SS14.Launcher/SS14.Launcher.csproj
@@ -0,0 +1,29 @@
+
+
+
+ net472
+ 7.3
+ false
+ x64;x86
+ false
+ ..\bin\SS14.Launcher\
+ Exe
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ..\RobustToolbox\Tools\
+
+
+
diff --git a/SpaceStation14.sln b/SpaceStation14.sln
index 878f0c3e6d..734804dfef 100644
--- a/SpaceStation14.sln
+++ b/SpaceStation14.sln
@@ -40,6 +40,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Content.IntegrationTests",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Content.Benchmarks", "Content.Benchmarks\Content.Benchmarks.csproj", "{7AC832A1-2461-4EB5-AC26-26F6AFFA9E46}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Robust.Lite", "RobustToolbox\Robust.Lite\Robust.Lite.csproj", "{0131AAE0-EF7D-4985-86FD-59EEC31B9A5C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SS14.Launcher", "SS14.Launcher\SS14.Launcher.csproj", "{47B4D2F3-6767-4ACB-A803-972FEF7215E9}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -151,6 +155,22 @@ Global
{7AC832A1-2461-4EB5-AC26-26F6AFFA9E46}.Release|x64.Build.0 = Release|x64
{7AC832A1-2461-4EB5-AC26-26F6AFFA9E46}.Release|x86.ActiveCfg = Release|x86
{7AC832A1-2461-4EB5-AC26-26F6AFFA9E46}.Release|x86.Build.0 = Release|x86
+ {0131AAE0-EF7D-4985-86FD-59EEC31B9A5C}.Debug|x64.ActiveCfg = Debug|x64
+ {0131AAE0-EF7D-4985-86FD-59EEC31B9A5C}.Debug|x64.Build.0 = Debug|x64
+ {0131AAE0-EF7D-4985-86FD-59EEC31B9A5C}.Debug|x86.ActiveCfg = Debug|x86
+ {0131AAE0-EF7D-4985-86FD-59EEC31B9A5C}.Debug|x86.Build.0 = Debug|x86
+ {0131AAE0-EF7D-4985-86FD-59EEC31B9A5C}.Release|x64.ActiveCfg = Release|x64
+ {0131AAE0-EF7D-4985-86FD-59EEC31B9A5C}.Release|x64.Build.0 = Release|x64
+ {0131AAE0-EF7D-4985-86FD-59EEC31B9A5C}.Release|x86.ActiveCfg = Release|x86
+ {0131AAE0-EF7D-4985-86FD-59EEC31B9A5C}.Release|x86.Build.0 = Release|x86
+ {47B4D2F3-6767-4ACB-A803-972FEF7215E9}.Debug|x64.ActiveCfg = Debug|x64
+ {47B4D2F3-6767-4ACB-A803-972FEF7215E9}.Debug|x64.Build.0 = Debug|x64
+ {47B4D2F3-6767-4ACB-A803-972FEF7215E9}.Debug|x86.ActiveCfg = Debug|x86
+ {47B4D2F3-6767-4ACB-A803-972FEF7215E9}.Debug|x86.Build.0 = Debug|x86
+ {47B4D2F3-6767-4ACB-A803-972FEF7215E9}.Release|x64.ActiveCfg = Release|x64
+ {47B4D2F3-6767-4ACB-A803-972FEF7215E9}.Release|x64.Build.0 = Release|x64
+ {47B4D2F3-6767-4ACB-A803-972FEF7215E9}.Release|x86.ActiveCfg = Release|x86
+ {47B4D2F3-6767-4ACB-A803-972FEF7215E9}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -163,6 +183,7 @@ Global
{93F23A82-00C5-4572-964E-E7C9457726D4} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE}
{F0ADA779-40B8-4F7E-BA6C-CDB19F3065D9} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE}
{0529F740-0000-0000-0000-000000000000} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE}
+ {0131AAE0-EF7D-4985-86FD-59EEC31B9A5C} = {83B4CBBA-547A-42F0-A7CD-8A67D93196CE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AA37ED9F-F8D6-468E-A101-658AD605B09A}
diff --git a/SpaceStation14.sln.DotSettings b/SpaceStation14.sln.DotSettings
index 555541861c..4e299bbb28 100644
--- a/SpaceStation14.sln.DotSettings
+++ b/SpaceStation14.sln.DotSettings
@@ -13,6 +13,9 @@
<data />
<data><IncludeFilters /><ExcludeFilters><Filter ModuleMask="*.UnitTesting" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /></ExcludeFilters></data>
True
+ <data />
+ <data><IncludeFilters /><ExcludeFilters><Filter ModuleMask="Lidgren.Network" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /></ExcludeFilters></data>
+ True
True
True
- True
\ No newline at end of file
+ True
diff --git a/Tools/package_release_build.py b/Tools/package_release_build.py
index 560d8980c0..d0b3d3e6c3 100755
--- a/Tools/package_release_build.py
+++ b/Tools/package_release_build.py
@@ -44,8 +44,12 @@ SERVER_IGNORED_RESOURCES = {
"Shaders",
}
+LAUNCHER_RESOURCES = {
+ "Nano",
+ "Fonts",
+}
+
def main():
- global GODOT
parser = argparse.ArgumentParser(
description="Packages the SS14 content repo for release on all platforms.")
parser.add_argument("--platform",
@@ -125,6 +129,15 @@ def build_windows():
copy_content_assemblies(p("Resources", "Assemblies"), server_zip, server=True)
server_zip.close()
+ print(Fore.GREEN + "Packaging Windows x64 launcher..." + Style.RESET_ALL)
+ launcher_zip = zipfile.ZipFile(p("release", "SS14.Launcher_Windows_x64.zip"), "w",
+ compression=zipfile.ZIP_DEFLATED)
+
+ copy_dir_into_zip(p("bin", "SS14.Launcher"), "bin", launcher_zip)
+ copy_launcher_resources(p("bin", "Resources"), launcher_zip)
+ launcher_zip.write(p("BuildFiles", "Windows", "run_me.bat"), "run_me.bat")
+ launcher_zip.close()
+
def build_macos():
print(Fore.GREEN + "Building project for macOS x64..." + Style.RESET_ALL)
@@ -161,6 +174,17 @@ def build_macos():
copy_content_assemblies(p("Resources", "Assemblies"), server_zip, server=True)
server_zip.close()
+ print(Fore.GREEN + "Packaging macOS x64 launcher..." + Style.RESET_ALL)
+ launcher_zip = zipfile.ZipFile(p("release", "SS14.Launcher_macOS_x64.zip"), "w",
+ compression=zipfile.ZIP_DEFLATED)
+
+ contents = p("Space Station 14 Launcher.app", "Contents", "Resources")
+ copy_dir_into_zip(p("BuildFiles", "Mac", "Space Station 14 Launcher.app"), "Space Station 14 Launcher.app", launcher_zip)
+ copy_dir_into_zip(p("bin", "SS14.Launcher"), contents, launcher_zip)
+
+ copy_launcher_resources(p(contents, "Resources"), launcher_zip)
+ launcher_zip.close()
+
def build_linux():
# Run a full build.
@@ -197,21 +221,37 @@ def build_linux():
copy_content_assemblies(p("Resources", "Assemblies"), server_zip, server=True)
server_zip.close()
+ print(Fore.GREEN + "Packaging Linux x64 launcher..." + Style.RESET_ALL)
+ launcher_zip = zipfile.ZipFile(p("release", "SS14.Launcher_Linux_x64.zip"), "w",
+ compression=zipfile.ZIP_DEFLATED)
+
+ copy_dir_into_zip(p("bin", "SS14.Launcher"), "bin", launcher_zip)
+ copy_launcher_resources(p("bin", "Resources"), launcher_zip)
+ launcher_zip.write(p("BuildFiles", "Linux", "SS14.Launcher"), "SS14.Launcher")
+ launcher_zip.close()
def copy_resources(target, zipf, server):
# Content repo goes FIRST so that it won't override engine files as that's forbidden.
- do_resource_copy(target, "Resources", zipf, server)
- do_resource_copy(target, p("RobustToolbox", "Resources"), zipf, server)
+ ignore_set = SHARED_IGNORED_RESOURCES
+ if server:
+ ignore_set = ignore_set.union(SERVER_IGNORED_RESOURCES)
+ else:
+ ignore_set = ignore_set.union(CLIENT_IGNORED_RESOURCES)
+
+ do_resource_copy(target, "Resources", zipf, ignore_set)
+ do_resource_copy(target, p("RobustToolbox", "Resources"), zipf, ignore_set)
-def do_resource_copy(target, source, zipf, server):
+def copy_launcher_resources(target, zipf):
+ # Copy all engine resources, since those are stripped down enough now.
+ do_resource_copy(target, p("RobustToolbox", "Resources"), zipf, SHARED_IGNORED_RESOURCES)
+ for folder in LAUNCHER_RESOURCES:
+ copy_dir_into_zip(p("Resources", folder), p(target, folder), zipf)
+
+
+def do_resource_copy(target, source, zipf, ignore_set):
for filename in os.listdir(source):
- if filename in SHARED_IGNORED_RESOURCES \
- or filename in (SERVER_IGNORED_RESOURCES if server else CLIENT_IGNORED_RESOURCES):
- continue
-
- # Get rid of Godot .import files, thanks.
- if filename.endswith(".import"):
+ if filename in ignore_set:
continue
path = p(source, filename)