From 02d509fc5f56bf0afa54791de8c88bb5e368683a Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Thu, 26 Sep 2019 22:32:32 +0200 Subject: [PATCH] Shitty combat mode & animations. (#367) * Combat mode UI & targeting zones. * Fix inventory hud positioning. * Crappy attack animations. * Import TG combat sounds * More work on arcs. * Implement hit sounds. * Lunging, hit effects, some more stuff. --- Content.Client/EntryPoint.cs | 1 - .../Components/Mobs/CameraRecoilComponent.cs | 6 +- .../Components/Mobs/CombatModeComponent.cs | 59 +++++++++ .../Components/Mobs/MeleeLungeComponent.cs | 65 ++++++++++ .../Melee/MeleeWeaponArcAnimationComponent.cs | 67 ++++++++++ .../EntitySystems/CombatModeSystem.cs | 33 +++++ .../EntitySystems/MeleeLungeSystem.cs | 28 +++++ .../EntitySystems/MeleeWeaponSystem.cs | 101 +++++++++++++++ Content.Client/Input/ContentContexts.cs | 3 +- Content.Client/UserInterface/GameHud.cs | 52 +++++++- Content.Client/UserInterface/NanoStyle.cs | 17 +++ Content.Client/UserInterface/TargetingDoll.cs | 82 +++++++++++++ .../Components/Mobs/CombatModeComponent.cs | 32 ++++- .../Weapon/Melee/MeleeWeaponComponent.cs | 78 ++++++++++-- .../EntitySystems/CombatModeSystem.cs | 43 ++++++- .../EntitySystems/MeleeWeaponSystem.cs | 18 +++ .../Mobs/SharedCombatModeComponent.cs | 27 ++++ .../Components/Mobs/TargetingZone.cs | 27 ++++ .../Melee/MeleeWeaponAnimationPrototype.cs | 59 +++++++++ Content.Shared/GameObjects/ContentNetIDs.cs | 1 + .../CombatModeSystemMessages.cs | 32 +++++ .../MeleeWeaponSystemMessages.cs | 29 +++++ Resources/Audio/weapons/bladeslice.ogg | Bin 0 -> 7691 bytes Resources/Audio/weapons/genhit1.ogg | Bin 0 -> 8655 bytes Resources/Audio/weapons/genhit2.ogg | Bin 0 -> 8036 bytes Resources/Audio/weapons/genhit3.ogg | Bin 0 -> 7943 bytes Resources/Audio/weapons/punch1.ogg | Bin 0 -> 9174 bytes Resources/Audio/weapons/punch2.ogg | Bin 0 -> 11323 bytes Resources/Audio/weapons/punch3.ogg | Bin 0 -> 10966 bytes Resources/Audio/weapons/punch4.ogg | Bin 0 -> 10668 bytes Resources/Audio/weapons/punchmiss.ogg | Bin 0 -> 8147 bytes Resources/Audio/weapons/smash.ogg | Bin 0 -> 9004 bytes .../Prototypes/Entities/Effects/WeaponArc.yml | 10 ++ .../Prototypes/Entities/items/toolbox.yml | 29 +++-- .../Entities/items/weapons/spear.yml | 11 ++ .../MeleeWeaponAnimations/default.yml | 7 ++ .../Effects/weapons/arcs.rsi/meta.json | 18 +++ .../Effects/weapons/arcs.rsi/slash.png | Bin 0 -> 273 bytes .../Effects/weapons/arcs.rsi/spear.png | Bin 0 -> 234 bytes .../UserInterface/target-doll-high.svg | 68 ++++++++++ .../target-doll-high.svg.96dpi.png | Bin 0 -> 427 bytes .../UserInterface/target-doll-low.svg | 73 +++++++++++ .../target-doll-low.svg.96dpi.png | Bin 0 -> 420 bytes .../UserInterface/target-doll-middle.svg | 72 +++++++++++ .../target-doll-middle.svg.96dpi.png | Bin 0 -> 1021 bytes .../Textures/UserInterface/target-doll.svg | 116 ++++++++++++++++++ Resources/keybinds.yml | 2 +- 47 files changed, 1231 insertions(+), 35 deletions(-) create mode 100644 Content.Client/GameObjects/Components/Mobs/CombatModeComponent.cs create mode 100644 Content.Client/GameObjects/Components/Mobs/MeleeLungeComponent.cs create mode 100644 Content.Client/GameObjects/Components/Weapons/Melee/MeleeWeaponArcAnimationComponent.cs create mode 100644 Content.Client/GameObjects/EntitySystems/CombatModeSystem.cs create mode 100644 Content.Client/GameObjects/EntitySystems/MeleeLungeSystem.cs create mode 100644 Content.Client/GameObjects/EntitySystems/MeleeWeaponSystem.cs create mode 100644 Content.Client/UserInterface/TargetingDoll.cs create mode 100644 Content.Server/GameObjects/EntitySystems/MeleeWeaponSystem.cs create mode 100644 Content.Shared/GameObjects/Components/Mobs/SharedCombatModeComponent.cs create mode 100644 Content.Shared/GameObjects/Components/Mobs/TargetingZone.cs create mode 100644 Content.Shared/GameObjects/Components/Weapons/Melee/MeleeWeaponAnimationPrototype.cs create mode 100644 Content.Shared/GameObjects/EntitySystemMessages/CombatModeSystemMessages.cs create mode 100644 Content.Shared/GameObjects/EntitySystemMessages/MeleeWeaponSystemMessages.cs create mode 100644 Resources/Audio/weapons/bladeslice.ogg create mode 100644 Resources/Audio/weapons/genhit1.ogg create mode 100644 Resources/Audio/weapons/genhit2.ogg create mode 100644 Resources/Audio/weapons/genhit3.ogg create mode 100644 Resources/Audio/weapons/punch1.ogg create mode 100644 Resources/Audio/weapons/punch2.ogg create mode 100644 Resources/Audio/weapons/punch3.ogg create mode 100644 Resources/Audio/weapons/punch4.ogg create mode 100644 Resources/Audio/weapons/punchmiss.ogg create mode 100644 Resources/Audio/weapons/smash.ogg create mode 100644 Resources/Prototypes/Entities/Effects/WeaponArc.yml create mode 100644 Resources/Prototypes/MeleeWeaponAnimations/default.yml create mode 100644 Resources/Textures/Effects/weapons/arcs.rsi/meta.json create mode 100644 Resources/Textures/Effects/weapons/arcs.rsi/slash.png create mode 100644 Resources/Textures/Effects/weapons/arcs.rsi/spear.png create mode 100644 Resources/Textures/UserInterface/target-doll-high.svg create mode 100644 Resources/Textures/UserInterface/target-doll-high.svg.96dpi.png create mode 100644 Resources/Textures/UserInterface/target-doll-low.svg create mode 100644 Resources/Textures/UserInterface/target-doll-low.svg.96dpi.png create mode 100644 Resources/Textures/UserInterface/target-doll-middle.svg create mode 100644 Resources/Textures/UserInterface/target-doll-middle.svg.96dpi.png create mode 100644 Resources/Textures/UserInterface/target-doll.svg diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs index 13032876b0..0321584f53 100644 --- a/Content.Client/EntryPoint.cs +++ b/Content.Client/EntryPoint.cs @@ -62,7 +62,6 @@ namespace Content.Client "EmitSoundOnUse", "FootstepModifier", "HeatResistance", - "CombatMode", "Teleportable", "ItemTeleporter", "Portal", diff --git a/Content.Client/GameObjects/Components/Mobs/CameraRecoilComponent.cs b/Content.Client/GameObjects/Components/Mobs/CameraRecoilComponent.cs index 244e81cf26..6bd54f02bb 100644 --- a/Content.Client/GameObjects/Components/Mobs/CameraRecoilComponent.cs +++ b/Content.Client/GameObjects/Components/Mobs/CameraRecoilComponent.cs @@ -29,6 +29,10 @@ namespace Content.Client.GameObjects.Components.Mobs private EyeComponent _eye; + // Basically I needed a way to chain this effect for the attack lunge animation. + // Sorry! + public Vector2 BaseOffset { get; set; } + public override void Initialize() { base.Initialize(); @@ -95,7 +99,7 @@ namespace Content.Client.GameObjects.Components.Mobs private void _updateEye() { - _eye.Offset = _currentKick; + _eye.Offset = BaseOffset + _currentKick; } } } diff --git a/Content.Client/GameObjects/Components/Mobs/CombatModeComponent.cs b/Content.Client/GameObjects/Components/Mobs/CombatModeComponent.cs new file mode 100644 index 0000000000..48ae173ad2 --- /dev/null +++ b/Content.Client/GameObjects/Components/Mobs/CombatModeComponent.cs @@ -0,0 +1,59 @@ +using Content.Client.UserInterface; +using Content.Shared.GameObjects.Components.Mobs; +using Robust.Client.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Network; +using Robust.Shared.IoC; +using Robust.Shared.ViewVariables; + +namespace Content.Client.GameObjects.Components.Mobs +{ + [RegisterComponent] + public sealed class CombatModeComponent : SharedCombatModeComponent + { + [ViewVariables(VVAccess.ReadWrite)] + public bool IsInCombatMode { get; private set; } + + [ViewVariables(VVAccess.ReadWrite)] + public TargetingZone ActiveZone { get; private set; } + +#pragma warning disable 649 + [Dependency] private readonly IGameHud _gameHud; +#pragma warning restore 649 + + public override void HandleComponentState(ComponentState curState, ComponentState nextState) + { + base.HandleComponentState(curState, nextState); + + var state = (CombatModeComponentState) curState; + + IsInCombatMode = state.IsInCombatMode; + ActiveZone = state.TargetingZone; + UpdateHud(); + } + + public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null) + { + base.HandleMessage(message, netChannel, component); + + switch (message) + { + case PlayerAttachedMsg _: + _gameHud.CombatPanelVisible = true; + UpdateHud(); + break; + + case PlayerDetachedMsg _: + _gameHud.CombatPanelVisible = false; + break; + } + } + + private void UpdateHud() + { + _gameHud.CombatModeActive = IsInCombatMode; + _gameHud.TargetingZone = ActiveZone; + } + } +} diff --git a/Content.Client/GameObjects/Components/Mobs/MeleeLungeComponent.cs b/Content.Client/GameObjects/Components/Mobs/MeleeLungeComponent.cs new file mode 100644 index 0000000000..4dc93ac708 --- /dev/null +++ b/Content.Client/GameObjects/Components/Mobs/MeleeLungeComponent.cs @@ -0,0 +1,65 @@ +using Robust.Client.GameObjects; +using Robust.Client.Interfaces.GameObjects.Components; +using Robust.Shared.GameObjects; +using Robust.Shared.Maths; + +namespace Content.Client.GameObjects.Components.Mobs +{ + [RegisterComponent] + public sealed class MeleeLungeComponent : Component + { + public override string Name => "MeleeLunge"; + + private const float ResetTime = 0.3f; + private const float BaseOffset = 0.25f; + + private Angle _angle; + private float _time; + + public void SetData(Angle angle) + { + _angle = angle; + _time = 0; + } + + public void Update(float frameTime) + { + _time += frameTime; + + var offset = Vector2.Zero; + var deleteSelf = false; + + if (_time > ResetTime) + { + deleteSelf = true; + } + else + { + offset = _angle.RotateVec((BaseOffset, 0)); + offset *= (ResetTime - _time) / ResetTime; + } + + if (Owner.TryGetComponent(out CameraRecoilComponent recoilComponent)) + { + recoilComponent.BaseOffset = offset; + } + else if (Owner.TryGetComponent(out EyeComponent eyeComponent)) + { + eyeComponent.Offset = offset; + } + + if (Owner.TryGetComponent(out ISpriteComponent spriteComponent)) + { + // We have to account for rotation so the offset still checks out. + // SpriteComponent.Offset is applied before transform rotation (as expected). + var worldRotation = Owner.Transform.WorldRotation; + spriteComponent.Offset = new Angle(-worldRotation).RotateVec(offset); + } + + if (deleteSelf) + { + Owner.RemoveComponent(); + } + } + } +} diff --git a/Content.Client/GameObjects/Components/Weapons/Melee/MeleeWeaponArcAnimationComponent.cs b/Content.Client/GameObjects/Components/Weapons/Melee/MeleeWeaponArcAnimationComponent.cs new file mode 100644 index 0000000000..f2e2964c2b --- /dev/null +++ b/Content.Client/GameObjects/Components/Weapons/Melee/MeleeWeaponArcAnimationComponent.cs @@ -0,0 +1,67 @@ +using Content.Shared.GameObjects.Components.Weapons.Melee; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Shared.GameObjects; +using Robust.Shared.Maths; + +namespace Content.Client.GameObjects.Components.Weapons.Melee +{ + [RegisterComponent] + public sealed class MeleeWeaponArcAnimationComponent : Component + { + public override string Name => "MeleeWeaponArcAnimation"; + + private MeleeWeaponAnimationPrototype _meleeWeaponAnimation; + + private float _timer; + private SpriteComponent _sprite; + private Angle _baseAngle; + + public override void Initialize() + { + base.Initialize(); + + _sprite = Owner.GetComponent(); + } + + public void SetData(MeleeWeaponAnimationPrototype prototype, Angle baseAngle) + { + _meleeWeaponAnimation = prototype; + _sprite.AddLayer(new RSI.StateId(prototype.State)); + _baseAngle = baseAngle; + } + + internal void Update(float frameTime) + { + if (_meleeWeaponAnimation == null) + { + return; + } + + _timer += frameTime; + + var (r, g, b, a) = + Vector4.Clamp(_meleeWeaponAnimation.Color + _meleeWeaponAnimation.ColorDelta * _timer, Vector4.Zero, Vector4.One); + _sprite.Color = new Color(r, g, b, a); + + switch (_meleeWeaponAnimation.ArcType) + { + case WeaponArcType.Slash: + var angle = Angle.FromDegrees(_meleeWeaponAnimation.Width)/2; + Owner.Transform.LocalRotation = + _baseAngle + Angle.Lerp(-angle, angle, (float) (_timer / _meleeWeaponAnimation.Length.TotalSeconds)); + break; + + case WeaponArcType.Poke: + _sprite.Offset += (_meleeWeaponAnimation.Speed * frameTime, 0); + break; + } + + + if (_meleeWeaponAnimation.Length.TotalSeconds <= _timer) + { + Owner.Delete(); + } + } + } +} diff --git a/Content.Client/GameObjects/EntitySystems/CombatModeSystem.cs b/Content.Client/GameObjects/EntitySystems/CombatModeSystem.cs new file mode 100644 index 0000000000..850e61f477 --- /dev/null +++ b/Content.Client/GameObjects/EntitySystems/CombatModeSystem.cs @@ -0,0 +1,33 @@ +using Content.Client.UserInterface; +using Content.Shared.GameObjects.Components.Mobs; +using Content.Shared.GameObjects.EntitySystemMessages; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.IoC; + +namespace Content.Client.GameObjects.EntitySystems +{ + public sealed class CombatModeSystem : EntitySystem + { +#pragma warning disable 649 + [Dependency] private readonly IGameHud _gameHud; +#pragma warning restore 649 + + public override void Initialize() + { + base.Initialize(); + + _gameHud.OnCombatModeChanged = OnCombatModeChanged; + _gameHud.OnTargetingZoneChanged = OnTargetingZoneChanged; + } + + private void OnTargetingZoneChanged(TargetingZone obj) + { + RaiseNetworkEvent(new CombatModeSystemMessages.SetTargetZoneMessage(obj)); + } + + private void OnCombatModeChanged(bool obj) + { + RaiseNetworkEvent(new CombatModeSystemMessages.SetCombatModeActiveMessage(obj)); + } + } +} diff --git a/Content.Client/GameObjects/EntitySystems/MeleeLungeSystem.cs b/Content.Client/GameObjects/EntitySystems/MeleeLungeSystem.cs new file mode 100644 index 0000000000..bff419b8ab --- /dev/null +++ b/Content.Client/GameObjects/EntitySystems/MeleeLungeSystem.cs @@ -0,0 +1,28 @@ +using Content.Client.GameObjects.Components.Mobs; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Systems; + +namespace Content.Client.GameObjects.EntitySystems +{ + [UsedImplicitly] + public sealed class MeleeLungeSystem : EntitySystem + { + public override void Initialize() + { + base.Initialize(); + + EntityQuery = new TypeEntityQuery(); + } + + public override void FrameUpdate(float frameTime) + { + base.FrameUpdate(frameTime); + + foreach (var entity in RelevantEntities) + { + entity.GetComponent().Update(frameTime); + } + } + } +} diff --git a/Content.Client/GameObjects/EntitySystems/MeleeWeaponSystem.cs b/Content.Client/GameObjects/EntitySystems/MeleeWeaponSystem.cs new file mode 100644 index 0000000000..93871ede55 --- /dev/null +++ b/Content.Client/GameObjects/EntitySystems/MeleeWeaponSystem.cs @@ -0,0 +1,101 @@ +using System.Linq; +using Content.Client.GameObjects.Components.Mobs; +using Content.Client.GameObjects.Components.Weapons.Melee; +using Content.Shared.GameObjects.Components.Weapons.Melee; +using JetBrains.Annotations; +using Robust.Client.Interfaces.GameObjects.Components; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Interfaces.Network; +using Robust.Shared.IoC; +using Robust.Shared.Log; +using Robust.Shared.Maths; +using Robust.Shared.Prototypes; +using Robust.Shared.Timers; +using static Content.Shared.GameObjects.EntitySystemMessages.MeleeWeaponSystemMessages; + +namespace Content.Client.GameObjects.EntitySystems +{ + [UsedImplicitly] + public sealed class MeleeWeaponSystem : EntitySystem + { +#pragma warning disable 649 + [Dependency] private readonly IPrototypeManager _prototypeManager; +#pragma warning restore 649 + + public override void Initialize() + { + base.Initialize(); + + EntityQuery = new TypeEntityQuery(typeof(MeleeWeaponArcAnimationComponent)); + } + + public override void RegisterMessageTypes() + { + base.RegisterMessageTypes(); + + RegisterMessageType(); + } + + public override void HandleNetMessage(INetChannel channel, EntitySystemMessage message) + { + base.HandleNetMessage(channel, message); + + switch (message) + { + case PlayMeleeWeaponAnimationMessage playMsg: + PlayWeaponArc(playMsg); + break; + } + } + + public override void FrameUpdate(float frameTime) + { + base.FrameUpdate(frameTime); + + foreach (var entity in RelevantEntities) + { + entity.GetComponent().Update(frameTime); + } + } + + private void PlayWeaponArc(PlayMeleeWeaponAnimationMessage msg) + { + if (!_prototypeManager.TryIndex(msg.ArcPrototype, out MeleeWeaponAnimationPrototype weaponArc)) + { + Logger.Error("Tried to play unknown weapon arc prototype '{0}'", msg.ArcPrototype); + return; + } + + var attacker = EntityManager.GetEntity(msg.Attacker); + + var lunge = attacker.EnsureComponent(); + lunge.SetData(msg.Angle); + + var entity = EntityManager.SpawnEntityAt("WeaponArc", attacker.Transform.GridPosition); + entity.Transform.LocalRotation = msg.Angle; + + var weaponArcAnimation = entity.GetComponent(); + weaponArcAnimation.SetData(weaponArc, msg.Angle); + + + foreach (var hitEntity in msg.Hits.Select(u => EntityManager.GetEntity(u))) + { + if (!hitEntity.TryGetComponent(out ISpriteComponent sprite)) continue; + + var originalColor = sprite.Color; + var newColor = Color.Red * originalColor; + sprite.Color = newColor; + + Timer.Spawn(100, () => + { + // Only reset back to the original color if something else didn't change the color in the mean time. + if (sprite.Color == newColor) + { + sprite.Color = originalColor; + } + }); + } + } + } +} diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs index 13c5a43518..bf8a3749db 100644 --- a/Content.Client/Input/ContentContexts.cs +++ b/Content.Client/Input/ContentContexts.cs @@ -27,8 +27,7 @@ namespace Content.Client.Input human.AddFunction(ContentKeyFunctions.OpenCraftingMenu); human.AddFunction(ContentKeyFunctions.OpenInventoryMenu); human.AddFunction(ContentKeyFunctions.MouseMiddle); - // Disabled until there is feedback, so hitting tab doesn't suddenly break interaction. - // human.AddFunction(ContentKeyFunctions.ToggleCombatMode); + human.AddFunction(ContentKeyFunctions.ToggleCombatMode); var ghost = contexts.New("ghost", "common"); ghost.AddFunction(EngineKeyFunctions.MoveUp); diff --git a/Content.Client/UserInterface/GameHud.cs b/Content.Client/UserInterface/GameHud.cs index c8e7c70f53..3c4182b77b 100644 --- a/Content.Client/UserInterface/GameHud.cs +++ b/Content.Client/UserInterface/GameHud.cs @@ -1,5 +1,6 @@ using System; using Content.Client.Utility; +using Content.Shared.GameObjects.Components.Mobs; using Content.Shared.Input; using Robust.Client.Graphics; using Robust.Client.Graphics.Drawing; @@ -48,6 +49,13 @@ namespace Content.Client.UserInterface Control HandsContainer { get; } Control InventoryQuickButtonContainer { get; } + bool CombatPanelVisible { get; set; } + bool CombatModeActive { get; set; } + TargetingZone TargetingZone { get; set; } + Action OnCombatModeChanged { get; set; } + Action OnTargetingZoneChanged { get; set; } + + // Init logic. void Initialize(); } @@ -62,6 +70,9 @@ namespace Content.Client.UserInterface private TopButton _buttonCraftingMenu; private TopButton _buttonSandboxMenu; private TutorialWindow _tutorialWindow; + private TargetingDoll _targetingDoll; + private Button _combatModeButton; + private VBoxContainer _combatPanelContainer; #pragma warning disable 649 [Dependency] private readonly IResourceCache _resourceCache; @@ -71,6 +82,26 @@ namespace Content.Client.UserInterface public Control HandsContainer { get; private set; } public Control InventoryQuickButtonContainer { get; private set; } + public bool CombatPanelVisible + { + get => _combatPanelContainer.Visible; + set => _combatPanelContainer.Visible = value; + } + + public bool CombatModeActive + { + get => _combatModeButton.Pressed; + set => _combatModeButton.Pressed = value; + } + + public TargetingZone TargetingZone + { + get => _targetingDoll.ActiveZone; + set => _targetingDoll.ActiveZone = value; + } + + public Action OnCombatModeChanged { get; set; } + public Action OnTargetingZoneChanged { get; set; } public void Initialize() { @@ -179,16 +210,35 @@ namespace Content.Client.UserInterface { GrowHorizontal = Control.GrowDirection.Begin, GrowVertical = Control.GrowDirection.Begin, + SizeFlagsVertical = Control.SizeFlags.ShrinkEnd }; HandsContainer = new MarginContainer { GrowHorizontal = Control.GrowDirection.Both, - GrowVertical = Control.GrowDirection.Begin + GrowVertical = Control.GrowDirection.Begin, + SizeFlagsVertical = Control.SizeFlags.ShrinkEnd }; + _combatPanelContainer = new VBoxContainer + { + Children = + { + (_combatModeButton = new Button + { + Text = _loc.GetString("Combat Mode"), + ToggleMode = true + }), + (_targetingDoll = new TargetingDoll(_resourceCache)) + } + }; + + _combatModeButton.OnToggled += args => OnCombatModeChanged?.Invoke(args.Pressed); + _targetingDoll.OnZoneChanged += args => OnTargetingZoneChanged?.Invoke(args); + inventoryContainer.Children.Add(HandsContainer); inventoryContainer.Children.Add(InventoryQuickButtonContainer); + inventoryContainer.Children.Add(_combatPanelContainer); } private void ButtonTutorialOnOnToggled() diff --git a/Content.Client/UserInterface/NanoStyle.cs b/Content.Client/UserInterface/NanoStyle.cs index b4ddfed847..fd0df7a970 100644 --- a/Content.Client/UserInterface/NanoStyle.cs +++ b/Content.Client/UserInterface/NanoStyle.cs @@ -481,6 +481,23 @@ namespace Content.Client.UserInterface { new StyleProperty(Label.StylePropertyFont, notoSansDisplayBold14), }), + + // Targeting doll + + new StyleRule(new SelectorElement(typeof(TextureButton), new []{TargetingDoll.StyleClassTargetDollZone}, null, new [] {TextureButton.StylePseudoClassNormal}), new [] + { + new StyleProperty(Control.StylePropertyModulateSelf, Color.FromHex("#F00")), + }), + + new StyleRule(new SelectorElement(typeof(TextureButton), new []{TargetingDoll.StyleClassTargetDollZone}, null, new [] {TextureButton.StylePseudoClassHover}), new [] + { + new StyleProperty(Control.StylePropertyModulateSelf, Color.FromHex("#0F0")), + }), + + new StyleRule(new SelectorElement(typeof(TextureButton), new []{TargetingDoll.StyleClassTargetDollZone}, null, new [] {TextureButton.StylePseudoClassPressed}), new [] + { + new StyleProperty(Control.StylePropertyModulateSelf, Color.FromHex("#00F")), + }), }); } } diff --git a/Content.Client/UserInterface/TargetingDoll.cs b/Content.Client/UserInterface/TargetingDoll.cs new file mode 100644 index 0000000000..e631be946c --- /dev/null +++ b/Content.Client/UserInterface/TargetingDoll.cs @@ -0,0 +1,82 @@ +using System; +using Content.Client.Utility; +using Content.Shared.GameObjects.Components.Mobs; +using Robust.Client.Interfaces.ResourceManagement; +using Robust.Client.UserInterface.Controls; + +namespace Content.Client.UserInterface +{ + public sealed class TargetingDoll : VBoxContainer + { + private TargetingZone _activeZone = TargetingZone.Middle; + public const string StyleClassTargetDollZone = "target-doll-zone"; + + private const string TextureHigh = "/Textures/UserInterface/target-doll-high.svg.96dpi.png"; + private const string TextureMiddle = "/Textures/UserInterface/target-doll-middle.svg.96dpi.png"; + private const string TextureLow = "/Textures/UserInterface/target-doll-low.svg.96dpi.png"; + + private readonly TextureButton _buttonHigh; + private readonly TextureButton _buttonMiddle; + private readonly TextureButton _buttonLow; + + public TargetingZone ActiveZone + { + get => _activeZone; + set + { + if (_activeZone == value) + { + return; + } + + _activeZone = value; + OnZoneChanged?.Invoke(value); + + UpdateButtons(); + } + } + + public event Action OnZoneChanged; + + public TargetingDoll(IResourceCache resourceCache) + { + _buttonHigh = new TextureButton + { + TextureNormal = resourceCache.GetTexture(TextureHigh), + StyleClasses = {StyleClassTargetDollZone}, + SizeFlagsHorizontal = SizeFlags.ShrinkCenter + }; + + _buttonMiddle = new TextureButton + { + TextureNormal = resourceCache.GetTexture(TextureMiddle), + StyleClasses = {StyleClassTargetDollZone}, + SizeFlagsHorizontal = SizeFlags.ShrinkCenter + }; + + _buttonLow = new TextureButton + { + TextureNormal = resourceCache.GetTexture(TextureLow), + StyleClasses = {StyleClassTargetDollZone}, + SizeFlagsHorizontal = SizeFlags.ShrinkCenter + }; + + _buttonHigh.OnPressed += _ => ActiveZone = TargetingZone.High; + _buttonMiddle.OnPressed += _ => ActiveZone = TargetingZone.Middle; + _buttonLow.OnPressed += _ => ActiveZone = TargetingZone.Low; + + AddChild(_buttonHigh); + AddChild(_buttonMiddle); + AddChild(_buttonLow); + + UpdateButtons(); + } + + private void UpdateButtons() + { + _buttonHigh.Pressed = _activeZone == TargetingZone.High; + _buttonMiddle.Pressed = _activeZone == TargetingZone.Middle; + _buttonLow.Pressed = _activeZone == TargetingZone.Low; + } + } +} diff --git a/Content.Server/GameObjects/Components/Mobs/CombatModeComponent.cs b/Content.Server/GameObjects/Components/Mobs/CombatModeComponent.cs index d5078ec107..f8547b0830 100644 --- a/Content.Server/GameObjects/Components/Mobs/CombatModeComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/CombatModeComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared.GameObjects.Components.Mobs; using Robust.Shared.GameObjects; using Robust.Shared.ViewVariables; @@ -9,11 +10,36 @@ namespace Content.Server.GameObjects.Components.Mobs /// using *everything* as a weapon. /// [RegisterComponent] - public sealed class CombatModeComponent : Component + public sealed class CombatModeComponent : SharedCombatModeComponent { - public override string Name => "CombatMode"; + private bool _isInCombatMode; + private TargetingZone _activeZone; [ViewVariables(VVAccess.ReadWrite)] - public bool IsInCombatMode { get; set; } + public bool IsInCombatMode + { + get => _isInCombatMode; + set + { + _isInCombatMode = value; + Dirty(); + } + } + + [ViewVariables(VVAccess.ReadWrite)] + public TargetingZone ActiveZone + { + get => _activeZone; + set + { + _activeZone = value; + Dirty(); + } + } + + public override ComponentState GetComponentState() + { + return new CombatModeComponentState(IsInCombatMode, ActiveZone); + } } } diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs index 6f9cb85961..622fc3cc64 100644 --- a/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs @@ -1,43 +1,91 @@ -using Content.Server.GameObjects.EntitySystems; +using System.Collections.Generic; +using System.Linq; +using Content.Server.GameObjects.Components.Mobs; +using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects; +using Robust.Server.GameObjects.EntitySystems; using Robust.Server.Interfaces.GameObjects; using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; +using Robust.Shared.Interfaces.Timing; using Robust.Shared.IoC; using Robust.Shared.Maths; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; +using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Weapon.Melee { [RegisterComponent] public class MeleeWeaponComponent : Component, IAttack { + public override string Name => "MeleeWeapon"; + #pragma warning disable 649 [Dependency] private readonly IMapManager _mapManager; [Dependency] private readonly IServerEntityManager _serverEntityManager; + [Dependency] private readonly IEntitySystemManager _entitySystemManager; + [Dependency] private readonly IGameTiming _gameTiming; + [Dependency] private readonly IPrototypeManager _prototypeManager; #pragma warning restore 649 - public override string Name => "MeleeWeapon"; + private int _damage = 1; + private float _range = 1; + private float _arcWidth = 90; + private string _arc; + private string _hitSound; - public int Damage = 1; - public float Range = 1; - public float ArcWidth = 90; + [ViewVariables(VVAccess.ReadWrite)] + public string Arc + { + get => _arc; + set => _arc = value; + } + + [ViewVariables(VVAccess.ReadWrite)] + public float ArcWidth + { + get => _arcWidth; + set => _arcWidth = value; + } + + [ViewVariables(VVAccess.ReadWrite)] + public float Range + { + get => _range; + set => _range = value; + } + + [ViewVariables(VVAccess.ReadWrite)] + public int Damage + { + get => _damage; + set => _damage = value; + } public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); - serializer.DataField(ref Damage, "damage", 5); - serializer.DataField(ref Range, "range", 1); - serializer.DataField(ref ArcWidth, "arcwidth", 90); + serializer.DataField(ref _damage, "damage", 5); + serializer.DataField(ref _range, "range", 1); + serializer.DataField(ref _arcWidth, "arcwidth", 90); + serializer.DataField(ref _arc, "arc", "default"); + serializer.DataField(ref _hitSound, "hitSound", "/Audio/weapons/genhit1.ogg"); } void IAttack.Attack(AttackEventArgs eventArgs) { var location = eventArgs.User.Transform.GridPosition; - var angle = new Angle(eventArgs.ClickLocation.ToWorld(_mapManager).Position - location.ToWorld(_mapManager).Position); - var entities = _serverEntityManager.GetEntitiesInArc(eventArgs.User.Transform.GridPosition, Range, angle, ArcWidth); + var angle = new Angle(eventArgs.ClickLocation.ToWorld(_mapManager).Position - + location.ToWorld(_mapManager).Position); + // This should really be improved. GetEntitiesInArc uses pos instead of bounding boxes. + var entities = + _serverEntityManager.GetEntitiesInArc(eventArgs.User.Transform.GridPosition, Range, angle, ArcWidth); + + var hitEntities = new List(); foreach (var entity in entities) { if (!entity.Transform.IsMapTransform || entity == eventArgs.User) @@ -46,8 +94,18 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee if (entity.TryGetComponent(out DamageableComponent damageComponent)) { damageComponent.TakeDamage(DamageType.Brute, Damage); + hitEntities.Add(entity); } } + + var audioSystem = _entitySystemManager.GetEntitySystem(); + audioSystem.Play(hitEntities.Count > 0 ? _hitSound : "/Audio/weapons/punchmiss.ogg"); + + if (Arc != null) + { + var sys = _entitySystemManager.GetEntitySystem(); + sys.SendAnimation(Arc, angle, eventArgs.User, hitEntities); + } } } } diff --git a/Content.Server/GameObjects/EntitySystems/CombatModeSystem.cs b/Content.Server/GameObjects/EntitySystems/CombatModeSystem.cs index 2e94e1eead..cf1c98670c 100644 --- a/Content.Server/GameObjects/EntitySystems/CombatModeSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/CombatModeSystem.cs @@ -1,15 +1,25 @@ using Content.Server.GameObjects.Components.Mobs; using Content.Shared.Input; +using JetBrains.Annotations; using Robust.Server.GameObjects.EntitySystems; using Robust.Server.Interfaces.Player; +using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Input; +using Robust.Shared.Interfaces.Network; +using Robust.Shared.IoC; using Robust.Shared.Players; +using static Content.Shared.GameObjects.EntitySystemMessages.CombatModeSystemMessages; namespace Content.Server.GameObjects.EntitySystems { + [UsedImplicitly] public sealed class CombatModeSystem : EntitySystem { +#pragma warning disable 649 + [Dependency] private readonly IPlayerManager _playerManager; +#pragma warning restore 649 + public override void Initialize() { base.Initialize(); @@ -19,7 +29,15 @@ namespace Content.Server.GameObjects.EntitySystems InputCmdHandler.FromDelegate(CombatModeToggled)); } - private void CombatModeToggled(ICommonSession session) + public override void RegisterMessageTypes() + { + base.RegisterMessageTypes(); + + RegisterMessageType(); + RegisterMessageType(); + } + + private static void CombatModeToggled(ICommonSession session) { var playerSession = (IPlayerSession) session; @@ -31,5 +49,28 @@ namespace Content.Server.GameObjects.EntitySystems combatModeComponent.IsInCombatMode = !combatModeComponent.IsInCombatMode; } + + public override void HandleNetMessage(INetChannel channel, EntitySystemMessage message) + { + base.HandleNetMessage(channel, message); + + var player = _playerManager.GetSessionByChannel(channel); + if (player.AttachedEntity == null + || !player.AttachedEntity.TryGetComponent(out CombatModeComponent combatModeComponent)) + { + return; + } + + switch (message) + { + case SetTargetZoneMessage setTargetZone: + combatModeComponent.ActiveZone = setTargetZone.TargetZone; + break; + + case SetCombatModeActiveMessage setActive: + combatModeComponent.IsInCombatMode = setActive.Active; + break; + } + } } } diff --git a/Content.Server/GameObjects/EntitySystems/MeleeWeaponSystem.cs b/Content.Server/GameObjects/EntitySystems/MeleeWeaponSystem.cs new file mode 100644 index 0000000000..82ba72537a --- /dev/null +++ b/Content.Server/GameObjects/EntitySystems/MeleeWeaponSystem.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Linq; +using Content.Shared.GameObjects.EntitySystemMessages; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Maths; + +namespace Content.Server.GameObjects.EntitySystems +{ + public sealed class MeleeWeaponSystem : EntitySystem + { + public void SendAnimation(string arc, Angle angle, IEntity attacker, IEnumerable hits) + { + RaiseNetworkEvent(new MeleeWeaponSystemMessages.PlayMeleeWeaponAnimationMessage(arc, angle, attacker.Uid, + hits.Select(e => e.Uid).ToList())); + } + } +} diff --git a/Content.Shared/GameObjects/Components/Mobs/SharedCombatModeComponent.cs b/Content.Shared/GameObjects/Components/Mobs/SharedCombatModeComponent.cs new file mode 100644 index 0000000000..6275aa8a38 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Mobs/SharedCombatModeComponent.cs @@ -0,0 +1,27 @@ +using System; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.Components.Mobs +{ + public abstract class SharedCombatModeComponent : Component + { + public sealed override uint? NetID => ContentNetIDs.COMBATMODE; + public override string Name => "CombatMode"; + public sealed override Type StateType => typeof(CombatModeComponentState); + + [Serializable, NetSerializable] + protected sealed class CombatModeComponentState : ComponentState + { + public bool IsInCombatMode { get; } + public TargetingZone TargetingZone { get; } + + public CombatModeComponentState(bool isInCombatMode, TargetingZone targetingZone) + : base(ContentNetIDs.COMBATMODE) + { + IsInCombatMode = isInCombatMode; + TargetingZone = targetingZone; + } + } + } +} diff --git a/Content.Shared/GameObjects/Components/Mobs/TargetingZone.cs b/Content.Shared/GameObjects/Components/Mobs/TargetingZone.cs new file mode 100644 index 0000000000..307c36b97c --- /dev/null +++ b/Content.Shared/GameObjects/Components/Mobs/TargetingZone.cs @@ -0,0 +1,27 @@ +using System; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.Components.Mobs +{ + /// + /// Zones the player can target for attacks. + /// + [Serializable, NetSerializable] + public enum TargetingZone + { + /// + /// Torso/arm area. + /// + Middle, + + /// + /// Legs/groin area. + /// + Low, + + /// + /// Go for the head. + /// + High + } +} diff --git a/Content.Shared/GameObjects/Components/Weapons/Melee/MeleeWeaponAnimationPrototype.cs b/Content.Shared/GameObjects/Components/Weapons/Melee/MeleeWeaponAnimationPrototype.cs new file mode 100644 index 0000000000..765cb0882b --- /dev/null +++ b/Content.Shared/GameObjects/Components/Weapons/Melee/MeleeWeaponAnimationPrototype.cs @@ -0,0 +1,59 @@ +using System; +using Robust.Shared.Maths; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using Robust.Shared.ViewVariables; +using YamlDotNet.RepresentationModel; + +namespace Content.Shared.GameObjects.Components.Weapons.Melee +{ + [Prototype("MeleeWeaponAnimation")] + public sealed class MeleeWeaponAnimationPrototype : IPrototype, IIndexedPrototype + { + private string _state; + private string _id; + private Vector4 _colorDelta; + private Vector4 _color; + private TimeSpan _length; + private float _speed; + private float _width; + private WeaponArcType _arcType; + + [ViewVariables] public string ID => _id; + [ViewVariables] public string State => _state; + [ViewVariables] public TimeSpan Length => _length; + [ViewVariables] public float Speed => _speed; + [ViewVariables] public Vector4 Color => _color; + [ViewVariables] public Vector4 ColorDelta => _colorDelta; + [ViewVariables] public WeaponArcType ArcType => _arcType; + [ViewVariables] public float Width => _width; + + public void LoadFrom(YamlMappingNode mapping) + { + var serializer = YamlObjectSerializer.NewReader(mapping); + + serializer.DataField(ref _state, "state", null); + serializer.DataField(ref _id, "id", null); + serializer.DataField(ref _colorDelta, "colorDelta", Vector4.Zero); + serializer.DataField(ref _color, "color", new Vector4(1, 1, 1, 1)); + if (serializer.TryReadDataField("length", out float length)) + { + _length = TimeSpan.FromSeconds(length); + } + else + { + _length = TimeSpan.FromSeconds(0.5f); + } + + serializer.DataField(ref _speed, "speed", 1); + serializer.DataField(ref _arcType, "arcType", WeaponArcType.Slash); + serializer.DataField(ref _width, "width", 90); + } + } + + public enum WeaponArcType + { + Slash, + Poke, + } +} diff --git a/Content.Shared/GameObjects/ContentNetIDs.cs b/Content.Shared/GameObjects/ContentNetIDs.cs index 28d43f282a..3387bb90e4 100644 --- a/Content.Shared/GameObjects/ContentNetIDs.cs +++ b/Content.Shared/GameObjects/ContentNetIDs.cs @@ -28,5 +28,6 @@ public const uint TECHNOLOGY_DATABASE = 1022; public const uint RESEARCH_CONSOLE = 1023; public const uint WIRES = 1024; + public const uint COMBATMODE = 1025; } } diff --git a/Content.Shared/GameObjects/EntitySystemMessages/CombatModeSystemMessages.cs b/Content.Shared/GameObjects/EntitySystemMessages/CombatModeSystemMessages.cs new file mode 100644 index 0000000000..814d844c22 --- /dev/null +++ b/Content.Shared/GameObjects/EntitySystemMessages/CombatModeSystemMessages.cs @@ -0,0 +1,32 @@ +using System; +using Content.Shared.GameObjects.Components.Mobs; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.EntitySystemMessages +{ + public static class CombatModeSystemMessages + { + [Serializable, NetSerializable] + public sealed class SetTargetZoneMessage : EntitySystemMessage + { + public SetTargetZoneMessage(TargetingZone targetZone) + { + TargetZone = targetZone; + } + + public TargetingZone TargetZone { get; } + } + + [Serializable, NetSerializable] + public sealed class SetCombatModeActiveMessage : EntitySystemMessage + { + public SetCombatModeActiveMessage(bool active) + { + Active = active; + } + + public bool Active { get; } + } + } +} diff --git a/Content.Shared/GameObjects/EntitySystemMessages/MeleeWeaponSystemMessages.cs b/Content.Shared/GameObjects/EntitySystemMessages/MeleeWeaponSystemMessages.cs new file mode 100644 index 0000000000..9f250b4b24 --- /dev/null +++ b/Content.Shared/GameObjects/EntitySystemMessages/MeleeWeaponSystemMessages.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using Robust.Shared.GameObjects; +using Robust.Shared.Map; +using Robust.Shared.Maths; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.EntitySystemMessages +{ + public static class MeleeWeaponSystemMessages + { + [Serializable, NetSerializable] + public sealed class PlayMeleeWeaponAnimationMessage : EntitySystemMessage + { + public PlayMeleeWeaponAnimationMessage(string arcPrototype, Angle angle, EntityUid attacker, List hits) + { + ArcPrototype = arcPrototype; + Angle = angle; + Attacker = attacker; + Hits = hits; + } + + public string ArcPrototype { get; } + public Angle Angle { get; } + public EntityUid Attacker { get; } + public List Hits { get; } + } + } +} diff --git a/Resources/Audio/weapons/bladeslice.ogg b/Resources/Audio/weapons/bladeslice.ogg new file mode 100644 index 0000000000000000000000000000000000000000..ab8154ab9bd1456d40f85a75de9cf5d2fa50fb0c GIT binary patch literal 7691 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 literal 0 HcmV?d00001 diff --git a/Resources/Audio/weapons/genhit1.ogg b/Resources/Audio/weapons/genhit1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..65cd446c04a9d2240d1d25283968bc144bc8824a GIT binary patch literal 8655 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 literal 0 HcmV?d00001 diff --git a/Resources/Audio/weapons/genhit3.ogg b/Resources/Audio/weapons/genhit3.ogg new file mode 100644 index 0000000000000000000000000000000000000000..dd514bd17988b610c1fa8fe5cb92508b61ab2fec GIT binary patch literal 7943 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 QJ&sbnW$#rSjt7AM2VC%^@&Et; literal 0 HcmV?d00001 diff --git a/Resources/Audio/weapons/punch1.ogg b/Resources/Audio/weapons/punch1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..bf0f95fe2089470103df828a1b451e2d809f7f2d GIT binary patch literal 9174 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