* #3814 - dropping an item, which adds an action to the actions bar, will no longer leave weird ui glitch in actions bar * #3814 - small reformat + minor style tweaks * #3814 - bit better working ActionMenu locking + added missing toolips for ActionMenu lock and OpenAbilities button * #3814 - tooltip text typo fix * #3814 - incorporated suggestions * #3814 localization tweaks
269 lines
9.5 KiB
C#
269 lines
9.5 KiB
C#
using System.Collections.Generic;
|
|
using Content.Client.Actions.Assignments;
|
|
using Content.Client.Actions.UI;
|
|
using Content.Client.Hands;
|
|
using Content.Client.Inventory;
|
|
using Content.Client.Items.UI;
|
|
using Content.Shared.Actions.Components;
|
|
using Content.Shared.Actions.Prototypes;
|
|
using Robust.Client.GameObjects;
|
|
using Robust.Client.Player;
|
|
using Robust.Client.UserInterface;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.Input.Binding;
|
|
using Robust.Shared.IoC;
|
|
using Robust.Shared.Log;
|
|
using Robust.Shared.ViewVariables;
|
|
|
|
namespace Content.Client.Actions
|
|
{
|
|
/// <inheritdoc/>
|
|
[RegisterComponent]
|
|
[ComponentReference(typeof(SharedActionsComponent))]
|
|
public sealed class ClientActionsComponent : SharedActionsComponent
|
|
{
|
|
public const byte Hotbars = 9;
|
|
public const byte Slots = 10;
|
|
|
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
|
|
|
[ComponentDependency] private readonly HandsComponent? _handsComponent = null;
|
|
[ComponentDependency] private readonly ClientInventoryComponent? _inventoryComponent = null;
|
|
|
|
private ActionsUI? _ui;
|
|
private readonly List<ItemSlotButton> _highlightingItemSlots = new();
|
|
|
|
/// <summary>
|
|
/// Current assignments for all hotbars / slots for this entity.
|
|
/// </summary>
|
|
public ActionAssignments Assignments { get; } = new(Hotbars, Slots);
|
|
|
|
/// <summary>
|
|
/// Allows calculating if we need to act due to this component being controlled by the current mob
|
|
/// </summary>
|
|
[ViewVariables]
|
|
private bool CurrentlyControlled => _playerManager.LocalPlayer != null && _playerManager.LocalPlayer.ControlledEntity == Owner;
|
|
|
|
|
|
protected override void Shutdown()
|
|
{
|
|
base.Shutdown();
|
|
PlayerDetached();
|
|
}
|
|
|
|
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
|
|
{
|
|
base.HandleComponentState(curState, nextState);
|
|
|
|
if (curState is not ActionComponentState)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UpdateUI();
|
|
}
|
|
|
|
public void PlayerAttached()
|
|
{
|
|
if (!CurrentlyControlled || _ui != null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_ui = new ActionsUI(this);
|
|
IoCManager.Resolve<IUserInterfaceManager>().StateRoot.AddChild(_ui);
|
|
UpdateUI();
|
|
}
|
|
|
|
public void PlayerDetached()
|
|
{
|
|
if (_ui == null) return;
|
|
IoCManager.Resolve<IUserInterfaceManager>().StateRoot.RemoveChild(_ui);
|
|
_ui = null;
|
|
}
|
|
|
|
public void HandleHotbarKeybind(byte slot, in PointerInputCmdHandler.PointerInputCmdArgs args)
|
|
{
|
|
_ui?.HandleHotbarKeybind(slot, args);
|
|
}
|
|
|
|
public void HandleChangeHotbarKeybind(byte hotbar, in PointerInputCmdHandler.PointerInputCmdArgs args)
|
|
{
|
|
_ui?.HandleChangeHotbarKeybind(hotbar, args);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the displayed hotbar (and menu) based on current state of actions.
|
|
/// </summary>
|
|
private void UpdateUI()
|
|
{
|
|
if (!CurrentlyControlled || _ui == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Assignments.Reconcile(_ui.SelectedHotbar, ActionStates(), ItemActionStates(), _ui.Locked);
|
|
|
|
_ui.UpdateUI();
|
|
}
|
|
|
|
public void AttemptAction(ActionSlot slot)
|
|
{
|
|
|
|
var attempt = slot.ActionAttempt();
|
|
if (attempt == null) return;
|
|
|
|
switch (attempt.Action.BehaviorType)
|
|
{
|
|
case BehaviorType.Instant:
|
|
// for instant actions, we immediately tell the server we're doing it
|
|
SendNetworkMessage(attempt.PerformInstantActionMessage());
|
|
break;
|
|
case BehaviorType.Toggle:
|
|
// for toggle actions, we immediately tell the server we're toggling it.
|
|
if (attempt.TryGetActionState(this, out var actionState))
|
|
{
|
|
// TODO: At the moment we always predict that the toggle will work clientside,
|
|
// even if it sometimes may not (it will be reset by the server if wrong).
|
|
attempt.ToggleAction(this, !actionState.ToggledOn);
|
|
slot.ToggledOn = !actionState.ToggledOn;
|
|
SendNetworkMessage(attempt.PerformToggleActionMessage(!actionState.ToggledOn));
|
|
}
|
|
else
|
|
{
|
|
Logger.ErrorS("action", "attempted to toggle action {0} which has" +
|
|
" unknown state", attempt);
|
|
}
|
|
|
|
break;
|
|
case BehaviorType.TargetPoint:
|
|
case BehaviorType.TargetEntity:
|
|
// for target actions, we go into "select target" mode, we don't
|
|
// message the server until we actually pick our target.
|
|
|
|
// if we're clicking the same thing we're already targeting for, then we simply cancel
|
|
// targeting
|
|
_ui?.ToggleTargeting(slot);
|
|
break;
|
|
case BehaviorType.None:
|
|
break;
|
|
default:
|
|
Logger.ErrorS("action", "unhandled action press for action {0}",
|
|
attempt);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handles clicks when selecting the target for an action. Only has an effect when currently
|
|
/// selecting a target.
|
|
/// </summary>
|
|
public bool TargetingOnUse(in PointerInputCmdHandler.PointerInputCmdArgs args)
|
|
{
|
|
// not currently predicted
|
|
if (EntitySystem.Get<InputSystem>().Predicted) return false;
|
|
|
|
// only do something for actual target-based actions
|
|
if (_ui?.SelectingTargetFor?.Action == null ||
|
|
(!_ui.SelectingTargetFor.Action.IsTargetAction)) return false;
|
|
|
|
// do nothing if we know it's on cooldown
|
|
if (_ui.SelectingTargetFor.IsOnCooldown) return false;
|
|
|
|
var attempt = _ui.SelectingTargetFor.ActionAttempt();
|
|
if (attempt == null)
|
|
{
|
|
_ui.StopTargeting();
|
|
return false;
|
|
}
|
|
|
|
switch (_ui.SelectingTargetFor.Action.BehaviorType)
|
|
{
|
|
case BehaviorType.TargetPoint:
|
|
{
|
|
// send our action to the server, we chose our target
|
|
SendNetworkMessage(attempt.PerformTargetPointActionMessage(args));
|
|
if (!attempt.Action.Repeat)
|
|
{
|
|
_ui.StopTargeting();
|
|
}
|
|
return true;
|
|
}
|
|
// target the currently hovered entity, if there is one
|
|
case BehaviorType.TargetEntity when args.EntityUid != EntityUid.Invalid:
|
|
{
|
|
// send our action to the server, we chose our target
|
|
SendNetworkMessage(attempt.PerformTargetEntityActionMessage(args));
|
|
if (!attempt.Action.Repeat)
|
|
{
|
|
_ui.StopTargeting();
|
|
}
|
|
return true;
|
|
}
|
|
// we are supposed to target an entity but we didn't click it
|
|
case BehaviorType.TargetEntity when args.EntityUid == EntityUid.Invalid:
|
|
{
|
|
if (attempt.Action.DeselectWhenEntityNotClicked)
|
|
_ui.StopTargeting();
|
|
return false;
|
|
}
|
|
default:
|
|
_ui.StopTargeting();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
protected override void AfterActionChanged()
|
|
{
|
|
UpdateUI();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Highlights the item slot (inventory or hand) that contains this item
|
|
/// </summary>
|
|
/// <param name="item"></param>
|
|
public void HighlightItemSlot(IEntity item)
|
|
{
|
|
StopHighlightingItemSlots();
|
|
|
|
// figure out if it's in hand or inventory and highlight it
|
|
foreach (var hand in _handsComponent!.Hands)
|
|
{
|
|
if (hand.Entity != item || hand.Button == null) continue;
|
|
_highlightingItemSlots.Add(hand.Button);
|
|
hand.Button.Highlight(true);
|
|
return;
|
|
}
|
|
|
|
foreach (var (slot, slotItem) in _inventoryComponent!.AllSlots)
|
|
{
|
|
if (slotItem != item) continue;
|
|
foreach (var itemSlotButton in
|
|
_inventoryComponent.InterfaceController.GetItemSlotButtons(slot))
|
|
{
|
|
_highlightingItemSlots.Add(itemSlotButton);
|
|
itemSlotButton.Highlight(true);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stops highlighting any item slots we are currently highlighting.
|
|
/// </summary>
|
|
public void StopHighlightingItemSlots()
|
|
{
|
|
foreach (var itemSlot in _highlightingItemSlots)
|
|
{
|
|
itemSlot.Highlight(false);
|
|
}
|
|
_highlightingItemSlots.Clear();
|
|
}
|
|
|
|
public void ToggleActionsMenu()
|
|
{
|
|
_ui?.ToggleActionsMenu();
|
|
}
|
|
}
|
|
}
|