Fancy Verb Menu & Verb API Refactor (#928)
@@ -1,25 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using Content.Client.State;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.EntitySystemMessages;
|
||||
using Content.Shared.Input;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects.EntitySystems;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Client.Interfaces.Input;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.Interfaces.State;
|
||||
using Robust.Client.Interfaces.UserInterface;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
using Timer = Robust.Shared.Timers.Timer;
|
||||
|
||||
namespace Content.Client.GameObjects.EntitySystems
|
||||
{
|
||||
@@ -31,11 +43,21 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
[Dependency] private readonly IEntityManager _entityManager;
|
||||
[Dependency] private readonly IPlayerManager _playerManager;
|
||||
[Dependency] private readonly IInputManager _inputManager;
|
||||
[Dependency] private readonly IItemSlotManager _itemSlotManager;
|
||||
[Dependency] private readonly IGameTiming _gameTiming;
|
||||
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager;
|
||||
[Dependency] private readonly IResourceCache _resourceCache;
|
||||
#pragma warning restore 649
|
||||
|
||||
private VerbPopup _currentPopup;
|
||||
private EntityList _currentEntityList;
|
||||
private VerbPopup _currentVerbListRoot;
|
||||
private VerbPopup _currentGroupList;
|
||||
|
||||
private EntityUid _currentEntity;
|
||||
|
||||
private bool IsAnyContextMenuOpen => _currentEntityList != null || _currentVerbListRoot != null;
|
||||
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -51,29 +73,28 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
|
||||
public void OpenContextMenu(IEntity entity, ScreenCoordinates screenCoordinates)
|
||||
{
|
||||
if (_currentPopup != null)
|
||||
if (_currentVerbListRoot != null)
|
||||
{
|
||||
CloseContextMenu();
|
||||
CloseVerbMenu();
|
||||
}
|
||||
|
||||
_currentEntity = entity.Uid;
|
||||
_currentPopup = new VerbPopup();
|
||||
_currentPopup.UserInterfaceManager.ModalRoot.AddChild(_currentPopup);
|
||||
_currentPopup.OnPopupHide += CloseContextMenu;
|
||||
_currentVerbListRoot = new VerbPopup();
|
||||
_userInterfaceManager.ModalRoot.AddChild(_currentVerbListRoot);
|
||||
_currentVerbListRoot.OnPopupHide += CloseVerbMenu;
|
||||
|
||||
_currentPopup.List.AddChild(new Label {Text = "Waiting on Server..."});
|
||||
_currentVerbListRoot.List.AddChild(new Label {Text = "Waiting on Server..."});
|
||||
RaiseNetworkEvent(new VerbSystemMessages.RequestVerbsMessage(_currentEntity));
|
||||
|
||||
var size = _currentPopup.List.CombinedMinimumSize;
|
||||
var box = UIBox2.FromDimensions(screenCoordinates.Position, size);
|
||||
_currentPopup.Open(box);
|
||||
var box = UIBox2.FromDimensions(screenCoordinates.Position, (1, 1));
|
||||
_currentVerbListRoot.Open(box);
|
||||
}
|
||||
|
||||
private bool OnOpenContextMenu(in PointerInputCmdHandler.PointerInputCmdArgs args)
|
||||
{
|
||||
if (_currentPopup != null)
|
||||
if (IsAnyContextMenuOpen)
|
||||
{
|
||||
CloseContextMenu();
|
||||
CloseAllMenus();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -89,20 +110,29 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
return false;
|
||||
}
|
||||
|
||||
_currentPopup = new VerbPopup();
|
||||
_currentPopup.OnPopupHide += CloseContextMenu;
|
||||
foreach (var entity in entities)
|
||||
_currentEntityList = new EntityList();
|
||||
_currentEntityList.OnPopupHide += CloseAllMenus;
|
||||
for (var i = 0; i < entities.Count; i++)
|
||||
{
|
||||
var button = new Button {Text = entity.Name};
|
||||
_currentPopup.List.AddChild(button);
|
||||
button.OnPressed += _ => OnContextButtonPressed(entity);
|
||||
if (i != 0)
|
||||
{
|
||||
_currentEntityList.List.AddChild(new PanelContainer
|
||||
{
|
||||
CustomMinimumSize = (0, 2),
|
||||
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#333")}
|
||||
});
|
||||
}
|
||||
|
||||
_currentPopup.UserInterfaceManager.ModalRoot.AddChild(_currentPopup);
|
||||
var entity = entities[i];
|
||||
|
||||
var size = _currentPopup.List.CombinedMinimumSize;
|
||||
_currentEntityList.List.AddChild(new EntityButton(this, entity));
|
||||
}
|
||||
|
||||
_userInterfaceManager.ModalRoot.AddChild(_currentEntityList);
|
||||
|
||||
var size = _currentEntityList.List.CombinedMinimumSize;
|
||||
var box = UIBox2.FromDimensions(args.ScreenCoordinates.Position, size);
|
||||
_currentPopup.Open(box);
|
||||
_currentEntityList.Open(box);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -119,28 +149,31 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
return;
|
||||
}
|
||||
|
||||
DebugTools.AssertNotNull(_currentPopup);
|
||||
DebugTools.AssertNotNull(_currentVerbListRoot);
|
||||
|
||||
var buttons = new Dictionary<string, List<Button>>();
|
||||
var buttons = new Dictionary<string, List<ListedVerbData>>();
|
||||
var groupIcons = new Dictionary<string, SpriteSpecifier>();
|
||||
|
||||
var vBox = _currentPopup.List;
|
||||
var vBox = _currentVerbListRoot.List;
|
||||
vBox.DisposeAllChildren();
|
||||
|
||||
// Local variable so that scope capture ensures this is the correct value.
|
||||
var curEntity = _currentEntity;
|
||||
|
||||
foreach (var data in msg.Verbs)
|
||||
{
|
||||
var button = new Button {Text = data.Text, Disabled = !data.Available};
|
||||
if (data.Available)
|
||||
var list = buttons.GetOrNew(data.Category);
|
||||
|
||||
if (data.CategoryIcon != null && !groupIcons.ContainsKey(data.Category))
|
||||
{
|
||||
button.OnPressed += _ =>
|
||||
{
|
||||
RaiseNetworkEvent(new VerbSystemMessages.UseVerbMessage(_currentEntity, data.Key));
|
||||
CloseContextMenu();
|
||||
};
|
||||
groupIcons.Add(data.Category, data.CategoryIcon);
|
||||
}
|
||||
|
||||
if(!buttons.ContainsKey(data.Category))
|
||||
buttons[data.Category] = new List<Button>();
|
||||
|
||||
buttons[data.Category].Add(button);
|
||||
list.Add(new ListedVerbData(data.Text, !data.Available, data.Key, entity.ToString(), () =>
|
||||
{
|
||||
RaiseNetworkEvent(new VerbSystemMessages.UseVerbMessage(curEntity, data.Key));
|
||||
CloseAllMenus();
|
||||
}, data.Icon));
|
||||
}
|
||||
|
||||
var user = GetUserEntity();
|
||||
@@ -150,55 +183,87 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
if (verb.RequireInteractionRange && !VerbUtility.InVerbUseRange(user, entity))
|
||||
continue;
|
||||
|
||||
if (VerbUtility.IsVerbInvisible(verb, user, component, out var vis))
|
||||
var verbData = verb.GetData(user, component);
|
||||
|
||||
if (verbData.IsInvisible)
|
||||
continue;
|
||||
|
||||
var disabled = vis != VerbVisibility.Visible;
|
||||
var category = verb.GetCategory(user, component);
|
||||
var list = buttons.GetOrNew(verbData.Category);
|
||||
|
||||
|
||||
if(!buttons.ContainsKey(category))
|
||||
buttons[category] = new List<Button>();
|
||||
|
||||
buttons[category].Add(CreateVerbButton(verb.GetText(user, component), disabled, verb.ToString(),
|
||||
entity.ToString(), () => verb.Activate(user, component)));
|
||||
if (verbData.CategoryIcon != null && !groupIcons.ContainsKey(verbData.Category))
|
||||
{
|
||||
groupIcons.Add(verbData.Category, verbData.CategoryIcon);
|
||||
}
|
||||
|
||||
list.Add(new ListedVerbData(verbData.Text, verbData.IsDisabled, verb.ToString(), entity.ToString(),
|
||||
() => verb.Activate(user, component), verbData.Icon));
|
||||
}
|
||||
|
||||
//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;
|
||||
|
||||
if (VerbUtility.IsVerbInvisible(globalVerb, user, entity, out var vis))
|
||||
var verbData = globalVerb.GetData(user, entity);
|
||||
|
||||
if (verbData.IsInvisible)
|
||||
continue;
|
||||
|
||||
var disabled = vis != VerbVisibility.Visible;
|
||||
var category = globalVerb.GetCategory(user, entity);
|
||||
var list = buttons.GetOrNew(verbData.Category);
|
||||
|
||||
if(!buttons.ContainsKey(category))
|
||||
buttons[category] = new List<Button>();
|
||||
if (verbData.CategoryIcon != null && !groupIcons.ContainsKey(verbData.Category))
|
||||
{
|
||||
groupIcons.Add(verbData.Category, verbData.CategoryIcon);
|
||||
}
|
||||
|
||||
buttons[category].Add(CreateVerbButton(globalVerb.GetText(user, entity), disabled, globalVerb.ToString(),
|
||||
entity.ToString(), () => globalVerb.Activate(user, entity)));
|
||||
list.Add(new ListedVerbData(verbData.Text, verbData.IsDisabled, globalVerb.ToString(),
|
||||
entity.ToString(),
|
||||
() => globalVerb.Activate(user, entity), verbData.Icon));
|
||||
}
|
||||
|
||||
if (buttons.Count > 0)
|
||||
{
|
||||
var first = true;
|
||||
foreach (var (category, verbs) in buttons)
|
||||
{
|
||||
if (string.IsNullOrEmpty(category))
|
||||
continue;
|
||||
|
||||
vBox.AddChild(CreateCategoryButton(category, verbs));
|
||||
if (!first)
|
||||
{
|
||||
vBox.AddChild(new PanelContainer
|
||||
{
|
||||
CustomMinimumSize = (0, 2),
|
||||
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#333")}
|
||||
});
|
||||
}
|
||||
|
||||
first = false;
|
||||
|
||||
groupIcons.TryGetValue(category, out var icon);
|
||||
|
||||
vBox.AddChild(CreateCategoryButton(category, verbs, icon));
|
||||
}
|
||||
|
||||
if (buttons.ContainsKey(""))
|
||||
{
|
||||
buttons[""].Sort((a, b) => string.Compare(a.Text, b.Text, StringComparison.Ordinal));
|
||||
buttons[""].Sort((a, b) => string.Compare(a.Text, b.Text, StringComparison.CurrentCulture));
|
||||
|
||||
foreach (var verb in buttons[""])
|
||||
{
|
||||
vBox.AddChild(verb);
|
||||
if (!first)
|
||||
{
|
||||
vBox.AddChild(new PanelContainer
|
||||
{
|
||||
CustomMinimumSize = (0, 2),
|
||||
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#333")}
|
||||
});
|
||||
}
|
||||
|
||||
first = false;
|
||||
|
||||
vBox.AddChild(CreateVerbButton(verb));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -210,69 +275,364 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
}
|
||||
}
|
||||
|
||||
private Button CreateVerbButton(string text, bool disabled, string verbName, string ownerName, Action action)
|
||||
private VerbButton CreateVerbButton(ListedVerbData data)
|
||||
{
|
||||
var button = new Button
|
||||
var button = new VerbButton
|
||||
{
|
||||
Text = text,
|
||||
Disabled = disabled
|
||||
Text = data.Text,
|
||||
Disabled = data.Disabled
|
||||
};
|
||||
if (!disabled)
|
||||
|
||||
if (data.Icon != null)
|
||||
{
|
||||
button.Icon = data.Icon.Frame0();
|
||||
}
|
||||
|
||||
if (!data.Disabled)
|
||||
{
|
||||
button.OnPressed += _ =>
|
||||
{
|
||||
CloseContextMenu();
|
||||
CloseAllMenus();
|
||||
try
|
||||
{
|
||||
action.Invoke();
|
||||
data.Action.Invoke();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.ErrorS("verb", "Exception in verb {0} on {1}:\n{2}", verbName, ownerName, e);
|
||||
Logger.ErrorS("verb", "Exception in verb {0} on {1}:\n{2}", data.VerbName, data.OwnerName, e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
private Button CreateCategoryButton(string text, List<Button> verbButtons)
|
||||
private Control CreateCategoryButton(string text, List<ListedVerbData> verbButtons, SpriteSpecifier icon)
|
||||
{
|
||||
verbButtons.Sort((a, b) => string.Compare(a.Text, b.Text, StringComparison.Ordinal));
|
||||
verbButtons.Sort((a, b) => string.Compare(a.Text, b.Text, StringComparison.CurrentCulture));
|
||||
|
||||
var button = new Button
|
||||
return new VerbGroupButton(this, verbButtons, icon)
|
||||
{
|
||||
Text = $"{text}...",
|
||||
Text = text,
|
||||
};
|
||||
button.OnPressed += _ =>
|
||||
{
|
||||
_currentPopup.List.DisposeAllChildren();
|
||||
foreach (var verb in verbButtons)
|
||||
{
|
||||
_currentPopup.List.AddChild(verb);
|
||||
}
|
||||
};
|
||||
return button;
|
||||
}
|
||||
|
||||
private void CloseContextMenu()
|
||||
private void CloseVerbMenu()
|
||||
{
|
||||
_currentPopup?.Dispose();
|
||||
_currentPopup = null;
|
||||
_currentVerbListRoot?.Dispose();
|
||||
_currentVerbListRoot = null;
|
||||
_currentEntity = EntityUid.Invalid;
|
||||
}
|
||||
|
||||
private void CloseEntityList()
|
||||
{
|
||||
_currentEntityList?.Dispose();
|
||||
_currentEntityList = null;
|
||||
}
|
||||
|
||||
private void CloseAllMenus()
|
||||
{
|
||||
CloseVerbMenu();
|
||||
CloseEntityList();
|
||||
CloseGroupMenu();
|
||||
}
|
||||
|
||||
private void CloseGroupMenu()
|
||||
{
|
||||
_currentGroupList?.Dispose();
|
||||
_currentGroupList = null;
|
||||
}
|
||||
|
||||
private IEntity GetUserEntity()
|
||||
{
|
||||
return _playerManager.LocalPlayer.ControlledEntity;
|
||||
}
|
||||
|
||||
private sealed class EntityList : Popup
|
||||
{
|
||||
public VBoxContainer List { get; }
|
||||
|
||||
public EntityList()
|
||||
{
|
||||
AddChild(new PanelContainer
|
||||
{
|
||||
Children = {(List = new VBoxContainer())},
|
||||
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#111E")}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class VerbPopup : Popup
|
||||
{
|
||||
public VBoxContainer List { get; }
|
||||
|
||||
public VerbPopup()
|
||||
{
|
||||
AddChild(List = new VBoxContainer());
|
||||
AddChild(new PanelContainer
|
||||
{
|
||||
Children = {(List = new VBoxContainer())},
|
||||
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#111E")}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class EntityButton : Control
|
||||
{
|
||||
private readonly VerbSystem _master;
|
||||
private readonly IEntity _entity;
|
||||
|
||||
public EntityButton(VerbSystem master, IEntity entity)
|
||||
{
|
||||
_master = master;
|
||||
_entity = entity;
|
||||
|
||||
MouseFilter = MouseFilterMode.Stop;
|
||||
|
||||
var control = new HBoxContainer {SeparationOverride = 6};
|
||||
if (entity.TryGetComponent(out ISpriteComponent sprite))
|
||||
{
|
||||
control.AddChild(new SpriteView {Sprite = sprite});
|
||||
}
|
||||
|
||||
control.AddChild(new MarginContainer
|
||||
{
|
||||
MarginLeftOverride = 4,
|
||||
MarginRightOverride = 4,
|
||||
Children = {new Label {Text = entity.Name}}
|
||||
});
|
||||
|
||||
AddChild(control);
|
||||
}
|
||||
|
||||
protected override void KeyBindDown(GUIBoundKeyEventArgs args)
|
||||
{
|
||||
base.KeyBindDown(args);
|
||||
|
||||
if (args.Function == ContentKeyFunctions.OpenContextMenu)
|
||||
{
|
||||
_master.OnContextButtonPressed(_entity);
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Function == EngineKeyFunctions.Use)
|
||||
{
|
||||
var inputSys = _master.EntitySystemManager.GetEntitySystem<InputSystem>();
|
||||
|
||||
var func = args.Function;
|
||||
var funcId = _master._inputManager.NetworkBindMap.KeyFunctionID(args.Function);
|
||||
|
||||
var message = new FullInputCmdMessage(_master._gameTiming.CurTick, funcId, BoundKeyState.Down,
|
||||
_entity.Transform.GridPosition,
|
||||
args.PointerLocation, _entity.Uid);
|
||||
|
||||
// client side command handlers will always be sent the local player session.
|
||||
var session = _master._playerManager.LocalPlayer.Session;
|
||||
inputSys.HandleInputCommand(session, func, message);
|
||||
|
||||
_master.CloseAllMenus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_master._itemSlotManager.OnButtonPressed(args, _entity))
|
||||
{
|
||||
_master.CloseAllMenus();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Draw(DrawingHandleScreen handle)
|
||||
{
|
||||
base.Draw(handle);
|
||||
|
||||
if (UserInterfaceManager.CurrentlyHovered == this)
|
||||
{
|
||||
handle.DrawRect(PixelSizeBox, Color.DarkSlateGray);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class VerbButton : BaseButton
|
||||
{
|
||||
private readonly Label _label;
|
||||
private readonly TextureRect _icon;
|
||||
|
||||
public Texture Icon
|
||||
{
|
||||
get => _icon.Texture;
|
||||
set => _icon.Texture = value;
|
||||
}
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => _label.Text;
|
||||
set => _label.Text = value;
|
||||
}
|
||||
|
||||
public VerbButton()
|
||||
{
|
||||
AddChild(new HBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
(_icon = new TextureRect
|
||||
{
|
||||
CustomMinimumSize = (32, 32),
|
||||
Stretch = TextureRect.StretchMode.KeepCentered
|
||||
}),
|
||||
(_label = new Label()),
|
||||
// Padding
|
||||
new Control {CustomMinimumSize = (8, 0)}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected override void Draw(DrawingHandleScreen handle)
|
||||
{
|
||||
base.Draw(handle);
|
||||
|
||||
if (DrawMode == DrawModeEnum.Hover)
|
||||
{
|
||||
handle.DrawRect(PixelSizeBox, Color.DarkSlateGray);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class VerbGroupButton : Control
|
||||
{
|
||||
private static readonly TimeSpan HoverDelay = TimeSpan.FromSeconds(0.2);
|
||||
|
||||
private readonly VerbSystem _system;
|
||||
public List<ListedVerbData> VerbButtons { get; }
|
||||
private readonly Label _label;
|
||||
private readonly TextureRect _icon;
|
||||
|
||||
private CancellationTokenSource _openCancel;
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => _label.Text;
|
||||
set => _label.Text = value;
|
||||
}
|
||||
|
||||
public Texture Icon
|
||||
{
|
||||
get => _icon.Texture;
|
||||
set => _icon.Texture = value;
|
||||
}
|
||||
|
||||
public VerbGroupButton(VerbSystem system, List<ListedVerbData> verbButtons, SpriteSpecifier icon)
|
||||
{
|
||||
_system = system;
|
||||
VerbButtons = verbButtons;
|
||||
|
||||
MouseFilter = MouseFilterMode.Stop;
|
||||
|
||||
AddChild(new HBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
(_icon = new TextureRect
|
||||
{
|
||||
CustomMinimumSize = (32, 32),
|
||||
Stretch = TextureRect.StretchMode.KeepCentered
|
||||
}),
|
||||
|
||||
(_label = new Label
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand
|
||||
}),
|
||||
|
||||
// Padding
|
||||
new Control {CustomMinimumSize = (8, 0)},
|
||||
|
||||
new TextureRect
|
||||
{
|
||||
Texture = IoCManager.Resolve<IResourceCache>()
|
||||
.GetTexture("/Textures/UserInterface/VerbIcons/group.svg.96dpi.png"),
|
||||
Stretch = TextureRect.StretchMode.KeepCentered,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (icon != null)
|
||||
{
|
||||
_icon.Texture = icon.Frame0();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Draw(DrawingHandleScreen handle)
|
||||
{
|
||||
base.Draw(handle);
|
||||
|
||||
if (this == UserInterfaceManager.CurrentlyHovered)
|
||||
{
|
||||
handle.DrawRect(PixelSizeBox, Color.DarkSlateGray);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void MouseEntered()
|
||||
{
|
||||
base.MouseEntered();
|
||||
|
||||
_openCancel = new CancellationTokenSource();
|
||||
|
||||
Timer.Spawn(HoverDelay, () =>
|
||||
{
|
||||
if (_system._currentGroupList != null)
|
||||
{
|
||||
_system.CloseGroupMenu();
|
||||
}
|
||||
|
||||
var popup = _system._currentGroupList = new VerbPopup();
|
||||
|
||||
var first = true;
|
||||
foreach (var verb in VerbButtons)
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
popup.List.AddChild(new PanelContainer
|
||||
{
|
||||
CustomMinimumSize = (0, 2),
|
||||
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#333")}
|
||||
});
|
||||
}
|
||||
|
||||
first = false;
|
||||
|
||||
popup.List.AddChild(_system.CreateVerbButton(verb));
|
||||
}
|
||||
|
||||
UserInterfaceManager.ModalRoot.AddChild(popup);
|
||||
popup.Open(UIBox2.FromDimensions(GlobalPosition + (Width, 0), (1, 1)), GlobalPosition);
|
||||
}, _openCancel.Token);
|
||||
}
|
||||
|
||||
protected override void MouseExited()
|
||||
{
|
||||
base.MouseExited();
|
||||
|
||||
_openCancel?.Cancel();
|
||||
_openCancel = null;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class ListedVerbData
|
||||
{
|
||||
public string Text { get; }
|
||||
public bool Disabled { get; }
|
||||
public string VerbName { get; }
|
||||
public string OwnerName { get; }
|
||||
public SpriteSpecifier Icon { get; }
|
||||
public Action Action { get; }
|
||||
|
||||
public ListedVerbData(string text, bool disabled, string verbName, string ownerName,
|
||||
Action action, SpriteSpecifier icon)
|
||||
{
|
||||
Text = text;
|
||||
Disabled = disabled;
|
||||
VerbName = verbName;
|
||||
OwnerName = ownerName;
|
||||
Action = action;
|
||||
Icon = icon;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,17 +12,19 @@ namespace Content.Client.GlobalVerbs
|
||||
[GlobalVerb]
|
||||
class ViewVariablesVerb : GlobalVerb
|
||||
{
|
||||
public override string GetText(IEntity user, IEntity target) => "View variables";
|
||||
public override string GetCategory(IEntity user, IEntity target) => "Debug";
|
||||
|
||||
public override bool RequireInteractionRange => false;
|
||||
|
||||
public override VerbVisibility GetVisibility(IEntity user, IEntity target)
|
||||
public override void GetData(IEntity user, IEntity target, VerbData data)
|
||||
{
|
||||
var groupController = IoCManager.Resolve<IClientConGroupController>();
|
||||
if (groupController.CanViewVar())
|
||||
return VerbVisibility.Visible;
|
||||
return VerbVisibility.Invisible;
|
||||
if (!groupController.CanViewVar())
|
||||
{
|
||||
data.Visibility = VerbVisibility.Invisible;
|
||||
return;
|
||||
}
|
||||
|
||||
data.Text = "View Variables";
|
||||
data.CategoryData = VerbCategories.Debug;
|
||||
}
|
||||
|
||||
public override void Activate(IEntity user, IEntity target)
|
||||
|
||||
@@ -216,21 +216,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
|
||||
[Verb]
|
||||
private sealed class FillTargetVerb : Verb<SolutionComponent>
|
||||
{
|
||||
protected override string GetText(IEntity user, SolutionComponent component)
|
||||
{
|
||||
if(!user.TryGetComponent<HandsComponent>(out var hands))
|
||||
return "<I SHOULD BE INVISIBLE>";
|
||||
|
||||
if(hands.GetActiveHand == null)
|
||||
return "<I SHOULD BE INVISIBLE>";
|
||||
|
||||
var heldEntityName = hands.GetActiveHand.Owner?.Prototype?.Name ?? "<Item>";
|
||||
var myName = component.Owner.Prototype?.Name ?? "<Item>";
|
||||
|
||||
return $"Transfer liquid from [{heldEntityName}] to [{myName}].";
|
||||
}
|
||||
|
||||
protected override VerbVisibility GetVisibility(IEntity user, SolutionComponent component)
|
||||
protected override void GetData(IEntity user, SolutionComponent component, VerbData data)
|
||||
{
|
||||
if (user.TryGetComponent<HandsComponent>(out var hands))
|
||||
{
|
||||
@@ -238,13 +224,20 @@ namespace Content.Server.GameObjects.Components.Chemistry
|
||||
{
|
||||
if (hands.GetActiveHand.Owner.TryGetComponent<SolutionComponent>(out var solution))
|
||||
{
|
||||
if ((solution.Capabilities & SolutionCaps.PourOut) != 0 && (component.Capabilities & SolutionCaps.PourIn) != 0)
|
||||
return VerbVisibility.Visible;
|
||||
if ((solution.Capabilities & SolutionCaps.PourOut) != 0 &&
|
||||
(component.Capabilities & SolutionCaps.PourIn) != 0)
|
||||
{
|
||||
var heldEntityName = hands.GetActiveHand.Owner?.Prototype?.Name ?? "<Item>";
|
||||
var myName = component.Owner.Prototype?.Name ?? "<Item>";
|
||||
|
||||
data.Text= $"Transfer liquid from [{heldEntityName}] to [{myName}].";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return VerbVisibility.Invisible;
|
||||
data.Visibility = VerbVisibility.Invisible;
|
||||
}
|
||||
|
||||
protected override void Activate(IEntity user, SolutionComponent component)
|
||||
@@ -269,7 +262,6 @@ namespace Content.Server.GameObjects.Components.Chemistry
|
||||
|
||||
var transferSolution = handSolutionComp.SplitSolution(transferQuantity);
|
||||
component.TryAddSolution(transferSolution);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,21 +296,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
|
||||
[Verb]
|
||||
private sealed class EmptyTargetVerb : Verb<SolutionComponent>
|
||||
{
|
||||
protected override string GetText(IEntity user, SolutionComponent component)
|
||||
{
|
||||
if (!user.TryGetComponent<HandsComponent>(out var hands))
|
||||
return "<I SHOULD BE INVISIBLE>";
|
||||
|
||||
if (hands.GetActiveHand == null)
|
||||
return "<I SHOULD BE INVISIBLE>";
|
||||
|
||||
var heldEntityName = hands.GetActiveHand.Owner?.Prototype?.Name ?? "<Item>";
|
||||
var myName = component.Owner.Prototype?.Name ?? "<Item>";
|
||||
|
||||
return $"Transfer liquid from [{myName}] to [{heldEntityName}].";
|
||||
}
|
||||
|
||||
protected override VerbVisibility GetVisibility(IEntity user, SolutionComponent component)
|
||||
protected override void GetData(IEntity user, SolutionComponent component, VerbData data)
|
||||
{
|
||||
if (user.TryGetComponent<HandsComponent>(out var hands))
|
||||
{
|
||||
@@ -326,13 +304,20 @@ namespace Content.Server.GameObjects.Components.Chemistry
|
||||
{
|
||||
if (hands.GetActiveHand.Owner.TryGetComponent<SolutionComponent>(out var solution))
|
||||
{
|
||||
if ((solution.Capabilities & SolutionCaps.PourIn) != 0 && (component.Capabilities & SolutionCaps.PourOut) != 0)
|
||||
return VerbVisibility.Visible;
|
||||
if ((solution.Capabilities & SolutionCaps.PourIn) != 0 &&
|
||||
(component.Capabilities & SolutionCaps.PourOut) != 0)
|
||||
{
|
||||
var heldEntityName = hands.GetActiveHand.Owner?.Prototype?.Name ?? "<Item>";
|
||||
var myName = component.Owner.Prototype?.Name ?? "<Item>";
|
||||
|
||||
data.Text = $"Transfer liquid from [{myName}] to [{heldEntityName}].";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return VerbVisibility.Invisible;
|
||||
data.Visibility = VerbVisibility.Invisible;
|
||||
}
|
||||
|
||||
protected override void Activate(IEntity user, SolutionComponent component)
|
||||
|
||||
@@ -19,19 +19,18 @@ namespace Content.Server.GameObjects.Components.Fluids
|
||||
[Verb]
|
||||
private sealed class FillTargetVerb : Verb<CanSpillComponent>
|
||||
{
|
||||
protected override string GetText(IEntity user, CanSpillComponent component)
|
||||
protected override void GetData(IEntity user, CanSpillComponent component, VerbData data)
|
||||
{
|
||||
return "Spill liquid";
|
||||
if (!component.Owner.TryGetComponent(out SolutionComponent solutionComponent))
|
||||
{
|
||||
data.Visibility = VerbVisibility.Invisible;
|
||||
return;
|
||||
}
|
||||
|
||||
protected override VerbVisibility GetVisibility(IEntity user, CanSpillComponent component)
|
||||
{
|
||||
if (component.Owner.TryGetComponent(out SolutionComponent solutionComponent))
|
||||
{
|
||||
return solutionComponent.CurrentVolume > ReagentUnit.Zero ? VerbVisibility.Visible : VerbVisibility.Disabled;
|
||||
}
|
||||
|
||||
return VerbVisibility.Invisible;
|
||||
data.Text = "Spill liquid";
|
||||
data.Visibility = solutionComponent.CurrentVolume > ReagentUnit.Zero
|
||||
? VerbVisibility.Visible
|
||||
: VerbVisibility.Disabled;
|
||||
}
|
||||
|
||||
protected override void Activate(IEntity user, CanSpillComponent component)
|
||||
|
||||
@@ -250,14 +250,17 @@ namespace Content.Server.GameObjects.Components.Interactable
|
||||
[Verb]
|
||||
public sealed class EjectCellVerb : Verb<HandheldLightComponent>
|
||||
{
|
||||
protected override string GetText(IEntity user, HandheldLightComponent component)
|
||||
protected override void GetData(IEntity user, HandheldLightComponent component, VerbData data)
|
||||
{
|
||||
return component.Cell == null ? "Eject cell (cell missing)" : "Eject cell";
|
||||
if (component.Cell == null)
|
||||
{
|
||||
data.Text = "Eject cell (cell missing)";
|
||||
data.Visibility = VerbVisibility.Disabled;
|
||||
}
|
||||
|
||||
protected override VerbVisibility GetVisibility(IEntity user, HandheldLightComponent component)
|
||||
else
|
||||
{
|
||||
return component.Cell == null ? VerbVisibility.Disabled : VerbVisibility.Visible;
|
||||
data.Text = "Eject cell";
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Activate(IEntity user, HandheldLightComponent component)
|
||||
|
||||
@@ -328,16 +328,9 @@ namespace Content.Server.GameObjects.Components
|
||||
[Verb]
|
||||
private sealed class LockToggleVerb : Verb<EntityStorageComponent>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override string GetText(IEntity user, EntityStorageComponent component)
|
||||
protected override void GetData(IEntity user, EntityStorageComponent component, VerbData data)
|
||||
{
|
||||
return component._locked ? "Unlock" : "Lock";
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override VerbVisibility GetVisibility(IEntity user, EntityStorageComponent component)
|
||||
{
|
||||
return VerbVisibility.Visible;
|
||||
data.Text = component._locked ? "Unlock" : "Lock";
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -350,16 +343,15 @@ namespace Content.Server.GameObjects.Components
|
||||
[Verb]
|
||||
private sealed class OpenToggleVerb : Verb<EntityStorageComponent>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override string GetText(IEntity user, EntityStorageComponent component)
|
||||
protected override void GetData(IEntity user, EntityStorageComponent component, VerbData data)
|
||||
{
|
||||
return component.Open ? "Close" : "Open";
|
||||
if (component.NoDoor)
|
||||
{
|
||||
data.Visibility = VerbVisibility.Invisible;
|
||||
return;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override VerbVisibility GetVisibility(IEntity user, EntityStorageComponent component)
|
||||
{
|
||||
return component.NoDoor ? VerbVisibility.Invisible : VerbVisibility.Visible;
|
||||
data.Text = component.Open ? "Close" : "Open";
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -113,23 +113,15 @@ namespace Content.Server.GameObjects
|
||||
[Verb]
|
||||
public sealed class PickUpVerb : Verb<ItemComponent>
|
||||
{
|
||||
protected override string GetText(IEntity user, ItemComponent component)
|
||||
{
|
||||
if (user.TryGetComponent(out HandsComponent hands) && hands.IsHolding(component.Owner))
|
||||
{
|
||||
return "Pick Up (Already Holding)";
|
||||
}
|
||||
return "Pick Up";
|
||||
}
|
||||
|
||||
protected override VerbVisibility GetVisibility(IEntity user, ItemComponent component)
|
||||
protected override void GetData(IEntity user, ItemComponent component, VerbData data)
|
||||
{
|
||||
if (ContainerHelpers.IsInContainer(component.Owner) || !component.CanPickup(user))
|
||||
{
|
||||
return VerbVisibility.Invisible;
|
||||
data.Visibility = VerbVisibility.Invisible;
|
||||
return;
|
||||
}
|
||||
|
||||
return VerbVisibility.Visible;
|
||||
data.Text = "Pick Up";
|
||||
}
|
||||
|
||||
protected override void Activate(IEntity user, ItemComponent component)
|
||||
|
||||
@@ -128,14 +128,10 @@ namespace Content.Server.GameObjects.Components.Medical
|
||||
[Verb]
|
||||
public sealed class EnterVerb : Verb<MedicalScannerComponent>
|
||||
{
|
||||
protected override string GetText(IEntity user, MedicalScannerComponent component)
|
||||
protected override void GetData(IEntity user, MedicalScannerComponent component, VerbData data)
|
||||
{
|
||||
return "Enter";
|
||||
}
|
||||
|
||||
protected override VerbVisibility GetVisibility(IEntity user, MedicalScannerComponent component)
|
||||
{
|
||||
return component.IsOccupied ? VerbVisibility.Invisible : VerbVisibility.Visible;
|
||||
data.Text = "Enter";
|
||||
data.Visibility = component.IsOccupied ? VerbVisibility.Invisible : VerbVisibility.Visible;
|
||||
}
|
||||
|
||||
protected override void Activate(IEntity user, MedicalScannerComponent component)
|
||||
@@ -147,14 +143,10 @@ namespace Content.Server.GameObjects.Components.Medical
|
||||
[Verb]
|
||||
public sealed class EjectVerb : Verb<MedicalScannerComponent>
|
||||
{
|
||||
protected override string GetText(IEntity user, MedicalScannerComponent component)
|
||||
protected override void GetData(IEntity user, MedicalScannerComponent component, VerbData data)
|
||||
{
|
||||
return "Eject";
|
||||
}
|
||||
|
||||
protected override VerbVisibility GetVisibility(IEntity user, MedicalScannerComponent component)
|
||||
{
|
||||
return component.IsOccupied ? VerbVisibility.Visible : VerbVisibility.Invisible;
|
||||
data.Text = "Eject";
|
||||
data.Visibility = component.IsOccupied ? VerbVisibility.Visible : VerbVisibility.Invisible;
|
||||
}
|
||||
|
||||
protected override void Activate(IEntity user, MedicalScannerComponent component)
|
||||
|
||||
@@ -58,28 +58,22 @@ namespace Content.Server.GameObjects.Components.Power.Chargers
|
||||
[Verb]
|
||||
private sealed class InsertVerb : Verb<PowerCellChargerComponent>
|
||||
{
|
||||
protected override string GetText(IEntity user, PowerCellChargerComponent component)
|
||||
{
|
||||
if (!user.TryGetComponent(out HandsComponent handsComponent) || handsComponent.GetActiveHand == null)
|
||||
{
|
||||
return "Insert";
|
||||
}
|
||||
return $"Insert {handsComponent.GetActiveHand.Owner.Name}";
|
||||
}
|
||||
|
||||
protected override VerbVisibility GetVisibility(IEntity user, PowerCellChargerComponent component)
|
||||
protected override void GetData(IEntity user, PowerCellChargerComponent component, VerbData data)
|
||||
{
|
||||
if (!user.TryGetComponent(out HandsComponent handsComponent))
|
||||
{
|
||||
return VerbVisibility.Invisible;
|
||||
data.Visibility = VerbVisibility.Invisible;
|
||||
return;
|
||||
}
|
||||
|
||||
if (component._container.ContainedEntity != null || handsComponent.GetActiveHand == null)
|
||||
{
|
||||
return VerbVisibility.Disabled;
|
||||
data.Visibility = VerbVisibility.Disabled;
|
||||
data.Text = "Insert";
|
||||
return;
|
||||
}
|
||||
|
||||
return VerbVisibility.Visible;
|
||||
data.Text = $"Insert {handsComponent.GetActiveHand.Owner.Name}";
|
||||
}
|
||||
|
||||
protected override void Activate(IEntity user, PowerCellChargerComponent component)
|
||||
@@ -102,22 +96,16 @@ namespace Content.Server.GameObjects.Components.Power.Chargers
|
||||
[Verb]
|
||||
private sealed class EjectVerb : Verb<PowerCellChargerComponent>
|
||||
{
|
||||
protected override string GetText(IEntity user, PowerCellChargerComponent component)
|
||||
protected override void GetData(IEntity user, PowerCellChargerComponent component, VerbData data)
|
||||
{
|
||||
if (component._container.ContainedEntity == null)
|
||||
{
|
||||
return "Eject";
|
||||
}
|
||||
return $"Eject {component._container.ContainedEntity.Name}";
|
||||
data.Text = "Eject";
|
||||
data.Visibility = VerbVisibility.Disabled;
|
||||
return;
|
||||
}
|
||||
|
||||
protected override VerbVisibility GetVisibility(IEntity user, PowerCellChargerComponent component)
|
||||
{
|
||||
if (component._container.ContainedEntity == null)
|
||||
{
|
||||
return VerbVisibility.Disabled;
|
||||
}
|
||||
return VerbVisibility.Visible;
|
||||
data.Text = $"Eject {component._container.ContainedEntity.Name}";
|
||||
}
|
||||
|
||||
protected override void Activate(IEntity user, PowerCellChargerComponent component)
|
||||
|
||||
@@ -48,28 +48,27 @@ namespace Content.Server.GameObjects.Components.Power.Chargers
|
||||
[Verb]
|
||||
private sealed class InsertVerb : Verb<WeaponCapacitorChargerComponent>
|
||||
{
|
||||
protected override string GetText(IEntity user, WeaponCapacitorChargerComponent component)
|
||||
{
|
||||
if (!user.TryGetComponent(out HandsComponent handsComponent) || handsComponent.GetActiveHand == null)
|
||||
{
|
||||
return "Insert";
|
||||
}
|
||||
return $"Insert {handsComponent.GetActiveHand.Owner.Name}";
|
||||
}
|
||||
|
||||
protected override VerbVisibility GetVisibility(IEntity user, WeaponCapacitorChargerComponent component)
|
||||
protected override void GetData(IEntity user, WeaponCapacitorChargerComponent component, VerbData data)
|
||||
{
|
||||
if (!user.TryGetComponent(out HandsComponent handsComponent))
|
||||
{
|
||||
return VerbVisibility.Invisible;
|
||||
data.Visibility = VerbVisibility.Invisible;
|
||||
return;
|
||||
}
|
||||
|
||||
if (component._container.ContainedEntity != null || handsComponent.GetActiveHand == null)
|
||||
if (handsComponent.GetActiveHand == null)
|
||||
{
|
||||
return VerbVisibility.Disabled;
|
||||
data.Visibility = VerbVisibility.Disabled;
|
||||
data.Text = "Insert";
|
||||
return;
|
||||
}
|
||||
|
||||
return VerbVisibility.Visible;
|
||||
if (component._container.ContainedEntity != null)
|
||||
{
|
||||
data.Visibility = VerbVisibility.Disabled;
|
||||
}
|
||||
|
||||
data.Text = $"Insert {handsComponent.GetActiveHand.Owner.Name}";
|
||||
}
|
||||
|
||||
protected override void Activate(IEntity user, WeaponCapacitorChargerComponent component)
|
||||
@@ -92,22 +91,16 @@ namespace Content.Server.GameObjects.Components.Power.Chargers
|
||||
[Verb]
|
||||
private sealed class EjectVerb : Verb<WeaponCapacitorChargerComponent>
|
||||
{
|
||||
protected override string GetText(IEntity user, WeaponCapacitorChargerComponent component)
|
||||
protected override void GetData(IEntity user, WeaponCapacitorChargerComponent component, VerbData data)
|
||||
{
|
||||
if (component._container.ContainedEntity == null)
|
||||
{
|
||||
return "Eject";
|
||||
}
|
||||
return $"Eject {component._container.ContainedEntity.Name}";
|
||||
data.Visibility = VerbVisibility.Disabled;
|
||||
data.Text = "Eject";
|
||||
return;
|
||||
}
|
||||
|
||||
protected override VerbVisibility GetVisibility(IEntity user, WeaponCapacitorChargerComponent component)
|
||||
{
|
||||
if (component._container.ContainedEntity == null)
|
||||
{
|
||||
return VerbVisibility.Disabled;
|
||||
}
|
||||
return VerbVisibility.Visible;
|
||||
data.Text = $"Eject {component._container.ContainedEntity.Name}";
|
||||
}
|
||||
|
||||
protected override void Activate(IEntity user, WeaponCapacitorChargerComponent component)
|
||||
|
||||
@@ -35,16 +35,11 @@ namespace Content.Server.GameObjects.Components
|
||||
[Verb]
|
||||
public sealed class RotateVerb : Verb<RotatableComponent>
|
||||
{
|
||||
protected override string GetText(IEntity user, RotatableComponent component)
|
||||
protected override void GetData(IEntity user, RotatableComponent component, VerbData data)
|
||||
{
|
||||
return "Rotate clockwise";
|
||||
}
|
||||
|
||||
protected override string GetCategory(IEntity user, RotatableComponent component) => "Rotate";
|
||||
|
||||
protected override VerbVisibility GetVisibility(IEntity user, RotatableComponent component)
|
||||
{
|
||||
return VerbVisibility.Visible;
|
||||
data.CategoryData = VerbCategories.Rotate;
|
||||
data.Text = "Rotate clockwise";
|
||||
data.IconTexture = "/Textures/UserInterface/VerbIcons/rotate_cw.svg.96dpi.png";
|
||||
}
|
||||
|
||||
protected override void Activate(IEntity user, RotatableComponent component)
|
||||
@@ -56,16 +51,11 @@ namespace Content.Server.GameObjects.Components
|
||||
[Verb]
|
||||
public sealed class RotateCounterVerb : Verb<RotatableComponent>
|
||||
{
|
||||
protected override string GetText(IEntity user, RotatableComponent component)
|
||||
protected override void GetData(IEntity user, RotatableComponent component, VerbData data)
|
||||
{
|
||||
return "Rotate counter-clockwise";
|
||||
}
|
||||
|
||||
protected override string GetCategory(IEntity user, RotatableComponent component) => "Rotate";
|
||||
|
||||
protected override VerbVisibility GetVisibility(IEntity user, RotatableComponent component)
|
||||
{
|
||||
return VerbVisibility.Visible;
|
||||
data.CategoryData = VerbCategories.Rotate;
|
||||
data.Text = "Rotate counter-clockwise";
|
||||
data.IconTexture = "/Textures/UserInterface/VerbIcons/rotate_cw.svg.96dpi.png";
|
||||
}
|
||||
|
||||
protected override void Activate(IEntity user, RotatableComponent component)
|
||||
|
||||
@@ -266,14 +266,16 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile
|
||||
[Verb]
|
||||
public sealed class EjectMagazineVerb : Verb<BallisticMagazineWeaponComponent>
|
||||
{
|
||||
protected override string GetText(IEntity user, BallisticMagazineWeaponComponent component)
|
||||
protected override void GetData(IEntity user, BallisticMagazineWeaponComponent component, VerbData data)
|
||||
{
|
||||
return component.Magazine == null ? "Eject magazine (magazine missing)" : "Eject magazine";
|
||||
if (component.Magazine == null)
|
||||
{
|
||||
data.Text = "Eject magazine (magazine missing)";
|
||||
data.Visibility = VerbVisibility.Disabled;
|
||||
return;
|
||||
}
|
||||
|
||||
protected override VerbVisibility GetVisibility(IEntity user, BallisticMagazineWeaponComponent component)
|
||||
{
|
||||
return component.Magazine == null ? VerbVisibility.Disabled : VerbVisibility.Visible;
|
||||
data.Text = "Eject magazine";
|
||||
}
|
||||
|
||||
protected override void Activate(IEntity user, BallisticMagazineWeaponComponent component)
|
||||
|
||||
@@ -12,9 +12,9 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
public class VerbSystem : EntitySystem
|
||||
{
|
||||
#pragma warning disable 649
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IEntityManager _entityManager;
|
||||
#pragma warning restore 649
|
||||
#pragma warning restore 649
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -90,19 +90,19 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
|
||||
var userEntity = player.AttachedEntity;
|
||||
|
||||
var data = new List<VerbsResponseMessage.VerbData>();
|
||||
var data = new List<VerbsResponseMessage.NetVerbData>();
|
||||
//Get verbs, component dependent.
|
||||
foreach (var (component, verb) in VerbUtility.GetVerbs(entity))
|
||||
{
|
||||
if (verb.RequireInteractionRange && !VerbUtility.InVerbUseRange(userEntity, entity))
|
||||
continue;
|
||||
if (VerbUtility.IsVerbInvisible(verb, userEntity, component, out var vis))
|
||||
|
||||
var verbData = verb.GetData(userEntity, component);
|
||||
if (verbData.IsInvisible)
|
||||
continue;
|
||||
|
||||
// TODO: These keys being giant strings is inefficient as hell.
|
||||
data.Add(new VerbsResponseMessage.VerbData(verb.GetText(userEntity, component),
|
||||
$"{component.GetType()}:{verb.GetType()}", verb.GetCategory(userEntity, component),
|
||||
vis == VerbVisibility.Visible));
|
||||
data.Add(new VerbsResponseMessage.NetVerbData(verbData, $"{component.GetType()}:{verb.GetType()}"));
|
||||
}
|
||||
|
||||
//Get global verbs. Visible for all entities regardless of their components.
|
||||
@@ -110,14 +110,15 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
if (globalVerb.RequireInteractionRange && !VerbUtility.InVerbUseRange(userEntity, entity))
|
||||
continue;
|
||||
if (VerbUtility.IsVerbInvisible(globalVerb, userEntity, entity, out var vis))
|
||||
|
||||
var verbData = globalVerb.GetData(userEntity, entity);
|
||||
if (verbData.IsInvisible)
|
||||
continue;
|
||||
|
||||
data.Add(new VerbsResponseMessage.VerbData(globalVerb.GetText(userEntity, entity),
|
||||
globalVerb.GetType().ToString(), globalVerb.GetCategory(userEntity, entity), vis == VerbVisibility.Visible));
|
||||
data.Add(new VerbsResponseMessage.NetVerbData(verbData, globalVerb.GetType().ToString()));
|
||||
}
|
||||
|
||||
var response = new VerbsResponseMessage(data, req.EntityUid);
|
||||
var response = new VerbsResponseMessage(data.ToArray(), req.EntityUid);
|
||||
RaiseNetworkEvent(response, player.ConnectedClient);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,53 +1,64 @@
|
||||
using Content.Server.GameObjects;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.GameObjects.Components.Nutrition;
|
||||
using Content.Server.GameObjects.Components.Observer;
|
||||
using Content.Server.Players;
|
||||
using Content.Shared.GameObjects;
|
||||
using Robust.Server.Console;
|
||||
using Robust.Server.Interfaces.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
|
||||
namespace Content.Server.GlobalVerbs
|
||||
{
|
||||
[GlobalVerb]
|
||||
public class ControlMobVerb : GlobalVerb
|
||||
{
|
||||
public override string GetText(IEntity user, IEntity target) => "Control Mob";
|
||||
public override string GetCategory(IEntity user, IEntity target) => "Debug";
|
||||
|
||||
public override bool RequireInteractionRange => false;
|
||||
|
||||
public override VerbVisibility GetVisibility(IEntity user, IEntity target)
|
||||
public override void GetData(IEntity user, IEntity target, VerbData data)
|
||||
{
|
||||
data.Visibility = VerbVisibility.Invisible;
|
||||
|
||||
var groupController = IoCManager.Resolve<IConGroupController>();
|
||||
if (user == target) return VerbVisibility.Invisible;
|
||||
if (user == target)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.TryGetComponent<IActorComponent>(out var player))
|
||||
{
|
||||
if (!user.HasComponent<MindComponent>() || !target.HasComponent<MindComponent>())
|
||||
return VerbVisibility.Invisible;
|
||||
|
||||
if (groupController.CanCommand(player.playerSession, "controlmob"))
|
||||
return VerbVisibility.Visible;
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
return VerbVisibility.Invisible;
|
||||
if (groupController.CanCommand(player.playerSession, "controlmob"))
|
||||
{
|
||||
data.Visibility = VerbVisibility.Visible;
|
||||
data.Text = "Control Mob";
|
||||
data.CategoryData = VerbCategories.Debug;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Activate(IEntity user, IEntity target)
|
||||
{
|
||||
var userMind = user.GetComponent<IActorComponent>().playerSession.ContentData().Mind;
|
||||
var groupController = IoCManager.Resolve<IConGroupController>();
|
||||
|
||||
var player = user.GetComponent<IActorComponent>().playerSession;
|
||||
if (!groupController.CanCommand(player, "controlmob"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var userMind = player.ContentData().Mind;
|
||||
|
||||
var targetMind = target.GetComponent<MindComponent>();
|
||||
var oldEntity = userMind.CurrentEntity;
|
||||
|
||||
targetMind.Mind?.TransferTo(null);
|
||||
userMind.TransferTo(target);
|
||||
|
||||
if(oldEntity.HasComponent<GhostComponent>())
|
||||
if (oldEntity.HasComponent<GhostComponent>())
|
||||
oldEntity.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,24 +14,29 @@ namespace Content.Server.GlobalVerbs
|
||||
[GlobalVerb]
|
||||
class RejuvenateVerb : GlobalVerb
|
||||
{
|
||||
public override string GetText(IEntity user, IEntity target) => "Rejuvenate";
|
||||
public override string GetCategory(IEntity user, IEntity target) => "Debug";
|
||||
|
||||
public override bool RequireInteractionRange => false;
|
||||
|
||||
public override VerbVisibility GetVisibility(IEntity user, IEntity target)
|
||||
public override void GetData(IEntity user, IEntity target, VerbData data)
|
||||
{
|
||||
data.Text = "Rejuvenate";
|
||||
data.CategoryData = VerbCategories.Debug;
|
||||
data.Visibility = VerbVisibility.Invisible;
|
||||
|
||||
var groupController = IoCManager.Resolve<IConGroupController>();
|
||||
|
||||
if (user.TryGetComponent<IActorComponent>(out var player))
|
||||
{
|
||||
if (!target.HasComponent<DamageableComponent>() && !target.HasComponent<HungerComponent>() && !target.HasComponent<ThirstComponent>())
|
||||
return VerbVisibility.Invisible;
|
||||
if (!target.HasComponent<DamageableComponent>() && !target.HasComponent<HungerComponent>() &&
|
||||
!target.HasComponent<ThirstComponent>())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (groupController.CanCommand(player.playerSession, "rejuvenate"))
|
||||
return VerbVisibility.Visible;
|
||||
{
|
||||
data.Visibility = VerbVisibility.Visible;
|
||||
}
|
||||
}
|
||||
return VerbVisibility.Invisible;
|
||||
}
|
||||
|
||||
public override void Activate(IEntity user, IEntity target)
|
||||
@@ -42,7 +47,6 @@ namespace Content.Server.GlobalVerbs
|
||||
if (groupController.CanCommand(player.playerSession, "rejuvenate"))
|
||||
PerformRejuvenate(target);
|
||||
}
|
||||
|
||||
}
|
||||
public static void PerformRejuvenate(IEntity target)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.GameObjects.EntitySystemMessages
|
||||
{
|
||||
@@ -21,29 +22,33 @@ namespace Content.Shared.GameObjects.EntitySystemMessages
|
||||
[Serializable, NetSerializable]
|
||||
public class VerbsResponseMessage : EntitySystemMessage
|
||||
{
|
||||
public readonly List<VerbData> Verbs;
|
||||
public readonly NetVerbData[] Verbs;
|
||||
public readonly EntityUid Entity;
|
||||
|
||||
public VerbsResponseMessage(List<VerbData> verbs, EntityUid entity)
|
||||
public VerbsResponseMessage(NetVerbData[] verbs, EntityUid entity)
|
||||
{
|
||||
Verbs = verbs;
|
||||
Entity = entity;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public readonly struct VerbData
|
||||
public readonly struct NetVerbData
|
||||
{
|
||||
public readonly string Text;
|
||||
public readonly string Key;
|
||||
public readonly string Category;
|
||||
public readonly SpriteSpecifier Icon;
|
||||
public readonly SpriteSpecifier CategoryIcon;
|
||||
public readonly bool Available;
|
||||
|
||||
public VerbData(string text, string key, string category, bool available)
|
||||
public NetVerbData(VerbData data, string key)
|
||||
{
|
||||
Text = text;
|
||||
Text = data.Text;
|
||||
Key = key;
|
||||
Category = category;
|
||||
Available = available;
|
||||
Category = data.Category;
|
||||
CategoryIcon = data.CategoryIcon;
|
||||
Icon = data.Icon;
|
||||
Available = data.Visibility == VerbVisibility.Visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,25 +21,16 @@ namespace Content.Shared.GameObjects
|
||||
public virtual bool RequireInteractionRange => true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the text string that will be shown to <paramref name="user"/> in the right click menu.
|
||||
/// Gets the visible verb data for the user.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Implementations should write into <paramref name="data"/> to return their data.
|
||||
/// </remarks>
|
||||
/// <param name="user">The entity of the user opening this menu.</param>
|
||||
/// <param name="target">The entity this verb is being evaluated for.</param>
|
||||
/// <param name="data">The data that must be filled in.</param>
|
||||
/// <returns>The text string that is shown in the right click menu for this verb.</returns>
|
||||
public abstract string GetText(IEntity user, IEntity target);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the category of this verb.
|
||||
/// </summary>
|
||||
/// <param name="user">The entity of the user opening this menu.</param>
|
||||
/// <returns>The category of this verb.</returns>
|
||||
public virtual string GetCategory(IEntity user, IEntity target) => "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the visibility level of this verb in the right click menu.
|
||||
/// </summary>
|
||||
/// <param name="user">The entity of the user opening this menu.</param>
|
||||
/// <returns>The visibility level of the verb in the client's right click menu.</returns>
|
||||
public abstract VerbVisibility GetVisibility(IEntity user, IEntity target);
|
||||
public abstract void GetData(IEntity user, IEntity target, VerbData data);
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when this verb is activated from the right click menu.
|
||||
@@ -47,6 +38,13 @@ namespace Content.Shared.GameObjects
|
||||
/// <param name="user">The entity of the user opening this menu.</param>
|
||||
/// <param name="target">The entity that is being acted upon.</param>
|
||||
public abstract void Activate(IEntity user, IEntity target);
|
||||
|
||||
public VerbData GetData(IEntity user, IEntity target)
|
||||
{
|
||||
var data = new VerbData();
|
||||
GetData(user, target, data);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -19,33 +19,20 @@ namespace Content.Shared.GameObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// If true, this verb requires the user to be inside within
|
||||
/// <see cref="InteractionRange"/> meters from the entity on which this verb resides.
|
||||
/// <see cref="VerbUtility.InteractionRange"/> meters from the entity on which this verb resides.
|
||||
/// </summary>
|
||||
public virtual bool RequireInteractionRange => true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the text string that will be shown to <paramref name="user"/> in the right click menu.
|
||||
/// Gets the visible verb data for the user.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Implementations should write into <paramref name="data"/> to return their data.
|
||||
/// </remarks>
|
||||
/// <param name="user">The entity of the user opening this menu.</param>
|
||||
/// <param name="component">The component instance for which this verb is being loaded.</param>
|
||||
/// <returns>The text string that is shown in the right click menu for this verb.</returns>
|
||||
public abstract string GetText(IEntity user, IComponent component);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the category of this verb.
|
||||
/// </summary>
|
||||
/// <param name="user">The entity of the user opening this menu.</param>
|
||||
/// <param name="component">The component instance for which this verb is being loaded.</param>
|
||||
/// <returns>The category of this verb.</returns>
|
||||
public virtual string GetCategory(IEntity user, IComponent component) => "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the visibility level of this verb in the right click menu.
|
||||
/// </summary>
|
||||
/// <param name="user">The entity of the user opening this menu.</param>
|
||||
/// <param name="component">The component instance for which this verb is being loaded.</param>
|
||||
/// <returns>The visibility level of the verb in the client's right click menu.</returns>
|
||||
public abstract VerbVisibility GetVisibility(IEntity user, IComponent component);
|
||||
/// <param name="data">The data that must be filled into.</param>
|
||||
protected abstract void GetData(IEntity user, IComponent component, VerbData data);
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when this verb is activated from the right click menu.
|
||||
@@ -53,6 +40,13 @@ namespace Content.Shared.GameObjects
|
||||
/// <param name="user">The entity of the user opening this menu.</param>
|
||||
/// <param name="component">The component instance for which this verb is being loaded.</param>
|
||||
public abstract void Activate(IEntity user, IComponent component);
|
||||
|
||||
public VerbData GetData(IEntity user, IComponent component)
|
||||
{
|
||||
var data = new VerbData();
|
||||
GetData(user, component, data);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -64,28 +58,15 @@ namespace Content.Shared.GameObjects
|
||||
public abstract class Verb<T> : Verb where T : IComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the text string that will be shown to <paramref name="user"/> in the right click menu.
|
||||
/// Gets the visible verb data for the user.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Implementations should write into <paramref name="data"/> to return their data.
|
||||
/// </remarks>
|
||||
/// <param name="user">The entity of the user opening this menu.</param>
|
||||
/// <param name="component">The component instance for which this verb is being loaded.</param>
|
||||
/// <returns>The text string that is shown in the right click menu for this verb.</returns>
|
||||
protected abstract string GetText(IEntity user, T component);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the category of this verb.
|
||||
/// </summary>
|
||||
/// <param name="user">The entity of the user opening this menu.</param>
|
||||
/// <param name="component">The component instance for which this verb is being loaded.</param>
|
||||
/// <returns>The category of this verb.</returns>
|
||||
protected virtual string GetCategory(IEntity user, T component) => "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the visibility level of this verb in the right click menu.
|
||||
/// </summary>
|
||||
/// <param name="user">The entity of the user opening this menu.</param>
|
||||
/// <param name="component">The component instance for which this verb is being loaded.</param>
|
||||
/// <returns>The visibility level of the verb in the client's right click menu.</returns>
|
||||
protected abstract VerbVisibility GetVisibility(IEntity user, T component);
|
||||
/// <param name="data">The data that must be filled into.</param>
|
||||
protected abstract void GetData(IEntity user, T component, VerbData data);
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when this verb is activated from the right click menu.
|
||||
@@ -94,22 +75,9 @@ namespace Content.Shared.GameObjects
|
||||
/// <param name="component">The component instance for which this verb is being loaded.</param>
|
||||
protected abstract void Activate(IEntity user, T component);
|
||||
|
||||
/// <inheritdoc />
|
||||
public sealed override string GetText(IEntity user, IComponent component)
|
||||
protected sealed override void GetData(IEntity user, IComponent component, VerbData data)
|
||||
{
|
||||
return GetText(user, (T) component);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public sealed override string GetCategory(IEntity user, IComponent component)
|
||||
{
|
||||
return GetCategory(user, (T) component);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public sealed override VerbVisibility GetVisibility(IEntity user, IComponent component)
|
||||
{
|
||||
return GetVisibility(user, (T) component);
|
||||
GetData(user, (T) component, data);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -128,25 +96,4 @@ namespace Content.Shared.GameObjects
|
||||
public sealed class VerbAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Possible states of visibility for the verb in the right click menu.
|
||||
/// </summary>
|
||||
public enum VerbVisibility
|
||||
{
|
||||
/// <summary>
|
||||
/// The verb will be listed in the right click menu.
|
||||
/// </summary>
|
||||
Visible,
|
||||
|
||||
/// <summary>
|
||||
/// The verb will be listed, but it will be grayed out and unable to be clicked on.
|
||||
/// </summary>
|
||||
Disabled,
|
||||
|
||||
/// <summary>
|
||||
/// The verb will not be listed in the right click menu.
|
||||
/// </summary>
|
||||
Invisible
|
||||
}
|
||||
}
|
||||
|
||||
13
Content.Shared/GameObjects/Verbs/VerbCategories.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Content.Shared.GameObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// Standard verb categories.
|
||||
/// </summary>
|
||||
public static class VerbCategories
|
||||
{
|
||||
public static readonly VerbCategoryData Debug =
|
||||
("Debug", "/Textures/UserInterface/VerbIcons/debug.svg.96dpi.png");
|
||||
|
||||
public static readonly VerbCategoryData Rotate = ("Rotate", null);
|
||||
}
|
||||
}
|
||||
24
Content.Shared/GameObjects/Verbs/VerbCategoryData.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.GameObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains combined name and icon information for a verb category.
|
||||
/// </summary>
|
||||
public readonly struct VerbCategoryData
|
||||
{
|
||||
public VerbCategoryData(string name, SpriteSpecifier icon)
|
||||
{
|
||||
Name = name;
|
||||
Icon = icon;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public SpriteSpecifier Icon { get; }
|
||||
|
||||
public static implicit operator VerbCategoryData((string name, string icon) tuple)
|
||||
{
|
||||
return new VerbCategoryData(tuple.name, tuple.icon == null ? null : new SpriteSpecifier.Texture(new ResourcePath(tuple.icon)));
|
||||
}
|
||||
}
|
||||
}
|
||||
65
Content.Shared/GameObjects/Verbs/VerbData.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.GameObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores visual data for a verb.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// An instance of this class gets instantiated by the verb system and should be filled in by implementations of
|
||||
/// <see cref="Verb.GetData(IEntity, IComponent, VerbData)"/>.
|
||||
/// </remarks>
|
||||
public sealed class VerbData
|
||||
{
|
||||
/// <summary>
|
||||
/// The text that the user sees on the verb button.
|
||||
/// </summary>
|
||||
public string Text { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sprite of the icon that the user sees on the verb button.
|
||||
/// </summary>
|
||||
public SpriteSpecifier Icon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the category this button is under.
|
||||
/// </summary>
|
||||
public string Category { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Sprite of the icon that the user sees on the verb button.
|
||||
/// </summary>
|
||||
public SpriteSpecifier CategoryIcon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this verb is visible, disabled (greyed out) or hidden.
|
||||
/// </summary>
|
||||
public VerbVisibility Visibility { get; set; } = VerbVisibility.Visible;
|
||||
|
||||
public bool IsInvisible => Visibility == VerbVisibility.Invisible;
|
||||
public bool IsDisabled => Visibility == VerbVisibility.Disabled;
|
||||
|
||||
/// <summary>
|
||||
/// Convenience property to set verb category and icon at once.
|
||||
/// </summary>
|
||||
[ValueProvider("Content.Shared.GameObjects.VerbCategories")]
|
||||
public VerbCategoryData CategoryData
|
||||
{
|
||||
set
|
||||
{
|
||||
Category = value.Name;
|
||||
CategoryIcon = value.Icon;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convenience property to set <see cref="Icon"/> to a raw texture path.
|
||||
/// </summary>
|
||||
public string IconTexture
|
||||
{
|
||||
set => Icon = new SpriteSpecifier.Texture(new ResourcePath(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,17 +60,5 @@ namespace Content.Shared.GameObjects
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsVerbInvisible(Verb verb, IEntity user, IComponent target, out VerbVisibility visibility)
|
||||
{
|
||||
visibility = verb.GetVisibility(user, target);
|
||||
return visibility == VerbVisibility.Invisible;
|
||||
}
|
||||
|
||||
public static bool IsVerbInvisible(GlobalVerb verb, IEntity user, IEntity target, out VerbVisibility visibility)
|
||||
{
|
||||
visibility = verb.GetVisibility(user, target);
|
||||
return visibility == VerbVisibility.Invisible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
23
Content.Shared/GameObjects/Verbs/VerbVisibility.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace Content.Shared.GameObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// Possible states of visibility for the verb in the right click menu.
|
||||
/// </summary>
|
||||
public enum VerbVisibility
|
||||
{
|
||||
/// <summary>
|
||||
/// The verb will be listed in the right click menu.
|
||||
/// </summary>
|
||||
Visible,
|
||||
|
||||
/// <summary>
|
||||
/// The verb will be listed, but it will be grayed out and unable to be clicked on.
|
||||
/// </summary>
|
||||
Disabled,
|
||||
|
||||
/// <summary>
|
||||
/// The verb will not be listed in the right click menu.
|
||||
/// </summary>
|
||||
Invisible
|
||||
}
|
||||
}
|
||||
103
Resources/Textures/UserInterface/VerbIcons/debug.svg
Normal file
@@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 6.3499998 6.3500002"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
sodipodi:docname="debug.svg"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
inkscape:export-filename="/home/pj/Projects/space-station-14/Resources/Textures/UserInterface/VerbIcons/debug.svg.96dpi.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#1e2121"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="23.470348"
|
||||
inkscape:cx="10.081453"
|
||||
inkscape:cy="13.861109"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:document-rotation="0"
|
||||
showgrid="false"
|
||||
inkscape:pagecheckerboard="false"
|
||||
units="px"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1043"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-0.35898988,-0.29466516)">
|
||||
<path
|
||||
transform="matrix(0.26458333,0,0,0.26458333,0.35898988,0.29466516)"
|
||||
d="m 12,4.1367188 a 6.7719046,8.6036511 0 0 0 -6.7714844,8.6035152 6.7719046,8.6036511 0 0 0 5.4921874,8.449219 1.2499994,1.2499994 0 0 1 0,-0.04687 l 0.05859,-10.179687 a 1.2499994,1.2499994 0 0 1 1.253906,-1.2402348 1.2499994,1.2499994 0 0 1 1.240235,1.2558598 l -0.05078,10.179687 a 1.2499994,1.2499994 0 0 1 -0.002,0.04687 6.7719046,8.6036511 0 0 0 5.550781,-8.464844 A 6.7719046,8.6036511 0 0 0 12,4.1367188 Z"
|
||||
style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.1732;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="path2786" />
|
||||
<path
|
||||
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.74991px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||
d="M 2.8688267,4.6071132 1.3961568,5.9240289"
|
||||
id="path2790" />
|
||||
<path
|
||||
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.74991px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||
d="m 4.4712953,4.7414055 1.3160631,1.0882394 v 0"
|
||||
id="path2792" />
|
||||
<path
|
||||
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.74991px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||
d="m 4.2344863,3.7587164 2.043264,-0.027483"
|
||||
id="path2794" />
|
||||
<path
|
||||
style="fill:none;stroke:#ffffff;stroke-width:0.74991px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 3.1795381,2.9022976 1.1255836,1.7708898"
|
||||
id="path2796"
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:transform-center-x="0.12808358"
|
||||
inkscape:transform-center-y="0.13235299" />
|
||||
<path
|
||||
id="path2794-56"
|
||||
d="M 0.81382462,3.7512129 2.8570887,3.72373"
|
||||
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.74991px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" />
|
||||
<path
|
||||
inkscape:transform-center-y="0.17965894"
|
||||
inkscape:transform-center-x="-0.040563355"
|
||||
sodipodi:nodetypes="cc"
|
||||
id="path2796-2"
|
||||
d="M 5.9376668,1.8134763 3.8659632,2.912047"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:0.74991px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<ellipse
|
||||
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.79375;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||
id="path3479"
|
||||
cx="3.5339899"
|
||||
cy="1.4727732"
|
||||
rx="0.89334828"
|
||||
ry="0.8606078" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.1 KiB |
BIN
Resources/Textures/UserInterface/VerbIcons/debug.svg.96dpi.png
Normal file
|
After Width: | Height: | Size: 590 B |
68
Resources/Textures/UserInterface/VerbIcons/group.svg
Normal file
@@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
inkscape:export-ydpi="96"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-filename="/home/pj/Projects/space-station-14/Resources/Textures/UserInterface/VerbIcons/group.svg.96dpi.png"
|
||||
sodipodi:docname="group.svg"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
id="svg2892"
|
||||
version="1.1"
|
||||
viewBox="0 0 4.2333332 4.2333332"
|
||||
height="16"
|
||||
width="16">
|
||||
<defs
|
||||
id="defs2886" />
|
||||
<sodipodi:namedview
|
||||
units="px"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-height="1080"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:pagecheckerboard="true"
|
||||
showgrid="false"
|
||||
inkscape:document-rotation="0"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:document-units="px"
|
||||
inkscape:cy="7.7684689"
|
||||
inkscape:cx="8.625185"
|
||||
inkscape:zoom="38.76146"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff"
|
||||
id="base" />
|
||||
<metadata
|
||||
id="metadata2889">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:groupmode="layer"
|
||||
inkscape:label="Layer 1">
|
||||
<path
|
||||
id="path3455"
|
||||
d="M 5.3128544,3.0306137 5.2510052,13.878976 12.710029,8.4980906 Z"
|
||||
style="fill:none;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
id="path3457"
|
||||
d="M 1.4374722,0.75584911 2.8315087,2.0357963 1.4125146,3.3656578"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:0.52916665;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
BIN
Resources/Textures/UserInterface/VerbIcons/group.svg.96dpi.png
Normal file
|
After Width: | Height: | Size: 280 B |
73
Resources/Textures/UserInterface/VerbIcons/rotate_ccw.svg
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
inkscape:export-ydpi="96"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-filename="/home/pj/Projects/space-station-14/Resources/Textures/UserInterface/VerbIcons/rotate_ccw.svg.96dpi.png"
|
||||
sodipodi:docname="rotate_ccw.svg"
|
||||
id="svg8"
|
||||
version="1.1"
|
||||
viewBox="0 0 8.4666665 8.4666669"
|
||||
height="32"
|
||||
width="32">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-height="1043"
|
||||
inkscape:window-width="1920"
|
||||
units="px"
|
||||
inkscape:pagecheckerboard="true"
|
||||
showgrid="false"
|
||||
inkscape:document-rotation="0"
|
||||
inkscape:current-layer="a836"
|
||||
inkscape:document-units="px"
|
||||
inkscape:cy="22.023433"
|
||||
inkscape:cx="5.8819795"
|
||||
inkscape:zoom="11.617229"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff"
|
||||
id="base" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:groupmode="layer"
|
||||
inkscape:label="Layer 1">
|
||||
<a
|
||||
id="a836">
|
||||
<path
|
||||
id="path833"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:0.79375;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;stop-color:#000000"
|
||||
d="M 6.8444093,4.4763634 C 6.1968058,3.7953131 5.2819769,3.3707564 4.267987,3.3707564 c -1.0092212,0 -1.9202122,0.4205733 -2.5672681,1.0960146"
|
||||
sodipodi:nodetypes="csc" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
id="path1115"
|
||||
d="M 2.0746212,2.5444979 1.7007189,4.4667709 3.1208546,5.1803407"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:0.79375;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</a>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 417 B |
73
Resources/Textures/UserInterface/VerbIcons/rotate_cw.svg
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
inkscape:export-ydpi="96"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-filename="/home/pj/Projects/space-station-14/Resources/Textures/UserInterface/VerbIcons/rotate_cw.svg.96dpi.png"
|
||||
sodipodi:docname="rotate_cw.svg"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
id="svg8"
|
||||
version="1.1"
|
||||
viewBox="0 0 8.4666665 8.4666669"
|
||||
height="32"
|
||||
width="32">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-height="1043"
|
||||
inkscape:window-width="1920"
|
||||
units="px"
|
||||
inkscape:pagecheckerboard="true"
|
||||
showgrid="false"
|
||||
inkscape:document-rotation="0"
|
||||
inkscape:current-layer="a836"
|
||||
inkscape:document-units="px"
|
||||
inkscape:cy="23.917177"
|
||||
inkscape:cx="15.058009"
|
||||
inkscape:zoom="11.617229"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff"
|
||||
id="base" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:groupmode="layer"
|
||||
inkscape:label="Layer 1">
|
||||
<a
|
||||
id="a836">
|
||||
<path
|
||||
id="path833"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:0.79375;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;stop-color:#000000"
|
||||
d="m 1.5914553,4.4763634 c 0.6476035,-0.6810503 1.5624324,-1.105607 2.5764223,-1.105607 1.0092212,0 1.9202122,0.4205733 2.5672681,1.0960146"
|
||||
sodipodi:nodetypes="csc" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
id="path1115"
|
||||
d="M 6.3612434,2.5444979 6.7351457,4.4667709 5.31501,5.1803407"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:0.79375;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</a>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 427 B |
@@ -4,6 +4,10 @@ binds:
|
||||
type: state
|
||||
key: MouseLeft
|
||||
canFocus: true
|
||||
- function: CloseModals
|
||||
type: state
|
||||
key: Escape
|
||||
priority: 10
|
||||
- function: Use
|
||||
type: state
|
||||
key: MouseLeft
|
||||
@@ -215,6 +219,7 @@ binds:
|
||||
- function: TextReleaseFocus
|
||||
type: state
|
||||
key: Escape
|
||||
priority: 15
|
||||
- function: TextScrollToBottom
|
||||
type: state
|
||||
key: PageDown
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
<s:String x:Key="/Default/FilterSettingsManager/CoverageFilterXml/@EntryValue"><data><IncludeFilters /><ExcludeFilters><Filter ModuleMask="Lidgren.Network" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /></ExcludeFilters></data></s:String>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Fluidsynth/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=freepats/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Kibibyte/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Lerp/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Noto/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=occluder/@EntryIndexedValue">True</s:Boolean>
|
||||
|
||||