2019-05-15 12:49:29 -07:00
|
|
|
|
using System;
|
2018-11-21 20:58:11 +01:00
|
|
|
|
using System.Collections.Generic;
|
2019-10-30 11:31:35 -04:00
|
|
|
|
using System.Reflection;
|
2019-12-06 00:41:30 +01:00
|
|
|
|
using Content.Client.State;
|
2018-11-21 20:58:11 +01:00
|
|
|
|
using Content.Shared.GameObjects;
|
|
|
|
|
|
using Content.Shared.GameObjects.EntitySystemMessages;
|
|
|
|
|
|
using Content.Shared.Input;
|
2019-08-25 12:54:55 +02:00
|
|
|
|
using JetBrains.Annotations;
|
2019-04-15 21:11:38 -06:00
|
|
|
|
using Robust.Client.GameObjects.EntitySystems;
|
|
|
|
|
|
using Robust.Client.Interfaces.Input;
|
|
|
|
|
|
using Robust.Client.Interfaces.State;
|
|
|
|
|
|
using Robust.Client.Player;
|
|
|
|
|
|
using Robust.Client.UserInterface.Controls;
|
|
|
|
|
|
using Robust.Shared.GameObjects;
|
|
|
|
|
|
using Robust.Shared.GameObjects.Systems;
|
|
|
|
|
|
using Robust.Shared.Input;
|
|
|
|
|
|
using Robust.Shared.Interfaces.GameObjects;
|
|
|
|
|
|
using Robust.Shared.IoC;
|
|
|
|
|
|
using Robust.Shared.Log;
|
|
|
|
|
|
using Robust.Shared.Map;
|
|
|
|
|
|
using Robust.Shared.Maths;
|
|
|
|
|
|
using Robust.Shared.Utility;
|
2018-11-21 20:58:11 +01:00
|
|
|
|
|
|
|
|
|
|
namespace Content.Client.GameObjects.EntitySystems
|
|
|
|
|
|
{
|
2019-08-25 12:54:55 +02:00
|
|
|
|
[UsedImplicitly]
|
|
|
|
|
|
public sealed class VerbSystem : EntitySystem
|
2018-11-21 20:58:11 +01:00
|
|
|
|
{
|
|
|
|
|
|
#pragma warning disable 649
|
|
|
|
|
|
[Dependency] private readonly IStateManager _stateManager;
|
|
|
|
|
|
[Dependency] private readonly IEntityManager _entityManager;
|
|
|
|
|
|
[Dependency] private readonly IPlayerManager _playerManager;
|
|
|
|
|
|
[Dependency] private readonly IInputManager _inputManager;
|
|
|
|
|
|
#pragma warning restore 649
|
|
|
|
|
|
|
2019-08-25 12:54:55 +02:00
|
|
|
|
private VerbPopup _currentPopup;
|
2018-11-21 20:58:11 +01:00
|
|
|
|
private EntityUid _currentEntity;
|
|
|
|
|
|
|
|
|
|
|
|
public override void Initialize()
|
|
|
|
|
|
{
|
|
|
|
|
|
base.Initialize();
|
|
|
|
|
|
|
2020-02-19 17:08:59 -08:00
|
|
|
|
SubscribeNetworkEvent<VerbSystemMessages.VerbsResponseMessage>(FillEntityPopup);
|
2020-02-18 19:43:54 -08:00
|
|
|
|
|
2018-11-21 20:58:11 +01:00
|
|
|
|
IoCManager.InjectDependencies(this);
|
|
|
|
|
|
|
|
|
|
|
|
var input = EntitySystemManager.GetEntitySystem<InputSystem>();
|
|
|
|
|
|
input.BindMap.BindFunction(ContentKeyFunctions.OpenContextMenu,
|
|
|
|
|
|
new PointerInputCmdHandler(OnOpenContextMenu));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void OpenContextMenu(IEntity entity, ScreenCoordinates screenCoordinates)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_currentPopup != null)
|
|
|
|
|
|
{
|
2020-02-18 19:43:54 -08:00
|
|
|
|
CloseContextMenu();
|
2018-11-21 20:58:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_currentEntity = entity.Uid;
|
2019-08-25 12:54:55 +02:00
|
|
|
|
_currentPopup = new VerbPopup();
|
2020-01-25 17:28:39 +01:00
|
|
|
|
_currentPopup.UserInterfaceManager.ModalRoot.AddChild(_currentPopup);
|
2020-02-18 19:43:54 -08:00
|
|
|
|
_currentPopup.OnPopupHide += CloseContextMenu;
|
2018-11-21 20:58:11 +01:00
|
|
|
|
|
2019-08-25 12:54:55 +02:00
|
|
|
|
_currentPopup.List.AddChild(new Label {Text = "Waiting on Server..."});
|
2018-11-21 20:58:11 +01:00
|
|
|
|
RaiseNetworkEvent(new VerbSystemMessages.RequestVerbsMessage(_currentEntity));
|
|
|
|
|
|
|
2019-08-25 12:54:55 +02:00
|
|
|
|
var size = _currentPopup.List.CombinedMinimumSize;
|
2019-01-18 11:40:30 +01:00
|
|
|
|
var box = UIBox2.FromDimensions(screenCoordinates.Position, size);
|
2018-11-21 20:58:11 +01:00
|
|
|
|
_currentPopup.Open(box);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-09-17 16:08:45 -07:00
|
|
|
|
private bool OnOpenContextMenu(in PointerInputCmdHandler.PointerInputCmdArgs args)
|
2018-11-21 20:58:11 +01:00
|
|
|
|
{
|
|
|
|
|
|
if (_currentPopup != null)
|
|
|
|
|
|
{
|
2020-02-18 19:43:54 -08:00
|
|
|
|
CloseContextMenu();
|
2019-09-17 16:08:45 -07:00
|
|
|
|
return true;
|
2018-11-21 20:58:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-02-26 16:42:12 +01:00
|
|
|
|
if (!(_stateManager.CurrentState is GameScreenBase gameScreen))
|
2018-11-21 20:58:11 +01:00
|
|
|
|
{
|
2019-09-17 16:08:45 -07:00
|
|
|
|
return false;
|
2018-11-21 20:58:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var entities = gameScreen.GetEntitiesUnderPosition(args.Coordinates);
|
|
|
|
|
|
|
2019-08-25 22:53:36 +02:00
|
|
|
|
if (entities.Count == 0)
|
|
|
|
|
|
{
|
2019-09-17 16:08:45 -07:00
|
|
|
|
return false;
|
2019-08-25 22:53:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-08-25 12:54:55 +02:00
|
|
|
|
_currentPopup = new VerbPopup();
|
2020-02-18 19:43:54 -08:00
|
|
|
|
_currentPopup.OnPopupHide += CloseContextMenu;
|
2018-11-21 20:58:11 +01:00
|
|
|
|
foreach (var entity in entities)
|
|
|
|
|
|
{
|
|
|
|
|
|
var button = new Button {Text = entity.Name};
|
2019-08-25 12:54:55 +02:00
|
|
|
|
_currentPopup.List.AddChild(button);
|
2018-11-21 20:58:11 +01:00
|
|
|
|
button.OnPressed += _ => OnContextButtonPressed(entity);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-01-25 23:35:03 +01:00
|
|
|
|
_currentPopup.UserInterfaceManager.ModalRoot.AddChild(_currentPopup);
|
2018-11-21 20:58:11 +01:00
|
|
|
|
|
2019-08-25 12:54:55 +02:00
|
|
|
|
var size = _currentPopup.List.CombinedMinimumSize;
|
2018-11-21 20:58:11 +01:00
|
|
|
|
var box = UIBox2.FromDimensions(args.ScreenCoordinates.Position, size);
|
|
|
|
|
|
_currentPopup.Open(box);
|
2019-09-17 16:08:45 -07:00
|
|
|
|
|
|
|
|
|
|
return true;
|
2018-11-21 20:58:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void OnContextButtonPressed(IEntity entity)
|
|
|
|
|
|
{
|
|
|
|
|
|
OpenContextMenu(entity, new ScreenCoordinates(_inputManager.MouseScreenPosition));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-02-19 14:39:00 -08:00
|
|
|
|
private void FillEntityPopup(VerbSystemMessages.VerbsResponseMessage msg)
|
2018-11-21 20:58:11 +01:00
|
|
|
|
{
|
|
|
|
|
|
if (_currentEntity != msg.Entity || !_entityManager.TryGetEntity(_currentEntity, out var entity))
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DebugTools.AssertNotNull(_currentPopup);
|
|
|
|
|
|
|
2020-03-06 20:11:24 +01:00
|
|
|
|
var buttons = new Dictionary<string, List<Button>>();
|
2018-11-21 20:58:11 +01:00
|
|
|
|
|
2019-08-25 12:54:55 +02:00
|
|
|
|
var vBox = _currentPopup.List;
|
2018-11-21 20:58:11 +01:00
|
|
|
|
vBox.DisposeAllChildren();
|
|
|
|
|
|
foreach (var data in msg.Verbs)
|
|
|
|
|
|
{
|
|
|
|
|
|
var button = new Button {Text = data.Text, Disabled = !data.Available};
|
|
|
|
|
|
if (data.Available)
|
|
|
|
|
|
{
|
|
|
|
|
|
button.OnPressed += _ =>
|
|
|
|
|
|
{
|
|
|
|
|
|
RaiseNetworkEvent(new VerbSystemMessages.UseVerbMessage(_currentEntity, data.Key));
|
2020-02-18 19:43:54 -08:00
|
|
|
|
CloseContextMenu();
|
2018-11-21 20:58:11 +01:00
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-03-06 20:11:24 +01:00
|
|
|
|
if(!buttons.ContainsKey(data.Category))
|
|
|
|
|
|
buttons[data.Category] = new List<Button>();
|
|
|
|
|
|
|
|
|
|
|
|
buttons[data.Category].Add(button);
|
2018-11-21 20:58:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var user = GetUserEntity();
|
2019-10-30 11:31:35 -04:00
|
|
|
|
//Get verbs, component dependent.
|
2018-11-21 20:58:11 +01:00
|
|
|
|
foreach (var (component, verb) in VerbUtility.GetVerbs(entity))
|
|
|
|
|
|
{
|
2019-10-30 11:31:35 -04:00
|
|
|
|
if (verb.RequireInteractionRange && !VerbUtility.InVerbUseRange(user, entity))
|
|
|
|
|
|
continue;
|
2018-11-21 20:58:11 +01:00
|
|
|
|
|
2019-05-15 12:49:29 -07:00
|
|
|
|
var disabled = verb.GetVisibility(user, component) != VerbVisibility.Visible;
|
2020-03-06 20:11:24 +01:00
|
|
|
|
var category = verb.GetCategory(user, component);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(!buttons.ContainsKey(category))
|
|
|
|
|
|
buttons[category] = new List<Button>();
|
|
|
|
|
|
|
|
|
|
|
|
buttons[category].Add(CreateVerbButton(verb.GetText(user, component), disabled, verb.ToString(),
|
2019-10-30 11:31:35 -04:00
|
|
|
|
entity.ToString(), () => verb.Activate(user, component)));
|
|
|
|
|
|
}
|
|
|
|
|
|
//Get global verbs. Visible for all entities regardless of their components.
|
|
|
|
|
|
foreach (var globalVerb in VerbUtility.GetGlobalVerbs(Assembly.GetExecutingAssembly()))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (globalVerb.RequireInteractionRange && !VerbUtility.InVerbUseRange(user, entity))
|
|
|
|
|
|
continue;
|
2018-11-21 20:58:11 +01:00
|
|
|
|
|
2019-10-30 11:31:35 -04:00
|
|
|
|
var disabled = globalVerb.GetVisibility(user, entity) != VerbVisibility.Visible;
|
2020-03-06 20:11:24 +01:00
|
|
|
|
var category = globalVerb.GetCategory(user, entity);
|
|
|
|
|
|
|
|
|
|
|
|
if(!buttons.ContainsKey(category))
|
|
|
|
|
|
buttons[category] = new List<Button>();
|
|
|
|
|
|
|
|
|
|
|
|
buttons[category].Add(CreateVerbButton(globalVerb.GetText(user, entity), disabled, globalVerb.ToString(),
|
2019-10-30 11:31:35 -04:00
|
|
|
|
entity.ToString(), () => globalVerb.Activate(user, entity)));
|
2018-11-21 20:58:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (buttons.Count > 0)
|
|
|
|
|
|
{
|
2020-03-06 20:11:24 +01:00
|
|
|
|
foreach (var (category, verbs) in buttons)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(category))
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
vBox.AddChild(CreateCategoryButton(category, verbs));
|
|
|
|
|
|
}
|
2018-11-21 20:58:11 +01:00
|
|
|
|
|
2020-03-06 20:11:24 +01:00
|
|
|
|
if (buttons.ContainsKey(""))
|
2018-11-21 20:58:11 +01:00
|
|
|
|
{
|
2020-03-06 20:11:24 +01:00
|
|
|
|
buttons[""].Sort((a, b) => string.Compare(a.Text, b.Text, StringComparison.Ordinal));
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var verb in buttons[""])
|
|
|
|
|
|
{
|
|
|
|
|
|
vBox.AddChild(verb);
|
|
|
|
|
|
}
|
2018-11-21 20:58:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var panel = new PanelContainer();
|
|
|
|
|
|
panel.AddChild(new Label {Text = "No verbs!"});
|
|
|
|
|
|
vBox.AddChild(panel);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-10-30 11:31:35 -04:00
|
|
|
|
private Button CreateVerbButton(string text, bool disabled, string verbName, string ownerName, Action action)
|
|
|
|
|
|
{
|
|
|
|
|
|
var button = new Button
|
|
|
|
|
|
{
|
|
|
|
|
|
Text = text,
|
|
|
|
|
|
Disabled = disabled
|
|
|
|
|
|
};
|
|
|
|
|
|
if (!disabled)
|
|
|
|
|
|
{
|
|
|
|
|
|
button.OnPressed += _ =>
|
|
|
|
|
|
{
|
2020-02-18 19:43:54 -08:00
|
|
|
|
CloseContextMenu();
|
2019-10-30 11:31:35 -04:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
action.Invoke();
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Logger.ErrorS("verb", "Exception in verb {0} on {1}:\n{2}", verbName, ownerName, e);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
return button;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-03-06 20:11:24 +01:00
|
|
|
|
private Button CreateCategoryButton(string text, List<Button> verbButtons)
|
|
|
|
|
|
{
|
|
|
|
|
|
verbButtons.Sort((a, b) => string.Compare(a.Text, b.Text, StringComparison.Ordinal));
|
|
|
|
|
|
|
|
|
|
|
|
var button = new Button
|
|
|
|
|
|
{
|
|
|
|
|
|
Text = $"{text}...",
|
|
|
|
|
|
};
|
|
|
|
|
|
button.OnPressed += _ =>
|
|
|
|
|
|
{
|
|
|
|
|
|
_currentPopup.List.DisposeAllChildren();
|
|
|
|
|
|
foreach (var verb in verbButtons)
|
|
|
|
|
|
{
|
|
|
|
|
|
_currentPopup.List.AddChild(verb);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
return button;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-02-18 19:43:54 -08:00
|
|
|
|
private void CloseContextMenu()
|
2018-11-21 20:58:11 +01:00
|
|
|
|
{
|
|
|
|
|
|
_currentPopup?.Dispose();
|
|
|
|
|
|
_currentPopup = null;
|
|
|
|
|
|
_currentEntity = EntityUid.Invalid;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private IEntity GetUserEntity()
|
|
|
|
|
|
{
|
|
|
|
|
|
return _playerManager.LocalPlayer.ControlledEntity;
|
|
|
|
|
|
}
|
2019-08-25 12:54:55 +02:00
|
|
|
|
|
|
|
|
|
|
private sealed class VerbPopup : Popup
|
|
|
|
|
|
{
|
|
|
|
|
|
public VBoxContainer List { get; }
|
|
|
|
|
|
|
|
|
|
|
|
public VerbPopup()
|
|
|
|
|
|
{
|
|
|
|
|
|
AddChild(List = new VBoxContainer());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2018-11-21 20:58:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|