Merge branch 'master' into 2020-04-28-tool-component
# Conflicts: # Content.Server/GameObjects/Components/AnchorableComponent.cs # Content.Server/GameObjects/Components/Gravity/GravityGeneratorComponent.cs # Content.Server/GameObjects/Components/Interactable/Tools/CrowbarComponent.cs # Content.Server/GameObjects/Components/Power/PowerTransferComponent.cs # Content.Server/GameObjects/Components/WiresComponent.cs # Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs # Resources/Prototypes/Entities/Items/tools.yml
This commit is contained in:
@@ -4,6 +4,7 @@ using Content.Shared.GameObjects.Components.Markers;
|
||||
using Robust.Client.Interfaces.Console;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
@@ -48,8 +49,7 @@ namespace Content.Client.Commands
|
||||
|
||||
public bool Execute(IDebugConsole console, params string[] args)
|
||||
{
|
||||
IoCManager.Resolve<IEntitySystemManager>()
|
||||
.GetEntitySystem<SubFloorHideSystem>()
|
||||
EntitySystem.Get<SubFloorHideSystem>()
|
||||
.EnableAll ^= true;
|
||||
|
||||
return false;
|
||||
|
||||
@@ -148,6 +148,14 @@ namespace Content.Client
|
||||
"RandomPottedPlant",
|
||||
"CommunicationsConsole",
|
||||
"BarSign",
|
||||
"DroppedBodyPart",
|
||||
"DroppedMechanism",
|
||||
"BodyManager",
|
||||
"Stunnable",
|
||||
"SolarPanel",
|
||||
"BodyScanner",
|
||||
"Stunbaton",
|
||||
"EmergencyClosetFill"
|
||||
};
|
||||
|
||||
foreach (var ignoreName in registerIgnore)
|
||||
@@ -239,7 +247,6 @@ namespace Content.Client
|
||||
IoCManager.Resolve<IChatManager>().Initialize();
|
||||
IoCManager.Resolve<ISandboxManager>().Initialize();
|
||||
IoCManager.Resolve<IClientPreferencesManager>().Initialize();
|
||||
IoCManager.Resolve<IItemSlotManager>().Initialize();
|
||||
|
||||
_baseClient.RunLevelChanged += (sender, args) =>
|
||||
{
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using Robust.Client.Animations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.GameObjects.Components.Animations;
|
||||
using Robust.Shared.Animations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Client.GameObjects.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class EmergencyLightComponent : Component
|
||||
{
|
||||
public override string Name => "EmergencyLight";
|
||||
|
||||
protected override void Startup()
|
||||
{
|
||||
base.Startup();
|
||||
|
||||
var animation = new Animation
|
||||
{
|
||||
Length = TimeSpan.FromSeconds(4),
|
||||
AnimationTracks =
|
||||
{
|
||||
new AnimationTrackComponentProperty
|
||||
{
|
||||
ComponentType = typeof(PointLightComponent),
|
||||
InterpolationMode = AnimationInterpolationMode.Linear,
|
||||
Property = nameof(PointLightComponent.Rotation),
|
||||
KeyFrames =
|
||||
{
|
||||
new AnimationTrackProperty.KeyFrame(Angle.Zero, 0),
|
||||
new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(1080), 4)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var playerComponent = Owner.EnsureComponent<AnimationPlayerComponent>();
|
||||
playerComponent.Play(animation, "emergency");
|
||||
|
||||
playerComponent.AnimationCompleted += s => playerComponent.Play(animation, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Shared.GameObjects.Components.Instruments;
|
||||
using JetBrains.Annotations;
|
||||
using NFluidsynth;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Client.Audio.Midi;
|
||||
using Robust.Shared.Audio.Midi;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using Logger = Robust.Shared.Log.Logger;
|
||||
using MidiEvent = Robust.Shared.Audio.Midi.MidiEvent;
|
||||
using Timer = Robust.Shared.Timers.Timer;
|
||||
|
||||
|
||||
@@ -20,6 +22,8 @@ namespace Content.Client.GameObjects.Components.Instruments
|
||||
[RegisterComponent]
|
||||
public class InstrumentComponent : SharedInstrumentComponent
|
||||
{
|
||||
public const float TimeBetweenNetMessages = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Called when a midi song stops playing.
|
||||
/// </summary>
|
||||
@@ -27,17 +31,22 @@ namespace Content.Client.GameObjects.Components.Instruments
|
||||
|
||||
#pragma warning disable 649
|
||||
[Dependency] private IMidiManager _midiManager;
|
||||
[Dependency] private readonly IGameTiming _timing;
|
||||
[Dependency] private readonly IGameTiming _gameTiming;
|
||||
#pragma warning restore 649
|
||||
|
||||
[CanBeNull]
|
||||
private IMidiRenderer _renderer;
|
||||
private int _instrumentProgram = 1;
|
||||
private byte _instrumentProgram = 1;
|
||||
private uint _syncSequencerTick;
|
||||
|
||||
/// <summary>
|
||||
/// A queue of MidiEvents to be sent to the server.
|
||||
/// </summary>
|
||||
private Queue<MidiEvent> _eventQueue = new Queue<MidiEvent>();
|
||||
[ViewVariables]
|
||||
private readonly Queue<MidiEvent> _midiQueue = new Queue<MidiEvent>();
|
||||
|
||||
[ViewVariables]
|
||||
private float _timer = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// Whether a midi song will loop or not.
|
||||
@@ -59,7 +68,7 @@ namespace Content.Client.GameObjects.Components.Instruments
|
||||
/// Changes the instrument the midi renderer will play.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int InstrumentProgram
|
||||
public byte InstrumentProgram
|
||||
{
|
||||
get => _instrumentProgram;
|
||||
set
|
||||
@@ -84,61 +93,102 @@ namespace Content.Client.GameObjects.Components.Instruments
|
||||
[ViewVariables]
|
||||
public bool IsInputOpen => _renderer?.Status == MidiRendererStatus.Input;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the midi renderer is alive or not.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool IsRendererAlive => _renderer != null;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
IoCManager.InjectDependencies(this);
|
||||
}
|
||||
|
||||
protected void SetupRenderer()
|
||||
{
|
||||
if (IsRendererAlive)
|
||||
return;
|
||||
|
||||
_renderer = _midiManager.GetNewRenderer();
|
||||
|
||||
if (_renderer != null)
|
||||
{
|
||||
_renderer.MidiProgram = _instrumentProgram;
|
||||
_renderer.TrackingEntity = Owner;
|
||||
_renderer.OnMidiPlayerFinished += () => { OnMidiPlaybackEnded?.Invoke(); };
|
||||
_renderer.OnMidiPlayerFinished += () => { OnMidiPlaybackEnded?.Invoke(); EndRenderer(); SendNetworkMessage(new InstrumentStopMidiMessage()); };
|
||||
}
|
||||
}
|
||||
|
||||
protected void EndRenderer()
|
||||
{
|
||||
if (IsInputOpen)
|
||||
CloseInput();
|
||||
|
||||
if (IsMidiOpen)
|
||||
CloseMidi();
|
||||
|
||||
_renderer?.StopAllNotes();
|
||||
|
||||
var renderer = _renderer;
|
||||
|
||||
// We dispose of the synth two seconds from now to allow the last notes to stop from playing.
|
||||
Timer.Spawn(2000, () => { renderer?.Dispose(); });
|
||||
_renderer = null;
|
||||
_midiQueue.Clear();
|
||||
}
|
||||
|
||||
protected override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
_renderer?.Dispose();
|
||||
EndRenderer();
|
||||
}
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
serializer.DataField(ref _instrumentProgram, "program", 1);
|
||||
serializer.DataField(ref _instrumentProgram, "program", (byte)1);
|
||||
}
|
||||
|
||||
public override void HandleNetworkMessage(ComponentMessage message, INetChannel channel, ICommonSession session = null)
|
||||
{
|
||||
base.HandleNetworkMessage(message, channel, session);
|
||||
|
||||
if (_renderer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case InstrumentMidiEventMessage midiEventMessage:
|
||||
// If we're the ones sending the MidiEvents, we ignore this message.
|
||||
if (IsInputOpen || IsMidiOpen) break;
|
||||
Timer.Spawn((int) (500 + _timing.CurTime.TotalMilliseconds - midiEventMessage.Timestamp),
|
||||
() => _renderer.SendMidiEvent(midiEventMessage.MidiEvent));
|
||||
break;
|
||||
|
||||
case InstrumentStopMidiMessage _:
|
||||
_renderer.StopAllNotes();
|
||||
if (IsInputOpen) CloseInput();
|
||||
if (IsMidiOpen) CloseMidi();
|
||||
if (!IsRendererAlive || IsInputOpen || IsMidiOpen) break;
|
||||
for (var i = 0; i < midiEventMessage.MidiEvent.Length; i++)
|
||||
{
|
||||
var ev = midiEventMessage.MidiEvent[i];
|
||||
var delta = ((uint)TimeBetweenNetMessages*1250) + ev.Timestamp - _syncSequencerTick;
|
||||
_renderer?.ScheduleMidiEvent(ev, delta, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||
{
|
||||
base.HandleComponentState(curState, nextState);
|
||||
if (!(curState is InstrumentState state)) return;
|
||||
|
||||
if (state.Playing)
|
||||
{
|
||||
SetupRenderer();
|
||||
_syncSequencerTick = state.SequencerTick;
|
||||
}
|
||||
else
|
||||
EndRenderer();
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="MidiRenderer.OpenInput"/>
|
||||
public bool OpenInput()
|
||||
{
|
||||
SetupRenderer();
|
||||
SendNetworkMessage(new InstrumentStartMidiMessage());
|
||||
|
||||
if (_renderer != null && _renderer.OpenInput())
|
||||
{
|
||||
_renderer.OnMidiEvent += RendererOnMidiEvent;
|
||||
@@ -156,13 +206,17 @@ namespace Content.Client.GameObjects.Components.Instruments
|
||||
return false;
|
||||
}
|
||||
|
||||
_renderer.OnMidiEvent -= RendererOnMidiEvent;
|
||||
EndRenderer();
|
||||
SendNetworkMessage(new InstrumentStopMidiMessage());
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="MidiRenderer.OpenMidi(string)"/>
|
||||
public bool OpenMidi(string filename)
|
||||
{
|
||||
SetupRenderer();
|
||||
SendNetworkMessage(new InstrumentStartMidiMessage());
|
||||
|
||||
if (_renderer == null || !_renderer.OpenMidi(filename))
|
||||
{
|
||||
return false;
|
||||
@@ -180,7 +234,8 @@ namespace Content.Client.GameObjects.Components.Instruments
|
||||
return false;
|
||||
}
|
||||
|
||||
_renderer.OnMidiEvent -= RendererOnMidiEvent;
|
||||
EndRenderer();
|
||||
SendNetworkMessage(new InstrumentStopMidiMessage());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -190,7 +245,29 @@ namespace Content.Client.GameObjects.Components.Instruments
|
||||
/// <param name="midiEvent">The received midi event</param>
|
||||
private void RendererOnMidiEvent(MidiEvent midiEvent)
|
||||
{
|
||||
SendNetworkMessage(new InstrumentMidiEventMessage(midiEvent, _timing.CurTime.TotalMilliseconds));
|
||||
_midiQueue.Enqueue(midiEvent);
|
||||
}
|
||||
|
||||
public override void Update(float delta)
|
||||
{
|
||||
if (!IsMidiOpen && !IsInputOpen)
|
||||
return;
|
||||
|
||||
_timer -= delta;
|
||||
|
||||
if (_timer > 0f) return;
|
||||
|
||||
SendAllMidiMessages();
|
||||
_timer = TimeBetweenNetMessages;
|
||||
}
|
||||
|
||||
private void SendAllMidiMessages()
|
||||
{
|
||||
if (_midiQueue.Count == 0) return;
|
||||
var events = _midiQueue.ToArray();
|
||||
_midiQueue.Clear();
|
||||
|
||||
SendNetworkMessage(new InstrumentMidiEventMessage(events));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,10 +137,11 @@ namespace Content.Client.GameObjects.Components.Kitchen
|
||||
{
|
||||
Text = (index <= 0 ? 1 : index).ToString(),
|
||||
TextAlign = Label.AlignMode.Center,
|
||||
ToggleMode = true,
|
||||
Group = CookTimeButtonGroup,
|
||||
};
|
||||
CookTimeButtonVbox.AddChild(newButton);
|
||||
newButton.OnPressed += args =>
|
||||
newButton.OnToggled += args =>
|
||||
{
|
||||
OnCookTimeSelected?.Invoke(args);
|
||||
_cookTimeInfoLabel.Text = $"{Loc.GetString("COOK TIME")}: {VisualCookTime}";
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Microsoft.CodeAnalysis.Completion;
|
||||
using Robust.Client.Animations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.GameObjects.Components.Animations;
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Collections.Generic;
|
||||
using Content.Shared.GameObjects.Components.Sound;
|
||||
using Robust.Client.GameObjects.EntitySystems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.Interfaces.Random;
|
||||
@@ -9,6 +10,7 @@ using Robust.Shared.IoC;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Timers;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Sound
|
||||
{
|
||||
@@ -54,7 +56,7 @@ namespace Content.Client.GameObjects.Components.Sound
|
||||
Timer.Spawn((int) schedule.Delay + (_random.Next((int) schedule.RandomDelay)),() =>
|
||||
{
|
||||
if (!schedule.Play) return; // We make sure this hasn't changed.
|
||||
if (_audioSystem == null) _audioSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AudioSystem>();
|
||||
if (_audioSystem == null) _audioSystem = EntitySystem.Get<AudioSystem>();
|
||||
_audioStreams.Add(schedule,_audioSystem.Play(schedule.Filename, Owner, schedule.AudioParams));
|
||||
|
||||
if (schedule.Times == 0) return;
|
||||
@@ -87,7 +89,7 @@ namespace Content.Client.GameObjects.Components.Sound
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
IoCManager.Resolve<IEntitySystemManager>().TryGetEntitySystem(out _audioSystem);
|
||||
EntitySystem.TryGet(out _audioSystem);
|
||||
}
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Content.Shared.GameObjects.Components.Storage;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
@@ -8,6 +9,7 @@ namespace Content.Client.GameObjects.Components.Storage
|
||||
{
|
||||
public sealed class StorageVisualizer2D : AppearanceVisualizer
|
||||
{
|
||||
private string _stateBase;
|
||||
private string _stateOpen;
|
||||
private string _stateClosed;
|
||||
|
||||
@@ -15,7 +17,12 @@ namespace Content.Client.GameObjects.Components.Storage
|
||||
{
|
||||
base.LoadData(node);
|
||||
|
||||
if (node.TryGetNode("state_open", out var child))
|
||||
if (node.TryGetNode("state", out var child))
|
||||
{
|
||||
_stateBase = child.AsString();
|
||||
}
|
||||
|
||||
if (node.TryGetNode("state_open", out child))
|
||||
{
|
||||
_stateOpen = child.AsString();
|
||||
}
|
||||
@@ -26,6 +33,19 @@ namespace Content.Client.GameObjects.Components.Storage
|
||||
}
|
||||
}
|
||||
|
||||
public override void InitializeEntity(IEntity entity)
|
||||
{
|
||||
if (!entity.TryGetComponent(out ISpriteComponent sprite))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_stateBase != null)
|
||||
{
|
||||
sprite.LayerSetState(0, _stateBase);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
@@ -36,7 +56,9 @@ namespace Content.Client.GameObjects.Components.Storage
|
||||
}
|
||||
|
||||
component.TryGetData(StorageVisuals.Open, out bool open);
|
||||
sprite.LayerSetState(StorageVisualLayers.Door, open ? _stateOpen : _stateClosed);
|
||||
sprite.LayerSetState(StorageVisualLayers.Door, open
|
||||
? _stateOpen ?? $"{_stateBase}_open"
|
||||
: _stateClosed ?? $"{_stateBase}_door");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
25
Content.Client/GameObjects/EntitySystems/InstrumentSystem.cs
Normal file
25
Content.Client/GameObjects/EntitySystems/InstrumentSystem.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using Content.Client.GameObjects.Components.Instruments;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
|
||||
namespace Content.Client.GameObjects.EntitySystems
|
||||
{
|
||||
public class InstrumentSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
EntityQuery = new TypeEntityQuery(typeof(InstrumentComponent));
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
foreach (var entity in RelevantEntities)
|
||||
{
|
||||
entity.GetComponent<InstrumentComponent>().Update(frameTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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")}
|
||||
});
|
||||
}
|
||||
|
||||
var entity = entities[i];
|
||||
|
||||
_currentEntityList.List.AddChild(new EntityButton(this, entity));
|
||||
}
|
||||
|
||||
_currentPopup.UserInterfaceManager.ModalRoot.AddChild(_currentPopup);
|
||||
_userInterfaceManager.ModalRoot.AddChild(_currentEntityList);
|
||||
|
||||
var size = _currentPopup.List.CombinedMinimumSize;
|
||||
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 (verbData.CategoryIcon != null && !groupIcons.ContainsKey(verbData.Category))
|
||||
{
|
||||
groupIcons.Add(verbData.Category, verbData.CategoryIcon);
|
||||
}
|
||||
|
||||
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)));
|
||||
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)
|
||||
|
||||
33
Content.Client/UserInterface/CooldownGraphic.cs
Normal file
33
Content.Client/UserInterface/CooldownGraphic.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Client.Interfaces.Graphics;
|
||||
using Robust.Shared.Maths;
|
||||
using System;
|
||||
|
||||
namespace Robust.Client.UserInterface.Controls
|
||||
{
|
||||
public class CooldownGraphic : Control
|
||||
{
|
||||
public float Fraction { get; set; }
|
||||
|
||||
protected override void Draw(DrawingHandleScreen handle)
|
||||
{
|
||||
const int maxSegments = 64;
|
||||
const float segment = MathHelper.TwoPi / maxSegments;
|
||||
|
||||
var segments = (int)Math.Max(2, Math.Ceiling(maxSegments * Fraction)); // ensure that we always have 3 vertices
|
||||
var max = MathHelper.TwoPi * Fraction;
|
||||
var radius = (Math.Min(SizeBox.Height, SizeBox.Width) / 2) * 0.875f; // 28/32 = 0.875 - 2 pixels inwards from the edge
|
||||
|
||||
Span<Vector2> vertices = stackalloc Vector2[segments + 1];
|
||||
vertices[0] = PixelPosition + SizeBox.Center;
|
||||
for (int i = 0; i < segments; i++)
|
||||
{
|
||||
var angle = MathHelper.Pi + Math.Min(max, segment * i);
|
||||
vertices[i + 1] = vertices[0] + new Vector2((float) Math.Sin(angle) * radius, (float) Math.Cos(angle) * radius);
|
||||
}
|
||||
|
||||
handle.DrawPrimitives(DrawPrimitiveTopology.TriangleFan, vertices, new Color(0.3f, 0.3f, 0.4f, 0.5f));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ namespace Content.Client.UserInterface
|
||||
{
|
||||
public interface IItemSlotManager
|
||||
{
|
||||
void Initialize();
|
||||
bool OnButtonPressed(GUIBoundKeyEventArgs args, IEntity item);
|
||||
void UpdateCooldown(ItemSlotButton cooldownTexture, IEntity entity);
|
||||
bool SetItemSlot(ItemSlotButton button, IEntity entity);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Shared.Input;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
@@ -13,7 +14,7 @@ namespace Content.Client.GameObjects
|
||||
public TextureRect Button { get; }
|
||||
public SpriteView SpriteView { get; }
|
||||
public BaseButton StorageButton { get; }
|
||||
public TextureRect CooldownCircle { get; }
|
||||
public CooldownGraphic CooldownDisplay { get; }
|
||||
|
||||
public Action<GUIBoundKeyEventArgs> OnPressed { get; set; }
|
||||
public Action<GUIBoundKeyEventArgs> OnStoragePressed { get; set; }
|
||||
@@ -56,12 +57,10 @@ namespace Content.Client.GameObjects
|
||||
|
||||
StorageButton.OnPressed += OnStorageButtonPressed;
|
||||
|
||||
AddChild(CooldownCircle = new TextureRect
|
||||
AddChild(CooldownDisplay = new CooldownGraphic
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.ShrinkCenter,
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter,
|
||||
Stretch = TextureRect.StretchMode.KeepCentered,
|
||||
TextureScale = (2, 2),
|
||||
SizeFlagsHorizontal = SizeFlags.Fill,
|
||||
SizeFlagsVertical = SizeFlags.Fill,
|
||||
Visible = false,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -30,22 +30,8 @@ namespace Content.Client.UserInterface
|
||||
[Dependency] private readonly IInputManager _inputManager;
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager;
|
||||
[Dependency] private readonly IEyeManager _eyeManager;
|
||||
[Dependency] private readonly IResourceCache _resourceCache;
|
||||
#pragma warning restore 0649
|
||||
|
||||
private const int CooldownLevels = 8;
|
||||
|
||||
private readonly Texture[] _texturesCooldownOverlay = new Texture[CooldownLevels];
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
for (var i = 0; i < CooldownLevels; i++)
|
||||
{
|
||||
_texturesCooldownOverlay[i] =
|
||||
_resourceCache.GetTexture($"/Textures/UserInterface/Inventory/cooldown-{i}.png");
|
||||
}
|
||||
}
|
||||
|
||||
public bool SetItemSlot(ItemSlotButton button, IEntity entity)
|
||||
{
|
||||
if (entity == null)
|
||||
@@ -103,7 +89,7 @@ namespace Content.Client.UserInterface
|
||||
|
||||
public void UpdateCooldown(ItemSlotButton button, IEntity entity)
|
||||
{
|
||||
var cooldownTexture = button.CooldownCircle;
|
||||
var cooldownDisplay = button.CooldownDisplay;
|
||||
|
||||
if (entity != null
|
||||
&& entity.TryGetComponent(out ItemCooldownComponent cooldown)
|
||||
@@ -115,30 +101,23 @@ namespace Content.Client.UserInterface
|
||||
|
||||
var length = (end - start).TotalSeconds;
|
||||
var progress = (_gameTiming.CurTime - start).TotalSeconds;
|
||||
var ratio = (float)(progress / length);
|
||||
var ratio = 1 - (float)(progress / length).Clamp(0, 1);
|
||||
|
||||
var textureIndex = CalculateCooldownLevel(ratio);
|
||||
if (textureIndex == CooldownLevels)
|
||||
cooldownDisplay.Fraction = ratio;
|
||||
|
||||
if (ratio > 0)
|
||||
{
|
||||
cooldownTexture.Visible = false;
|
||||
cooldownDisplay.Visible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
cooldownTexture.Visible = true;
|
||||
cooldownTexture.Texture = _texturesCooldownOverlay[textureIndex];
|
||||
cooldownDisplay.Visible = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cooldownTexture.Visible = false;
|
||||
cooldownDisplay.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
internal static int CalculateCooldownLevel(float cooldownValue)
|
||||
{
|
||||
var val = cooldownValue.Clamp(0, 1);
|
||||
val *= CooldownLevels;
|
||||
return (int)Math.Floor(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Content.IntegrationTests.Tests
|
||||
uniform = entityMan.SpawnEntity("JanitorUniform", MapCoordinates.Nullspace);
|
||||
idCard = entityMan.SpawnEntity("AssistantIDCard", MapCoordinates.Nullspace);
|
||||
pocketItem = entityMan.SpawnEntity("FlashlightLantern", MapCoordinates.Nullspace);
|
||||
var tooBigItem = entityMan.SpawnEntity("RedToolboxItem", MapCoordinates.Nullspace);
|
||||
var tooBigItem = entityMan.SpawnEntity("ToolboxEmergency", MapCoordinates.Nullspace);
|
||||
|
||||
inventory = human.GetComponent<InventoryComponent>();
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.Interfaces.GameObjects.Components.Movement;
|
||||
using Content.Shared.Physics;
|
||||
using Robust.Server.AI;
|
||||
@@ -114,7 +115,7 @@ namespace Content.Server.AI
|
||||
var ray = new CollisionRay(myTransform.WorldPosition, dir.Normalized, (int)(CollisionGroup.MobImpassable | CollisionGroup.Impassable));
|
||||
|
||||
// cast the ray
|
||||
var result = _physMan.IntersectRay(myTransform.MapID, ray, maxRayLen, SelfEntity);
|
||||
var result = _physMan.IntersectRay(myTransform.MapID, ray, maxRayLen, SelfEntity).First();
|
||||
|
||||
// add to visible list
|
||||
if (result.HitEntity == entity)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.Movement;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Interfaces.Chat;
|
||||
@@ -127,17 +128,20 @@ namespace Content.Server.AI
|
||||
{
|
||||
var dir = new Vector2(Random01(ref rngState) * 2 - 1, Random01(ref rngState) *2 -1).Normalized;
|
||||
var ray = new CollisionRay(entWorldPos, dir, (int) CollisionGroup.Impassable);
|
||||
var rayResult = _physMan.IntersectRay(SelfEntity.Transform.MapID, ray, MaxWalkDistance, SelfEntity);
|
||||
var rayResults = _physMan.IntersectRay(SelfEntity.Transform.MapID, ray, MaxWalkDistance, SelfEntity).ToList();
|
||||
|
||||
if (rayResult.DidHitObject && rayResult.Distance > 1) // hit an impassable object
|
||||
if (rayResults.Count == 1)
|
||||
{
|
||||
// set the new position back from the wall a bit
|
||||
_walkTargetPos = entWorldPos + dir * (rayResult.Distance - 0.5f);
|
||||
WalkingPositiveEdge();
|
||||
return;
|
||||
var rayResult = rayResults[0];
|
||||
if (rayResult.Distance > 1) // hit an impassable object
|
||||
{
|
||||
// set the new position back from the wall a bit
|
||||
_walkTargetPos = entWorldPos + dir * (rayResult.Distance - 0.5f);
|
||||
WalkingPositiveEdge();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rayResult.DidHitObject) // hit nothing (path clear)
|
||||
else // hit nothing (path clear)
|
||||
{
|
||||
_walkTargetPos = dir * MaxWalkDistance;
|
||||
WalkingPositiveEdge();
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace Content.Server
|
||||
"IconSmooth",
|
||||
"SubFloorHide",
|
||||
"LowWall",
|
||||
"ReinforcedWall",
|
||||
"Window",
|
||||
"CharacterInfo",
|
||||
"InteractionOutline",
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.Access;
|
||||
using Content.Shared.GameObjects.Components.Access;
|
||||
using Robust.Server.GameObjects.Components.Container;
|
||||
|
||||
@@ -4,8 +4,10 @@ using Content.Shared.GameObjects.Components.Interactable;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.GameObjects.Components
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Utility;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Cargo
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Content.Server.GameObjects.Components.Metabolism;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.GameObjects.Components.Chemistry;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -110,6 +111,8 @@ namespace Content.Server.GameObjects.Components.Chemistry
|
||||
/// <param name="eventArgs"></param>
|
||||
void IAfterAttack.AfterAttack(AfterAttackEventArgs eventArgs)
|
||||
{
|
||||
if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return;
|
||||
|
||||
//Make sure we have the attacking entity
|
||||
if (eventArgs.Attacked == null || !_internalContents.Injector)
|
||||
{
|
||||
|
||||
@@ -4,12 +4,15 @@ using System.Text;
|
||||
using Content.Server.GameObjects.Components.Nutrition;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.Chemistry;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Chemistry
|
||||
{
|
||||
@@ -25,6 +28,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IServerNotifyManager _notifyManager;
|
||||
[Dependency] private readonly ILocalizationManager _localizationManager;
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
public override string Name => "Pourable";
|
||||
|
||||
@@ -5,6 +5,7 @@ using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.GameObjects.Components.Power;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.GameObjects.Components.Chemistry;
|
||||
using Robust.Server.GameObjects.Components.Container;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Content.Server.GameObjects.Components.Power;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Interfaces.GameTicking;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects.Components.Command;
|
||||
using Robust.Server.GameObjects.Components.UserInterface;
|
||||
using Robust.Server.Interfaces.GameObjects;
|
||||
|
||||
@@ -4,6 +4,7 @@ using Content.Server.GameObjects.Components.Interactable;
|
||||
using Content.Server.GameObjects.Components.Stack;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.Construction;
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using Content.Shared.GameObjects.Components.Interactable;
|
||||
@@ -11,6 +12,7 @@ using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Server.Interfaces.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.Random;
|
||||
@@ -19,6 +21,8 @@ using Robust.Shared.Localization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using static Content.Shared.Construction.ConstructionStepMaterial;
|
||||
using static Content.Shared.Construction.ConstructionStepTool;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Construction
|
||||
{
|
||||
@@ -47,18 +51,16 @@ namespace Content.Server.GameObjects.Components.Construction
|
||||
|
||||
Sprite = Owner.GetComponent<SpriteComponent>();
|
||||
Transform = Owner.GetComponent<ITransformComponent>();
|
||||
var systemman = IoCManager.Resolve<IEntitySystemManager>();
|
||||
}
|
||||
|
||||
public bool AttackBy(AttackByEventArgs eventArgs)
|
||||
{
|
||||
var playerEntity = eventArgs.User;
|
||||
var interactionSystem = _entitySystemManager.GetEntitySystem<InteractionSystem>();
|
||||
if (!interactionSystem.InRangeUnobstructed(playerEntity.Transform.MapPosition, Owner.Transform.WorldPosition, ignoredEnt: Owner, insideBlockerValid: Prototype.CanBuildInImpassable))
|
||||
// default interaction check for AttackBy allows inside blockers, so we will check if its blocked if
|
||||
// we're not allowed to build on impassable stuff
|
||||
if (Prototype.CanBuildInImpassable == false)
|
||||
{
|
||||
_notifyManager.PopupMessage(Owner.Transform.GridPosition, playerEntity,
|
||||
_localizationManager.GetString("You can't reach there!"));
|
||||
return false;
|
||||
if (!InteractionChecks.InRangeUnobstructed(eventArgs, false))
|
||||
return false;
|
||||
}
|
||||
|
||||
var stage = Prototype.Stages[Stage];
|
||||
@@ -125,7 +127,7 @@ namespace Content.Server.GameObjects.Components.Construction
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var sound = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AudioSystem>();
|
||||
var sound = EntitySystem.Get<AudioSystem>();
|
||||
|
||||
switch (step)
|
||||
{
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
using System;
|
||||
using Content.Server.GameObjects.Components.Stack;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.Construction;
|
||||
using Content.Shared.GameObjects.Components.Construction;
|
||||
using Content.Shared.Interfaces;
|
||||
using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Server.Interfaces.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
@@ -16,6 +18,7 @@ using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Construction
|
||||
{
|
||||
@@ -47,16 +50,13 @@ namespace Content.Server.GameObjects.Components.Construction
|
||||
{
|
||||
var prototype = _prototypeManager.Index<ConstructionPrototype>(prototypeName);
|
||||
|
||||
var transform = Owner.Transform;
|
||||
|
||||
var interactionSystem = _entitySystemManager.GetEntitySystem<InteractionSystem>();
|
||||
if (!interactionSystem.InRangeUnobstructed(loc.ToMap(_mapManager), Owner.Transform.WorldPosition, ignoredEnt: Owner, insideBlockerValid: prototype.CanBuildInImpassable))
|
||||
if (!InteractionChecks.InRangeUnobstructed(Owner, loc.ToMapPos(_mapManager),
|
||||
ignoredEnt: Owner, insideBlockerValid: prototype.CanBuildInImpassable))
|
||||
{
|
||||
_notifyManager.PopupMessage(transform.GridPosition, Owner,
|
||||
_localizationManager.GetString("You can't reach there!"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (prototype.Stages.Count < 2)
|
||||
{
|
||||
throw new InvalidOperationException($"Prototype '{prototypeName}' does not have enough stages.");
|
||||
|
||||
@@ -5,6 +5,7 @@ using Content.Server.GameObjects.Components.Power;
|
||||
using Content.Server.GameObjects.Components.VendingMachines;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects.Components.Doors;
|
||||
using Content.Shared.GameObjects.Components.Interactable;
|
||||
using Robust.Server.GameObjects;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.Components.Access;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects.Components.Doors;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -17,7 +19,7 @@ namespace Content.Server.GameObjects
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(IActivate))]
|
||||
public class ServerDoorComponent : Component, IActivate
|
||||
public class ServerDoorComponent : Component, IActivate, ICollideBehavior
|
||||
{
|
||||
public override string Name => "Door";
|
||||
|
||||
@@ -85,26 +87,16 @@ namespace Content.Server.GameObjects
|
||||
ActivateImpl(eventArgs);
|
||||
}
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, IComponent component)
|
||||
|
||||
void ICollideBehavior.CollideWith(IEntity entity)
|
||||
{
|
||||
base.HandleMessage(message, component);
|
||||
|
||||
switch (message)
|
||||
if (State != DoorState.Closed)
|
||||
{
|
||||
case BumpedEntMsg msg:
|
||||
if (State != DoorState.Closed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Only open when bumped by mobs.
|
||||
if (!msg.Entity.HasComponent(typeof(SpeciesComponent)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TryOpen(msg.Entity);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
if (entity.HasComponent(typeof(SpeciesComponent)))
|
||||
{
|
||||
TryOpen(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +147,7 @@ namespace Content.Server.GameObjects
|
||||
|
||||
Timer.Spawn(OpenTimeOne, async () =>
|
||||
{
|
||||
collidableComponent.IsHardCollidable = false;
|
||||
collidableComponent.CanCollide = false;
|
||||
|
||||
await Timer.Delay(OpenTimeTwo, _cancellationTokenSource.Token);
|
||||
|
||||
@@ -191,14 +183,14 @@ namespace Content.Server.GameObjects
|
||||
|
||||
public bool Close()
|
||||
{
|
||||
if (collidableComponent.TryCollision(Vector2.Zero))
|
||||
if (collidableComponent.IsColliding(Vector2.Zero))
|
||||
{
|
||||
// Do nothing, somebody's in the door.
|
||||
return false;
|
||||
}
|
||||
|
||||
State = DoorState.Closing;
|
||||
collidableComponent.IsHardCollidable = true;
|
||||
collidableComponent.CanCollide = true;
|
||||
OpenTimeCounter = 0;
|
||||
SetAppearance(DoorVisualState.Closing);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using Content.Server.GameObjects.Components.Chemistry;
|
||||
using Content.Server.GameObjects.Components.Sound;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Interfaces;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
protected override VerbVisibility GetVisibility(IEntity user, CanSpillComponent component)
|
||||
{
|
||||
if (component.Owner.TryGetComponent(out SolutionComponent solutionComponent))
|
||||
if (!component.Owner.TryGetComponent(out SolutionComponent solutionComponent))
|
||||
{
|
||||
return solutionComponent.CurrentVolume > ReagentUnit.Zero ? VerbVisibility.Visible : VerbVisibility.Disabled;
|
||||
data.Visibility = VerbVisibility.Invisible;
|
||||
return;
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using Content.Server.GameObjects.Components.Chemistry;
|
||||
using Content.Server.GameObjects.Components.Sound;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Interfaces;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -59,6 +60,8 @@ namespace Content.Server.GameObjects.Components.Fluids
|
||||
|
||||
void IAfterAttack.AfterAttack(AfterAttackEventArgs eventArgs)
|
||||
{
|
||||
if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return;
|
||||
|
||||
Solution solution;
|
||||
if (eventArgs.Attacked == null)
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@ using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects.Components.Transform;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Random;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -17,6 +18,7 @@ using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using Timer = Robust.Shared.Timers.Timer;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Fluids
|
||||
{
|
||||
@@ -34,7 +36,7 @@ namespace Content.Server.GameObjects.Components.Fluids
|
||||
// Small puddles will evaporate after a set delay
|
||||
|
||||
// TODO: 'leaves fluidtracks', probably in a separate component for stuff like gibb chunks?;
|
||||
// TODO: Add stuff like slipping -> probably in a separate component (for stuff like bananas) and using BumpEntMsg
|
||||
// TODO: Add stuff like slipping -> probably in a separate component (for stuff like bananas)
|
||||
|
||||
// based on behaviour (e.g. someone being punched vs slashed with a sword would have different blood sprite)
|
||||
// to check for low volumes for evaporation or whatever
|
||||
@@ -137,8 +139,7 @@ namespace Content.Server.GameObjects.Components.Fluids
|
||||
return true;
|
||||
}
|
||||
|
||||
var entitySystemManager = IoCManager.Resolve<IEntitySystemManager>();
|
||||
entitySystemManager.GetEntitySystem<AudioSystem>().Play(_spillSound);
|
||||
EntitySystem.Get<AudioSystem>().Play(_spillSound);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using Content.Server.GameObjects.Components.Interactable;
|
||||
using Content.Server.GameObjects.Components.Power;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects.Components.Gravity;
|
||||
using Content.Shared.GameObjects.Components.Interactable;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
@@ -12,10 +13,12 @@ using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Server.Interfaces.GameObjects;
|
||||
using Robust.Server.Interfaces.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Gravity
|
||||
{
|
||||
@@ -114,10 +117,8 @@ namespace Content.Server.GameObjects.Components.Gravity
|
||||
breakable.broken = false;
|
||||
_intact = true;
|
||||
|
||||
var entitySystemManager = IoCManager.Resolve<IEntitySystemManager>();
|
||||
var notifyManager = IoCManager.Resolve<IServerNotifyManager>();
|
||||
|
||||
entitySystemManager.GetEntitySystem<AudioSystem>().Play("/Audio/items/welder2.ogg", Owner);
|
||||
notifyManager.PopupMessage(Owner, eventArgs.User, Loc.GetString("You repair the gravity generator with the welder"));
|
||||
|
||||
return true;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Server.GameObjects.Components.Stack;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
@@ -24,6 +25,8 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee
|
||||
|
||||
void IAfterAttack.AfterAttack(AfterAttackEventArgs eventArgs)
|
||||
{
|
||||
if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return;
|
||||
|
||||
if (eventArgs.Attacked == null)
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -1,15 +1,26 @@
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Server.Mobs;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects.Components.Instruments;
|
||||
using NFluidsynth;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameObjects.Components.UserInterface;
|
||||
using Robust.Server.Interfaces.GameObjects;
|
||||
using Robust.Server.Interfaces.Player;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using Logger = Robust.Shared.Log.Logger;
|
||||
using MidiEvent = Robust.Shared.Audio.Midi.MidiEvent;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Instruments
|
||||
{
|
||||
@@ -18,12 +29,35 @@ namespace Content.Server.GameObjects.Components.Instruments
|
||||
public class InstrumentComponent : SharedInstrumentComponent,
|
||||
IDropped, IHandSelected, IHandDeselected, IActivate, IUse, IThrown
|
||||
{
|
||||
[Dependency] private IServerNotifyManager _notifyManager;
|
||||
|
||||
// These 2 values are quite high for now, and this could be easily abused. Change this if people are abusing it.
|
||||
public const int MaxMidiEventsPerSecond = 20;
|
||||
public const int MaxMidiEventsPerBatch = 50;
|
||||
public const int MaxMidiBatchDropped = 20;
|
||||
|
||||
/// <summary>
|
||||
/// The client channel currently playing the instrument, or null if there's none.
|
||||
/// </summary>
|
||||
private ICommonSession _instrumentPlayer;
|
||||
[ViewVariables]
|
||||
private IPlayerSession _instrumentPlayer;
|
||||
private bool _handheld;
|
||||
|
||||
[ViewVariables]
|
||||
private bool _playing = false;
|
||||
|
||||
[ViewVariables]
|
||||
private float _timer = 0f;
|
||||
|
||||
[ViewVariables]
|
||||
private int _batchesDropped = 0;
|
||||
|
||||
[ViewVariables]
|
||||
private uint _lastSequencerTick = 0;
|
||||
|
||||
[ViewVariables]
|
||||
private int _midiEventCount = 0;
|
||||
|
||||
[ViewVariables]
|
||||
private BoundUserInterface _userInterface;
|
||||
|
||||
@@ -33,6 +67,43 @@ namespace Content.Server.GameObjects.Components.Instruments
|
||||
[ViewVariables]
|
||||
public bool Handheld => _handheld;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the instrument is currently playing or not.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool Playing
|
||||
{
|
||||
get => _playing;
|
||||
set
|
||||
{
|
||||
_playing = value;
|
||||
Dirty();
|
||||
}
|
||||
}
|
||||
|
||||
public IPlayerSession InstrumentPlayer
|
||||
{
|
||||
get => _instrumentPlayer;
|
||||
private set
|
||||
{
|
||||
Playing = false;
|
||||
|
||||
if(_instrumentPlayer != null)
|
||||
_instrumentPlayer.PlayerStatusChanged -= OnPlayerStatusChanged;
|
||||
|
||||
_instrumentPlayer = value;
|
||||
|
||||
if(value != null)
|
||||
_instrumentPlayer.PlayerStatusChanged += OnPlayerStatusChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
|
||||
{
|
||||
if (e.NewStatus == SessionStatus.Disconnected)
|
||||
InstrumentPlayer = null;
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -46,31 +117,52 @@ namespace Content.Server.GameObjects.Components.Instruments
|
||||
serializer.DataField(ref _handheld, "handheld", false);
|
||||
}
|
||||
|
||||
public override ComponentState GetComponentState()
|
||||
{
|
||||
return new InstrumentState(Playing, _lastSequencerTick);
|
||||
}
|
||||
|
||||
public override void HandleNetworkMessage(ComponentMessage message, INetChannel channel, ICommonSession session = null)
|
||||
{
|
||||
base.HandleNetworkMessage(message, channel, session);
|
||||
|
||||
// If the client that sent the message isn't the client playing this instrument, we ignore it.
|
||||
if (session != _instrumentPlayer) return;
|
||||
switch (message)
|
||||
{
|
||||
case InstrumentMidiEventMessage midiEventMsg:
|
||||
SendNetworkMessage(midiEventMsg);
|
||||
if (!Playing || session != _instrumentPlayer)
|
||||
return;
|
||||
|
||||
if (++_midiEventCount <= MaxMidiEventsPerSecond &&
|
||||
midiEventMsg.MidiEvent.Length < MaxMidiEventsPerBatch)
|
||||
SendNetworkMessage(midiEventMsg);
|
||||
else
|
||||
_batchesDropped++; // Batch dropped!
|
||||
|
||||
_lastSequencerTick = midiEventMsg.MidiEvent[^1].Timestamp;
|
||||
break;
|
||||
case InstrumentStartMidiMessage startMidi:
|
||||
Playing = true;
|
||||
break;
|
||||
case InstrumentStopMidiMessage stopMidi:
|
||||
Playing = false;
|
||||
_lastSequencerTick = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dropped(DroppedEventArgs eventArgs)
|
||||
{
|
||||
Playing = false;
|
||||
SendNetworkMessage(new InstrumentStopMidiMessage());
|
||||
_instrumentPlayer = null;
|
||||
InstrumentPlayer = null;
|
||||
_userInterface.CloseAll();
|
||||
}
|
||||
|
||||
public void Thrown(ThrownEventArgs eventArgs)
|
||||
{
|
||||
Playing = false;
|
||||
SendNetworkMessage(new InstrumentStopMidiMessage());
|
||||
_instrumentPlayer = null;
|
||||
InstrumentPlayer = null;
|
||||
_userInterface.CloseAll();
|
||||
}
|
||||
|
||||
@@ -80,11 +172,12 @@ namespace Content.Server.GameObjects.Components.Instruments
|
||||
|
||||
if (session == null) return;
|
||||
|
||||
_instrumentPlayer = session;
|
||||
InstrumentPlayer = session;
|
||||
}
|
||||
|
||||
public void HandDeselected(HandDeselectedEventArgs eventArgs)
|
||||
{
|
||||
Playing = false;
|
||||
SendNetworkMessage(new InstrumentStopMidiMessage());
|
||||
_userInterface.CloseAll();
|
||||
}
|
||||
@@ -94,10 +187,10 @@ namespace Content.Server.GameObjects.Components.Instruments
|
||||
if (Handheld || !eventArgs.User.TryGetComponent(out IActorComponent actor))
|
||||
return;
|
||||
|
||||
if (_instrumentPlayer != null)
|
||||
if (InstrumentPlayer != null)
|
||||
return;
|
||||
|
||||
_instrumentPlayer = actor.playerSession;
|
||||
InstrumentPlayer = actor.playerSession;
|
||||
OpenUserInterface(actor.playerSession);
|
||||
}
|
||||
|
||||
@@ -106,17 +199,18 @@ namespace Content.Server.GameObjects.Components.Instruments
|
||||
if (!eventArgs.User.TryGetComponent(out IActorComponent actor))
|
||||
return false;
|
||||
|
||||
if(_instrumentPlayer == actor.playerSession)
|
||||
if(InstrumentPlayer == actor.playerSession)
|
||||
OpenUserInterface(actor.playerSession);
|
||||
return false;
|
||||
}
|
||||
|
||||
private void UserInterfaceOnClosed(IPlayerSession player)
|
||||
{
|
||||
if (!Handheld && player == _instrumentPlayer)
|
||||
if (!Handheld && player == InstrumentPlayer)
|
||||
{
|
||||
_instrumentPlayer = null;
|
||||
InstrumentPlayer = null;
|
||||
SendNetworkMessage(new InstrumentStopMidiMessage());
|
||||
Playing = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,5 +218,35 @@ namespace Content.Server.GameObjects.Components.Instruments
|
||||
{
|
||||
_userInterface.Open(session);
|
||||
}
|
||||
|
||||
public override void Update(float delta)
|
||||
{
|
||||
base.Update(delta);
|
||||
|
||||
if (_instrumentPlayer != null && !ActionBlockerSystem.CanInteract(_instrumentPlayer.AttachedEntity))
|
||||
InstrumentPlayer = null;
|
||||
|
||||
if (_batchesDropped > MaxMidiBatchDropped && InstrumentPlayer != null)
|
||||
{
|
||||
_batchesDropped = 0;
|
||||
var mob = InstrumentPlayer.AttachedEntity;
|
||||
|
||||
_userInterface.CloseAll();
|
||||
|
||||
if (mob.TryGetComponent(out StunnableComponent stun))
|
||||
stun.Stun(1);
|
||||
else
|
||||
StandingStateHelper.DropAllItemsInHands(mob);
|
||||
|
||||
InstrumentPlayer = null;
|
||||
|
||||
_notifyManager.PopupMessage(Owner, mob, "Your fingers cramp up from playing!");
|
||||
}
|
||||
|
||||
_timer += delta;
|
||||
if (_timer < 1) return;
|
||||
_timer = 0f;
|
||||
_midiEventCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Content.Server.GameObjects.Components.Sound;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using Content.Shared.Interfaces;
|
||||
@@ -250,14 +251,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";
|
||||
}
|
||||
|
||||
protected override VerbVisibility GetVisibility(IEntity user, HandheldLightComponent component)
|
||||
{
|
||||
return component.Cell == null ? VerbVisibility.Disabled : VerbVisibility.Visible;
|
||||
if (component.Cell == null)
|
||||
{
|
||||
data.Text = "Eject cell (cell missing)";
|
||||
data.Visibility = VerbVisibility.Disabled;
|
||||
}
|
||||
else
|
||||
{
|
||||
data.Text = "Eject cell";
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Activate(IEntity user, HandheldLightComponent component)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Server.GameObjects.Components.Sound;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.Audio;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Server.GameObjects.Components.Stack;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.Maps;
|
||||
using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -40,18 +41,11 @@ namespace Content.Server.GameObjects.Components.Items
|
||||
}
|
||||
public void AfterAttack(AfterAttackEventArgs eventArgs)
|
||||
{
|
||||
if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return;
|
||||
|
||||
var attacked = eventArgs.Attacked;
|
||||
var mapGrid = _mapManager.GetGrid(eventArgs.ClickLocation.GridID);
|
||||
var tile = mapGrid.GetTileRef(eventArgs.ClickLocation);
|
||||
|
||||
var coordinates = mapGrid.GridTileToLocal(tile.GridIndices);
|
||||
float distance = coordinates.Distance(_mapManager, Owner.Transform.GridPosition);
|
||||
|
||||
if (distance > InteractionSystem.InteractionRange)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var tileDef = (ContentTileDefinition)_tileDefinitionManager[tile.Tile.TypeId];
|
||||
if (tileDef.IsSubFloor && attacked == null && Stack.Use(1))
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Linq;
|
||||
using Content.Server.GameObjects.Components.Items.Storage;
|
||||
using Content.Server.GameObjects.Components.Sound;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Storage;
|
||||
using Robust.Server.GameObjects;
|
||||
@@ -190,7 +191,7 @@ namespace Content.Server.GameObjects.Components
|
||||
{
|
||||
if (Owner.TryGetComponent<ICollidableComponent>(out var collidableComponent))
|
||||
{
|
||||
collidableComponent.CollisionEnabled = IsCollidableWhenOpen || !Open;
|
||||
collidableComponent.CanCollide = IsCollidableWhenOpen || !Open;
|
||||
}
|
||||
|
||||
if (Owner.TryGetComponent<PlaceableSurfaceComponent>(out var placeableSurfaceComponent))
|
||||
@@ -250,7 +251,7 @@ namespace Content.Server.GameObjects.Components
|
||||
entity.Transform.WorldPosition = worldPos;
|
||||
if (entityCollidableComponent != null)
|
||||
{
|
||||
entityCollidableComponent.CollisionEnabled = false;
|
||||
entityCollidableComponent.CanCollide = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -265,7 +266,7 @@ namespace Content.Server.GameObjects.Components
|
||||
{
|
||||
if (contained.TryGetComponent<ICollidableComponent>(out var entityCollidableComponent))
|
||||
{
|
||||
entityCollidableComponent.CollisionEnabled = true;
|
||||
entityCollidableComponent.CanCollide = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -328,16 +329,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 +344,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 />
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
using Robust.Server.Interfaces.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.Random;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Items.Storage.Fill
|
||||
{
|
||||
[RegisterComponent]
|
||||
internal sealed class EmergencyClosetFillComponent : Component, IMapInit
|
||||
{
|
||||
public override string Name => "EmergencyClosetFill";
|
||||
|
||||
void IMapInit.MapInit()
|
||||
{
|
||||
var storage = Owner.GetComponent<IStorageComponent>();
|
||||
var random = IoCManager.Resolve<IRobustRandom>();
|
||||
|
||||
void Spawn(string prototype)
|
||||
{
|
||||
storage.Insert(Owner.EntityManager.SpawnEntity(prototype, Owner.Transform.GridPosition));
|
||||
}
|
||||
|
||||
if (random.Prob(40))
|
||||
{
|
||||
Spawn("ToolboxEmergencyFilled");
|
||||
}
|
||||
|
||||
var pick = random.Next(0, 100);
|
||||
if (pick < 40) // 40%
|
||||
{
|
||||
// TODO: uncomment when we actually have these items.
|
||||
// Spawn("TankOxygenSmallFilled");
|
||||
// Spawn("TankOxygenSmallFilled");
|
||||
Spawn("BreathMaskClothing");
|
||||
Spawn("BreathMaskClothing");
|
||||
}
|
||||
else if (pick < 65) // 25%
|
||||
{
|
||||
// Spawn("TankOxygenSmallFilled");
|
||||
// Spawn("MedkitOxygenFilled");
|
||||
Spawn("BreathMaskClothing");
|
||||
}
|
||||
else if (pick < 85) // 20%
|
||||
{
|
||||
// Spawn("TankOxygenFilled");
|
||||
Spawn("BreathMaskClothing");
|
||||
}
|
||||
else if (pick < 95) // 10%
|
||||
{
|
||||
// Spawn("TankOxygenSmallFilled");
|
||||
Spawn("BreathMaskClothing");
|
||||
}
|
||||
else if (pick < 99) // 4%
|
||||
{
|
||||
// nothing, doot
|
||||
}
|
||||
else // 1%
|
||||
{
|
||||
// teehee
|
||||
Owner.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,10 +12,6 @@ namespace Content.Server.GameObjects.Components.Items.Storage.Fill
|
||||
{
|
||||
public override string Name => "ToolLockerFill";
|
||||
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IEntityManager _entityManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
void IMapInit.MapInit()
|
||||
{
|
||||
var storage = Owner.GetComponent<IStorageComponent>();
|
||||
@@ -23,7 +19,7 @@ namespace Content.Server.GameObjects.Components.Items.Storage.Fill
|
||||
|
||||
void Spawn(string prototype)
|
||||
{
|
||||
storage.Insert(_entityManager.SpawnEntity(prototype, Owner.Transform.GridPosition));
|
||||
storage.Insert(Owner.EntityManager.SpawnEntity(prototype, Owner.Transform.GridPosition));
|
||||
}
|
||||
|
||||
if (random.Prob(0.4f))
|
||||
|
||||
@@ -4,6 +4,7 @@ using Content.Server.GameObjects.Components.Destructible;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Server.Throw;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Items;
|
||||
using Content.Shared.Physics;
|
||||
@@ -12,6 +13,7 @@ using Robust.Server.Interfaces.GameObjects;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
@@ -23,6 +25,7 @@ using Robust.Shared.Maths;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.GameObjects
|
||||
{
|
||||
@@ -35,7 +38,6 @@ namespace Content.Server.GameObjects
|
||||
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IRobustRandom _robustRandom;
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager;
|
||||
[Dependency] private readonly IMapManager _mapManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
@@ -97,8 +99,7 @@ namespace Content.Server.GameObjects
|
||||
var userPos = user.Transform.MapPosition;
|
||||
var itemPos = Owner.Transform.WorldPosition;
|
||||
|
||||
return _entitySystemManager.GetEntitySystem<InteractionSystem>()
|
||||
.InRangeUnobstructed(userPos, itemPos, ignoredEnt: Owner, insideBlockerValid:true);
|
||||
return InteractionChecks.InRangeUnobstructed(user, itemPos, ignoredEnt: Owner, insideBlockerValid:true);
|
||||
}
|
||||
|
||||
public bool AttackHand(AttackHandEventArgs eventArgs)
|
||||
@@ -113,23 +114,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)
|
||||
|
||||
@@ -5,6 +5,7 @@ using Content.Server.GameObjects.Components;
|
||||
using Content.Server.GameObjects.Components.Items.Storage;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects.Components.Storage;
|
||||
using Content.Shared.Interfaces;
|
||||
using Robust.Server.GameObjects;
|
||||
@@ -149,6 +150,8 @@ namespace Content.Server.GameObjects
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return PlayerInsertEntity(eventArgs.User);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ using Robust.Server.GameObjects.Components.UserInterface;
|
||||
using Robust.Server.Interfaces.GameObjects;
|
||||
using Robust.Shared.Localization;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Utility;
|
||||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Kitchen
|
||||
@@ -177,6 +178,7 @@ namespace Content.Server.GameObjects.Components.Kitchen
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateUserInterface();
|
||||
_userInterface.Open(actor.playerSession);
|
||||
|
||||
@@ -224,6 +226,8 @@ namespace Content.Server.GameObjects.Components.Kitchen
|
||||
|
||||
if (!itemEntity.TryGetComponent(typeof(FoodComponent), out var food))
|
||||
{
|
||||
|
||||
_notifyManager.PopupMessage(Owner, eventArgs.User, "That won't work!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using Content.Shared.Interfaces;
|
||||
using Content.Shared.Preferences.Appearance;
|
||||
|
||||
@@ -4,6 +4,7 @@ using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Medical;
|
||||
using Content.Server.GameObjects.Components.Power;
|
||||
using Content.Server.Utility;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameObjects.Components.Container;
|
||||
using Robust.Server.GameObjects.Components.UserInterface;
|
||||
@@ -120,22 +121,20 @@ namespace Content.Server.GameObjects.Components.Medical
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Powered)
|
||||
return;
|
||||
|
||||
_userInterface.Open(actor.playerSession);
|
||||
}
|
||||
|
||||
[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 +146,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)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Content.Server.GameObjects.Components.Sound;
|
||||
using Content.Server.GameObjects.Components.Weapon.Melee;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
|
||||
@@ -195,7 +195,7 @@ namespace Content.Server.GameObjects
|
||||
|
||||
if (entity.TryGetComponent(out CollidableComponent collidable))
|
||||
{
|
||||
collidable.CollisionEnabled = false;
|
||||
collidable.CanCollide = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ namespace Content.Server.GameObjects
|
||||
|
||||
if (entity.TryGetComponent(out CollidableComponent collidable))
|
||||
{
|
||||
collidable.CollisionEnabled = true;
|
||||
collidable.CanCollide = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,11 +6,13 @@ using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Server.Interfaces.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Timers;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Movement
|
||||
{
|
||||
@@ -63,7 +65,7 @@ namespace Content.Server.GameObjects.Components.Movement
|
||||
base.OnAdd();
|
||||
if (Owner.TryGetComponent<CollidableComponent>(out var collide))
|
||||
{
|
||||
collide.IsHardCollidable = false;
|
||||
//collide.IsHardCollidable = false;
|
||||
}
|
||||
|
||||
_state = PortalState.Pending;
|
||||
@@ -195,7 +197,7 @@ namespace Content.Server.GameObjects.Components.Movement
|
||||
if (!immuneEntities.Contains(entity))
|
||||
{
|
||||
var position = _connectingTeleporter.Transform.GridPosition;
|
||||
var soundPlayer = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AudioSystem>();
|
||||
var soundPlayer = EntitySystem.Get<AudioSystem>();
|
||||
|
||||
// Departure
|
||||
// Do we need to rate-limit sounds to stop ear BLAST?
|
||||
|
||||
@@ -7,6 +7,7 @@ using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Server.Interfaces.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.Interfaces.Random;
|
||||
@@ -16,6 +17,7 @@ using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Timers;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Movement
|
||||
{
|
||||
@@ -141,7 +143,7 @@ namespace Content.Server.GameObjects.Components.Movement
|
||||
Timer.Spawn(TimeSpan.FromSeconds(_chargeTime + _cooldown), () => SetState(ItemTeleporterState.Off));
|
||||
if (_cooldownSound != null)
|
||||
{
|
||||
var soundPlayer = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AudioSystem>();
|
||||
var soundPlayer = EntitySystem.Get<AudioSystem>();
|
||||
soundPlayer.Play(_cooldownSound, Owner);
|
||||
}
|
||||
}
|
||||
@@ -227,7 +229,7 @@ namespace Content.Server.GameObjects.Components.Movement
|
||||
{
|
||||
// Messy maybe?
|
||||
GridCoordinates targetGrid = new GridCoordinates(vector, user.Transform.GridID);
|
||||
var soundPlayer = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AudioSystem>();
|
||||
var soundPlayer = EntitySystem.Get<AudioSystem>();
|
||||
|
||||
// If portals use those, otherwise just move em over
|
||||
if (_portalAliveTime > 0.0f)
|
||||
|
||||
@@ -65,8 +65,8 @@ namespace Content.Server.GameObjects.Components.Movement
|
||||
if (!gridEntity.HasComponent<ICollidableComponent>())
|
||||
{
|
||||
var collideComp = gridEntity.AddComponent<CollidableComponent>();
|
||||
collideComp.CollisionEnabled = true;
|
||||
collideComp.IsHardCollidable = true;
|
||||
collideComp.CanCollide = true;
|
||||
//collideComp.IsHardCollidable = true;
|
||||
collideComp.PhysicsShapes.Add(new PhysShapeGrid(grid));
|
||||
}
|
||||
|
||||
|
||||
@@ -3,18 +3,22 @@ using System.Linq;
|
||||
using Content.Server.GameObjects.Components.Chemistry;
|
||||
using Content.Server.GameObjects.Components.Sound;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.GameObjects.Components.Nutrition;
|
||||
using Content.Shared.Interfaces;
|
||||
using Content.Shared.Maths;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Nutrition
|
||||
{
|
||||
@@ -98,23 +102,25 @@ namespace Content.Server.GameObjects.Components.Nutrition
|
||||
|
||||
void IAfterAttack.AfterAttack(AfterAttackEventArgs eventArgs)
|
||||
{
|
||||
if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return;
|
||||
|
||||
UseDrink(eventArgs.Attacked);
|
||||
}
|
||||
|
||||
private void UseDrink(IEntity user)
|
||||
private void UseDrink(IEntity targetEntity)
|
||||
{
|
||||
if (user == null)
|
||||
if (targetEntity == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (UsesLeft() == 0 && !_despawnOnFinish)
|
||||
{
|
||||
user.PopupMessage(user, _localizationManager.GetString("Empty"));
|
||||
targetEntity.PopupMessage(targetEntity, _localizationManager.GetString("Empty"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.TryGetComponent(out StomachComponent stomachComponent))
|
||||
if (targetEntity.TryGetComponent(out StomachComponent stomachComponent))
|
||||
{
|
||||
_drinking = true;
|
||||
var transferAmount = ReagentUnit.Min(_transferAmount, _contents.CurrentVolume);
|
||||
@@ -124,17 +130,16 @@ namespace Content.Server.GameObjects.Components.Nutrition
|
||||
// When we split Finish gets called which may delete the can so need to use the entity system for sound
|
||||
if (_useSound != null)
|
||||
{
|
||||
var entitySystemManager = IoCManager.Resolve<IEntitySystemManager>();
|
||||
var audioSystem = entitySystemManager.GetEntitySystem<AudioSystem>();
|
||||
audioSystem.Play(_useSound);
|
||||
user.PopupMessage(user, _localizationManager.GetString("Slurp"));
|
||||
var audioSystem = EntitySystem.Get<AudioSystem>();
|
||||
audioSystem.Play(_useSound, Owner, AudioParams.Default.WithVolume(-2f));
|
||||
targetEntity.PopupMessage(targetEntity, _localizationManager.GetString("Slurp"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add it back in
|
||||
_contents.TryAddSolution(split);
|
||||
user.PopupMessage(user, _localizationManager.GetString("Can't drink"));
|
||||
targetEntity.PopupMessage(targetEntity, _localizationManager.GetString("Can't drink"));
|
||||
}
|
||||
_drinking = false;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Content.Server.GameObjects.Components.Chemistry;
|
||||
using Content.Server.GameObjects.Components.Sound;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.GameObjects.Components.Nutrition;
|
||||
using Content.Shared.Interfaces;
|
||||
@@ -111,6 +112,8 @@ namespace Content.Server.GameObjects.Components.Nutrition
|
||||
|
||||
void IAfterAttack.AfterAttack(AfterAttackEventArgs eventArgs)
|
||||
{
|
||||
if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return;
|
||||
|
||||
UseFood(eventArgs.Attacked);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameObjects.Components.UserInterface;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Server.GameObjects.Components.Sound;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects.Components.Power;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameObjects.Components.UserInterface;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Power;
|
||||
using Content.Shared.Interfaces;
|
||||
@@ -58,28 +59,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 +97,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";
|
||||
data.Text = "Eject";
|
||||
data.Visibility = VerbVisibility.Disabled;
|
||||
return;
|
||||
}
|
||||
return $"Eject {component._container.ContainedEntity.Name}";
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Power;
|
||||
using Content.Shared.Interfaces;
|
||||
@@ -48,28 +49,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 +92,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";
|
||||
data.Visibility = VerbVisibility.Disabled;
|
||||
data.Text = "Eject";
|
||||
return;
|
||||
}
|
||||
return $"Eject {component._container.ContainedEntity.Name}";
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
@@ -4,6 +4,7 @@ using Content.Shared.Audio;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Random;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -12,6 +13,7 @@ using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Power
|
||||
{
|
||||
@@ -126,7 +128,7 @@ namespace Content.Server.GameObjects.Components.Power
|
||||
var soundCollection = _prototypeManager.Index<SoundCollectionPrototype>("glassbreak");
|
||||
var file = _random.Pick(soundCollection.PickFiles);
|
||||
|
||||
IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AudioSystem>().Play(file, Owner);
|
||||
EntitySystem.Get<AudioSystem>().Play(file, Owner);
|
||||
|
||||
State = LightBulbState.Broken;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using Content.Server.GameObjects.Components.Interactable;
|
||||
using Content.Server.GameObjects.Components.Stack;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.GameObjects.Components.Interactable;
|
||||
using Content.Server.Utility;
|
||||
using Robust.Server.Interfaces.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components.Transform;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using Content.Server.GameObjects.Components.Sound;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameObjects.Components.Container;
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Power
|
||||
{
|
||||
@@ -15,8 +17,7 @@ namespace Content.Server.GameObjects.Components.Power
|
||||
{
|
||||
public Powernet()
|
||||
{
|
||||
var EntitySystemManager = IoCManager.Resolve<IEntitySystemManager>();
|
||||
var powerSystem = EntitySystemManager.GetEntitySystem<PowerSystem>();
|
||||
var powerSystem = EntitySystem.Get<PowerSystem>();
|
||||
powerSystem.Powernets.Add(this);
|
||||
Uid = powerSystem.NewUid();
|
||||
}
|
||||
@@ -374,8 +375,7 @@ namespace Content.Server.GameObjects.Components.Power
|
||||
/// </summary>
|
||||
private void RemoveFromSystem()
|
||||
{
|
||||
var EntitySystemManager = IoCManager.Resolve<IEntitySystemManager>();
|
||||
EntitySystemManager.GetEntitySystem<PowerSystem>().Powernets.Remove(this);
|
||||
EntitySystem.Get<PowerSystem>().Powernets.Remove(this);
|
||||
}
|
||||
|
||||
#region Registration
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Server.GameObjects.Components.Stack;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Interfaces.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -25,6 +26,8 @@ namespace Content.Server.GameObjects.Components.Power
|
||||
/// <inheritdoc />
|
||||
public void AfterAttack(AfterAttackEventArgs eventArgs)
|
||||
{
|
||||
if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return;
|
||||
|
||||
if(!_mapManager.TryGetGrid(eventArgs.ClickLocation.GridID, out var grid))
|
||||
return;
|
||||
|
||||
|
||||
@@ -62,36 +62,32 @@ namespace Content.Server.GameObjects.Components.Projectiles
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applys the damage when our projectile collides with its victim
|
||||
/// Applies the damage when our projectile collides with its victim
|
||||
/// </summary>
|
||||
/// <param name="collidedwith"></param>
|
||||
void ICollideBehavior.CollideWith(List<IEntity> collidedwith)
|
||||
/// <param name="entity"></param>
|
||||
void ICollideBehavior.CollideWith(IEntity entity)
|
||||
{
|
||||
foreach (var entity in collidedwith)
|
||||
if (entity.TryGetComponent(out DamageableComponent damage))
|
||||
{
|
||||
if (entity.TryGetComponent(out DamageableComponent damage))
|
||||
Owner.EntityManager.TryGetEntity(Shooter, out var shooter);
|
||||
|
||||
foreach (var (damageType, amount) in _damages)
|
||||
{
|
||||
Owner.EntityManager.TryGetEntity(Shooter, out var shooter);
|
||||
|
||||
foreach (var (damageType, amount) in _damages)
|
||||
{
|
||||
|
||||
damage.TakeDamage(damageType, amount, Owner, shooter);
|
||||
}
|
||||
}
|
||||
|
||||
if (!entity.Deleted && entity.TryGetComponent(out CameraRecoilComponent recoilComponent)
|
||||
&& Owner.TryGetComponent(out PhysicsComponent physicsComponent))
|
||||
{
|
||||
var direction = physicsComponent.LinearVelocity.Normalized;
|
||||
recoilComponent.Kick(direction);
|
||||
damage.TakeDamage(damageType, amount, Owner, shooter);
|
||||
}
|
||||
}
|
||||
|
||||
if (collidedwith.Count > 0)
|
||||
if (!entity.Deleted && entity.TryGetComponent(out CameraRecoilComponent recoilComponent)
|
||||
&& Owner.TryGetComponent(out PhysicsComponent physicsComponent))
|
||||
{
|
||||
Owner.Delete();
|
||||
var direction = physicsComponent.LinearVelocity.Normalized;
|
||||
recoilComponent.Kick(direction);
|
||||
}
|
||||
}
|
||||
|
||||
void ICollideBehavior.PostCollide(int collideCount)
|
||||
{
|
||||
if (collideCount > 0) Owner.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ namespace Content.Server.GameObjects.Components
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
private bool _shouldCollide = true;
|
||||
|
||||
public override string Name => "ThrownItem";
|
||||
|
||||
/// <summary>
|
||||
@@ -25,32 +27,37 @@ namespace Content.Server.GameObjects.Components
|
||||
/// </summary>
|
||||
public IEntity User;
|
||||
|
||||
void ICollideBehavior.CollideWith(List<IEntity> collidedwith)
|
||||
void ICollideBehavior.CollideWith(IEntity entity)
|
||||
{
|
||||
foreach (var entity in collidedwith)
|
||||
if (!_shouldCollide) return;
|
||||
if (entity.TryGetComponent(out DamageableComponent damage))
|
||||
{
|
||||
if (entity.TryGetComponent(out DamageableComponent damage))
|
||||
{
|
||||
damage.TakeDamage(DamageType.Brute, 10, Owner, User);
|
||||
}
|
||||
damage.TakeDamage(DamageType.Brute, 10, Owner, User);
|
||||
}
|
||||
|
||||
// Stop colliding with mobs, this mimics not having enough velocity to do damage
|
||||
// after impacting the first object.
|
||||
// For realism this should actually be changed when the velocity of the object is less than a threshold.
|
||||
// This would allow ricochets off walls, and weird gravity effects from slowing the object.
|
||||
if (collidedwith.Count > 0 && Owner.TryGetComponent(out CollidableComponent body) && body.PhysicsShapes.Count >= 1)
|
||||
if (Owner.TryGetComponent(out CollidableComponent body) && body.PhysicsShapes.Count >= 1)
|
||||
{
|
||||
_shouldCollide = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void PostCollide(int collideCount)
|
||||
{
|
||||
|
||||
if (collideCount > 0 && Owner.TryGetComponent(out CollidableComponent body) && body.PhysicsShapes.Count >= 1)
|
||||
{
|
||||
body.PhysicsShapes[0].CollisionMask &= (int)~CollisionGroup.MobImpassable;
|
||||
body.IsScrapingFloor = true;
|
||||
|
||||
// KYS, your job is finished. Trigger ILand as well.
|
||||
var physics = Owner.GetComponent<PhysicsComponent>();
|
||||
(physics.Controller as ThrowController).StopThrow();
|
||||
physics.RemoveController();
|
||||
Owner.RemoveComponent<ThrownItemComponent>();
|
||||
_entitySystemManager.GetEntitySystem<InteractionSystem>().LandInteraction(User, Owner, Owner.Transform.GridPosition);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
using System.Collections.Generic;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Interfaces.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.Random;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Server.GameObjects.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class RandomToolColorComponent : Component, IMapInit
|
||||
{
|
||||
public override string Name => "RandomToolColor";
|
||||
|
||||
private string _selectedColor;
|
||||
private string _baseState;
|
||||
private Dictionary<string, Color> _colors;
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
|
||||
serializer.DataField(ref _selectedColor, "selected", null);
|
||||
serializer.DataField(ref _baseState, "state", "error");
|
||||
serializer.DataFieldCached(ref _colors, "colors", new Dictionary<string, Color>());
|
||||
}
|
||||
|
||||
void IMapInit.MapInit()
|
||||
{
|
||||
if (_colors == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var random = IoCManager.Resolve<IRobustRandom>();
|
||||
_selectedColor = random.Pick(_colors.Keys);
|
||||
UpdateColor();
|
||||
}
|
||||
|
||||
protected override void Startup()
|
||||
{
|
||||
base.Startup();
|
||||
|
||||
UpdateColor();
|
||||
}
|
||||
|
||||
private void UpdateColor()
|
||||
{
|
||||
if (Owner.TryGetComponent(out SpriteComponent spriteComponent) && _colors != null && _selectedColor != null)
|
||||
{
|
||||
spriteComponent.LayerSetState(0, _baseState);
|
||||
spriteComponent.LayerSetColor(0, _colors[_selectedColor]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ using System.Linq;
|
||||
using Content.Server.GameObjects.Components.Power;
|
||||
using Content.Server.GameObjects.Components.Stack;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects.Components.Materials;
|
||||
using Content.Shared.GameObjects.Components.Power;
|
||||
using Content.Shared.GameObjects.Components.Research;
|
||||
@@ -150,12 +151,13 @@ namespace Content.Server.GameObjects.Components.Research
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OpenUserInterface(actor.playerSession);
|
||||
}
|
||||
bool IAttackBy.AttackBy(AttackByEventArgs eventArgs)
|
||||
{
|
||||
if (!Owner.TryGetComponent(out MaterialStorageComponent storage)
|
||||
|| !eventArgs.AttackWith.TryGetComponent(out MaterialComponent material)) return false;
|
||||
|| !eventArgs.AttackWith.TryGetComponent(out MaterialComponent material)) return false;
|
||||
|
||||
var multiplier = 1;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects.Components.Research;
|
||||
using Robust.Server.GameObjects.Components.UserInterface;
|
||||
using Robust.Server.Interfaces.GameObjects;
|
||||
@@ -60,7 +61,6 @@ namespace Content.Server.GameObjects.Components.Research
|
||||
return;
|
||||
|
||||
OpenUserInterface(actor.playerSession);
|
||||
return;
|
||||
}
|
||||
|
||||
public void UpdateUserInterface()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Server.GameObjects.Components.Power;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.GameObjects.Components.Research;
|
||||
using Content.Shared.Research;
|
||||
@@ -110,6 +111,7 @@ namespace Content.Server.GameObjects.Components.Research
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OpenUserInterface(actor.playerSession);
|
||||
PlayKeyboardSound();
|
||||
return;
|
||||
|
||||
@@ -3,10 +3,12 @@ using Content.Server.GameObjects.Components.Power;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.Research;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Research
|
||||
{
|
||||
@@ -73,7 +75,7 @@ namespace Content.Server.GameObjects.Components.Research
|
||||
{
|
||||
base.Initialize();
|
||||
Id = ServerCount++;
|
||||
IoCManager.Resolve<IEntitySystemManager>()?.GetEntitySystem<ResearchSystem>()?.RegisterServer(this);
|
||||
EntitySystem.Get<ResearchSystem>()?.RegisterServer(this);
|
||||
Database = Owner.GetComponent<TechnologyDatabaseComponent>();
|
||||
Owner.TryGetComponent(out _powerDevice);
|
||||
}
|
||||
@@ -82,7 +84,7 @@ namespace Content.Server.GameObjects.Components.Research
|
||||
protected override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
IoCManager.Resolve<IEntitySystemManager>()?.GetEntitySystem<ResearchSystem>()?.UnregisterServer(this);
|
||||
EntitySystem.Get<ResearchSystem>()?.UnregisterServer(this);
|
||||
}
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using Content.Shared.Interfaces;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.Power;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects.Components.VendingMachines;
|
||||
using Content.Shared.VendingMachines;
|
||||
using Robust.Server.GameObjects;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Items;
|
||||
@@ -140,7 +141,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee
|
||||
for (var i = 0; i < increments; i++)
|
||||
{
|
||||
var castAngle = new Angle(baseAngle + increment * i);
|
||||
var res = _physicsManager.IntersectRay(mapId, new CollisionRay(position, castAngle.ToVec(), 23), _range, ignore, ignoreNonHardCollidables: true);
|
||||
var res = _physicsManager.IntersectRay(mapId, new CollisionRay(position, castAngle.ToVec(), 23), _range, ignore).First();
|
||||
if (res.HitEntity != null)
|
||||
{
|
||||
resSet.Add(res.HitEntity);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.Power;
|
||||
using Content.Server.GameObjects.Components.Sound;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.Interfaces;
|
||||
using Content.Shared.Physics;
|
||||
@@ -9,6 +11,7 @@ using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.EntitySystemMessages;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Physics;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
@@ -17,6 +20,7 @@ using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan
|
||||
{
|
||||
@@ -90,10 +94,13 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan
|
||||
var angle = new Angle(clickLocation.Position - userPosition);
|
||||
|
||||
var ray = new CollisionRay(userPosition, angle.ToVec(), (int)(CollisionGroup.Impassable | CollisionGroup.MobImpassable));
|
||||
var rayCastResults = IoCManager.Resolve<IPhysicsManager>().IntersectRay(user.Transform.MapID, ray, MaxLength, user, ignoreNonHardCollidables: true);
|
||||
var rayCastResults = IoCManager.Resolve<IPhysicsManager>().IntersectRay(user.Transform.MapID, ray, MaxLength, user).ToList();
|
||||
|
||||
Hit(rayCastResults, energyModifier, user);
|
||||
AfterEffects(user, rayCastResults, angle, energyModifier);
|
||||
if (rayCastResults.Count == 1)
|
||||
{
|
||||
Hit(rayCastResults[0], energyModifier, user);
|
||||
AfterEffects(user, rayCastResults[0], angle, energyModifier);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Hit(RayCastResults ray, float damageModifier, IEntity user = null)
|
||||
@@ -109,7 +116,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan
|
||||
protected virtual void AfterEffects(IEntity user, RayCastResults ray, Angle angle, float energyModifier)
|
||||
{
|
||||
var time = IoCManager.Resolve<IGameTiming>().CurTime;
|
||||
var dist = ray.DidHitObject ? ray.Distance : MaxLength;
|
||||
var dist = ray.Distance;
|
||||
var offset = angle.ToVec() * dist / 2;
|
||||
var message = new EffectSystemMessage
|
||||
{
|
||||
@@ -125,8 +132,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan
|
||||
|
||||
Shaded = false
|
||||
};
|
||||
var mgr = IoCManager.Resolve<IEntitySystemManager>();
|
||||
mgr.GetEntitySystem<EffectSystem>().CreateParticle(message);
|
||||
EntitySystem.Get<EffectSystem>().CreateParticle(message);
|
||||
Owner.GetComponent<SoundComponent>().Play(_fireSound, AudioParams.Default.WithVolume(-5));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged;
|
||||
using Content.Shared.Interfaces;
|
||||
using Robust.Server.GameObjects;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged;
|
||||
using Content.Shared.Interfaces;
|
||||
using Robust.Server.GameObjects;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.GameObjects.Components.Sound;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Weapons.Ranged;
|
||||
using Content.Shared.Interfaces;
|
||||
@@ -266,14 +267,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)
|
||||
|
||||
@@ -6,6 +6,7 @@ using Content.Server.GameObjects.Components.VendingMachines;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using Content.Shared.GameObjects.Components.Interactable;
|
||||
using JetBrains.Annotations;
|
||||
@@ -14,6 +15,7 @@ using Robust.Server.GameObjects.Components.UserInterface;
|
||||
using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Server.Interfaces.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Random;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -21,6 +23,7 @@ using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.GameObjects.Components
|
||||
{
|
||||
@@ -109,7 +112,7 @@ namespace Content.Server.GameObjects.Components
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_audioSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AudioSystem>();
|
||||
_audioSystem = EntitySystem.Get<AudioSystem>();
|
||||
_appearance = Owner.GetComponent<AppearanceComponent>();
|
||||
_appearance.SetData(WiresVisuals.MaintenancePanelState, IsPanelOpen);
|
||||
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
|
||||
@@ -236,8 +239,7 @@ namespace Content.Server.GameObjects.Components
|
||||
return;
|
||||
}
|
||||
|
||||
var interactionSystem = IoCManager.Resolve<EntitySystemManager>().GetEntitySystem<InteractionSystem>();
|
||||
if (!interactionSystem.InRangeUnobstructed(player.Transform.MapPosition, Owner.Transform.WorldPosition, ignoredEnt: Owner))
|
||||
if (!EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(player.Transform.MapPosition, Owner.Transform.WorldPosition, ignoredEnt: Owner))
|
||||
{
|
||||
_notifyManager.PopupMessage(Owner.Transform.GridPosition, player, _localizationManager.GetString("You can't reach there!"));
|
||||
return;
|
||||
@@ -304,8 +306,7 @@ namespace Content.Server.GameObjects.Components
|
||||
return false;
|
||||
|
||||
IsPanelOpen = !IsPanelOpen;
|
||||
IoCManager.Resolve<IEntitySystemManager>()
|
||||
.GetEntitySystem<AudioSystem>()
|
||||
EntitySystem.Get<AudioSystem>()
|
||||
.Play(IsPanelOpen ? "/Audio/machines/screwdriveropen.ogg" : "/Audio/machines/screwdriverclose.ogg", Owner);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Reflection;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
@@ -101,7 +102,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
var processorId = args[0];
|
||||
var entId = new EntityUid(int.Parse(args[1]));
|
||||
var ent = IoCManager.Resolve<IEntityManager>().GetEntity(entId);
|
||||
var aiSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AiSystem>();
|
||||
var aiSystem = EntitySystem.Get<AiSystem>();
|
||||
|
||||
if (!aiSystem.ProcessorTypeExists(processorId))
|
||||
{
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.Interactable;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.GameObjects.Components.Timing;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Interactable;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.GameObjects.Components.Inventory;
|
||||
using Content.Shared.Input;
|
||||
using Content.Shared.Physics;
|
||||
@@ -21,6 +21,7 @@ using Robust.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.Interfaces.Physics;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
@@ -30,36 +31,53 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
/// <summary>
|
||||
/// This interface gives components behavior when being clicked on or "attacked" by a user with an object in their hand
|
||||
/// who is in range and has unobstructed reach of the target entity (allows inside blockers).
|
||||
/// </summary>
|
||||
public interface IAttackBy
|
||||
{
|
||||
/// <summary>
|
||||
/// Called when using one object on another
|
||||
/// Called when using one object on another when user is in range of the target entity.
|
||||
/// </summary>
|
||||
bool AttackBy(AttackByEventArgs eventArgs);
|
||||
}
|
||||
|
||||
public class AttackByEventArgs : EventArgs
|
||||
public class AttackByEventArgs : EventArgs, ITargetedAttackEventArgs
|
||||
{
|
||||
public IEntity User { get; set; }
|
||||
public GridCoordinates ClickLocation { get; set; }
|
||||
public IEntity AttackWith { get; set; }
|
||||
public IEntity Attacked { get; set; }
|
||||
}
|
||||
|
||||
public interface ITargetedAttackEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Performer of the attack
|
||||
/// </summary>
|
||||
IEntity User { get; }
|
||||
/// <summary>
|
||||
/// Target of the attack
|
||||
/// </summary>
|
||||
IEntity Attacked { get; }
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This interface gives components behavior when being clicked on or "attacked" by a user with an empty hand
|
||||
/// who is in range and has unobstructed reach of the target entity (allows inside blockers).
|
||||
/// </summary>
|
||||
public interface IAttackHand
|
||||
{
|
||||
/// <summary>
|
||||
/// Called when a player directly interacts with an empty hand
|
||||
/// Called when a player directly interacts with an empty hand when user is in range of the target entity.
|
||||
/// </summary>
|
||||
bool AttackHand(AttackHandEventArgs eventArgs);
|
||||
}
|
||||
|
||||
public class AttackHandEventArgs : EventArgs
|
||||
public class AttackHandEventArgs : EventArgs, ITargetedAttackEventArgs
|
||||
{
|
||||
public IEntity User { get; set; }
|
||||
public IEntity Attacked { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -83,8 +101,8 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This interface gives components a behavior when clicking on another object and no interaction occurs
|
||||
/// Doesn't pass what you clicked on as an argument, but if it becomes necessary we can add it later
|
||||
/// This interface gives components a behavior when clicking on another object and no interaction occurs,
|
||||
/// at any range.
|
||||
/// </summary>
|
||||
public interface IAfterAttack
|
||||
{
|
||||
@@ -119,19 +137,21 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This interface gives components behavior when being activated in the world.
|
||||
/// This interface gives components behavior when being activated in the world when the user
|
||||
/// is in range and has unobstructed access to the target entity (allows inside blockers).
|
||||
/// </summary>
|
||||
public interface IActivate
|
||||
{
|
||||
/// <summary>
|
||||
/// Called when this component is activated by another entity.
|
||||
/// Called when this component is activated by another entity who is in range.
|
||||
/// </summary>
|
||||
void Activate(ActivateEventArgs eventArgs);
|
||||
}
|
||||
|
||||
public class ActivateEventArgs : EventArgs
|
||||
public class ActivateEventArgs : EventArgs, ITargetedAttackEventArgs
|
||||
{
|
||||
public IEntity User { get; set; }
|
||||
public IEntity Attacked { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -295,6 +315,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IMapManager _mapManager;
|
||||
[Dependency] private readonly IPhysicsManager _physicsManager;
|
||||
[Dependency] private readonly ILocalizationManager _localizationManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
public const float InteractionRange = 2;
|
||||
@@ -362,7 +383,12 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
return;
|
||||
}
|
||||
|
||||
activateComp.Activate(new ActivateEventArgs {User = user});
|
||||
// all activates should only fire when in range / unbostructed
|
||||
var activateEventArgs = new ActivateEventArgs {User = user, Attacked = used};
|
||||
if (InteractionChecks.InRangeUnobstructed(activateEventArgs))
|
||||
{
|
||||
activateComp.Activate(activateEventArgs);
|
||||
}
|
||||
}
|
||||
|
||||
private bool HandleWideAttack(ICommonSession session, GridCoordinates coords, EntityUid uid)
|
||||
@@ -559,14 +585,20 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
var attackBys = attacked.GetAllComponents<IAttackBy>().ToList();
|
||||
var attackByEventArgs = new AttackByEventArgs
|
||||
{
|
||||
User = user, ClickLocation = clickLocation, AttackWith = weapon
|
||||
User = user, ClickLocation = clickLocation, AttackWith = weapon, Attacked = attacked
|
||||
};
|
||||
|
||||
foreach (var attackBy in attackBys)
|
||||
// all AttackBys should only happen when in range / unobstructed, so no range check is needed
|
||||
if (InteractionChecks.InRangeUnobstructed(attackByEventArgs))
|
||||
{
|
||||
if (attackBy.AttackBy(attackByEventArgs))
|
||||
// If an AttackBy returns a status completion we finish our attack
|
||||
return;
|
||||
foreach (var attackBy in attackBys)
|
||||
{
|
||||
if (attackBy.AttackBy(attackByEventArgs))
|
||||
{
|
||||
// If an AttackBy returns a status completion we finish our attack
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var afterAtkMsg = new AfterAttackMessage(user, weapon, attacked, clickLocation);
|
||||
@@ -603,14 +635,18 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
}
|
||||
|
||||
var attackHands = attacked.GetAllComponents<IAttackHand>().ToList();
|
||||
var attackHandEventArgs = new AttackHandEventArgs {User = user};
|
||||
var attackHandEventArgs = new AttackHandEventArgs {User = user, Attacked = attacked};
|
||||
|
||||
foreach (var attackHand in attackHands)
|
||||
// all attackHands should only fire when in range / unbostructed
|
||||
if (InteractionChecks.InRangeUnobstructed(attackHandEventArgs))
|
||||
{
|
||||
if (attackHand.AttackHand(attackHandEventArgs))
|
||||
foreach (var attackHand in attackHands)
|
||||
{
|
||||
// If an AttackHand returns a status completion we finish our attack
|
||||
return;
|
||||
if (attackHand.AttackHand(attackHandEventArgs))
|
||||
{
|
||||
// If an AttackHand returns a status completion we finish our attack
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
@@ -105,7 +106,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
if (!TryGetAttachedComponent(session as IPlayerSession, out HandsComponent handsComp))
|
||||
return;
|
||||
|
||||
var interactionSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<InteractionSystem>();
|
||||
var interactionSystem = EntitySystem.Get<InteractionSystem>();
|
||||
|
||||
var oldItem = handsComp.GetActiveHand;
|
||||
|
||||
@@ -133,9 +134,8 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
if (handsComp.GetActiveHand == null)
|
||||
return false;
|
||||
|
||||
var interactionSystem = _entitySystemManager.GetEntitySystem<InteractionSystem>();
|
||||
|
||||
if(interactionSystem.InRangeUnobstructed(coords.ToMap(_mapManager), ent.Transform.WorldPosition, ignoredEnt: ent))
|
||||
if(EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(coords.ToMap(_mapManager), ent.Transform.WorldPosition, ignoredEnt: ent))
|
||||
if (coords.InRange(_mapManager, ent.Transform.GridPosition, InteractionSystem.InteractionRange))
|
||||
{
|
||||
handsComp.Drop(handsComp.ActiveIndex, coords);
|
||||
|
||||
25
Content.Server/GameObjects/EntitySystems/InstrumentSystem.cs
Normal file
25
Content.Server/GameObjects/EntitySystems/InstrumentSystem.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using Content.Server.GameObjects.Components.Instruments;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
|
||||
namespace Content.Server.GameObjects.EntitySystems
|
||||
{
|
||||
public class InstrumentSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
EntityQuery = new TypeEntityQuery(typeof(InstrumentComponent));
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
foreach (var entity in RelevantEntities)
|
||||
{
|
||||
entity.GetComponent<InstrumentComponent>().Update(frameTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ using Content.Server.Observer;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.GameObjects.Components.Inventory;
|
||||
using Content.Shared.Maps;
|
||||
using Content.Shared.Physics;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameObjects.EntitySystems;
|
||||
@@ -148,7 +149,13 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
|
||||
private void UpdateKinematics(ITransformComponent transform, IMoverComponent mover, PhysicsComponent physics, CollidableComponent collider = null)
|
||||
{
|
||||
bool weightless = false;
|
||||
if (physics.Controller == null)
|
||||
{
|
||||
// Set up controller
|
||||
physics.SetController<MoverController>();
|
||||
}
|
||||
|
||||
var weightless = false;
|
||||
|
||||
var tile = _mapManager.GetGrid(transform.GridID).GetTileRef(transform.GridPosition).Tile;
|
||||
|
||||
@@ -167,27 +174,27 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
&& !entity.HasComponent<ItemComponent>(); // This can't be an item
|
||||
}
|
||||
}
|
||||
|
||||
if (!touching)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (mover.VelocityDir.LengthSquared < 0.001 || !ActionBlockerSystem.CanMove(mover.Owner))
|
||||
{
|
||||
if (physics.LinearVelocity != Vector2.Zero)
|
||||
physics.LinearVelocity = Vector2.Zero;
|
||||
|
||||
if (mover.VelocityDir.LengthSquared < 0.001 || !ActionBlockerSystem.CanMove(mover.Owner) && !weightless)
|
||||
{
|
||||
(physics.Controller as MoverController)?.StopMoving();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (weightless)
|
||||
{
|
||||
physics.LinearVelocity = mover.VelocityDir * mover.CurrentPushSpeed;
|
||||
(physics.Controller as MoverController)?.Push(mover.VelocityDir, mover.CurrentPushSpeed);
|
||||
transform.LocalRotation = mover.VelocityDir.GetDir().ToAngle();
|
||||
return;
|
||||
}
|
||||
|
||||
physics.LinearVelocity = mover.VelocityDir * (mover.Sprinting ? mover.CurrentSprintSpeed : mover.CurrentWalkSpeed);
|
||||
(physics.Controller as MoverController)?.Move(mover.VelocityDir,
|
||||
mover.Sprinting ? mover.CurrentSprintSpeed : mover.CurrentWalkSpeed);
|
||||
transform.LocalRotation = mover.VelocityDir.GetDir().ToAngle();
|
||||
|
||||
// Handle footsteps.
|
||||
|
||||
@@ -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;
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (groupController.CanCommand(player.playerSession, "controlmob"))
|
||||
return VerbVisibility.Visible;
|
||||
{
|
||||
data.Visibility = VerbVisibility.Visible;
|
||||
data.Text = "Control Mob";
|
||||
data.CategoryData = VerbCategories.Debug;
|
||||
}
|
||||
}
|
||||
|
||||
return VerbVisibility.Invisible;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.BodySystem;
|
||||
|
||||
|
||||
@@ -41,6 +42,7 @@ namespace Content.Server.BodySystem
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (actor.playerSession.AttachedEntity.TryGetComponent(out BodyManagerComponent attempt))
|
||||
{
|
||||
_userInterface.SetState(PrepareBodyScannerInterfaceState(attempt.Template, attempt.PartDictionary));
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.BodySystem;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.BodySystem;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.Components.Items;
|
||||
@@ -42,6 +43,8 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee
|
||||
|
||||
void IAfterAttack.AfterAttack(AfterAttackEventArgs eventArgs)
|
||||
{
|
||||
if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return;
|
||||
|
||||
if (eventArgs.Attacked == null)
|
||||
return;
|
||||
if (eventArgs.Attacked.TryGetComponent<BodySystem.BodyManagerComponent>(out BodySystem.BodyManagerComponent bodyManager))
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Content.Server.Throw
|
||||
|
||||
var mapManager = IoCManager.Resolve<IMapManager>();
|
||||
|
||||
colComp.CollisionEnabled = true;
|
||||
colComp.CanCollide = true;
|
||||
// I can now collide with player, so that i can do damage.
|
||||
|
||||
if (!thrownEnt.TryGetComponent(out ThrownItemComponent projComp))
|
||||
@@ -37,7 +37,7 @@ namespace Content.Server.Throw
|
||||
colComp.PhysicsShapes.Add(new PhysShapeAabb());
|
||||
|
||||
colComp.PhysicsShapes[0].CollisionMask |= (int) (CollisionGroup.MobImpassable | CollisionGroup.Impassable);
|
||||
colComp.IsScrapingFloor = false;
|
||||
colComp.Status = BodyStatus.InAir;
|
||||
}
|
||||
var angle = new Angle(targetLoc.ToMapPos(mapManager) - sourceLoc.ToMapPos(mapManager));
|
||||
|
||||
@@ -58,20 +58,16 @@ namespace Content.Server.Throw
|
||||
if (!thrownEnt.TryGetComponent(out PhysicsComponent physComp))
|
||||
physComp = thrownEnt.AddComponent<PhysicsComponent>();
|
||||
|
||||
// TODO: Move this into PhysicsSystem, we need an ApplyForce function.
|
||||
var a = throwForce / (float) Math.Max(0.001, physComp.Mass); // a = f / m
|
||||
|
||||
var timing = IoCManager.Resolve<IGameTiming>();
|
||||
var spd = a / (1f / timing.TickRate); // acceleration is applied in 1 tick instead of 1 second, scale appropriately
|
||||
var spd = throwForce / (1f / timing.TickRate); // acceleration is applied in 1 tick instead of 1 second, scale appropriately
|
||||
|
||||
physComp.LinearVelocity = angle.ToVec() * spd;
|
||||
physComp.SetController<ThrowController>();
|
||||
(physComp.Controller as ThrowController)?.StartThrow(angle.ToVec() * spd);
|
||||
|
||||
if (throwSourceEnt != null)
|
||||
if (throwSourceEnt != null && throwSourceEnt.TryGetComponent<PhysicsComponent>(out var physics))
|
||||
{
|
||||
var p = throwSourceEnt.GetComponent<PhysicsComponent>();
|
||||
var playerAccel = 5 * throwForce / (float) Math.Max(0.001, p.Mass);
|
||||
p.LinearVelocity = Angle.FromDegrees(angle.Degrees + 180).ToVec()
|
||||
* playerAccel / (1f / timing.TickRate);
|
||||
const float ThrowFactor = 5.0f; // Break Newton's Third Law for better gameplay
|
||||
(physics.Controller as MoverController)?.Push(-angle.ToVec(), spd * ThrowFactor / physics.Mass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
100
Content.Server/Utility/InteractionChecks.cs
Normal file
100
Content.Server/Utility/InteractionChecks.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.Interfaces;
|
||||
using Content.Shared.Physics;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Map;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Server.Utility
|
||||
{
|
||||
/// <summary>
|
||||
/// Convenient methods for checking for various conditions commonly needed
|
||||
/// for interactions.
|
||||
/// </summary>
|
||||
public static class InteractionChecks
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Default interaction check for targeted attack interaction types.
|
||||
/// Same as <see cref="SharedInteractionSystem.InRangeUnobstructed"/>, but defaults to allow inside blockers.
|
||||
/// Validates that attacker is in range of the attacked entity. Additionally shows a popup if
|
||||
/// validation fails.
|
||||
/// </summary>
|
||||
public static bool InRangeUnobstructed(ITargetedAttackEventArgs eventArgs, bool insideBlockerValid = true)
|
||||
{
|
||||
if (!EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(eventArgs.User.Transform.MapPosition,
|
||||
eventArgs.Attacked.Transform.WorldPosition, ignoredEnt: eventArgs.Attacked, insideBlockerValid: insideBlockerValid))
|
||||
{
|
||||
var localizationManager = IoCManager.Resolve<ILocalizationManager>();
|
||||
eventArgs.Attacked.PopupMessage(eventArgs.User, localizationManager.GetString("You can't reach there!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default interaction check for after attack interaction types.
|
||||
/// Same as <see cref="SharedInteractionSystem.InRangeUnobstructed"/>, but defaults to allow inside blockers.
|
||||
/// Validates that attacker is in range of the attacked entity, if there is such an entity.
|
||||
/// If there is no attacked entity, validates that they are in range of the clicked position.
|
||||
/// Additionally shows a popup if validation fails.
|
||||
/// </summary>
|
||||
public static bool InRangeUnobstructed(AfterAttackEventArgs eventArgs, bool insideBlockerValid = true)
|
||||
{
|
||||
if (eventArgs.Attacked != null)
|
||||
{
|
||||
if (!EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(eventArgs.User.Transform.MapPosition,
|
||||
eventArgs.Attacked.Transform.WorldPosition, ignoredEnt: eventArgs.Attacked, insideBlockerValid: insideBlockerValid))
|
||||
{
|
||||
var localizationManager = IoCManager.Resolve<ILocalizationManager>();
|
||||
eventArgs.Attacked.PopupMessage(eventArgs.User, localizationManager.GetString("You can't reach there!"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var mapManager = IoCManager.Resolve<IMapManager>();
|
||||
if (!EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(eventArgs.User.Transform.MapPosition,
|
||||
eventArgs.ClickLocation.ToMapPos(mapManager), ignoredEnt: eventArgs.User, insideBlockerValid: insideBlockerValid))
|
||||
{
|
||||
var localizationManager = IoCManager.Resolve<ILocalizationManager>();
|
||||
eventArgs.User.PopupMessage(eventArgs.User, localizationManager.GetString("You can't reach there!"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convenient static alternative to <see cref="SharedInteractionSystem.InRangeUnobstructed"/>, which also
|
||||
/// shows a popup message if not in range.
|
||||
/// </summary>
|
||||
public static bool InRangeUnobstructed(IEntity user, Vector2 targetWorldCoords,
|
||||
float range = SharedInteractionSystem.InteractionRange,
|
||||
int collisionMask = (int) CollisionGroup.Impassable, IEntity ignoredEnt = null,
|
||||
bool insideBlockerValid = false)
|
||||
{
|
||||
var interactionSystem = EntitySystem.Get<SharedInteractionSystem>();
|
||||
if (!interactionSystem.InRangeUnobstructed(user.Transform.MapPosition, targetWorldCoords, range, collisionMask,
|
||||
ignoredEnt, insideBlockerValid))
|
||||
{
|
||||
var localizationManager = IoCManager.Resolve<ILocalizationManager>();
|
||||
user.PopupMessage(user, localizationManager.GetString("You can't reach there!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Content.Shared.BodySystem;
|
||||
using Robust.Shared.Audio.Midi;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
@@ -9,6 +10,10 @@ namespace Content.Shared.GameObjects.Components.Instruments
|
||||
{
|
||||
public override string Name => "Instrument";
|
||||
public override uint? NetID => ContentNetIDs.INSTRUMENTS;
|
||||
|
||||
public virtual void Update(float delta)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,19 +25,39 @@ namespace Content.Shared.GameObjects.Components.Instruments
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This message is sent to the client to start the synth.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public class InstrumentStartMidiMessage : ComponentMessage
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This message carries a MidiEvent to be played on clients.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public class InstrumentMidiEventMessage : ComponentMessage
|
||||
{
|
||||
public MidiEvent MidiEvent;
|
||||
public double Timestamp;
|
||||
public MidiEvent[] MidiEvent;
|
||||
|
||||
public InstrumentMidiEventMessage(MidiEvent midiEvent, double timestamp)
|
||||
public InstrumentMidiEventMessage(MidiEvent[] midiEvent)
|
||||
{
|
||||
MidiEvent = midiEvent;
|
||||
Timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class InstrumentState : ComponentState
|
||||
{
|
||||
public bool Playing { get; }
|
||||
public uint SequencerTick { get; }
|
||||
|
||||
public InstrumentState(bool playing, uint sequencerTick = 0) : base(ContentNetIDs.INSTRUMENTS)
|
||||
{
|
||||
Playing = playing;
|
||||
SequencerTick = sequencerTick;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ using Content.Shared.GameObjects.Components.Mobs;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.GameObjects.EntitySystems
|
||||
{
|
||||
@@ -30,8 +30,7 @@ namespace Content.Shared.GameObjects.EntitySystems
|
||||
return false;
|
||||
}
|
||||
|
||||
return IoCManager.Resolve<IEntitySystemManager>()
|
||||
.GetEntitySystem<SharedInteractionSystem>()
|
||||
return EntitySystem.Get<SharedInteractionSystem>()
|
||||
.InRangeUnobstructed(examiner.Transform.MapPosition, examined.Transform.MapPosition.Position,
|
||||
ExamineRange, predicate: entity => entity == examiner || entity == examined, insideBlockerValid:true);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Content.Shared.Physics;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
@@ -36,7 +37,6 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
/// <param name="range">maximum distance between the two sets of coordinates.</param>
|
||||
/// <param name="collisionMask">the mask to check for collisions</param>
|
||||
/// <param name="predicate">.</param>
|
||||
/// <param name="mapManager">Map manager containing the two GridIds.</param>
|
||||
/// <param name="insideBlockerValid">if coordinates inside obstructions count as obstructed or not</param>
|
||||
/// <returns>True if the two points are within a given range without being obstructed.</returns>
|
||||
public bool InRangeUnobstructed(MapCoordinates coords, Vector2 otherCoords, float range = InteractionRange,
|
||||
@@ -48,8 +48,8 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
if (range > 0f && !(dir.LengthSquared <= range * range)) return false;
|
||||
|
||||
var ray = new CollisionRay(coords.Position, dir.Normalized, collisionMask);
|
||||
var rayResults = _physicsManager.IntersectRayWithPredicate(coords.MapId, ray, dir.Length, predicate, true);
|
||||
if(!rayResults.DidHitObject || (insideBlockerValid && rayResults.DidHitObject && (rayResults.HitPos - otherCoords).Length < 1f))
|
||||
var rayResults = _physicsManager.IntersectRayWithPredicate(coords.MapId, ray, dir.Length, predicate).ToList();
|
||||
if(rayResults.Count == 0 || (insideBlockerValid && rayResults.Count > 0 && (rayResults[0].HitPos - otherCoords).Length < 1f))
|
||||
{
|
||||
|
||||
if (_mapManager.TryFindGridAt(coords, out var mapGrid) && mapGrid != null)
|
||||
@@ -77,7 +77,6 @@ namespace Content.Server.GameObjects.EntitySystems
|
||||
/// <param name="range">maximum distance between the two sets of coordinates.</param>
|
||||
/// <param name="collisionMask">the mask to check for collisions</param>
|
||||
/// <param name="ignoredEnt">the entity to be ignored when checking for collisions.</param>
|
||||
/// <param name="mapManager">Map manager containing the two GridIds.</param>
|
||||
/// <param name="insideBlockerValid">if coordinates inside obstructions count as obstructed or not</param>
|
||||
/// <returns>True if the two points are within a given range without being obstructed.</returns>
|
||||
public bool InRangeUnobstructed(MapCoordinates coords, Vector2 otherCoords, float range = InteractionRange,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user