From b85161a35fb01764dc18a1081fc0af96696d2c28 Mon Sep 17 00:00:00 2001 From: zumorica Date: Wed, 13 May 2020 16:53:01 +0200 Subject: [PATCH 01/29] Adds stuns --- .../Components/GUI/InventoryComponent.cs | 7 + .../Components/Mobs/DamageStates.cs | 30 ++++ .../Components/Mobs/StunnableComponent.cs | 145 ++++++++++++++++++ .../EntitySystems/ActionBlockerSystem.cs | 26 ++++ Resources/Prototypes/Entities/Mobs/human.yml | 1 + SpaceStation14.sln.DotSettings | 1 + 6 files changed, 210 insertions(+) create mode 100644 Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs diff --git a/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs b/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs index 6244af156a..db412a8467 100644 --- a/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs +++ b/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks.Dataflow; using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects; using Robust.Server.GameObjects.Components.Container; @@ -129,6 +130,9 @@ namespace Content.Server.GameObjects { var pass = false; + if (!ActionBlockerSystem.CanEquip(Owner)) + return false; + if (item is ClothingComponent clothing) { if (clothing.SlotFlags != SlotFlags.PREVENTEQUIP && (clothing.SlotFlags & SlotMasks[slot]) != 0) @@ -185,6 +189,9 @@ namespace Content.Server.GameObjects /// public bool CanUnequip(Slots slot) { + if (!ActionBlockerSystem.CanUnequip(Owner)) + return false; + var InventorySlot = SlotContainers[slot]; return InventorySlot.ContainedEntity != null && InventorySlot.CanRemove(InventorySlot.ContainedEntity); } diff --git a/Content.Server/GameObjects/Components/Mobs/DamageStates.cs b/Content.Server/GameObjects/Components/Mobs/DamageStates.cs index 515cf77e60..418afb2ce6 100644 --- a/Content.Server/GameObjects/Components/Mobs/DamageStates.cs +++ b/Content.Server/GameObjects/Components/Mobs/DamageStates.cs @@ -77,6 +77,16 @@ namespace Content.Server.GameObjects { return true; } + + bool IActionBlocker.CanEquip() + { + return true; + } + + bool IActionBlocker.CanUnequip() + { + return true; + } } /// @@ -138,6 +148,16 @@ namespace Content.Server.GameObjects { return false; } + + bool IActionBlocker.CanEquip() + { + return false; + } + + bool IActionBlocker.CanUnequip() + { + return false; + } } /// @@ -219,5 +239,15 @@ namespace Content.Server.GameObjects { return false; } + + bool IActionBlocker.CanEquip() + { + return false; + } + + bool IActionBlocker.CanUnequip() + { + return false; + } } } diff --git a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs new file mode 100644 index 0000000000..ed60cdd358 --- /dev/null +++ b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs @@ -0,0 +1,145 @@ +using System; +using System.Threading; +using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces.GameObjects; +using Content.Shared.GameObjects.Components.Mobs; +using Robust.Server.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.Timers; +using Robust.Shared.IoC; +using Robust.Shared.ViewVariables; +using Timer = Robust.Shared.Timers.Timer; + +namespace Content.Server.GameObjects.Components.Mobs +{ + [RegisterComponent] + public class StunnableComponent : Component, IActionBlocker + { + [Dependency] private ITimerManager _timerManager; + + private bool _stunned = false; + private bool _knocked = false; + + private int _stunCapMs = 20000; + private int _knockdownCapMs = 20000; + + private Timer _stunTimer; + private Timer _knockdownTimer; + + private CancellationTokenSource _stunTimerCancellation; + private CancellationTokenSource _knockdownTimerCancellation; + + public override string Name => "Stunnable"; + + [ViewVariables] public bool Stunned => _stunned; + [ViewVariables] public bool KnockedDown => _knocked; + + public void Stun(int milliseconds) + { + if (_stunTimer != null) + { + _stunTimerCancellation.Cancel(); + milliseconds += _stunTimer.Time; + } + + milliseconds = Math.Min(milliseconds, _stunCapMs); + + DropItemsInHands(); + + _stunned = true; + _stunTimerCancellation = new CancellationTokenSource(); + _stunTimer = new Timer(milliseconds, false, OnStunTimerFired); + _timerManager.AddTimer(_stunTimer, _stunTimerCancellation.Token); + } + + public override void Initialize() + { + base.Initialize(); + Timer.Spawn(10000, () => Paralyze(5000)); + } + + public void Knockdown(int milliseconds) + { + if (_knockdownTimer != null) + { + _knockdownTimerCancellation.Cancel(); + milliseconds += _knockdownTimer.Time; + } + + if (Owner.TryGetComponent(out AppearanceComponent appearance)) + { + var state = SharedSpeciesComponent.MobState.Down; + appearance.SetData(SharedSpeciesComponent.MobVisuals.RotationState, state); + } + + milliseconds = Math.Min(milliseconds, _knockdownCapMs); + + DropItemsInHands(); + + _knocked = true; + _knockdownTimerCancellation = new CancellationTokenSource(); + _knockdownTimer = new Timer(milliseconds, false, OnKnockdownTimerFired); + _timerManager.AddTimer(_knockdownTimer, _knockdownTimerCancellation.Token); + } + + private void DropItemsInHands() + { + if (!Owner.TryGetComponent(out IHandsComponent hands)) return; + + foreach (var heldItem in hands.GetAllHeldItems()) + { + hands.Drop(heldItem.Owner); + } + } + + private void OnStunTimerFired() + { + _stunned = false; + _stunTimer = null; + _stunTimerCancellation = null; + } + + private void OnKnockdownTimerFired() + { + if (Owner.TryGetComponent(out AppearanceComponent appearance)) + { + var state = SharedSpeciesComponent.MobState.Stand; + appearance.SetData(SharedSpeciesComponent.MobVisuals.RotationState, state); + } + + _knocked = false; + _knockdownTimer = null; + _knockdownTimerCancellation = null; + } + + public void Paralyze(int milliseconds) + { + Stun(milliseconds); + Knockdown(milliseconds); + } + + #region ActionBlockers + public bool CanMove() => (!Stunned); + + public bool CanInteract() => (!Stunned); + + public bool CanUse() => (!Stunned); + + public bool CanThrow() => (!Stunned); + + public bool CanSpeak() => true; + + public bool CanDrop() => (!Stunned); + + public bool CanPickup() => (!Stunned); + + public bool CanEmote() => true; + + public bool CanAttack() => (!Stunned); + + public bool CanEquip() => (!Stunned); + + public bool CanUnequip() => (!Stunned); + #endregion + } +} diff --git a/Content.Server/GameObjects/EntitySystems/ActionBlockerSystem.cs b/Content.Server/GameObjects/EntitySystems/ActionBlockerSystem.cs index 36de02bb79..e6ce5d7862 100644 --- a/Content.Server/GameObjects/EntitySystems/ActionBlockerSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/ActionBlockerSystem.cs @@ -22,6 +22,8 @@ namespace Content.Server.GameObjects.EntitySystems bool CanEmote() => true; bool CanAttack() => true; + bool CanEquip() => true; + bool CanUnequip() => true; } public class ActionBlockerSystem : EntitySystem @@ -119,5 +121,29 @@ namespace Content.Server.GameObjects.EntitySystems return canattack; } + + public static bool CanEquip(IEntity entity) + { + bool canequip = true; + + foreach (var actionblockercomponents in entity.GetAllComponents()) + { + canequip &= actionblockercomponents.CanEquip(); + } + + return canequip; + } + + public static bool CanUnequip(IEntity entity) + { + bool canunequip = true; + + foreach (var actionblockercomponents in entity.GetAllComponents()) + { + canunequip &= actionblockercomponents.CanUnequip(); + } + + return canunequip; + } } } diff --git a/Resources/Prototypes/Entities/Mobs/human.yml b/Resources/Prototypes/Entities/Mobs/human.yml index 88e23fd6c0..fdae22bac7 100644 --- a/Resources/Prototypes/Entities/Mobs/human.yml +++ b/Resources/Prototypes/Entities/Mobs/human.yml @@ -127,6 +127,7 @@ - type: FootstepSound - type: HumanoidAppearance - type: HumanInventoryController + - type: Stunnable - type: entity save: false diff --git a/SpaceStation14.sln.DotSettings b/SpaceStation14.sln.DotSettings index 7853887435..cdfdaad665 100644 --- a/SpaceStation14.sln.DotSettings +++ b/SpaceStation14.sln.DotSettings @@ -55,4 +55,5 @@ True True True + True True From 6737200117a04c37d2bdb8fd55c52b1bfaeb115d Mon Sep 17 00:00:00 2001 From: zumorica Date: Wed, 13 May 2020 19:04:29 +0200 Subject: [PATCH 02/29] Add sounds for bodyfall and thudswoosh --- Resources/Audio/effects/bodyfall1.ogg | Bin 0 -> 11905 bytes Resources/Audio/effects/bodyfall2.ogg | Bin 0 -> 11981 bytes Resources/Audio/effects/bodyfall3.ogg | Bin 0 -> 8312 bytes Resources/Audio/effects/bodyfall4.ogg | Bin 0 -> 13249 bytes Resources/Audio/effects/thudswoosh.ogg | Bin 0 -> 9123 bytes .../Prototypes/SoundCollections/body_fall.yml | 7 +++++++ 6 files changed, 7 insertions(+) create mode 100644 Resources/Audio/effects/bodyfall1.ogg create mode 100644 Resources/Audio/effects/bodyfall2.ogg create mode 100644 Resources/Audio/effects/bodyfall3.ogg create mode 100644 Resources/Audio/effects/bodyfall4.ogg create mode 100644 Resources/Audio/effects/thudswoosh.ogg create mode 100644 Resources/Prototypes/SoundCollections/body_fall.yml diff --git a/Resources/Audio/effects/bodyfall1.ogg b/Resources/Audio/effects/bodyfall1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..6a8eecefeecd45309d1896213409a18c7fd23d77 GIT binary patch literal 11905 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%0ArZf?JfxiJ>L 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 literal 0 HcmV?d00001 diff --git a/Resources/Audio/effects/bodyfall4.ogg b/Resources/Audio/effects/bodyfall4.ogg new file mode 100644 index 0000000000000000000000000000000000000000..8951e75b40b17aca1cd99898856f450422311998 GIT binary patch literal 13249 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 literal 0 HcmV?d00001 diff --git a/Resources/Audio/effects/thudswoosh.ogg b/Resources/Audio/effects/thudswoosh.ogg new file mode 100644 index 0000000000000000000000000000000000000000..934ec6350f56a82051419c443e7ef17d1b43d8f5 GIT binary patch literal 9123 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 JE;zA({{x#GoVox2 literal 0 HcmV?d00001 diff --git a/Resources/Prototypes/SoundCollections/body_fall.yml b/Resources/Prototypes/SoundCollections/body_fall.yml new file mode 100644 index 0000000000..a3338c94e4 --- /dev/null +++ b/Resources/Prototypes/SoundCollections/body_fall.yml @@ -0,0 +1,7 @@ +- type: sound_collection + id: bodyfall + files: + - /Audio/effects/bodyfall1.ogg + - /Audio/effects/bodyfall2.ogg + - /Audio/effects/bodyfall3.ogg + - /Audio/effects/bodyfall4.ogg From f968128af78ba5039405d51f22909424373c5c18 Mon Sep 17 00:00:00 2001 From: zumorica Date: Wed, 13 May 2020 19:04:50 +0200 Subject: [PATCH 03/29] StandingStateHelper, StunSystem --- .../Components/Mobs/SpeciesVisualizer2D.cs | 2 +- .../Components/Mobs/DamageStates.cs | 28 ++-- .../Components/Mobs/StunnableComponent.cs | 137 +++++++++--------- .../GameObjects/EntitySystems/StunSystem.cs | 27 ++++ Content.Server/Mobs/StandingStateHelper.cs | 81 +++++++++++ .../Components/Mobs/SharedSpeciesComponent.cs | 2 +- 6 files changed, 199 insertions(+), 78 deletions(-) create mode 100644 Content.Server/GameObjects/EntitySystems/StunSystem.cs create mode 100644 Content.Server/Mobs/StandingStateHelper.cs diff --git a/Content.Client/GameObjects/Components/Mobs/SpeciesVisualizer2D.cs b/Content.Client/GameObjects/Components/Mobs/SpeciesVisualizer2D.cs index 9c4400588d..d49f93f920 100644 --- a/Content.Client/GameObjects/Components/Mobs/SpeciesVisualizer2D.cs +++ b/Content.Client/GameObjects/Components/Mobs/SpeciesVisualizer2D.cs @@ -16,7 +16,7 @@ namespace Content.Client.GameObjects.Components.Mobs { switch (state) { - case SharedSpeciesComponent.MobState.Stand: + case SharedSpeciesComponent.MobState.Standing: sprite.Rotation = 0; break; case SharedSpeciesComponent.MobState.Down: diff --git a/Content.Server/GameObjects/Components/Mobs/DamageStates.cs b/Content.Server/GameObjects/Components/Mobs/DamageStates.cs index 418afb2ce6..73f9433436 100644 --- a/Content.Server/GameObjects/Components/Mobs/DamageStates.cs +++ b/Content.Server/GameObjects/Components/Mobs/DamageStates.cs @@ -1,8 +1,14 @@ -using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.Components.Mobs; +using Content.Server.GameObjects.EntitySystems; +using Content.Server.Mobs; +using Content.Shared.Audio; using Content.Shared.GameObjects.Components.Mobs; +using Microsoft.EntityFrameworkCore.Metadata.Builders; using Robust.Server.GameObjects; +using Robust.Server.GameObjects.EntitySystems; using Robust.Shared.GameObjects.Components; using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.IoC; namespace Content.Server.GameObjects { @@ -96,10 +102,15 @@ namespace Content.Server.GameObjects { public void EnterState(IEntity entity) { + if(entity.TryGetComponent(out StunnableComponent stun)) + stun.CancelAll(); + + StandingStateHelper.Down(entity); } public void ExitState(IEntity entity) { + StandingStateHelper.Standing(entity); } public bool IsConscious => false; @@ -167,11 +178,10 @@ namespace Content.Server.GameObjects { public void EnterState(IEntity entity) { - if (entity.TryGetComponent(out AppearanceComponent appearance)) - { - var newState = SharedSpeciesComponent.MobState.Down; - appearance.SetData(SharedSpeciesComponent.MobVisuals.RotationState, newState); - } + if(entity.TryGetComponent(out StunnableComponent stun)) + stun.CancelAll(); + + StandingStateHelper.Down(entity); if (entity.TryGetComponent(out CollidableComponent collidable)) { @@ -181,11 +191,7 @@ namespace Content.Server.GameObjects public void ExitState(IEntity entity) { - if (entity.TryGetComponent(out AppearanceComponent appearance)) - { - var newState = SharedSpeciesComponent.MobState.Stand; - appearance.SetData(SharedSpeciesComponent.MobVisuals.RotationState, newState); - } + StandingStateHelper.Standing(entity); if (entity.TryGetComponent(out CollidableComponent collidable)) { diff --git a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs index ed60cdd358..01ada4e049 100644 --- a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs @@ -2,9 +2,14 @@ using System; using System.Threading; using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces.GameObjects; +using Content.Server.Mobs; +using Content.Shared.Audio; using Content.Shared.GameObjects.Components.Mobs; using Robust.Server.GameObjects; +using Robust.Server.GameObjects.EntitySystems; +using Robust.Shared.Audio; using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Timers; using Robust.Shared.IoC; using Robust.Shared.ViewVariables; @@ -13,109 +18,111 @@ using Timer = Robust.Shared.Timers.Timer; namespace Content.Server.GameObjects.Components.Mobs { [RegisterComponent] - public class StunnableComponent : Component, IActionBlocker + public class StunnableComponent : Component, IActionBlocker, IAttackHand { + [Dependency] private IEntitySystemManager _entitySystemManager; [Dependency] private ITimerManager _timerManager; private bool _stunned = false; private bool _knocked = false; + private bool _canHelp = true; - private int _stunCapMs = 20000; - private int _knockdownCapMs = 20000; + private float _stunCap = 20f; + private float _knockdownCap = 20f; + private float _helpKnockdownRemove = 1f; + private float _helpInterval = 1f; - private Timer _stunTimer; - private Timer _knockdownTimer; - - private CancellationTokenSource _stunTimerCancellation; - private CancellationTokenSource _knockdownTimerCancellation; + private float _stunnedTimer = 0f; + private float _knockdownTimer = 0f; public override string Name => "Stunnable"; [ViewVariables] public bool Stunned => _stunned; [ViewVariables] public bool KnockedDown => _knocked; - public void Stun(int milliseconds) + public void Stun(float seconds) { - if (_stunTimer != null) - { - _stunTimerCancellation.Cancel(); - milliseconds += _stunTimer.Time; - } + seconds = Math.Min(seconds + _stunnedTimer, _stunCap); - milliseconds = Math.Min(milliseconds, _stunCapMs); - - DropItemsInHands(); + StandingStateHelper.DropAllItemsInHands(Owner); _stunned = true; - _stunTimerCancellation = new CancellationTokenSource(); - _stunTimer = new Timer(milliseconds, false, OnStunTimerFired); - _timerManager.AddTimer(_stunTimer, _stunTimerCancellation.Token); + _stunnedTimer = seconds; } public override void Initialize() { base.Initialize(); - Timer.Spawn(10000, () => Paralyze(5000)); + Timer.Spawn(10000, () => Paralyze(15f)); } - public void Knockdown(int milliseconds) + public void Knockdown(float seconds) { - if (_knockdownTimer != null) - { - _knockdownTimerCancellation.Cancel(); - milliseconds += _knockdownTimer.Time; - } + seconds = MathF.Min(_knockdownTimer + seconds, _knockdownCap); - if (Owner.TryGetComponent(out AppearanceComponent appearance)) - { - var state = SharedSpeciesComponent.MobState.Down; - appearance.SetData(SharedSpeciesComponent.MobVisuals.RotationState, state); - } - - milliseconds = Math.Min(milliseconds, _knockdownCapMs); - - DropItemsInHands(); + StandingStateHelper.Down(Owner); _knocked = true; - _knockdownTimerCancellation = new CancellationTokenSource(); - _knockdownTimer = new Timer(milliseconds, false, OnKnockdownTimerFired); - _timerManager.AddTimer(_knockdownTimer, _knockdownTimerCancellation.Token); + _knockdownTimer = seconds; } - private void DropItemsInHands() + public void Paralyze(float seconds) { - if (!Owner.TryGetComponent(out IHandsComponent hands)) return; - - foreach (var heldItem in hands.GetAllHeldItems()) - { - hands.Drop(heldItem.Owner); - } + Stun(seconds); + Knockdown(seconds); } - private void OnStunTimerFired() + /// + /// Used when + /// + public void CancelAll() { - _stunned = false; - _stunTimer = null; - _stunTimerCancellation = null; - } - - private void OnKnockdownTimerFired() - { - if (Owner.TryGetComponent(out AppearanceComponent appearance)) - { - var state = SharedSpeciesComponent.MobState.Stand; - appearance.SetData(SharedSpeciesComponent.MobVisuals.RotationState, state); - } - _knocked = false; - _knockdownTimer = null; - _knockdownTimerCancellation = null; + _stunned = false; + + _knockdownTimer = 0f; + _stunnedTimer = 0f; } - public void Paralyze(int milliseconds) + public bool AttackHand(AttackHandEventArgs eventArgs) { - Stun(milliseconds); - Knockdown(milliseconds); + if (!_canHelp || KnockedDown) + return false; + + _canHelp = false; + Timer.Spawn(((int)_helpInterval*1000), () => _canHelp = true); + + IoCManager.Resolve().GetEntitySystem() + .Play("/Audio/effects/thudswoosh.ogg", Owner, AudioHelpers.WithVariation(0.5f)); + + _knockdownTimer -= _helpKnockdownRemove; + + return true; + } + + public void Update(float delta) + { + if (_knocked) + { + _knockdownTimer -= delta; + + if (_knockdownTimer <= 0f) + { + StandingStateHelper.Standing(Owner); + + _knocked = false; + } + } + + if (_stunned) + { + _stunnedTimer -= delta; + + if (_stunnedTimer <= 0) + { + _stunned = false; + } + } } #region ActionBlockers diff --git a/Content.Server/GameObjects/EntitySystems/StunSystem.cs b/Content.Server/GameObjects/EntitySystems/StunSystem.cs new file mode 100644 index 0000000000..8f742b8092 --- /dev/null +++ b/Content.Server/GameObjects/EntitySystems/StunSystem.cs @@ -0,0 +1,27 @@ +using Content.Server.GameObjects.Components.Mobs; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Interfaces.GameObjects; + +namespace Content.Server.GameObjects.EntitySystems +{ + public class StunSystem : EntitySystem + { + public override void Initialize() + { + base.Initialize(); + + EntityQuery = new TypeEntityQuery(typeof(StunnableComponent)); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + foreach (var entity in RelevantEntities) + { + entity.GetComponent().Update(frameTime); + } + } + } +} diff --git a/Content.Server/Mobs/StandingStateHelper.cs b/Content.Server/Mobs/StandingStateHelper.cs new file mode 100644 index 0000000000..e4b0c09e52 --- /dev/null +++ b/Content.Server/Mobs/StandingStateHelper.cs @@ -0,0 +1,81 @@ +using Content.Server.Interfaces.GameObjects; +using Content.Shared.Audio; +using Content.Shared.GameObjects.Components.Mobs; +using Robust.Server.GameObjects; +using Robust.Server.GameObjects.EntitySystems; +using Robust.Shared.Audio; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Random; +using Robust.Shared.IoC; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +namespace Content.Server.Mobs +{ + public static class StandingStateHelper + { + /// + /// Set's the mob standing state to down. + /// + /// The mob in question + /// Whether to play a sound when falling down or not + /// Whether to make the mob drop all the items on his hands + /// False if the mob was already downed or couldn't set the state + public static bool Down(IEntity entity, bool playSound = true, bool dropItems = true) + { + if (!entity.TryGetComponent(out AppearanceComponent appearance)) return false; + + appearance.TryGetData(SharedSpeciesComponent.MobVisuals.RotationState, out var oldState); + + var newState = SharedSpeciesComponent.MobState.Down; + if (newState == oldState) + return false; + + appearance.SetData(SharedSpeciesComponent.MobVisuals.RotationState, newState); + + if (playSound) + PlaySoundCollection("bodyfall", AudioHelpers.WithVariation(0.5f)); + + if(dropItems) + DropAllItemsInHands(entity); + + return true; + } + + /// + /// Sets the mob's standing state to standing. + /// + /// The mob in question. + /// False if the mob was already standing or couldn't set the state + public static bool Standing(IEntity entity) + { + if (!entity.TryGetComponent(out AppearanceComponent appearance)) return false; + appearance.TryGetData(SharedSpeciesComponent.MobVisuals.RotationState, out var oldState); + var newState = SharedSpeciesComponent.MobState.Standing; + if (newState == oldState) + return false; + + appearance.SetData(SharedSpeciesComponent.MobVisuals.RotationState, newState); + + return true; + } + + public static void DropAllItemsInHands(IEntity entity) + { + if (!entity.TryGetComponent(out IHandsComponent hands)) return; + + foreach (var heldItem in hands.GetAllHeldItems()) + { + hands.Drop(heldItem.Owner); + } + } + + private static void PlaySoundCollection(string name, AudioParams parameters = default) + { + var soundCollection = IoCManager.Resolve().Index(name); + var file = IoCManager.Resolve().Pick(soundCollection.PickFiles); + IoCManager.Resolve().GetEntitySystem() + .Play(file, parameters); + } + } +} diff --git a/Content.Shared/GameObjects/Components/Mobs/SharedSpeciesComponent.cs b/Content.Shared/GameObjects/Components/Mobs/SharedSpeciesComponent.cs index 0396410c9a..eed7165fbb 100644 --- a/Content.Shared/GameObjects/Components/Mobs/SharedSpeciesComponent.cs +++ b/Content.Shared/GameObjects/Components/Mobs/SharedSpeciesComponent.cs @@ -20,7 +20,7 @@ namespace Content.Shared.GameObjects.Components.Mobs /// /// Mob is standing up /// - Stand, + Standing, /// /// Mob is laying down From c3c5b87fd571b048217e168b74cd76884dcbfbbf Mon Sep 17 00:00:00 2001 From: zumorica Date: Wed, 13 May 2020 19:10:29 +0200 Subject: [PATCH 04/29] Expose data on StunnableComponent --- .../Components/Mobs/StunnableComponent.cs | 22 +++++++++++-------- Content.Server/Mobs/StandingStateHelper.cs | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs index 01ada4e049..faf2d9f62a 100644 --- a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs @@ -12,6 +12,7 @@ using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Timers; using Robust.Shared.IoC; +using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; using Timer = Robust.Shared.Timers.Timer; @@ -30,7 +31,7 @@ namespace Content.Server.GameObjects.Components.Mobs private float _stunCap = 20f; private float _knockdownCap = 20f; private float _helpKnockdownRemove = 1f; - private float _helpInterval = 1f; + private float _helpInterval = 0.5f; private float _stunnedTimer = 0f; private float _knockdownTimer = 0f; @@ -40,6 +41,15 @@ namespace Content.Server.GameObjects.Components.Mobs [ViewVariables] public bool Stunned => _stunned; [ViewVariables] public bool KnockedDown => _knocked; + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + serializer.DataField(ref _stunCap, "stunCap", 20f); + serializer.DataField(ref _knockdownCap, "knockdownCap", 20f); + serializer.DataField(ref _helpInterval, "helpInterval", 0.5f); + serializer.DataField(ref _helpKnockdownRemove, "helpKnockdownRemove", 1f); + } + public void Stun(float seconds) { seconds = Math.Min(seconds + _stunnedTimer, _stunCap); @@ -50,12 +60,6 @@ namespace Content.Server.GameObjects.Components.Mobs _stunnedTimer = seconds; } - public override void Initialize() - { - base.Initialize(); - Timer.Spawn(10000, () => Paralyze(15f)); - } - public void Knockdown(float seconds) { seconds = MathF.Min(_knockdownTimer + seconds, _knockdownCap); @@ -86,14 +90,14 @@ namespace Content.Server.GameObjects.Components.Mobs public bool AttackHand(AttackHandEventArgs eventArgs) { - if (!_canHelp || KnockedDown) + if (!_canHelp || !KnockedDown) return false; _canHelp = false; Timer.Spawn(((int)_helpInterval*1000), () => _canHelp = true); IoCManager.Resolve().GetEntitySystem() - .Play("/Audio/effects/thudswoosh.ogg", Owner, AudioHelpers.WithVariation(0.5f)); + .Play("/Audio/effects/thudswoosh.ogg", Owner, AudioHelpers.WithVariation(0.25f)); _knockdownTimer -= _helpKnockdownRemove; diff --git a/Content.Server/Mobs/StandingStateHelper.cs b/Content.Server/Mobs/StandingStateHelper.cs index e4b0c09e52..741b2e43da 100644 --- a/Content.Server/Mobs/StandingStateHelper.cs +++ b/Content.Server/Mobs/StandingStateHelper.cs @@ -34,7 +34,7 @@ namespace Content.Server.Mobs appearance.SetData(SharedSpeciesComponent.MobVisuals.RotationState, newState); if (playSound) - PlaySoundCollection("bodyfall", AudioHelpers.WithVariation(0.5f)); + PlaySoundCollection("bodyfall", AudioHelpers.WithVariation(0.25f)); if(dropItems) DropAllItemsInHands(entity); From a524eca44b392344c5b7471f6d7014cb1014d20e Mon Sep 17 00:00:00 2001 From: zumorica Date: Wed, 13 May 2020 19:26:39 +0200 Subject: [PATCH 05/29] Action blocker for changing direction --- .../GameObjects/Components/Mobs/DamageStates.cs | 15 +++++++++++++++ .../Components/Mobs/StunnableComponent.cs | 1 + .../EntitySystems/ActionBlockerSystem.cs | 13 +++++++++++++ .../EntitySystems/Click/InteractionSystem.cs | 5 +++-- 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Content.Server/GameObjects/Components/Mobs/DamageStates.cs b/Content.Server/GameObjects/Components/Mobs/DamageStates.cs index 73f9433436..1134a65539 100644 --- a/Content.Server/GameObjects/Components/Mobs/DamageStates.cs +++ b/Content.Server/GameObjects/Components/Mobs/DamageStates.cs @@ -93,6 +93,11 @@ namespace Content.Server.GameObjects { return true; } + + bool IActionBlocker.CanChangeDirection() + { + return true; + } } /// @@ -169,6 +174,11 @@ namespace Content.Server.GameObjects { return false; } + + bool IActionBlocker.CanChangeDirection() + { + return true; + } } /// @@ -255,5 +265,10 @@ namespace Content.Server.GameObjects { return false; } + + bool IActionBlocker.CanChangeDirection() + { + return false; + } } } diff --git a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs index faf2d9f62a..7e654e6241 100644 --- a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs @@ -151,6 +151,7 @@ namespace Content.Server.GameObjects.Components.Mobs public bool CanEquip() => (!Stunned); public bool CanUnequip() => (!Stunned); + public bool CanChangeDirection() => true; #endregion } } diff --git a/Content.Server/GameObjects/EntitySystems/ActionBlockerSystem.cs b/Content.Server/GameObjects/EntitySystems/ActionBlockerSystem.cs index e6ce5d7862..90bb573228 100644 --- a/Content.Server/GameObjects/EntitySystems/ActionBlockerSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/ActionBlockerSystem.cs @@ -24,6 +24,7 @@ namespace Content.Server.GameObjects.EntitySystems bool CanAttack() => true; bool CanEquip() => true; bool CanUnequip() => true; + bool CanChangeDirection() => true; } public class ActionBlockerSystem : EntitySystem @@ -145,5 +146,17 @@ namespace Content.Server.GameObjects.EntitySystems return canunequip; } + + public static bool CanChangeDirection(IEntity entity) + { + bool canchangedirection = true; + + foreach (var actionblockercomponents in entity.GetAllComponents()) + { + canchangedirection &= actionblockercomponents.CanChangeDirection(); + } + + return canchangedirection; + } } } diff --git a/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs b/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs index 1dcf645020..c5deb92514 100644 --- a/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs @@ -451,13 +451,14 @@ namespace Content.Server.GameObjects.EntitySystems var item = hands.GetActiveHand?.Owner; + if(ActionBlockerSystem.CanChangeDirection(player)) + playerTransform.LocalRotation = new Angle(coordinates.ToMapPos(_mapManager) - playerTransform.MapPosition.Position); + if (!ActionBlockerSystem.CanInteract(player)) { return; } - playerTransform.LocalRotation = new Angle(coordinates.ToMapPos(_mapManager) - playerTransform.MapPosition.Position); - // TODO: Check if client should be able to see that object to click on it in the first place // Clicked on empty space behavior, try using ranged attack From 6428cdd596938bfa3fb42458a74dcf6697fffe6f Mon Sep 17 00:00:00 2001 From: zumorica Date: Wed, 13 May 2020 20:21:03 +0200 Subject: [PATCH 06/29] Adds stunbaton --- .../Components/Mobs/DamageStates.cs | 2 +- .../Components/Mobs/StunnableComponent.cs | 4 +-- .../Weapon/Melee/MeleeWeaponComponent.cs | 6 ++++ .../Weapon/Melee/StunbatonComponent.cs | 32 +++++++++++++++++++ .../Entities/Items/Weapons/security.yml | 24 ++++++++++++++ 5 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs create mode 100644 Resources/Prototypes/Entities/Items/Weapons/security.yml diff --git a/Content.Server/GameObjects/Components/Mobs/DamageStates.cs b/Content.Server/GameObjects/Components/Mobs/DamageStates.cs index 1134a65539..74ce8cf13e 100644 --- a/Content.Server/GameObjects/Components/Mobs/DamageStates.cs +++ b/Content.Server/GameObjects/Components/Mobs/DamageStates.cs @@ -191,7 +191,7 @@ namespace Content.Server.GameObjects if(entity.TryGetComponent(out StunnableComponent stun)) stun.CancelAll(); - StandingStateHelper.Down(entity); + StandingStateHelper.Down(entity, playSound:false); if (entity.TryGetComponent(out CollidableComponent collidable)) { diff --git a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs index 7e654e6241..d5d64aa8e8 100644 --- a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs @@ -31,7 +31,7 @@ namespace Content.Server.GameObjects.Components.Mobs private float _stunCap = 20f; private float _knockdownCap = 20f; private float _helpKnockdownRemove = 1f; - private float _helpInterval = 0.5f; + private float _helpInterval = 1f; private float _stunnedTimer = 0f; private float _knockdownTimer = 0f; @@ -46,7 +46,7 @@ namespace Content.Server.GameObjects.Components.Mobs base.ExposeData(serializer); serializer.DataField(ref _stunCap, "stunCap", 20f); serializer.DataField(ref _knockdownCap, "knockdownCap", 20f); - serializer.DataField(ref _helpInterval, "helpInterval", 0.5f); + serializer.DataField(ref _helpInterval, "helpInterval", 1f); serializer.DataField(ref _helpKnockdownRemove, "helpKnockdownRemove", 1f); } diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs index 32c9f4c127..5e399f2aa7 100644 --- a/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs @@ -75,6 +75,10 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee serializer.DataField(ref _cooldownTime, "cooldownTime", 1f); } + public virtual void OnHitEntities(IEnumerable entities) + { + } + void IAttack.Attack(AttackEventArgs eventArgs) { var curTime = IoCManager.Resolve().CurTime; @@ -101,6 +105,8 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee } } + OnHitEntities(hitEntities); + var audioSystem = _entitySystemManager.GetEntitySystem(); var emitter = hitEntities.Count == 0 ? eventArgs.User : hitEntities[0]; audioSystem.Play(hitEntities.Count > 0 ? _hitSound : "/Audio/weapons/punchmiss.ogg", emitter); diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs new file mode 100644 index 0000000000..e03a2172c8 --- /dev/null +++ b/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using Content.Server.GameObjects.Components.Mobs; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Serialization; + +namespace Content.Server.GameObjects.Components.Weapon.Melee +{ + [RegisterComponent] + public class StunbatonComponent : MeleeWeaponComponent + { + public override string Name => "Stunbaton"; + + private float _paralyzeTime = 10f; + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + + serializer.DataField(ref _paralyzeTime, "paralyzeTime", 10f); + } + + public override void OnHitEntities(IEnumerable entities) + { + foreach (var entity in entities) + { + if(entity.TryGetComponent(out StunnableComponent stunnable)) + stunnable.Paralyze(_paralyzeTime); + } + } + } +} diff --git a/Resources/Prototypes/Entities/Items/Weapons/security.yml b/Resources/Prototypes/Entities/Items/Weapons/security.yml new file mode 100644 index 0000000000..cb0ccd7b73 --- /dev/null +++ b/Resources/Prototypes/Entities/Items/Weapons/security.yml @@ -0,0 +1,24 @@ +- type: entity + name: Stun baton + parent: BaseItem + id: Stunbaton + components: + - type: Sprite + sprite: Objects/Melee/spear.rsi + state: spear + + - type: Icon + sprite: Objects/Melee/spear.rsi + state: spear + + - type: Stunbaton + range: 1.5 + arcwidth: 0 + arc: default + + - type: Item + Size: 24 + sprite: Objects/Melee/spear.rsi + prefix: inhand + + - type: ItemCooldown From 4e843358bd60f7b1de8dc9c7fa3909a22c8077a7 Mon Sep 17 00:00:00 2001 From: zumorica Date: Wed, 13 May 2020 22:13:22 +0200 Subject: [PATCH 07/29] Remove useless bools --- .../Components/Mobs/StunnableComponent.cs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs index d5d64aa8e8..be7dcd7590 100644 --- a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs @@ -24,8 +24,6 @@ namespace Content.Server.GameObjects.Components.Mobs [Dependency] private IEntitySystemManager _entitySystemManager; [Dependency] private ITimerManager _timerManager; - private bool _stunned = false; - private bool _knocked = false; private bool _canHelp = true; private float _stunCap = 20f; @@ -38,8 +36,8 @@ namespace Content.Server.GameObjects.Components.Mobs public override string Name => "Stunnable"; - [ViewVariables] public bool Stunned => _stunned; - [ViewVariables] public bool KnockedDown => _knocked; + [ViewVariables] public bool Stunned => _stunnedTimer > 0f; + [ViewVariables] public bool KnockedDown => _knockdownTimer > 0f; public override void ExposeData(ObjectSerializer serializer) { @@ -56,7 +54,6 @@ namespace Content.Server.GameObjects.Components.Mobs StandingStateHelper.DropAllItemsInHands(Owner); - _stunned = true; _stunnedTimer = seconds; } @@ -66,7 +63,6 @@ namespace Content.Server.GameObjects.Components.Mobs StandingStateHelper.Down(Owner); - _knocked = true; _knockdownTimer = seconds; } @@ -81,9 +77,6 @@ namespace Content.Server.GameObjects.Components.Mobs /// public void CancelAll() { - _knocked = false; - _stunned = false; - _knockdownTimer = 0f; _stunnedTimer = 0f; } @@ -106,7 +99,7 @@ namespace Content.Server.GameObjects.Components.Mobs public void Update(float delta) { - if (_knocked) + if (KnockedDown) { _knockdownTimer -= delta; @@ -114,17 +107,17 @@ namespace Content.Server.GameObjects.Components.Mobs { StandingStateHelper.Standing(Owner); - _knocked = false; + _knockdownTimer = 0f; } } - if (_stunned) + if (Stunned) { _stunnedTimer -= delta; if (_stunnedTimer <= 0) { - _stunned = false; + _stunnedTimer = 0f; } } } From 390127924b1c867517d875efccde88f0d1b0c148 Mon Sep 17 00:00:00 2001 From: zumorica Date: Wed, 13 May 2020 22:35:23 +0200 Subject: [PATCH 08/29] Add slowdown stun --- .../Components/Mobs/StunnableComponent.cs | 57 +++++++++++++++++-- 1 file changed, 52 insertions(+), 5 deletions(-) diff --git a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs index be7dcd7590..5e6b6d95fe 100644 --- a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs @@ -1,5 +1,6 @@ using System; using System.Threading; +using Content.Server.GameObjects.Components.Movement; using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces.GameObjects; using Content.Server.Mobs; @@ -19,7 +20,7 @@ using Timer = Robust.Shared.Timers.Timer; namespace Content.Server.GameObjects.Components.Mobs { [RegisterComponent] - public class StunnableComponent : Component, IActionBlocker, IAttackHand + public class StunnableComponent : Component, IActionBlocker, IAttackHand, IMoveSpeedModifier { [Dependency] private IEntitySystemManager _entitySystemManager; [Dependency] private ITimerManager _timerManager; @@ -28,22 +29,39 @@ namespace Content.Server.GameObjects.Components.Mobs private float _stunCap = 20f; private float _knockdownCap = 20f; + private float _slowdownCap = 20f; private float _helpKnockdownRemove = 1f; private float _helpInterval = 1f; private float _stunnedTimer = 0f; private float _knockdownTimer = 0f; + private float _slowdownTimer = 0f; + + private float _walkModifierOverride = 0f; + private float _runModifierOverride = 0f; public override string Name => "Stunnable"; [ViewVariables] public bool Stunned => _stunnedTimer > 0f; [ViewVariables] public bool KnockedDown => _knockdownTimer > 0f; + [ViewVariables] public bool SlowedDown => _slowdownTimer > 0f; + [ViewVariables] public float StunCap => _stunCap; + [ViewVariables] public float KnockdownCap => _knockdownCap; + [ViewVariables] public float SlowdownCap => _slowdownCap; + + public override void Initialize() + { + base.Initialize(); + + Timer.Spawn(1000, () => Slowdown(20f)); + } public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); serializer.DataField(ref _stunCap, "stunCap", 20f); serializer.DataField(ref _knockdownCap, "knockdownCap", 20f); + serializer.DataField(ref _slowdownCap, "slowdownCap", 20f); serializer.DataField(ref _helpInterval, "helpInterval", 1f); serializer.DataField(ref _helpKnockdownRemove, "helpKnockdownRemove", 1f); } @@ -72,6 +90,19 @@ namespace Content.Server.GameObjects.Components.Mobs Knockdown(seconds); } + public void Slowdown(float seconds, float walkModifierOverride = 0f, float runModifierOverride = 0f) + { + seconds = MathF.Min(_slowdownTimer + seconds, _slowdownCap); + + _walkModifierOverride = walkModifierOverride; + _runModifierOverride = runModifierOverride; + + _slowdownTimer = seconds; + + if(Owner.TryGetComponent(out MovementSpeedModifierComponent movement)) + movement.RefreshMovementSpeedModifiers(); + } + /// /// Used when /// @@ -99,6 +130,16 @@ namespace Content.Server.GameObjects.Components.Mobs public void Update(float delta) { + if (Stunned) + { + _stunnedTimer -= delta; + + if (_stunnedTimer <= 0) + { + _stunnedTimer = 0f; + } + } + if (KnockedDown) { _knockdownTimer -= delta; @@ -111,13 +152,16 @@ namespace Content.Server.GameObjects.Components.Mobs } } - if (Stunned) + if (SlowedDown) { - _stunnedTimer -= delta; + _slowdownTimer -= delta; - if (_stunnedTimer <= 0) + if (_slowdownTimer <= 0f) { - _stunnedTimer = 0f; + _slowdownTimer = 0f; + + if(Owner.TryGetComponent(out MovementSpeedModifierComponent movement)) + movement.RefreshMovementSpeedModifiers(); } } } @@ -146,5 +190,8 @@ namespace Content.Server.GameObjects.Components.Mobs public bool CanUnequip() => (!Stunned); public bool CanChangeDirection() => true; #endregion + + public float WalkSpeedModifier => (SlowedDown ? (_walkModifierOverride <= 0f ? 0.5f : _walkModifierOverride) : 1f); + public float SprintSpeedModifier => (SlowedDown ? (_runModifierOverride <= 0f ? 0.5f : _runModifierOverride) : 1f); } } From 567c0a1312de78a93141db3bfb297721344c7c0e Mon Sep 17 00:00:00 2001 From: zumorica Date: Thu, 14 May 2020 13:34:45 +0200 Subject: [PATCH 09/29] Animation for when mobs fall/stand --- .../Components/Mobs/SpeciesVisualizer2D.cs | 43 +++++++++++++++++-- Resources/Prototypes/Entities/Mobs/human.yml | 1 + 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/Content.Client/GameObjects/Components/Mobs/SpeciesVisualizer2D.cs b/Content.Client/GameObjects/Components/Mobs/SpeciesVisualizer2D.cs index d49f93f920..1f80e7cbc6 100644 --- a/Content.Client/GameObjects/Components/Mobs/SpeciesVisualizer2D.cs +++ b/Content.Client/GameObjects/Components/Mobs/SpeciesVisualizer2D.cs @@ -1,6 +1,10 @@ -using Content.Shared.GameObjects.Components.Mobs; +using System; +using Content.Shared.GameObjects.Components.Mobs; +using Robust.Client.Animations; using Robust.Client.GameObjects; +using Robust.Client.GameObjects.Components.Animations; using Robust.Client.Interfaces.GameObjects.Components; +using Robust.Shared.Animations; using Robust.Shared.Maths; namespace Content.Client.GameObjects.Components.Mobs @@ -11,19 +15,50 @@ namespace Content.Client.GameObjects.Components.Mobs { base.OnChangeData(component); - var sprite = component.Owner.GetComponent(); if (component.TryGetData(SharedSpeciesComponent.MobVisuals.RotationState, out var state)) { switch (state) { case SharedSpeciesComponent.MobState.Standing: - sprite.Rotation = 0; + SetRotation(component, 0); break; case SharedSpeciesComponent.MobState.Down: - sprite.Rotation = Angle.FromDegrees(90); + SetRotation(component, Angle.FromDegrees(90)); break; } } } + + public void SetRotation(AppearanceComponent component, Angle rotation) + { + var sprite = component.Owner.GetComponent(); + + if (!sprite.Owner.TryGetComponent(out AnimationPlayerComponent animation)) + { + sprite.Rotation = rotation; + return; + } + + animation.Stop("rotate"); + + animation.Play(new Animation + { + Length = TimeSpan.FromSeconds(0.125), + AnimationTracks = + { + new AnimationTrackComponentProperty + { + ComponentType = typeof(ISpriteComponent), + Property = nameof(ISpriteComponent.Rotation), + InterpolationMode = AnimationInterpolationMode.Linear, + KeyFrames = + { + new AnimationTrackProperty.KeyFrame(sprite.Rotation, 0), + new AnimationTrackProperty.KeyFrame(rotation, 0.125f) + } + } + } + }, "rotate"); + } } } diff --git a/Resources/Prototypes/Entities/Mobs/human.yml b/Resources/Prototypes/Entities/Mobs/human.yml index fdae22bac7..0d251b7c2b 100644 --- a/Resources/Prototypes/Entities/Mobs/human.yml +++ b/Resources/Prototypes/Entities/Mobs/human.yml @@ -128,6 +128,7 @@ - type: HumanoidAppearance - type: HumanInventoryController - type: Stunnable + - type: AnimationPlayer - type: entity save: false From 8668c78f43cd18d2c675f51febca2a2a52f3d0d2 Mon Sep 17 00:00:00 2001 From: zumorica Date: Thu, 14 May 2020 15:38:17 +0200 Subject: [PATCH 10/29] Stun baton sprites --- .../Entities/Items/Weapons/security.yml | 16 +- .../Objects/Melee/stunbaton.rsi/meta.json | 143 ++++++++++++++++++ .../Melee/stunbaton.rsi/off-inhand-left.png | Bin 0 -> 259 bytes .../Melee/stunbaton.rsi/off-inhand-right.png | Bin 0 -> 261 bytes .../Melee/stunbaton.rsi/on-inhand-left.png | Bin 0 -> 807 bytes .../Melee/stunbaton.rsi/on-inhand-right.png | Bin 0 -> 789 bytes .../Melee/stunbaton.rsi/stunbaton_nocell.png | Bin 0 -> 431 bytes .../Melee/stunbaton.rsi/stunbaton_off.png | Bin 0 -> 362 bytes .../Melee/stunbaton.rsi/stunbaton_on.png | Bin 0 -> 1091 bytes 9 files changed, 151 insertions(+), 8 deletions(-) create mode 100644 Resources/Textures/Objects/Melee/stunbaton.rsi/meta.json create mode 100644 Resources/Textures/Objects/Melee/stunbaton.rsi/off-inhand-left.png create mode 100644 Resources/Textures/Objects/Melee/stunbaton.rsi/off-inhand-right.png create mode 100644 Resources/Textures/Objects/Melee/stunbaton.rsi/on-inhand-left.png create mode 100644 Resources/Textures/Objects/Melee/stunbaton.rsi/on-inhand-right.png create mode 100644 Resources/Textures/Objects/Melee/stunbaton.rsi/stunbaton_nocell.png create mode 100644 Resources/Textures/Objects/Melee/stunbaton.rsi/stunbaton_off.png create mode 100644 Resources/Textures/Objects/Melee/stunbaton.rsi/stunbaton_on.png diff --git a/Resources/Prototypes/Entities/Items/Weapons/security.yml b/Resources/Prototypes/Entities/Items/Weapons/security.yml index cb0ccd7b73..4183ba8f4e 100644 --- a/Resources/Prototypes/Entities/Items/Weapons/security.yml +++ b/Resources/Prototypes/Entities/Items/Weapons/security.yml @@ -4,21 +4,21 @@ id: Stunbaton components: - type: Sprite - sprite: Objects/Melee/spear.rsi - state: spear + sprite: Objects/Melee/stunbaton.rsi + state: stunbaton_off - type: Icon - sprite: Objects/Melee/spear.rsi - state: spear + sprite: Objects/Melee/stunbaton.rsi + state: stunbaton_off - type: Stunbaton - range: 1.5 + range: 0.75 arcwidth: 0 arc: default - type: Item - Size: 24 - sprite: Objects/Melee/spear.rsi - prefix: inhand + Size: 10 + sprite: Objects/Melee/stunbaton.rsi + HeldPrefix: off - type: ItemCooldown diff --git a/Resources/Textures/Objects/Melee/stunbaton.rsi/meta.json b/Resources/Textures/Objects/Melee/stunbaton.rsi/meta.json new file mode 100644 index 0000000000..a49523ff93 --- /dev/null +++ b/Resources/Textures/Objects/Melee/stunbaton.rsi/meta.json @@ -0,0 +1,143 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC BY-SA 3.0", + "copyright": "Taken from https://github.com/vgstation-coders/vgstation13 at b8758256b31013946fdbd320ca043a663c399656", + "states": + [ + { + "name": "off-inhand-left", + "directions": 4, + "delays": [ + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ] + ] + }, + { + "name": "off-inhand-right", + "directions": 4, + "delays": [ + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ], + [ + 1.0 + ] + ] + }, + { + "name": "on-inhand-left", + "directions": 4, + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + ], + ] + }, + { + "name": "on-inhand-right", + "directions": 4, + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + ], + ] + }, + { + "name": "stunbaton_off", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "stunbaton_nocell", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "stunbaton_on", + "directions": 1, + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + ] + ] + } + + ] +} + diff --git a/Resources/Textures/Objects/Melee/stunbaton.rsi/off-inhand-left.png b/Resources/Textures/Objects/Melee/stunbaton.rsi/off-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..fd0560130a67ffe4dd8dc11270e2eb98c71f18e6 GIT binary patch literal 259 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=r#xL8Ln`LHy|q!W*?^}tG5*^J zANJ$Qb>`yt zyr=hlckn%2^Dwskg6eAF;zHpy?InUtV3Qdb7L@O=V%)ms7xS~f4Qt~Zbf^Dq-2DIh z?$`VgJg=A8U-+88DeUlFqn2yVca2zL8fFV{FfuSCOy|#TuR6Gy?_UVW6i-(_mvv4F FO#t3!auxsp literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Melee/stunbaton.rsi/off-inhand-right.png b/Resources/Textures/Objects/Melee/stunbaton.rsi/off-inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..0c01f273cb8c28c52b6e0e1885a974102c7ace27 GIT binary patch literal 261 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=XFOdTLn`LHy=5rWtRT>uc&xgh zQ{>u}J4)scgT8&#h&y*cOi-*@4(zk9ff zbNZ9*QB7CxR7GZP$?$utnsJ^TXeJ0`oLepVC(^WBwC%k6r_{3#jAz^l-BGpuz@2qY zog321M7{c#g!J#pY7LHbdK;kS{UYeP{>86Pfi8;L#9V7wbucd_{SwF=Pgg&ebxsLQ E04#NHSO5S3 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Melee/stunbaton.rsi/on-inhand-left.png b/Resources/Textures/Objects/Melee/stunbaton.rsi/on-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..540811b676155bbe1fdbd6a6cc07ee5dae12e655 GIT binary patch literal 807 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrV0!22;uumf=j~nVpvMj(tq-I5 z)YTdsx;jM#tgq>%spqt$PT=Qmunpi_Go!)9(SK3d*B({JMb&z*{(CQ&GpBCnUyb{D z#z5nMAYuJE_19VF)=x`%F!PP49LIacL?$MS`D?rv|DE-3+t2#-ImVm+f41G^9r`@} zkbM8j_rIsOWh+0a);+Z1ueq^xj^v#AKMyB--|m0>`tUzWzx{d5#Mf)_ z)=34Qw*K_JykzI`z4vN#pH^>8)V<$qQm=RCv++-Vi9fo>o$vmi@FVC%W7SjF^Y^O+ z+irh5xn5l!;uR?A^FP_Q)J|=pno>}7%!*gvr@LexfA@6K!c8?Nia$L6^!agI?u^sl zmz>*f5_S9g-YpFiYkdD5Jd-2w=Go7Om*ei)zxnp^hZRrR`<=orXTP85oACcUr%g%`mezzCd_lMJGuh30SrZ+6F+$P8;2%@;vf#;R{+*O}fFO{fJt6pSP-oVMRz$Rbe ze)M}&!*J97;C=38D_{NDTK#(J&$w=btpDEax=o*r<4g1ZhW{+@-J5%tE%m?hlhg0l zhCiMDzB230|D%`oetkZ<)URFd%(Lp1w(-^Zwm)zESt@0=-aJ0rv_vj9;QEKw-43@< z!;_;(#|gz<3}5yy4}P93l&Pe&^=Rv=bM>B6%HG83>1v(sv0<;*v$ubDwQXmO|Erpp zf4@D+pZ$OBXU1vowtue@a{~w2`n~t3Fl`}y{Y@l)d0ncM`b&i*`o zn{>b1n%vS?K`&l?dajoIzWKn~M~xqz`X{`adcsd2K|R2{=?_CU)Io-SSuK)3$nuNt Q+71%&boFyt=akR{0NX^4LjV8( literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Melee/stunbaton.rsi/on-inhand-right.png b/Resources/Textures/Objects/Melee/stunbaton.rsi/on-inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..d983fde6fc8840a41a194cc1b6b811ede6d763fc GIT binary patch literal 789 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrV7lY!;uumf=j|QCqDKw_tq<4n znyVdX6cH8{5PmIIEgavHJYhET1M2`5AD;&<2Xi(|@|NfR7H96V{*Iue)gLu2rji>J)zlAMbS+?C-NW z>Z@T@|0eCsU!^~9Bdx!GZ9jB+{(&pj6DKPi@LZtR^oLuUOS8X$A-M0HR5nkIW(%zMSj@PQLFXKJ+)&0cwjr+>aD|<|}|8p+*(JyEvhqt=0eh|JldC!Z64Xnp>s<$8OWxPK09XW1ccO^B;wmVNg@wzl}P5lF<-)z4*}Q$iB} DkW6?> literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Melee/stunbaton.rsi/stunbaton_nocell.png b/Resources/Textures/Objects/Melee/stunbaton.rsi/stunbaton_nocell.png new file mode 100644 index 0000000000000000000000000000000000000000..8c4fbac7fdb19358dfe2c67931a69999e091f0e7 GIT binary patch literal 431 zcmV;g0Z{&lP)2UMv`7&_pgS&+Jzp%-wa4k#mMVCM>)p@Nx-0qAewMQY83WWXbRO+ldwU&tHg?(j`gaHjN!M0e`-XFvhS+qE>+%K1v~%XiQ)o z{-9u#!erQPMqm^CCVoTRKeZYWh@yyVE5C&UeC@TXt#E*?16AQl zDYVvDYtdSNJAbe(r~-#T4XnenEMqpC?LDt|13qwX0be+HY{5EwKA&TZsWexm213E1 zLIZ=rz{PRQa=G+|!>WPRikwnvT6>mc5 Zd;o5C;m$m^u^RvY002ovPDHLkV1oNo!x;bo literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Melee/stunbaton.rsi/stunbaton_off.png b/Resources/Textures/Objects/Melee/stunbaton.rsi/stunbaton_off.png new file mode 100644 index 0000000000000000000000000000000000000000..59940f44ca4373ace1a3068261c7b823721077c6 GIT binary patch literal 362 zcmV-w0hRuVP)`xB_SB1vm;l0TNy!A&>5m0S_IbN(^SQ6p2*% zu^k3@S4-dX__Y%y@SndB5%E=3`M$NwCE)Lm1=d>nB(e$w_;wFLVlja({I!Jb9(J46 zG6H?@=er~2%iF~w0!2~q;vwAMU0$8NJa3kNv6Fc)5yC0c8ob7-vx z=O;UYIdDkSKo{OL4Ru|Qo*Ugj3_MyO77h_d(1jagu-49+HLHPCaG246h$2-S)} zF>BjE7=~Y$7)nOh5JQcjOY7+h@oK2DIN%J0{)5t?WB)?vPsrH+(IHuyKafB@nc}H& zi36^O45pyrx=7|MTbAV9-KYC>F9eG~{M@VWPSU~mMt~QoYBnG;L?=3&*Xmf>V7kIT zFbF-24x6(XngGyh0W!365=z4F0~jax-C7-2#^KRV=l%}ILI^n=4(0tFj%A3Ba&k=b z2P$8N7+B_K`hR8u9vwDkGc-@n#LdqS4NRv~eEK}RiDpAnH#dbpSNUh}hnEq*Z-Wn@ zo8@170b;m%@=vaTco3G9#UC4F_hbIsp14fmcjE&S1=ukEBLGgWfs3B8Th1CE%FH9+ zk8}86O#tl$NQ0lhdc>Qrx4l*ia{zPQT$QiRJPLjh|5^(WKW;S|4SZRMRJf_9kX`(D z-)>JS`H}x-lCOOqAcT-X5MVSKVX;`?qIa-Sd6SQUuJN^A6qE4F@1q_7n4Wn#_)P#~ zLVl`$Z7U!NAB{#e8KP6G#?M`V7(SUy zp32-yT=}^Qpu#C;A7_4M0XUm41Ak`$xSKBnKXV08nXd{z^9$SUwgiCiP~zd&AL}Qe z>ijhwy?!Y@U#|-71CE}*fDnT0BvhIogQ*6ggKGQ=SI?AYi^&cly?XL%f{{*CSIQu_1P`eSyrYuMl$;tpzcT;# zdHVBBt%kIGf|Yzk3|7s{^FSsCVTir;e?3=L0tS<1O=7 zPeHox1JRRD;e3S82N3hM79gWP-uUxxR)0Q#zR5A{z4| zU~=PC)PHgX`g{N}-{%8}`IXBD=(rpe&k)UA0O`92@u3ZH9#J~iLx1Bm7G0WR@5-UMCZdwKDbm5l}U|L-re z*uFoY(xQHUfJ9y?+vB3Dz(LOD1Gvb^d;ljomk;13r}66cUafJ%$HKcB07K7d%x Date: Thu, 14 May 2020 15:43:49 +0200 Subject: [PATCH 11/29] Stunbaton now has a 3/4 chance of applying slowdown instead of paralyze --- .../Weapon/Melee/StunbatonComponent.cs | 47 ++++++++++++++++++- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs index e03a2172c8..59874ffe1a 100644 --- a/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs @@ -1,32 +1,75 @@ using System.Collections.Generic; using Content.Server.GameObjects.Components.Mobs; +using Content.Server.GameObjects.EntitySystems; +using Robust.Server.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Random; +using Robust.Shared.IoC; +using Robust.Shared.Random; using Robust.Shared.Serialization; namespace Content.Server.GameObjects.Components.Weapon.Melee { [RegisterComponent] - public class StunbatonComponent : MeleeWeaponComponent + public class StunbatonComponent : MeleeWeaponComponent, IUse { + [Dependency] private IRobustRandom _robustRandom; + public override string Name => "Stunbaton"; private float _paralyzeTime = 10f; + private float _paralyzeChance = 0.25f; + private float _slowdownTime = 5f; + + private bool _activated = false; + + public bool Activated => _activated; public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); + serializer.DataField(ref _paralyzeChance, "paralyzeChance", 0.25f); serializer.DataField(ref _paralyzeTime, "paralyzeTime", 10f); + serializer.DataField(ref _slowdownTime, "slowdownTime", 5f); } public override void OnHitEntities(IEnumerable entities) { + if (!_activated) + return; + foreach (var entity in entities) { - if(entity.TryGetComponent(out StunnableComponent stunnable)) + if (!entity.TryGetComponent(out StunnableComponent stunnable)) continue; + + if(_robustRandom.Prob(_paralyzeChance)) stunnable.Paralyze(_paralyzeTime); + else + stunnable.Slowdown(_slowdownTime); } } + + public bool UseEntity(UseEntityEventArgs eventArgs) + { + var sprite = Owner.GetComponent(); + var item = Owner.GetComponent(); + + if (_activated) + { + item.EquippedPrefix = "off"; + sprite.LayerSetState(0, "stunbaton_off"); + _activated = false; + } + else + { + item.EquippedPrefix = "on"; + sprite.LayerSetState(0, "stunbaton_on"); + _activated = true; + } + + return true; + } } } From 2132ff41d4d540650e395864393f10db02ad1c50 Mon Sep 17 00:00:00 2001 From: zumorica Date: Thu, 14 May 2020 15:44:05 +0200 Subject: [PATCH 12/29] In-hands are now refreshed when the prefix is changed --- .../Components/Items/ClientHandsComponent.cs | 26 ++++++++++++++++++- .../Components/Items/ItemComponent.cs | 10 ++++++- .../Components/GUI/ServerHandsComponent.cs | 5 ++++ .../Components/Items/Storage/ItemComponent.cs | 3 ++- .../Components/Items/IHandsComponent.cs | 5 ++++ .../Components/Items/SharedHandsComponent.cs | 12 +++++++++ 6 files changed, 58 insertions(+), 3 deletions(-) diff --git a/Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs b/Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs index 74e040398e..4b465454fe 100644 --- a/Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs +++ b/Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs @@ -6,6 +6,7 @@ using System.Linq; using Content.Client.Interfaces.GameObjects; using Content.Client.UserInterface; using Content.Shared.GameObjects; +using Mono.Cecil; using Robust.Client.GameObjects; using Robust.Client.Interfaces.GameObjects.Components; using Robust.Shared.GameObjects; @@ -116,7 +117,19 @@ namespace Content.Client.GameObjects return; } - var item = entity.GetComponent(); + SetInHands(hand, entity); + } + + private void SetInHands(string hand, IEntity entity) + { + if (entity == null) + { + _sprite.LayerSetVisible($"hand-{hand}", false); + + return; + } + + if (!entity.TryGetComponent(out ItemComponent item)) return; var maybeInhands = item.GetInHandStateInfo(hand); if (!maybeInhands.HasValue) { @@ -130,6 +143,14 @@ namespace Content.Client.GameObjects } } + public void RefreshInHands() + { + foreach (var (hand, entity) in _hands) + { + SetInHands(hand, entity); + } + } + public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); @@ -168,6 +189,9 @@ namespace Content.Client.GameObjects case PlayerDetachedMsg _: _gui.Parent?.RemoveChild(_gui); break; + case RefreshInHandsMsg _: + RefreshInHands(); + break; } } diff --git a/Content.Client/GameObjects/Components/Items/ItemComponent.cs b/Content.Client/GameObjects/Components/Items/ItemComponent.cs index 4140314c55..4c6a1d0402 100644 --- a/Content.Client/GameObjects/Components/Items/ItemComponent.cs +++ b/Content.Client/GameObjects/Components/Items/ItemComponent.cs @@ -3,8 +3,10 @@ using Content.Shared.GameObjects.Components.Items; using Robust.Client.Graphics; using Robust.Client.Interfaces.ResourceManagement; using Robust.Client.ResourceManagement; +using Robust.Shared.Containers; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components.Renderable; +using Robust.Shared.Interfaces.GameObjects.Components; using Robust.Shared.IoC; using Robust.Shared.Serialization; using Robust.Shared.Utility; @@ -26,7 +28,13 @@ namespace Content.Client.GameObjects public string EquippedPrefix { get => _equippedPrefix; - set => _equippedPrefix = value; + set + { + _equippedPrefix = value; + if (!ContainerHelpers.TryGetContainer(Owner, out IContainer container)) return; + if(container.Owner.TryGetComponent(out HandsComponent hands)) + hands.RefreshInHands(); + } } public (RSI rsi, RSI.StateId stateId)? GetInHandStateInfo(string hand) diff --git a/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs b/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs index ab265e3693..b336e1b9c0 100644 --- a/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs +++ b/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs @@ -406,6 +406,11 @@ namespace Content.Server.GameObjects return hands.ContainsKey(index); } + public void RefreshInHands() + { + SendNetworkMessage(new RefreshInHandsMsg()); + } + /// /// Get the name of the slot passed to the inventory component. /// diff --git a/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs index d50c346adc..4c8cde4ae8 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs @@ -13,6 +13,7 @@ using Robust.Shared.Containers; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components; using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.GameObjects.Components; using Robust.Shared.Interfaces.Map; using Robust.Shared.Interfaces.Physics; using Robust.Shared.Interfaces.Random; @@ -48,8 +49,8 @@ namespace Content.Server.GameObjects } set { - Dirty(); _equippedPrefix = value; + Dirty(); } } diff --git a/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs b/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs index 27a11740f7..e1154fb4f9 100644 --- a/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs +++ b/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs @@ -191,6 +191,11 @@ namespace Content.Server.Interfaces.GameObjects /// True if the hand exists, false otherwise. bool HasHand(string index); + /// + /// Refresh all in-hands sprites. + /// + void RefreshInHands(); + void HandleSlotModifiedMaybe(ContainerModifiedMessage message); } } diff --git a/Content.Shared/GameObjects/Components/Items/SharedHandsComponent.cs b/Content.Shared/GameObjects/Components/Items/SharedHandsComponent.cs index dc3604eae6..617c54e983 100644 --- a/Content.Shared/GameObjects/Components/Items/SharedHandsComponent.cs +++ b/Content.Shared/GameObjects/Components/Items/SharedHandsComponent.cs @@ -75,4 +75,16 @@ namespace Content.Shared.GameObjects Index = index; } } + + /// + /// A message that tells the client to refresh in-hands. + /// + [Serializable, NetSerializable] + public class RefreshInHandsMsg : ComponentMessage + { + public RefreshInHandsMsg() + { + Directed = true; + } + } } From 4fd4b4f6f37c134a97ac8bbc878a9a7e04b89791 Mon Sep 17 00:00:00 2001 From: zumorica Date: Thu, 14 May 2020 15:55:53 +0200 Subject: [PATCH 13/29] Add method to AudioHelpers to get a random file from a sound collection --- Content.Shared/Audio/AudioHelpers.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Content.Shared/Audio/AudioHelpers.cs b/Content.Shared/Audio/AudioHelpers.cs index f6a920f479..41f8262df0 100644 --- a/Content.Shared/Audio/AudioHelpers.cs +++ b/Content.Shared/Audio/AudioHelpers.cs @@ -1,10 +1,14 @@ using System; using Content.Shared.GameObjects.Components.Sound; +using Robust.Client.GameObjects.EntitySystems; using Robust.Shared.Audio; using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Random; using Robust.Shared.IoC; using Robust.Shared.Log; +using Robust.Shared.Map; +using Robust.Shared.Prototypes; using Robust.Shared.Random; namespace Content.Shared.Audio @@ -18,5 +22,11 @@ namespace Content.Shared.Audio var scale = (float)(IoCManager.Resolve().NextGaussian(1, amplitude)); return AudioParams.Default.WithPitchScale(scale); } + + public static string GetRandomFileFromSoundCollection(string name) + { + var soundCollection = IoCManager.Resolve().Index(name); + return IoCManager.Resolve().Pick(soundCollection.PickFiles); + } } } From 735ba70f4a127b40f26ea04adf20a0612231ae4b Mon Sep 17 00:00:00 2001 From: zumorica Date: Thu, 14 May 2020 16:08:35 +0200 Subject: [PATCH 14/29] Remove unused using statement --- .../GameObjects/Components/Items/ClientHandsComponent.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs b/Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs index 4b465454fe..7ef5ab94fc 100644 --- a/Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs +++ b/Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs @@ -6,7 +6,6 @@ using System.Linq; using Content.Client.Interfaces.GameObjects; using Content.Client.UserInterface; using Content.Shared.GameObjects; -using Mono.Cecil; using Robust.Client.GameObjects; using Robust.Client.Interfaces.GameObjects.Components; using Robust.Shared.GameObjects; @@ -145,6 +144,8 @@ namespace Content.Client.GameObjects public void RefreshInHands() { + if (!Initialized) return; + foreach (var (hand, entity) in _hands) { SetInHands(hand, entity); From a22c1cb196fd26fc0e22dcf954c87ea4204733ec Mon Sep 17 00:00:00 2001 From: zumorica Date: Thu, 14 May 2020 16:09:44 +0200 Subject: [PATCH 15/29] Whoops. --- Content.Shared/Audio/AudioHelpers.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Content.Shared/Audio/AudioHelpers.cs b/Content.Shared/Audio/AudioHelpers.cs index 41f8262df0..4e2a68b0fb 100644 --- a/Content.Shared/Audio/AudioHelpers.cs +++ b/Content.Shared/Audio/AudioHelpers.cs @@ -1,6 +1,5 @@ using System; using Content.Shared.GameObjects.Components.Sound; -using Robust.Client.GameObjects.EntitySystems; using Robust.Shared.Audio; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; From a8275b4fae542a20d815a07dc5f24cd41505be6a Mon Sep 17 00:00:00 2001 From: zumorica Date: Thu, 14 May 2020 16:13:25 +0200 Subject: [PATCH 16/29] Sounds for stun baton --- .../Components/Mobs/StunnableComponent.cs | 7 ----- .../Weapon/Melee/StunbatonComponent.cs | 26 ++++++++++++++---- Content.Server/Mobs/StandingStateHelper.cs | 11 ++------ Resources/Audio/effects/Egloves.ogg | Bin 0 -> 10878 bytes Resources/Audio/effects/sparks1.ogg | Bin 0 -> 11033 bytes Resources/Audio/effects/sparks2.ogg | Bin 0 -> 12141 bytes Resources/Audio/effects/sparks3.ogg | Bin 0 -> 13236 bytes Resources/Audio/effects/sparks4.ogg | Bin 0 -> 15615 bytes Resources/Audio/weapons/egloves.ogg | Bin 0 -> 7045 bytes .../Prototypes/SoundCollections/sparks.yml | 7 +++++ 10 files changed, 30 insertions(+), 21 deletions(-) create mode 100644 Resources/Audio/effects/Egloves.ogg create mode 100644 Resources/Audio/effects/sparks1.ogg create mode 100644 Resources/Audio/effects/sparks2.ogg create mode 100644 Resources/Audio/effects/sparks3.ogg create mode 100644 Resources/Audio/effects/sparks4.ogg create mode 100644 Resources/Audio/weapons/egloves.ogg create mode 100644 Resources/Prototypes/SoundCollections/sparks.yml diff --git a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs index 5e6b6d95fe..55cfce3e1f 100644 --- a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs @@ -49,13 +49,6 @@ namespace Content.Server.GameObjects.Components.Mobs [ViewVariables] public float KnockdownCap => _knockdownCap; [ViewVariables] public float SlowdownCap => _slowdownCap; - public override void Initialize() - { - base.Initialize(); - - Timer.Spawn(1000, () => Slowdown(20f)); - } - public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs index 59874ffe1a..0e1fd5c599 100644 --- a/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs @@ -1,13 +1,16 @@ using System.Collections.Generic; using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.EntitySystems; +using Content.Shared.Audio; using Robust.Server.GameObjects; +using Robust.Server.GameObjects.EntitySystems; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Random; using Robust.Shared.IoC; using Robust.Shared.Random; using Robust.Shared.Serialization; +using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Weapon.Melee { @@ -15,15 +18,22 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee public class StunbatonComponent : MeleeWeaponComponent, IUse { [Dependency] private IRobustRandom _robustRandom; + [Dependency] private IEntitySystemManager _entitySystemManager; public override string Name => "Stunbaton"; - private float _paralyzeTime = 10f; - private float _paralyzeChance = 0.25f; - private float _slowdownTime = 5f; - private bool _activated = false; + [ViewVariables(VVAccess.ReadWrite)] + private float _paralyzeChance = 0.25f; + + [ViewVariables(VVAccess.ReadWrite)] + private float _paralyzeTime = 10f; + + [ViewVariables(VVAccess.ReadWrite)] + private float _slowdownTime = 5f; + + [ViewVariables] public bool Activated => _activated; public override void ExposeData(ObjectSerializer serializer) @@ -37,9 +47,12 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee public override void OnHitEntities(IEnumerable entities) { - if (!_activated) + if (!Activated) return; + _entitySystemManager.GetEntitySystem() + .Play("/Audio/weapons/egloves.ogg", Owner, AudioHelpers.WithVariation(0.25f)); + foreach (var entity in entities) { if (!entity.TryGetComponent(out StunnableComponent stunnable)) continue; @@ -64,6 +77,9 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee } else { + _entitySystemManager.GetEntitySystem() + .Play(AudioHelpers.GetRandomFileFromSoundCollection("sparks"), Owner, AudioHelpers.WithVariation(0.25f)); + item.EquippedPrefix = "on"; sprite.LayerSetState(0, "stunbaton_on"); _activated = true; diff --git a/Content.Server/Mobs/StandingStateHelper.cs b/Content.Server/Mobs/StandingStateHelper.cs index 741b2e43da..36e1c584c2 100644 --- a/Content.Server/Mobs/StandingStateHelper.cs +++ b/Content.Server/Mobs/StandingStateHelper.cs @@ -34,7 +34,8 @@ namespace Content.Server.Mobs appearance.SetData(SharedSpeciesComponent.MobVisuals.RotationState, newState); if (playSound) - PlaySoundCollection("bodyfall", AudioHelpers.WithVariation(0.25f)); + IoCManager.Resolve().GetEntitySystem() + .Play(AudioHelpers.GetRandomFileFromSoundCollection("bodyfall"), entity, AudioHelpers.WithVariation(0.25f)); if(dropItems) DropAllItemsInHands(entity); @@ -69,13 +70,5 @@ namespace Content.Server.Mobs hands.Drop(heldItem.Owner); } } - - private static void PlaySoundCollection(string name, AudioParams parameters = default) - { - var soundCollection = IoCManager.Resolve().Index(name); - var file = IoCManager.Resolve().Pick(soundCollection.PickFiles); - IoCManager.Resolve().GetEntitySystem() - .Play(file, parameters); - } } } diff --git a/Resources/Audio/effects/Egloves.ogg b/Resources/Audio/effects/Egloves.ogg new file mode 100644 index 0000000000000000000000000000000000000000..c3ebddf0ff28bc068d9cf19a38913b51240e9579 GIT binary patch literal 10878 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 E0NYv}&j0`b literal 0 HcmV?d00001 diff --git a/Resources/Audio/effects/sparks2.ogg b/Resources/Audio/effects/sparks2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..8dd8af706688acd0d7a238130e5e3e69ab406d3d GIT binary patch literal 12141 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 O+GvZC<(UuZl>Z07UM^Mu literal 0 HcmV?d00001 diff --git a/Resources/Audio/effects/sparks4.ogg b/Resources/Audio/effects/sparks4.ogg new file mode 100644 index 0000000000000000000000000000000000000000..3faca5ec2e4280ea35c2fc215135215eb5ab6048 GIT binary patch literal 15615 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 literal 0 HcmV?d00001 diff --git a/Resources/Audio/weapons/egloves.ogg b/Resources/Audio/weapons/egloves.ogg new file mode 100644 index 0000000000000000000000000000000000000000..5df3a1498f1f0a444674093bd313cfeee428c1b5 GIT binary patch literal 7045 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 literal 0 HcmV?d00001 diff --git a/Resources/Prototypes/SoundCollections/sparks.yml b/Resources/Prototypes/SoundCollections/sparks.yml new file mode 100644 index 0000000000..8f81b6055c --- /dev/null +++ b/Resources/Prototypes/SoundCollections/sparks.yml @@ -0,0 +1,7 @@ +- type: sound_collection + id: sparks + files: + - /Audio/effects/sparks1.ogg + - /Audio/effects/sparks2.ogg + - /Audio/effects/sparks3.ogg + - /Audio/effects/sparks4.ogg From b5cf3cf2da78b26adc3a41c7115c480d475602ed Mon Sep 17 00:00:00 2001 From: zumorica Date: Thu, 14 May 2020 17:26:08 +0200 Subject: [PATCH 17/29] Adds stun status effect --- .../Components/Mobs/SpeciesVisualizer2D.cs | 4 +- .../Components/Mobs/StunnableComponent.cs | 67 ++++++++++++++++-- .../Weapon/Melee/StunbatonComponent.cs | 4 +- .../GameObjects/EntitySystems/StunSystem.cs | 1 + .../Mobs/SharedStatusEffectsComponent.cs | 1 + Resources/Audio/weapons/egloves.ogg | Bin 7045 -> 10878 bytes 6 files changed, 69 insertions(+), 8 deletions(-) diff --git a/Content.Client/GameObjects/Components/Mobs/SpeciesVisualizer2D.cs b/Content.Client/GameObjects/Components/Mobs/SpeciesVisualizer2D.cs index 1f80e7cbc6..2ea49471de 100644 --- a/Content.Client/GameObjects/Components/Mobs/SpeciesVisualizer2D.cs +++ b/Content.Client/GameObjects/Components/Mobs/SpeciesVisualizer2D.cs @@ -1,5 +1,6 @@ using System; using Content.Shared.GameObjects.Components.Mobs; +using Microsoft.CodeAnalysis.Completion; using Robust.Client.Animations; using Robust.Client.GameObjects; using Robust.Client.GameObjects.Components.Animations; @@ -39,7 +40,8 @@ namespace Content.Client.GameObjects.Components.Mobs return; } - animation.Stop("rotate"); + if (animation.HasRunningAnimation("rotate")) + animation.Stop("rotate"); animation.Play(new Animation { diff --git a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs index 55cfce3e1f..11cc8a765d 100644 --- a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs @@ -12,7 +12,9 @@ using Robust.Shared.Audio; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Timers; +using Robust.Shared.Interfaces.Timing; using Robust.Shared.IoC; +using Robust.Shared.Maths; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; using Timer = Robust.Shared.Timers.Timer; @@ -22,11 +24,26 @@ namespace Content.Server.GameObjects.Components.Mobs [RegisterComponent] public class StunnableComponent : Component, IActionBlocker, IAttackHand, IMoveSpeedModifier { + public override string Name => "Stunnable"; + +#pragma warning disable 649 [Dependency] private IEntitySystemManager _entitySystemManager; - [Dependency] private ITimerManager _timerManager; + [Dependency] private IGameTiming _gameTiming; +#pragma warning restore 649 + + private TimeSpan? _lastStun; + + [ViewVariables] + public TimeSpan? StunStart => _lastStun; + + [ViewVariables] + public TimeSpan? StunEnd => _lastStun == null + ? (TimeSpan?) null + : _gameTiming.CurTime + TimeSpan.FromSeconds(_stunnedTimer + _knockdownTimer + _slowdownTimer); + + private const int StunLevels = 8; private bool _canHelp = true; - private float _stunCap = 20f; private float _knockdownCap = 20f; private float _slowdownCap = 20f; @@ -39,8 +56,7 @@ namespace Content.Server.GameObjects.Components.Mobs private float _walkModifierOverride = 0f; private float _runModifierOverride = 0f; - - public override string Name => "Stunnable"; + private readonly string[] _texturesStunOverlay = new string[StunLevels]; [ViewVariables] public bool Stunned => _stunnedTimer > 0f; [ViewVariables] public bool KnockedDown => _knockdownTimer > 0f; @@ -59,6 +75,16 @@ namespace Content.Server.GameObjects.Components.Mobs serializer.DataField(ref _helpKnockdownRemove, "helpKnockdownRemove", 1f); } + public override void Initialize() + { + base.Initialize(); + + for (var i = 0; i < StunLevels; i++) + { + _texturesStunOverlay[i] = $"/Textures/UserInterface/Inventory/cooldown-{i}.png"; + } + } + public void Stun(float seconds) { seconds = Math.Min(seconds + _stunnedTimer, _stunCap); @@ -66,6 +92,7 @@ namespace Content.Server.GameObjects.Components.Mobs StandingStateHelper.DropAllItemsInHands(Owner); _stunnedTimer = seconds; + _lastStun = _gameTiming.CurTime; } public void Knockdown(float seconds) @@ -75,6 +102,7 @@ namespace Content.Server.GameObjects.Components.Mobs StandingStateHelper.Down(Owner); _knockdownTimer = seconds; + _lastStun = _gameTiming.CurTime; } public void Paralyze(float seconds) @@ -91,6 +119,7 @@ namespace Content.Server.GameObjects.Components.Mobs _runModifierOverride = runModifierOverride; _slowdownTimer = seconds; + _lastStun = _gameTiming.CurTime; if(Owner.TryGetComponent(out MovementSpeedModifierComponent movement)) movement.RefreshMovementSpeedModifiers(); @@ -113,7 +142,7 @@ namespace Content.Server.GameObjects.Components.Mobs _canHelp = false; Timer.Spawn(((int)_helpInterval*1000), () => _canHelp = true); - IoCManager.Resolve().GetEntitySystem() + _entitySystemManager.GetEntitySystem() .Play("/Audio/effects/thudswoosh.ogg", Owner, AudioHelpers.WithVariation(0.25f)); _knockdownTimer -= _helpKnockdownRemove; @@ -157,6 +186,34 @@ namespace Content.Server.GameObjects.Components.Mobs movement.RefreshMovementSpeedModifiers(); } } + + if (!_lastStun.HasValue || !StunEnd.HasValue || !Owner.TryGetComponent(out ServerStatusEffectsComponent status)) + return; + + var start = _lastStun.Value; + var end = StunEnd.Value; + + var length = (end - start).TotalSeconds; + var progress = (_gameTiming.CurTime - start).TotalSeconds; + var ratio = (float)(progress / length); + + var textureIndex = CalculateStunLevel(ratio); + if (textureIndex == StunLevels) + { + _lastStun = null; + status.RemoveStatus(StatusEffect.Stun); + } + else + { + status.ChangeStatus(StatusEffect.Stun, _texturesStunOverlay[textureIndex]); + } + } + + private static int CalculateStunLevel(float stunValue) + { + var val = stunValue.Clamp(0, 1); + val *= StunLevels; + return (int)Math.Floor(val); } #region ActionBlockers diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs index 0e1fd5c599..9fccf2c3ad 100644 --- a/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs @@ -51,7 +51,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee return; _entitySystemManager.GetEntitySystem() - .Play("/Audio/weapons/egloves.ogg", Owner, AudioHelpers.WithVariation(0.25f)); + .Play("/Audio/weapons/egloves.ogg", Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f)); foreach (var entity in entities) { @@ -78,7 +78,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee else { _entitySystemManager.GetEntitySystem() - .Play(AudioHelpers.GetRandomFileFromSoundCollection("sparks"), Owner, AudioHelpers.WithVariation(0.25f)); + .Play(AudioHelpers.GetRandomFileFromSoundCollection("sparks"), Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f)); item.EquippedPrefix = "on"; sprite.LayerSetState(0, "stunbaton_on"); diff --git a/Content.Server/GameObjects/EntitySystems/StunSystem.cs b/Content.Server/GameObjects/EntitySystems/StunSystem.cs index 8f742b8092..fea2a19502 100644 --- a/Content.Server/GameObjects/EntitySystems/StunSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/StunSystem.cs @@ -1,4 +1,5 @@ using Content.Server.GameObjects.Components.Mobs; +using Content.Shared.GameObjects.Components.Mobs; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; diff --git a/Content.Shared/GameObjects/Components/Mobs/SharedStatusEffectsComponent.cs b/Content.Shared/GameObjects/Components/Mobs/SharedStatusEffectsComponent.cs index 48c2e1c2fd..482b24fc17 100644 --- a/Content.Shared/GameObjects/Components/Mobs/SharedStatusEffectsComponent.cs +++ b/Content.Shared/GameObjects/Components/Mobs/SharedStatusEffectsComponent.cs @@ -32,5 +32,6 @@ namespace Content.Shared.GameObjects.Components.Mobs Health, Hunger, Thirst, + Stun, } } diff --git a/Resources/Audio/weapons/egloves.ogg b/Resources/Audio/weapons/egloves.ogg index 5df3a1498f1f0a444674093bd313cfeee428c1b5..bd92ec294e58929819eb872f8ca899c036e026d6 100644 GIT binary patch literal 10878 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 C*LVH^ literal 7045 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 From ebb49b3377db722b3b4b8cdd643bc1e017dcf95a Mon Sep 17 00:00:00 2001 From: zumorica Date: Thu, 14 May 2020 17:49:40 +0200 Subject: [PATCH 18/29] Document some stun code --- .../Components/Items/IHandsComponent.cs | 1 + .../Components/Mobs/StunnableComponent.cs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/Content.Client/Interfaces/GameObjects/Components/Items/IHandsComponent.cs b/Content.Client/Interfaces/GameObjects/Components/Items/IHandsComponent.cs index 031f760198..0915f66599 100644 --- a/Content.Client/Interfaces/GameObjects/Components/Items/IHandsComponent.cs +++ b/Content.Client/Interfaces/GameObjects/Components/Items/IHandsComponent.cs @@ -14,5 +14,6 @@ namespace Content.Client.Interfaces.GameObjects void AttackByInHand(string index); void UseActiveHand(); void ActivateItemInHand(string handIndex); + void RefreshInHands(); } } diff --git a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs index 11cc8a765d..9890cb8a38 100644 --- a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs @@ -85,6 +85,10 @@ namespace Content.Server.GameObjects.Components.Mobs } } + /// + /// Stuns the entity, disallowing it from doing many interactions temporarily. + /// + /// How many seconds the mob will stay stunned public void Stun(float seconds) { seconds = Math.Min(seconds + _stunnedTimer, _stunCap); @@ -95,6 +99,10 @@ namespace Content.Server.GameObjects.Components.Mobs _lastStun = _gameTiming.CurTime; } + /// + /// Knocks down the mob, making it fall to the ground. + /// + /// How many seconds the mob will stay on the ground public void Knockdown(float seconds) { seconds = MathF.Min(_knockdownTimer + seconds, _knockdownCap); @@ -105,12 +113,22 @@ namespace Content.Server.GameObjects.Components.Mobs _lastStun = _gameTiming.CurTime; } + /// + /// Applies knockdown and stun to the mob temporarily + /// + /// How many seconds the mob will be paralyzed public void Paralyze(float seconds) { Stun(seconds); Knockdown(seconds); } + /// + /// Slows down the mob's walking/running speed temporarily + /// + /// How many seconds the mob will be slowed down + /// Walk speed modifier. Set to 0 or negative for default value. (0.5f) + /// Run speed modifier. Set to 0 or negative for default value. (0.5f) public void Slowdown(float seconds, float walkModifierOverride = 0f, float runModifierOverride = 0f) { seconds = MathF.Min(_slowdownTimer + seconds, _slowdownCap); From 014c51f9134dc66dedc73a2b7c9a967beb5793e4 Mon Sep 17 00:00:00 2001 From: zumorica Date: Thu, 14 May 2020 17:51:57 +0200 Subject: [PATCH 19/29] Makes SetRotation on SpeciesVisualizer2D private --- .../GameObjects/Components/Mobs/SpeciesVisualizer2D.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Client/GameObjects/Components/Mobs/SpeciesVisualizer2D.cs b/Content.Client/GameObjects/Components/Mobs/SpeciesVisualizer2D.cs index 2ea49471de..46a31f069f 100644 --- a/Content.Client/GameObjects/Components/Mobs/SpeciesVisualizer2D.cs +++ b/Content.Client/GameObjects/Components/Mobs/SpeciesVisualizer2D.cs @@ -30,7 +30,7 @@ namespace Content.Client.GameObjects.Components.Mobs } } - public void SetRotation(AppearanceComponent component, Angle rotation) + private void SetRotation(AppearanceComponent component, Angle rotation) { var sprite = component.Owner.GetComponent(); From 569a5b3c851f9810224ccf1f57c7d22d33c924ed Mon Sep 17 00:00:00 2001 From: zumorica Date: Thu, 14 May 2020 18:03:08 +0200 Subject: [PATCH 20/29] Add IStunModifier component interface --- .../Components/Mobs/StunnableComponent.cs | 73 ++++++++++++++++++- 1 file changed, 70 insertions(+), 3 deletions(-) diff --git a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs index 9890cb8a38..5ca35b0a6e 100644 --- a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs @@ -91,7 +91,10 @@ namespace Content.Server.GameObjects.Components.Mobs /// How many seconds the mob will stay stunned public void Stun(float seconds) { - seconds = Math.Min(seconds + _stunnedTimer, _stunCap); + seconds = Math.Min(_stunnedTimer + (seconds * StunTimeModifier), _stunCap); + + if (seconds <= 0f) + return; StandingStateHelper.DropAllItemsInHands(Owner); @@ -105,7 +108,10 @@ namespace Content.Server.GameObjects.Components.Mobs /// How many seconds the mob will stay on the ground public void Knockdown(float seconds) { - seconds = MathF.Min(_knockdownTimer + seconds, _knockdownCap); + seconds = MathF.Min(_knockdownTimer + (seconds * KnockdownTimeModifier), _knockdownCap); + + if (seconds <= 0f) + return; StandingStateHelper.Down(Owner); @@ -131,7 +137,10 @@ namespace Content.Server.GameObjects.Components.Mobs /// Run speed modifier. Set to 0 or negative for default value. (0.5f) public void Slowdown(float seconds, float walkModifierOverride = 0f, float runModifierOverride = 0f) { - seconds = MathF.Min(_slowdownTimer + seconds, _slowdownCap); + seconds = MathF.Min(_slowdownTimer + (seconds * SlowdownTimeModifier), _slowdownCap); + + if (seconds <= 0f) + return; _walkModifierOverride = walkModifierOverride; _runModifierOverride = runModifierOverride; @@ -259,7 +268,65 @@ namespace Content.Server.GameObjects.Components.Mobs public bool CanChangeDirection() => true; #endregion + public float StunTimeModifier + { + get + { + var modifier = 1.0f; + var components = Owner.GetAllComponents(); + + foreach (var component in components) + { + modifier *= component.StunTimeModifier; + } + + return modifier; + } + } + + public float KnockdownTimeModifier + { + get + { + var modifier = 1.0f; + var components = Owner.GetAllComponents(); + + foreach (var component in components) + { + modifier *= component.KnockdownTimeModifier; + } + + return modifier; + } + } + + public float SlowdownTimeModifier + { + get + { + var modifier = 1.0f; + var components = Owner.GetAllComponents(); + + foreach (var component in components) + { + modifier *= component.SlowdownTimeModifier; + } + + return modifier; + } + } + public float WalkSpeedModifier => (SlowedDown ? (_walkModifierOverride <= 0f ? 0.5f : _walkModifierOverride) : 1f); public float SprintSpeedModifier => (SlowedDown ? (_runModifierOverride <= 0f ? 0.5f : _runModifierOverride) : 1f); } + + /// + /// This interface allows components to multiply the time in seconds of various stuns by a number. + /// + public interface IStunModifier + { + float StunTimeModifier => 1.0f; + float KnockdownTimeModifier => 1.0f; + float SlowdownTimeModifier => 1.0f; + } } From 51f06c41421d1397ce803aee9435d6fc034f27bb Mon Sep 17 00:00:00 2001 From: zumorica Date: Thu, 14 May 2020 18:58:45 +0200 Subject: [PATCH 21/29] Math -> MathF --- .../GameObjects/Components/Mobs/StunnableComponent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs index 5ca35b0a6e..3ec94fa9b7 100644 --- a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs @@ -91,7 +91,7 @@ namespace Content.Server.GameObjects.Components.Mobs /// How many seconds the mob will stay stunned public void Stun(float seconds) { - seconds = Math.Min(_stunnedTimer + (seconds * StunTimeModifier), _stunCap); + seconds = MathF.Min(_stunnedTimer + (seconds * StunTimeModifier), _stunCap); if (seconds <= 0f) return; From e1324fff19e1f402d2fa7015ea62abe4c12d7fef Mon Sep 17 00:00:00 2001 From: FL-OZ <58238103+FL-OZ@users.noreply.github.com> Date: Wed, 20 May 2020 12:11:38 -0500 Subject: [PATCH 22/29] Fix RND console keyboard sound being global. (#933) * global keyboard * e * fixes microwave while im at it Co-authored-by: FL-OZ --- .../Components/Kitchen/KitchenMicrowaveComponent.cs | 6 +++--- .../Components/Research/ResearchConsoleComponent.cs | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Content.Server/GameObjects/Components/Kitchen/KitchenMicrowaveComponent.cs b/Content.Server/GameObjects/Components/Kitchen/KitchenMicrowaveComponent.cs index 36a52aa7a5..d5e4aa8191 100644 --- a/Content.Server/GameObjects/Components/Kitchen/KitchenMicrowaveComponent.cs +++ b/Content.Server/GameObjects/Components/Kitchen/KitchenMicrowaveComponent.cs @@ -274,7 +274,7 @@ namespace Content.Server.GameObjects.Components.Kitchen (_currentCookTimerTime == (uint)recipeToCook.CookTime) ? true : false; SetAppearance(MicrowaveVisualState.Cooking); - _audioSystem.Play(_startCookingSound, AudioParams.Default); + _audioSystem.Play(_startCookingSound,Owner, AudioParams.Default); Timer.Spawn((int)(_currentCookTimerTime * _cookTimeMultiplier), () => { @@ -290,7 +290,7 @@ namespace Content.Server.GameObjects.Components.Kitchen var entityToSpawn = goodMeal ? recipeToCook.Result : _badRecipeName; _entityManager.SpawnEntity(entityToSpawn, Owner.Transform.GridPosition); - _audioSystem.Play(_cookingCompleteSound, AudioParams.Default); + _audioSystem.Play(_cookingCompleteSound,Owner, AudioParams.Default); SetAppearance(MicrowaveVisualState.Idle); _busy = false; UpdateUserInterface(); @@ -395,7 +395,7 @@ namespace Content.Server.GameObjects.Components.Kitchen private void ClickSound() { - _audioSystem.Play("/Audio/machines/machine_switch.ogg", AudioParams.Default.WithVolume(-2f)); + _audioSystem.Play("/Audio/machines/machine_switch.ogg",Owner, AudioParams.Default.WithVolume(-2f)); } diff --git a/Content.Server/GameObjects/Components/Research/ResearchConsoleComponent.cs b/Content.Server/GameObjects/Components/Research/ResearchConsoleComponent.cs index 9b10ad832a..89f3d2ddd4 100644 --- a/Content.Server/GameObjects/Components/Research/ResearchConsoleComponent.cs +++ b/Content.Server/GameObjects/Components/Research/ResearchConsoleComponent.cs @@ -7,6 +7,7 @@ using Robust.Server.GameObjects.Components.UserInterface; using Robust.Server.GameObjects.EntitySystems; using Robust.Server.Interfaces.GameObjects; using Robust.Server.Interfaces.Player; +using Robust.Shared.Audio; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Random; @@ -33,7 +34,7 @@ namespace Content.Server.GameObjects.Components.Research private const string _soundCollectionName = "keyboard"; private bool Powered => _powerDevice.Powered; - + public override void Initialize() { base.Initialize(); @@ -119,7 +120,7 @@ namespace Content.Server.GameObjects.Components.Research var soundCollection = _prototypeManager.Index(_soundCollectionName); var file = _random.Pick(soundCollection.PickFiles); var audioSystem = _entitySystemManager.GetEntitySystem(); - audioSystem.Play(file); + audioSystem.Play(file,Owner,AudioParams.Default); } From da4f87dd6a63b13f4bcfc3903a36a33157e08356 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Thu, 21 May 2020 13:17:34 +0200 Subject: [PATCH 23/29] Update submodule --- RobustToolbox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RobustToolbox b/RobustToolbox index a72dd8c85b..feb5050b32 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit a72dd8c85bc1903ef98e709fc1a735bd5e667bdc +Subproject commit feb5050b32499c5f9e1e61ceae63bf74f6797a27 From 629ff929c51ab5c38519fb5587afb5b47144e2cb Mon Sep 17 00:00:00 2001 From: FL-OZ <58238103+FL-OZ@users.noreply.github.com> Date: Thu, 21 May 2020 08:17:34 -0500 Subject: [PATCH 24/29] Change some instrument program #'s to better fit their name/sound. (#938) --- Resources/Prototypes/Entities/Buildings/instruments.yml | 2 +- Resources/Prototypes/Entities/Items/Instruments.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/Prototypes/Entities/Buildings/instruments.yml b/Resources/Prototypes/Entities/Buildings/instruments.yml index 22826ba0fe..671e6fc1df 100644 --- a/Resources/Prototypes/Entities/Buildings/instruments.yml +++ b/Resources/Prototypes/Entities/Buildings/instruments.yml @@ -47,7 +47,7 @@ id: MinimoogInstrument components: - type: Instrument - program: 7 + program: 81 - type: Sprite sprite: Objects/Instruments/otherinstruments.rsi state: minimoog diff --git a/Resources/Prototypes/Entities/Items/Instruments.yml b/Resources/Prototypes/Entities/Items/Instruments.yml index 24b8e5565e..b083775970 100644 --- a/Resources/Prototypes/Entities/Items/Instruments.yml +++ b/Resources/Prototypes/Entities/Items/Instruments.yml @@ -17,7 +17,7 @@ id: SynthesizerInstrument components: - type: Instrument - program: 2 + program: 62 - type: Sprite sprite: Objects/Instruments/h_synthesizer.rsi state: icon From 7cbd2fd8ce090f0a6b82a6105d73e0a4ae4ec2a7 Mon Sep 17 00:00:00 2001 From: zumorica Date: Thu, 21 May 2020 19:40:08 +0200 Subject: [PATCH 25/29] OnHitEntities now returns a bool and takes a read only list --- .../Components/Weapon/Melee/MeleeWeaponComponent.cs | 5 +++-- .../Components/Weapon/Melee/StunbatonComponent.cs | 8 +++++--- Resources/Prototypes/Entities/Items/Weapons/security.yml | 1 + 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs index 5e399f2aa7..c2f24bb97f 100644 --- a/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs @@ -75,8 +75,9 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee serializer.DataField(ref _cooldownTime, "cooldownTime", 1f); } - public virtual void OnHitEntities(IEnumerable entities) + public virtual bool OnHitEntities(IReadOnlyList entities) { + return false; } void IAttack.Attack(AttackEventArgs eventArgs) @@ -105,7 +106,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee } } - OnHitEntities(hitEntities); + if(OnHitEntities(hitEntities)) return; var audioSystem = _entitySystemManager.GetEntitySystem(); var emitter = hitEntities.Count == 0 ? eventArgs.User : hitEntities[0]; diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs index 9fccf2c3ad..21000d1e39 100644 --- a/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs @@ -45,10 +45,10 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee serializer.DataField(ref _slowdownTime, "slowdownTime", 5f); } - public override void OnHitEntities(IEnumerable entities) + public override bool OnHitEntities(IReadOnlyList entities) { - if (!Activated) - return; + if (!Activated || entities.Count == 0) + return false; _entitySystemManager.GetEntitySystem() .Play("/Audio/weapons/egloves.ogg", Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f)); @@ -62,6 +62,8 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee else stunnable.Slowdown(_slowdownTime); } + + return false; } public bool UseEntity(UseEntityEventArgs eventArgs) diff --git a/Resources/Prototypes/Entities/Items/Weapons/security.yml b/Resources/Prototypes/Entities/Items/Weapons/security.yml index 4183ba8f4e..646b5b605a 100644 --- a/Resources/Prototypes/Entities/Items/Weapons/security.yml +++ b/Resources/Prototypes/Entities/Items/Weapons/security.yml @@ -12,6 +12,7 @@ state: stunbaton_off - type: Stunbaton + damage: 0.25 range: 0.75 arcwidth: 0 arc: default From d3102dbf960bf4df15d4f22861852cd624863ad7 Mon Sep 17 00:00:00 2001 From: zumorica Date: Thu, 21 May 2020 19:44:49 +0200 Subject: [PATCH 26/29] Remove server-side RefreshInHands, refresh them on component state update --- .../Components/Items/ClientHandsComponent.cs | 4 +--- .../Components/GUI/ServerHandsComponent.cs | 5 ----- .../GameObjects/Components/Items/IHandsComponent.cs | 5 ----- .../Components/Items/SharedHandsComponent.cs | 12 ------------ .../Prototypes/Entities/Items/Weapons/security.yml | 2 +- 5 files changed, 2 insertions(+), 26 deletions(-) diff --git a/Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs b/Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs index 7ef5ab94fc..f7f1e3c815 100644 --- a/Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs +++ b/Content.Client/GameObjects/Components/Items/ClientHandsComponent.cs @@ -101,6 +101,7 @@ namespace Content.Client.GameObjects ActiveIndex = cast.ActiveIndex; _gui?.UpdateHandIcons(); + RefreshInHands(); } private void _setHand(string hand, IEntity entity) @@ -190,9 +191,6 @@ namespace Content.Client.GameObjects case PlayerDetachedMsg _: _gui.Parent?.RemoveChild(_gui); break; - case RefreshInHandsMsg _: - RefreshInHands(); - break; } } diff --git a/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs b/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs index b336e1b9c0..ab265e3693 100644 --- a/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs +++ b/Content.Server/GameObjects/Components/GUI/ServerHandsComponent.cs @@ -406,11 +406,6 @@ namespace Content.Server.GameObjects return hands.ContainsKey(index); } - public void RefreshInHands() - { - SendNetworkMessage(new RefreshInHandsMsg()); - } - /// /// Get the name of the slot passed to the inventory component. /// diff --git a/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs b/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs index e1154fb4f9..27a11740f7 100644 --- a/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs +++ b/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs @@ -191,11 +191,6 @@ namespace Content.Server.Interfaces.GameObjects /// True if the hand exists, false otherwise. bool HasHand(string index); - /// - /// Refresh all in-hands sprites. - /// - void RefreshInHands(); - void HandleSlotModifiedMaybe(ContainerModifiedMessage message); } } diff --git a/Content.Shared/GameObjects/Components/Items/SharedHandsComponent.cs b/Content.Shared/GameObjects/Components/Items/SharedHandsComponent.cs index 617c54e983..dc3604eae6 100644 --- a/Content.Shared/GameObjects/Components/Items/SharedHandsComponent.cs +++ b/Content.Shared/GameObjects/Components/Items/SharedHandsComponent.cs @@ -75,16 +75,4 @@ namespace Content.Shared.GameObjects Index = index; } } - - /// - /// A message that tells the client to refresh in-hands. - /// - [Serializable, NetSerializable] - public class RefreshInHandsMsg : ComponentMessage - { - public RefreshInHandsMsg() - { - Directed = true; - } - } } diff --git a/Resources/Prototypes/Entities/Items/Weapons/security.yml b/Resources/Prototypes/Entities/Items/Weapons/security.yml index 646b5b605a..cc0a69562b 100644 --- a/Resources/Prototypes/Entities/Items/Weapons/security.yml +++ b/Resources/Prototypes/Entities/Items/Weapons/security.yml @@ -12,7 +12,7 @@ state: stunbaton_off - type: Stunbaton - damage: 0.25 + damage: 1 range: 0.75 arcwidth: 0 arc: default From 0cfd2f3bb2e830f595d47523ddf02cb6aacc261a Mon Sep 17 00:00:00 2001 From: 20kdc Date: Thu, 21 May 2020 20:08:03 +0100 Subject: [PATCH 27/29] Solar Panels (#936) --- .../Power/PowerGeneratorComponent.cs | 2 +- .../Components/Power/SolarPanelComponent.cs | 91 ++++++++++++++++++ .../EntitySystems/PowerSolarSystem.cs | 65 +++++++++++++ .../Prototypes/Entities/Buildings/power.yml | 29 ++++++ .../Buildings/solar_panel.rsi/broken.png | Bin 0 -> 291 bytes .../Buildings/solar_panel.rsi/meta.json | 1 + .../Buildings/solar_panel.rsi/normal.png | Bin 0 -> 886 bytes 7 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 Content.Server/GameObjects/Components/Power/SolarPanelComponent.cs create mode 100644 Content.Server/GameObjects/EntitySystems/PowerSolarSystem.cs create mode 100644 Resources/Textures/Buildings/solar_panel.rsi/broken.png create mode 100644 Resources/Textures/Buildings/solar_panel.rsi/meta.json create mode 100644 Resources/Textures/Buildings/solar_panel.rsi/normal.png diff --git a/Content.Server/GameObjects/Components/Power/PowerGeneratorComponent.cs b/Content.Server/GameObjects/Components/Power/PowerGeneratorComponent.cs index e9285e7541..df10e90df4 100644 --- a/Content.Server/GameObjects/Components/Power/PowerGeneratorComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerGeneratorComponent.cs @@ -65,7 +65,7 @@ namespace Content.Server.GameObjects.Components.Power { _supply = value; var node = Owner.GetComponent(); - node.Parent.UpdateGenerator(this); + node?.Parent?.UpdateGenerator(this); } /// diff --git a/Content.Server/GameObjects/Components/Power/SolarPanelComponent.cs b/Content.Server/GameObjects/Components/Power/SolarPanelComponent.cs new file mode 100644 index 0000000000..4707180c59 --- /dev/null +++ b/Content.Server/GameObjects/Components/Power/SolarPanelComponent.cs @@ -0,0 +1,91 @@ +using System; +using Content.Server.GameObjects.Components.Damage; +using Content.Server.GameObjects.EntitySystems; +using Content.Shared.Audio; +using Robust.Server.GameObjects; +using Robust.Server.GameObjects.EntitySystems; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Random; +using Robust.Shared.IoC; +using Robust.Shared.Maths; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; +using Robust.Shared.Serialization; +using Robust.Shared.ViewVariables; + +namespace Content.Server.GameObjects.Components.Power +{ + + /// + /// This is a solar panel. + /// It generates power from the sun based on coverage. + /// + [RegisterComponent] + public class SolarPanelComponent : Component, IBreakAct + { + public override string Name => "SolarPanel"; + + private PowerGeneratorComponent _powerGenerator; + + /// + /// Maximum supply output by this panel (coverage = 1) + /// + private float _maxSupply = 1500; + [ViewVariables(VVAccess.ReadWrite)] + public float MaxSupply + { + get => _maxSupply; + set { + _maxSupply = value; + UpdateSupply(); + } + } + + /// + /// Current coverage of this panel (from 0 to 1). + /// This is updated by . + /// + private float _coverage = 0; + [ViewVariables] + public float Coverage + { + get => _coverage; + set { + // This gets updated once-per-tick, so avoid updating it if truly unnecessary + if (_coverage != value) { + _coverage = value; + UpdateSupply(); + } + } + } + + private void UpdateSupply() + { + if (_powerGenerator != null) + _powerGenerator.Supply = _maxSupply * _coverage; + } + + public override void Initialize() + { + base.Initialize(); + + _powerGenerator = Owner.GetComponent(); + UpdateSupply(); + } + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + + serializer.DataField(ref _maxSupply, "maxsupply", 1500); + } + + public void OnBreak(BreakageEventArgs args) + { + var sprite = Owner.GetComponent(); + sprite.LayerSetState(0, "broken"); + MaxSupply = 0; + } + } +} diff --git a/Content.Server/GameObjects/EntitySystems/PowerSolarSystem.cs b/Content.Server/GameObjects/EntitySystems/PowerSolarSystem.cs new file mode 100644 index 0000000000..4108748e48 --- /dev/null +++ b/Content.Server/GameObjects/EntitySystems/PowerSolarSystem.cs @@ -0,0 +1,65 @@ +using Content.Server.GameObjects.Components.Power; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Maths; +using System; + +namespace Content.Server.GameObjects.EntitySystems +{ + /// + /// Responsible for maintaining the solar-panel sun angle and updating coverage. + /// + [UsedImplicitly] + public class PowerSolarSystem: EntitySystem + { + /// + /// The current sun angle. + /// + public Angle TowardsSun = Angle.South; + + public override void Initialize() + { + EntityQuery = new TypeEntityQuery(typeof(SolarPanelComponent)); + } + + public override void Update(float frameTime) + { + TowardsSun += Angle.FromDegrees(frameTime / 10); + TowardsSun = TowardsSun.Reduced(); + foreach (var entity in RelevantEntities) + { + // In the 'sunRelative' coordinate system: + // the sun is considered to be an infinite distance directly up. + // this is the rotation of the panel relative to that. + // directly upwards (theta = 0) = coverage 1 + // left/right 90 degrees (abs(theta) = (pi / 2)) = coverage 0 + // directly downwards (abs(theta) = pi) = coverage -1 + // as TowardsSun + = CCW, + // panelRelativeToSun should - = CW + var panelRelativeToSun = entity.Transform.WorldRotation - TowardsSun; + // essentially, given cos = X & sin = Y & Y is 'downwards', + // then for the first 90 degrees of rotation in either direction, + // this plots the lower-right quadrant of a circle. + // now basically assume a line going from the negated X/Y to there, + // and that's the hypothetical solar panel. + // + // since, again, the sun is considered to be an infinite distance upwards, + // this essentially means Cos(panelRelativeToSun) is half of the cross-section, + // and since the full cross-section has a max of 2, effectively-halving it is fine. + // + // as for when it goes negative, it only does that when (abs(theta) > pi) + // and that's expected behavior. + float coverage = (float) Math.Max(0, Math.Cos(panelRelativeToSun)); + + // Would determine occlusion, but that requires raytraces. + // And I'm not sure where those are in the codebase. + // Luckily, auto-rotation isn't in yet, so it won't matter anyway. + + // Total coverage calculated; apply it to the panel. + var panel = entity.GetComponent(); + panel.Coverage = coverage; + } + } + } +} diff --git a/Resources/Prototypes/Entities/Buildings/power.yml b/Resources/Prototypes/Entities/Buildings/power.yml index 5191c4e1f0..a599ba1842 100644 --- a/Resources/Prototypes/Entities/Buildings/power.yml +++ b/Resources/Prototypes/Entities/Buildings/power.yml @@ -62,6 +62,35 @@ - type: SnapGrid offset: Center +- type: entity + id: SolarPanel + name: Solar Panel + description: Generates power from sunlight. Usually used to power replacements for sunlight. Fragile. + placement: + mode: SnapgridCenter + components: + - type: Clickable + - type: InteractionOutline + - type: Collidable + shapes: + - !type:PhysShapeAabb + layer: 31 + - type: Sprite + sprite: Buildings/solar_panel.rsi + state: normal + - type: Icon + sprite: Buildings/solar_panel.rsi + state: normal + - type: PowerGenerator + - type: SolarPanel + supply: 1500 + - type: Rotatable + - type: SnapGrid + offset: Center + - type: Damageable + - type: Breakable + thresholdvalue: 100 + - type: entity id: WPPnobattery name: WPPnobattery diff --git a/Resources/Textures/Buildings/solar_panel.rsi/broken.png b/Resources/Textures/Buildings/solar_panel.rsi/broken.png new file mode 100644 index 0000000000000000000000000000000000000000..ded81ca75f5a50eb079b870437dcfd01f34465e0 GIT binary patch literal 291 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv=>VS)S4AL$!I*&|jh&rcOH0ec z<3B^%|1)U}J9qvs@Jg2iN-~xN`2{mLJiCzw;v{*yyD)UH%6b4fD?MEtLp08>ooLI~ zO&9T{$@ecRM@&0*3z?yy6$>aE$Q*yidBo)u5&V~WaKAorGcM`B(7 zp$D@Yx1N}AYE@rU$@x-K)5~8Zn3-R+ue!i9r!AH3Y}k9jtrmVo?_1h-@d(Y?*y(pK i?y>rwqzV5&UE<%VCn?BuzW*@L(F~rhelF{r5}E+`6>HQ0 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Buildings/solar_panel.rsi/meta.json b/Resources/Textures/Buildings/solar_panel.rsi/meta.json new file mode 100644 index 0000000000..377fa6ccb7 --- /dev/null +++ b/Resources/Textures/Buildings/solar_panel.rsi/meta.json @@ -0,0 +1 @@ +{"version":1,"license":"CC-BY-SA-3.0","copyright":"Taken from https://github.com/discordia-space/CEV-Eris/blob/d1e0161af146835f4fb79d21a6200caa9cc842d0/icons/obj/power.dmi and modified.","size":{"x":32,"y":32},"states":[{"name":"normal","select":[],"flags":{},"directions":8},{"name":"broken","select":[],"flags":{},"directions":1}]} diff --git a/Resources/Textures/Buildings/solar_panel.rsi/normal.png b/Resources/Textures/Buildings/solar_panel.rsi/normal.png new file mode 100644 index 0000000000000000000000000000000000000000..1e1c620029d4e29cecd7e67db13e08f4b46c1ff0 GIT binary patch literal 886 zcmV-+1Bv{JP)0$r?00DGTPE!Ct=GbNc0004EOGiWi zhy@);0008{Nkl29!XzW>MFZg%9B1 z^WLPj%{fT~bs^k)7-&19`TL#!{7I7hBekE?XZU*W`f}fvWPSA|-YcMiBT_JF^}7Y^ zfgu4EsNW|9q($_#G0;D&11h=so7I4U|aV%jd?)GeSh;M=x3mG z1VIW69v4vi1i}{NwY+reWFRSmhVuvlOYs>2lmLT(fC0dI0qT0dAAU&Cst5t_)nWa( zfClg!PLy7X5P&|~JH{!3-1JZV1OQsKj0;FhRK-Yu!4~6#s|WzxNLQc<0wWC+cnDGs zE3Z>dz_u&cEf#F%1Yi$L0|FKR^j=FjqX>iyU0@mBR0>zMlu1&aPA%u0olZ(?HMW3z z1Uv!O0qt#(34^Qj5%7Wn;3I&3ZFwt8(98!IX!fGw1dM*#g3bX0=G402;30td9RPX% z=0km_igResXV6-k%WND&OrTV-Joo_M2TfRjpv8lbYBd7L;Icx0v&_6YszE?QJ;11d z4uDIW7y`g9n1EUi3Nx}En`JAaXe0m%6VPVXeE@ShB|ZX_1)T#1fm!c4Fc(9e6(6o0 z2h*Lk3nEMaG$xP>d12UPDQiO)I0T;vfXR))aQ0%7WLUm8=kNm!XLCXT3lPR4jG7Ge zeFQcHkvwKb?tE6g=SnN!fF^TTVo!QFwOK;|Xu98|nuRVY$*bpWyhN~4B)X6^c~9#i7PC$|sj~~WgEJFYry{vEx-ci;A__=JC?-h`2yfge{nfxd97nBSytbq7klK=n! M07*qoM6N<$f)CPawEzGB literal 0 HcmV?d00001 From 54642bdd91bf9176b74e1745b8bd06055601dd5a Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Thu, 21 May 2020 23:19:51 +0200 Subject: [PATCH 28/29] Fix water tank texture casing. Also adds suffixes to make mapping easier. --- Resources/Prototypes/Entities/water_tank.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Resources/Prototypes/Entities/water_tank.yml b/Resources/Prototypes/Entities/water_tank.yml index 34be446a38..66c8a90136 100644 --- a/Resources/Prototypes/Entities/water_tank.yml +++ b/Resources/Prototypes/Entities/water_tank.yml @@ -2,13 +2,14 @@ parent: ReagentItem id: WaterTank name: Water Tank + suffix: Empty description: "A water tank. It is used to store high amounts of water." components: - type: Sprite - texture: Buildings/WaterTank.png + texture: Buildings/watertank.png - type: Icon - texture: Buildings/WaterTank.png + texture: Buildings/watertank.png - type: Clickable - type: InteractionOutline @@ -37,6 +38,7 @@ - type: entity parent: WaterTank id: WaterTankFull + suffix: Full components: - type: Solution contents: From 958c101e52c851887174bf6cc9599b597129cb15 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Thu, 21 May 2020 23:48:43 +0200 Subject: [PATCH 29/29] Move locked airlock types to their own file. --- .../Prototypes/Entities/Buildings/airlock_access.yml | 8 ++++++++ .../Prototypes/Entities/Buildings/airlock_types.yml | 10 ---------- 2 files changed, 8 insertions(+), 10 deletions(-) create mode 100644 Resources/Prototypes/Entities/Buildings/airlock_access.yml diff --git a/Resources/Prototypes/Entities/Buildings/airlock_access.yml b/Resources/Prototypes/Entities/Buildings/airlock_access.yml new file mode 100644 index 0000000000..6bffa1c88a --- /dev/null +++ b/Resources/Prototypes/Entities/Buildings/airlock_access.yml @@ -0,0 +1,8 @@ +- type: entity + parent: airlock_engineering + id: airlock_engineering_locked + name: Engineering Airlock + suffix: Locked + components: + - type: AccessReader + required: ["engineering"] diff --git a/Resources/Prototypes/Entities/Buildings/airlock_types.yml b/Resources/Prototypes/Entities/Buildings/airlock_types.yml index d3b2f17098..f5407b8007 100644 --- a/Resources/Prototypes/Entities/Buildings/airlock_types.yml +++ b/Resources/Prototypes/Entities/Buildings/airlock_types.yml @@ -40,16 +40,6 @@ - type: Icon sprite: Buildings/Doors/airlock_engineering_glass.rsi - -- type: entity - parent: airlock_engineering - id: airlock_engineering_locked - name: Locked Engineering Airlock - components: - - type: AccessReader - required: ["engineering"] - - - type: entity parent: Airlock id: airlock_medical