diff --git a/Content.Client/Construction/ConstructionMenu.cs b/Content.Client/Construction/ConstructionMenu.cs index 81b14fe21d..af374ca281 100644 --- a/Content.Client/Construction/ConstructionMenu.cs +++ b/Content.Client/Construction/ConstructionMenu.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Content.Client.GameObjects.Components.Construction; using Content.Shared.Construction; +using Content.Shared.GameObjects.Components.Interactable; using Robust.Client.Graphics; using Robust.Client.Interfaces.Placement; using Robust.Client.Interfaces.ResourceManagement; @@ -182,25 +183,25 @@ namespace Content.Client.Construction case ConstructionStepTool tool: switch (tool.Tool) { - case ConstructionStepTool.ToolType.Wrench: + case Tool.Wrench: icon = ResourceCache.GetResource("/Textures/Objects/Tools/wrench.png"); text = "Wrench"; break; - case ConstructionStepTool.ToolType.Crowbar: + case Tool.Crowbar: icon = ResourceCache.GetResource("/Textures/Objects/Tools/crowbar.png"); text = "Crowbar"; break; - case ConstructionStepTool.ToolType.Screwdriver: + case Tool.Screwdriver: icon = ResourceCache.GetResource( "/Textures/Objects/Tools/screwdriver.png"); text = "Screwdriver"; break; - case ConstructionStepTool.ToolType.Welder: + case Tool.Welder: icon = ResourceCache.GetResource("/Textures/Objects/tools.rsi") .RSI["welder"].Frame0; text = $"Welding tool ({tool.Amount} fuel)"; break; - case ConstructionStepTool.ToolType.Wirecutters: + case Tool.Wirecutter: icon = ResourceCache.GetResource( "/Textures/Objects/Tools/wirecutter.png"); text = "Wirecutters"; diff --git a/Content.Client/GameObjects/Components/WelderComponent.cs b/Content.Client/GameObjects/Components/Interactable/ToolComponent.cs similarity index 51% rename from Content.Client/GameObjects/Components/WelderComponent.cs rename to Content.Client/GameObjects/Components/Interactable/ToolComponent.cs index e5a64d5ccb..2df19d40ec 100644 --- a/Content.Client/GameObjects/Components/WelderComponent.cs +++ b/Content.Client/GameObjects/Components/Interactable/ToolComponent.cs @@ -1,38 +1,49 @@ using System; -using Content.Client.UserInterface; using Content.Client.UserInterface.Stylesheets; using Content.Client.Utility; -using Content.Shared.GameObjects; -using Content.Shared.GameObjects.Components; +using Content.Shared.GameObjects.Components.Interactable; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Shared.GameObjects; using Robust.Shared.Localization; +using Robust.Shared.Serialization; using Robust.Shared.Timing; using Robust.Shared.ViewVariables; -namespace Content.Client.GameObjects.Components +namespace Content.Client.GameObjects.Components.Interactable { [RegisterComponent] - public class WelderComponent : Component, IItemStatus + public class ToolComponent : SharedToolComponent, IItemStatus { - public override string Name => "Welder"; - public override uint? NetID => ContentNetIDs.WELDER; - + private Tool _behavior; + [ViewVariables(VVAccess.ReadWrite)] private bool _uiUpdateNeeded; + private bool _statusShowBehavior; [ViewVariables] public float FuelCapacity { get; private set; } [ViewVariables] public float Fuel { get; private set; } [ViewVariables] public bool Activated { get; private set; } + [ViewVariables] public bool StatusShowBehavior => _statusShowBehavior; + [ViewVariables] + public override Tool Behavior + { + get => _behavior; + set {} + } - [ViewVariables(VVAccess.ReadWrite)] private bool _uiUpdateNeeded; + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + serializer.DataField(ref _statusShowBehavior, "statusShowBehavior", false); + } public override void HandleComponentState(ComponentState curState, ComponentState nextState) { - if (!(curState is WelderComponentState cast)) + if (!(curState is ToolComponentState cast)) return; FuelCapacity = cast.FuelCapacity; Fuel = cast.Fuel; Activated = cast.Activated; + _behavior = cast.Behavior; _uiUpdateNeeded = true; } @@ -41,10 +52,10 @@ namespace Content.Client.GameObjects.Components private sealed class StatusControl : Control { - private readonly WelderComponent _parent; + private readonly ToolComponent _parent; private readonly RichTextLabel _label; - public StatusControl(WelderComponent parent) + public StatusControl(ToolComponent parent) { _parent = parent; _label = new RichTextLabel {StyleClasses = {StyleNano.StyleClassItemStatus}}; @@ -64,11 +75,22 @@ namespace Content.Client.GameObjects.Components _parent._uiUpdateNeeded = false; - var fuelCap = _parent.FuelCapacity; - var fuel = _parent.Fuel; + if (_parent.Behavior == Tool.Welder) + { + var fuelCap = _parent.FuelCapacity; + var fuel = _parent.Fuel; + + _label.SetMarkup(Loc.GetString("Fuel: [color={0}]{1}/{2}[/color]", + fuel < fuelCap / 4f ? "darkorange" : "orange", Math.Round(fuel), fuelCap)); + } + else + { + if(!_parent.StatusShowBehavior) + _label.SetMarkup(string.Empty); + else + _label.SetMarkup(_parent.Behavior.ToString()); + } - _label.SetMarkup(Loc.GetString("Fuel: [color={0}]{1}/{2}[/color]", - fuel < fuelCap / 4f ? "darkorange" : "orange", Math.Round(fuel), fuelCap)); } } } diff --git a/Content.Server/GameObjects/Components/WrenchableComponent.cs b/Content.Server/GameObjects/Components/AnchorableComponent.cs similarity index 52% rename from Content.Server/GameObjects/Components/WrenchableComponent.cs rename to Content.Server/GameObjects/Components/AnchorableComponent.cs index 056a874900..5afa2fbfd9 100644 --- a/Content.Server/GameObjects/Components/WrenchableComponent.cs +++ b/Content.Server/GameObjects/Components/AnchorableComponent.cs @@ -1,5 +1,6 @@ -using Content.Server.GameObjects.Components.Interactable.Tools; +using Content.Server.GameObjects.Components.Interactable; using Content.Server.GameObjects.EntitySystems; +using Content.Shared.GameObjects.Components.Interactable; using Robust.Server.GameObjects; using Robust.Server.GameObjects.EntitySystems; using Robust.Shared.GameObjects; @@ -9,31 +10,25 @@ using Robust.Shared.IoC; namespace Content.Server.GameObjects.Components { [RegisterComponent] - public class WrenchableComponent : Component, IAttackBy + public class AnchorableComponent : Component, IWrenchAct { - public override string Name => "Wrenchable"; - private AudioSystem _audioSystem; + public override string Name => "Anchorable"; public override void Initialize() { base.Initialize(); - _audioSystem = IoCManager.Resolve().GetEntitySystem(); + Owner.EnsureComponent(); } - public bool AttackBy(AttackByEventArgs eventArgs) + public bool WrenchAct(WrenchActEventArgs eventArgs) { - if (!eventArgs.AttackWith.HasComponent()) - { - return false; - } - if (!Owner.TryGetComponent(out PhysicsComponent physics)) { return false; } physics.Anchored = !physics.Anchored; - _audioSystem.Play("/Audio/items/ratchet.ogg", Owner); + eventArgs.ToolComponent.PlayUseSound(); return true; } diff --git a/Content.Server/GameObjects/Components/Construction/ConstructionComponent.cs b/Content.Server/GameObjects/Components/Construction/ConstructionComponent.cs index be64cfb14f..7281fe695d 100644 --- a/Content.Server/GameObjects/Components/Construction/ConstructionComponent.cs +++ b/Content.Server/GameObjects/Components/Construction/ConstructionComponent.cs @@ -1,11 +1,12 @@ using System; using System.Collections.Generic; -using Content.Server.GameObjects.Components.Interactable.Tools; +using Content.Server.GameObjects.Components.Interactable; using Content.Server.GameObjects.Components.Stack; using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces; using Content.Shared.Construction; using Content.Shared.GameObjects.Components; +using Content.Shared.GameObjects.Components.Interactable; using Robust.Server.GameObjects; using Robust.Server.GameObjects.EntitySystems; using Robust.Server.Interfaces.GameObjects; @@ -141,46 +142,42 @@ namespace Content.Server.GameObjects.Components.Construction sound.Play("/Audio/items/deconstruct.ogg", Transform.GridPosition); return true; case ConstructionStepTool toolStep: + if (!slapped.TryGetComponent(out var tool)) + return false; switch (toolStep.Tool) { - case ToolType.Crowbar: - if (slapped.HasComponent()) + case Tool.Crowbar: + if (tool.Behavior == Tool.Crowbar) { - sound.Play("/Audio/items/crowbar.ogg", Transform.GridPosition); + tool.PlayUseSound(); return true; } return false; - case ToolType.Welder: - if (slapped.TryGetComponent(out WelderComponent welder) && welder.TryUse(toolStep.Amount)) + case Tool.Welder: + if (tool.Behavior == Tool.Welder && tool.TryWeld(toolStep.Amount)) { - if (_random.NextDouble() > 0.5) - sound.Play("/Audio/items/welder.ogg", Transform.GridPosition); - else - sound.Play("/Audio/items/welder2.ogg", Transform.GridPosition); + tool.PlayUseSound(); return true; } return false; - case ToolType.Wrench: - if (slapped.HasComponent()) + case Tool.Wrench: + if (tool.Behavior == Tool.Wrench) { - sound.Play("/Audio/items/ratchet.ogg", Transform.GridPosition); + tool.PlayUseSound(); return true; } return false; - case ToolType.Screwdriver: - if (slapped.HasComponent()) + case Tool.Screwdriver: + if (tool.Behavior == Tool.Screwdriver) { - if (_random.NextDouble() > 0.5) - sound.Play("/Audio/items/screwdriver.ogg", Transform.GridPosition); - else - sound.Play("/Audio/items/screwdriver2.ogg", Transform.GridPosition); + tool.PlayUseSound(); return true; } return false; - case ToolType.Wirecutters: - if (slapped.HasComponent()) + case Tool.Wirecutter: + if (tool.Behavior == Tool.Wirecutter) { - sound.Play("/Audio/items/wirecutter.ogg", Transform.GridPosition); + tool.PlayUseSound(); return true; } return false; diff --git a/Content.Server/GameObjects/Components/Doors/AirlockComponent.cs b/Content.Server/GameObjects/Components/Doors/AirlockComponent.cs index 3e064befc4..91c4678005 100644 --- a/Content.Server/GameObjects/Components/Doors/AirlockComponent.cs +++ b/Content.Server/GameObjects/Components/Doors/AirlockComponent.cs @@ -1,11 +1,12 @@ using System; using System.Threading; -using Content.Server.GameObjects.Components.Interactable.Tools; +using Content.Server.GameObjects.Components.Interactable; using Content.Server.GameObjects.Components.Power; using Content.Server.GameObjects.Components.VendingMachines; using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces; using Content.Shared.GameObjects.Components.Doors; +using Content.Shared.GameObjects.Components.Interactable; using Robust.Server.GameObjects; using Robust.Server.Interfaces.GameObjects; using Robust.Shared.GameObjects; @@ -200,27 +201,28 @@ namespace Content.Server.GameObjects.Components.Doors public bool AttackBy(AttackByEventArgs eventArgs) { - if (eventArgs.AttackWith.HasComponent()) - { - if (IsPowered()) - { - var notify = IoCManager.Resolve(); - notify.PopupMessage(Owner, eventArgs.User, "The powered motors block your efforts!"); - return true; - } + if (!eventArgs.AttackWith.TryGetComponent(out var tool)) + return false; - if (State == DoorState.Closed) - { - Open(); - } - else if(State == DoorState.Open) - { - Close(); - } + if (tool.Behavior != Tool.Crowbar) return false; + + if (IsPowered()) + { + var notify = IoCManager.Resolve(); + notify.PopupMessage(Owner, eventArgs.User, "The powered motors block your efforts!"); return true; } - return false; + if (State == DoorState.Closed) + { + Open(); + } + else if(State == DoorState.Open) + { + Close(); + } + return true; + } } } diff --git a/Content.Server/GameObjects/Components/Interactable/MultitoolComponent.cs b/Content.Server/GameObjects/Components/Interactable/MultitoolComponent.cs new file mode 100644 index 0000000000..124115d262 --- /dev/null +++ b/Content.Server/GameObjects/Components/Interactable/MultitoolComponent.cs @@ -0,0 +1,114 @@ +using System.Collections.Generic; +using Content.Server.GameObjects.EntitySystems; +using Content.Shared.GameObjects.Components.Interactable; +using Robust.Server.GameObjects; +using Robust.Server.GameObjects.EntitySystems; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Serialization; +using Robust.Shared.IoC; +using Robust.Shared.Serialization; + +namespace Content.Server.GameObjects.Components.Interactable +{ + /// + /// Not to be confused with Multitool (power) + /// + [RegisterComponent] + public class MultiToolComponent : Component, IUse + { + public class ToolEntry : IExposeData + { + private string _state; + private string _sound; + private string _soundCollection; + private string _texture; + private string _sprite; + private string _changeSound; + + public Tool Behavior { get; private set; } + public string State => _state; + public string Texture => _texture; + public string Sprite => _sprite; + public string Sound => _sound; + public string SoundCollection => _soundCollection; + public string ChangeSound => _changeSound; + + public void ExposeData(ObjectSerializer serializer) + { + Behavior = (Tool)serializer.ReadStringEnumKey("behavior"); + serializer.DataField(ref _state, "state", string.Empty); + serializer.DataField(ref _sprite, "sprite", string.Empty); + serializer.DataField(ref _texture, "texture", string.Empty); + serializer.DataField(ref _sound, "useSound", string.Empty); + serializer.DataField(ref _soundCollection, "useSoundCollection", string.Empty); + serializer.DataField(ref _changeSound, "changeSound", string.Empty); + } + } + +#pragma warning disable 649 + [Dependency] private IEntitySystemManager _entitySystemManager; +#pragma warning restore 649 + + public override string Name => "MultiTool"; + private List _tools; + private int _currentTool = 0; + + private AudioSystem _audioSystem; + private ToolComponent _tool; + private SpriteComponent _sprite; + + public override void Initialize() + { + base.Initialize(); + Owner.TryGetComponent(out _tool); + Owner.TryGetComponent(out _sprite); + + _audioSystem = _entitySystemManager.GetEntitySystem(); + + SetTool(); + } + + public void Cycle() + { + _currentTool = (_currentTool + 1) % _tools.Count; + SetTool(); + var current = _tools[_currentTool]; + if(!string.IsNullOrEmpty(current.ChangeSound)) + _audioSystem.Play(current.ChangeSound, Owner); + } + + private void SetTool() + { + if (_tool == null) return; + + var current = _tools[_currentTool]; + + _tool.UseSound = current.Sound; + _tool.UseSoundCollection = current.SoundCollection; + _tool.Behavior = current.Behavior; + + if (_sprite == null) return; + + if (string.IsNullOrEmpty(current.Texture)) + if (!string.IsNullOrEmpty(current.Sprite)) + _sprite.LayerSetState(0, current.State, current.Sprite); + else + _sprite.LayerSetState(0, current.State); + else + _sprite.LayerSetTexture(0, current.Texture); + } + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + serializer.DataField(ref _tools, "tools", new List()); + } + + public bool UseEntity(UseEntityEventArgs eventArgs) + { + Cycle(); + return true; + } + } +} diff --git a/Content.Server/GameObjects/Components/Interactable/ToolComponent.cs b/Content.Server/GameObjects/Components/Interactable/ToolComponent.cs index fa1b3357a8..86542343f6 100644 --- a/Content.Server/GameObjects/Components/Interactable/ToolComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/ToolComponent.cs @@ -1,96 +1,37 @@ // Only unused on .NET Core due to KeyValuePair.Deconstruct // ReSharper disable once RedundantUsingDirective +using System; using Content.Server.GameObjects.Components.Chemistry; using Content.Server.GameObjects.EntitySystems; +using Content.Shared.Audio; +using Content.Shared.Chemistry; +using Content.Shared.GameObjects; +using Content.Shared.GameObjects.Components; +using Content.Shared.GameObjects.Components.Interactable; using Content.Shared.Maps; +using Robust.Server.GameObjects; using Robust.Server.GameObjects.EntitySystems; +using Robust.Shared.Audio; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; +using Robust.Shared.Interfaces.Random; using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Log; using Robust.Shared.Map; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; using Robust.Shared.Serialization; using Robust.Shared.Utility; using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Interactable { - public enum Tool : byte + [RegisterComponent] + public class ToolComponent : SharedToolComponent, IExamine, IAfterAttack, IUse, IAttack { - Wrench, - Crowbar, - Screwdriver, - Wirecutters, - Welder, - Multitool, - } - - public abstract class ToolComponent : Component, IExamine, IAfterAttack - { -#pragma warning disable 649 - [Dependency] private IEntitySystemManager _entitySystemManager; - [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager; - [Dependency] private readonly IMapManager _mapManager; -#pragma warning restore 649 - - private AudioSystem _audioSystem; - private InteractionSystem _interactionSystem; - private SolutionComponent - - private Tool _behavior; - private bool _activated = false; - - public override string Name => "Tool"; - - public Tool Behavior - { - get => _behavior; - set => _behavior = value; - } - - public override void Initialize() - { - base.Initialize(); - - _audioSystem = _entitySystemManager.GetEntitySystem(); - _interactionSystem = _entitySystemManager.GetEntitySystem(); - } - - public override void ExposeData(ObjectSerializer serializer) - { - base.ExposeData(serializer); - - serializer.DataField(ref _behavior, "behavior", Tool.Wrench); - serializer.DataField(ref _speedModifier, "Speed", 1); - } - - public void Examine(FormattedMessage message) - { - throw new System.NotImplementedException(); - } - - /// - /// For tool interactions that have a delay before action this will modify the rate, time to wait is divided by this value - /// - [ViewVariables(VVAccess.ReadWrite)] - public float SpeedModifier - { - get => _speedModifier; - set => _speedModifier = value; - } - private float _speedModifier = 1; - - /// - /// Status modifier which determines whether or not we can act as a tool at this time - /// - /// - public virtual bool CanUse() - { - if (_behavior != Tool.Welder) - return true; - } - /// /// Default Cost of using the welder fuel for an action /// @@ -99,22 +40,197 @@ namespace Content.Server.GameObjects.Components.Interactable /// /// Rate at which we expunge fuel from ourselves when activated /// - public const float FuelLossRate = 0.2f; + public const float FuelLossRate = 5f; // 0.2f + +#pragma warning disable 649 + [Dependency] private IEntitySystemManager _entitySystemManager; + [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager; + [Dependency] private readonly IMapManager _mapManager; + [Dependency] private readonly IPrototypeManager _prototypeManager; + [Dependency] private readonly IRobustRandom _robustRandom; +#pragma warning restore 649 + + private AudioSystem _audioSystem; + private InteractionSystem _interactionSystem; + private ToolSystem _toolSystem; + + private SolutionComponent _solutionComponent; + private SpriteComponent _spriteComponent; + + private Tool _behavior = Tool.Wrench; + private float _speedModifier = 1; + private bool _welderLit = false; + private string _useSound; + private string _useSoundCollection; + + [ViewVariables] + public override Tool Behavior + { + get => _behavior; + set + { + _behavior = value; + Dirty(); + } + } + + [ViewVariables] + public float Fuel => _solutionComponent?.Solution.GetReagentQuantity("chem.WeldingFuel").Float() ?? 0f; + + [ViewVariables] + public float FuelCapacity => _solutionComponent?.MaxVolume.Float() ?? 0f; + + /// + /// For tool interactions that have a delay before action this will modify the rate, time to wait is divided by this value + /// + [ViewVariables(VVAccess.ReadWrite)] + public float SpeedModifier + { + get => _speedModifier; + set => _speedModifier = value; + } /// /// Status of welder, whether it is ignited /// [ViewVariables] - public bool Activated + public bool WelderLit { - get => _activated; + get => _welderLit; private set { - _activated = value; + _welderLit = value; Dirty(); } } + public string UseSound + { + get => _useSound; + set => _useSound = value; + } + + public string UseSoundCollection + { + get => _useSoundCollection; + set => _useSoundCollection = value; + } + + public override void Initialize() + { + base.Initialize(); + + _audioSystem = _entitySystemManager.GetEntitySystem(); + _interactionSystem = _entitySystemManager.GetEntitySystem(); + _toolSystem = _entitySystemManager.GetEntitySystem(); + + Owner.TryGetComponent(out _solutionComponent); + Owner.TryGetComponent(out _spriteComponent); + } + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + + serializer.DataField(ref _speedModifier, "speed", 1); + serializer.DataField(ref _useSound, "useSound", string.Empty); + serializer.DataField(ref _useSoundCollection, "useSoundCollection", string.Empty); + _behavior = (Tool)serializer.ReadStringEnumKey("behavior"); + } + + /// + /// Status modifier which determines whether or not we can act as a tool at this time + /// + public bool CanUse() + { + return _behavior != Tool.Welder || CanWeld(DefaultFuelCost); + } + + public bool TryWeld(float value) + { + if (!WelderLit || !CanWeld(value) || _solutionComponent == null) + { + return false; + } + + return _solutionComponent.TryRemoveReagent("chem.WeldingFuel", ReagentUnit.New(value)); + } + + public bool CanWeld(float value) + { + return Fuel > value || Behavior != Tool.Welder; + } + + public bool CanLitWelder() + { + return Fuel > 0 || Behavior != Tool.Welder; + } + + /// + /// Deactivates welding tool if active, activates welding tool if possible + /// + /// + public bool ToggleWelderStatus() + { + if (WelderLit) + { + WelderLit = false; + // Layer 1 is the flame. + _spriteComponent.LayerSetVisible(1, false); + PlaySoundCollection("WelderOff", -5); + _toolSystem.Unsubscribe(this); + return true; + } + + if (!CanLitWelder()) return false; + + WelderLit = true; + _spriteComponent.LayerSetVisible(1, true); + PlaySoundCollection("WelderOn", -5); + _toolSystem.Subscribe(this); + return true; + } + + public void OnUpdate(float frameTime) + { + if (Behavior != Tool.Welder || !WelderLit) + { + return; + } + + _solutionComponent.TryRemoveReagent("chem.WeldingFuel", ReagentUnit.New(FuelLossRate * frameTime)); + + Logger.Info(_solutionComponent.Solution.GetReagentQuantity("chem.WeldingFuel").ToString()); + + if (Fuel == 0) + { + ToggleWelderStatus(); + } + + Dirty(); + } + + private void PlaySoundCollection(string name, float volume=-5f) + { + var soundCollection = _prototypeManager.Index(name); + var file = _robustRandom.Pick(soundCollection.PickFiles); + _entitySystemManager.GetEntitySystem() + .Play(file, Owner, AudioParams.Default.WithVolume(volume)); + } + + public void PlayUseSound() + { + if(string.IsNullOrEmpty(UseSoundCollection)) + _audioSystem.Play(UseSound, Owner); + else + PlaySoundCollection(UseSoundCollection, 0f); + } + + public override ComponentState GetComponentState() + { + return Behavior == Tool.Welder ? new ToolComponentState(FuelCapacity, Fuel, WelderLit) : new ToolComponentState(Behavior); + } + public void AfterAttack(AfterAttackEventArgs eventArgs) { if (Behavior != Tool.Crowbar) @@ -134,11 +250,49 @@ namespace Content.Server.GameObjects.Components.Interactable var underplating = _tileDefinitionManager["underplating"]; mapGrid.SetTile(eventArgs.ClickLocation, new Tile(underplating.TileId)); - _audioSystem.Play("/Audio/items/crowbar.ogg", Owner); + PlayUseSound(); //Actually spawn the relevant tile item at the right position and give it some offset to the corner. var tileItem = Owner.EntityManager.SpawnEntity(tileDef.ItemDropPrototypeName, coordinates); tileItem.Transform.WorldPosition += (0.2f, 0.2f); } + + public bool UseEntity(UseEntityEventArgs eventArgs) + { + Logger.Info(Behavior.ToString()); + + switch (Behavior) + { + case Tool.Welder: + return ToggleWelderStatus(); + } + + return false; + } + + public void Examine(FormattedMessage message) + { + switch (Behavior) + { + case Tool.Welder: + if (WelderLit) + { + message.AddMarkup(Loc.GetString("[color=orange]Lit[/color]\n")); + } + else + { + message.AddText(Loc.GetString("Not lit\n")); + } + + message.AddMarkup(Loc.GetString("Fuel: [color={0}]{1}/{2}[/color].", + Fuel < FuelCapacity / 4f ? "darkorange" : "orange", Math.Round(Fuel), FuelCapacity)); + break; + } + } + + public void Attack(AttackEventArgs eventArgs) + { + + } } } diff --git a/Content.Server/GameObjects/Components/Interactable/Tools/CrowbarComponent.cs b/Content.Server/GameObjects/Components/Interactable/Tools/CrowbarComponent.cs deleted file mode 100644 index 593759413a..0000000000 --- a/Content.Server/GameObjects/Components/Interactable/Tools/CrowbarComponent.cs +++ /dev/null @@ -1,29 +0,0 @@ -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; -using Robust.Shared.Map; - -namespace Content.Server.GameObjects.Components.Interactable.Tools -{ - [RegisterComponent] - public class CrowbarComponent : ToolComponent, IAfterAttack - { -#pragma warning disable 649 - -#pragma warning restore 649 - - /// - /// Tool that can be used to crowbar things apart, such as deconstructing - /// - public override string Name => "Crowbar"; - - public void AfterAttack(AfterAttackEventArgs eventArgs) - { - - } - } -} diff --git a/Content.Server/GameObjects/Components/Interactable/Tools/WelderComponent.cs b/Content.Server/GameObjects/Components/Interactable/Tools/WelderComponent.cs deleted file mode 100644 index e2fa2791fc..0000000000 --- a/Content.Server/GameObjects/Components/Interactable/Tools/WelderComponent.cs +++ /dev/null @@ -1,217 +0,0 @@ -using System; -using Content.Server.GameObjects.EntitySystems; -using Content.Shared.Audio; -using Content.Shared.GameObjects; -using Content.Shared.GameObjects.Components; -using Robust.Server.GameObjects; -using Robust.Server.GameObjects.EntitySystems; -using Robust.Shared.Audio; -using Robust.Shared.GameObjects; -using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.Interfaces.Random; -using Robust.Shared.IoC; -using Robust.Shared.Localization; -using Robust.Shared.Prototypes; -using Robust.Shared.Random; -using Robust.Shared.Serialization; -using Robust.Shared.Utility; -using Robust.Shared.ViewVariables; - -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, IUse, IExamine - { - SpriteComponent spriteComponent; - -#pragma warning disable 649 - [Dependency] private readonly IPrototypeManager _prototypeManager; - [Dependency] private readonly IRobustRandom _robustRandom; - [Dependency] private readonly IEntitySystemManager _entitySystemManager; -#pragma warning restore 649 - - public override string Name => "Welder"; - public override uint? NetID => ContentNetIDs.WELDER; - - /// - /// Maximum fuel capacity the welder can hold - /// - [ViewVariables(VVAccess.ReadWrite)] - public float FuelCapacity - { - get => _fuelCapacity; - set - { - _fuelCapacity = value; - Dirty(); - } - } - - private float _fuelCapacity = 50; - - /// - /// Fuel the welder has to do tasks - /// - [ViewVariables(VVAccess.ReadWrite)] - public float Fuel - { - get => _fuel; - set - { - _fuel = value; - Dirty(); - } - } - - private float _fuel = 0; - private bool _activated = false; - - /// - /// Default Cost of using the welder fuel for an action - /// - public const float DefaultFuelCost = 5; - - /// - /// Rate at which we expunge fuel from ourselves when activated - /// - public const float FuelLossRate = 0.2f; - - /// - /// Status of welder, whether it is ignited - /// - [ViewVariables] - public bool Activated - { - get => _activated; - private set - { - _activated = value; - Dirty(); - } - } - - //private string OnSprite { get; set; } - //private string OffSprite { get; set; } - - public override void Initialize() - { - base.Initialize(); - - spriteComponent = Owner.GetComponent(); - } - - public override void ExposeData(ObjectSerializer serializer) - { - base.ExposeData(serializer); - - serializer.DataField(ref _fuelCapacity, "Capacity", 50); - serializer.DataField(ref _fuel, "Fuel", FuelCapacity); - serializer.DataField(ref _activated, "Activated", false); - } - - public void OnUpdate(float frameTime) - { - if (!Activated) - { - return; - } - - Fuel = Math.Max(Fuel - (FuelLossRate * frameTime), 0); - - if (Fuel == 0) - { - ToggleStatus(); - } - } - - public bool TryUse(float value) - { - if (!Activated || !CanUse(value)) - { - return false; - } - - Fuel -= value; - return true; - } - - public bool CanUse(float value) - { - return Fuel > value; - } - - public override bool CanUse() - { - return CanUse(DefaultFuelCost); - } - - public bool CanActivate() - { - return Fuel > 0; - } - - public bool UseEntity(UseEntityEventArgs eventArgs) - { - return ToggleStatus(); - } - - /// - /// Deactivates welding tool if active, activates welding tool if possible - /// - /// - public bool ToggleStatus() - { - if (Activated) - { - Activated = false; - // Layer 1 is the flame. - spriteComponent.LayerSetVisible(1, false); - PlaySoundCollection("welder_off", -5); - return true; - } - else if (CanActivate()) - { - Activated = true; - spriteComponent.LayerSetVisible(1, true); - PlaySoundCollection("welder_on", -5); - return true; - } - else - { - return false; - } - } - - void IExamine.Examine(FormattedMessage message) - { - var loc = IoCManager.Resolve(); - if (Activated) - { - message.AddMarkup(loc.GetString("[color=orange]Lit[/color]\n")); - } - else - { - message.AddText(loc.GetString("Not lit\n")); - } - - message.AddMarkup(loc.GetString("Fuel: [color={0}]{1}/{2}[/color].", - Fuel < FuelCapacity / 4f ? "darkorange" : "orange", Math.Round(Fuel), FuelCapacity)); - } - - private void PlaySoundCollection(string name, float volume) - { - var soundCollection = _prototypeManager.Index(name); - var file = _robustRandom.Pick(soundCollection.PickFiles); - _entitySystemManager.GetEntitySystem() - .Play(file, AudioParams.Default.WithVolume(volume)); - } - - public override ComponentState GetComponentState() - { - return new WelderComponentState(FuelCapacity, Fuel, Activated); - } - } -} diff --git a/Content.Server/GameObjects/Components/Power/PowerTransferComponent.cs b/Content.Server/GameObjects/Components/Power/PowerTransferComponent.cs index 541b4f2f5a..9bafecbb2e 100644 --- a/Content.Server/GameObjects/Components/Power/PowerTransferComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerTransferComponent.cs @@ -1,7 +1,8 @@ using System.Linq; -using Content.Server.GameObjects.Components.Interactable.Tools; +using Content.Server.GameObjects.Components.Interactable; using Content.Server.GameObjects.Components.Stack; using Content.Server.GameObjects.EntitySystems; +using Content.Shared.GameObjects.Components.Interactable; using Robust.Server.Interfaces.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components.Transform; @@ -140,17 +141,16 @@ namespace Content.Server.GameObjects.Components.Power public bool AttackBy(AttackByEventArgs eventArgs) { - if (eventArgs.AttackWith.TryGetComponent(out WirecutterComponent wirecutter)) - { - Owner.Delete(); - var droppedEnt = Owner.EntityManager.SpawnEntity("CableStack", eventArgs.ClickLocation); + if (!eventArgs.AttackWith.TryGetComponent(out ToolComponent tool)) return false; + if (tool.Behavior != Tool.Wirecutter) return false; - if (droppedEnt.TryGetComponent(out var stackComp)) - stackComp.Count = 1; + Owner.Delete(); + var droppedEnt = Owner.EntityManager.SpawnEntity("CableStack", eventArgs.ClickLocation); - return true; - } - return false; + if (droppedEnt.TryGetComponent(out var stackComp)) + stackComp.Count = 1; + + return true; } } } diff --git a/Content.Server/GameObjects/Components/WiresComponent.cs b/Content.Server/GameObjects/Components/WiresComponent.cs index 18510e6908..8dc48fdd89 100644 --- a/Content.Server/GameObjects/Components/WiresComponent.cs +++ b/Content.Server/GameObjects/Components/WiresComponent.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; using System.Linq; -using Content.Server.GameObjects.Components.Interactable.Tools; +using Content.Server.GameObjects.Components.Interactable; using Content.Server.GameObjects.Components.VendingMachines; using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces; using Content.Server.Interfaces.GameObjects; using Content.Shared.GameObjects.Components; +using Content.Shared.GameObjects.Components.Interactable; using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.UserInterface; @@ -235,30 +236,31 @@ namespace Content.Server.GameObjects.Components return; } var activeHandEntity = handsComponent.GetActiveHand?.Owner; + activeHandEntity.TryGetComponent(out var tool); switch (msg.Action) { case WiresAction.Cut: - if (activeHandEntity?.HasComponent() != true) + if (tool == null || tool.Behavior != Tool.Wirecutter) { _notifyManager.PopupMessage(Owner.Transform.GridPosition, player, _localizationManager.GetString("You need to hold a wirecutter in your hand!")); return; } - _audioSystem.Play("/Audio/items/wirecutter.ogg", Owner); + tool.PlayUseSound(); wire.IsCut = true; UpdateUserInterface(); break; case WiresAction.Mend: - if (activeHandEntity?.HasComponent() != true) + if (tool == null || tool.Behavior != Tool.Wirecutter) { _notifyManager.PopupMessage(Owner.Transform.GridPosition, player, _localizationManager.GetString("You need to hold a wirecutter in your hand!")); return; } - _audioSystem.Play("/Audio/items/wirecutter.ogg", Owner); + tool.PlayUseSound(); wire.IsCut = false; UpdateUserInterface(); break; case WiresAction.Pulse: - if (activeHandEntity?.HasComponent() != true) + if (tool == null || tool.Behavior != Tool.Multitool) { _notifyManager.PopupMessage(Owner.Transform.GridPosition, player, _localizationManager.GetString("You need to hold a multitool in your hand!")); return; @@ -288,10 +290,10 @@ namespace Content.Server.GameObjects.Components bool IAttackBy.AttackBy(AttackByEventArgs eventArgs) { - if (!eventArgs.AttackWith.HasComponent()) - { + if (!eventArgs.AttackWith.TryGetComponent(out var tool)) + return false; + if (tool.Behavior != Tool.Screwdriver) return false; - } IsPanelOpen = !IsPanelOpen; IoCManager.Resolve() diff --git a/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs b/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs index e42c37978c..85f81ec427 100644 --- a/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs @@ -1,8 +1,11 @@ using System; +using System.Collections.Generic; using System.Linq; +using Content.Server.GameObjects.Components.Interactable; using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Timing; using Content.Server.Interfaces.GameObjects; +using Content.Shared.GameObjects.Components.Interactable; using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.Input; using Content.Shared.Physics; @@ -43,6 +46,129 @@ namespace Content.Server.GameObjects.EntitySystems public IEntity AttackWith { get; set; } } + #region Tools + + /// + /// This interface gives components behavior when being clicked on or "attacked" by a user with a tool in their hand + /// + public interface IToolAct + { + /// + /// Called when using a wrench on an entity + /// + bool ToolAct(ToolActEventArgs eventArgs) => false; + } + + public class ToolActEventArgs : EventArgs + { + public IEntity User { get; set; } + public GridCoordinates ClickLocation { get; set; } + public IEntity AttackWith { get; set; } + public ToolComponent ToolComponent => AttackWith.GetComponent(); + public virtual Tool Behavior { get; } + } + + /// + /// This interface gives components behavior when being clicked on or "attacked" by a user with a wrench in their hand + /// + public interface IWrenchAct : IToolAct + { + /// + /// Called when using a wrench on an entity + /// + bool WrenchAct(WrenchActEventArgs eventArgs); + } + + public class WrenchActEventArgs : ToolActEventArgs + { + public override Tool Behavior => Tool.Wrench; + } + + /// + /// This interface gives components behavior when being clicked on or "attacked" by a user with a crowbar in their hand + /// + public interface ICrowbarAct : IToolAct + { + /// + /// Called when using a wrench on an entity + /// + bool CrowbarAct(CrowbarActEventArgs eventArgs); + } + + public class CrowbarActEventArgs : ToolActEventArgs + { + public override Tool Behavior => Tool.Crowbar; + } + + /// + /// This interface gives components behavior when being clicked on or "attacked" by a user with a screwdriver in their hand + /// + public interface IScrewdriverAct + { + /// + /// Called when using a wrench on an entity + /// + bool ScrewdriverAct(ScrewdriverActEventArgs eventArgs); + } + + public class ScrewdriverActEventArgs : ToolActEventArgs + { + public override Tool Behavior => Tool.Screwdriver; + } + + /// + /// This interface gives components behavior when being clicked on or "attacked" by a user with a wirecutter in their hand + /// + public interface IWirecutterAct + { + /// + /// Called when using a wrench on an entity + /// + bool WirecutterAct(WirecutterActEventArgs eventArgs); + } + + public class WirecutterActEventArgs : ToolActEventArgs + { + public override Tool Behavior => Tool.Wirecutter; + } + + /// + /// This interface gives components behavior when being clicked on or "attacked" by a user with a welder in their hand + /// + public interface IWelderAct + { + /// + /// Called when using a wrench on an entity + /// + bool WelderAct(WelderActEventArgs eventArgs); + } + + public class WelderActEventArgs : ToolActEventArgs + { + public override Tool Behavior => Tool.Welder; + public bool Lit { get; set; } + public float Fuel { get; set; } + public float FuelCapacity { get; set; } + } + + /// + /// This interface gives components behavior when being clicked on or "attacked" by a user with a multitool in their hand + /// + public interface IMultitoolAct + { + /// + /// Called when using a wrench on an entity + /// + bool MultitoolAct(MultitoolActEventArgs eventArgs); + } + + public class MultitoolActEventArgs : ToolActEventArgs + { + public override Tool Behavior => Tool.Multitool; + } + + #endregion + /// /// This interface gives components behavior when being clicked on or "attacked" by a user with an empty hand /// @@ -561,9 +687,97 @@ namespace Content.Server.GameObjects.EntitySystems foreach (var attackBy in attackBys) { if (attackBy.AttackBy(attackByEventArgs)) - { // If an AttackBy returns a status completion we finish our attack return; + } + + // We handle specific tools AttackBy here. + if (weapon.TryGetComponent(out var tool)) + { + switch (tool.Behavior) + { + case Tool.Wrench: + var wrenchList = attacked.GetAllComponents().ToList(); + var wrenchAttackBy = new WrenchActEventArgs() + { User = user, ClickLocation = clickLocation, AttackWith = weapon }; + + foreach (var comp in wrenchList) + { + if (comp.WrenchAct(wrenchAttackBy)) + return; + } + + break; + + case Tool.Crowbar: + var crowbarList = attacked.GetAllComponents().ToList(); + var crowbarAttackBy = new CrowbarActEventArgs() + { User = user, ClickLocation = clickLocation, AttackWith = weapon }; + + foreach (var comp in crowbarList) + { + if (comp.CrowbarAct(crowbarAttackBy)) + return; + } + + break; + + case Tool.Screwdriver: + var screwdriverList = attacked.GetAllComponents().ToList(); + var screwdriverAttackBy = new ScrewdriverActEventArgs() + { User = user, ClickLocation = clickLocation, AttackWith = weapon }; + + foreach (var comp in screwdriverList) + { + if (comp.ScrewdriverAct(screwdriverAttackBy)) + return; + } + + break; + + case Tool.Wirecutter: + var wirecutterList = attacked.GetAllComponents().ToList(); + var wirecutterAttackBy = new WirecutterActEventArgs() + { User = user, ClickLocation = clickLocation, AttackWith = weapon }; + + foreach (var comp in wirecutterList) + { + if (comp.WirecutterAct(wirecutterAttackBy)) + return; + } + break; + + case Tool.Welder: + var welderList = attacked.GetAllComponents().ToList(); + var welderAttackBy = new WelderActEventArgs() + { + User = user, ClickLocation = clickLocation, AttackWith = weapon, + Fuel = tool.Fuel, FuelCapacity = tool.FuelCapacity + }; + + foreach (var comp in welderList) + { + if (comp.WelderAct(welderAttackBy)) + return; + } + + break; + + case Tool.Multitool: + var multitoolList = attacked.GetAllComponents().ToList(); + var multitoolAttackBy = new MultitoolActEventArgs() + { User = user, ClickLocation = clickLocation, AttackWith = weapon }; + + foreach (var comp in multitoolList) + { + if (comp.MultitoolAct(multitoolAttackBy)) + return; + } + + break; + + default: + throw new ArgumentOutOfRangeException(); } } diff --git a/Content.Server/GameObjects/EntitySystems/ToolSystem.cs b/Content.Server/GameObjects/EntitySystems/ToolSystem.cs index 6d46fd5155..4d90696592 100644 --- a/Content.Server/GameObjects/EntitySystems/ToolSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/ToolSystem.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; +using System.Linq; using Content.Server.GameObjects.Components.Interactable; -using Content.Server.GameObjects.Components.Interactable.Tools; -using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; namespace Content.Server.GameObjects.EntitySystems @@ -13,9 +12,22 @@ namespace Content.Server.GameObjects.EntitySystems { private readonly HashSet _activeWelders = new HashSet(); + public bool Subscribe(ToolComponent welder) + { + return _activeWelders.Add(welder); + } + + public bool Unsubscribe(ToolComponent welder) + { + return _activeWelders.Remove(welder); + } + public override void Update(float frameTime) { - foreach (var tool in _activeWelders) ; + foreach (var tool in _activeWelders.ToArray()) + { + tool.OnUpdate(frameTime); + } } } } diff --git a/Content.Shared/Construction/ConstructionPrototype.cs b/Content.Shared/Construction/ConstructionPrototype.cs index d9e04eacbf..be9f6c1ef3 100644 --- a/Content.Shared/Construction/ConstructionPrototype.cs +++ b/Content.Shared/Construction/ConstructionPrototype.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Content.Shared.GameObjects.Components.Interactable; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.Utility; @@ -138,7 +139,7 @@ namespace Content.Shared.Construction if (step.TryGetNode("tool", out node)) { return new ConstructionStepTool( - node.AsEnum(), + node.AsEnum(), amount ); } @@ -190,21 +191,12 @@ namespace Content.Shared.Construction public class ConstructionStepTool : ConstructionStep { - public readonly ToolType Tool; + public readonly Tool Tool; - public ConstructionStepTool(ToolType tool, int amount) : base(amount) + public ConstructionStepTool(Tool tool, int amount) : base(amount) { Tool = tool; } - - public enum ToolType - { - Wrench, - Welder, - Screwdriver, - Crowbar, - Wirecutters, - } } public class ConstructionStepMaterial : ConstructionStep diff --git a/Content.Shared/GameObjects/Components/Interactable/SharedToolComponent.cs b/Content.Shared/GameObjects/Components/Interactable/SharedToolComponent.cs new file mode 100644 index 0000000000..2ba8c13928 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Interactable/SharedToolComponent.cs @@ -0,0 +1,46 @@ +using System; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.Components.Interactable +{ + public enum Tool : byte + { + Wrench, + Crowbar, + Screwdriver, + Wirecutter, + Welder, + Multitool, + } + + public class SharedToolComponent : Component + { + public override string Name => "Tool"; + public override uint? NetID => ContentNetIDs.TOOL; + + public virtual Tool Behavior { get; set; } + } + + [NetSerializable, Serializable] + public class ToolComponentState : ComponentState + { + public float FuelCapacity { get; } + public float Fuel { get; } + public bool Activated { get; } + public Tool Behavior { get; } + + public ToolComponentState(Tool behavior) : base(ContentNetIDs.TOOL) + { + Behavior = behavior; + } + + public ToolComponentState(float fuelCapacity, float fuel, bool activated) : base(ContentNetIDs.TOOL) + { + FuelCapacity = fuelCapacity; + Fuel = fuel; + Activated = activated; + Behavior = Tool.Welder; + } + } +} diff --git a/Content.Shared/GameObjects/Components/WelderComponentState.cs b/Content.Shared/GameObjects/Components/WelderComponentState.cs deleted file mode 100644 index 61aaa5ed1b..0000000000 --- a/Content.Shared/GameObjects/Components/WelderComponentState.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using Robust.Shared.GameObjects; -using Robust.Shared.Serialization; - -namespace Content.Shared.GameObjects.Components -{ - [NetSerializable, Serializable] - public class WelderComponentState : ComponentState - { - public float FuelCapacity { get; } - public float Fuel { get; } - public bool Activated { get; } - - public WelderComponentState(float fuelCapacity, float fuel, bool activated) : base(ContentNetIDs.WELDER) - { - FuelCapacity = fuelCapacity; - Fuel = fuel; - Activated = activated; - } - } -} diff --git a/Content.Shared/GameObjects/ContentNetIDs.cs b/Content.Shared/GameObjects/ContentNetIDs.cs index ef69972f4d..f8f70db30b 100644 --- a/Content.Shared/GameObjects/ContentNetIDs.cs +++ b/Content.Shared/GameObjects/ContentNetIDs.cs @@ -36,7 +36,7 @@ public const uint GALACTIC_MARKET = 1031; public const uint HUMANOID_APPEARANCE = 1032; public const uint INSTRUMENTS = 1033; - public const uint WELDER = 1034; + public const uint TOOL = 1034; public const uint STACK = 1035; public const uint HANDHELD_LIGHT = 1036; public const uint PAPER = 1037; diff --git a/Resources/Audio/items/change_drill.ogg b/Resources/Audio/items/change_drill.ogg new file mode 100644 index 0000000000..f8928fc00f Binary files /dev/null and b/Resources/Audio/items/change_drill.ogg differ diff --git a/Resources/Audio/items/change_jaws.ogg b/Resources/Audio/items/change_jaws.ogg new file mode 100644 index 0000000000..13960ccc3e Binary files /dev/null and b/Resources/Audio/items/change_jaws.ogg differ diff --git a/Resources/Audio/items/drill_hit.ogg b/Resources/Audio/items/drill_hit.ogg new file mode 100644 index 0000000000..0f8fa631aa Binary files /dev/null and b/Resources/Audio/items/drill_hit.ogg differ diff --git a/Resources/Audio/items/drill_use.ogg b/Resources/Audio/items/drill_use.ogg new file mode 100644 index 0000000000..82f37cd35b Binary files /dev/null and b/Resources/Audio/items/drill_use.ogg differ diff --git a/Resources/Audio/items/jaws_cut.ogg b/Resources/Audio/items/jaws_cut.ogg new file mode 100644 index 0000000000..a0bfd85502 Binary files /dev/null and b/Resources/Audio/items/jaws_cut.ogg differ diff --git a/Resources/Audio/items/jaws_pry.ogg b/Resources/Audio/items/jaws_pry.ogg new file mode 100644 index 0000000000..05178bd466 Binary files /dev/null and b/Resources/Audio/items/jaws_pry.ogg differ diff --git a/Resources/Prototypes/Entities/Buildings/computers.yml b/Resources/Prototypes/Entities/Buildings/computers.yml index 3771493ff0..c18ee7d92a 100644 --- a/Resources/Prototypes/Entities/Buildings/computers.yml +++ b/Resources/Prototypes/Entities/Buildings/computers.yml @@ -20,7 +20,7 @@ - type: Computer - type: PowerDevice priority: High - - type: Wrenchable + - type: Anchorable - type: Sprite sprite: Buildings/computer.rsi diff --git a/Resources/Prototypes/Entities/Buildings/vending_machines.yml b/Resources/Prototypes/Entities/Buildings/vending_machines.yml index 19fb4399ac..c0a9c2af49 100644 --- a/Resources/Prototypes/Entities/Buildings/vending_machines.yml +++ b/Resources/Prototypes/Entities/Buildings/vending_machines.yml @@ -39,7 +39,7 @@ - type: PowerDevice priority: Low - type: Wires - - type: Wrenchable + - type: Anchorable - type: entity parent: VendingMachine diff --git a/Resources/Prototypes/Entities/Items/powercells.yml b/Resources/Prototypes/Entities/Items/powercells.yml index 02a615d128..b74b5f1c83 100644 --- a/Resources/Prototypes/Entities/Items/powercells.yml +++ b/Resources/Prototypes/Entities/Items/powercells.yml @@ -116,7 +116,7 @@ - type: Appearance visuals: - type: PowerChargerVisualizer2D - - type: Wrenchable + - type: Anchorable - type: Physics mass: 5 - type: Clickable @@ -148,7 +148,7 @@ - type: Appearance visuals: - type: PowerChargerVisualizer2D - - type: Wrenchable + - type: Anchorable - type: Physics mass: 5 - type: Clickable diff --git a/Resources/Prototypes/Entities/Items/tools.yml b/Resources/Prototypes/Entities/Items/tools.yml index a057ee819a..9ab807a6e6 100644 --- a/Resources/Prototypes/Entities/Items/tools.yml +++ b/Resources/Prototypes/Entities/Items/tools.yml @@ -11,7 +11,8 @@ - type: ItemCooldown - type: MeleeWeapon - type: Tool - behavior: enum.Tool.Wirecutter + behavior: enum.Tool.Wirecutter + useSound: /Audio/items/wirecutter.ogg - type: entity name: Screwdriver @@ -30,7 +31,8 @@ - type: ItemCooldown - type: MeleeWeapon - type: Tool - behavior: enum.Tool.Screwdriver + behavior: enum.Tool.Screwdriver + useSoundCollection: Screwdriver - type: entity name: Welding Tool @@ -51,8 +53,16 @@ - type: ItemCooldown - type: MeleeWeapon - type: ItemStatus + - type: Solution + maxVol: 50 + caps: 9 + contents: + reagents: + - ReagentId: chem.WeldingFuel + Quantity: 50 - type: Tool - behavior: enum.Tool.Screwdriver + behavior: enum.Tool.Welder + useSoundCollection: Welder - type: entity name: Wrench @@ -67,7 +77,8 @@ - type: ItemCooldown - type: MeleeWeapon - type: Tool - behavior: enum.Tool.Wrench + behavior: enum.Tool.Wrench + useSound: /Audio/items/ratchet.ogg - type: entity name: Crowbar @@ -82,7 +93,8 @@ - type: ItemCooldown - type: MeleeWeapon - type: Tool - behavior: enum.Tool.Crowbar + behavior: enum.Tool.Crowbar + useSound: /Audio/items/crowbar.ogg - type: entity name: Multitool @@ -99,4 +111,60 @@ - type: Item sprite: Objects/Tools/multitool.rsi - type: Tool - behavior: enum.Tool.Multitool + behavior: enum.Tool.Multitool + +- type: entity + name: Jaws of life + parent: BaseItem + id: JawsOfLife + description: A set of jaws of life, compressed through the magic of science. + components: + - type: Sprite + sprite: Objects/Tools/jaws_of_life.rsi + state: jaws_pry + - type: Icon + sprite: Objects/Tools/jaws_of_life.rsi + state: jaws_pry + - type: Item + sprite: Objects/Tools/jaws_of_life.rsi + - type: Tool + behavior: enum.Tool.Crowbar + statusShowBehavior: true + - type: MultiTool + tools: + - behavior: enum.Tool.Crowbar + state: jaws_pry + useSound: /Audio/items/jaws_pry.ogg + changeSound: /Audio/items/change_jaws.ogg + - behavior: enum.Tool.Wirecutter + state: jaws_cutter + useSound: /Audio/items/jaws_cut.ogg + changeSound: /Audio/items/change_jaws.ogg + +- type: entity + name: Power Drill + parent: BaseItem + id: PowerDrill + description: A simple powered hand drill. + components: + - type: Sprite + sprite: Objects/Tools/drill.rsi + state: drill_screw + - type: Icon + sprite: Objects/Tools/drill.rsi + state: drill_screw + - type: Item + sprite: Objects/Tools/drill.rsi + - type: Tool + behavior: enum.Tool.Screwdriver + statusShowBehavior: true + - type: MultiTool + tools: + - behavior: enum.Tool.Screwdriver + state: drill_screw + useSound: /Audio/items/drill_use.ogg + changeSound: /Audio/items/change_drill.ogg + - behavior: enum.Tool.Wrench + state: drill_bolt + useSound: /Audio/items/drill_use.ogg + changeSound: /Audio/items/change_drill.ogg diff --git a/Resources/Prototypes/Reagents/chemicals.yml b/Resources/Prototypes/Reagents/chemicals.yml index 2886f5accd..35129f9d7b 100644 --- a/Resources/Prototypes/Reagents/chemicals.yml +++ b/Resources/Prototypes/Reagents/chemicals.yml @@ -105,3 +105,9 @@ name: Unstable Mutagen desc: Causes mutations when injected into living people or plants. High doses may be lethal, especially in humans. color: "#77b58e" + +- type: reagent + id: chem.WeldingFuel + name: Welding Fuel + desc: Used by welders to weld. + color: "#a76b1c" diff --git a/Resources/Prototypes/SoundCollections/tools.yml b/Resources/Prototypes/SoundCollections/tools.yml index 5be73b3aed..fbb9647b3d 100644 --- a/Resources/Prototypes/SoundCollections/tools.yml +++ b/Resources/Prototypes/SoundCollections/tools.yml @@ -8,3 +8,15 @@ id: WelderOff files: - /Audio/effects/zzzt.ogg + +- type: soundCollection + id: Welder + files: + - /Audio/items/welder.ogg + - /Audio/items/welder2.ogg + +- type: soundCollection + id: Screwdriver + files: + - /Audio/items/screwdriver.ogg + - /Audio/items/screwdriver2.ogg diff --git a/Resources/Textures/Objects/Tools/drill.rsi/drill_bolt.png b/Resources/Textures/Objects/Tools/drill.rsi/drill_bolt.png new file mode 100644 index 0000000000..7ae77acf3a Binary files /dev/null and b/Resources/Textures/Objects/Tools/drill.rsi/drill_bolt.png differ diff --git a/Resources/Textures/Objects/Tools/drill.rsi/drill_screw.png b/Resources/Textures/Objects/Tools/drill.rsi/drill_screw.png new file mode 100644 index 0000000000..f4cb59c283 Binary files /dev/null and b/Resources/Textures/Objects/Tools/drill.rsi/drill_screw.png differ diff --git a/Resources/Textures/Objects/Tools/drill.rsi/meta.json b/Resources/Textures/Objects/Tools/drill.rsi/meta.json new file mode 100644 index 0000000000..0b31ed1416 --- /dev/null +++ b/Resources/Textures/Objects/Tools/drill.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/tgstation/tgstation at commit ea59fb4b810decbb5996b36d8876614b57c3d189", "states": [{"name": "drill_bolt", "directions": 1, "delays": [[1.0]]}, {"name": "drill_screw", "directions": 1, "delays": [[1.0]]}]} diff --git a/Resources/Textures/Objects/Tools/jaws_of_life.rsi/jaws_cutter.png b/Resources/Textures/Objects/Tools/jaws_of_life.rsi/jaws_cutter.png new file mode 100644 index 0000000000..42695acd7c Binary files /dev/null and b/Resources/Textures/Objects/Tools/jaws_of_life.rsi/jaws_cutter.png differ diff --git a/Resources/Textures/Objects/Tools/jaws_of_life.rsi/jaws_pry.png b/Resources/Textures/Objects/Tools/jaws_of_life.rsi/jaws_pry.png new file mode 100644 index 0000000000..8877f81e18 Binary files /dev/null and b/Resources/Textures/Objects/Tools/jaws_of_life.rsi/jaws_pry.png differ diff --git a/Resources/Textures/Objects/Tools/jaws_of_life.rsi/meta.json b/Resources/Textures/Objects/Tools/jaws_of_life.rsi/meta.json new file mode 100644 index 0000000000..7adb58c6ef --- /dev/null +++ b/Resources/Textures/Objects/Tools/jaws_of_life.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/tgstation/tgstation at commit ea59fb4b810decbb5996b36d8876614b57c3d189", "states": [{"name": "jaws_cutter", "directions": 1, "delays": [[1.0]]}, {"name": "jaws_pry", "directions": 1, "delays": [[1.0]]}]} diff --git a/RobustToolbox b/RobustToolbox index 7c4b1af967..b366070cd4 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit 7c4b1af96743d2b87a787726c851e141b7ba45c2 +Subproject commit b366070cd4f1912844710b475dacf84328c74d89 diff --git a/SpaceStation14.sln.DotSettings b/SpaceStation14.sln.DotSettings index 3497a17c82..7d2c5a9648 100644 --- a/SpaceStation14.sln.DotSettings +++ b/SpaceStation14.sln.DotSettings @@ -56,4 +56,5 @@ True True True - True + True + True