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:
Pieter-Jan Briers
2020-01-26 03:38:51 +01:00
parent 7e43d574d8
commit 2ec493e2af
6 changed files with 182 additions and 15 deletions

View File

@@ -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));
}
}
}
}
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);
}
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>

View File

@@ -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";

View File

@@ -1,6 +1,6 @@
version: 1 # Not used right now, whatever.
binds:
- function: Use
- function: UseOrAttack
type: state
key: MouseLeft
canFocus: true