Merge branch 'master' into no-tscn
This commit is contained in:
@@ -127,6 +127,7 @@
|
|||||||
<Compile Include="UserInterface\LobbyGui.cs" />
|
<Compile Include="UserInterface\LobbyGui.cs" />
|
||||||
<Compile Include="UserInterface\NanoStyle.cs" />
|
<Compile Include="UserInterface\NanoStyle.cs" />
|
||||||
<Compile Include="UserInterface\Placeholder.cs" />
|
<Compile Include="UserInterface\Placeholder.cs" />
|
||||||
|
<Compile Include="UserInterface\TutorialButton.cs" />
|
||||||
<Compile Include="Utility\ResourceCacheExtensions.cs" />
|
<Compile Include="Utility\ResourceCacheExtensions.cs" />
|
||||||
<Compile Include="GameObjects\Components\Mobs\SpeciesVisualizer2D.cs" />
|
<Compile Include="GameObjects\Components\Mobs\SpeciesVisualizer2D.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
using Content.Client.UserInterface;
|
using Content.Client.UserInterface;
|
||||||
using Robust.Client.Console;
|
using Robust.Client.Console;
|
||||||
using Robust.Client.Interfaces.Graphics;
|
|
||||||
using Robust.Client.Interfaces.Input;
|
using Robust.Client.Interfaces.Input;
|
||||||
using Robust.Client.Interfaces.Placement;
|
using Robust.Client.Interfaces.Placement;
|
||||||
using Robust.Client.Interfaces.ResourceManagement;
|
using Robust.Client.Interfaces.ResourceManagement;
|
||||||
using Robust.Client.Interfaces.State;
|
using Robust.Client.Interfaces.State;
|
||||||
using Robust.Client.State.States;
|
using Robust.Client.State.States;
|
||||||
using Robust.Client.UserInterface.CustomControls;
|
|
||||||
using Robust.Shared.Input;
|
using Robust.Shared.Input;
|
||||||
using Robust.Shared.Interfaces.Configuration;
|
using Robust.Shared.Interfaces.Configuration;
|
||||||
using Robust.Shared.Interfaces.Map;
|
using Robust.Shared.Interfaces.Map;
|
||||||
@@ -19,7 +17,6 @@ namespace Content.Client
|
|||||||
{
|
{
|
||||||
#pragma warning disable 649
|
#pragma warning disable 649
|
||||||
[Dependency] private readonly IStateManager _stateManager;
|
[Dependency] private readonly IStateManager _stateManager;
|
||||||
[Dependency] private readonly IDisplayManager _displayManager;
|
|
||||||
[Dependency] private readonly IClientConsole _clientConsole;
|
[Dependency] private readonly IClientConsole _clientConsole;
|
||||||
[Dependency] private readonly ITileDefinitionManager _tileDefinitionManager;
|
[Dependency] private readonly ITileDefinitionManager _tileDefinitionManager;
|
||||||
[Dependency] private readonly IPlacementManager _placementManager;
|
[Dependency] private readonly IPlacementManager _placementManager;
|
||||||
@@ -41,7 +38,7 @@ namespace Content.Client
|
|||||||
if (obj.NewState is GameScreen)
|
if (obj.NewState is GameScreen)
|
||||||
{
|
{
|
||||||
// Switched TO GameScreen.
|
// Switched TO GameScreen.
|
||||||
_escapeMenu = new EscapeMenu(_displayManager, _clientConsole, _tileDefinitionManager, _placementManager,
|
_escapeMenu = new EscapeMenu(_clientConsole, _tileDefinitionManager, _placementManager,
|
||||||
_prototypeManager, _resourceCache, _configurationManager)
|
_prototypeManager, _resourceCache, _configurationManager)
|
||||||
{
|
{
|
||||||
Visible = false
|
Visible = false
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ namespace Content.Client.GameTicking
|
|||||||
[ViewVariables] private LobbyGui _lobby;
|
[ViewVariables] private LobbyGui _lobby;
|
||||||
[ViewVariables] private bool _gameStarted;
|
[ViewVariables] private bool _gameStarted;
|
||||||
[ViewVariables] private DateTime _startTime;
|
[ViewVariables] private DateTime _startTime;
|
||||||
|
[ViewVariables] private TutorialButton _tutorialButton;
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
@@ -66,6 +67,11 @@ namespace Content.Client.GameTicking
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_updatePlayerList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _updatePlayerList()
|
||||||
|
{
|
||||||
_lobby.OnlinePlayerItemList.Clear();
|
_lobby.OnlinePlayerItemList.Clear();
|
||||||
foreach (var session in _playerManager.Sessions.OrderBy(s => s.Name))
|
foreach (var session in _playerManager.Sessions.OrderBy(s => s.Name))
|
||||||
{
|
{
|
||||||
@@ -165,6 +171,12 @@ namespace Content.Client.GameTicking
|
|||||||
_gameChat = null;
|
_gameChat = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_tutorialButton != null)
|
||||||
|
{
|
||||||
|
_tutorialButton.Dispose();
|
||||||
|
_tutorialButton = null;
|
||||||
|
}
|
||||||
|
|
||||||
_tickerState = TickerState.InLobby;
|
_tickerState = TickerState.InLobby;
|
||||||
|
|
||||||
_lobby = new LobbyGui(_localization, _resourceCache);
|
_lobby = new LobbyGui(_localization, _resourceCache);
|
||||||
@@ -208,6 +220,8 @@ namespace Content.Client.GameTicking
|
|||||||
};
|
};
|
||||||
|
|
||||||
_lobby.LeaveButton.OnPressed += args => _console.ProcessCommand("disconnect");
|
_lobby.LeaveButton.OnPressed += args => _console.ProcessCommand("disconnect");
|
||||||
|
|
||||||
|
_updatePlayerList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void _joinGame(MsgTickerJoinGame message)
|
private void _joinGame(MsgTickerJoinGame message)
|
||||||
@@ -235,6 +249,9 @@ namespace Content.Client.GameTicking
|
|||||||
_gameChat = new ChatBox();
|
_gameChat = new ChatBox();
|
||||||
_userInterfaceManager.StateRoot.AddChild(_gameChat);
|
_userInterfaceManager.StateRoot.AddChild(_gameChat);
|
||||||
_chatManager.SetChatBox(_gameChat);
|
_chatManager.SetChatBox(_gameChat);
|
||||||
|
_tutorialButton = new TutorialButton();
|
||||||
|
_userInterfaceManager.StateRoot.AddChild(_tutorialButton);
|
||||||
|
_tutorialButton.SetAnchorAndMarginPreset(Control.LayoutPreset.BottomLeft, Control.LayoutPresetMode.MinSize, 50);
|
||||||
_gameChat.DefaultChatFormat = "say \"{0}\"";
|
_gameChat.DefaultChatFormat = "say \"{0}\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ namespace Content.Client.UserInterface
|
|||||||
private readonly IPlacementManager _placementManager;
|
private readonly IPlacementManager _placementManager;
|
||||||
private readonly IPrototypeManager _prototypeManager;
|
private readonly IPrototypeManager _prototypeManager;
|
||||||
private readonly IResourceCache _resourceCache;
|
private readonly IResourceCache _resourceCache;
|
||||||
private readonly IDisplayManager _displayManager;
|
|
||||||
private readonly IConfigurationManager _configSystem;
|
private readonly IConfigurationManager _configSystem;
|
||||||
|
|
||||||
private BaseButton QuitButton;
|
private BaseButton QuitButton;
|
||||||
@@ -27,16 +26,14 @@ namespace Content.Client.UserInterface
|
|||||||
private BaseButton SpawnTilesButton;
|
private BaseButton SpawnTilesButton;
|
||||||
private OptionsMenu optionsMenu;
|
private OptionsMenu optionsMenu;
|
||||||
|
|
||||||
public EscapeMenu(IDisplayManager displayManager,
|
public EscapeMenu(IClientConsole console,
|
||||||
IClientConsole console,
|
|
||||||
ITileDefinitionManager tileDefinitionManager,
|
ITileDefinitionManager tileDefinitionManager,
|
||||||
IPlacementManager placementManager,
|
IPlacementManager placementManager,
|
||||||
IPrototypeManager prototypeManager,
|
IPrototypeManager prototypeManager,
|
||||||
IResourceCache resourceCache,
|
IResourceCache resourceCache,
|
||||||
IConfigurationManager configSystem) : base(displayManager)
|
IConfigurationManager configSystem)
|
||||||
{
|
{
|
||||||
_configSystem = configSystem;
|
_configSystem = configSystem;
|
||||||
_displayManager = displayManager;
|
|
||||||
_console = console;
|
_console = console;
|
||||||
__tileDefinitionManager = tileDefinitionManager;
|
__tileDefinitionManager = tileDefinitionManager;
|
||||||
_placementManager = placementManager;
|
_placementManager = placementManager;
|
||||||
@@ -48,7 +45,7 @@ namespace Content.Client.UserInterface
|
|||||||
|
|
||||||
private void PerformLayout()
|
private void PerformLayout()
|
||||||
{
|
{
|
||||||
optionsMenu = new OptionsMenu(_displayManager, _configSystem)
|
optionsMenu = new OptionsMenu(_configSystem)
|
||||||
{
|
{
|
||||||
Visible = false
|
Visible = false
|
||||||
};
|
};
|
||||||
@@ -97,14 +94,14 @@ namespace Content.Client.UserInterface
|
|||||||
|
|
||||||
private void OnSpawnEntitiesButtonClicked(BaseButton.ButtonEventArgs args)
|
private void OnSpawnEntitiesButtonClicked(BaseButton.ButtonEventArgs args)
|
||||||
{
|
{
|
||||||
var window = new EntitySpawnWindow(_displayManager, _placementManager, _prototypeManager, _resourceCache);
|
var window = new EntitySpawnWindow(_placementManager, _prototypeManager, _resourceCache);
|
||||||
window.AddToScreen();
|
window.AddToScreen();
|
||||||
window.OpenToLeft();
|
window.OpenToLeft();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSpawnTilesButtonClicked(BaseButton.ButtonEventArgs args)
|
private void OnSpawnTilesButtonClicked(BaseButton.ButtonEventArgs args)
|
||||||
{
|
{
|
||||||
var window = new TileSpawnWindow(__tileDefinitionManager, _placementManager, _displayManager, _resourceCache);
|
var window = new TileSpawnWindow(__tileDefinitionManager, _placementManager, _resourceCache);
|
||||||
window.AddToScreen();
|
window.AddToScreen();
|
||||||
window.OpenToLeft();
|
window.OpenToLeft();
|
||||||
}
|
}
|
||||||
|
|||||||
61
Content.Client/UserInterface/TutorialButton.cs
Normal file
61
Content.Client/UserInterface/TutorialButton.cs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Client.UserInterface
|
||||||
|
{
|
||||||
|
internal sealed class TutorialButton : Button
|
||||||
|
{
|
||||||
|
private const string TutorialContents = @"Hi and welcome to Space Station 14!
|
||||||
|
|
||||||
|
This tutorial will assume that you know a bit about how SS13 plays.
|
||||||
|
It's mostly intended to lay out the controls and their differences from SS13.
|
||||||
|
|
||||||
|
Just like in any game, WASD is movement. If that does not work, the server probably broke.
|
||||||
|
|
||||||
|
Clicking on things ""interacts"" in some object-defined sense with it, with your active hand.
|
||||||
|
|
||||||
|
X switches hands. Z uses the item in your hand. Q drops items. T focuses chat. C opens your inventory.
|
||||||
|
|
||||||
|
New to SS14: You can press ""E"" to activate objects. This functions similarly to clicking with an empty hand most of the time: opens interfaces, etc. The difference is that it works even without an empty hand. No longer do you need to drop your tools to use a computer!
|
||||||
|
|
||||||
|
You can talk in OOC by prefixing the message with [ or /ooc.
|
||||||
|
|
||||||
|
If you are not on a QWERTY keyboard, the keys mentioned above are bound to the physical location on your keyboard,
|
||||||
|
not what letter they correspond to. For example on AZERTY movement is ZQSD, drop is A, W is activate in hand.
|
||||||
|
|
||||||
|
If you have any feedback, questions, bug reports, etc..., do not be afraid to tell us!
|
||||||
|
You can ask on Discord or heck, just write it in OOC, we'll catch it.
|
||||||
|
";
|
||||||
|
|
||||||
|
|
||||||
|
public TutorialButton()
|
||||||
|
{
|
||||||
|
OnPressed += OnOnPressed;
|
||||||
|
|
||||||
|
Text = "Tutorial";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnOnPressed(ButtonEventArgs obj)
|
||||||
|
{
|
||||||
|
_openTutorialWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _openTutorialWindow()
|
||||||
|
{
|
||||||
|
var window = new SS14Window {Title = "Tutorial"};
|
||||||
|
|
||||||
|
var scrollContainer = new ScrollContainer();
|
||||||
|
window.Contents.AddChild(scrollContainer);
|
||||||
|
|
||||||
|
var label = new RichTextLabel();
|
||||||
|
scrollContainer.AddChild(label);
|
||||||
|
|
||||||
|
var message = new FormattedMessage();
|
||||||
|
message.AddText(TutorialContents);
|
||||||
|
label.SetMessage(message);
|
||||||
|
|
||||||
|
window.AddToScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -142,7 +142,7 @@
|
|||||||
<Compile Include="GameObjects\EntitySystems\TemperatureSystem.cs" />
|
<Compile Include="GameObjects\EntitySystems\TemperatureSystem.cs" />
|
||||||
<Compile Include="GameTicking\GamePreset.cs" />
|
<Compile Include="GameTicking\GamePreset.cs" />
|
||||||
<Compile Include="GameTicking\GamePresets\PresetDeathMatch.cs" />
|
<Compile Include="GameTicking\GamePresets\PresetDeathMatch.cs" />
|
||||||
<Compile Include="GameTicking\GamePresets\PresetTraitor.cs" />
|
<Compile Include="GameTicking\GamePresets\PresetSandbox.cs" />
|
||||||
<Compile Include="GameTicking\GameRule.cs" />
|
<Compile Include="GameTicking\GameRule.cs" />
|
||||||
<Compile Include="GameTicking\GameRules\RuleDeathMatch.cs" />
|
<Compile Include="GameTicking\GameRules\RuleDeathMatch.cs" />
|
||||||
<Compile Include="GameTicking\GameTicker.cs" />
|
<Compile Include="GameTicking\GameTicker.cs" />
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ namespace Content.Server
|
|||||||
factory.Register<DestructibleComponent>();
|
factory.Register<DestructibleComponent>();
|
||||||
factory.Register<TemperatureComponent>();
|
factory.Register<TemperatureComponent>();
|
||||||
factory.Register<ServerDoorComponent>();
|
factory.Register<ServerDoorComponent>();
|
||||||
|
factory.RegisterReference<ServerDoorComponent, IActivate>();
|
||||||
|
|
||||||
//Power Components
|
//Power Components
|
||||||
factory.Register<PowerTransferComponent>();
|
factory.Register<PowerTransferComponent>();
|
||||||
@@ -127,6 +128,7 @@ namespace Content.Server
|
|||||||
factory.RegisterReference<ServerStorageComponent, IActivate>();
|
factory.RegisterReference<ServerStorageComponent, IActivate>();
|
||||||
factory.Register<EntityStorageComponent>();
|
factory.Register<EntityStorageComponent>();
|
||||||
factory.RegisterReference<EntityStorageComponent, IStorageComponent>();
|
factory.RegisterReference<EntityStorageComponent, IStorageComponent>();
|
||||||
|
factory.RegisterReference<EntityStorageComponent, IActivate>();
|
||||||
|
|
||||||
factory.Register<ToolLockerFillComponent>();
|
factory.Register<ToolLockerFillComponent>();
|
||||||
factory.Register<ToolboxElectricalFillComponent>();
|
factory.Register<ToolboxElectricalFillComponent>();
|
||||||
@@ -135,6 +137,7 @@ namespace Content.Server
|
|||||||
factory.Register<PoweredLightComponent>();
|
factory.Register<PoweredLightComponent>();
|
||||||
factory.Register<SmesComponent>();
|
factory.Register<SmesComponent>();
|
||||||
factory.Register<ApcComponent>();
|
factory.Register<ApcComponent>();
|
||||||
|
factory.RegisterReference<ApcComponent, IActivate>();
|
||||||
factory.Register<MaterialComponent>();
|
factory.Register<MaterialComponent>();
|
||||||
factory.Register<StackComponent>();
|
factory.Register<StackComponent>();
|
||||||
factory.Register<MaterialStorageComponent>();
|
factory.Register<MaterialStorageComponent>();
|
||||||
@@ -152,6 +155,7 @@ namespace Content.Server
|
|||||||
factory.RegisterReference<SpawnPointComponent, SharedSpawnPointComponent>();
|
factory.RegisterReference<SpawnPointComponent, SharedSpawnPointComponent>();
|
||||||
|
|
||||||
factory.Register<LatheComponent>();
|
factory.Register<LatheComponent>();
|
||||||
|
factory.RegisterReference<LatheComponent, IActivate>();
|
||||||
factory.Register<LatheDatabaseComponent>();
|
factory.Register<LatheDatabaseComponent>();
|
||||||
|
|
||||||
factory.RegisterReference<LatheDatabaseComponent, SharedLatheDatabaseComponent>();
|
factory.RegisterReference<LatheDatabaseComponent, SharedLatheDatabaseComponent>();
|
||||||
|
|||||||
@@ -93,6 +93,10 @@ namespace Content.Server.GameObjects.Components.Construction
|
|||||||
|
|
||||||
bool TryProcessStep(ConstructionStep step, IEntity slapped)
|
bool TryProcessStep(ConstructionStep step, IEntity slapped)
|
||||||
{
|
{
|
||||||
|
if (step == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
var sound = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AudioSystem>();
|
var sound = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AudioSystem>();
|
||||||
|
|
||||||
switch (step)
|
switch (step)
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ namespace Content.Server.GameObjects.Components.Construction
|
|||||||
var prototype = _prototypeManager.Index<ConstructionPrototype>(prototypeName);
|
var prototype = _prototypeManager.Index<ConstructionPrototype>(prototypeName);
|
||||||
|
|
||||||
var transform = Owner.Transform;
|
var transform = Owner.Transform;
|
||||||
if (!loc.InRange(_mapManager, transform.GridPosition, InteractionSystem.INTERACTION_RANGE))
|
if (!loc.InRange(_mapManager, transform.GridPosition, InteractionSystem.InteractionRange))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ using Robust.Shared.Timers;
|
|||||||
|
|
||||||
namespace Content.Server.GameObjects
|
namespace Content.Server.GameObjects
|
||||||
{
|
{
|
||||||
public class ServerDoorComponent : Component, IAttackHand
|
public class ServerDoorComponent : Component, IActivate
|
||||||
{
|
{
|
||||||
public override string Name => "Door";
|
public override string Name => "Door";
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ namespace Content.Server.GameObjects
|
|||||||
base.OnRemove();
|
base.OnRemove();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AttackHand(AttackHandEventArgs eventArgs)
|
void IActivate.Activate(ActivateEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
if (_state == DoorState.Open)
|
if (_state == DoorState.Open)
|
||||||
{
|
{
|
||||||
@@ -51,7 +51,6 @@ namespace Content.Server.GameObjects
|
|||||||
{
|
{
|
||||||
Open();
|
Open();
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
|
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
|
||||||
|
|||||||
@@ -462,8 +462,8 @@ namespace Content.Server.GameObjects
|
|||||||
var playerEntity = session.AttachedEntity;
|
var playerEntity = session.AttachedEntity;
|
||||||
var used = GetActiveHand?.Owner;
|
var used = GetActiveHand?.Owner;
|
||||||
|
|
||||||
if (playerEntity == Owner && used != null)
|
if (playerEntity == Owner && used != null && slot.ContainedEntity != null)
|
||||||
{
|
{
|
||||||
var interactionSystem = _entitySystemManager.GetEntitySystem<InteractionSystem>();
|
var interactionSystem = _entitySystemManager.GetEntitySystem<InteractionSystem>();
|
||||||
interactionSystem.Interaction(Owner, used, slot.ContainedEntity,
|
interactionSystem.Interaction(Owner, used, slot.ContainedEntity,
|
||||||
GridCoordinates.Nullspace);
|
GridCoordinates.Nullspace);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ using Robust.Server.GameObjects;
|
|||||||
|
|
||||||
namespace Content.Server.GameObjects.Components
|
namespace Content.Server.GameObjects.Components
|
||||||
{
|
{
|
||||||
public class EntityStorageComponent : Component, IAttackHand, IStorageComponent
|
public class EntityStorageComponent : Component, IActivate, IStorageComponent
|
||||||
{
|
{
|
||||||
public override string Name => "EntityStorage";
|
public override string Name => "EntityStorage";
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ namespace Content.Server.GameObjects.Components
|
|||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public bool Open { get; private set; }
|
public bool Open { get; private set; }
|
||||||
|
|
||||||
public bool AttackHand(AttackHandEventArgs eventArgs)
|
void IActivate.Activate(ActivateEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
if (Open)
|
if (Open)
|
||||||
{
|
{
|
||||||
@@ -51,7 +51,6 @@ namespace Content.Server.GameObjects.Components
|
|||||||
{
|
{
|
||||||
OpenStorage();
|
OpenStorage();
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CloseStorage()
|
private void CloseStorage()
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ using Robust.Shared.IoC;
|
|||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Power
|
namespace Content.Server.GameObjects.Components.Power
|
||||||
{
|
{
|
||||||
public sealed class ApcComponent : SharedApcComponent, IAttackHand
|
public sealed class ApcComponent : SharedApcComponent, IActivate
|
||||||
{
|
{
|
||||||
PowerStorageComponent Storage;
|
PowerStorageComponent Storage;
|
||||||
AppearanceComponent Appearance;
|
AppearanceComponent Appearance;
|
||||||
@@ -106,15 +106,14 @@ namespace Content.Server.GameObjects.Components.Power
|
|||||||
return net.Lack > 0 ? ApcExternalPowerState.Low : ApcExternalPowerState.Good;
|
return net.Lack > 0 ? ApcExternalPowerState.Low : ApcExternalPowerState.Good;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IAttackHand.AttackHand(AttackHandEventArgs eventArgs)
|
void IActivate.Activate(ActivateEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
if (!eventArgs.User.TryGetComponent(out IActorComponent actor))
|
if (!eventArgs.User.TryGetComponent(out IActorComponent actor))
|
||||||
{
|
{
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_userInterface.Open(actor.playerSession);
|
_userInterface.Open(actor.playerSession);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void _clickSound()
|
private void _clickSound()
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ using Robust.Shared.ViewVariables;
|
|||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Research
|
namespace Content.Server.GameObjects.Components.Research
|
||||||
{
|
{
|
||||||
public class LatheComponent : SharedLatheComponent, IAttackHand, IAttackBy, IActivate
|
public class LatheComponent : SharedLatheComponent, IAttackBy, IActivate
|
||||||
{
|
{
|
||||||
public const int VolumePerSheet = 3750;
|
public const int VolumePerSheet = 3750;
|
||||||
|
|
||||||
@@ -94,17 +94,6 @@ namespace Content.Server.GameObjects.Components.Research
|
|||||||
_userInterface.Open(actor.playerSession);
|
_userInterface.Open(actor.playerSession);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IAttackHand.AttackHand(AttackHandEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!eventArgs.User.TryGetComponent(out IActorComponent actor))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
_userInterface.Open(actor.playerSession);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IAttackBy.AttackBy(AttackByEventArgs eventArgs)
|
bool IAttackBy.AttackBy(AttackByEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
if (!Owner.TryGetComponent(out MaterialStorageComponent storage)
|
if (!Owner.TryGetComponent(out MaterialStorageComponent storage)
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
using System;
|
using System;
|
||||||
using Content.Server.Interfaces.GameObjects;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.GameObjects.Systems;
|
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Content.Server.Interfaces.GameObjects;
|
||||||
using Content.Shared.Input;
|
using Content.Shared.Input;
|
||||||
using Robust.Shared.Input;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.Log;
|
|
||||||
using Robust.Shared.Map;
|
|
||||||
using Robust.Server.GameObjects.EntitySystems;
|
using Robust.Server.GameObjects.EntitySystems;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.GameObjects.Systems;
|
||||||
|
using Robust.Shared.Input;
|
||||||
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
using Robust.Shared.Interfaces.GameObjects.Components;
|
using Robust.Shared.Interfaces.GameObjects.Components;
|
||||||
using Robust.Shared.Interfaces.Map;
|
using Robust.Shared.Interfaces.Map;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Log;
|
||||||
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Players;
|
using Robust.Shared.Players;
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.EntitySystems
|
namespace Content.Server.GameObjects.EntitySystems
|
||||||
@@ -26,9 +26,6 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when using one object on another
|
/// Called when using one object on another
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user"></param>
|
|
||||||
/// <param name="attackwith"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
bool AttackBy(AttackByEventArgs eventArgs);
|
bool AttackBy(AttackByEventArgs eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,8 +44,6 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when a player directly interacts with an empty hand
|
/// Called when a player directly interacts with an empty hand
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
bool AttackHand(AttackHandEventArgs eventArgs);
|
bool AttackHand(AttackHandEventArgs eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,13 +60,11 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when we try to interact with an entity out of range
|
/// Called when we try to interact with an entity out of range
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user"></param>
|
|
||||||
/// <param name="attackwith"></param>
|
|
||||||
/// <param name="clicklocation"></param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
bool RangedAttackBy(RangedAttackByEventArgs eventArgs);
|
bool RangedAttackBy(RangedAttackByEventArgs eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[PublicAPI]
|
||||||
public class RangedAttackByEventArgs : EventArgs
|
public class RangedAttackByEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public IEntity User { get; set; }
|
public IEntity User { get; set; }
|
||||||
@@ -88,9 +81,6 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when we interact with nothing, or when we interact with an entity out of range that has no behavior
|
/// Called when we interact with nothing, or when we interact with an entity out of range that has no behavior
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user"></param>
|
|
||||||
/// <param name="clicklocation"></param>
|
|
||||||
/// <param name="attacked">The entity that was clicked on out of range. May be null if no entity was clicked on.true</param>
|
|
||||||
void AfterAttack(AfterAttackEventArgs eventArgs);
|
void AfterAttack(AfterAttackEventArgs eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +99,6 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when we activate an object we are holding to use it
|
/// Called when we activate an object we are holding to use it
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user"></param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
bool UseEntity(UseEntityEventArgs eventArgs);
|
bool UseEntity(UseEntityEventArgs eventArgs);
|
||||||
}
|
}
|
||||||
@@ -127,7 +116,6 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when this component is activated by another entity.
|
/// Called when this component is activated by another entity.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user">Entity that activated this component.</param>
|
|
||||||
void Activate(ActivateEventArgs eventArgs);
|
void Activate(ActivateEventArgs eventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,50 +127,66 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Governs interactions during clicking on entities
|
/// Governs interactions during clicking on entities
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class InteractionSystem : EntitySystem
|
[UsedImplicitly]
|
||||||
|
public sealed class InteractionSystem : EntitySystem
|
||||||
{
|
{
|
||||||
#pragma warning disable 649
|
#pragma warning disable 649
|
||||||
[Dependency] private readonly IMapManager _mapManager;
|
[Dependency] private readonly IMapManager _mapManager;
|
||||||
#pragma warning restore 649
|
#pragma warning restore 649
|
||||||
|
|
||||||
public const float INTERACTION_RANGE = 2;
|
public const float InteractionRange = 2;
|
||||||
public const float INTERACTION_RANGE_SQUARED = INTERACTION_RANGE * INTERACTION_RANGE;
|
public const float InteractionRangeSquared = InteractionRange * InteractionRange;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
var inputSys = EntitySystemManager.GetEntitySystem<InputSystem>();
|
var inputSys = EntitySystemManager.GetEntitySystem<InputSystem>();
|
||||||
inputSys.BindMap.BindFunction(ContentKeyFunctions.UseItemInHand, new PointerInputCmdHandler(HandleUseItemInHand));
|
inputSys.BindMap.BindFunction(ContentKeyFunctions.UseItemInHand,
|
||||||
inputSys.BindMap.BindFunction(ContentKeyFunctions.ActivateItemInWorld, new PointerInputCmdHandler((HandleUseItemInWorld)));
|
new PointerInputCmdHandler(HandleUseItemInHand));
|
||||||
|
inputSys.BindMap.BindFunction(ContentKeyFunctions.ActivateItemInWorld,
|
||||||
|
new PointerInputCmdHandler((HandleActivateItemInWorld)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleUseItemInWorld(ICommonSession session, GridCoordinates coords, EntityUid uid)
|
public void HandleActivateItemInWorld(ICommonSession session, GridCoordinates coords, EntityUid uid)
|
||||||
{
|
{
|
||||||
if(!EntityManager.TryGetEntity(uid, out var used))
|
if (!EntityManager.TryGetEntity(uid, out var used))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var playerEnt = ((IPlayerSession) session).AttachedEntity;
|
var playerEnt = ((IPlayerSession) session).AttachedEntity;
|
||||||
|
|
||||||
if(playerEnt == null || !playerEnt.IsValid())
|
if (playerEnt == null || !playerEnt.IsValid())
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!playerEnt.Transform.GridPosition.InRange(_mapManager, used.Transform.GridPosition, INTERACTION_RANGE))
|
if (!playerEnt.Transform.GridPosition.InRange(_mapManager, used.Transform.GridPosition, InteractionRange))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var activateMsg = new ActivateInWorldMessage(playerEnt, used);
|
InteractionActivate(playerEnt, used);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InteractionActivate(IEntity user, IEntity used)
|
||||||
|
{
|
||||||
|
var activateMsg = new ActivateInWorldMessage(user, used);
|
||||||
RaiseEvent(activateMsg);
|
RaiseEvent(activateMsg);
|
||||||
if(activateMsg.Handled)
|
if (activateMsg.Handled)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!used.TryGetComponent(out IActivate activateComp))
|
if (!used.TryGetComponent(out IActivate activateComp))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
activateComp.Activate(new ActivateEventArgs { User = playerEnt });
|
activateComp.Activate(new ActivateEventArgs {User = user});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleUseItemInHand(ICommonSession session, GridCoordinates coords, EntityUid uid)
|
private void HandleUseItemInHand(ICommonSession session, GridCoordinates coords, EntityUid uid)
|
||||||
{
|
{
|
||||||
// client sanitization
|
// client sanitization
|
||||||
if(!_mapManager.GridExists(coords.GridID))
|
if (!_mapManager.GridExists(coords.GridID))
|
||||||
{
|
{
|
||||||
Logger.InfoS("system.interaction", $"Invalid Coordinates: client={session}, coords={coords}");
|
Logger.InfoS("system.interaction", $"Invalid Coordinates: client={session}, coords={coords}");
|
||||||
return;
|
return;
|
||||||
@@ -190,32 +194,37 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
|
|
||||||
if (uid.IsClientSide())
|
if (uid.IsClientSide())
|
||||||
{
|
{
|
||||||
Logger.WarningS("system.interaction", $"Client sent interaction with client-side entity. Session={session}, Uid={uid}");
|
Logger.WarningS("system.interaction",
|
||||||
|
$"Client sent interaction with client-side entity. Session={session}, Uid={uid}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UserInteraction(((IPlayerSession)session).AttachedEntity, coords, uid);
|
UserInteraction(((IPlayerSession) session).AttachedEntity, coords, uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UserInteraction(IEntity player, GridCoordinates coordinates, EntityUid clickedUid)
|
private void UserInteraction(IEntity player, GridCoordinates coordinates, EntityUid clickedUid)
|
||||||
{
|
{
|
||||||
//Get entity clicked upon from UID if valid UID, if not assume no entity clicked upon and null
|
// Get entity clicked upon from UID if valid UID, if not assume no entity clicked upon and null
|
||||||
if (!EntityManager.TryGetEntity(clickedUid, out var attacked))
|
if (!EntityManager.TryGetEntity(clickedUid, out var attacked))
|
||||||
|
{
|
||||||
attacked = null;
|
attacked = null;
|
||||||
|
}
|
||||||
|
|
||||||
//Verify player has a transform component
|
// Verify player has a transform component
|
||||||
if (!player.TryGetComponent<ITransformComponent>(out var playerTransform))
|
if (!player.TryGetComponent<ITransformComponent>(out var playerTransform))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//Verify player is on the same map as the entity he clicked on
|
|
||||||
else if (_mapManager.GetGrid(coordinates.GridID).ParentMap.Index != playerTransform.MapID)
|
// Verify player is on the same map as the entity he clicked on
|
||||||
|
if (_mapManager.GetGrid(coordinates.GridID).ParentMap.Index != playerTransform.MapID)
|
||||||
{
|
{
|
||||||
Logger.Warning(string.Format("Player named {0} clicked on a map he isn't located on", player.Name));
|
Logger.WarningS("system.interaction",
|
||||||
|
$"Player named {player.Name} clicked on a map he isn't located on");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Verify player has a hand, and find what object he is currently holding in his active hand
|
// Verify player has a hand, and find what object he is currently holding in his active hand
|
||||||
if (!player.TryGetComponent<IHandsComponent>(out var hands))
|
if (!player.TryGetComponent<IHandsComponent>(out var hands))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -224,59 +233,64 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
var item = hands.GetActiveHand?.Owner;
|
var item = hands.GetActiveHand?.Owner;
|
||||||
|
|
||||||
if (!ActionBlockerSystem.CanInteract(player))
|
if (!ActionBlockerSystem.CanInteract(player))
|
||||||
return;
|
|
||||||
//TODO: Check if client should be able to see that object to click on it in the first place, prevent using locaters by firing a laser or something
|
|
||||||
|
|
||||||
|
|
||||||
//Clicked on empty space behavior, try using ranged attack
|
|
||||||
if (attacked == null && item != null)
|
|
||||||
{
|
|
||||||
//AFTERATTACK: Check if we clicked on an empty location, if so the only interaction we can do is afterattack
|
|
||||||
InteractAfterattack(player, item, coordinates);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (attacked == null)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Verify attacked object is on the map if we managed to click on it somehow
|
// TODO: Check if client should be able to see that object to click on it in the first place
|
||||||
if (!attacked.GetComponent<ITransformComponent>().IsMapTransform)
|
|
||||||
{
|
|
||||||
Logger.Warning(string.Format("Player named {0} clicked on object {1} that isn't currently on the map somehow", player.Name, attacked.Name));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Check if ClickLocation is in object bounds here, if not lets log as warning and see why
|
// Clicked on empty space behavior, try using ranged attack
|
||||||
if (attacked.TryGetComponent(out BoundingBoxComponent boundingbox))
|
if (attacked == null)
|
||||||
{
|
{
|
||||||
if (!boundingbox.WorldAABB.Contains(coordinates.Position))
|
if (item != null)
|
||||||
{
|
{
|
||||||
Logger.Warning(string.Format("Player {0} clicked {1} outside of its bounding box component somehow", player.Name, attacked.Name));
|
// After attack: Check if we clicked on an empty location, if so the only interaction we can do is AfterAttack
|
||||||
|
InteractAfterAttack(player, item, coordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify attacked object is on the map if we managed to click on it somehow
|
||||||
|
if (!attacked.Transform.IsMapTransform)
|
||||||
|
{
|
||||||
|
Logger.WarningS("system.interaction",
|
||||||
|
$"Player named {player.Name} clicked on object {attacked.Name} that isn't currently on the map somehow");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if ClickLocation is in object bounds here, if not lets log as warning and see why
|
||||||
|
if (attacked.TryGetComponent(out BoundingBoxComponent boundingBox))
|
||||||
|
{
|
||||||
|
if (!boundingBox.WorldAABB.Contains(coordinates.Position))
|
||||||
|
{
|
||||||
|
Logger.WarningS("system.interaction",
|
||||||
|
$"Player {player.Name} clicked {attacked.Name} outside of its bounding box component somehow");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//RANGEDATTACK/AFTERATTACK: Check distance between user and clicked item, if too large parse it in the ranged function
|
// RangedAttack/AfterAttack: Check distance between user and clicked item, if too large parse it in the ranged function
|
||||||
//TODO: have range based upon the item being used? or base it upon some variables of the player himself?
|
// TODO: have range based upon the item being used? or base it upon some variables of the player himself?
|
||||||
var distance = (playerTransform.WorldPosition - attacked.GetComponent<ITransformComponent>().WorldPosition).LengthSquared;
|
var distance = (playerTransform.WorldPosition - attacked.Transform.WorldPosition).LengthSquared;
|
||||||
if (distance > INTERACTION_RANGE_SQUARED)
|
if (distance > InteractionRangeSquared)
|
||||||
{
|
{
|
||||||
if (item != null)
|
if (item != null)
|
||||||
{
|
{
|
||||||
RangedInteraction(player, item, attacked, coordinates);
|
RangedInteraction(player, item, attacked, coordinates);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return; //Add some form of ranged attackhand here if you need it someday, or perhaps just ways to modify the range of attackhand
|
|
||||||
|
return; // Add some form of ranged AttackHand here if you need it someday, or perhaps just ways to modify the range of AttackHand
|
||||||
}
|
}
|
||||||
|
|
||||||
//We are close to the nearby object and the object isn't contained in our active hand
|
// We are close to the nearby object and the object isn't contained in our active hand
|
||||||
//ATTACKBY/AFTERATTACK: We will either use the item on the nearby object
|
// AttackBy/AfterAttack: We will either use the item on the nearby object
|
||||||
if (item != null)
|
if (item != null)
|
||||||
{
|
{
|
||||||
Interaction(player, item, attacked, coordinates);
|
Interaction(player, item, attacked, coordinates);
|
||||||
}
|
}
|
||||||
//ATTACKHAND: Since our hand is empty we will use attackhand
|
// AttackHand/Activate: Since our hand is empty we will use AttackHand/Activate
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Interaction(player, attacked);
|
Interaction(player, attacked);
|
||||||
@@ -284,90 +298,101 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// We didn't click on any entity, try doing an afterattack on the click location
|
/// We didn't click on any entity, try doing an AfterAttack on the click location
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user"></param>
|
private void InteractAfterAttack(IEntity user, IEntity weapon, GridCoordinates clickLocation)
|
||||||
/// <param name="weapon"></param>
|
|
||||||
/// <param name="clicklocation"></param>
|
|
||||||
public void InteractAfterattack(IEntity user, IEntity weapon, GridCoordinates clicklocation)
|
|
||||||
{
|
{
|
||||||
var message = new AfterAttackMessage(user, weapon, null, clicklocation);
|
var message = new AfterAttackMessage(user, weapon, null, clickLocation);
|
||||||
RaiseEvent(message);
|
RaiseEvent(message);
|
||||||
if(message.Handled)
|
if (message.Handled)
|
||||||
return;
|
|
||||||
|
|
||||||
List<IAfterAttack> afterattacks = weapon.GetAllComponents<IAfterAttack>().ToList();
|
|
||||||
|
|
||||||
for (var i = 0; i < afterattacks.Count; i++)
|
|
||||||
{
|
{
|
||||||
afterattacks[i].AfterAttack(new AfterAttackEventArgs { User = user, ClickLocation = clicklocation });
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var afterAttacks = weapon.GetAllComponents<IAfterAttack>().ToList();
|
||||||
|
var afterAttackEventArgs = new AfterAttackEventArgs {User = user, ClickLocation = clickLocation};
|
||||||
|
|
||||||
|
foreach (var afterAttack in afterAttacks)
|
||||||
|
{
|
||||||
|
afterAttack.AfterAttack(afterAttackEventArgs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Uses a weapon/object on an entity
|
/// Uses a weapon/object on an entity
|
||||||
/// Finds interactable components with the Attackby interface and calls their function
|
/// Finds components with the AttackBy interface and calls their function
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user"></param>
|
public void Interaction(IEntity user, IEntity weapon, IEntity attacked, GridCoordinates clickLocation)
|
||||||
/// <param name="weapon"></param>
|
|
||||||
/// <param name="attacked"></param>
|
|
||||||
public void Interaction(IEntity user, IEntity weapon, IEntity attacked, GridCoordinates clicklocation)
|
|
||||||
{
|
{
|
||||||
var attackMsg = new AttackByMessage(user, weapon, attacked, clicklocation);
|
var attackMsg = new AttackByMessage(user, weapon, attacked, clickLocation);
|
||||||
RaiseEvent(attackMsg);
|
RaiseEvent(attackMsg);
|
||||||
if(attackMsg.Handled)
|
if (attackMsg.Handled)
|
||||||
return;
|
|
||||||
|
|
||||||
List<IAttackBy> interactables = attacked.GetAllComponents<IAttackBy>().ToList();
|
|
||||||
|
|
||||||
for (var i = 0; i < interactables.Count; i++)
|
|
||||||
{
|
{
|
||||||
if (interactables[i].AttackBy(new AttackByEventArgs { User = user, ClickLocation = clicklocation, AttackWith = weapon })) //If an attackby returns a status completion we finish our attack
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var attackBys = attacked.GetAllComponents<IAttackBy>().ToList();
|
||||||
|
var attackByEventArgs = new AttackByEventArgs
|
||||||
|
{
|
||||||
|
User = user, ClickLocation = clickLocation, AttackWith = weapon
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var attackBy in attackBys)
|
||||||
|
{
|
||||||
|
if (attackBy.AttackBy(attackByEventArgs))
|
||||||
{
|
{
|
||||||
|
// If an AttackBy returns a status completion we finish our attack
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Else check damage component to see if we damage if not attackby, and if so can we attack object
|
var afterAtkMsg = new AfterAttackMessage(user, weapon, attacked, clickLocation);
|
||||||
|
|
||||||
var afterAtkMsg = new AfterAttackMessage(user, weapon, attacked, clicklocation);
|
|
||||||
RaiseEvent(afterAtkMsg);
|
RaiseEvent(afterAtkMsg);
|
||||||
if (afterAtkMsg.Handled)
|
if (afterAtkMsg.Handled)
|
||||||
return;
|
|
||||||
|
|
||||||
//If we aren't directly attacking the nearby object, lets see if our item has an after attack we can do
|
|
||||||
List<IAfterAttack> afterattacks = weapon.GetAllComponents<IAfterAttack>().ToList();
|
|
||||||
|
|
||||||
for (var i = 0; i < afterattacks.Count; i++)
|
|
||||||
{
|
{
|
||||||
afterattacks[i].AfterAttack(new AfterAttackEventArgs { User = user, ClickLocation = clicklocation, Attacked = attacked });
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we aren't directly attacking the nearby object, lets see if our item has an after attack we can do
|
||||||
|
var afterAttacks = weapon.GetAllComponents<IAfterAttack>().ToList();
|
||||||
|
var afterAttackEventArgs = new AfterAttackEventArgs
|
||||||
|
{
|
||||||
|
User = user, ClickLocation = clickLocation, Attacked = attacked
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var afterAttack in afterAttacks)
|
||||||
|
{
|
||||||
|
afterAttack.AfterAttack(afterAttackEventArgs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Uses an empty hand on an entity
|
/// Uses an empty hand on an entity
|
||||||
/// Finds interactable components with the Attackhand interface and calls their function
|
/// Finds components with the AttackHand interface and calls their function
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user"></param>
|
|
||||||
/// <param name="attacked"></param>
|
|
||||||
public void Interaction(IEntity user, IEntity attacked)
|
public void Interaction(IEntity user, IEntity attacked)
|
||||||
{
|
{
|
||||||
var message = new AttackHandMessage(user, attacked);
|
var message = new AttackHandMessage(user, attacked);
|
||||||
RaiseEvent(message);
|
RaiseEvent(message);
|
||||||
if(message.Handled)
|
if (message.Handled)
|
||||||
return;
|
|
||||||
|
|
||||||
List<IAttackHand> interactables = attacked.GetAllComponents<IAttackHand>().ToList();
|
|
||||||
|
|
||||||
for (var i = 0; i < interactables.Count; i++)
|
|
||||||
{
|
{
|
||||||
if (interactables[i].AttackHand(new AttackHandEventArgs { User = user})) //If an attackby returns a status completion we finish our attack
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var attackHands = attacked.GetAllComponents<IAttackHand>().ToList();
|
||||||
|
var attackHandEventArgs = new AttackHandEventArgs {User = user};
|
||||||
|
|
||||||
|
foreach (var attackHand in attackHands)
|
||||||
|
{
|
||||||
|
if (attackHand.AttackHand(attackHandEventArgs))
|
||||||
{
|
{
|
||||||
|
// If an AttackHand returns a status completion we finish our attack
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Else check damage component to see if we damage if not attackby, and if so can we attack object
|
// Else we run Activate.
|
||||||
|
InteractionActivate(user, attacked);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -388,22 +413,23 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
/// Activates/Uses an object in control/possession of a user
|
/// Activates/Uses an object in control/possession of a user
|
||||||
/// If the item has the IUse interface on one of its components we use the object in our hand
|
/// If the item has the IUse interface on one of its components we use the object in our hand
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user"></param>
|
|
||||||
/// <param name="attacked"></param>
|
|
||||||
public void UseInteraction(IEntity user, IEntity used)
|
public void UseInteraction(IEntity user, IEntity used)
|
||||||
{
|
{
|
||||||
var useMsg = new UseInHandMessage(user, used);
|
var useMsg = new UseInHandMessage(user, used);
|
||||||
RaiseEvent(useMsg);
|
RaiseEvent(useMsg);
|
||||||
if(useMsg.Handled)
|
if (useMsg.Handled)
|
||||||
return;
|
|
||||||
|
|
||||||
List<IUse> usables = used.GetAllComponents<IUse>().ToList();
|
|
||||||
|
|
||||||
//Try to use item on any components which have the interface
|
|
||||||
for (var i = 0; i < usables.Count; i++)
|
|
||||||
{
|
{
|
||||||
if (usables[i].UseEntity(new UseEntityEventArgs { User = user })) //If an attackby returns a status completion we finish our attack
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var uses = used.GetAllComponents<IUse>().ToList();
|
||||||
|
|
||||||
|
// Try to use item on any components which have the interface
|
||||||
|
foreach (var use in uses)
|
||||||
|
{
|
||||||
|
if (use.UseEntity(new UseEntityEventArgs {User = user}))
|
||||||
{
|
{
|
||||||
|
// If a Use returns a status completion we finish our attack
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -413,41 +439,44 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
/// Will have two behaviors, either "uses" the weapon at range on the entity if it is capable of accepting that action
|
/// Will have two behaviors, either "uses" the weapon at range on the entity if it is capable of accepting that action
|
||||||
/// Or it will use the weapon itself on the position clicked, regardless of what was there
|
/// Or it will use the weapon itself on the position clicked, regardless of what was there
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user"></param>
|
|
||||||
/// <param name="weapon"></param>
|
|
||||||
/// <param name="attacked"></param>
|
|
||||||
public void RangedInteraction(IEntity user, IEntity weapon, IEntity attacked, GridCoordinates clickLocation)
|
public void RangedInteraction(IEntity user, IEntity weapon, IEntity attacked, GridCoordinates clickLocation)
|
||||||
{
|
{
|
||||||
var rangedMsg = new RangedAttackMessage(user, weapon, attacked, clickLocation);
|
var rangedMsg = new RangedAttackMessage(user, weapon, attacked, clickLocation);
|
||||||
RaiseEvent(rangedMsg);
|
RaiseEvent(rangedMsg);
|
||||||
if(rangedMsg.Handled)
|
if (rangedMsg.Handled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
List<IRangedAttackBy> rangedusables = attacked.GetAllComponents<IRangedAttackBy>().ToList();
|
var rangedAttackBys = attacked.GetAllComponents<IRangedAttackBy>().ToList();
|
||||||
|
var rangedAttackByEventArgs = new RangedAttackByEventArgs
|
||||||
//See if we have a ranged attack interaction
|
|
||||||
for (var i = 0; i < rangedusables.Count; i++)
|
|
||||||
{
|
{
|
||||||
if (rangedusables[i].RangedAttackBy(new RangedAttackByEventArgs { User = user, Weapon = weapon, ClickLocation = clickLocation })) //If an attackby returns a status completion we finish our attack
|
User = user, Weapon = weapon, ClickLocation = clickLocation
|
||||||
|
};
|
||||||
|
|
||||||
|
// See if we have a ranged attack interaction
|
||||||
|
foreach (var t in rangedAttackBys)
|
||||||
|
{
|
||||||
|
if (t.RangedAttackBy(rangedAttackByEventArgs))
|
||||||
{
|
{
|
||||||
|
// If an AttackBy returns a status completion we finish our attack
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (weapon != null)
|
var afterAtkMsg = new AfterAttackMessage(user, weapon, attacked, clickLocation);
|
||||||
|
RaiseEvent(afterAtkMsg);
|
||||||
|
if (afterAtkMsg.Handled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var afterAttacks = weapon.GetAllComponents<IAfterAttack>().ToList();
|
||||||
|
var afterAttackEventArgs = new AfterAttackEventArgs
|
||||||
{
|
{
|
||||||
var afterAtkMsg = new AfterAttackMessage(user, weapon, attacked, clickLocation);
|
User = user, ClickLocation = clickLocation, Attacked = attacked
|
||||||
RaiseEvent(afterAtkMsg);
|
};
|
||||||
if (afterAtkMsg.Handled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
List<IAfterAttack> afterattacks = weapon.GetAllComponents<IAfterAttack>().ToList();
|
//See if we have a ranged attack interaction
|
||||||
|
foreach (var afterAttack in afterAttacks)
|
||||||
//See if we have a ranged attack interaction
|
{
|
||||||
for (var i = 0; i < afterattacks.Count; i++)
|
afterAttack.AfterAttack(afterAttackEventArgs);
|
||||||
{
|
|
||||||
afterattacks[i].AfterAttack(new AfterAttackEventArgs { User = user, ClickLocation = clickLocation, Attacked = attacked });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -455,6 +484,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raised when being clicked on or "attacked" by a user with an object in their hand
|
/// Raised when being clicked on or "attacked" by a user with an object in their hand
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[PublicAPI]
|
||||||
public class AttackByMessage : EntitySystemMessage
|
public class AttackByMessage : EntitySystemMessage
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -471,7 +501,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
/// Entity that the User attacked with.
|
/// Entity that the User attacked with.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEntity ItemInHand { get; }
|
public IEntity ItemInHand { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Entity that was attacked.
|
/// Entity that was attacked.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -494,6 +524,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raised when being clicked on or "attacked" by a user with an empty hand.
|
/// Raised when being clicked on or "attacked" by a user with an empty hand.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[PublicAPI]
|
||||||
public class AttackHandMessage : EntitySystemMessage
|
public class AttackHandMessage : EntitySystemMessage
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -521,6 +552,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raised when being clicked by objects outside the range of direct use.
|
/// Raised when being clicked by objects outside the range of direct use.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[PublicAPI]
|
||||||
public class RangedAttackMessage : EntitySystemMessage
|
public class RangedAttackMessage : EntitySystemMessage
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -560,6 +592,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raised when clicking on another object and no attack event was handled.
|
/// Raised when clicking on another object and no attack event was handled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[PublicAPI]
|
||||||
public class AfterAttackMessage : EntitySystemMessage
|
public class AfterAttackMessage : EntitySystemMessage
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -599,6 +632,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raised when using the entity in your hands.
|
/// Raised when using the entity in your hands.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[PublicAPI]
|
||||||
public class UseInHandMessage : EntitySystemMessage
|
public class UseInHandMessage : EntitySystemMessage
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -626,6 +660,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raised when an entity is activated in the world.
|
/// Raised when an entity is activated in the world.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[PublicAPI]
|
||||||
public class ActivateInWorldMessage : EntitySystemMessage
|
public class ActivateInWorldMessage : EntitySystemMessage
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
var distanceSquared = (storagePos - attachedEntity.Transform.WorldPosition).LengthSquared;
|
var distanceSquared = (storagePos - attachedEntity.Transform.WorldPosition).LengthSquared;
|
||||||
if (distanceSquared > InteractionSystem.INTERACTION_RANGE_SQUARED)
|
if (distanceSquared > InteractionSystem.InteractionRangeSquared)
|
||||||
{
|
{
|
||||||
storageComp.UnsubscribeSession(session);
|
storageComp.UnsubscribeSession(session);
|
||||||
}
|
}
|
||||||
|
|||||||
10
Content.Server/GameTicking/GamePresets/PresetSandbox.cs
Normal file
10
Content.Server/GameTicking/GamePresets/PresetSandbox.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Content.Server.GameTicking.GamePresets
|
||||||
|
{
|
||||||
|
public sealed class PresetSandbox : GamePreset
|
||||||
|
{
|
||||||
|
public override void Start()
|
||||||
|
{
|
||||||
|
// Nothing yet.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
using Robust.Shared.Log;
|
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.GamePresets
|
|
||||||
{
|
|
||||||
public class PresetTraitor : GamePreset
|
|
||||||
{
|
|
||||||
public override void Start()
|
|
||||||
{
|
|
||||||
Logger.DebugS("ticker.preset", "Current preset is traitor.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,13 +15,13 @@ using Robust.Server.Interfaces.Maps;
|
|||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Console;
|
|
||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.Interfaces.Configuration;
|
using Robust.Shared.Interfaces.Configuration;
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
using Robust.Shared.Interfaces.Map;
|
using Robust.Shared.Interfaces.Map;
|
||||||
using Robust.Shared.Interfaces.Network;
|
using Robust.Shared.Interfaces.Network;
|
||||||
|
using Robust.Shared.Interfaces.Reflection;
|
||||||
using Robust.Shared.Interfaces.Timing;
|
using Robust.Shared.Interfaces.Timing;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Log;
|
using Robust.Shared.Log;
|
||||||
@@ -81,6 +81,8 @@ namespace Content.Server.GameTicking
|
|||||||
|
|
||||||
[ViewVariables] private readonly List<GameRule> _gameRules = new List<GameRule>();
|
[ViewVariables] private readonly List<GameRule> _gameRules = new List<GameRule>();
|
||||||
|
|
||||||
|
[ViewVariables] private Type _presetType;
|
||||||
|
|
||||||
#pragma warning disable 649
|
#pragma warning disable 649
|
||||||
[Dependency] private IEntityManager _entityManager;
|
[Dependency] private IEntityManager _entityManager;
|
||||||
[Dependency] private IMapManager _mapManager;
|
[Dependency] private IMapManager _mapManager;
|
||||||
@@ -155,7 +157,7 @@ namespace Content.Server.GameTicking
|
|||||||
RunLevel = GameRunLevel.InRound;
|
RunLevel = GameRunLevel.InRound;
|
||||||
|
|
||||||
// TODO: Allow other presets to be selected.
|
// TODO: Allow other presets to be selected.
|
||||||
var preset = _dynamicTypeFactory.CreateInstance<PresetTraitor>();
|
var preset = (GamePreset)_dynamicTypeFactory.CreateInstance(_presetType ?? typeof(PresetSandbox));
|
||||||
preset.Start();
|
preset.Start();
|
||||||
|
|
||||||
foreach (var (playerSession, ready) in _playersInLobby.ToList())
|
foreach (var (playerSession, ready) in _playersInLobby.ToList())
|
||||||
@@ -248,6 +250,15 @@ namespace Content.Server.GameTicking
|
|||||||
|
|
||||||
public IEnumerable<GameRule> ActiveGameRules => _gameRules;
|
public IEnumerable<GameRule> ActiveGameRules => _gameRules;
|
||||||
|
|
||||||
|
public void SetStartPreset(Type type)
|
||||||
|
{
|
||||||
|
if (!typeof(GamePreset).IsAssignableFrom(type))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("type must inherit GamePreset");
|
||||||
|
}
|
||||||
|
_presetType = type;
|
||||||
|
}
|
||||||
|
|
||||||
private IEntity _spawnPlayerMob()
|
private IEntity _spawnPlayerMob()
|
||||||
{
|
{
|
||||||
var entity = _entityManager.ForceSpawnEntityAt(PlayerPrototypeName, _getLateJoinSpawnPoint());
|
var entity = _entityManager.ForceSpawnEntityAt(PlayerPrototypeName, _getLateJoinSpawnPoint());
|
||||||
@@ -643,4 +654,38 @@ namespace Content.Server.GameTicking
|
|||||||
ticker.ToggleReady(player, bool.Parse(args[0]));
|
ticker.ToggleReady(player, bool.Parse(args[0]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SetGamePresetCommand : IClientCommand
|
||||||
|
{
|
||||||
|
public string Command => "setgamepreset";
|
||||||
|
public string Description => "";
|
||||||
|
public string Help => "";
|
||||||
|
|
||||||
|
public void Execute(IConsoleShell shell, IPlayerSession player, string[] args)
|
||||||
|
{
|
||||||
|
if (args.Length != 1)
|
||||||
|
{
|
||||||
|
shell.SendText(player, "Need exactly one argument.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var ticker = IoCManager.Resolve<IGameTicker>();
|
||||||
|
|
||||||
|
Type presetType;
|
||||||
|
switch (args[0])
|
||||||
|
{
|
||||||
|
case "DeathMatch":
|
||||||
|
presetType = typeof(PresetDeathMatch);
|
||||||
|
break;
|
||||||
|
case "Sandbox":
|
||||||
|
presetType = typeof(PresetSandbox);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
shell.SendText(player, "That is not a valid game preset!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ticker.SetStartPreset(presetType);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,5 +33,7 @@ namespace Content.Server.Interfaces.GameTicking
|
|||||||
T AddGameRule<T>() where T : GameRule, new();
|
T AddGameRule<T>() where T : GameRule, new();
|
||||||
void RemoveGameRule(GameRule rule);
|
void RemoveGameRule(GameRule rule);
|
||||||
IEnumerable<GameRule> ActiveGameRules { get; }
|
IEnumerable<GameRule> ActiveGameRules { get; }
|
||||||
|
|
||||||
|
void SetStartPreset(Type type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,4 +45,9 @@
|
|||||||
- delete
|
- delete
|
||||||
- tp
|
- tp
|
||||||
- tpgrid
|
- tpgrid
|
||||||
|
- setgamepreset
|
||||||
|
- startround
|
||||||
|
- endround
|
||||||
|
- restartround
|
||||||
|
- respawn
|
||||||
CanViewVar: true
|
CanViewVar: true
|
||||||
|
|||||||
@@ -45,13 +45,13 @@ binds:
|
|||||||
key: MouseMiddle
|
key: MouseMiddle
|
||||||
type: State
|
type: State
|
||||||
- function: SwapHands
|
- function: SwapHands
|
||||||
key: Tab
|
key: X
|
||||||
type: State
|
type: State
|
||||||
- function: Drop
|
- function: Drop
|
||||||
key: Q
|
key: Q
|
||||||
type: State
|
type: State
|
||||||
- function: ActivateItemInHand
|
- function: ActivateItemInHand
|
||||||
key: F
|
key: Z
|
||||||
type: State
|
type: State
|
||||||
- function: OpenCharacterMenu
|
- function: OpenCharacterMenu
|
||||||
key: C
|
key: C
|
||||||
|
|||||||
Submodule RobustToolbox updated: 3bad55a705...10440648bc
Reference in New Issue
Block a user