Combat mode improvements.
You now need to hold the mouse for 0.15 seconds in combat mode to actually do an attack. Otherwise it's regular item interaction (for now).
This commit is contained in:
@@ -1,23 +1,62 @@
|
||||
using Content.Client.GameObjects.Components.Mobs;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Content.Shared.GameObjects.EntitySystemMessages;
|
||||
using Content.Shared.Input;
|
||||
using Robust.Client.GameObjects.EntitySystems;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.Graphics.Overlays;
|
||||
using Robust.Client.Interfaces.Graphics.Overlays;
|
||||
using Robust.Client.Interfaces.Input;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Players;
|
||||
using static Content.Client.StaticIoC;
|
||||
|
||||
namespace Content.Client.GameObjects.EntitySystems
|
||||
{
|
||||
public sealed class CombatModeSystem : EntitySystem
|
||||
{
|
||||
private const float AttackTimeThreshold = 0.15f;
|
||||
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IGameHud _gameHud;
|
||||
[Dependency] private readonly IPlayerManager _playerManager;
|
||||
[Dependency] private readonly IInputManager _inputManager;
|
||||
[Dependency] private readonly IOverlayManager _overlayManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
private InputSystem _inputSystem;
|
||||
|
||||
public bool UseOrAttackIsDown { get; private set; }
|
||||
private float _timeHeld;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_gameHud.OnCombatModeChanged = OnCombatModeChanged;
|
||||
_gameHud.OnTargetingZoneChanged = OnTargetingZoneChanged;
|
||||
|
||||
_inputSystem = EntitySystemManager.GetEntitySystem<InputSystem>();
|
||||
_inputSystem.BindMap.BindFunction(ContentKeyFunctions.UseOrAttack, new InputHandler(this));
|
||||
|
||||
_overlayManager.AddOverlay(new CombatModeOverlay(this));
|
||||
}
|
||||
|
||||
private bool IsInCombatMode()
|
||||
{
|
||||
var entity = _playerManager.LocalPlayer.ControlledEntity;
|
||||
if (entity == null || !entity.TryGetComponent(out CombatModeComponent combatMode))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return combatMode.IsInCombatMode;
|
||||
}
|
||||
|
||||
private void OnTargetingZoneChanged(TargetingZone obj)
|
||||
@@ -28,6 +67,104 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
private void OnCombatModeChanged(bool obj)
|
||||
{
|
||||
RaiseNetworkEvent(new CombatModeSystemMessages.SetCombatModeActiveMessage(obj));
|
||||
|
||||
// Just in case.
|
||||
UseOrAttackIsDown = false;
|
||||
}
|
||||
|
||||
private bool HandleInputMessage(ICommonSession session, InputCmdMessage message)
|
||||
{
|
||||
if (!(message is FullInputCmdMessage msg))
|
||||
return false;
|
||||
|
||||
void SendMsg(BoundKeyFunction function, BoundKeyState state)
|
||||
{
|
||||
var functionId = _inputManager.NetworkBindMap.KeyFunctionID(function);
|
||||
|
||||
var sendMsg = new FullInputCmdMessage(msg.Tick, functionId, state,
|
||||
msg.Coordinates, msg.ScreenCoordinates, msg.Uid);
|
||||
_inputSystem.HandleInputCommand(session, function, sendMsg);
|
||||
}
|
||||
|
||||
// If we are not in combat mode, relay it as a regular Use instead.
|
||||
if (!IsInCombatMode())
|
||||
{
|
||||
SendMsg(EngineKeyFunctions.Use, msg.State);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (msg.State == BoundKeyState.Down)
|
||||
{
|
||||
UseOrAttackIsDown = true;
|
||||
_timeHeld = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Up.
|
||||
if (_timeHeld >= AttackTimeThreshold)
|
||||
{
|
||||
// Attack.
|
||||
SendMsg(ContentKeyFunctions.Attack, BoundKeyState.Down);
|
||||
SendMsg(ContentKeyFunctions.Attack, BoundKeyState.Up);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use.
|
||||
SendMsg(EngineKeyFunctions.Use, BoundKeyState.Down);
|
||||
SendMsg(EngineKeyFunctions.Use, BoundKeyState.Up);
|
||||
}
|
||||
|
||||
UseOrAttackIsDown = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void FrameUpdate(float frameTime)
|
||||
{
|
||||
if (UseOrAttackIsDown)
|
||||
{
|
||||
_timeHeld += frameTime;
|
||||
}
|
||||
}
|
||||
|
||||
// Custom input handler type so we get the ENTIRE InputCmdMessage.
|
||||
private sealed class InputHandler : InputCmdHandler
|
||||
{
|
||||
private readonly CombatModeSystem _combatModeSystem;
|
||||
|
||||
public InputHandler(CombatModeSystem combatModeSystem)
|
||||
{
|
||||
_combatModeSystem = combatModeSystem;
|
||||
}
|
||||
|
||||
public override bool HandleCmdMessage(ICommonSession session, InputCmdMessage message)
|
||||
{
|
||||
return _combatModeSystem.HandleInputMessage(session, message);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class CombatModeOverlay : Overlay
|
||||
{
|
||||
private readonly CombatModeSystem _system;
|
||||
|
||||
public CombatModeOverlay(CombatModeSystem system) : base(nameof(CombatModeOverlay))
|
||||
{
|
||||
_system = system;
|
||||
}
|
||||
|
||||
protected override void Draw(DrawingHandleBase handle)
|
||||
{
|
||||
var screenHandle = (DrawingHandleScreen) handle;
|
||||
|
||||
var mousePos = IoCManager.Resolve<IInputManager>().MouseScreenPosition;
|
||||
|
||||
if (_system.UseOrAttackIsDown && _system._timeHeld > AttackTimeThreshold)
|
||||
{
|
||||
var tex = ResC.GetTexture($"/Textures/Objects/Tools/toolbox_r.png");
|
||||
|
||||
screenHandle.DrawTextureRect(tex, UIBox2.FromDimensions(mousePos, tex.Size * 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Client.GameObjects.Components.Weapons.Ranged;
|
||||
using Content.Client.Interfaces.GameObjects;
|
||||
using Content.Shared.Input;
|
||||
using Robust.Client.GameObjects.EntitySystems;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
using Robust.Client.Interfaces.Input;
|
||||
@@ -20,6 +21,7 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
#pragma warning restore 649
|
||||
|
||||
private InputSystem _inputSystem;
|
||||
private CombatModeSystem _combatModeSystem;
|
||||
private bool _isFirstShot;
|
||||
private bool _blocked;
|
||||
|
||||
@@ -29,6 +31,7 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
|
||||
IoCManager.InjectDependencies(this);
|
||||
_inputSystem = EntitySystemManager.GetEntitySystem<InputSystem>();
|
||||
_combatModeSystem = EntitySystemManager.GetEntitySystem<CombatModeSystem>();
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
@@ -36,8 +39,8 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
base.Update(frameTime);
|
||||
|
||||
var canFireSemi = _isFirstShot;
|
||||
var state = _inputSystem.CmdStates.GetState(EngineKeyFunctions.Use);
|
||||
if (state != BoundKeyState.Down)
|
||||
var state = _inputSystem.CmdStates.GetState(ContentKeyFunctions.Attack);
|
||||
if (!_combatModeSystem.UseOrAttackIsDown && state != BoundKeyState.Down)
|
||||
{
|
||||
_isFirstShot = true;
|
||||
_blocked = false;
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace Content.Client.Input
|
||||
common.AddFunction(ContentKeyFunctions.FocusChat);
|
||||
common.AddFunction(ContentKeyFunctions.ExamineEntity);
|
||||
common.AddFunction(ContentKeyFunctions.OpenTutorial);
|
||||
common.AddFunction(ContentKeyFunctions.UseOrAttack);
|
||||
|
||||
var human = contexts.GetContext("human");
|
||||
human.AddFunction(ContentKeyFunctions.SwapHands);
|
||||
@@ -28,6 +29,7 @@ namespace Content.Client.Input
|
||||
human.AddFunction(ContentKeyFunctions.OpenInventoryMenu);
|
||||
human.AddFunction(ContentKeyFunctions.MouseMiddle);
|
||||
human.AddFunction(ContentKeyFunctions.ToggleCombatMode);
|
||||
human.AddFunction(ContentKeyFunctions.Attack);
|
||||
|
||||
var ghost = contexts.New("ghost", "common");
|
||||
ghost.AddFunction(EngineKeyFunctions.MoveUp);
|
||||
|
||||
@@ -257,6 +257,8 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
var inputSys = EntitySystemManager.GetEntitySystem<InputSystem>();
|
||||
inputSys.BindMap.BindFunction(EngineKeyFunctions.Use,
|
||||
new PointerInputCmdHandler(HandleUseItemInHand));
|
||||
inputSys.BindMap.BindFunction(ContentKeyFunctions.Attack,
|
||||
new PointerInputCmdHandler(HandleAttack));
|
||||
inputSys.BindMap.BindFunction(ContentKeyFunctions.ActivateItemInWorld,
|
||||
new PointerInputCmdHandler(HandleActivateItemInWorld));
|
||||
}
|
||||
@@ -313,6 +315,37 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
activateComp.Activate(new ActivateEventArgs {User = user});
|
||||
}
|
||||
|
||||
private bool HandleAttack(ICommonSession session, GridCoordinates coords, EntityUid uid)
|
||||
{
|
||||
// client sanitization
|
||||
if (!_mapManager.GridExists(coords.GridID))
|
||||
{
|
||||
Logger.InfoS("system.interaction", $"Invalid Coordinates: client={session}, coords={coords}");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (uid.IsClientSide())
|
||||
{
|
||||
Logger.WarningS("system.interaction",
|
||||
$"Client sent attack with client-side entity. Session={session}, Uid={uid}");
|
||||
return true;
|
||||
}
|
||||
|
||||
var userEntity = ((IPlayerSession) session).AttachedEntity;
|
||||
|
||||
if (userEntity == null || !userEntity.IsValid())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (userEntity.TryGetComponent(out CombatModeComponent combatMode) && combatMode.IsInCombatMode)
|
||||
{
|
||||
DoAttack(userEntity, coords);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandleUseItemInHand(ICommonSession session, GridCoordinates coords, EntityUid uid)
|
||||
{
|
||||
// client sanitization
|
||||
@@ -336,14 +369,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
return true;
|
||||
}
|
||||
|
||||
if (userEntity.TryGetComponent(out CombatModeComponent combatMode) && combatMode.IsInCombatMode)
|
||||
{
|
||||
DoAttack(userEntity, coords);
|
||||
}
|
||||
else
|
||||
{
|
||||
UserInteraction(userEntity, coords, uid);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -561,10 +587,9 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
/// </summary>
|
||||
public void UseInteraction(IEntity user, IEntity used)
|
||||
{
|
||||
|
||||
if (used.TryGetComponent<UseDelayComponent>(out var delayComponent))
|
||||
{
|
||||
if(delayComponent.ActiveDelay)
|
||||
if (delayComponent.ActiveDelay)
|
||||
return;
|
||||
else
|
||||
delayComponent.BeginDelay();
|
||||
@@ -600,7 +625,6 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
|
||||
ThrownInteraction(user, item);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -657,7 +681,6 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
|
||||
DroppedInteraction(user, item);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -5,6 +5,8 @@ namespace Content.Shared.Input
|
||||
[KeyFunctions]
|
||||
public static class ContentKeyFunctions
|
||||
{
|
||||
public static readonly BoundKeyFunction UseOrAttack = "UseOrAttack";
|
||||
public static readonly BoundKeyFunction Attack = "Attack";
|
||||
public static readonly BoundKeyFunction ActivateItemInHand = "ActivateItemInHand";
|
||||
public static readonly BoundKeyFunction ActivateItemInWorld = "ActivateItemInWorld"; // default action on world entity
|
||||
public static readonly BoundKeyFunction Drop = "Drop";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
version: 1 # Not used right now, whatever.
|
||||
binds:
|
||||
- function: Use
|
||||
- function: UseOrAttack
|
||||
type: state
|
||||
key: MouseLeft
|
||||
canFocus: true
|
||||
|
||||
Reference in New Issue
Block a user