diff --git a/Content.Client/Items/Systems/ItemToggleSystem.cs b/Content.Client/Items/Systems/ItemToggleSystem.cs new file mode 100644 index 0000000000..46d6f1b464 --- /dev/null +++ b/Content.Client/Items/Systems/ItemToggleSystem.cs @@ -0,0 +1,9 @@ +using Content.Shared.Item.ItemToggle; + +namespace Content.Shared.Item; + +/// +public sealed class ItemToggleSystem : SharedItemToggleSystem +{ + +} diff --git a/Content.Client/Tools/ToolSystem.cs b/Content.Client/Tools/ToolSystem.cs index 966f37146e..a305fd5bb2 100644 --- a/Content.Client/Tools/ToolSystem.cs +++ b/Content.Client/Tools/ToolSystem.cs @@ -1,7 +1,7 @@ using Content.Client.Items; using Content.Client.Tools.Components; using Content.Client.Tools.UI; -using Content.Shared.Tools; +using Content.Shared.Item; using Content.Shared.Tools.Components; using Robust.Client.GameObjects; using Robust.Shared.GameStates; @@ -50,7 +50,7 @@ namespace Content.Client.Tools private void OnWelderGetStatusMessage(EntityUid uid, WelderComponent component, ItemStatusCollectMessage args) { - args.Controls.Add(new WelderStatusControl(component)); + args.Controls.Add(new WelderStatusControl(component, uid)); } private void OnWelderHandleState(EntityUid uid, WelderComponent welder, ref ComponentHandleState args) @@ -60,7 +60,6 @@ namespace Content.Client.Tools welder.FuelCapacity = state.FuelCapacity; welder.Fuel = state.Fuel; - welder.Lit = state.Lit; welder.UiUpdateNeeded = true; } diff --git a/Content.Client/Tools/UI/WelderStatusControl.cs b/Content.Client/Tools/UI/WelderStatusControl.cs index c8d4df2b8f..8da7a1448b 100644 --- a/Content.Client/Tools/UI/WelderStatusControl.cs +++ b/Content.Client/Tools/UI/WelderStatusControl.cs @@ -1,6 +1,7 @@ using Content.Client.Message; using Content.Client.Stylesheets; using Content.Client.Tools.Components; +using Content.Shared.Item; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Shared.Timing; @@ -9,13 +10,19 @@ namespace Content.Client.Tools.UI; public sealed class WelderStatusControl : Control { + [Dependency] private readonly IEntityManager _entMan = default!; + private readonly WelderComponent _parent; + private readonly ItemToggleComponent? _toggleComponent; private readonly RichTextLabel _label; - public WelderStatusControl(WelderComponent parent) + public WelderStatusControl(WelderComponent parent, EntityUid? uid = null) { _parent = parent; - _label = new RichTextLabel {StyleClasses = {StyleNano.StyleClassItemStatus}}; + _entMan = IoCManager.Resolve(); + if (_entMan.TryGetComponent(uid, out var itemToggle)) + _toggleComponent = itemToggle; + _label = new RichTextLabel { StyleClasses = { StyleNano.StyleClassItemStatus } }; AddChild(_label); UpdateDraw(); @@ -39,7 +46,11 @@ public sealed class WelderStatusControl : Control var fuelCap = _parent.FuelCapacity; var fuel = _parent.Fuel; - var lit = _parent.Lit; + var lit = false; + if (_toggleComponent != null) + { + lit = _toggleComponent.Activated; + } _label.SetMarkup(Loc.GetString("welder-component-on-examine-detailed-message", ("colorName", fuel < fuelCap / 4f ? "darkorange" : "orange"), diff --git a/Content.Client/Tools/Visualizers/WelderVisualizerSystem.cs b/Content.Client/Tools/Visualizers/WelderVisualizerSystem.cs deleted file mode 100644 index 02df7d98b0..0000000000 --- a/Content.Client/Tools/Visualizers/WelderVisualizerSystem.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Content.Client.Tools.Components; -using Content.Shared.Tools.Components; -using Robust.Client.GameObjects; - -namespace Content.Client.Tools.Visualizers; - -public sealed class WelderVisualizerSystem : VisualizerSystem -{ - protected override void OnAppearanceChange(EntityUid uid, WelderComponent component, ref AppearanceChangeEvent args) - { - if (args.Sprite == null) - return; - - if (AppearanceSystem.TryGetData(uid, WelderVisuals.Lit, out var isLit, args.Component)) - { - args.Sprite.LayerSetVisible(WelderLayers.Flame, isLit); - } - } -} diff --git a/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs b/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs index 6c842f0082..695de4461d 100644 --- a/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs +++ b/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs @@ -10,8 +10,8 @@ using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; using Content.Server.Construction.Components; using Content.Server.Gravity; +using Content.Server.Item; using Content.Server.Power.Components; -using Content.Server.Tools.Components; using Content.Shared.Atmos; using Content.Shared.Construction.Prototypes; using Content.Shared.Gravity; @@ -164,7 +164,7 @@ public abstract partial class InteractionTest // spawn and pick up the new item var item = await SpawnEntity(entity, SEntMan.GetCoordinates(PlayerCoords)); - WelderComponent? welder = null; + ItemToggleComponent? itemToggle = null; await Server.WaitPost(() => { @@ -173,14 +173,16 @@ public abstract partial class InteractionTest Assert.That(HandSys.TryPickup(playerEnt, item, Hands.ActiveHand, false, false, Hands)); // turn on welders - if (enableWelder && SEntMan.TryGetComponent(item, out welder) && !welder.Lit) - Assert.That(ToolSys.TryTurnWelderOn(item, playerEnt, welder)); + if (enableWelder && SEntMan.TryGetComponent(item, out itemToggle) && !itemToggle.Activated) + { + Assert.That(ItemToggleSys.TryActivate(item, playerEnt, itemToggle: itemToggle)); + } }); await RunTicks(1); Assert.That(Hands.ActiveHandEntity, Is.EqualTo(item)); - if (enableWelder && welder != null) - Assert.That(welder.Lit); + if (enableWelder && itemToggle != null) + Assert.That(itemToggle.Activated); return item; } diff --git a/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs b/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs index 58076454c1..f54d772881 100644 --- a/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs +++ b/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs @@ -12,6 +12,7 @@ using Content.Shared.DoAfter; using Content.Shared.Hands.Components; using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; +using Content.Server.Item; using Content.Shared.Mind; using Content.Shared.Players; using Robust.Client.Input; @@ -23,6 +24,7 @@ using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Timing; using Robust.UnitTesting; +using Content.Shared.Item.ItemToggle; namespace Content.IntegrationTests.Tests.Interaction; @@ -97,6 +99,7 @@ public abstract partial class InteractionTest protected Content.Server.Construction.ConstructionSystem SConstruction = default!; protected SharedDoAfterSystem DoAfterSys = default!; protected ToolSystem ToolSys = default!; + protected SharedItemToggleSystem ItemToggleSys = default!; protected InteractionTestSystem STestSystem = default!; protected SharedTransformSystem Transform = default!; protected ISawmill SLogger = default!; @@ -152,6 +155,7 @@ public abstract partial class InteractionTest HandSys = SEntMan.System(); InteractSys = SEntMan.System(); ToolSys = SEntMan.System(); + ItemToggleSys = SEntMan.System(); DoAfterSys = SEntMan.System(); Transform = SEntMan.System(); SConstruction = SEntMan.System(); diff --git a/Content.Server/Damage/Systems/DamageOnToolInteractSystem.cs b/Content.Server/Damage/Systems/DamageOnToolInteractSystem.cs index 2abd6fdf86..c12c71a850 100644 --- a/Content.Server/Damage/Systems/DamageOnToolInteractSystem.cs +++ b/Content.Server/Damage/Systems/DamageOnToolInteractSystem.cs @@ -1,6 +1,7 @@ using Content.Server.Administration.Logs; using Content.Server.Damage.Components; using Content.Server.Tools.Components; +using Content.Shared.Item; using Content.Shared.Damage; using Content.Shared.Database; using Content.Shared.Interaction; @@ -11,7 +12,7 @@ namespace Content.Server.Damage.Systems public sealed class DamageOnToolInteractSystem : EntitySystem { [Dependency] private readonly DamageableSystem _damageableSystem = default!; - [Dependency] private readonly IAdminLogManager _adminLogger= default!; + [Dependency] private readonly IAdminLogManager _adminLogger = default!; public override void Initialize() { @@ -25,16 +26,19 @@ namespace Content.Server.Damage.Systems if (args.Handled) return; + if (!TryComp(uid, out var itemToggle)) + return; + if (component.WeldingDamage is {} weldingDamage - && EntityManager.TryGetComponent(args.Used, out WelderComponent? welder) - && welder.Lit - && !welder.TankSafe) + && EntityManager.TryGetComponent(args.Used, out WelderComponent? welder) + && itemToggle.Activated + && !welder.TankSafe) { var dmg = _damageableSystem.TryChangeDamage(args.Target, weldingDamage, origin: args.User); if (dmg != null) _adminLogger.Add(LogType.Damaged, - $"{ToPrettyString(args.User):user} used {ToPrettyString(args.Used):used} as a welder to deal {dmg.Total:damage} damage to {ToPrettyString(args.Target):target}"); + $"{ToPrettyString(args.User):user} used {ToPrettyString(args.Used):used} as a welder to deal {dmg.GetTotal():damage} damage to {ToPrettyString(args.Target):target}"); args.Handled = true; } @@ -46,7 +50,7 @@ namespace Content.Server.Damage.Systems if (dmg != null) _adminLogger.Add(LogType.Damaged, - $"{ToPrettyString(args.User):user} used {ToPrettyString(args.Used):used} as a tool to deal {dmg.Total:damage} damage to {ToPrettyString(args.Target):target}"); + $"{ToPrettyString(args.User):user} used {ToPrettyString(args.Used):used} as a tool to deal {dmg.GetTotal():damage} damage to {ToPrettyString(args.Target):target}"); args.Handled = true; } diff --git a/Content.Server/Eye/Blinding/EyeProtection/EyeProtectionSystem.cs b/Content.Server/Eye/Blinding/EyeProtection/EyeProtectionSystem.cs index d31f9eeed6..1b6a5bb930 100644 --- a/Content.Server/Eye/Blinding/EyeProtection/EyeProtectionSystem.cs +++ b/Content.Server/Eye/Blinding/EyeProtection/EyeProtectionSystem.cs @@ -1,10 +1,10 @@ -using Content.Shared.Eye.Blinding; using Content.Shared.StatusEffect; using Content.Shared.Inventory; -using Content.Server.Tools; +using Content.Shared.Item; using Content.Shared.Eye.Blinding.Components; using Content.Shared.Eye.Blinding.Systems; using Content.Shared.Tools.Components; +using Content.Shared.Item.ItemToggle; namespace Content.Server.Eye.Blinding.EyeProtection { @@ -12,11 +12,13 @@ namespace Content.Server.Eye.Blinding.EyeProtection { [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; [Dependency] private readonly BlindableSystem _blindingSystem = default!; + [Dependency] private readonly SharedItemToggleSystem _itemToggle = default!; + public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnUseAttempt); - SubscribeLocalEvent(OnWelderToggled); + SubscribeLocalEvent(OnWelderToggled); SubscribeLocalEvent(OnGetProtection); SubscribeLocalEvent>(OnGetRelayedProtection); @@ -44,7 +46,7 @@ namespace Content.Server.Eye.Blinding.EyeProtection var ev = new GetEyeProtectionEvent(); RaiseLocalEvent(args.User, ev); - var time = (float) (component.StatusEffectTime- ev.Protection).TotalSeconds; + var time = (float) (component.StatusEffectTime - ev.Protection).TotalSeconds; if (time <= 0) return; @@ -55,9 +57,9 @@ namespace Content.Server.Eye.Blinding.EyeProtection _statusEffectsSystem.TryAddStatusEffect(args.User, TemporaryBlindnessSystem.BlindingStatusEffect, statusTimeSpan, false, TemporaryBlindnessSystem.BlindingStatusEffect); } - private void OnWelderToggled(EntityUid uid, RequiresEyeProtectionComponent component, WelderToggledEvent args) + private void OnWelderToggled(EntityUid uid, RequiresEyeProtectionComponent component, ItemToggleDoneEvent args) { - component.Toggled = args.WelderOn; + component.Toggled = _itemToggle.IsActivated(uid); } } } diff --git a/Content.Server/Item/ItemToggle/Components/ItemToggleDisarmMalusComponent.cs b/Content.Server/Item/ItemToggle/Components/ItemToggleDisarmMalusComponent.cs new file mode 100644 index 0000000000..923a10b22a --- /dev/null +++ b/Content.Server/Item/ItemToggle/Components/ItemToggleDisarmMalusComponent.cs @@ -0,0 +1,20 @@ +namespace Content.Server.Item; + +/// +/// Handles whether this item applies a disarm malus when active. +/// +[RegisterComponent] +public sealed partial class ItemToggleDisarmMalusComponent : Component +{ + /// + /// Item has this modifier to the chance to disarm when activated. + /// + [ViewVariables(VVAccess.ReadOnly), DataField] + public float? ActivatedDisarmMalus = null; + + /// + /// Item has this modifier to the chance to disarm when deactivated. If none is mentioned, it uses the item's default disarm modifier. + /// + [ViewVariables(VVAccess.ReadOnly), DataField] + public float? DeactivatedDisarmMalus = null; +} diff --git a/Content.Server/Item/ItemToggle/Components/ItemToggleSharpComponent.cs b/Content.Server/Item/ItemToggle/Components/ItemToggleSharpComponent.cs new file mode 100644 index 0000000000..ea2efae147 --- /dev/null +++ b/Content.Server/Item/ItemToggle/Components/ItemToggleSharpComponent.cs @@ -0,0 +1,14 @@ +namespace Content.Server.Item; + +/// +/// Handles whether this item is sharp when toggled on. +/// +[RegisterComponent] +public sealed partial class ItemToggleSharpComponent : Component +{ + /// + /// Item can be used to butcher when activated. + /// + [ViewVariables(VVAccess.ReadOnly), DataField] + public bool ActivatedSharp = true; +} diff --git a/Content.Server/Item/ItemToggle/ItemToggleSystem.cs b/Content.Server/Item/ItemToggle/ItemToggleSystem.cs new file mode 100644 index 0000000000..8a6903dd49 --- /dev/null +++ b/Content.Server/Item/ItemToggle/ItemToggleSystem.cs @@ -0,0 +1,57 @@ +using Content.Shared.Item; +using Content.Server.CombatMode.Disarm; +using Content.Server.Kitchen.Components; +using Content.Shared.Item.ItemToggle; + +namespace Content.Server.Item; + +public sealed class ItemToggleSystem : SharedItemToggleSystem +{ + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(Toggle); + } + + private void Toggle(EntityUid uid, ItemToggleComponent comp, ref ItemToggleDoneEvent args) + { + if (args.Activated == true) + { + if (TryComp(uid, out var itemSharpness)) + { + if (itemSharpness.ActivatedSharp) + EnsureComp(uid); + } + + if (!TryComp(uid, out var itemToggleDisarmMalus) || + !TryComp(uid, out var malus)) + return; + + //Default the deactivated DisarmMalus to the item's value before activation happens. + itemToggleDisarmMalus.DeactivatedDisarmMalus ??= malus.Malus; + + if (itemToggleDisarmMalus.ActivatedDisarmMalus != null) + { + malus.Malus = (float) itemToggleDisarmMalus.ActivatedDisarmMalus; + } + } + else + { + if (TryComp(uid, out var itemSharpness)) + { + if (itemSharpness.ActivatedSharp) + RemCompDeferred(uid); + } + + if (!TryComp(uid, out var itemToggleDisarmMalus) || + !TryComp(uid, out var malus)) + return; + + if (itemToggleDisarmMalus.DeactivatedDisarmMalus != null) + { + malus.Malus = (float) itemToggleDisarmMalus.DeactivatedDisarmMalus; + } + } + } +} diff --git a/Content.Server/Item/ItemToggleSystem.cs b/Content.Server/Item/ItemToggleSystem.cs deleted file mode 100644 index fb72148b88..0000000000 --- a/Content.Server/Item/ItemToggleSystem.cs +++ /dev/null @@ -1,94 +0,0 @@ -using Content.Server.CombatMode.Disarm; -using Content.Shared.Interaction; -using Content.Shared.Interaction.Events; -using Content.Shared.Item; -using Content.Shared.Toggleable; -using Content.Shared.Tools.Components; -using Robust.Shared.Audio; -using Robust.Shared.Audio.Systems; -using Robust.Shared.Player; - -namespace Content.Server.Weapons.Melee.ItemToggle; - -public sealed class ItemToggleSystem : EntitySystem -{ - [Dependency] private readonly SharedItemSystem _item = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnUseInHand); - SubscribeLocalEvent(OnInteractUsing); - SubscribeLocalEvent(TurnOff); - SubscribeLocalEvent(TurnOn); - } - - private void OnUseInHand(EntityUid uid, ItemToggleComponent comp, UseInHandEvent args) - { - if (args.Handled) - return; - - args.Handled = true; - - if (comp.Activated) - { - var ev = new ItemToggleDeactivatedEvent(); - RaiseLocalEvent(uid, ref ev); - } - else - { - var ev = new ItemToggleActivatedEvent(); - RaiseLocalEvent(uid, ref ev); - } - - UpdateAppearance(uid, comp); - } - - private void TurnOff(EntityUid uid, ItemToggleComponent comp, ref ItemToggleDeactivatedEvent args) - { - if (TryComp(uid, out ItemComponent? item)) - _item.SetSize(uid, comp.OffSize, item); - - if (TryComp(uid, out var malus)) - malus.Malus -= comp.ActivatedDisarmMalus; - - _audio.PlayEntity(comp.DeActivateSound, Filter.Pvs(uid, entityManager: EntityManager), uid, true, comp.DeActivateSound.Params); - - comp.Activated = false; - } - - private void TurnOn(EntityUid uid, ItemToggleComponent comp, ref ItemToggleActivatedEvent args) - { - if (TryComp(uid, out ItemComponent? item)) - _item.SetSize(uid, comp.OnSize, item); - - if (TryComp(uid, out var malus)) - malus.Malus += comp.ActivatedDisarmMalus; - - _audio.PlayEntity(comp.ActivateSound, Filter.Pvs(uid, entityManager: EntityManager), uid, true, comp.ActivateSound.Params); - - comp.Activated = true; - } - - private void UpdateAppearance(EntityUid uid, ItemToggleComponent component) - { - if (!TryComp(uid, out AppearanceComponent? appearanceComponent)) - return; - - _appearance.SetData(uid, ToggleableLightVisuals.Enabled, component.Activated, appearanceComponent); - } - - private void OnInteractUsing(EntityUid uid, ItemToggleComponent comp, InteractUsingEvent args) - { - if (args.Handled) - return; - - if (!TryComp(args.Used, out ToolComponent? tool) || !tool.Qualities.ContainsAny("Pulsing")) - return; - - args.Handled = true; - } -} diff --git a/Content.Server/Stunnable/Systems/StunbatonSystem.cs b/Content.Server/Stunnable/Systems/StunbatonSystem.cs index da2391a86b..2ed30d8942 100644 --- a/Content.Server/Stunnable/Systems/StunbatonSystem.cs +++ b/Content.Server/Stunnable/Systems/StunbatonSystem.cs @@ -2,45 +2,39 @@ using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Server.Power.Events; using Content.Server.Stunnable.Components; -using Content.Shared.Audio; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Damage.Events; using Content.Shared.Examine; -using Content.Shared.Interaction.Events; using Content.Shared.Item; +using Content.Shared.Item.ItemToggle; using Content.Shared.Popups; using Content.Shared.Stunnable; -using Content.Shared.Toggleable; -using Robust.Server.GameObjects; -using Robust.Shared.Audio; -using Robust.Shared.Audio.Systems; -using Robust.Shared.Player; namespace Content.Server.Stunnable.Systems { public sealed class StunbatonSystem : SharedStunbatonSystem { [Dependency] private readonly SharedItemSystem _item = default!; - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly RiggableSystem _riggableSystem = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly BatterySystem _battery = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedItemToggleSystem _itemToggle = default!; public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnUseInHand); - SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnExamined); SubscribeLocalEvent(OnSolutionChange); SubscribeLocalEvent(OnStaminaHitAttempt); + SubscribeLocalEvent(TryTurnOn); + SubscribeLocalEvent(ToggleDone); } private void OnStaminaHitAttempt(EntityUid uid, StunbatonComponent component, ref StaminaDamageOnHitAttemptEvent args) { - if (!component.Activated || - !TryComp(uid, out var battery) || !_battery.TryUseCharge(uid, component.EnergyPerUse, battery)) + if (!_itemToggle.IsActivated(uid) || + !TryComp(uid, out var battery) || !_battery.TryUseCharge(uid, component.EnergyPerUse, battery)) { args.Cancelled = true; return; @@ -48,93 +42,56 @@ namespace Content.Server.Stunnable.Systems if (battery.CurrentCharge < component.EnergyPerUse) { - _audio.PlayPvs(component.SparksSound, uid, AudioHelpers.WithVariation(0.25f)); - TurnOff(uid, component); + _itemToggle.Toggle(uid, predicted: false); } } - private void OnUseInHand(EntityUid uid, StunbatonComponent comp, UseInHandEvent args) + private void OnExamined(EntityUid uid, BatteryComponent battery, ExaminedEvent args) { - if (comp.Activated) - { - TurnOff(uid, comp); - } - else - { - TurnOn(uid, comp, args.User); - } + var onMsg = _itemToggle.IsActivated(uid) + ? Loc.GetString("comp-stunbaton-examined-on") + : Loc.GetString("comp-stunbaton-examined-off"); + args.PushMarkup(onMsg); + + var chargeMessage = Loc.GetString("stunbaton-component-on-examine-charge", + ("charge", (int) (battery.CurrentCharge / battery.MaxCharge * 100))); + args.PushMarkup(chargeMessage); } - private void OnExamined(EntityUid uid, StunbatonComponent comp, ExaminedEvent args) + private void ToggleDone(EntityUid uid, StunbatonComponent comp, ref ItemToggleDoneEvent args) { - var msg = comp.Activated - ? Loc.GetString("comp-stunbaton-examined-on") - : Loc.GetString("comp-stunbaton-examined-off"); - args.PushMarkup(msg); - if (TryComp(uid, out var battery)) - { - args.PushMarkup(Loc.GetString("stunbaton-component-on-examine-charge", - ("charge", (int)((battery.CurrentCharge/battery.MaxCharge) * 100)))); - } - } - - private void TurnOff(EntityUid uid, StunbatonComponent comp) - { - if (!comp.Activated) + if (!TryComp(uid, out var item)) return; - - if (TryComp(uid, out var appearance) && - TryComp(uid, out var item)) - { - _item.SetHeldPrefix(uid, "off", item); - _appearance.SetData(uid, ToggleVisuals.Toggled, false, appearance); - } - - _audio.PlayPvs(comp.SparksSound, uid, AudioHelpers.WithVariation(0.25f)); - - comp.Activated = false; - Dirty(uid, comp); + _item.SetHeldPrefix(uid, args.Activated ? "on" : "off", item); } - private void TurnOn(EntityUid uid, StunbatonComponent comp, EntityUid user) + private void TryTurnOn(EntityUid uid, StunbatonComponent comp, ref ItemToggleActivateAttemptEvent args) { - if (comp.Activated) - return; - if (!TryComp(uid, out var battery) || battery.CurrentCharge < comp.EnergyPerUse) { - - _audio.PlayPvs(comp.TurnOnFailSound, uid, AudioHelpers.WithVariation(0.25f)); - _popup.PopupEntity(Loc.GetString("stunbaton-component-low-charge"), user, user); + args.Cancelled = true; + if (args.User != null) + { + _popup.PopupEntity(Loc.GetString("stunbaton-component-low-charge"), (EntityUid) args.User, (EntityUid) args.User); + } return; } if (TryComp(uid, out var rig) && rig.IsRigged) { - _riggableSystem.Explode(uid, battery, user); + _riggableSystem.Explode(uid, battery, args.User); } - - - if (EntityManager.TryGetComponent(uid, out var appearance) && - EntityManager.TryGetComponent(uid, out var item)) - { - _item.SetHeldPrefix(uid, "on", item); - _appearance.SetData(uid, ToggleVisuals.Toggled, true, appearance); - } - - _audio.PlayPvs(comp.SparksSound, uid, AudioHelpers.WithVariation(0.25f)); - comp.Activated = true; - Dirty(uid, comp); } // https://github.com/space-wizards/space-station-14/pull/17288#discussion_r1241213341 private void OnSolutionChange(EntityUid uid, StunbatonComponent component, SolutionChangedEvent args) { // Explode if baton is activated and rigged. - if (!TryComp(uid, out var riggable) || !TryComp(uid, out var battery)) + if (!TryComp(uid, out var riggable) || + !TryComp(uid, out var battery)) return; - if (component.Activated && riggable.IsRigged) + if (_itemToggle.IsActivated(uid) && riggable.IsRigged) _riggableSystem.Explode(uid, battery); } diff --git a/Content.Server/Tools/Components/WelderComponent.cs b/Content.Server/Tools/Components/WelderComponent.cs index 48fbd3640a..a620fa2ef4 100644 --- a/Content.Server/Tools/Components/WelderComponent.cs +++ b/Content.Server/Tools/Components/WelderComponent.cs @@ -1,9 +1,8 @@ using Content.Shared.Chemistry.Reagent; -using Content.Shared.Damage; using Content.Shared.FixedPoint; using Content.Shared.Tools.Components; using Robust.Shared.Audio; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.Prototypes; namespace Content.Server.Tools.Components { @@ -13,56 +12,37 @@ namespace Content.Server.Tools.Components /// /// Solution on the entity that contains the fuel. /// - [DataField("fuelSolution"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public string FuelSolution { get; private set; } = "Welder"; /// /// Reagent that will be used as fuel for welding. /// - [DataField("fuelReagent", customTypeSerializer:typeof(PrototypeIdSerializer)), ViewVariables(VVAccess.ReadWrite)] - public string FuelReagent { get; private set; } = "WeldingFuel"; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public ProtoId FuelReagent { get; private set; } = "WeldingFuel"; /// - /// Fuel consumption per second, while the welder is active. + /// Fuel consumption per second while the welder is active. /// - [DataField("fuelConsumption"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public FixedPoint2 FuelConsumption { get; private set; } = FixedPoint2.New(2.0f); /// /// A fuel amount to be consumed when the welder goes from being unlit to being lit. /// - [DataField("fuelLitCost"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public FixedPoint2 FuelLitCost { get; private set; } = FixedPoint2.New(0.5f); /// - /// Sound played when the welder is turned off. + /// Sound played when refilling the welder. /// - [DataField("welderOffSounds")] - public SoundSpecifier WelderOffSounds { get; private set; } = new SoundCollectionSpecifier("WelderOff"); - - /// - /// Sound played when the tool is turned on. - /// - [DataField("welderOnSounds")] - public SoundSpecifier WelderOnSounds { get; private set; } = new SoundCollectionSpecifier("WelderOn"); - - [DataField("welderRefill")] + [DataField] public SoundSpecifier WelderRefill { get; private set; } = new SoundPathSpecifier("/Audio/Effects/refill.ogg"); - /// - /// When the welder is lit, this damage is added to the base melee weapon damage. - /// - /// - /// If this is a standard welder, this damage bonus should probably subtract the entity's standard melee weapon damage - /// and replace it all with heat damage. - /// - [DataField("litMeleeDamageBonus")] - public DamageSpecifier LitMeleeDamageBonus = new(); - /// /// Whether the item is safe to refill while lit without exploding the tank. /// - [DataField("tankSafe")] + [DataField] public bool TankSafe = false; //I have no idea what I'm doing } diff --git a/Content.Server/Tools/ToolSystem.Welder.cs b/Content.Server/Tools/ToolSystem.Welder.cs index e0dc341a16..7827cbdfc5 100644 --- a/Content.Server/Tools/ToolSystem.Welder.cs +++ b/Content.Server/Tools/ToolSystem.Welder.cs @@ -2,24 +2,21 @@ using System.Linq; using Content.Server.Chemistry.Components; using Content.Server.Tools.Components; using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Database; using Content.Shared.DoAfter; using Content.Shared.Examine; using Content.Shared.FixedPoint; using Content.Shared.Interaction; using Content.Shared.Item; -using Content.Shared.Temperature; -using Content.Shared.Toggleable; +using Content.Shared.Item.ItemToggle; using Content.Shared.Tools.Components; -using Content.Shared.Weapons.Melee.Events; -using Robust.Shared.Audio; using Robust.Shared.GameStates; namespace Content.Server.Tools { public sealed partial class ToolSystem { + [Dependency] private readonly SharedItemToggleSystem _itemToggle = default!; private readonly HashSet _activeWelders = new(); private const float WelderUpdateTimer = 1f; @@ -27,106 +24,51 @@ namespace Content.Server.Tools public void InitializeWelders() { - SubscribeLocalEvent(OnWelderStartup); - SubscribeLocalEvent(OnWelderIsHotEvent); SubscribeLocalEvent(OnWelderExamine); - SubscribeLocalEvent(OnWelderSolutionChange); - SubscribeLocalEvent(OnWelderActivate); SubscribeLocalEvent(OnWelderAfterInteract); SubscribeLocalEvent>(OnWelderToolUseAttempt); SubscribeLocalEvent(OnWelderShutdown); SubscribeLocalEvent(OnWelderGetState); - SubscribeLocalEvent(OnGetMeleeDamage); - } - - private void OnGetMeleeDamage(EntityUid uid, WelderComponent component, ref GetMeleeDamageEvent args) - { - if (component.Lit) - args.Damage += component.LitMeleeDamageBonus; + SubscribeLocalEvent(TryTurnOn); + SubscribeLocalEvent(TurnOff); } public (FixedPoint2 fuel, FixedPoint2 capacity) GetWelderFuelAndCapacity(EntityUid uid, WelderComponent? welder = null, SolutionContainerManagerComponent? solutionContainer = null) { if (!Resolve(uid, ref welder, ref solutionContainer) - || !_solutionContainerSystem.TryGetSolution(uid, welder.FuelSolution, out var fuelSolution, solutionContainer)) + || !_solutionContainer.TryGetSolution(uid, welder.FuelSolution, out var fuelSolution, solutionContainer)) return (FixedPoint2.Zero, FixedPoint2.Zero); - return (_solutionContainerSystem.GetTotalPrototypeQuantity(uid, welder.FuelReagent), fuelSolution.MaxVolume); + return (_solutionContainer.GetTotalPrototypeQuantity(uid, welder.FuelReagent), fuelSolution.MaxVolume); } - public bool TryToggleWelder(EntityUid uid, EntityUid? user, - WelderComponent? welder = null, - SolutionContainerManagerComponent? solutionContainer = null, - ItemComponent? item = null, - SharedPointLightComponent? light = null, - AppearanceComponent? appearance = null) + public void TryTurnOn(EntityUid uid, WelderComponent welder, ref ItemToggleActivateAttemptEvent args) { - // Right now, we only need the welder. - // So let's not unnecessarily resolve components - if (!Resolve(uid, ref welder)) - return false; - - return !welder.Lit - ? TryTurnWelderOn(uid, user, welder, solutionContainer, item, light, appearance) - : TryTurnWelderOff(uid, user, welder, item, light, appearance); - } - - public bool TryTurnWelderOn(EntityUid uid, EntityUid? user, - WelderComponent? welder = null, - SolutionContainerManagerComponent? solutionContainer = null, - ItemComponent? item = null, - SharedPointLightComponent? light = null, - AppearanceComponent? appearance = null, - TransformComponent? transform = null) - { - if (!Resolve(uid, ref welder, ref solutionContainer, ref transform)) - return false; - - // Optional components. - Resolve(uid, ref item, ref appearance, false); - - _light.ResolveLight(uid, ref light); - - if (!_solutionContainerSystem.TryGetSolution(uid, welder.FuelSolution, out var solution, solutionContainer)) - return false; - + if (!_solutionContainer.TryGetSolution(uid, welder.FuelSolution, out var solution) || + !TryComp(uid, out var transform)) + { + args.Cancelled = true; + return; + } var fuel = solution.GetTotalPrototypeQuantity(welder.FuelReagent); // Not enough fuel to lit welder. if (fuel == FixedPoint2.Zero || fuel < welder.FuelLitCost) { - if(user != null) - _popupSystem.PopupEntity(Loc.GetString("welder-component-no-fuel-message"), uid, user.Value); - return false; + if (args.User != null) + { + _popup.PopupEntity(Loc.GetString("welder-component-no-fuel-message"), uid, (EntityUid) args.User); + } + args.Cancelled = true; + return; } solution.RemoveReagent(welder.FuelReagent, welder.FuelLitCost); - welder.Lit = true; - // Logging - if (user != null) - _adminLogger.Add(LogType.InteractActivate, LogImpact.Low, $"{ToPrettyString(user.Value):user} toggled {ToPrettyString(uid):welder} on"); - else - _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(uid):welder} toggled on"); + _adminLogger.Add(LogType.InteractActivate, LogImpact.Low, $"{ToPrettyString(args.User):user} toggled {ToPrettyString(uid):welder} on"); - var ev = new WelderToggledEvent(true); - RaiseLocalEvent(uid, ev); - - var hotEvent = new IsHotEvent() {IsHot = true}; - RaiseLocalEvent(uid, hotEvent); - - _appearanceSystem.SetData(uid, WelderVisuals.Lit, true); - _appearanceSystem.SetData(uid, ToggleableLightVisuals.Enabled, true); - - if (light != null) - { - _light.SetEnabled(uid, true, light); - } - - _audioSystem.PlayPvs(welder.WelderOnSounds, uid, AudioParams.Default.WithVariation(0.125f).WithVolume(-5f)); - - if (transform.GridUid is {} gridUid) + if (transform.GridUid is { } gridUid) { var position = _transformSystem.GetGridOrMapTilePosition(uid, transform); _atmosphereSystem.HotspotExpose(gridUid, position, 700, 50, uid, true); @@ -135,68 +77,21 @@ namespace Content.Server.Tools Dirty(uid, welder); _activeWelders.Add(uid); - return true; } - public bool TryTurnWelderOff(EntityUid uid, EntityUid? user, - WelderComponent? welder = null, - ItemComponent? item = null, - SharedPointLightComponent? light = null, - AppearanceComponent? appearance = null) + public void TurnOff(EntityUid uid, WelderComponent welder, ref ItemToggleDeactivateAttemptEvent args) { - if (!Resolve(uid, ref welder)) - return false; - - // Optional components. - Resolve(uid, ref item, ref appearance, false); - - _light.ResolveLight(uid, ref light); - - welder.Lit = false; - // Logging - if (user != null) - _adminLogger.Add(LogType.InteractActivate, LogImpact.Low, $"{ToPrettyString(user.Value):user} toggled {ToPrettyString(uid):welder} off"); - else - _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(uid):welder} toggled off"); - - var ev = new WelderToggledEvent(false); - RaiseLocalEvent(uid, ev); - - var hotEvent = new IsHotEvent() {IsHot = false}; - RaiseLocalEvent(uid, hotEvent); - - // Layer 1 is the flame. - _appearanceSystem.SetData(uid, WelderVisuals.Lit, false); - _appearanceSystem.SetData(uid, ToggleableLightVisuals.Enabled, false); - - if (light != null) - { - _light.SetEnabled(uid, false, light); - } - - _audioSystem.PlayPvs(welder.WelderOffSounds, uid, AudioParams.Default.WithVariation(0.125f).WithVolume(-5f)); + _adminLogger.Add(LogType.InteractActivate, LogImpact.Low, $"{ToPrettyString(args.User):user} toggled {ToPrettyString(uid):welder} off"); Dirty(uid, welder); _activeWelders.Remove(uid); - return true; - } - - private void OnWelderStartup(EntityUid uid, WelderComponent welder, ComponentStartup args) - { - // TODO: Delete this shit what - Dirty(uid, welder); - } - - private void OnWelderIsHotEvent(EntityUid uid, WelderComponent welder, IsHotEvent args) - { - args.IsHot = welder.Lit; } private void OnWelderExamine(EntityUid uid, WelderComponent welder, ExaminedEvent args) { - if (welder.Lit) + if (_itemToggle.IsActivated(uid)) { args.PushMarkup(Loc.GetString("welder-component-on-examine-welder-lit-message")); } @@ -217,50 +112,34 @@ namespace Content.Server.Tools } } - private void OnWelderSolutionChange(EntityUid uid, WelderComponent welder, SolutionChangedEvent args) - { - // TODO what - // ???? - Dirty(uid, welder); - } - - private void OnWelderActivate(EntityUid uid, WelderComponent welder, ActivateInWorldEvent args) - { - args.Handled = TryToggleWelder(uid, args.User, welder); - if (args.Handled) - args.WasLogged = true; - } - private void OnWelderAfterInteract(EntityUid uid, WelderComponent welder, AfterInteractEvent args) { if (args.Handled) return; - if (args.Target is not {Valid: true} target || !args.CanReach) + if (args.Target is not { Valid: true } target || !args.CanReach) return; - // TODO: Clean up this inherited oldcode. - - if (EntityManager.TryGetComponent(target, out ReagentTankComponent? tank) + if (TryComp(target, out ReagentTankComponent? tank) && tank.TankType == ReagentTankType.Fuel - && _solutionContainerSystem.TryGetDrainableSolution(target, out var targetSolution) - && _solutionContainerSystem.TryGetSolution(uid, welder.FuelSolution, out var welderSolution)) + && _solutionContainer.TryGetDrainableSolution(target, out var targetSolution) + && _solutionContainer.TryGetSolution(uid, welder.FuelSolution, out var welderSolution)) { var trans = FixedPoint2.Min(welderSolution.AvailableVolume, targetSolution.Volume); if (trans > 0) { - var drained = _solutionContainerSystem.Drain(target, targetSolution, trans); - _solutionContainerSystem.TryAddSolution(uid, welderSolution, drained); - _audioSystem.PlayPvs(welder.WelderRefill, uid); - _popupSystem.PopupEntity(Loc.GetString("welder-component-after-interact-refueled-message"), uid, args.User); + var drained = _solutionContainer.Drain(target, targetSolution, trans); + _solutionContainer.TryAddSolution(uid, welderSolution, drained); + _audio.PlayPvs(welder.WelderRefill, uid); + _popup.PopupEntity(Loc.GetString("welder-component-after-interact-refueled-message"), uid, args.User); } else if (welderSolution.AvailableVolume <= 0) { - _popupSystem.PopupEntity(Loc.GetString("welder-component-already-full"), uid, args.User); + _popup.PopupEntity(Loc.GetString("welder-component-already-full"), uid, args.User); } else { - _popupSystem.PopupEntity(Loc.GetString("welder-component-no-fuel-in-tank", ("owner", args.Target)), uid, args.User); + _popup.PopupEntity(Loc.GetString("welder-component-no-fuel-in-tank", ("owner", args.Target)), uid, args.User); } } @@ -271,11 +150,10 @@ namespace Content.Server.Tools { var user = args.DoAfter.Args.User; - if (!welder.Lit) + if (!_itemToggle.IsActivated(uid)) { - _popupSystem.PopupEntity(Loc.GetString("welder-component-welder-not-lit-message"), uid, user); + _popup.PopupEntity(Loc.GetString("welder-component-welder-not-lit-message"), uid, user); args.Cancel(); - return; } } @@ -287,7 +165,7 @@ namespace Content.Server.Tools private void OnWelderGetState(EntityUid uid, WelderComponent welder, ref ComponentGetState args) { var (fuel, capacity) = GetWelderFuelAndCapacity(uid, welder); - args.State = new WelderComponentState(capacity.Float(), fuel.Float(), welder.Lit); + args.State = new WelderComponentState(capacity.Float(), fuel.Float()); } private void UpdateWelders(float frameTime) @@ -297,37 +175,26 @@ namespace Content.Server.Tools if (_welderTimer < WelderUpdateTimer) return; - // TODO Use an "active welder" component instead, EntityQuery over that. foreach (var tool in _activeWelders.ToArray()) { - if (!EntityManager.TryGetComponent(tool, out WelderComponent? welder) - || !EntityManager.TryGetComponent(tool, out SolutionContainerManagerComponent? solutionContainer) - || !EntityManager.TryGetComponent(tool, out TransformComponent? transform)) + if (!TryComp(tool, out WelderComponent? welder) + || !TryComp(tool, out SolutionContainerManagerComponent? solutionContainer)) continue; - if (!_solutionContainerSystem.TryGetSolution(tool, welder.FuelSolution, out var solution, solutionContainer)) + if (!_solutionContainer.TryGetSolution(tool, welder.FuelSolution, out var solution, solutionContainer)) continue; solution.RemoveReagent(welder.FuelReagent, welder.FuelConsumption * _welderTimer); if (solution.GetTotalPrototypeQuantity(welder.FuelReagent) <= FixedPoint2.Zero) - TryTurnWelderOff(tool, null, welder); + { + _itemToggle.Toggle(tool, predicted: false); + } Dirty(tool, welder); } - _welderTimer -= WelderUpdateTimer; } } - - public sealed class WelderToggledEvent : EntityEventArgs - { - public bool WelderOn; - - public WelderToggledEvent(bool welderOn) - { - WelderOn = welderOn; - } - } } diff --git a/Content.Server/Tools/ToolSystem.cs b/Content.Server/Tools/ToolSystem.cs index de6a7fefc1..7366bfce40 100644 --- a/Content.Server/Tools/ToolSystem.cs +++ b/Content.Server/Tools/ToolSystem.cs @@ -19,10 +19,10 @@ namespace Content.Server.Tools [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!; [Dependency] private readonly AppearanceSystem _appearanceSystem = default!; [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; - [Dependency] private readonly PopupSystem _popupSystem = default!; - [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + [Dependency] private readonly PopupSystem _popup = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedPointLightSystem _light = default!; - [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; + [Dependency] private readonly SolutionContainerSystem _solutionContainer = default!; [Dependency] private readonly TransformSystem _transformSystem = default!; public override void Initialize() diff --git a/Content.Server/Weapons/Melee/EnergySword/EnergySwordComponent.cs b/Content.Server/Weapons/Melee/EnergySword/EnergySwordComponent.cs index f699ef7b34..458c88af3e 100644 --- a/Content.Server/Weapons/Melee/EnergySword/EnergySwordComponent.cs +++ b/Content.Server/Weapons/Melee/EnergySword/EnergySwordComponent.cs @@ -1,44 +1,14 @@ -using Content.Shared.Damage; -using Robust.Shared.Audio; - namespace Content.Server.Weapons.Melee.EnergySword; [RegisterComponent] internal sealed partial class EnergySwordComponent : Component { - public Color BladeColor = Color.DodgerBlue; - - public bool Hacked = false; - - public bool Activated = false; - - [DataField("isSharp")] - public bool IsSharp = true; + [ViewVariables(VVAccess.ReadWrite), DataField("activatedColor"), AutoNetworkedField] + public Color ActivatedColor = Color.DodgerBlue; /// - /// Does this become hidden when deactivated + /// A color option list for the random color picker. /// - [DataField("secret")] - public bool Secret { get; set; } = false; - - /// - /// RGB cycle rate for hacked e-swords. - /// - [DataField("cycleRate")] - public float CycleRate = 1f; - - [DataField("activateSound")] - public SoundSpecifier ActivateSound { get; set; } = new SoundPathSpecifier("/Audio/Weapons/ebladeon.ogg"); - - [DataField("deActivateSound")] - public SoundSpecifier DeActivateSound { get; set; } = new SoundPathSpecifier("/Audio/Weapons/ebladeoff.ogg"); - - [DataField("onHitOn")] - public SoundSpecifier OnHitOn { get; set; } = new SoundPathSpecifier("/Audio/Weapons/eblade1.ogg"); - - [DataField("onHitOff")] - public SoundSpecifier OnHitOff { get; set; } = new SoundPathSpecifier("/Audio/Weapons/genhit1.ogg"); - [DataField("colorOptions")] public List ColorOptions = new() { @@ -49,15 +19,10 @@ internal sealed partial class EnergySwordComponent : Component Color.MediumOrchid }; - [DataField("litDamageBonus")] - public DamageSpecifier LitDamageBonus = new(); - - [DataField("litDisarmMalus")] - public float LitDisarmMalus = 0.6f; + public bool Hacked = false; + /// + /// RGB cycle rate for hacked e-swords. + /// + [DataField("cycleRate")] + public float CycleRate = 1f; } - -[ByRefEvent] -public readonly record struct EnergySwordActivatedEvent(); - -[ByRefEvent] -public readonly record struct EnergySwordDeactivatedEvent(); diff --git a/Content.Server/Weapons/Melee/EnergySword/EnergySwordSystem.cs b/Content.Server/Weapons/Melee/EnergySword/EnergySwordSystem.cs index a08ff17ec8..e8897781f5 100644 --- a/Content.Server/Weapons/Melee/EnergySword/EnergySwordSystem.cs +++ b/Content.Server/Weapons/Melee/EnergySword/EnergySwordSystem.cs @@ -1,164 +1,38 @@ -using Content.Server.CombatMode.Disarm; -using Content.Server.Kitchen.Components; using Content.Shared.Interaction; -using Content.Shared.Interaction.Events; -using Content.Shared.Item; using Content.Shared.Light; using Content.Shared.Light.Components; -using Content.Shared.Temperature; using Content.Shared.Toggleable; using Content.Shared.Tools.Components; -using Content.Shared.Weapons.Melee; -using Content.Shared.Weapons.Melee.Events; -using Content.Shared.Wieldable; -using Content.Shared.Wieldable.Components; -using Robust.Shared.Audio; -using Robust.Shared.Audio.Systems; -using Robust.Shared.Player; +using Content.Shared.Item; using Robust.Shared.Random; namespace Content.Server.Weapons.Melee.EnergySword; public sealed class EnergySwordSystem : EntitySystem { - [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly SharedRgbLightControllerSystem _rgbSystem = default!; - [Dependency] private readonly SharedItemSystem _item = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly IRobustRandom _random = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnMapInit); - SubscribeLocalEvent(OnGetMeleeDamage); - SubscribeLocalEvent(OnUseInHand); SubscribeLocalEvent(OnInteractUsing); - SubscribeLocalEvent(OnIsHotEvent); - SubscribeLocalEvent(TurnOff); - SubscribeLocalEvent(TurnOn); - - SubscribeLocalEvent(TurnOffonUnwielded); - SubscribeLocalEvent(TurnOnonWielded); } - + // Used to pick a random color for the blade on map init. private void OnMapInit(EntityUid uid, EnergySwordComponent comp, MapInitEvent args) { if (comp.ColorOptions.Count != 0) - comp.BladeColor = _random.Pick(comp.ColorOptions); - } + comp.ActivatedColor = _random.Pick(comp.ColorOptions); - private void OnGetMeleeDamage(EntityUid uid, EnergySwordComponent comp, ref GetMeleeDamageEvent args) - { - if (!comp.Activated) - return; - - // Adjusts base damage when the energy blade is active, by values set in yaml - args.Damage += comp.LitDamageBonus; - } - - private void OnUseInHand(EntityUid uid, EnergySwordComponent comp, UseInHandEvent args) - { - if (args.Handled) - return; - - args.Handled = true; - - if (TryComp(uid, out var wieldableComp)) - return; - - if (comp.Activated) - { - var ev = new EnergySwordDeactivatedEvent(); - RaiseLocalEvent(uid, ref ev); - } - else - { - var ev = new EnergySwordActivatedEvent(); - RaiseLocalEvent(uid, ref ev); - } - - UpdateAppearance(uid, comp); - } - - private void TurnOffonUnwielded(EntityUid uid, EnergySwordComponent comp, ItemUnwieldedEvent args) - { - var ev = new EnergySwordDeactivatedEvent(); - RaiseLocalEvent(uid, ref ev); - UpdateAppearance(uid, comp); - } - - private void TurnOnonWielded(EntityUid uid, EnergySwordComponent comp, ref ItemWieldedEvent args) - { - var ev = new EnergySwordActivatedEvent(); - RaiseLocalEvent(uid, ref ev); - UpdateAppearance(uid, comp); - } - - private void TurnOff(EntityUid uid, EnergySwordComponent comp, ref EnergySwordDeactivatedEvent args) - { - if (TryComp(uid, out ItemComponent? item)) - { - _item.SetSize(uid, "Small", item); - } - - if (TryComp(uid, out var malus)) - { - malus.Malus -= comp.LitDisarmMalus; - } - - if (TryComp(uid, out var weaponComp)) - { - weaponComp.HitSound = comp.OnHitOff; - if (comp.Secret) - weaponComp.Hidden = true; - } - - if (comp.IsSharp) - RemComp(uid); - - _audio.PlayEntity(comp.DeActivateSound, Filter.Pvs(uid, entityManager: EntityManager), uid, true, comp.DeActivateSound.Params); - - comp.Activated = false; - } - - private void TurnOn(EntityUid uid, EnergySwordComponent comp, ref EnergySwordActivatedEvent args) - { - if (TryComp(uid, out ItemComponent? item)) - { - _item.SetSize(uid, "Huge", item); - } - - if (comp.IsSharp) - EnsureComp(uid); - - if (TryComp(uid, out var weaponComp)) - { - weaponComp.HitSound = comp.OnHitOn; - if (comp.Secret) - weaponComp.Hidden = false; - } - - if (TryComp(uid, out var malus)) - { - malus.Malus += comp.LitDisarmMalus; - } - - _audio.PlayEntity(comp.ActivateSound, Filter.Pvs(uid, entityManager: EntityManager), uid, true, comp.ActivateSound.Params); - - comp.Activated = true; - } - - private void UpdateAppearance(EntityUid uid, EnergySwordComponent component) - { if (!TryComp(uid, out AppearanceComponent? appearanceComponent)) return; - - _appearance.SetData(uid, ToggleableLightVisuals.Enabled, component.Activated, appearanceComponent); - _appearance.SetData(uid, ToggleableLightVisuals.Color, component.BladeColor, appearanceComponent); + _appearance.SetData(uid, ToggleableLightVisuals.Color, comp.ActivatedColor, appearanceComponent); } + // Used to make the make the blade multicolored when using a multitool on it. private void OnInteractUsing(EntityUid uid, EnergySwordComponent comp, InteractUsingEvent args) { if (args.Handled) @@ -178,9 +52,4 @@ public sealed class EnergySwordSystem : EntitySystem else RemComp(uid); } - - private void OnIsHotEvent(EntityUid uid, EnergySwordComponent energySword, IsHotEvent args) - { - args.IsHot = energySword.Activated; - } } diff --git a/Content.Server/Weapons/Reflect/ReflectSystem.cs b/Content.Server/Weapons/Reflect/ReflectSystem.cs index 48dffd87e3..5c1939478e 100644 --- a/Content.Server/Weapons/Reflect/ReflectSystem.cs +++ b/Content.Server/Weapons/Reflect/ReflectSystem.cs @@ -1,5 +1,4 @@ -using Content.Server.Weapons.Melee.EnergySword; -using Content.Server.Weapons.Melee.ItemToggle; +using Content.Shared.Item; using Content.Shared.Weapons.Reflect; namespace Content.Server.Weapons.Reflect; @@ -10,33 +9,12 @@ public sealed class ReflectSystem : SharedReflectSystem { base.Initialize(); - SubscribeLocalEvent(EnableReflect); - SubscribeLocalEvent(DisableReflect); - SubscribeLocalEvent(ShieldEnableReflect); - SubscribeLocalEvent(ShieldDisableReflect); + SubscribeLocalEvent(ToggleReflect); } - private void EnableReflect(EntityUid uid, ReflectComponent comp, ref EnergySwordActivatedEvent args) + private void ToggleReflect(EntityUid uid, ReflectComponent comp, ref ItemToggleReflectUpdateEvent args) { - comp.Enabled = true; - Dirty(comp); - } - - private void DisableReflect(EntityUid uid, ReflectComponent comp, ref EnergySwordDeactivatedEvent args) - { - comp.Enabled = false; - Dirty(comp); - } - - private void ShieldEnableReflect(EntityUid uid, ReflectComponent comp, ref ItemToggleActivatedEvent args) - { - comp.Enabled = true; - Dirty(comp); - } - - private void ShieldDisableReflect(EntityUid uid, ReflectComponent comp, ref ItemToggleDeactivatedEvent args) - { - comp.Enabled = false; - Dirty(comp); + comp.Enabled = args.Activated; + Dirty(uid, comp); } } diff --git a/Content.Shared/Damage/DamageSpecifier.cs b/Content.Shared/Damage/DamageSpecifier.cs index b7181e297f..702b6fe3e9 100644 --- a/Content.Shared/Damage/DamageSpecifier.cs +++ b/Content.Shared/Damage/DamageSpecifier.cs @@ -5,6 +5,7 @@ using JetBrains.Annotations; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; using Robust.Shared.Utility; +using Robust.Shared.Serialization; namespace Content.Shared.Damage { @@ -15,7 +16,7 @@ namespace Content.Shared.Damage /// The actual damage information is stored in . This class provides /// functions to apply resistance sets and supports basic math operations to modify this dictionary. /// - [DataDefinition] + [DataDefinition, Serializable, NetSerializable] public sealed partial class DamageSpecifier : IEquatable { // These exist solely so the wiki works. Please do not touch them or use them. diff --git a/Content.Shared/Item/ItemToggle/Components/ItemToggleActiveSoundComponent.cs b/Content.Shared/Item/ItemToggle/Components/ItemToggleActiveSoundComponent.cs new file mode 100644 index 0000000000..eb992975b3 --- /dev/null +++ b/Content.Shared/Item/ItemToggle/Components/ItemToggleActiveSoundComponent.cs @@ -0,0 +1,34 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Item; + +/// +/// Handles the active sound being played continuously with some items that are activated (ie e-sword hum). +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class ItemToggleActiveSoundComponent : Component +{ + /// + /// The continuous noise this item makes when it's activated (like an e-sword's hum). This loops. + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public SoundSpecifier? ActiveSound; + + /// + /// Used when the item emits sound while active. + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public EntityUid? PlayingStream; +} + +/// +/// Raised in order to effect changes upon the ActiveSound of the entity. +/// +[ByRefEvent] +public record struct ItemToggleActiveSoundUpdateEvent(bool Activated, bool Predicted, EntityUid? User) +{ + public bool Activated = Activated; + public bool Predicted = Predicted; + public EntityUid? User = User; +} diff --git a/Content.Shared/Item/ItemToggle/Components/ItemToggleComponent.cs b/Content.Shared/Item/ItemToggle/Components/ItemToggleComponent.cs new file mode 100644 index 0000000000..6d27d9ee12 --- /dev/null +++ b/Content.Shared/Item/ItemToggle/Components/ItemToggleComponent.cs @@ -0,0 +1,126 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Item; + +/// +/// Handles generic item toggles, like a welder turning on and off, or an e-sword. +/// +/// +/// If you need extended functionality (e.g. requiring power) then add a new component and use events: +/// ItemToggleActivateAttemptEvent, ItemToggleDeactivateAttemptEvent or ItemToggleForceToggleEvent. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class ItemToggleComponent : Component +{ + /// + /// The item's toggle state. + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public bool Activated = false; + + /// + /// Whether the item's toggle can be predicted by the client. + /// + /// /// + /// If server-side systems affect the item's toggle, like charge/fuel systems, then the item is not predictable. + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public bool Predictable = true; + + /// + /// The noise this item makes when it is toggled on. + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public SoundSpecifier? SoundActivate; + + /// + /// The noise this item makes when it is toggled off. + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public SoundSpecifier? SoundDeactivate; + + /// + /// The noise this item makes when it is toggled on. + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public SoundSpecifier? SoundFailToActivate; +} + +/// +/// Raised directed on an entity when its ItemToggle is attempted to be activated. +/// +[ByRefEvent] +public record struct ItemToggleActivateAttemptEvent(EntityUid? User) +{ + public bool Cancelled = false; + public EntityUid? User = User; +} + +/// +/// Raised directed on an entity when its ItemToggle is attempted to be deactivated. +/// +[ByRefEvent] +public record struct ItemToggleDeactivateAttemptEvent(EntityUid? User) +{ + public bool Cancelled = false; + public EntityUid? User = User; +} + +/// +/// Raised directed on an entity any sort of toggle is complete. +/// +[ByRefEvent] +public record struct ItemToggleDoneEvent(bool Activated, EntityUid? User) +{ + public bool Activated = Activated; + public EntityUid? User = User; +} + +/// +/// Raised in order to play a toggle sound effect. +/// +[ByRefEvent] +public record struct ItemTogglePlayToggleSoundEvent(bool Activated, bool Predicted, EntityUid? User) +{ + public bool Activated = Activated; + public bool Predicted = Predicted; + public EntityUid? User = User; +} + +/// +/// Raised in order to play a failure to toggle sound effect. +/// +[ByRefEvent] +public record struct ItemTogglePlayFailSoundEvent(bool Predicted, EntityUid? User) +{ + public bool Predicted = Predicted; + public EntityUid? User = User; +} + +/// +/// Raised in order to effect changes upon the Light component of the entity. +/// +[ByRefEvent] +public record struct ItemToggleLightUpdateEvent(bool Activated) +{ + public bool Activated = Activated; +} + +/// +/// Raised in order to effect changes upon the Appearance component of the entity. +/// +[ByRefEvent] +public record struct ItemToggleAppearanceUpdateEvent(bool Activated) +{ + public bool Activated = Activated; +} + +/// +/// Raised in order to effect changes upon the Reflect component of the entity. +/// +[ByRefEvent] +public record struct ItemToggleReflectUpdateEvent(bool Activated) +{ + public bool Activated = Activated; +} diff --git a/Content.Shared/Item/ItemToggle/Components/ItemToggleHotComponent.cs b/Content.Shared/Item/ItemToggle/Components/ItemToggleHotComponent.cs new file mode 100644 index 0000000000..b35adfadac --- /dev/null +++ b/Content.Shared/Item/ItemToggle/Components/ItemToggleHotComponent.cs @@ -0,0 +1,16 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Item; + +/// +/// Handles whether the item is hot when toggled on. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class ItemToggleHotComponent : Component +{ + /// + /// Item becomes hot when active. + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public bool IsHotWhenActivated = true; +} diff --git a/Content.Shared/Item/ItemToggle/Components/ItemToggleMeleeWeaponComponent.cs b/Content.Shared/Item/ItemToggle/Components/ItemToggleMeleeWeaponComponent.cs new file mode 100644 index 0000000000..5e57491af0 --- /dev/null +++ b/Content.Shared/Item/ItemToggle/Components/ItemToggleMeleeWeaponComponent.cs @@ -0,0 +1,79 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Audio; +using Content.Shared.Damage; + +namespace Content.Shared.Item; + +/// +/// Handles the changes to the melee weapon component when the item is toggled. +/// +/// +/// You can change the damage, sound on hit, on swing, as well as hidden status while activated. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class ItemToggleMeleeWeaponComponent : Component +{ + /// + /// The noise this item makes when hitting something with it on. + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public SoundSpecifier? ActivatedSoundOnHit; + + /// + /// The noise this item makes when hitting something with it off. + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public SoundSpecifier? DeactivatedSoundOnHit; + + /// + /// The noise this item makes when hitting something with it on and it does no damage. + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public SoundSpecifier? ActivatedSoundOnHitNoDamage; + + /// + /// The noise this item makes when hitting something with it off and it does no damage. + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public SoundSpecifier? DeactivatedSoundOnHitNoDamage; + + /// + /// The noise this item makes when swinging at nothing while activated. + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public SoundSpecifier? ActivatedSoundOnSwing; + + /// + /// The noise this item makes when swinging at nothing while not activated. + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public SoundSpecifier? DeactivatedSoundOnSwing; + + /// + /// Damage done by this item when activated. + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public DamageSpecifier? ActivatedDamage = null; + + /// + /// Damage done by this item when deactivated. + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public DamageSpecifier? DeactivatedDamage = null; + + /// + /// Does this become hidden when deactivated + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public bool DeactivatedSecret = false; +} + +/// +/// Raised in order to effect changes upon the MeleeWeaponComponent of the entity. +/// +[ByRefEvent] +public record struct ItemToggleMeleeWeaponUpdateEvent(bool Activated) +{ + public bool Activated = Activated; +} + diff --git a/Content.Shared/Item/ItemToggle/Components/ItemToggleSizeComponent.cs b/Content.Shared/Item/ItemToggle/Components/ItemToggleSizeComponent.cs new file mode 100644 index 0000000000..f280934f1b --- /dev/null +++ b/Content.Shared/Item/ItemToggle/Components/ItemToggleSizeComponent.cs @@ -0,0 +1,35 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Item; + +/// +/// Handles the changes to the item size when toggled. +/// +/// +/// You can change the size when activated or not. By default the sizes are copied from the item. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class ItemToggleSizeComponent : Component +{ + /// + /// Item's size when activated + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public ProtoId? ActivatedSize = null; + + /// + /// Item's size when deactivated. If none is mentioned, it uses the item's default size instead. + /// + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + public ProtoId? DeactivatedSize = null; +} + +/// +/// Raised in order to effect changes upon the MeleeWeaponComponent of the entity. +/// +[ByRefEvent] +public record struct ItemToggleSizeUpdateEvent(bool Activated) +{ + public bool Activated = Activated; +} diff --git a/Content.Shared/Item/ItemToggle/SharedItemToggleSystem.cs b/Content.Shared/Item/ItemToggle/SharedItemToggleSystem.cs new file mode 100644 index 0000000000..e44d135bf2 --- /dev/null +++ b/Content.Shared/Item/ItemToggle/SharedItemToggleSystem.cs @@ -0,0 +1,293 @@ +using Content.Shared.Interaction.Events; +using Content.Shared.Toggleable; +using Content.Shared.Temperature; +using Content.Shared.Wieldable; +using Content.Shared.Wieldable.Components; +using Robust.Shared.Audio; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Prototypes; +using Robust.Shared.Network; + +namespace Content.Shared.Item.ItemToggle; +/// +/// Handles generic item toggles, like a welder turning on and off, or an e-sword. +/// +/// +/// If you need extended functionality (e.g. requiring power) then add a new component and use events. +/// +public abstract class SharedItemToggleSystem : EntitySystem +{ + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly SharedPointLightSystem _light = default!; + [Dependency] private readonly INetManager _netManager = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(TurnOffonUnwielded); + SubscribeLocalEvent(TurnOnonWielded); + SubscribeLocalEvent(OnUseInHand); + SubscribeLocalEvent(OnIsHotEvent); + SubscribeLocalEvent(UpdateActiveSound); + SubscribeLocalEvent(UpdateAppearance); + SubscribeLocalEvent(UpdateLight); + SubscribeLocalEvent(PlayToggleSound); + SubscribeLocalEvent(PlayFailToggleSound); + } + + private void OnUseInHand(EntityUid uid, ItemToggleComponent itemToggle, UseInHandEvent args) + { + if (args.Handled) + return; + + args.Handled = true; + + Toggle(uid, args.User, predicted: itemToggle.Predictable, itemToggle: itemToggle); + } + + /// + /// Used when an item is attempted to be toggled. + /// + public void Toggle(EntityUid uid, EntityUid? user = null, bool predicted = true, ItemToggleComponent? itemToggle = null) + { + if (!Resolve(uid, ref itemToggle)) + return; + + if (itemToggle.Activated) + { + TryDeactivate(uid, user, itemToggle: itemToggle, predicted: predicted); + } + else + { + TryActivate(uid, user, itemToggle: itemToggle, predicted: predicted); + } + } + + /// + /// Used when an item is attempting to be activated. It returns false if the attempt fails any reason, interrupting the activation. + /// + public bool TryActivate(EntityUid uid, EntityUid? user = null, bool predicted = true, ItemToggleComponent? itemToggle = null) + { + if (!Resolve(uid, ref itemToggle)) + return false; + + if (itemToggle.Activated) + return true; + + var attempt = new ItemToggleActivateAttemptEvent(user); + RaiseLocalEvent(uid, ref attempt); + + if (attempt.Cancelled) + { + //Raises the event to play the failure to activate noise. + var evPlayFailToggleSound = new ItemTogglePlayFailSoundEvent(Predicted: predicted, user); + RaiseLocalEvent(uid, ref evPlayFailToggleSound); + + return false; + } + // If the item's toggle is unpredictable because of something like requiring fuel or charge, then clients exit here. + // Otherwise you get stuff like an item activating client-side and then turning back off when it synchronizes with the server. + if (predicted == false && _netManager.IsClient) + return true; + + Activate(uid, itemToggle); + + var evPlayToggleSound = new ItemTogglePlayToggleSoundEvent(Activated: true, Predicted: predicted, user); + RaiseLocalEvent(uid, ref evPlayToggleSound); + + var evActiveSound = new ItemToggleActiveSoundUpdateEvent(Activated: true, Predicted: predicted, user); + RaiseLocalEvent(uid, ref evActiveSound); + + var toggleUsed = new ItemToggleDoneEvent(Activated: true, user); + RaiseLocalEvent(uid, ref toggleUsed); + + return true; + } + + /// + /// Used when an item is attempting to be deactivated. It returns false if the attempt fails any reason, interrupting the deactivation. + /// + public bool TryDeactivate(EntityUid uid, EntityUid? user = null, bool predicted = true, ItemToggleComponent? itemToggle = null) + { + if (!Resolve(uid, ref itemToggle)) + return false; + + if (!itemToggle.Activated) + return true; + + var attempt = new ItemToggleDeactivateAttemptEvent(user); + RaiseLocalEvent(uid, ref attempt); + + if (attempt.Cancelled) + { + return false; + } + + // If the item's toggle is unpredictable because of something like requiring fuel or charge, then clients exit here. + if (predicted == false && _netManager.IsClient) + return true; + + Deactivate(uid, itemToggle); + + var evPlayToggleSound = new ItemTogglePlayToggleSoundEvent(Activated: false, Predicted: predicted, user); + RaiseLocalEvent(uid, ref evPlayToggleSound); + + var evActiveSound = new ItemToggleActiveSoundUpdateEvent(Activated: false, Predicted: predicted, user); + RaiseLocalEvent(uid, ref evActiveSound); + + var toggleUsed = new ItemToggleDoneEvent(Activated: false, user); + RaiseLocalEvent(uid, ref toggleUsed); + + return true; + } + + /// + /// Used to make the actual changes to the item's components on activation. + /// + private void Activate(EntityUid uid, ItemToggleComponent itemToggle) + { + UpdateComponents(uid, itemToggle.Activated = true); + + Dirty(uid, itemToggle); + } + + /// + /// Used to make the actual changes to the item's components on deactivation. + /// + private void Deactivate(EntityUid uid, ItemToggleComponent itemToggle) + { + UpdateComponents(uid, itemToggle.Activated = false); + + Dirty(uid, itemToggle); + } + + /// + /// Used to raise events to update components on toggle. + /// + private void UpdateComponents(EntityUid uid, bool activated) + { + var evSize = new ItemToggleSizeUpdateEvent(activated); + RaiseLocalEvent(uid, ref evSize); + + var evMelee = new ItemToggleMeleeWeaponUpdateEvent(activated); + RaiseLocalEvent(uid, ref evMelee); + + var evAppearance = new ItemToggleAppearanceUpdateEvent(activated); + RaiseLocalEvent(uid, ref evAppearance); + + var evLight = new ItemToggleLightUpdateEvent(activated); + RaiseLocalEvent(uid, ref evLight); + + var evReflect = new ItemToggleReflectUpdateEvent(activated); + RaiseLocalEvent(uid, ref evReflect); + } + + /// + /// Used for items that require to be wielded in both hands to activate. For instance the dual energy sword will turn off if not wielded. + /// + private void TurnOffonUnwielded(EntityUid uid, ItemToggleComponent itemToggle, ItemUnwieldedEvent args) + { + if (itemToggle.Activated) + TryDeactivate(uid, args.User, itemToggle: itemToggle); + } + + /// + /// Wieldable items will automatically turn on when wielded. + /// + private void TurnOnonWielded(EntityUid uid, ItemToggleComponent itemToggle, ref ItemWieldedEvent args) + { + if (!itemToggle.Activated) + TryActivate(uid, itemToggle: itemToggle); + } + + public bool IsActivated(EntityUid uid, ItemToggleComponent? comp = null) + { + if (!Resolve(uid, ref comp, false)) + return true; // assume always activated if no component + + return comp.Activated; + } + + /// + /// Used to make the item hot when activated. + /// + private void OnIsHotEvent(EntityUid uid, ItemToggleHotComponent itemToggleHot, IsHotEvent args) + { + if (itemToggleHot.IsHotWhenActivated) + args.IsHot = IsActivated(uid); + } + + /// + /// Used to update item appearance. + /// + private void UpdateAppearance(EntityUid uid, AppearanceComponent appearance, ref ItemToggleAppearanceUpdateEvent args) + { + _appearance.SetData(uid, ToggleableLightVisuals.Enabled, args.Activated, appearance); + _appearance.SetData(uid, ToggleVisuals.Toggled, args.Activated, appearance); + } + + /// + /// Used to update light settings. + /// + private void UpdateLight(EntityUid uid, ItemToggleComponent comp, ref ItemToggleLightUpdateEvent args) + { + if (!_light.TryGetLight(uid, out var light)) + return; + + _light.SetEnabled(uid, args.Activated, light); + } + + /// + /// Used to update the looping active sound linked to the entity. + /// + private void UpdateActiveSound(EntityUid uid, ItemToggleActiveSoundComponent activeSound, ref ItemToggleActiveSoundUpdateEvent args) + { + if (args.Activated) + { + if (activeSound.ActiveSound != null && activeSound.PlayingStream == null) + { + if (args.Predicted) + activeSound.PlayingStream = _audio.PlayPredicted(activeSound.ActiveSound, uid, args.User, AudioParams.Default.WithLoop(true)).Value.Entity; + else + activeSound.PlayingStream = _audio.PlayPvs(activeSound.ActiveSound, uid, AudioParams.Default.WithLoop(true)).Value.Entity; + } + } + else + { + activeSound.PlayingStream = _audio.Stop(activeSound.PlayingStream); + } + } + + /// + /// Used to play a toggle sound. + /// + private void PlayToggleSound(EntityUid uid, ItemToggleComponent itemToggle, ref ItemTogglePlayToggleSoundEvent args) + { + SoundSpecifier? soundToPlay; + if (args.Activated) + soundToPlay = itemToggle.SoundActivate; + else + soundToPlay = itemToggle.SoundDeactivate; + + if (soundToPlay == null) + return; + + if (args.Predicted) + _audio.PlayPredicted(soundToPlay, uid, args.User); + else + _audio.PlayPvs(soundToPlay, uid); + } + + /// + /// Used to play a failure to toggle sound. + /// + private void PlayFailToggleSound(EntityUid uid, ItemToggleComponent itemToggle, ref ItemTogglePlayFailSoundEvent args) + { + if (args.Predicted) + _audio.PlayPredicted(itemToggle.SoundFailToActivate, uid, args.User); + else + _audio.PlayPvs(itemToggle.SoundFailToActivate, uid); + } +} diff --git a/Content.Shared/Item/ItemToggleComponent.cs b/Content.Shared/Item/ItemToggleComponent.cs deleted file mode 100644 index eb25f259ae..0000000000 --- a/Content.Shared/Item/ItemToggleComponent.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Content.Shared.Item; -using Robust.Shared.Audio; -using Robust.Shared.GameStates; -using Robust.Shared.Prototypes; - -namespace Content.Server.Weapons.Melee.ItemToggle; - -[RegisterComponent, NetworkedComponent] -public sealed partial class ItemToggleComponent : Component -{ - public bool Activated = false; - - [DataField("activateSound")] - public SoundSpecifier ActivateSound { get; set; } = default!; - - [DataField("deActivateSound")] - public SoundSpecifier DeActivateSound { get; set; } = default!; - - [ViewVariables(VVAccess.ReadWrite)] - [DataField("activatedDisarmMalus")] - public float ActivatedDisarmMalus = 0.6f; - - [ViewVariables(VVAccess.ReadWrite)] - [DataField("offSize")] - public ProtoId OffSize = "Small"; - - [ViewVariables(VVAccess.ReadWrite)] - [DataField("onSize")] - public ProtoId OnSize = "Huge"; -} - -[ByRefEvent] -public readonly record struct ItemToggleActivatedEvent(); - -[ByRefEvent] -public readonly record struct ItemToggleDeactivatedEvent(); diff --git a/Content.Shared/Item/SharedItemSystem.cs b/Content.Shared/Item/SharedItemSystem.cs index c718b21e0f..fe925c5547 100644 --- a/Content.Shared/Item/SharedItemSystem.cs +++ b/Content.Shared/Item/SharedItemSystem.cs @@ -27,6 +27,8 @@ public abstract class SharedItemSystem : EntitySystem SubscribeLocalEvent(OnHandleState); SubscribeLocalEvent(OnExamine); + + SubscribeLocalEvent(OnItemToggle); } #region Public API @@ -205,4 +207,32 @@ public abstract class SharedItemSystem : EntitySystem return adjustedShapes; } + + /// + /// Used to update the Item component on item toggle (specifically size). + /// + private void OnItemToggle(EntityUid uid, ItemToggleSizeComponent itemToggleSize, ItemToggleSizeUpdateEvent args) + { + if (!TryComp(uid, out ItemComponent? item)) + return; + + if (args.Activated) + { + if (itemToggleSize.ActivatedSize != null) + { + // Set the deactivated size to the default item's size before it gets changed. + itemToggleSize.DeactivatedSize ??= item.Size; + SetSize(uid, (ProtoId) itemToggleSize.ActivatedSize, item); + } + } + else + { + if (itemToggleSize.DeactivatedSize != null) + { + SetSize(uid, (ProtoId) itemToggleSize.DeactivatedSize, item); + } + } + + Dirty(uid, item); + } } diff --git a/Content.Shared/Stunnable/SharedStunbatonSystem.cs b/Content.Shared/Stunnable/SharedStunbatonSystem.cs index c964a9427d..28b68553b3 100644 --- a/Content.Shared/Stunnable/SharedStunbatonSystem.cs +++ b/Content.Shared/Stunnable/SharedStunbatonSystem.cs @@ -1,7 +1,3 @@ -using Content.Server.Stunnable.Components; -using Content.Shared.Damage; -using Content.Shared.Weapons.Melee.Events; - namespace Content.Shared.Stunnable; public abstract class SharedStunbatonSystem : EntitySystem @@ -9,16 +5,5 @@ public abstract class SharedStunbatonSystem : EntitySystem public override void Initialize() { base.Initialize(); - - SubscribeLocalEvent(OnGetMeleeDamage); - } - - private void OnGetMeleeDamage(EntityUid uid, StunbatonComponent component, ref GetMeleeDamageEvent args) - { - if (!component.Activated) - return; - - // Don't apply damage if it's activated; just do stamina damage. - args.Damage = new DamageSpecifier(); } } diff --git a/Content.Shared/Stunnable/StunbatonComponent.cs b/Content.Shared/Stunnable/StunbatonComponent.cs index 1cbba641be..1df009f780 100644 --- a/Content.Shared/Stunnable/StunbatonComponent.cs +++ b/Content.Shared/Stunnable/StunbatonComponent.cs @@ -9,17 +9,10 @@ namespace Content.Server.Stunnable.Components; [Access(typeof(SharedStunbatonSystem))] public sealed partial class StunbatonComponent : Component { - [DataField("activated"), ViewVariables(VVAccess.ReadWrite)] - [AutoNetworkedField] - public bool Activated = false; - [DataField("energyPerUse"), ViewVariables(VVAccess.ReadWrite)] [AutoNetworkedField] public float EnergyPerUse = 350; [DataField("sparksSound")] public SoundSpecifier SparksSound = new SoundCollectionSpecifier("sparks"); - - [DataField("turnOnFailSound")] - public SoundSpecifier TurnOnFailSound = new SoundPathSpecifier("/Audio/Machines/button.ogg"); } diff --git a/Content.Shared/Tools/Components/SharedWelderComponent.cs b/Content.Shared/Tools/Components/SharedWelderComponent.cs index 735aef88c1..78c1cde201 100644 --- a/Content.Shared/Tools/Components/SharedWelderComponent.cs +++ b/Content.Shared/Tools/Components/SharedWelderComponent.cs @@ -4,36 +4,18 @@ using Robust.Shared.Serialization; namespace Content.Shared.Tools.Components { [NetworkedComponent] - public abstract partial class SharedWelderComponent : Component - { - public bool Lit { get; set; } - } + public abstract partial class SharedWelderComponent : Component { } [NetSerializable, Serializable] public sealed class WelderComponentState : ComponentState { public float FuelCapacity { get; } public float Fuel { get; } - public bool Lit { get; } - public WelderComponentState(float fuelCapacity, float fuel, bool lit) + public WelderComponentState(float fuelCapacity, float fuel) { FuelCapacity = fuelCapacity; Fuel = fuel; - Lit = lit; } } - - [Serializable, NetSerializable] - public enum WelderVisuals : byte - { - Lit - } - - [Serializable, NetSerializable] - public enum WelderLayers : byte - { - Base, - Flame - } } diff --git a/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs b/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs index 54db0b8c67..d76d7340ff 100644 --- a/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs +++ b/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs @@ -63,8 +63,8 @@ public sealed partial class MeleeWeaponComponent : Component /// /// Base damage for this weapon. Can be modified via heavy damage or other means. /// - [DataField(required:true)] - [ViewVariables(VVAccess.ReadWrite)] + [DataField(required: true)] + [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public DamageSpecifier Damage = default!; [DataField] @@ -113,7 +113,7 @@ public sealed partial class MeleeWeaponComponent : Component /// This gets played whenever a melee attack is done. This is predicted by the client. /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("soundSwing")] + [DataField("soundSwing"), AutoNetworkedField] public SoundSpecifier SwingSound { get; set; } = new SoundPathSpecifier("/Audio/Weapons/punchmiss.ogg") { Params = AudioParams.Default.WithVolume(-3f).WithVariation(0.025f), @@ -124,14 +124,14 @@ public sealed partial class MeleeWeaponComponent : Component // If overwatch and apex do this then we probably should too. [ViewVariables(VVAccess.ReadWrite)] - [DataField("soundHit")] + [DataField("soundHit"), AutoNetworkedField] public SoundSpecifier? HitSound; /// /// Plays if no damage is done to the target entity. /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("soundNoDamage")] + [DataField("soundNoDamage"), AutoNetworkedField] public SoundSpecifier NoDamageSound { get; set; } = new SoundPathSpecifier("/Audio/Weapons/tap.ogg"); } diff --git a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs index 5eac283ef1..3505149564 100644 --- a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs +++ b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs @@ -12,6 +12,7 @@ using Content.Shared.Hands; using Content.Shared.Hands.Components; using Content.Shared.Interaction; using Content.Shared.Inventory; +using Content.Shared.Item; using Content.Shared.Physics; using Content.Shared.Popups; using Content.Shared.Weapons.Melee.Components; @@ -72,6 +73,8 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem SubscribeLocalEvent(OnGetBonusHeavyDamageModifier); SubscribeLocalEvent(OnGetBonusMeleeAttackRate); + SubscribeLocalEvent(OnItemToggle); + SubscribeAllEvent(OnHeavyAttack); SubscribeAllEvent(OnLightAttack); SubscribeAllEvent(OnDisarmAttack); @@ -849,4 +852,60 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem } public abstract void DoLunge(EntityUid user, EntityUid weapon, Angle angle, Vector2 localPos, string? animation, bool predicted = true); + + /// + /// Used to update the MeleeWeapon component on item toggle. + /// + private void OnItemToggle(EntityUid uid, ItemToggleMeleeWeaponComponent itemToggleMelee, ItemToggleMeleeWeaponUpdateEvent args) + { + if (!TryComp(uid, out MeleeWeaponComponent? meleeWeapon)) + return; + + if (args.Activated) + { + if (itemToggleMelee.ActivatedDamage != null) + { + //Setting deactivated damage to the weapon's regular value before changing it. + itemToggleMelee.DeactivatedDamage ??= meleeWeapon.Damage; + meleeWeapon.Damage = itemToggleMelee.ActivatedDamage; + } + + meleeWeapon.HitSound = itemToggleMelee.ActivatedSoundOnHit; + + if (itemToggleMelee.ActivatedSoundOnHitNoDamage != null) + { + //Setting the deactivated sound on no damage hit to the weapon's regular value before changing it. + itemToggleMelee.DeactivatedSoundOnHitNoDamage ??= meleeWeapon.NoDamageSound; + meleeWeapon.NoDamageSound = itemToggleMelee.ActivatedSoundOnHitNoDamage; + } + + if (itemToggleMelee.ActivatedSoundOnSwing != null) + { + //Setting the deactivated sound on no damage hit to the weapon's regular value before changing it. + itemToggleMelee.DeactivatedSoundOnSwing ??= meleeWeapon.SwingSound; + meleeWeapon.SwingSound = itemToggleMelee.ActivatedSoundOnSwing; + } + + if (itemToggleMelee.DeactivatedSecret) + meleeWeapon.Hidden = false; + } + else + { + if (itemToggleMelee.DeactivatedDamage != null) + meleeWeapon.Damage = itemToggleMelee.DeactivatedDamage; + + meleeWeapon.HitSound = itemToggleMelee.DeactivatedSoundOnHit; + + if (itemToggleMelee.DeactivatedSoundOnHitNoDamage != null) + meleeWeapon.NoDamageSound = itemToggleMelee.DeactivatedSoundOnHitNoDamage; + + if (itemToggleMelee.DeactivatedSoundOnSwing != null) + meleeWeapon.SwingSound = itemToggleMelee.DeactivatedSoundOnSwing; + + if (itemToggleMelee.DeactivatedSecret) + meleeWeapon.Hidden = true; + } + + Dirty(uid, meleeWeapon); + } } diff --git a/Resources/Audio/Weapons/attributions.yml b/Resources/Audio/Weapons/attributions.yml index 02b1c13d53..b29f498fee 100644 --- a/Resources/Audio/Weapons/attributions.yml +++ b/Resources/Audio/Weapons/attributions.yml @@ -33,6 +33,11 @@ copyright: "User Nimfar11 on GitHub." source: "https://github.com/Nimfar11" +- files: ["ebladehum.ogg", "eblademiss.ogg"] + license: "CC0-1.0" + copyright: "User gyzhor on freesound.org. Modified by Darkenson on github." + source: "https://freesound.org/people/gyzhor/sounds/47123/" + - files: ["dodgeball.ogg"] license: "CC-BY-SA-3.0" copyright: "Taken from tgstation" diff --git a/Resources/Audio/Weapons/ebladehum.ogg b/Resources/Audio/Weapons/ebladehum.ogg new file mode 100644 index 0000000000..aa885b14d2 Binary files /dev/null and b/Resources/Audio/Weapons/ebladehum.ogg differ diff --git a/Resources/Audio/Weapons/eblademiss.ogg b/Resources/Audio/Weapons/eblademiss.ogg new file mode 100644 index 0000000000..5ebdbaef2a Binary files /dev/null and b/Resources/Audio/Weapons/eblademiss.ogg differ diff --git a/Resources/Prototypes/Entities/Objects/Shields/shields.yml b/Resources/Prototypes/Entities/Objects/Shields/shields.yml index 4596085f34..c7fda9779a 100644 --- a/Resources/Prototypes/Entities/Objects/Shields/shields.yml +++ b/Resources/Prototypes/Entities/Objects/Shields/shields.yml @@ -1,4 +1,4 @@ -- type: entity +- type: entity name: base shield parent: BaseItem id: BaseShield @@ -316,7 +316,11 @@ state: mirror-icon - type: Item heldPrefix: mirror - - type: Blocking #Mirror shield should reflect heat/laser eventually, but be relatively weak to everything else. + - type: Reflect + reflectProb: 0.95 + reflects: + - Energy + - type: Blocking #Mirror shield reflects heat/laser, but is relatively weak to everything else. passiveBlockModifier: coefficients: Blunt: 1.2 @@ -356,12 +360,17 @@ description: Exotic energy shield, when folded, can even fit in your pocket. components: - type: ItemToggle - activatedDisarmMalus: 0.6 - activateSound: + soundActivate: path: /Audio/Weapons/ebladeon.ogg - deActivateSound: + soundDeactivate: path: /Audio/Weapons/ebladeoff.ogg - offSize: Small + - type: ItemToggleActiveSound + activeSound: + path: /Audio/Weapons/ebladehum.ogg + - type: ItemToggleSize + activatedSize: Huge + - type: ItemToggleDisarmMalus + activatedDisarmMalus: 0.6 - type: Sprite sprite: Objects/Weapons/Melee/e_shield.rsi layers: @@ -461,16 +470,18 @@ description: An advanced riot shield made of lightweight materials that collapses for easy storage. components: - type: ItemToggle - activatedDisarmMalus: 0.6 - activateSound: + soundActivate: path: /Audio/Weapons/telescopicon.ogg params: volume: -5 - deActivateSound: + soundDeactivate: path: /Audio/Weapons/telescopicoff.ogg params: volume: -5 - offSize: Small + - type: ItemToggleDisarmMalus + activatedDisarmMalus: 0.6 + - type: ItemToggleSize + activatedSize: Huge - type: Sprite sprite: Objects/Weapons/Melee/teleriot_shield.rsi layers: diff --git a/Resources/Prototypes/Entities/Objects/Tools/lighters.yml b/Resources/Prototypes/Entities/Objects/Tools/lighters.yml index a3b6b3fd6e..7d3ede8eaf 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/lighters.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/lighters.yml @@ -4,45 +4,73 @@ id: Lighter description: "A simple plastic cigarette lighter." components: - # Sloth: What is this comment ????????? - - type: RandomSprite #this has to be before sprite component for the flame to toggle right because weldercomponent behaves weird (and i dont trust myself to fix it right) - available: - - enum.WelderLayers.Base: - basic_icon_base-1: "" - - enum.WelderLayers.Base: - basic_icon_base-2: "" - - enum.WelderLayers.Base: - basic_icon_base-3: "" - - enum.WelderLayers.Base: - basic_icon_base-4: "" - - enum.WelderLayers.Base: - basic_icon_base-5: "" - - enum.WelderLayers.Base: - basic_icon_base-6: "" - - enum.WelderLayers.Base: - basic_icon_base-7: "" - - enum.WelderLayers.Base: - basic_icon_base-8: "" - - enum.WelderLayers.Base: - basic_icon_base-9: "" - - enum.WelderLayers.Base: - basic_icon_base-10: "" - - enum.WelderLayers.Base: - basic_icon_base-11: "" + - type: ItemToggle + predictable: false + soundActivate: + collection: lighterOnSounds + soundDeactivate: + collection: lighterOffSounds + - type: ItemToggleMeleeWeapon + activatedDamage: + types: + Heat: 1 + - type: ItemToggleSize + activatedSize: Small + - type: ItemToggleHot - type: Sprite sprite: Objects/Tools/lighters.rsi layers: - state: icon_map - map: ["enum.WelderLayers.Base"] - - state: lighter_flame - map: ["enum.WelderLayers.Flame"] - shader: unshaded - visible: false + - state: cheap_icon_base + map: [ "skin" ] - state: basic_icon_top + - state: lighter_flame + visible: false + shader: unshaded + map: [ "flame" ] + - type: Appearance + - type: RandomSprite + available: + - skin: + basic_icon_base-1: "" + - skin: + basic_icon_base-2: "" + - skin: + basic_icon_base-3: "" + - skin: + basic_icon_base-4: "" + - skin: + basic_icon_base-5: "" + - skin: + basic_icon_base-6: "" + - skin: + basic_icon_base-7: "" + - skin: + basic_icon_base-8: "" + - skin: + basic_icon_base-9: "" + - skin: + basic_icon_base-10: "" + - skin: + basic_icon_base-11: "" + - type: GenericVisualizer + visuals: + enum.ToggleVisuals.Toggled: + flame: + True: { visible: true } + False: { visible: false } + - type: ToggleableLightVisuals + spriteLayer: lighter_flame + inhandVisuals: + left: + - state: inhand-left-flame + shader: unshaded + right: + - state: inhand-right-flame + shader: unshaded - type: Item size: Tiny sprite: Objects/Tools/lighters.rsi - heldPrefix: off - type: ItemCooldown - type: RefillableSolution solution: Welder @@ -56,24 +84,16 @@ - type: MeleeWeapon damage: types: - Blunt: 0 #this feels hacky, but is needed for burn damage while active (i think) + Blunt: 0 - type: Welder fuelConsumption: 0.01 fuelLitCost: 0.1 - litMeleeDamageBonus: - types: - Heat: 1 tankSafe: true - welderOnSounds: - collection: lighterOnSounds - welderOffSounds: - collection: lighterOffSounds - type: PointLight enabled: false + netsync: false radius: 1.1 #smallest possible color: orange - - type: Appearance - - type: entity name: cheap lighter @@ -81,20 +101,21 @@ id: CheapLighter description: "A dangerously inexpensive plastic lighter, don't burn your thumb!" components: - - type: RandomSprite - available: - - enum.WelderLayers.Base: - cheap_icon_base: Rainbow - type: Sprite sprite: Objects/Tools/lighters.rsi layers: - state: icon_map - map: ["enum.WelderLayers.Base"] - - state: lighter_flame - map: ["enum.WelderLayers.Flame"] - shader: unshaded - visible: false + - state: cheap_icon_base + map: [ "skin" ] - state: cheap_icon_top + - state: lighter_flame + visible: false + shader: unshaded + map: [ "flame" ] + - type: RandomSprite + available: + - skin: + cheap_icon_base: Rainbow - type: SolutionContainerManager solutions: Welder: @@ -102,5 +123,3 @@ - ReagentId: WeldingFuel Quantity: 4 maxVol: 4 #uses less fuel than a welder, so this isnt as bad as it looks - - #TODO: zippos diff --git a/Resources/Prototypes/Entities/Objects/Tools/welders.yml b/Resources/Prototypes/Entities/Objects/Tools/welders.yml index caa0d4c208..ccfbca8246 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/welders.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/welders.yml @@ -11,14 +11,50 @@ sprite: Objects/Tools/welder.rsi layers: - state: icon - map: ["enum.WelderLayers.Base"] - state: welder_flame - map: ["enum.WelderLayers.Flame"] - shader: unshaded visible: false + shader: unshaded + map: ["enum.ToggleVisuals.Layer"] + - type: GenericVisualizer + visuals: + enum.ToggleVisuals.Toggled: + enum.ToggleVisuals.Layer: + True: { visible: true } + False: { visible: false } - type: Item size: Small sprite: Objects/Tools/welder.rsi + - type: ItemToggle + predictable: false + soundActivate: + collection: WelderOn + params: + variation: 0.125 + volume: -5 + soundDeactivate: + collection: WelderOff + params: + variation: 0.125 + volume: -5 + - type: ItemToggleMeleeWeapon + activatedSoundOnHit: + path: /Audio/Weapons/eblade1.ogg + params: + variation: 0.250 + volume: -10 + activatedSoundOnHitNoDamage: + path: /Audio/Weapons/eblade1.ogg + params: + variation: 0.250 + volume: -12 + activatedDamage: + types: + Heat: 8 + - type: ItemToggleSize + activatedSize: Large + - type: ItemToggleHot + - type: ItemToggleDisarmMalus + activatedDisarmMalus: 0.6 - type: ToggleableLightVisuals spriteLayer: flame inhandVisuals: @@ -48,10 +84,6 @@ collection: Welder qualities: Welding - type: Welder - litMeleeDamageBonus: - types: - Heat: 8 - Blunt: -5 - type: PointLight enabled: false radius: 1.5 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml index b2b7bfd20c..a070a55199 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml @@ -5,13 +5,39 @@ description: A very loud & dangerous sword with a beam made of pure, concentrated plasma. Cuts through unarmored targets like butter. components: - type: EnergySword - litDamageBonus: + - type: ItemToggle + soundActivate: + path: /Audio/Weapons/ebladeon.ogg + soundDeactivate: + path: /Audio/Weapons/ebladeoff.ogg + - type: ItemToggleActiveSound + activeSound: + path: /Audio/Weapons/ebladehum.ogg + - type: ItemToggleSharp + - type: ItemToggleHot + - type: ItemToggleDisarmMalus + activatedDisarmMalus: 0.6 + - type: ItemToggleSize + activatedSize: Huge + - type: ItemToggleMeleeWeapon + activatedSoundOnHit: + path: /Audio/Weapons/eblade1.ogg + params: + variation: 0.250 + activatedSoundOnHitNoDamage: + path: /Audio/Weapons/eblade1.ogg + params: + variation: 0.250 + volume: -10 + activatedSoundOnSwing: + path: /Audio/Weapons/eblademiss.ogg + params: + variation: 0.125 + activatedDamage: types: Slash: 15 Heat: 15 Structural: 20 - Blunt: -4.5 - litDisarmMalus: 0.6 - type: Sprite sprite: Objects/Weapons/Melee/e_sword.rsi layers: @@ -24,8 +50,6 @@ - type: MeleeWeapon wideAnimationRotation: -135 attackRate: 1 - soundHit: - path: /Audio/Weapons/eblade1.ogg damage: types: Blunt: 4.5 @@ -63,21 +87,33 @@ description: 'A dark ink pen.' components: - type: EnergySword - secret: true - litDamageBonus: - types: - Slash: 10 - Heat: 10 - Blunt: -1 - litDisarmMalus: 0.4 - activateSound: !type:SoundPathSpecifier + - type: ItemToggle + soundActivate: path: /Audio/Weapons/ebladeon.ogg params: volume: -6 - deActivateSound: !type:SoundPathSpecifier + soundDeactivate: path: /Audio/Weapons/ebladeoff.ogg params: volume: -6 + - type: ItemToggleMeleeWeapon + activatedSoundOnSwing: + path: /Audio/Weapons/eblademiss.ogg + params: + volume: -6 + variation: 0.250 + activatedDamage: + types: + Slash: 10 + Heat: 10 + deactivatedSecret: true + - type: ItemToggleActiveSound + activeSound: + path: /Audio/Weapons/ebladehum.ogg + params: + volume: -6 + - type: ItemToggleDisarmMalus + activatedDisarmMalus: 0.4 - type: Sprite sprite: Objects/Weapons/Melee/e_dagger.rsi layers: @@ -146,13 +182,14 @@ description: An exotic energy weapon. components: - type: EnergySword - secret: true - litDamageBonus: + - type: ItemToggleMeleeWeapon + activatedDamage: types: Slash: 10 Heat: 12 - Blunt: -1 - litDisarmMalus: 0.6 + deactivatedSecret: true + - type: ItemToggleDisarmMalus + activatedDisarmMalus: 0.6 - type: Sprite sprite: Objects/Weapons/Melee/e_cutlass.rsi layers: @@ -181,21 +218,39 @@ id: EnergySwordDouble description: Syndicate Command Interns thought that having one blade on the energy sword was not enough. This can be stored in pockets. components: - - type: Wieldable - type: EnergySword - litDamageBonus: + - type: ItemToggle + soundActivate: + path: /Audio/Weapons/ebladeon.ogg + params: + volume: 3 + soundDeactivate: + path: /Audio/Weapons/ebladeoff.ogg + params: + volume: 3 + - type: ItemToggleMeleeWeapon + activatedSoundOnSwing: + path: /Audio/Weapons/eblademiss.ogg + params: + volume: 3 + variation: 0.250 + activatedDamage: types: Slash: 12 Heat: 12 Structural: 15 - Blunt: -4.5 - litDisarmMalus: 0.7 + - type: ItemToggleActiveSound + activeSound: + path: /Audio/Weapons/ebladehum.ogg + params: + volume: 3 + - type: ItemToggleDisarmMalus + activatedDisarmMalus: 0.7 + - type: Wieldable - type: MeleeWeapon wideAnimationRotation: -135 attackRate: 1.5 angle: 100 - soundHit: - path: /Audio/Weapons/eblade1.ogg damage: types: Blunt: 4.5 @@ -212,7 +267,6 @@ size: Small sprite: Objects/Weapons/Melee/e_sword_double-inhands.rsi - type: Reflect - enabled: true reflectProb: .75 spread: 75 - type: UseDelay diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/stunprod.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/stunprod.yml index b43ea5059c..e6ecbe059f 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/stunprod.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/stunprod.yml @@ -9,6 +9,23 @@ layers: - state: stunprod_off map: [ "enum.ToggleVisuals.Layer" ] + - type: ItemToggle + soundActivate: + collection: sparks + params: + variation: 0.250 + soundDeactivate: + collection: sparks + params: + variation: 0.250 + soundFailToActivate: + path: /Audio/Machines/button.ogg + params: + variation: 0.250 + - type: ItemToggleMeleeWeapon + activatedDamage: + types: + Blunt: 0 - type: Stunbaton energyPerUse: 70 - type: MeleeWeapon @@ -37,7 +54,7 @@ - type: Appearance - type: GenericVisualizer visuals: - enum.ToggleVisuals.Toggled: + enum.ToggleVisuals.Toggled: enum.ToggleVisuals.Layer: True: {state: stunprod_on} False: {state: stunprod_off} diff --git a/Resources/Prototypes/Entities/Objects/Weapons/security.yml b/Resources/Prototypes/Entities/Objects/Weapons/security.yml index bf4a155ee4..d55a396164 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/security.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/security.yml @@ -11,6 +11,24 @@ map: [ "enum.ToggleVisuals.Layer" ] - type: Stunbaton energyPerUse: 50 + - type: ItemToggle + predictable: false + soundActivate: + collection: sparks + params: + variation: 0.250 + soundDeactivate: + collection: sparks + params: + variation: 0.250 + soundFailToActivate: + path: /Audio/Machines/button.ogg + params: + variation: 0.250 + - type: ItemToggleMeleeWeapon + activatedDamage: + types: + Blunt: 0 - type: MeleeWeapon wideAnimationRotation: -135 damage: diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/on-inhand-left.png b/Resources/Textures/Objects/Tools/lighters.rsi/inhand-left-flame.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/on-inhand-left.png rename to Resources/Textures/Objects/Tools/lighters.rsi/inhand-left-flame.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/off-inhand-left.png b/Resources/Textures/Objects/Tools/lighters.rsi/inhand-left.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/off-inhand-left.png rename to Resources/Textures/Objects/Tools/lighters.rsi/inhand-left.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/on-inhand-right.png b/Resources/Textures/Objects/Tools/lighters.rsi/inhand-right-flame.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/on-inhand-right.png rename to Resources/Textures/Objects/Tools/lighters.rsi/inhand-right-flame.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/off-inhand-right.png b/Resources/Textures/Objects/Tools/lighters.rsi/inhand-right.png similarity index 100% rename from Resources/Textures/Objects/Tools/lighters.rsi/off-inhand-right.png rename to Resources/Textures/Objects/Tools/lighters.rsi/inhand-right.png diff --git a/Resources/Textures/Objects/Tools/lighters.rsi/meta.json b/Resources/Textures/Objects/Tools/lighters.rsi/meta.json index e1c6d6e749..7617a25de9 100644 --- a/Resources/Textures/Objects/Tools/lighters.rsi/meta.json +++ b/Resources/Textures/Objects/Tools/lighters.rsi/meta.json @@ -71,19 +71,19 @@ "name": "zippo_top" }, { - "name": "off-inhand-left", + "name": "inhand-left", "directions": 4 }, { - "name": "off-inhand-right", + "name": "inhand-right", "directions": 4 }, { - "name": "on-inhand-left", + "name": "inhand-left-flame", "directions": 4 }, { - "name": "on-inhand-right", + "name": "inhand-right-flame", "directions": 4 }