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)