Merge branch 'master-upstream' into expl_int_analyzer
This commit is contained in:
7
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
7
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
contact_links:
|
||||
- name: Report a Security Exploit
|
||||
url: https://discord.gg/MwDDf6t
|
||||
about: Please report serious security exploits and vulnerabilities to @PJB3005. (PJB#3482 on discord).
|
||||
- name: Request a Feature
|
||||
url: https://hackmd.io/@ss14/docs
|
||||
about: Submit feature requests on our [discord server](https://discord.gg/ZBFGnb3) or checkout our design documentation on HackMD.
|
||||
19
.github/ISSUE_TEMPLATE/issue_report.md
vendored
Normal file
19
.github/ISSUE_TEMPLATE/issue_report.md
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
name: Report an Issue
|
||||
about: "..."
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!-- To automatically tag this issue, add the uppercase label(s) surrounded by brackets below, for example: [LABEL] -->
|
||||
|
||||
## Description
|
||||
<!-- Explain your issue in detail, including the steps to reproduce it if applicable. Issues without proper explanation are liable to be closed by maintainers.-->
|
||||
|
||||
**Screenshots**
|
||||
<!-- If applicable, add screenshots to help explain your problem. -->
|
||||
|
||||
**Additional context**
|
||||
<!-- Add any other context about the problem here. -->
|
||||
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<!-- The text between the arrows are comments - they will not be visible on your PR. -->
|
||||
<!-- To automatically tag this PR, add the uppercase label(s) surrounded by brackets below, for example: [LABEL] -->
|
||||
|
||||
## About the PR <!-- Describe the Pull Request here. What does it change? What other things could this impact? -->
|
||||
|
||||
**Screenshots**
|
||||
<!-- If applicable, add screenshots to showcase your PR. If your PR is a visual change, add
|
||||
screenshots or it's liable to be closed by maintainers. -->
|
||||
47
.github/keylabeler.yml
vendored
Normal file
47
.github/keylabeler.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
# Determines if we search the title (optional). Defaults to true.
|
||||
matchTitle: false
|
||||
|
||||
# Determines if we search the body (optional). Defaults to true.
|
||||
matchBody: true
|
||||
|
||||
# Determines if label matching is case sensitive (optional). Defaults to true.
|
||||
caseSensitive: false
|
||||
|
||||
# Explicit keyword mappings to labels. Form of match:label. Required.
|
||||
labelMappings:
|
||||
"[ATMOS]": "Feature: Atmospherics"
|
||||
"[AUDIO]": "Feature: Audio"
|
||||
"[CONSTRUCTION]": "Feature: Construction"
|
||||
"[ENTITIES]": "Feature: Entities"
|
||||
"[ENTITY]": "Feature: Entities"
|
||||
"[ENTITY AI]": "Feature: Entity AI"
|
||||
"[EVENTS]": "Feature: Events"
|
||||
"[EVENT]": "Feature: Events"
|
||||
"[INTERACTION]": "Feature: Interaction"
|
||||
"[MEDICAL]": "Feature: Medical"
|
||||
"[PHYSICS]": "Feature: Physics"
|
||||
"[POWER]": "Feature: Power"
|
||||
"[SPRITES]": "Feature: Sprites"
|
||||
"[SPRITE]": "Feature: Sprites"
|
||||
"[UI]": "Feature: UI"
|
||||
|
||||
"[BUG]": "Type: Bug"
|
||||
"[CLEANUP]": "Type: Cleanup"
|
||||
"[CLEAN]": "Type: Cleanup"
|
||||
"[CLEANLINESS]": "Type: Cleanup"
|
||||
"[DISCUSSION]": "Type: Discussion"
|
||||
"[DISCUSS]": "Type: Discussion"
|
||||
"[FEATURE]": "Type: Feature"
|
||||
"[FEAT]": "Type: Feature"
|
||||
"[IMPROVEMENT]": "Type: Improvement"
|
||||
"[IMPROVE]": "Type: Improvement"
|
||||
"[PERFORMANCE]": "Type: Performance"
|
||||
"[PERF]": "Type: Performance"
|
||||
"[REFACTOR]": "Type: Refactor"
|
||||
|
||||
"[HELP WANTED]": "Status: Help Wanted"
|
||||
"[DO NOT MERGE]": "Status: DO NOT MERGE"
|
||||
"[DNM]": "Status: DO NOT MERGE"
|
||||
|
||||
"[RESOURCES]": "Resources (No code)"
|
||||
"[NOCODE]": "Resources (No code)"
|
||||
@@ -458,7 +458,7 @@ namespace Content.Client.Arcade
|
||||
return grid;
|
||||
}
|
||||
|
||||
protected override void FocusExited()
|
||||
protected override void KeyboardFocusExited()
|
||||
{
|
||||
if (!IsOpen) return;
|
||||
if(_gameOver) return;
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace Content.Client.Chat
|
||||
public Button LocalButton { get; }
|
||||
public Button OOCButton { get; }
|
||||
public Button AdminButton { get; }
|
||||
public Button DeadButton { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Default formatting string for the ClientChatConsole.
|
||||
@@ -103,13 +104,23 @@ namespace Content.Client.Chat
|
||||
Visible = false
|
||||
};
|
||||
|
||||
DeadButton = new Button
|
||||
{
|
||||
Text = Loc.GetString("Dead"),
|
||||
Name = "Dead",
|
||||
ToggleMode = true,
|
||||
Visible = false
|
||||
};
|
||||
|
||||
AllButton.OnToggled += OnFilterToggled;
|
||||
LocalButton.OnToggled += OnFilterToggled;
|
||||
OOCButton.OnToggled += OnFilterToggled;
|
||||
AdminButton.OnToggled += OnFilterToggled;
|
||||
DeadButton.OnToggled += OnFilterToggled;
|
||||
|
||||
hBox.AddChild(AllButton);
|
||||
hBox.AddChild(LocalButton);
|
||||
hBox.AddChild(DeadButton);
|
||||
hBox.AddChild(OOCButton);
|
||||
hBox.AddChild(AdminButton);
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using Content.Client.Administration;
|
||||
using Content.Client.GameObjects.Components.Observer;
|
||||
using Content.Client.Interfaces.Chat;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Chat;
|
||||
using Robust.Client.Console;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
using Robust.Client.Interfaces.UserInterface;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -25,6 +27,8 @@ namespace Content.Client.Chat
|
||||
{
|
||||
internal sealed class ChatManager : IChatManager, IPostInjectInit
|
||||
{
|
||||
[Dependency] private IPlayerManager _playerManager = default!;
|
||||
|
||||
private struct SpeechBubbleData
|
||||
{
|
||||
public string Message;
|
||||
@@ -61,13 +65,14 @@ namespace Content.Client.Chat
|
||||
private const char MeAlias = '@';
|
||||
private const char AdminChatAlias = ']';
|
||||
|
||||
private readonly List<StoredChatMessage> filteredHistory = new();
|
||||
private readonly List<StoredChatMessage> _filteredHistory = new();
|
||||
|
||||
// Filter Button States
|
||||
private bool _allState;
|
||||
private bool _localState;
|
||||
private bool _oocState;
|
||||
private bool _adminState;
|
||||
private bool _deadState;
|
||||
|
||||
// Flag Enums for holding filtered channels
|
||||
private ChatChannel _filteredChannels;
|
||||
@@ -98,8 +103,8 @@ namespace Content.Client.Chat
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_netManager.RegisterNetMessage<MsgChatMessage>(MsgChatMessage.NAME, _onChatMessage);
|
||||
_netManager.RegisterNetMessage<ChatMaxMsgLengthMessage>(ChatMaxMsgLengthMessage.NAME, _onMaxLengthReceived);
|
||||
_netManager.RegisterNetMessage<MsgChatMessage>(MsgChatMessage.NAME, OnChatMessage);
|
||||
_netManager.RegisterNetMessage<ChatMaxMsgLengthMessage>(ChatMaxMsgLengthMessage.NAME, OnMaxLengthReceived);
|
||||
|
||||
_speechBubbleRoot = new LayoutContainer();
|
||||
LayoutContainer.SetAnchorPreset(_speechBubbleRoot, LayoutContainer.LayoutPreset.Wide);
|
||||
@@ -152,24 +157,25 @@ namespace Content.Client.Chat
|
||||
{
|
||||
if (_currentChatBox != null)
|
||||
{
|
||||
_currentChatBox.TextSubmitted -= _onChatBoxTextSubmitted;
|
||||
_currentChatBox.FilterToggled -= _onFilterButtonToggled;
|
||||
_currentChatBox.TextSubmitted -= OnChatBoxTextSubmitted;
|
||||
_currentChatBox.FilterToggled -= OnFilterButtonToggled;
|
||||
}
|
||||
|
||||
_currentChatBox = chatBox;
|
||||
if (_currentChatBox != null)
|
||||
{
|
||||
_currentChatBox.TextSubmitted += _onChatBoxTextSubmitted;
|
||||
_currentChatBox.FilterToggled += _onFilterButtonToggled;
|
||||
_currentChatBox.TextSubmitted += OnChatBoxTextSubmitted;
|
||||
_currentChatBox.FilterToggled += OnFilterButtonToggled;
|
||||
|
||||
_currentChatBox.AllButton.Pressed = !_allState;
|
||||
_currentChatBox.LocalButton.Pressed = !_localState;
|
||||
_currentChatBox.OOCButton.Pressed = !_oocState;
|
||||
_currentChatBox.AdminButton.Pressed = !_adminState;
|
||||
_currentChatBox.DeadButton.Pressed = !_deadState;
|
||||
AdminStatusUpdated();
|
||||
}
|
||||
|
||||
RepopulateChat(filteredHistory);
|
||||
RepopulateChat(_filteredHistory);
|
||||
}
|
||||
|
||||
public void RemoveSpeechBubble(EntityUid entityUid, SpeechBubble bubble)
|
||||
@@ -224,7 +230,7 @@ namespace Content.Client.Chat
|
||||
_currentChatBox?.AddLine(messageText, message.Channel, color);
|
||||
}
|
||||
|
||||
private void _onChatBoxTextSubmitted(ChatBox chatBox, string text)
|
||||
private void OnChatBoxTextSubmitted(ChatBox chatBox, string text)
|
||||
{
|
||||
DebugTools.Assert(chatBox == _currentChatBox);
|
||||
|
||||
@@ -295,7 +301,7 @@ namespace Content.Client.Chat
|
||||
}
|
||||
}
|
||||
|
||||
private void _onFilterButtonToggled(ChatBox chatBox, BaseButton.ButtonToggledEventArgs e)
|
||||
private void OnFilterButtonToggled(ChatBox chatBox, BaseButton.ButtonToggledEventArgs e)
|
||||
{
|
||||
switch (e.Button.Name)
|
||||
{
|
||||
@@ -336,6 +342,13 @@ namespace Content.Client.Chat
|
||||
_filteredChannels &= ~ChatChannel.AdminChat;
|
||||
break;
|
||||
}
|
||||
case "Dead":
|
||||
_deadState = !_deadState;
|
||||
if (_deadState)
|
||||
_filteredChannels |= ChatChannel.Dead;
|
||||
else
|
||||
_filteredChannels &= ~ChatChannel.Dead;
|
||||
break;
|
||||
|
||||
case "ALL":
|
||||
chatBox.LocalButton.Pressed ^= true;
|
||||
@@ -346,7 +359,7 @@ namespace Content.Client.Chat
|
||||
break;
|
||||
}
|
||||
|
||||
RepopulateChat(filteredHistory);
|
||||
RepopulateChat(_filteredHistory);
|
||||
}
|
||||
|
||||
private void RepopulateChat(IEnumerable<StoredChatMessage> filteredMessages)
|
||||
@@ -364,11 +377,11 @@ namespace Content.Client.Chat
|
||||
}
|
||||
}
|
||||
|
||||
private void _onChatMessage(MsgChatMessage msg)
|
||||
private void OnChatMessage(MsgChatMessage msg)
|
||||
{
|
||||
// Log all incoming chat to repopulate when filter is un-toggled
|
||||
var storedMessage = new StoredChatMessage(msg);
|
||||
filteredHistory.Add(storedMessage);
|
||||
_filteredHistory.Add(storedMessage);
|
||||
WriteChatMessage(storedMessage);
|
||||
|
||||
// Local messages that have an entity attached get a speech bubble.
|
||||
@@ -378,7 +391,13 @@ namespace Content.Client.Chat
|
||||
switch (msg.Channel)
|
||||
{
|
||||
case ChatChannel.Local:
|
||||
AddSpeechBubble(msg, SpeechBubble.SpeechType.Say);
|
||||
break;
|
||||
|
||||
case ChatChannel.Dead:
|
||||
if (!_playerManager.LocalPlayer?.ControlledEntity?.HasComponent<GhostComponent>() ?? true)
|
||||
break;
|
||||
|
||||
AddSpeechBubble(msg, SpeechBubble.SpeechType.Say);
|
||||
break;
|
||||
|
||||
@@ -388,7 +407,7 @@ namespace Content.Client.Chat
|
||||
}
|
||||
}
|
||||
|
||||
private void _onMaxLengthReceived(ChatMaxMsgLengthMessage msg)
|
||||
private void OnMaxLengthReceived(ChatMaxMsgLengthMessage msg)
|
||||
{
|
||||
_maxMessageLength = msg.MaxMessageLength;
|
||||
}
|
||||
@@ -522,6 +541,18 @@ namespace Content.Client.Chat
|
||||
if (_currentChatBox != null)
|
||||
{
|
||||
_currentChatBox.AdminButton.Visible = _adminMgr.HasFlag(AdminFlags.Admin);
|
||||
_currentChatBox.DeadButton.Visible = _adminMgr.HasFlag(AdminFlags.Admin);
|
||||
}
|
||||
}
|
||||
|
||||
public void ToggleDeadChatButtonVisibility(bool visibility)
|
||||
{
|
||||
if (_currentChatBox != null)
|
||||
{
|
||||
// If the user is an admin and returned to body, don't set the flag as null
|
||||
if (!visibility && _adminMgr.HasFlag(AdminFlags.Admin))
|
||||
return;
|
||||
_currentChatBox.DeadButton.Visible = visibility;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using Content.Client.GameObjects.Components.Construction;
|
||||
using Content.Client.GameObjects.EntitySystems;
|
||||
using Content.Shared.Construction;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Placement;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
@@ -49,7 +51,15 @@ namespace Content.Client.Construction
|
||||
{
|
||||
base.StartHijack(manager);
|
||||
|
||||
manager.CurrentBaseSprite = _prototype?.Icon.DirFrame0();
|
||||
var frame = _prototype?.Icon.DirFrame0();
|
||||
if (frame == null)
|
||||
{
|
||||
manager.CurrentTextures = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
manager.CurrentTextures = new List<IDirectionalTextureProvider> {frame};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,6 @@ namespace Content.Client
|
||||
prototypes.RegisterIgnore("seed"); // Seeds prototypes are server-only.
|
||||
prototypes.RegisterIgnore("barSign");
|
||||
prototypes.RegisterIgnore("objective");
|
||||
prototypes.RegisterIgnore("dataset");
|
||||
|
||||
ClientContentIoC.Register();
|
||||
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects.Components.UserInterface;
|
||||
|
||||
namespace Content.Client.GameObjects.Components
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class AcceptCloningBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
|
||||
public AcceptCloningBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
private AcceptCloningWindow _window;
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_window = new AcceptCloningWindow();
|
||||
_window.OnClose += Close;
|
||||
_window.DenyButton.OnPressed += _ => _window.Close();
|
||||
_window.ConfirmButton.OnPressed += _ =>
|
||||
{
|
||||
SendMessage(
|
||||
new SharedAcceptCloningComponent.UiButtonPressedMessage(
|
||||
SharedAcceptCloningComponent.UiButton.Accept));
|
||||
_window.Close();
|
||||
};
|
||||
_window.OpenCentered();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
_window?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,6 @@ namespace Content.Client.GameObjects.Components.Arcade
|
||||
base.Open();
|
||||
|
||||
_menu = new BlockGameMenu(this);
|
||||
_menu.OnClose += () => SendMessage(new BlockGameMessages.BlockGameUserUnregisterMessage());
|
||||
_menu.OnClose += Close;
|
||||
_menu.OpenCentered();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
#nullable enable
|
||||
using Content.Shared.GameObjects.Components.Atmos;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Atmos
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class GasFilterVisualizer : AppearanceVisualizer
|
||||
{
|
||||
private string _filterEnabledState = default!;
|
||||
|
||||
public override void LoadData(YamlMappingNode node)
|
||||
{
|
||||
base.LoadData(node);
|
||||
var serializer = YamlObjectSerializer.NewReader(node);
|
||||
serializer.DataField(ref _filterEnabledState, "filterEnabledState", "gasFilterOn");
|
||||
}
|
||||
|
||||
public override void InitializeEntity(IEntity entity)
|
||||
{
|
||||
base.InitializeEntity(entity);
|
||||
|
||||
if (!entity.TryGetComponent<ISpriteComponent>(out var sprite)) return;
|
||||
|
||||
sprite.LayerMapReserveBlank(Layer.FilterEnabled);
|
||||
var filterEnabledLayer = sprite.LayerMapGet(Layer.FilterEnabled);
|
||||
sprite.LayerSetState(filterEnabledLayer, _filterEnabledState);
|
||||
}
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
|
||||
if (!component.Owner.TryGetComponent<ISpriteComponent>(out var sprite)) return;
|
||||
if (!component.TryGetData(FilterVisuals.VisualState, out FilterVisualState filterVisualState)) return;
|
||||
|
||||
var filterEnabledLayer = sprite.LayerMapGet(Layer.FilterEnabled);
|
||||
sprite.LayerSetVisible(filterEnabledLayer, filterVisualState.Enabled);
|
||||
}
|
||||
|
||||
public enum Layer : byte
|
||||
{
|
||||
FilterEnabled,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using Content.Shared.GameObjects.Components.Atmos;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
@@ -10,6 +10,7 @@ using Robust.Shared.GameObjects.Components.Renderable;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
@@ -18,14 +19,18 @@ namespace Content.Client.GameObjects.Components.Atmos
|
||||
[UsedImplicitly]
|
||||
public class PipeVisualizer : AppearanceVisualizer
|
||||
{
|
||||
private string _rsiString;
|
||||
|
||||
private RSI _pipeRSI;
|
||||
|
||||
public override void LoadData(YamlMappingNode node)
|
||||
{
|
||||
base.LoadData(node);
|
||||
|
||||
var rsiString = node.GetNode("pipeRSI").ToString();
|
||||
var rsiPath = SharedSpriteComponent.TextureRoot / rsiString;
|
||||
var serializer = YamlObjectSerializer.NewReader(node);
|
||||
serializer.DataField(ref _rsiString, "rsiString", "Constructible/Atmos/pipe.rsi");
|
||||
|
||||
var rsiPath = SharedSpriteComponent.TextureRoot / _rsiString;
|
||||
try
|
||||
{
|
||||
var resourceCache = IoCManager.Resolve<IResourceCache>();
|
||||
@@ -62,7 +67,6 @@ namespace Content.Client.GameObjects.Components.Atmos
|
||||
{
|
||||
var stateId = "pipe";
|
||||
stateId += pipeVisualState.PipeDirection.PipeDirectionToPipeShape().ToString();
|
||||
stateId += (int) pipeVisualState.ConduitLayer;
|
||||
return stateId;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using Content.Shared.GameObjects.Components.Atmos;
|
||||
using Content.Shared.GameObjects.Components.Atmos;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.Serialization;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Atmos
|
||||
@@ -16,7 +16,9 @@ namespace Content.Client.GameObjects.Components.Atmos
|
||||
public override void LoadData(YamlMappingNode node)
|
||||
{
|
||||
base.LoadData(node);
|
||||
_pumpEnabledState = node.GetNode("pumpEnabledState").ToString();
|
||||
|
||||
var serializer = YamlObjectSerializer.NewReader(node);
|
||||
serializer.DataField(ref _pumpEnabledState, "pumpEnabledState", "pumpPressureOn");
|
||||
}
|
||||
|
||||
public override void InitializeEntity(IEntity entity)
|
||||
@@ -0,0 +1,51 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Content.Shared.GameObjects.Components.Atmos;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Atmos
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class SiphonVisualizer : AppearanceVisualizer
|
||||
{
|
||||
private string _siphonOnState;
|
||||
|
||||
public override void LoadData(YamlMappingNode node)
|
||||
{
|
||||
base.LoadData(node);
|
||||
|
||||
var serializer = YamlObjectSerializer.NewReader(node);
|
||||
serializer.DataField(ref _siphonOnState, "siphonOnState", "scrubOn");
|
||||
}
|
||||
|
||||
public override void InitializeEntity(IEntity entity)
|
||||
{
|
||||
base.InitializeEntity(entity);
|
||||
|
||||
if (!entity.TryGetComponent(out ISpriteComponent sprite)) return;
|
||||
|
||||
sprite.LayerMapReserveBlank(Layer.SiphonEnabled);
|
||||
var layer = sprite.LayerMapGet(Layer.SiphonEnabled);
|
||||
sprite.LayerSetState(layer, _siphonOnState);
|
||||
}
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
|
||||
if (!component.Owner.TryGetComponent(out ISpriteComponent sprite)) return;
|
||||
if (!component.TryGetData(SiphonVisuals.VisualState, out SiphonVisualState siphonVisualState)) return;
|
||||
|
||||
var layer = sprite.LayerMapGet(Layer.SiphonEnabled);
|
||||
sprite.LayerSetVisible(layer, siphonVisualState.SiphonEnabled);
|
||||
}
|
||||
|
||||
private enum Layer : byte
|
||||
{
|
||||
SiphonEnabled,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Content.Shared.GameObjects.Components.Atmos;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Atmos
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class VentVisualizer : AppearanceVisualizer
|
||||
{
|
||||
private string _ventOnstate;
|
||||
|
||||
public override void LoadData(YamlMappingNode node)
|
||||
{
|
||||
base.LoadData(node);
|
||||
|
||||
var serializer = YamlObjectSerializer.NewReader(node);
|
||||
serializer.DataField(ref _ventOnstate, "ventOnState", "ventOn");
|
||||
}
|
||||
|
||||
public override void InitializeEntity(IEntity entity)
|
||||
{
|
||||
base.InitializeEntity(entity);
|
||||
|
||||
if (!entity.TryGetComponent(out ISpriteComponent sprite)) return;
|
||||
|
||||
sprite.LayerMapReserveBlank(Layer.VentEnabled);
|
||||
var layer = sprite.LayerMapGet(Layer.VentEnabled);
|
||||
sprite.LayerSetState(layer, _ventOnstate);
|
||||
}
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
|
||||
if (!component.Owner.TryGetComponent(out ISpriteComponent sprite)) return;
|
||||
if (!component.TryGetData(VentVisuals.VisualState, out VentVisualState ventVisualState)) return;
|
||||
|
||||
var layer = sprite.LayerMapGet(Layer.VentEnabled);
|
||||
sprite.LayerSetVisible(layer, ventVisualState.VentEnabled);
|
||||
}
|
||||
|
||||
private enum Layer : byte
|
||||
{
|
||||
VentEnabled,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.GameObjects.Components.Renderable;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Utility;
|
||||
using System;
|
||||
using Content.Shared.GameObjects.Components.Atmos;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Atmos
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class SiphonVisualizer : AppearanceVisualizer
|
||||
{
|
||||
private RSI _siphonRSI;
|
||||
|
||||
public override void LoadData(YamlMappingNode node)
|
||||
{
|
||||
base.LoadData(node);
|
||||
|
||||
var rsiString = node.GetNode("siphonRSI").ToString();
|
||||
var rsiPath = SharedSpriteComponent.TextureRoot / rsiString;
|
||||
try
|
||||
{
|
||||
var resourceCache = IoCManager.Resolve<IResourceCache>();
|
||||
var resource = resourceCache.GetResource<RSIResource>(rsiPath);
|
||||
_siphonRSI = resource.RSI;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.ErrorS("go.siphonvisualizer", "Unable to load RSI '{0}'. Trace:\n{1}", rsiPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
public override void InitializeEntity(IEntity entity)
|
||||
{
|
||||
base.InitializeEntity(entity);
|
||||
if (!entity.TryGetComponent(out ISpriteComponent sprite)) return;
|
||||
sprite.LayerMapReserveBlank(Layer.SiphonBase);
|
||||
var pipeBaseLayer = sprite.LayerMapGet(Layer.SiphonBase);
|
||||
sprite.LayerSetRSI(pipeBaseLayer, _siphonRSI);
|
||||
sprite.LayerSetVisible(pipeBaseLayer, true);
|
||||
}
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
|
||||
if (!component.Owner.TryGetComponent(out ISpriteComponent sprite)) return;
|
||||
if (!component.TryGetData(SiphonVisuals.VisualState, out SiphonVisualState siphonVisualState)) return;
|
||||
|
||||
var siphonBaseState = "scrub";
|
||||
siphonBaseState += siphonVisualState.SiphonEnabled ? "On" : "Off";
|
||||
|
||||
var baseSiphonLayer = sprite.LayerMapGet(Layer.SiphonBase);
|
||||
sprite.LayerSetRSI(baseSiphonLayer, _siphonRSI);
|
||||
sprite.LayerSetState(baseSiphonLayer, siphonBaseState);
|
||||
sprite.LayerSetVisible(baseSiphonLayer, true);
|
||||
}
|
||||
|
||||
private enum Layer : byte
|
||||
{
|
||||
SiphonBase,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.GameObjects.Components.Renderable;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Utility;
|
||||
using System;
|
||||
using Content.Shared.GameObjects.Components.Atmos;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Atmos
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class VentVisualizer : AppearanceVisualizer
|
||||
{
|
||||
private RSI _ventRSI;
|
||||
|
||||
public override void LoadData(YamlMappingNode node)
|
||||
{
|
||||
base.LoadData(node);
|
||||
|
||||
var rsiString = node.GetNode("ventRSI").ToString();
|
||||
var rsiPath = SharedSpriteComponent.TextureRoot / rsiString;
|
||||
try
|
||||
{
|
||||
var resourceCache = IoCManager.Resolve<IResourceCache>();
|
||||
var resource = resourceCache.GetResource<RSIResource>(rsiPath);
|
||||
_ventRSI = resource.RSI;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.ErrorS("go.ventvisualizer", "Unable to load RSI '{0}'. Trace:\n{1}", rsiPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
public override void InitializeEntity(IEntity entity)
|
||||
{
|
||||
base.InitializeEntity(entity);
|
||||
if (!entity.TryGetComponent(out ISpriteComponent sprite)) return;
|
||||
sprite.LayerMapReserveBlank(Layer.VentBase);
|
||||
var pipeBaseLayer = sprite.LayerMapGet(Layer.VentBase);
|
||||
sprite.LayerSetRSI(pipeBaseLayer, _ventRSI);
|
||||
sprite.LayerSetVisible(pipeBaseLayer, true);
|
||||
}
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
|
||||
if (!component.Owner.TryGetComponent(out ISpriteComponent sprite)) return;
|
||||
if (!component.TryGetData(VentVisuals.VisualState, out VentVisualState ventVisualState)) return;
|
||||
|
||||
var ventBaseState = "vent";
|
||||
ventBaseState += ventVisualState.VentEnabled ? "On" : "Off";
|
||||
|
||||
var baseVentLayer = sprite.LayerMapGet(Layer.VentBase);
|
||||
sprite.LayerSetRSI(baseVentLayer, _ventRSI);
|
||||
sprite.LayerSetState(baseVentLayer, ventBaseState);
|
||||
sprite.LayerSetVisible(baseVentLayer, true);
|
||||
}
|
||||
|
||||
private enum Layer : byte
|
||||
{
|
||||
VentBase,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
#nullable enable
|
||||
using Content.Client.GameObjects.Components.Disposal;
|
||||
using Content.Client.GameObjects.Components.MedicalScanner;
|
||||
using Content.Shared.GameObjects.Components.Body;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -11,16 +9,14 @@ namespace Content.Client.GameObjects.Components.Body
|
||||
[ComponentReference(typeof(IBody))]
|
||||
public class BodyComponent : SharedBodyComponent, IDraggable
|
||||
{
|
||||
public bool CanDrop(CanDropEventArgs eventArgs)
|
||||
bool IDraggable.CanStartDrag(StartDragDropEventArgs args)
|
||||
{
|
||||
if (eventArgs.Target.HasComponent<DisposalUnitComponent>() ||
|
||||
eventArgs.Target.HasComponent<MedicalScannerComponent>() ||
|
||||
eventArgs.Target.HasComponent<DisposalMailingUnitComponent>())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
public bool CanDrop(CanDropEventArgs args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using Robust.Shared.Interfaces.GameObjects;
|
||||
namespace Content.Client.GameObjects.Components.Buckle
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SharedBuckleComponent))]
|
||||
public class BuckleComponent : SharedBuckleComponent
|
||||
{
|
||||
private bool _buckled;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Content.Client.UserInterface.Stylesheets;
|
||||
using Content.Shared.Chemistry;
|
||||
@@ -378,7 +378,7 @@ namespace Content.Client.GameObjects.Components.Chemistry.ChemMaster
|
||||
bufferHBox.AddChild(bufferLabel);
|
||||
var bufferVol = new Label
|
||||
{
|
||||
Text = $"{state.BufferCurrentVolume}/{state.BufferMaxVolume}",
|
||||
Text = $"{state.BufferCurrentVolume}",
|
||||
StyleClasses = {StyleNano.StyleClassLabelSecondaryColor}
|
||||
};
|
||||
bufferHBox.AddChild(bufferVol);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Content.Shared.Chemistry;
|
||||
#nullable enable
|
||||
using Content.Shared.GameObjects.Components.Chemistry;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
@@ -8,22 +8,6 @@ namespace Content.Client.GameObjects.Components.Chemistry
|
||||
[ComponentReference(typeof(SharedSolutionContainerComponent))]
|
||||
public class SolutionContainerComponent : SharedSolutionContainerComponent
|
||||
{
|
||||
public override bool CanAddSolution(Solution solution)
|
||||
{
|
||||
// TODO CLIENT
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool TryAddSolution(Solution solution, bool skipReactionCheck = false, bool skipColor = false)
|
||||
{
|
||||
// TODO CLIENT
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool TryRemoveReagent(string reagentId, ReagentUnit quantity)
|
||||
{
|
||||
// TODO CLIENT
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +87,8 @@ namespace Content.Client.GameObjects.Components
|
||||
{
|
||||
foreach (var layer in sprite.AllLayers)
|
||||
{
|
||||
if (!layer.Visible) continue;
|
||||
|
||||
if (layer.Texture != null)
|
||||
{
|
||||
if (_clickMapManager.IsOccluding(layer.Texture,
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#nullable enable
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Content.Client.GameObjects.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Spawns a set of entities on the client only, and removes them when this component is removed.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public class ClientEntitySpawnerComponent : Component
|
||||
{
|
||||
public override string Name => "ClientEntitySpawner";
|
||||
|
||||
private List<string> _prototypes = default!;
|
||||
|
||||
private List<IEntity> _entity = new();
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
serializer.DataField(ref _prototypes, "prototypes", new List<string> { "HVDummyWire" });
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SpawnEntities();
|
||||
}
|
||||
|
||||
public override void OnRemove()
|
||||
{
|
||||
RemoveEntities();
|
||||
base.OnRemove();
|
||||
}
|
||||
|
||||
private void SpawnEntities()
|
||||
{
|
||||
foreach (var proto in _prototypes)
|
||||
{
|
||||
var entity = Owner.EntityManager.SpawnEntity(proto, Owner.Transform.Coordinates);
|
||||
_entity.Add(entity);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveEntities()
|
||||
{
|
||||
foreach (var entity in _entity)
|
||||
{
|
||||
Owner.EntityManager.DeleteEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.GameObjects.Components.Disposal;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Disposal
|
||||
@@ -7,5 +8,9 @@ namespace Content.Client.GameObjects.Components.Disposal
|
||||
[ComponentReference(typeof(SharedDisposalMailingUnitComponent))]
|
||||
public class DisposalMailingUnitComponent : SharedDisposalMailingUnitComponent
|
||||
{
|
||||
public override bool DragDropOn(DragDropEventArgs eventArgs)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.GameObjects.Components.Disposal;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Disposal
|
||||
@@ -7,5 +8,9 @@ namespace Content.Client.GameObjects.Components.Disposal
|
||||
[ComponentReference(typeof(SharedDisposalUnitComponent))]
|
||||
public class DisposalUnitComponent : SharedDisposalUnitComponent
|
||||
{
|
||||
public override bool DragDropOn(DragDropEventArgs eventArgs)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
using Content.Shared.GameObjects.Components.Explosion;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Explosion
|
||||
{
|
||||
[UsedImplicitly]
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public class ClusterFlashVisualizer : AppearanceVisualizer
|
||||
{
|
||||
private string _state;
|
||||
|
||||
public override void LoadData(YamlMappingNode node)
|
||||
{
|
||||
base.LoadData(node);
|
||||
if (node.TryGetNode("state", out var state))
|
||||
{
|
||||
_state = state.AsString();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
|
||||
if (!component.Owner.TryGetComponent<ISpriteComponent>(out var sprite))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (component.TryGetData(ClusterFlashVisuals.GrenadesCounter, out int grenadesCounter))
|
||||
{
|
||||
sprite.LayerSetState(0, $"{_state}-{grenadesCounter}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Client.GameObjects.Components.Clothing;
|
||||
using Content.Shared.GameObjects.Components.Inventory;
|
||||
using Content.Shared.GameObjects.Components.Movement;
|
||||
using Content.Shared.Preferences.Appearance;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
@@ -78,6 +79,46 @@ namespace Content.Client.GameObjects.Components.HUD.Inventory
|
||||
return item != null && _slots.Values.Any(e => e == item);
|
||||
}
|
||||
|
||||
public override float WalkSpeedModifier
|
||||
{
|
||||
get
|
||||
{
|
||||
var mod = 1f;
|
||||
foreach (var slot in _slots.Values)
|
||||
{
|
||||
if (slot != null)
|
||||
{
|
||||
foreach (var modifier in slot.GetAllComponents<IMoveSpeedModifier>())
|
||||
{
|
||||
mod *= modifier.WalkSpeedModifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mod;
|
||||
}
|
||||
}
|
||||
|
||||
public override float SprintSpeedModifier
|
||||
{
|
||||
get
|
||||
{
|
||||
var mod = 1f;
|
||||
foreach (var slot in _slots.Values)
|
||||
{
|
||||
if (slot != null)
|
||||
{
|
||||
foreach (var modifier in slot.GetAllComponents<IMoveSpeedModifier>())
|
||||
{
|
||||
mod *= modifier.SprintSpeedModifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mod;
|
||||
}
|
||||
}
|
||||
|
||||
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
|
||||
{
|
||||
base.HandleComponentState(curState, nextState);
|
||||
@@ -117,6 +158,11 @@ namespace Content.Client.GameObjects.Components.HUD.Inventory
|
||||
_slots.Remove(slot);
|
||||
}
|
||||
}
|
||||
|
||||
if (Owner.TryGetComponent(out MovementSpeedModifierComponent? mod))
|
||||
{
|
||||
mod.RefreshMovementSpeedModifiers();
|
||||
}
|
||||
}
|
||||
|
||||
private void _setSlot(Slots slot, IEntity entity)
|
||||
|
||||
@@ -30,7 +30,8 @@ namespace Content.Client.GameObjects.Components.HUD.Inventory
|
||||
private ItemSlotButton _hudButtonBelt;
|
||||
private ItemSlotButton _hudButtonBack;
|
||||
private ItemSlotButton _hudButtonId;
|
||||
private Control _quickButtonsContainer;
|
||||
private Control _rightQuickButtonsContainer;
|
||||
private Control _leftQuickButtonsContainer;
|
||||
|
||||
public HumanInventoryInterfaceController(ClientInventoryComponent owner) : base(owner)
|
||||
{
|
||||
@@ -69,16 +70,26 @@ namespace Content.Client.GameObjects.Components.HUD.Inventory
|
||||
AddButton(out _hudButtonBelt, Slots.BELT, "belt");
|
||||
AddButton(out _hudButtonId, Slots.IDCARD, "id");
|
||||
|
||||
_quickButtonsContainer = new HBoxContainer
|
||||
_leftQuickButtonsContainer = new HBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
_hudButtonId,
|
||||
_hudButtonBelt,
|
||||
_hudButtonBack,
|
||||
_hudButtonBelt,
|
||||
},
|
||||
SeparationOverride = 5
|
||||
};
|
||||
_rightQuickButtonsContainer = new HBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
_hudButtonPocket1,
|
||||
_hudButtonPocket2,
|
||||
}
|
||||
// keeps this "balanced" with the left, so the hands will appear perfectly in the center
|
||||
new Control{CustomMinimumSize = (64, 64)}
|
||||
},
|
||||
SeparationOverride = 5
|
||||
};
|
||||
}
|
||||
|
||||
@@ -161,7 +172,8 @@ namespace Content.Client.GameObjects.Components.HUD.Inventory
|
||||
{
|
||||
base.PlayerAttached();
|
||||
|
||||
GameHud.InventoryQuickButtonContainer.AddChild(_quickButtonsContainer);
|
||||
GameHud.RightInventoryQuickButtonContainer.AddChild(_rightQuickButtonsContainer);
|
||||
GameHud.LeftInventoryQuickButtonContainer.AddChild(_leftQuickButtonsContainer);
|
||||
|
||||
// Update all the buttons to make sure they check out.
|
||||
|
||||
@@ -183,7 +195,8 @@ namespace Content.Client.GameObjects.Components.HUD.Inventory
|
||||
{
|
||||
base.PlayerDetached();
|
||||
|
||||
GameHud.InventoryQuickButtonContainer.RemoveChild(_quickButtonsContainer);
|
||||
GameHud.RightInventoryQuickButtonContainer.RemoveChild(_rightQuickButtonsContainer);
|
||||
GameHud.LeftInventoryQuickButtonContainer.RemoveChild(_leftQuickButtonsContainer);
|
||||
|
||||
foreach (var (slot, list) in _inventoryButtons)
|
||||
{
|
||||
@@ -197,7 +210,7 @@ namespace Content.Client.GameObjects.Components.HUD.Inventory
|
||||
private class HumanInventoryWindow : SS14Window
|
||||
{
|
||||
private const int ButtonSize = 64;
|
||||
private const int ButtonSeparation = 2;
|
||||
private const int ButtonSeparation = 4;
|
||||
private const int RightSeparation = 2;
|
||||
|
||||
public IReadOnlyDictionary<Slots, ItemSlotButton> Buttons { get; }
|
||||
|
||||
22
Content.Client/GameObjects/Components/MagbootsComponent.cs
Normal file
22
Content.Client/GameObjects/Components/MagbootsComponent.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Content.Client.GameObjects.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class MagbootsComponent : SharedMagbootsComponent
|
||||
{
|
||||
public override bool On { get; set; }
|
||||
|
||||
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
|
||||
{
|
||||
if (curState is not MagbootsComponentState compState)
|
||||
return;
|
||||
|
||||
On = compState.On;
|
||||
OnChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.GameObjects.Components.Medical;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.MedicalScanner
|
||||
@@ -7,5 +8,9 @@ namespace Content.Client.GameObjects.Components.MedicalScanner
|
||||
[ComponentReference(typeof(SharedMedicalScannerComponent))]
|
||||
public class MedicalScannerComponent : SharedMedicalScannerComponent
|
||||
{
|
||||
public override bool DragDropOn(DragDropEventArgs eventArgs)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,12 +24,12 @@ namespace Content.Client.GameObjects.Components.MedicalScanner
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case Off: return "scanner_off";
|
||||
case Open: return "scanner_open";
|
||||
case Red: return "scanner_red";
|
||||
case Death: return "scanner_death";
|
||||
case Green: return "scanner_green";
|
||||
case Yellow: return "scanner_yellow";
|
||||
case Off: return "closed";
|
||||
case Open: return "open";
|
||||
case Red: return "closed";
|
||||
case Death: return "closed";
|
||||
case Green: return "occupied";
|
||||
case Yellow: return "closed";
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(status), status, "unknown MedicalScannerStatus");
|
||||
}
|
||||
@@ -39,12 +39,12 @@ namespace Content.Client.GameObjects.Components.MedicalScanner
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case Off: return "scanner_terminal_off";
|
||||
case Open: return "scanner_terminal_blue";
|
||||
case Red: return "scanner_terminal_red";
|
||||
case Death: return "scanner_terminal_dead";
|
||||
case Green: return "scanner_terminal_green";
|
||||
case Yellow: return "scanner_terminal_blue";
|
||||
case Off: return "off_unlit";
|
||||
case Open: return "idle_unlit";
|
||||
case Red: return "red_unlit";
|
||||
case Death: return "red_unlit";
|
||||
case Green: return "idle_unlit";
|
||||
case Yellow: return "maint_unlit";
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(status), status, "unknown MedicalScannerStatus");
|
||||
}
|
||||
|
||||
@@ -30,8 +30,7 @@ namespace Content.Client.GameObjects.Components.Mobs
|
||||
private Vector2 _currentKick;
|
||||
private float _lastKickTime;
|
||||
|
||||
[ComponentDependency]
|
||||
private readonly EyeComponent? _eye;
|
||||
[ComponentDependency] private readonly EyeComponent? _eye = null;
|
||||
|
||||
// Basically I needed a way to chain this effect for the attack lunge animation.
|
||||
// Sorry!
|
||||
|
||||
@@ -184,8 +184,10 @@ namespace Content.Client.GameObjects.Components.Mobs
|
||||
|
||||
// only do something for actual target-based actions
|
||||
if (_ui?.SelectingTargetFor?.Action == null ||
|
||||
(_ui.SelectingTargetFor.Action.BehaviorType != BehaviorType.TargetEntity &&
|
||||
_ui.SelectingTargetFor.Action.BehaviorType != BehaviorType.TargetPoint)) return false;
|
||||
(!_ui.SelectingTargetFor.Action.IsTargetAction)) return false;
|
||||
|
||||
// do nothing if we know it's on cooldown
|
||||
if (_ui.SelectingTargetFor.IsOnCooldown) return false;
|
||||
|
||||
var attempt = _ui.SelectingTargetFor.ActionAttempt();
|
||||
if (attempt == null)
|
||||
@@ -217,6 +219,13 @@ namespace Content.Client.GameObjects.Components.Mobs
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// we are supposed to target an entity but we didn't click it
|
||||
case BehaviorType.TargetEntity when args.EntityUid == EntityUid.Invalid:
|
||||
{
|
||||
if (attempt.Action.DeselectWhenEntityNotClicked)
|
||||
_ui.StopTargeting();
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
_ui.StopTargeting();
|
||||
return false;
|
||||
|
||||
@@ -12,12 +12,6 @@ namespace Content.Client.GameObjects.Components.Mobs
|
||||
[ComponentReference(typeof(SharedStunnableComponent))]
|
||||
public class StunnableComponent : SharedStunnableComponent
|
||||
{
|
||||
protected override void OnInteractHand()
|
||||
{
|
||||
EntitySystem.Get<AudioSystem>()
|
||||
.Play("/Audio/Effects/thudswoosh.ogg", Owner, AudioHelpers.WithVariation(0.25f));
|
||||
}
|
||||
|
||||
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
|
||||
{
|
||||
base.HandleComponentState(curState, nextState);
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
using Content.Shared.GameObjects.Components.Movement;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
using Content.Shared.Utility;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Movement
|
||||
{
|
||||
@@ -7,6 +10,22 @@ namespace Content.Client.GameObjects.Components.Movement
|
||||
[ComponentReference(typeof(IClimbable))]
|
||||
public class ClimbableComponent : SharedClimbableComponent
|
||||
{
|
||||
|
||||
public override bool CanDragDropOn(DragDropEventArgs eventArgs)
|
||||
{
|
||||
if (!base.CanDragDropOn(eventArgs))
|
||||
return false;
|
||||
|
||||
var user = eventArgs.User;
|
||||
var target = eventArgs.Target;
|
||||
var dragged = eventArgs.Dragged;
|
||||
bool Ignored(IEntity entity) => entity == target || entity == user || entity == dragged;
|
||||
|
||||
return user.InRangeUnobstructed(target, Range, predicate: Ignored) && user.InRangeUnobstructed(dragged, Range, predicate: Ignored);
|
||||
}
|
||||
|
||||
public override bool DragDropOn(DragDropEventArgs eventArgs)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using Robust.Shared.GameObjects;
|
||||
namespace Content.Client.GameObjects.Components.Movement
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SharedClimbingComponent))]
|
||||
public class ClimbingComponent : SharedClimbingComponent
|
||||
{
|
||||
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Nutrition
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class BurnStateVisualizer : AppearanceVisualizer
|
||||
{
|
||||
private string _burntIcon = "burnt-icon";
|
||||
private string _litIcon = "lit-icon";
|
||||
private string _unlitIcon = "icon";
|
||||
|
||||
public override void LoadData(YamlMappingNode node)
|
||||
{
|
||||
base.LoadData(node);
|
||||
|
||||
if (node.TryGetNode("unlitIcon", out var unlitIcon))
|
||||
{
|
||||
_unlitIcon = unlitIcon.AsString();
|
||||
}
|
||||
|
||||
if (node.TryGetNode("litIcon", out var litIcon))
|
||||
{
|
||||
_litIcon = litIcon.AsString();
|
||||
}
|
||||
|
||||
if (node.TryGetNode("burntIcon", out var burntIcon))
|
||||
{
|
||||
_burntIcon = burntIcon.AsString();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
|
||||
if (component.TryGetData<SharedBurningStates>(SmokingVisuals.Smoking, out var smoking))
|
||||
{
|
||||
SetState(component, smoking);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetState(AppearanceComponent component, SharedBurningStates burnState)
|
||||
{
|
||||
if (component.Owner.TryGetComponent<ISpriteComponent>(out var sprite))
|
||||
{
|
||||
switch (burnState)
|
||||
{
|
||||
case SharedBurningStates.Lit:
|
||||
sprite.LayerSetState(0, _litIcon);
|
||||
break;
|
||||
case SharedBurningStates.Burnt:
|
||||
sprite.LayerSetState(0, _burntIcon);
|
||||
break;
|
||||
default:
|
||||
sprite.LayerSetState(0, _unlitIcon);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using Content.Client.Eui;
|
||||
using Content.Shared.GameObjects.Components.Medical;
|
||||
using Content.Shared.GameObjects.Components.Observer;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Observer
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class AcceptCloningEui : BaseEui
|
||||
{
|
||||
private readonly AcceptCloningWindow _window;
|
||||
|
||||
public AcceptCloningEui()
|
||||
{
|
||||
_window = new AcceptCloningWindow();
|
||||
|
||||
_window.DenyButton.OnPressed += _ =>
|
||||
{
|
||||
SendMessage(new AcceptCloningChoiceMessage(AcceptCloningUiButton.Deny));
|
||||
_window.Close();
|
||||
};
|
||||
|
||||
_window.AcceptButton.OnPressed += _ =>
|
||||
{
|
||||
SendMessage(new AcceptCloningChoiceMessage(AcceptCloningUiButton.Accept));
|
||||
_window.Close();
|
||||
};
|
||||
}
|
||||
|
||||
public override void Opened()
|
||||
{
|
||||
_window.OpenCentered();
|
||||
}
|
||||
|
||||
public override void Closed()
|
||||
{
|
||||
_window.Close();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
#nullable enable
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.Localization;
|
||||
|
||||
namespace Content.Client.GameObjects.Components
|
||||
namespace Content.Client.GameObjects.Components.Observer
|
||||
{
|
||||
public sealed class AcceptCloningWindow : SS14Window
|
||||
{
|
||||
public readonly Button DenyButton;
|
||||
public readonly Button ConfirmButton;
|
||||
public readonly Button AcceptButton;
|
||||
|
||||
public AcceptCloningWindow()
|
||||
{
|
||||
@@ -23,18 +24,25 @@ namespace Content.Client.GameObjects.Components
|
||||
{
|
||||
Children =
|
||||
{
|
||||
(new Label
|
||||
(new Label()
|
||||
{
|
||||
Text = Loc.GetString("You are being cloned! Transfer your soul to the clone body?")
|
||||
Text = Loc.GetString("You are being cloned!\nTransfer your soul to the clone body?")
|
||||
}),
|
||||
new HBoxContainer
|
||||
{
|
||||
Align = BoxContainer.AlignMode.Center,
|
||||
Children =
|
||||
{
|
||||
(ConfirmButton = new Button
|
||||
(AcceptButton = new Button
|
||||
{
|
||||
Text = Loc.GetString("Yes"),
|
||||
}),
|
||||
|
||||
(new Control()
|
||||
{
|
||||
CustomMinimumSize = (20, 0)
|
||||
}),
|
||||
|
||||
(DenyButton = new Button
|
||||
{
|
||||
Text = Loc.GetString("No"),
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Client.Interfaces.Chat;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Shared.GameObjects.Components.Observer;
|
||||
using Robust.Client.GameObjects;
|
||||
@@ -19,6 +20,7 @@ namespace Content.Client.GameObjects.Components.Observer
|
||||
[Dependency] private readonly IGameHud _gameHud = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IComponentManager _componentManager = default!;
|
||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||
public List<string> WarpNames = new();
|
||||
public Dictionary<EntityUid,string> PlayerNames = new();
|
||||
|
||||
@@ -83,6 +85,7 @@ namespace Content.Client.GameObjects.Components.Observer
|
||||
_gameHud.HandsContainer.AddChild(_gui);
|
||||
SetGhostVisibility(true);
|
||||
_isAttached = true;
|
||||
_chatManager.ToggleDeadChatButtonVisibility(true);
|
||||
|
||||
break;
|
||||
|
||||
@@ -90,6 +93,7 @@ namespace Content.Client.GameObjects.Components.Observer
|
||||
_gui!.Parent?.RemoveChild(_gui);
|
||||
SetGhostVisibility(false);
|
||||
_isAttached = false;
|
||||
_chatManager.ToggleDeadChatButtonVisibility(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#nullable enable
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Client.GameObjects.Components
|
||||
{
|
||||
@@ -9,6 +10,8 @@ namespace Content.Client.GameObjects.Components
|
||||
public class PlaceableSurfaceComponent : SharedPlaceableSurfaceComponent
|
||||
{
|
||||
private bool _isPlaceable;
|
||||
private bool _placeCentered;
|
||||
private Vector2 _positionOffset;
|
||||
|
||||
public override bool IsPlaceable
|
||||
{
|
||||
@@ -22,7 +25,36 @@ namespace Content.Client.GameObjects.Components
|
||||
|
||||
_isPlaceable = value;
|
||||
|
||||
Dirty();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool PlaceCentered
|
||||
{
|
||||
get => _placeCentered;
|
||||
set
|
||||
{
|
||||
if (_placeCentered == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_placeCentered = value;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public override Vector2 PositionOffset
|
||||
{
|
||||
get => _positionOffset;
|
||||
set
|
||||
{
|
||||
if (_positionOffset.EqualsApprox(value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_positionOffset = value;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +68,8 @@ namespace Content.Client.GameObjects.Components
|
||||
}
|
||||
|
||||
_isPlaceable = state.IsPlaceable;
|
||||
_placeCentered = state.PlaceCentered;
|
||||
_positionOffset = state.PositionOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#nullable enable
|
||||
using Content.Shared.GameObjects.Components.Strap;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Strap
|
||||
@@ -8,5 +9,9 @@ namespace Content.Client.GameObjects.Components.Strap
|
||||
[ComponentReference(typeof(SharedStrapComponent))]
|
||||
public class StrapComponent : SharedStrapComponent
|
||||
{
|
||||
public override bool DragDropOn(DragDropEventArgs eventArgs)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,14 +6,11 @@ using Content.Shared.GameObjects.Components.Suspicion;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
using Robust.Client.Interfaces.Graphics.Overlays;
|
||||
using Robust.Client.Interfaces.Input;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
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.Prototypes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Suspicion
|
||||
{
|
||||
@@ -28,6 +25,7 @@ namespace Content.Client.GameObjects.Components.Suspicion
|
||||
private SuspicionGui? _gui;
|
||||
private string? _role;
|
||||
private bool? _antagonist;
|
||||
private bool _overlayActive;
|
||||
|
||||
public string? Role
|
||||
{
|
||||
@@ -67,37 +65,8 @@ namespace Content.Client.GameObjects.Components.Suspicion
|
||||
}
|
||||
}
|
||||
|
||||
public HashSet<EntityUid> Allies { get; } = new();
|
||||
|
||||
private bool AddAlly(EntityUid ally)
|
||||
{
|
||||
if (!Allies.Add(ally))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_overlayManager.TryGetOverlay<TraitorOverlay>(nameof(TraitorOverlay), out var overlay))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return overlay.AddAlly(ally);
|
||||
}
|
||||
|
||||
private bool RemoveAlly(EntityUid ally)
|
||||
{
|
||||
if (!Allies.Remove(ally))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_overlayManager.TryGetOverlay<TraitorOverlay>(nameof(TraitorOverlay), out var overlay))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return overlay.RemoveAlly(ally);
|
||||
}
|
||||
[ViewVariables]
|
||||
public List<(string name, EntityUid uid)> Allies { get; } = new();
|
||||
|
||||
private void AddTraitorOverlay()
|
||||
{
|
||||
@@ -106,12 +75,18 @@ namespace Content.Client.GameObjects.Components.Suspicion
|
||||
return;
|
||||
}
|
||||
|
||||
var overlay = new TraitorOverlay(Owner, Owner.EntityManager, _resourceCache, _eyeManager);
|
||||
_overlayActive = true;
|
||||
var overlay = new TraitorOverlay(Owner.EntityManager, _resourceCache, _eyeManager);
|
||||
_overlayManager.AddOverlay(overlay);
|
||||
}
|
||||
|
||||
private void RemoveTraitorOverlay()
|
||||
{
|
||||
if (!_overlayActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_overlayManager.RemoveOverlay(nameof(TraitorOverlay));
|
||||
}
|
||||
|
||||
@@ -126,6 +101,8 @@ namespace Content.Client.GameObjects.Components.Suspicion
|
||||
|
||||
Role = state.Role;
|
||||
Antagonist = state.Antagonist;
|
||||
Allies.Clear();
|
||||
Allies.AddRange(state.Allies);
|
||||
}
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, IComponent? component)
|
||||
@@ -160,36 +137,6 @@ namespace Content.Client.GameObjects.Components.Suspicion
|
||||
}
|
||||
}
|
||||
|
||||
public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel, ICommonSession? session = null)
|
||||
{
|
||||
base.HandleNetworkMessage(message, netChannel, session);
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case SuspicionAlliesMessage msg:
|
||||
{
|
||||
Allies.Clear();
|
||||
|
||||
foreach (var uid in msg.Allies)
|
||||
{
|
||||
AddAlly(uid);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SuspicionAllyAddedMessage msg:
|
||||
{
|
||||
AddAlly(msg.Ally);
|
||||
break;
|
||||
}
|
||||
case SuspicionAllyRemovedMessage msg:
|
||||
{
|
||||
RemoveAlly(msg.Ally);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnRemove()
|
||||
{
|
||||
base.OnRemove();
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.Graphics.Overlays;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
@@ -18,37 +18,25 @@ namespace Content.Client.GameObjects.Components.Suspicion
|
||||
{
|
||||
private readonly IEntityManager _entityManager;
|
||||
private readonly IEyeManager _eyeManager;
|
||||
private readonly IPlayerManager _playerManager;
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.ScreenSpace;
|
||||
private readonly Font _font;
|
||||
|
||||
private readonly IEntity _user;
|
||||
private readonly HashSet<EntityUid> _allies = new();
|
||||
private readonly string _traitorText = Loc.GetString("Traitor");
|
||||
|
||||
public TraitorOverlay(
|
||||
IEntity user,
|
||||
IEntityManager entityManager,
|
||||
IResourceCache resourceCache,
|
||||
IEyeManager eyeManager)
|
||||
: base(nameof(TraitorOverlay))
|
||||
{
|
||||
_playerManager = IoCManager.Resolve<IPlayerManager>();
|
||||
|
||||
_entityManager = entityManager;
|
||||
_eyeManager = eyeManager;
|
||||
|
||||
_font = new VectorFont(resourceCache.GetResource<FontResource>("/Fonts/NotoSans/NotoSans-Regular.ttf"), 10);
|
||||
|
||||
_user = user;
|
||||
}
|
||||
|
||||
public bool AddAlly(EntityUid ally)
|
||||
{
|
||||
return _allies.Add(ally);
|
||||
}
|
||||
|
||||
public bool RemoveAlly(EntityUid ally)
|
||||
{
|
||||
return _allies.Remove(ally);
|
||||
}
|
||||
|
||||
protected override void Draw(DrawingHandleBase handle, OverlaySpace currentSpace)
|
||||
@@ -65,23 +53,29 @@ namespace Content.Client.GameObjects.Components.Suspicion
|
||||
{
|
||||
var viewport = _eyeManager.GetWorldViewport();
|
||||
|
||||
foreach (var uid in _allies)
|
||||
var ent = _playerManager.LocalPlayer?.ControlledEntity;
|
||||
if (ent == null || ent.TryGetComponent(out SuspicionRoleComponent sus) != true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var (_, uid) in sus.Allies)
|
||||
{
|
||||
// Otherwise the entity can not exist yet
|
||||
if (!_entityManager.TryGetEntity(uid, out var ally))
|
||||
{
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ally.TryGetComponent(out IPhysicsComponent physics))
|
||||
{
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ExamineSystemShared.InRangeUnOccluded(_user.Transform.MapPosition, ally.Transform.MapPosition, 15,
|
||||
entity => entity == _user || entity == ally))
|
||||
if (!ExamineSystemShared.InRangeUnOccluded(ent.Transform.MapPosition, ally.Transform.MapPosition, 15,
|
||||
entity => entity == ent || entity == ally))
|
||||
{
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
// all entities have a TransformComponent
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#nullable enable
|
||||
using Content.Shared.GameObjects.Components.Watercloset;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Watercloset
|
||||
{
|
||||
public class ToiletVisualizer : AppearanceVisualizer
|
||||
{
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
|
||||
if (!component.Owner.TryGetComponent(out ISpriteComponent? sprite)) return;
|
||||
|
||||
if (!component.TryGetData(ToiletVisuals.LidOpen, out bool lidOpen)) lidOpen = false;
|
||||
if (!component.TryGetData(ToiletVisuals.SeatUp, out bool seatUp)) seatUp = false;
|
||||
|
||||
var state = string.Format("{0}_toilet_{1}",
|
||||
lidOpen ? "open" : "closed",
|
||||
seatUp ? "seat_up" : "seat_down");
|
||||
|
||||
sprite.LayerSetState(0, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
|
||||
namespace Content.Client.GameObjects.EntitySystems.NewFolder
|
||||
{
|
||||
public class ChemicalReactionSystem : SharedChemicalReactionSystem
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -149,6 +149,16 @@ namespace Content.Client.GameObjects.EntitySystems.DoAfter
|
||||
if (doAfters.Count == 0)
|
||||
return;
|
||||
|
||||
if (_eyeManager.CurrentMap != AttachedEntity.Transform.MapID)
|
||||
{
|
||||
Visible = false;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Visible = true;
|
||||
}
|
||||
|
||||
// Set position ready for 2nd+ frames.
|
||||
var screenCoordinates = _eyeManager.CoordinatesToScreen(AttachedEntity.Transform.Coordinates);
|
||||
_playerPosition = new ScreenCoordinates(screenCoordinates.X / UIScale, screenCoordinates.Y / UIScale);
|
||||
|
||||
@@ -1,24 +1,32 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Client.State;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared.GameObjects;
|
||||
using Content.Shared.GameObjects.EntitySystemMessages;
|
||||
using Content.Shared.GameObjects.EntitySystems;
|
||||
using Content.Shared.Interfaces;
|
||||
using Content.Shared.Interfaces.GameObjects.Components;
|
||||
using Content.Shared.Utility;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.GameObjects.EntitySystems;
|
||||
using Robust.Client.Graphics.Shaders;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
using Robust.Client.Interfaces.Input;
|
||||
using Robust.Client.Interfaces.State;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Prototypes;
|
||||
using DrawDepth = Content.Shared.GameObjects.DrawDepth;
|
||||
|
||||
namespace Content.Client.GameObjects.EntitySystems
|
||||
{
|
||||
@@ -29,7 +37,9 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
public class DragDropSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IStateManager _stateManager = default!;
|
||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
// how often to recheck possible targets (prevents calling expensive
|
||||
@@ -45,9 +55,11 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
private const string ShaderDropTargetOutOfRange = "SelectionOutline";
|
||||
|
||||
// entity performing the drag action
|
||||
private IEntity _dragger;
|
||||
|
||||
private IEntity? _dragger;
|
||||
private readonly List<IDraggable> _draggables = new();
|
||||
private IEntity _dragShadow;
|
||||
private IEntity? _dragShadow;
|
||||
|
||||
// time since mouse down over the dragged entity
|
||||
private float _mouseDownTime;
|
||||
// how much time since last recheck of all possible targets
|
||||
@@ -58,14 +70,14 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
// can ignore any events sent to this system
|
||||
private bool _isReplaying;
|
||||
|
||||
private DragDropHelper<IEntity> _dragDropHelper;
|
||||
private DragDropHelper<IEntity> _dragDropHelper = default!;
|
||||
|
||||
private ShaderInstance _dropTargetInRangeShader;
|
||||
private ShaderInstance _dropTargetOutOfRangeShader;
|
||||
private SharedInteractionSystem _interactionSystem;
|
||||
private InputSystem _inputSystem;
|
||||
private ShaderInstance? _dropTargetInRangeShader;
|
||||
private ShaderInstance? _dropTargetOutOfRangeShader;
|
||||
private SharedInteractionSystem _interactionSystem = default!;
|
||||
private InputSystem _inputSystem = default!;
|
||||
|
||||
private readonly List<SpriteComponent> _highlightedSprites = new();
|
||||
private readonly List<ISpriteComponent> _highlightedSprites = new();
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -112,7 +124,7 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
|
||||
private bool OnUseMouseDown(in PointerInputCmdHandler.PointerInputCmdArgs args)
|
||||
{
|
||||
var dragger = args.Session.AttachedEntity;
|
||||
var dragger = args.Session?.AttachedEntity;
|
||||
// cancel any current dragging if there is one (shouldn't be because they would've had to have lifted
|
||||
// the mouse, canceling the drag, but just being cautious)
|
||||
_dragDropHelper.EndDrag();
|
||||
@@ -130,7 +142,7 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
var canDrag = false;
|
||||
foreach (var draggable in entity.GetAllComponents<IDraggable>())
|
||||
{
|
||||
var dragEventArgs = new StartDragDropEventArgs(args.Session.AttachedEntity, entity);
|
||||
var dragEventArgs = new StartDragDropEventArgs(dragger, entity);
|
||||
if (draggable.CanStartDrag(dragEventArgs))
|
||||
{
|
||||
_draggables.Add(draggable);
|
||||
@@ -156,7 +168,6 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private bool OnBeginDrag()
|
||||
{
|
||||
if (_dragDropHelper.Dragged == null || _dragDropHelper.Dragged.Deleted)
|
||||
@@ -183,6 +194,7 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
}
|
||||
|
||||
HighlightTargets();
|
||||
EntityManager.EventBus.RaiseEvent(EventSource.Local, new OutlineToggleMessage(false));
|
||||
|
||||
// drag initiated
|
||||
return true;
|
||||
@@ -209,6 +221,9 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
var mousePos = _eyeManager.ScreenToMap(_dragDropHelper.MouseScreenPosition);
|
||||
// TODO: would use MapPosition instead if it had a setter, but it has no setter.
|
||||
// is that intentional, or should we add a setter for Transform.MapPosition?
|
||||
if (_dragShadow == null)
|
||||
return false;
|
||||
|
||||
_dragShadow.Transform.WorldPosition = mousePos.Position;
|
||||
|
||||
_targetRecheckTime += frameTime;
|
||||
@@ -229,6 +244,7 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
EntityManager.DeleteEntity(_dragShadow);
|
||||
}
|
||||
|
||||
EntityManager.EventBus.RaiseEvent(EventSource.Local, new OutlineToggleMessage(true));
|
||||
_dragShadow = null;
|
||||
_draggables.Clear();
|
||||
_dragger = null;
|
||||
@@ -238,7 +254,7 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
|
||||
private bool OnUseMouseUp(in PointerInputCmdHandler.PointerInputCmdArgs args)
|
||||
{
|
||||
if (!_dragDropHelper.IsDragging)
|
||||
if (_dragDropHelper.IsDragging == false)
|
||||
{
|
||||
// haven't started the drag yet, quick mouseup, definitely treat it as a normal click by
|
||||
// replaying the original cmd
|
||||
@@ -251,40 +267,68 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
var adjustedInputMsg = new FullInputCmdMessage(args.OriginalMessage.Tick, args.OriginalMessage.SubTick,
|
||||
replayMsg.InputFunctionId, replayMsg.State, replayMsg.Coordinates, replayMsg.ScreenCoordinates, replayMsg.Uid);
|
||||
|
||||
_inputSystem.HandleInputCommand(savedValue.Session, EngineKeyFunctions.Use,
|
||||
adjustedInputMsg, true);
|
||||
if (savedValue.Session != null)
|
||||
{
|
||||
_inputSystem.HandleInputCommand(savedValue.Session, EngineKeyFunctions.Use, adjustedInputMsg, true);
|
||||
}
|
||||
|
||||
_isReplaying = false;
|
||||
}
|
||||
_dragDropHelper.EndDrag();
|
||||
return false;
|
||||
}
|
||||
|
||||
// now when ending the drag, we will not replay the click because
|
||||
// by this time we've determined the input was actually a drag attempt
|
||||
if (_dragger == null)
|
||||
{
|
||||
_dragDropHelper.EndDrag();
|
||||
return false;
|
||||
}
|
||||
|
||||
// now when ending the drag, we will not replay the click because
|
||||
// by this time we've determined the input was actually a drag attempt
|
||||
var range = (args.Coordinates.ToMapPos(EntityManager) - _dragger.Transform.MapPosition.Position).Length + 0.01f;
|
||||
// tell the server we are dropping if we are over a valid drop target in range.
|
||||
// We don't use args.EntityUid here because drag interactions generally should
|
||||
// work even if there's something "on top" of the drop target
|
||||
if (!_interactionSystem.InRangeUnobstructed(_dragger,
|
||||
args.Coordinates, ignoreInsideBlocker: true))
|
||||
args.Coordinates, range, ignoreInsideBlocker: true))
|
||||
{
|
||||
_dragDropHelper.EndDrag();
|
||||
return false;
|
||||
}
|
||||
|
||||
var entities = GameScreenBase.GetEntitiesUnderPosition(_stateManager, args.Coordinates);
|
||||
var outOfRange = false;
|
||||
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
// check if it's able to be dropped on by current dragged entity
|
||||
var dropArgs = new DragDropEventArgs(_dragger, args.Coordinates, _dragDropHelper.Dragged, entity);
|
||||
var valid = true;
|
||||
var anyDragDrop = false;
|
||||
var dragDropOn = new List<IDragDropOn>();
|
||||
|
||||
foreach (var comp in entity.GetAllComponents<IDragDropOn>())
|
||||
{
|
||||
anyDragDrop = true;
|
||||
|
||||
if (!comp.CanDragDropOn(dropArgs))
|
||||
{
|
||||
valid = false;
|
||||
dragDropOn.Add(comp);
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid || !anyDragDrop) continue;
|
||||
if (!dropArgs.InRangeUnobstructed(ignoreInsideBlocker: true))
|
||||
{
|
||||
outOfRange = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var draggable in _draggables)
|
||||
{
|
||||
if (!draggable.CanDrop(dropArgs))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!draggable.CanDrop(dropArgs)) continue;
|
||||
|
||||
// tell the server about the drop attempt
|
||||
RaiseNetworkEvent(new DragDropMessage(args.Coordinates, _dragDropHelper.Dragged.Uid,
|
||||
@@ -292,11 +336,22 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
|
||||
draggable.Drop(dropArgs);
|
||||
|
||||
// Don't fail if it isn't handled as server may do something with it
|
||||
foreach (var comp in dragDropOn)
|
||||
{
|
||||
if (!comp.DragDropOn(dropArgs)) continue;
|
||||
}
|
||||
|
||||
_dragDropHelper.EndDrag();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (outOfRange)
|
||||
{
|
||||
_playerManager.LocalPlayer?.ControlledEntity?.PopupMessage(Loc.GetString("You can't reach there!"));
|
||||
}
|
||||
|
||||
_dragDropHelper.EndDrag();
|
||||
return false;
|
||||
}
|
||||
@@ -304,7 +359,9 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
private void HighlightTargets()
|
||||
{
|
||||
if (_dragDropHelper.Dragged == null ||
|
||||
_dragDropHelper.Dragged.Deleted || _dragShadow == null || _dragShadow.Deleted)
|
||||
_dragDropHelper.Dragged.Deleted ||
|
||||
_dragShadow == null ||
|
||||
_dragShadow.Deleted)
|
||||
{
|
||||
Logger.Warning("Programming error. Can't highlight drag and drop targets, not currently " +
|
||||
"dragging anything or dragged entity / shadow was deleted.");
|
||||
@@ -319,28 +376,42 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
|
||||
// find possible targets on screen even if not reachable
|
||||
// TODO: Duplicated in SpriteSystem
|
||||
var pvsBounds = _eyeManager.GetWorldViewport().Enlarged(5);
|
||||
var pvsEntities = EntityManager.GetEntitiesIntersecting(_eyeManager.CurrentMap, pvsBounds, true);
|
||||
var mousePos = _eyeManager.ScreenToMap(_inputManager.MouseScreenPosition).Position;
|
||||
var bounds = new Box2(mousePos - 1.5f, mousePos + 1.5f);
|
||||
var pvsEntities = EntityManager.GetEntitiesIntersecting(_eyeManager.CurrentMap, bounds, true);
|
||||
foreach (var pvsEntity in pvsEntities)
|
||||
{
|
||||
if (pvsEntity.TryGetComponent<SpriteComponent>(out var inRangeSprite))
|
||||
if (!pvsEntity.TryGetComponent(out ISpriteComponent? inRangeSprite)) continue;
|
||||
|
||||
// can't highlight if there's no sprite or it's not visible
|
||||
if (inRangeSprite.Visible == false) continue;
|
||||
|
||||
var valid = (bool?) null;
|
||||
// check if it's able to be dropped on by current dragged entity
|
||||
var dropArgs = new DragDropEventArgs(_dragger, pvsEntity.Transform.Coordinates, _dragDropHelper.Dragged, pvsEntity);
|
||||
|
||||
foreach (var comp in pvsEntity.GetAllComponents<IDragDropOn>())
|
||||
{
|
||||
// can't highlight if there's no sprite or it's not visible
|
||||
if (inRangeSprite.Visible == false) continue;
|
||||
valid = comp.CanDragDropOn(dropArgs);
|
||||
|
||||
// check if it's able to be dropped on by current dragged entity
|
||||
var canDropArgs = new CanDropEventArgs(_dragger, _dragDropHelper.Dragged, pvsEntity);
|
||||
var anyValidDraggable = _draggables.Any(draggable => draggable.CanDrop(canDropArgs));
|
||||
|
||||
if (anyValidDraggable)
|
||||
{
|
||||
// highlight depending on whether its in or out of range
|
||||
var inRange = _interactionSystem.InRangeUnobstructed(_dragger, pvsEntity);
|
||||
inRangeSprite.PostShader = inRange ? _dropTargetInRangeShader : _dropTargetOutOfRangeShader;
|
||||
inRangeSprite.RenderOrder = EntityManager.CurrentTick.Value;
|
||||
_highlightedSprites.Add(inRangeSprite);
|
||||
}
|
||||
if (valid.Value)
|
||||
break;
|
||||
}
|
||||
|
||||
// Can't do anything so no highlight
|
||||
if (!valid.HasValue)
|
||||
continue;
|
||||
|
||||
// We'll do a final check given server-side does this before any dragdrop can take place.
|
||||
if (valid.Value)
|
||||
{
|
||||
valid = dropArgs.InRangeUnobstructed(ignoreInsideBlocker: true);
|
||||
}
|
||||
|
||||
// highlight depending on whether its in or out of range
|
||||
inRangeSprite.PostShader = valid.Value ? _dropTargetInRangeShader : _dropTargetOutOfRangeShader;
|
||||
inRangeSprite.RenderOrder = EntityManager.CurrentTick.Value;
|
||||
_highlightedSprites.Add(inRangeSprite);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -351,6 +422,7 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
highlightedSprite.PostShader = null;
|
||||
highlightedSprite.RenderOrder = 0;
|
||||
}
|
||||
|
||||
_highlightedSprites.Clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeNetworkEvent<PlayMeleeWeaponAnimationMessage>(PlayWeaponArc);
|
||||
SubscribeNetworkEvent<PlayLungeAnimationMessage>(PlayLunge);
|
||||
}
|
||||
|
||||
public override void FrameUpdate(float frameTime)
|
||||
@@ -50,39 +51,42 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
|
||||
var attacker = EntityManager.GetEntity(msg.Attacker);
|
||||
|
||||
var lunge = attacker.EnsureComponent<MeleeLungeComponent>();
|
||||
lunge.SetData(msg.Angle);
|
||||
|
||||
var entity = EntityManager.SpawnEntity(weaponArc.Prototype, attacker.Transform.Coordinates);
|
||||
entity.Transform.LocalRotation = msg.Angle;
|
||||
|
||||
var weaponArcAnimation = entity.GetComponent<MeleeWeaponArcAnimationComponent>();
|
||||
weaponArcAnimation.SetData(weaponArc, msg.Angle, attacker, msg.ArcFollowAttacker);
|
||||
|
||||
// Due to ISpriteComponent limitations, weapons that don't use an RSI won't have this effect.
|
||||
if (EntityManager.TryGetEntity(msg.Source, out var source) && msg.TextureEffect && source.TryGetComponent(out ISpriteComponent sourceSprite)
|
||||
&& sourceSprite.BaseRSI?.Path != null)
|
||||
if (!attacker.Deleted)
|
||||
{
|
||||
var sys = Get<EffectSystem>();
|
||||
var curTime = _gameTiming.CurTime;
|
||||
var effect = new EffectSystemMessage
|
||||
var lunge = attacker.EnsureComponent<MeleeLungeComponent>();
|
||||
lunge.SetData(msg.Angle);
|
||||
|
||||
var entity = EntityManager.SpawnEntity(weaponArc.Prototype, attacker.Transform.Coordinates);
|
||||
entity.Transform.LocalRotation = msg.Angle;
|
||||
|
||||
var weaponArcAnimation = entity.GetComponent<MeleeWeaponArcAnimationComponent>();
|
||||
weaponArcAnimation.SetData(weaponArc, msg.Angle, attacker, msg.ArcFollowAttacker);
|
||||
|
||||
// Due to ISpriteComponent limitations, weapons that don't use an RSI won't have this effect.
|
||||
if (EntityManager.TryGetEntity(msg.Source, out var source) && msg.TextureEffect && source.TryGetComponent(out ISpriteComponent sourceSprite)
|
||||
&& sourceSprite.BaseRSI?.Path != null)
|
||||
{
|
||||
EffectSprite = sourceSprite.BaseRSI.Path.ToString(),
|
||||
RsiState = sourceSprite.LayerGetState(0).Name,
|
||||
Coordinates = attacker.Transform.Coordinates,
|
||||
Color = Vector4.Multiply(new Vector4(255, 255, 255, 125), 1.0f),
|
||||
ColorDelta = Vector4.Multiply(new Vector4(0, 0, 0, -10), 1.0f),
|
||||
Velocity = msg.Angle.ToVec(),
|
||||
Acceleration = msg.Angle.ToVec() * 5f,
|
||||
Born = curTime,
|
||||
DeathTime = curTime.Add(TimeSpan.FromMilliseconds(300f)),
|
||||
};
|
||||
sys.CreateEffect(effect);
|
||||
var sys = Get<EffectSystem>();
|
||||
var curTime = _gameTiming.CurTime;
|
||||
var effect = new EffectSystemMessage
|
||||
{
|
||||
EffectSprite = sourceSprite.BaseRSI.Path.ToString(),
|
||||
RsiState = sourceSprite.LayerGetState(0).Name,
|
||||
Coordinates = attacker.Transform.Coordinates,
|
||||
Color = Vector4.Multiply(new Vector4(255, 255, 255, 125), 1.0f),
|
||||
ColorDelta = Vector4.Multiply(new Vector4(0, 0, 0, -10), 1.0f),
|
||||
Velocity = msg.Angle.ToVec(),
|
||||
Acceleration = msg.Angle.ToVec() * 5f,
|
||||
Born = curTime,
|
||||
DeathTime = curTime.Add(TimeSpan.FromMilliseconds(300f)),
|
||||
};
|
||||
sys.CreateEffect(effect);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var uid in msg.Hits)
|
||||
{
|
||||
if (!EntityManager.TryGetEntity(uid, out var hitEntity))
|
||||
if (!EntityManager.TryGetEntity(uid, out var hitEntity) || hitEntity.Deleted)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -106,5 +110,13 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void PlayLunge(PlayLungeAnimationMessage msg)
|
||||
{
|
||||
EntityManager
|
||||
.GetEntity(msg.Source)
|
||||
.EnsureComponent<MeleeLungeComponent>()
|
||||
.SetData(msg.Angle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using Content.Client.Interfaces;
|
||||
using Content.Client.State;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Shared;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Network.NetMessages;
|
||||
using Robust.Client.Interfaces.Graphics;
|
||||
@@ -11,6 +10,7 @@ using Robust.Client.Interfaces.State;
|
||||
using Robust.Shared.Interfaces.Network;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Content.Client.GameTicking
|
||||
[ViewVariables] public bool IsGameStarted { get; private set; }
|
||||
[ViewVariables] public bool DisallowedLateJoin { get; private set; }
|
||||
[ViewVariables] public string ServerInfoBlob { get; private set; }
|
||||
[ViewVariables] public DateTime StartTime { get; private set; }
|
||||
[ViewVariables] public TimeSpan StartTime { get; private set; }
|
||||
[ViewVariables] public bool Paused { get; private set; }
|
||||
[ViewVariables] public Dictionary<NetUserId, PlayerStatus> Status { get; private set; }
|
||||
[ViewVariables] public IReadOnlyList<string> JobsAvailable => _jobsAvailable;
|
||||
|
||||
@@ -169,6 +169,9 @@ namespace Content.Client
|
||||
"Flammable",
|
||||
"CreamPie",
|
||||
"CreamPied",
|
||||
"Smoking",
|
||||
"Matchstick",
|
||||
"Matchbox",
|
||||
"BlockGameArcade",
|
||||
"KitchenSpike",
|
||||
"Butcherable",
|
||||
@@ -228,7 +231,15 @@ namespace Content.Client
|
||||
"BiologicalSurgeryData",
|
||||
"CargoTelepad",
|
||||
"TraitorDeathMatchRedemption",
|
||||
"GlassBeaker"
|
||||
"GlassBeaker",
|
||||
"SliceableFood",
|
||||
"DamageOtherOnHit",
|
||||
"DamageOnLand",
|
||||
"GasFilter",
|
||||
"Recyclable",
|
||||
"SecretStash",
|
||||
"Toilet",
|
||||
"ClusterFlash"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,5 +13,7 @@ namespace Content.Client.Interfaces.Chat
|
||||
void SetChatBox(ChatBox chatBox);
|
||||
|
||||
void RemoveSpeechBubble(EntityUid entityUid, SpeechBubble bubble);
|
||||
|
||||
void ToggleDeadChatButtonVisibility(bool visibility);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Timing;
|
||||
using static Content.Shared.GameTicking.SharedGameTicker;
|
||||
|
||||
namespace Content.Client.Interfaces
|
||||
@@ -11,7 +12,7 @@ namespace Content.Client.Interfaces
|
||||
string ServerInfoBlob { get; }
|
||||
bool AreWeReady { get; }
|
||||
bool DisallowedLateJoin { get; }
|
||||
DateTime StartTime { get; }
|
||||
TimeSpan StartTime { get; }
|
||||
bool Paused { get; }
|
||||
Dictionary<NetUserId, PlayerStatus> Status { get; }
|
||||
IReadOnlyList<string> JobsAvailable { get; }
|
||||
|
||||
@@ -33,10 +33,12 @@ namespace Content.Client.Sandbox
|
||||
public readonly Button ShowMarkersButton; //Shows spawn points
|
||||
public readonly Button ShowBbButton; //Shows bounding boxes
|
||||
public readonly Button MachineLinkingButton; // Enables/disables machine linking mode.
|
||||
private readonly IGameHud _gameHud;
|
||||
|
||||
public SandboxWindow()
|
||||
{
|
||||
Resizable = false;
|
||||
_gameHud = IoCManager.Resolve<IGameHud>();
|
||||
|
||||
Title = "Sandbox Panel";
|
||||
|
||||
@@ -82,6 +84,20 @@ namespace Content.Client.Sandbox
|
||||
MachineLinkingButton = new Button { Text = Loc.GetString("Link machines"), ToggleMode = true };
|
||||
vBox.AddChild(MachineLinkingButton);
|
||||
}
|
||||
|
||||
|
||||
protected override void EnteredTree()
|
||||
{
|
||||
base.EnteredTree();
|
||||
_gameHud.SandboxButtonDown = true;
|
||||
}
|
||||
|
||||
protected override void ExitedTree()
|
||||
{
|
||||
base.ExitedTree();
|
||||
_gameHud.SandboxButtonDown = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal class SandboxManager : SharedSandboxManager, ISandboxManager
|
||||
@@ -197,7 +213,6 @@ namespace Content.Client.Sandbox
|
||||
private void WindowOnOnClose()
|
||||
{
|
||||
_window = null;
|
||||
_gameHud.SandboxButtonDown = false;
|
||||
_sandboxWindowToggled = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Content.Client.State
|
||||
// OH GOD.
|
||||
// Ok actually it's fine.
|
||||
// Instantiated dynamically through the StateManager, Dependencies will be resolved.
|
||||
public partial class GameScreenBase : Robust.Client.State.State
|
||||
public partial class GameScreenBase : Robust.Client.State.State, IEntityEventSubscriber
|
||||
{
|
||||
[Dependency] protected readonly IClientEntityManager EntityManager = default!;
|
||||
[Dependency] protected readonly IInputManager InputManager = default!;
|
||||
@@ -38,17 +38,29 @@ namespace Content.Client.State
|
||||
[Dependency] protected readonly IMapManager MapManager = default!;
|
||||
[Dependency] protected readonly IUserInterfaceManager UserInterfaceManager = default!;
|
||||
[Dependency] protected readonly IConfigurationManager ConfigurationManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
private IEventBus _eventBus => _entityManager.EventBus;
|
||||
|
||||
private IEntity _lastHoveredEntity;
|
||||
|
||||
private bool _outlineEnabled = true;
|
||||
|
||||
public override void Startup()
|
||||
{
|
||||
InputManager.KeyBindStateChanged += OnKeyBindStateChanged;
|
||||
_eventBus.SubscribeEvent<OutlineToggleMessage>(EventSource.Local, this, HandleOutlineToggle);
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
InputManager.KeyBindStateChanged -= OnKeyBindStateChanged;
|
||||
_eventBus.UnsubscribeEvent<OutlineToggleMessage>(EventSource.Local, this);
|
||||
}
|
||||
|
||||
private void HandleOutlineToggle(OutlineToggleMessage message)
|
||||
{
|
||||
_outlineEnabled = message.Enabled;
|
||||
}
|
||||
|
||||
public override void FrameUpdate(FrameEventArgs e)
|
||||
@@ -72,7 +84,7 @@ namespace Content.Client.State
|
||||
}
|
||||
|
||||
InteractionOutlineComponent outline;
|
||||
if(!ConfigurationManager.GetCVar(CCVars.OutlineEnabled))
|
||||
if(!_outlineEnabled || !ConfigurationManager.GetCVar(CCVars.OutlineEnabled))
|
||||
{
|
||||
if(entityToClick != null && entityToClick.TryGetComponent(out outline))
|
||||
{
|
||||
|
||||
@@ -13,6 +13,7 @@ using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -35,6 +36,7 @@ namespace Content.Client.State
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
|
||||
[Dependency] private readonly IClientPreferencesManager _preferencesManager = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
|
||||
[ViewVariables] private CharacterSetupGui _characterSetup;
|
||||
[ViewVariables] private LobbyGui _lobby;
|
||||
@@ -70,6 +72,12 @@ namespace Content.Client.State
|
||||
_inputManager.SetInputCommand(ContentKeyFunctions.FocusChat,
|
||||
InputCmdHandler.FromDelegate(s => GameScreen.FocusChat(_lobby.Chat)));
|
||||
|
||||
_inputManager.SetInputCommand(ContentKeyFunctions.FocusOOC,
|
||||
InputCmdHandler.FromDelegate(s => GameScreen.FocusOOC(_lobby.Chat)));
|
||||
|
||||
_inputManager.SetInputCommand(ContentKeyFunctions.FocusAdminChat,
|
||||
InputCmdHandler.FromDelegate(s => GameScreen.FocusAdminChat(_lobby.Chat)));
|
||||
|
||||
UpdateLobbyUi();
|
||||
|
||||
_lobby.CharacterPreview.CharacterSetupButton.OnPressed += args =>
|
||||
@@ -138,10 +146,11 @@ namespace Content.Client.State
|
||||
}
|
||||
else
|
||||
{
|
||||
var difference = _clientGameTicker.StartTime - DateTime.UtcNow;
|
||||
if (difference.Ticks < 0)
|
||||
var difference = _clientGameTicker.StartTime - _gameTiming.CurTime;
|
||||
var seconds = difference.TotalSeconds;
|
||||
if (seconds < 0)
|
||||
{
|
||||
if (difference.TotalSeconds < -5)
|
||||
if (seconds < -5)
|
||||
{
|
||||
text = Loc.GetString("Right Now?");
|
||||
}
|
||||
@@ -152,7 +161,7 @@ namespace Content.Client.State
|
||||
}
|
||||
else
|
||||
{
|
||||
text = $"{(int) Math.Floor(difference.TotalMinutes)}:{difference.Seconds:D2}";
|
||||
text = $"{(int) Math.Floor(difference.TotalMinutes / 60)}:{difference.Seconds:D2}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,8 +181,10 @@ namespace Content.Client.State
|
||||
_clientGameTicker.Status.Remove(p.Key);
|
||||
}
|
||||
}
|
||||
|
||||
UpdatePlayerList();
|
||||
}
|
||||
|
||||
private void LobbyReadyUpdated() => UpdatePlayerList();
|
||||
|
||||
private void LobbyStatusUpdated()
|
||||
@@ -218,8 +229,6 @@ namespace Content.Client.State
|
||||
|
||||
foreach (var session in _playerManager.Sessions.OrderBy(s => s.Name))
|
||||
{
|
||||
|
||||
|
||||
var readyState = "";
|
||||
// Don't show ready state if we're ingame
|
||||
if (!_clientGameTicker.IsGameStarted)
|
||||
@@ -238,6 +247,7 @@ namespace Content.Client.State
|
||||
_ => "",
|
||||
};
|
||||
}
|
||||
|
||||
_lobby.OnlinePlayerList.AddItem(session.Name, readyState);
|
||||
}
|
||||
}
|
||||
|
||||
14
Content.Client/State/OutlineToggleMessage.cs
Normal file
14
Content.Client/State/OutlineToggleMessage.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Client.State
|
||||
{
|
||||
public sealed class OutlineToggleMessage : EntitySystemMessage
|
||||
{
|
||||
public bool Enabled { get; }
|
||||
|
||||
public OutlineToggleMessage(bool enabled)
|
||||
{
|
||||
Enabled = enabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,7 @@ namespace Content.Client.UserInterface
|
||||
private readonly Button _clearButton;
|
||||
private readonly GridContainer _resultsGrid;
|
||||
private readonly TextureRect _dragShadow;
|
||||
private readonly IGameHud _gameHud;
|
||||
private readonly DragDropHelper<ActionMenuItem> _dragDropHelper;
|
||||
|
||||
|
||||
@@ -64,6 +65,8 @@ namespace Content.Client.UserInterface
|
||||
_actionsComponent = actionsComponent;
|
||||
_actionsUI = actionsUI;
|
||||
_actionManager = IoCManager.Resolve<ActionManager>();
|
||||
_gameHud = IoCManager.Resolve<IGameHud>();
|
||||
|
||||
Title = Loc.GetString("Actions");
|
||||
CustomMinimumSize = (300, 300);
|
||||
|
||||
@@ -143,14 +146,13 @@ namespace Content.Client.UserInterface
|
||||
_dragDropHelper = new DragDropHelper<ActionMenuItem>(OnBeginActionDrag, OnContinueActionDrag, OnEndActionDrag);
|
||||
}
|
||||
|
||||
|
||||
protected override void EnteredTree()
|
||||
{
|
||||
base.EnteredTree();
|
||||
_clearButton.OnPressed += OnClearButtonPressed;
|
||||
_searchBar.OnTextChanged += OnSearchTextChanged;
|
||||
_filterButton.OnItemSelected += OnFilterItemSelected;
|
||||
|
||||
_gameHud.ActionsButtonDown = true;
|
||||
foreach (var actionMenuControl in _resultsGrid.Children)
|
||||
{
|
||||
var actionMenuItem = (actionMenuControl as ActionMenuItem);
|
||||
@@ -167,7 +169,7 @@ namespace Content.Client.UserInterface
|
||||
_clearButton.OnPressed -= OnClearButtonPressed;
|
||||
_searchBar.OnTextChanged -= OnSearchTextChanged;
|
||||
_filterButton.OnItemSelected -= OnFilterItemSelected;
|
||||
|
||||
_gameHud.ActionsButtonDown = false;
|
||||
foreach (var actionMenuControl in _resultsGrid.Children)
|
||||
{
|
||||
var actionMenuItem = (actionMenuControl as ActionMenuItem);
|
||||
@@ -280,6 +282,12 @@ namespace Content.Client.UserInterface
|
||||
_dragDropHelper.EndDrag();
|
||||
}
|
||||
|
||||
private void OnItemFocusExited(ActionMenuItem item)
|
||||
{
|
||||
// lost focus, cancel the drag if one is in progress
|
||||
_dragDropHelper.EndDrag();
|
||||
}
|
||||
|
||||
private void OnItemPressed(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
if (args.Button is not ActionMenuItem actionMenuItem) return;
|
||||
@@ -402,8 +410,7 @@ namespace Content.Client.UserInterface
|
||||
ItemTag => action is ItemActionPrototype,
|
||||
NotItemTag => action is ActionPrototype,
|
||||
InstantActionTag => action.BehaviorType == BehaviorType.Instant,
|
||||
TargetActionTag => action.BehaviorType == BehaviorType.TargetEntity ||
|
||||
action.BehaviorType == BehaviorType.TargetPoint,
|
||||
TargetActionTag => action.IsTargetAction,
|
||||
ToggleActionTag => action.BehaviorType == BehaviorType.Toggle,
|
||||
_ => action.Filters.Contains(tag)
|
||||
};
|
||||
@@ -462,10 +469,9 @@ namespace Content.Client.UserInterface
|
||||
_actionList = actions.ToArray();
|
||||
foreach (var action in _actionList.OrderBy(act => act.Name.ToString()))
|
||||
{
|
||||
var actionItem = new ActionMenuItem(action);
|
||||
var actionItem = new ActionMenuItem(action, OnItemFocusExited);
|
||||
_resultsGrid.Children.Add(actionItem);
|
||||
actionItem.SetActionState(_actionsComponent.IsGranted(action));
|
||||
|
||||
actionItem.OnButtonDown += OnItemButtonDown;
|
||||
actionItem.OnButtonUp += OnItemButtonUp;
|
||||
actionItem.OnPressed += OnItemPressed;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using Content.Client.GameObjects.Components.Mobs;
|
||||
using Content.Client.UserInterface.Stylesheets;
|
||||
using Content.Shared.Actions;
|
||||
using Robust.Client.UserInterface;
|
||||
@@ -19,8 +21,11 @@ namespace Content.Client.UserInterface
|
||||
|
||||
public BaseActionPrototype Action { get; private set; }
|
||||
|
||||
public ActionMenuItem(BaseActionPrototype action)
|
||||
private Action<ActionMenuItem> _onControlFocusExited;
|
||||
|
||||
public ActionMenuItem(BaseActionPrototype action, Action<ActionMenuItem> onControlFocusExited)
|
||||
{
|
||||
_onControlFocusExited = onControlFocusExited;
|
||||
Action = action;
|
||||
|
||||
CustomMinimumSize = (64, 64);
|
||||
@@ -38,6 +43,12 @@ namespace Content.Client.UserInterface
|
||||
TooltipSupplier = SupplyTooltip;
|
||||
}
|
||||
|
||||
protected override void ControlFocusExited()
|
||||
{
|
||||
base.ControlFocusExited();
|
||||
_onControlFocusExited.Invoke(this);
|
||||
}
|
||||
|
||||
private Control SupplyTooltip(Control? sender)
|
||||
{
|
||||
return new ActionAlertTooltip(Action.Name, Action.Description, Action.Requires);
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace Content.Client.UserInterface
|
||||
private readonly ActionManager _actionManager;
|
||||
private readonly IEntityManager _entityManager;
|
||||
private readonly IGameTiming _gameTiming;
|
||||
private readonly IGameHud _gameHud;
|
||||
|
||||
private readonly ActionSlot[] _slots;
|
||||
|
||||
@@ -80,13 +81,15 @@ namespace Content.Client.UserInterface
|
||||
_actionManager = IoCManager.Resolve<ActionManager>();
|
||||
_entityManager = IoCManager.Resolve<IEntityManager>();
|
||||
_gameTiming = IoCManager.Resolve<IGameTiming>();
|
||||
_gameHud = IoCManager.Resolve<IGameHud>();
|
||||
_menu = new ActionMenu(_actionsComponent, this);
|
||||
|
||||
LayoutContainer.SetGrowHorizontal(this, LayoutContainer.GrowDirection.End);
|
||||
LayoutContainer.SetGrowVertical(this, LayoutContainer.GrowDirection.End);
|
||||
LayoutContainer.SetAnchorTop(this, 0f);
|
||||
LayoutContainer.SetAnchorBottom(this, 0.8f);
|
||||
LayoutContainer.SetMarginLeft(this, 10);
|
||||
LayoutContainer.SetMarginTop(this, 100);
|
||||
LayoutContainer.SetMarginLeft(this, 13);
|
||||
LayoutContainer.SetMarginTop(this, 110);
|
||||
|
||||
SizeFlagsHorizontal = SizeFlags.None;
|
||||
SizeFlagsVertical = SizeFlags.FillExpand;
|
||||
@@ -208,6 +211,9 @@ namespace Content.Client.UserInterface
|
||||
_lockButton.OnPressed += OnLockPressed;
|
||||
_settingsButton.OnPressed += OnToggleActionsMenu;
|
||||
_loadoutContainer.OnKeyBindDown += OnHotbarPaginate;
|
||||
_gameHud.ActionsButtonToggled += OnToggleActionsMenuTopButton;
|
||||
_gameHud.ActionsButtonDown = false;
|
||||
_gameHud.ActionsButtonVisible = true;
|
||||
}
|
||||
|
||||
protected override void ExitedTree()
|
||||
@@ -218,6 +224,9 @@ namespace Content.Client.UserInterface
|
||||
_lockButton.OnPressed -= OnLockPressed;
|
||||
_settingsButton.OnPressed -= OnToggleActionsMenu;
|
||||
_loadoutContainer.OnKeyBindDown -= OnHotbarPaginate;
|
||||
_gameHud.ActionsButtonToggled -= OnToggleActionsMenuTopButton;
|
||||
_gameHud.ActionsButtonDown = false;
|
||||
_gameHud.ActionsButtonVisible = false;
|
||||
}
|
||||
|
||||
protected override Vector2 CalculateMinimumSize()
|
||||
@@ -328,9 +337,9 @@ namespace Content.Client.UserInterface
|
||||
actionSlot.EnableAction();
|
||||
actionSlot.Cooldown = actionState.Cooldown;
|
||||
|
||||
// if we are targeting with an action now on cooldown, stop targeting
|
||||
// if we are targeting for this action and it's now on cooldown, stop targeting if we're supposed to
|
||||
if (SelectingTargetFor?.Action != null && SelectingTargetFor.Action == action &&
|
||||
actionState.IsOnCooldown(_gameTiming))
|
||||
actionState.IsOnCooldown(_gameTiming) && action.DeselectOnCooldown)
|
||||
{
|
||||
StopTargeting();
|
||||
}
|
||||
@@ -401,10 +410,10 @@ namespace Content.Client.UserInterface
|
||||
// action is currently granted
|
||||
actionSlot.EnableAction();
|
||||
|
||||
// if we are targeting with an action now on cooldown, stop targeting
|
||||
// if we are targeting with an action now on cooldown, stop targeting if we should
|
||||
if (SelectingTargetFor?.Action != null && SelectingTargetFor.Action == action &&
|
||||
SelectingTargetFor.Item == itemEntity &&
|
||||
actionState.IsOnCooldown(_gameTiming))
|
||||
actionState.IsOnCooldown(_gameTiming) && action.DeselectOnCooldown)
|
||||
{
|
||||
StopTargeting();
|
||||
}
|
||||
@@ -496,6 +505,13 @@ namespace Content.Client.UserInterface
|
||||
ToggleActionsMenu();
|
||||
}
|
||||
|
||||
|
||||
private void OnToggleActionsMenuTopButton(bool open)
|
||||
{
|
||||
if (open == _menu.IsOpen) return;
|
||||
ToggleActionsMenu();
|
||||
}
|
||||
|
||||
public void ToggleActionsMenu()
|
||||
{
|
||||
if (_menu.IsOpen)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Client.Administration;
|
||||
using Content.Shared.Input;
|
||||
using Robust.Client.Console;
|
||||
using Robust.Client.Interfaces.Input;
|
||||
@@ -13,6 +14,8 @@ namespace Content.Client.UserInterface.AdminMenu
|
||||
{
|
||||
[Dependency] private readonly INetManager _netManager = default!;
|
||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||
[Dependency] private readonly IGameHud _gameHud = default!;
|
||||
[Dependency] private readonly IClientAdminManager _clientAdminManager = default!;
|
||||
[Dependency] private readonly IClientConGroupController _clientConGroupController = default!;
|
||||
|
||||
private SS14Window _window;
|
||||
@@ -26,6 +29,30 @@ namespace Content.Client.UserInterface.AdminMenu
|
||||
|
||||
_inputManager.SetInputCommand(ContentKeyFunctions.OpenAdminMenu,
|
||||
InputCmdHandler.FromDelegate(session => Toggle()));
|
||||
|
||||
_clientAdminManager.AdminStatusUpdated += () =>
|
||||
{
|
||||
// when status changes, show the top button if we can open admin menu.
|
||||
// if we can't or we lost admin status, close it and hide the button.
|
||||
_gameHud.AdminButtonVisible = CanOpen();
|
||||
if (!_gameHud.AdminButtonVisible)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
};
|
||||
_gameHud.AdminButtonToggled += (open) =>
|
||||
{
|
||||
if (open)
|
||||
{
|
||||
TryOpen();
|
||||
}
|
||||
else
|
||||
{
|
||||
Close();
|
||||
}
|
||||
};
|
||||
_gameHud.AdminButtonVisible = CanOpen();
|
||||
_gameHud.AdminButtonDown = false;
|
||||
}
|
||||
|
||||
public void ResetWindow()
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#nullable enable
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Client.GameObjects.EntitySystems;
|
||||
using Content.Client.StationEvents;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Client.Console;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.Interfaces.Placement;
|
||||
@@ -30,6 +31,7 @@ namespace Content.Client.UserInterface.AdminMenu
|
||||
public readonly TabContainer MasterTabContainer;
|
||||
public readonly VBoxContainer PlayerList;
|
||||
public readonly Label PlayerCount;
|
||||
private readonly IGameHud _gameHud;
|
||||
|
||||
protected override Vector2? CustomSize => (500, 250);
|
||||
|
||||
@@ -44,7 +46,7 @@ namespace Content.Client.UserInterface.AdminMenu
|
||||
{
|
||||
new SpawnEntitiesCommandButton(),
|
||||
new SpawnTilesCommandButton(),
|
||||
new StationEventsCommandButton(),
|
||||
new StationEventsCommandButton()
|
||||
};
|
||||
private readonly List<CommandButton> _debugButtons = new()
|
||||
{
|
||||
@@ -206,6 +208,7 @@ namespace Content.Client.UserInterface.AdminMenu
|
||||
|
||||
public AdminMenuWindow() //TODO: search for buttons?
|
||||
{
|
||||
_gameHud = IoCManager.Resolve<IGameHud>();
|
||||
Title = Loc.GetString("Admin Menu");
|
||||
|
||||
#region PlayerList
|
||||
@@ -376,6 +379,19 @@ namespace Content.Client.UserInterface.AdminMenu
|
||||
IoCManager.Resolve<IStationEventManager>().RequestEvents();
|
||||
}
|
||||
|
||||
protected override void ExitedTree()
|
||||
{
|
||||
base.ExitedTree();
|
||||
_gameHud.AdminButtonDown = false;
|
||||
|
||||
}
|
||||
|
||||
protected override void EnteredTree()
|
||||
{
|
||||
base.EnteredTree();
|
||||
_gameHud.AdminButtonDown = true;
|
||||
}
|
||||
|
||||
#region CommandButtonBaseClass
|
||||
private abstract class CommandButton
|
||||
{
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
using Content.Client.Eui;
|
||||
using Content.Shared.Eui;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.IoC;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Shared.Administration;
|
||||
|
||||
namespace Content.Client.UserInterface.AdminMenu.SetOutfit
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed class SetOutfitEui : BaseEui
|
||||
{
|
||||
private readonly SetOutfitMenu _window;
|
||||
public SetOutfitEui()
|
||||
{
|
||||
_window = new SetOutfitMenu();
|
||||
}
|
||||
|
||||
public override void Opened()
|
||||
{
|
||||
_window.OpenCentered();
|
||||
}
|
||||
|
||||
public override void Closed()
|
||||
{
|
||||
base.Closed();
|
||||
_window.Close();
|
||||
}
|
||||
|
||||
public override void HandleState(EuiStateBase state)
|
||||
{
|
||||
var outfitState = (SetOutfitEuiState) state;
|
||||
_window.TargetEntityId = outfitState.TargetEntityId;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<customControls:SS14Window
|
||||
xmlns:customControls="clr-namespace:Robust.Client.UserInterface.CustomControls;assembly=Robust.Client"
|
||||
xmlns:controls="clr-namespace:Robust.Client.UserInterface.Controls;assembly=Robust.Client"
|
||||
xmlns:userInterface="clr-namespace:Robust.Client.UserInterface;assembly=Robust.Client">
|
||||
<controls:HBoxContainer SizeFlagsHorizontal="FillExpand">
|
||||
<controls:VBoxContainer SizeFlagsHorizontal="FillExpand" SizeFlagsStretchRatio="0.45">
|
||||
<controls:HBoxContainer SizeFlagsHorizontal="FillExpand" SizeFlagsVertical="FillExpand"
|
||||
SizeFlagsStretchRatio="0.1">
|
||||
<controls:LineEdit Name="SearchBar" PlaceHolder="Search" SizeFlagsHorizontal="FillExpand"
|
||||
SizeFlagsStretchRatio="0.6" />
|
||||
</controls:HBoxContainer>
|
||||
<controls:ItemList Name="OutfitList" SelectMode="Single" SizeFlagsVertical="FillExpand"
|
||||
SizeFlagsStretchRatio="0.9" />
|
||||
<controls:Button Name="ConfirmButton" SizeFlagsHorizontal="FillExpand" />
|
||||
</controls:VBoxContainer>
|
||||
</controls:HBoxContainer>
|
||||
</customControls:SS14Window>
|
||||
@@ -0,0 +1,105 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using Content.Shared.Construction;
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Console;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.UserInterface.AdminMenu.SetOutfit
|
||||
{
|
||||
[GenerateTypedNameReferences]
|
||||
public partial class SetOutfitMenu : SS14Window
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IClientConsole _console = default!;
|
||||
|
||||
public EntityUid? TargetEntityId { get; set; }
|
||||
protected override Vector2? CustomSize => (250, 320);
|
||||
|
||||
private StartingGearPrototype? _selectedOutfit;
|
||||
|
||||
public SetOutfitMenu()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
Title = Loc.GetString("Set Outfit");
|
||||
|
||||
ConfirmButton.Text = Loc.GetString("Confirm");
|
||||
ConfirmButton.OnPressed += ConfirmButtonOnOnPressed;
|
||||
SearchBar.OnTextChanged += SearchBarOnOnTextChanged;
|
||||
OutfitList.OnItemSelected += OutfitListOnOnItemSelected;
|
||||
OutfitList.OnItemDeselected += OutfitListOnOnItemDeselected;
|
||||
PopulateList();
|
||||
}
|
||||
|
||||
private void ConfirmButtonOnOnPressed(BaseButton.ButtonEventArgs obj)
|
||||
{
|
||||
if (TargetEntityId == null || _selectedOutfit == null)
|
||||
return;
|
||||
var command = $"setoutfit {TargetEntityId} {_selectedOutfit.ID}";
|
||||
_console.ProcessCommand(command);
|
||||
Close();
|
||||
}
|
||||
|
||||
private void OutfitListOnOnItemSelected(ItemList.ItemListSelectedEventArgs obj)
|
||||
{
|
||||
_selectedOutfit = (StartingGearPrototype) obj.ItemList[obj.ItemIndex].Metadata!;
|
||||
ConfirmButton.Disabled = false;
|
||||
}
|
||||
|
||||
private void OutfitListOnOnItemDeselected(ItemList.ItemListDeselectedEventArgs obj)
|
||||
{
|
||||
_selectedOutfit = null;
|
||||
ConfirmButton.Disabled = true;
|
||||
}
|
||||
|
||||
|
||||
private void SearchBarOnOnTextChanged(LineEdit.LineEditEventArgs obj)
|
||||
{
|
||||
PopulateByFilter(SearchBar.Text);
|
||||
}
|
||||
|
||||
private void PopulateList()
|
||||
{
|
||||
foreach (var gear in _prototypeManager.EnumeratePrototypes<StartingGearPrototype>())
|
||||
{
|
||||
OutfitList.Add(GetItem(gear, OutfitList));
|
||||
}
|
||||
}
|
||||
|
||||
private void PopulateByFilter(string filter)
|
||||
{
|
||||
OutfitList.Clear();
|
||||
foreach (var gear in _prototypeManager.EnumeratePrototypes<StartingGearPrototype>())
|
||||
{
|
||||
if (!string.IsNullOrEmpty(filter) &&
|
||||
gear.ID.ToLowerInvariant().Contains(filter.Trim().ToLowerInvariant()))
|
||||
{
|
||||
OutfitList.Add(GetItem(gear, OutfitList));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static ItemList.Item GetItem(StartingGearPrototype gear, ItemList itemList)
|
||||
{
|
||||
return new(itemList)
|
||||
{
|
||||
Metadata = gear,
|
||||
Text = gear.ID
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,8 +53,10 @@ namespace Content.Client.UserInterface.Controls
|
||||
|
||||
/// <summary>
|
||||
/// Is there an action in the slot that can currently be used?
|
||||
/// Target-basedActions on cooldown can still be selected / deselected if they've been configured as such
|
||||
/// </summary>
|
||||
public bool CanUseAction => HasAssignment && ActionEnabled && !IsOnCooldown;
|
||||
public bool CanUseAction => Action != null && ActionEnabled &&
|
||||
(!IsOnCooldown || (Action.IsTargetAction && !Action.DeselectOnCooldown));
|
||||
|
||||
/// <summary>
|
||||
/// Item the action is provided by, only valid if Action is an ItemActionPrototype. May be null
|
||||
@@ -325,6 +327,14 @@ namespace Content.Client.UserInterface.Controls
|
||||
DrawModeChanged();
|
||||
}
|
||||
|
||||
protected override void ControlFocusExited()
|
||||
{
|
||||
// lost focus for some reason, cancel the drag if there is one.
|
||||
base.ControlFocusExited();
|
||||
_actionsUI.DragDropHelper.EndDrag();
|
||||
DrawModeChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancel current press without triggering the action
|
||||
/// </summary>
|
||||
@@ -340,8 +350,10 @@ namespace Content.Client.UserInterface.Controls
|
||||
/// </summary>
|
||||
public void Depress(bool depress)
|
||||
{
|
||||
// action can still be toggled if it's allowed to stay selected
|
||||
if (!CanUseAction) return;
|
||||
|
||||
|
||||
if (_depressed && !depress)
|
||||
{
|
||||
// fire the action
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
using System;
|
||||
using System.Transactions;
|
||||
using Content.Client.UserInterface.Stylesheets;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Content.Shared.Input;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.Input;
|
||||
using Robust.Client.Interfaces.Input;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.Core.Tokens;
|
||||
using static Robust.Client.Input.Keyboard.Key;
|
||||
using Control = Robust.Client.UserInterface.Control;
|
||||
|
||||
namespace Content.Client.UserInterface
|
||||
{
|
||||
@@ -41,6 +49,16 @@ namespace Content.Client.UserInterface
|
||||
bool CraftingButtonVisible { get; set; }
|
||||
Action<bool> CraftingButtonToggled { get; set; }
|
||||
|
||||
// Actions top button.
|
||||
bool ActionsButtonDown { get; set; }
|
||||
bool ActionsButtonVisible { get; set; }
|
||||
Action<bool> ActionsButtonToggled { get; set; }
|
||||
|
||||
// Admin top button.
|
||||
bool AdminButtonDown { get; set; }
|
||||
bool AdminButtonVisible { get; set; }
|
||||
Action<bool> AdminButtonToggled { get; set; }
|
||||
|
||||
// Sandbox top button.
|
||||
bool SandboxButtonDown { get; set; }
|
||||
bool SandboxButtonVisible { get; set; }
|
||||
@@ -48,7 +66,8 @@ namespace Content.Client.UserInterface
|
||||
|
||||
Control HandsContainer { get; }
|
||||
Control SuspicionContainer { get; }
|
||||
Control InventoryQuickButtonContainer { get; }
|
||||
Control RightInventoryQuickButtonContainer { get; }
|
||||
Control LeftInventoryQuickButtonContainer { get; }
|
||||
|
||||
bool CombatPanelVisible { get; set; }
|
||||
bool CombatModeActive { get; set; }
|
||||
@@ -69,6 +88,8 @@ namespace Content.Client.UserInterface
|
||||
private TopButton _buttonCharacterMenu;
|
||||
private TopButton _buttonInventoryMenu;
|
||||
private TopButton _buttonCraftingMenu;
|
||||
private TopButton _buttonActionsMenu;
|
||||
private TopButton _buttonAdminMenu;
|
||||
private TopButton _buttonSandboxMenu;
|
||||
private TutorialWindow _tutorialWindow;
|
||||
private TargetingDoll _targetingDoll;
|
||||
@@ -80,7 +101,8 @@ namespace Content.Client.UserInterface
|
||||
|
||||
public Control HandsContainer { get; private set; }
|
||||
public Control SuspicionContainer { get; private set; }
|
||||
public Control InventoryQuickButtonContainer { get; private set; }
|
||||
public Control RightInventoryQuickButtonContainer { get; private set; }
|
||||
public Control LeftInventoryQuickButtonContainer { get; private set; }
|
||||
|
||||
public bool CombatPanelVisible
|
||||
{
|
||||
@@ -108,16 +130,18 @@ namespace Content.Client.UserInterface
|
||||
RootControl = new LayoutContainer();
|
||||
LayoutContainer.SetAnchorPreset(RootControl, LayoutContainer.LayoutPreset.Wide);
|
||||
|
||||
var escapeTexture = _resourceCache.GetTexture("/Textures/Interface/hamburger.svg.96dpi.png");
|
||||
var characterTexture = _resourceCache.GetTexture("/Textures/Interface/character.svg.96dpi.png");
|
||||
var inventoryTexture = _resourceCache.GetTexture("/Textures/Interface/inventory.svg.96dpi.png");
|
||||
var craftingTexture = _resourceCache.GetTexture("/Textures/Interface/hammer.svg.96dpi.png");
|
||||
var tutorialTexture = _resourceCache.GetTexture("/Textures/Interface/students-cap.svg.96dpi.png");
|
||||
var sandboxTexture = _resourceCache.GetTexture("/Textures/Interface/sandbox.svg.96dpi.png");
|
||||
var escapeTexture = _resourceCache.GetTexture("/Textures/Interface/hamburger.svg.192dpi.png");
|
||||
var characterTexture = _resourceCache.GetTexture("/Textures/Interface/character.svg.192dpi.png");
|
||||
var inventoryTexture = _resourceCache.GetTexture("/Textures/Interface/inventory.svg.192dpi.png");
|
||||
var craftingTexture = _resourceCache.GetTexture("/Textures/Interface/hammer.svg.192dpi.png");
|
||||
var actionsTexture = _resourceCache.GetTexture("/Textures/Interface/fist.svg.192dpi.png");
|
||||
var adminTexture = _resourceCache.GetTexture("/Textures/Interface/gavel.svg.192dpi.png");
|
||||
var tutorialTexture = _resourceCache.GetTexture("/Textures/Interface/tutorial.svg.192dpi.png");
|
||||
var sandboxTexture = _resourceCache.GetTexture("/Textures/Interface/sandbox.svg.192dpi.png");
|
||||
|
||||
_topButtonsContainer = new HBoxContainer
|
||||
{
|
||||
SeparationOverride = 4
|
||||
SeparationOverride = 8
|
||||
};
|
||||
|
||||
RootControl.AddChild(_topButtonsContainer);
|
||||
@@ -125,32 +149,29 @@ namespace Content.Client.UserInterface
|
||||
LayoutContainer.SetAnchorAndMarginPreset(_topButtonsContainer, LayoutContainer.LayoutPreset.TopLeft,
|
||||
margin: 10);
|
||||
|
||||
// TODO: Pull key names here from the actual key binding config.
|
||||
// the icon textures here should all have the same image height (32) but different widths, so in order to ensure
|
||||
// the buttons themselves are consistent widths we set a common custom min size
|
||||
Vector2 topMinSize = (42, 64);
|
||||
|
||||
// Escape
|
||||
_buttonEscapeMenu = new TopButton(escapeTexture, "Esc")
|
||||
_buttonEscapeMenu = new TopButton(escapeTexture, EngineKeyFunctions.EscapeMenu, _inputManager)
|
||||
{
|
||||
ToolTip = Loc.GetString("Open escape menu.")
|
||||
ToolTip = Loc.GetString("Open escape menu."),
|
||||
CustomMinimumSize = (70, 64),
|
||||
StyleClasses = {StyleBase.ButtonOpenRight}
|
||||
};
|
||||
|
||||
_topButtonsContainer.AddChild(_buttonEscapeMenu);
|
||||
|
||||
_buttonEscapeMenu.OnToggled += args => EscapeButtonToggled?.Invoke(args.Pressed);
|
||||
|
||||
// Tutorial
|
||||
_buttonTutorial = new TopButton(tutorialTexture, "F1")
|
||||
{
|
||||
ToolTip = Loc.GetString("Open tutorial.")
|
||||
};
|
||||
|
||||
_topButtonsContainer.AddChild(_buttonTutorial);
|
||||
|
||||
_buttonTutorial.OnToggled += a => ButtonTutorialOnOnToggled();
|
||||
|
||||
// Character
|
||||
_buttonCharacterMenu = new TopButton(characterTexture, "C")
|
||||
_buttonCharacterMenu = new TopButton(characterTexture, ContentKeyFunctions.OpenCharacterMenu, _inputManager)
|
||||
{
|
||||
ToolTip = Loc.GetString("Open character menu."),
|
||||
Visible = false
|
||||
CustomMinimumSize = topMinSize,
|
||||
Visible = false,
|
||||
StyleClasses = {StyleBase.ButtonSquare}
|
||||
};
|
||||
|
||||
_topButtonsContainer.AddChild(_buttonCharacterMenu);
|
||||
@@ -158,10 +179,12 @@ namespace Content.Client.UserInterface
|
||||
_buttonCharacterMenu.OnToggled += args => CharacterButtonToggled?.Invoke(args.Pressed);
|
||||
|
||||
// Inventory
|
||||
_buttonInventoryMenu = new TopButton(inventoryTexture, "I")
|
||||
_buttonInventoryMenu = new TopButton(inventoryTexture, ContentKeyFunctions.OpenInventoryMenu, _inputManager)
|
||||
{
|
||||
ToolTip = Loc.GetString("Open inventory menu."),
|
||||
Visible = false
|
||||
CustomMinimumSize = topMinSize,
|
||||
Visible = false,
|
||||
StyleClasses = {StyleBase.ButtonSquare}
|
||||
};
|
||||
|
||||
_topButtonsContainer.AddChild(_buttonInventoryMenu);
|
||||
@@ -169,27 +192,69 @@ namespace Content.Client.UserInterface
|
||||
_buttonInventoryMenu.OnToggled += args => InventoryButtonToggled?.Invoke(args.Pressed);
|
||||
|
||||
// Crafting
|
||||
_buttonCraftingMenu = new TopButton(craftingTexture, "G")
|
||||
_buttonCraftingMenu = new TopButton(craftingTexture, ContentKeyFunctions.OpenCraftingMenu, _inputManager)
|
||||
{
|
||||
ToolTip = Loc.GetString("Open crafting menu."),
|
||||
Visible = false
|
||||
CustomMinimumSize = topMinSize,
|
||||
Visible = false,
|
||||
StyleClasses = {StyleBase.ButtonSquare}
|
||||
};
|
||||
|
||||
_topButtonsContainer.AddChild(_buttonCraftingMenu);
|
||||
|
||||
_buttonCraftingMenu.OnToggled += args => CraftingButtonToggled?.Invoke(args.Pressed);
|
||||
|
||||
// Actions
|
||||
_buttonActionsMenu = new TopButton(actionsTexture, ContentKeyFunctions.OpenActionsMenu, _inputManager)
|
||||
{
|
||||
ToolTip = Loc.GetString("Open actions menu."),
|
||||
CustomMinimumSize = topMinSize,
|
||||
Visible = false,
|
||||
StyleClasses = {StyleBase.ButtonSquare}
|
||||
};
|
||||
|
||||
_topButtonsContainer.AddChild(_buttonActionsMenu);
|
||||
|
||||
_buttonActionsMenu.OnToggled += args => ActionsButtonToggled?.Invoke(args.Pressed);
|
||||
|
||||
// Admin
|
||||
_buttonAdminMenu = new TopButton(adminTexture, ContentKeyFunctions.OpenAdminMenu, _inputManager)
|
||||
{
|
||||
ToolTip = Loc.GetString("Open admin menu."),
|
||||
CustomMinimumSize = topMinSize,
|
||||
Visible = false,
|
||||
StyleClasses = {StyleBase.ButtonSquare}
|
||||
};
|
||||
|
||||
_topButtonsContainer.AddChild(_buttonAdminMenu);
|
||||
|
||||
_buttonAdminMenu.OnToggled += args => AdminButtonToggled?.Invoke(args.Pressed);
|
||||
|
||||
// Sandbox
|
||||
_buttonSandboxMenu = new TopButton(sandboxTexture, "B")
|
||||
_buttonSandboxMenu = new TopButton(sandboxTexture, ContentKeyFunctions.OpenSandboxWindow, _inputManager)
|
||||
{
|
||||
ToolTip = Loc.GetString("Open sandbox menu."),
|
||||
Visible = false
|
||||
CustomMinimumSize = topMinSize,
|
||||
Visible = false,
|
||||
StyleClasses = {StyleBase.ButtonSquare}
|
||||
};
|
||||
|
||||
_topButtonsContainer.AddChild(_buttonSandboxMenu);
|
||||
|
||||
_buttonSandboxMenu.OnToggled += args => SandboxButtonToggled?.Invoke(args.Pressed);
|
||||
|
||||
// Tutorial
|
||||
_buttonTutorial = new TopButton(tutorialTexture, ContentKeyFunctions.OpenTutorial, _inputManager)
|
||||
{
|
||||
ToolTip = Loc.GetString("Open tutorial."),
|
||||
CustomMinimumSize = topMinSize,
|
||||
StyleClasses = {StyleBase.ButtonOpenLeft, TopButton.StyleClassRedTopButton},
|
||||
};
|
||||
|
||||
_topButtonsContainer.AddChild(_buttonTutorial);
|
||||
|
||||
_buttonTutorial.OnToggled += a => ButtonTutorialOnOnToggled();
|
||||
|
||||
_tutorialWindow = new TutorialWindow();
|
||||
|
||||
_tutorialWindow.OnClose += () => _buttonTutorial.Pressed = false;
|
||||
@@ -197,21 +262,6 @@ namespace Content.Client.UserInterface
|
||||
_inputManager.SetInputCommand(ContentKeyFunctions.OpenTutorial,
|
||||
InputCmdHandler.FromDelegate(s => ButtonTutorialOnOnToggled()));
|
||||
|
||||
var inventoryContainer = new HBoxContainer
|
||||
{
|
||||
SeparationOverride = 10
|
||||
};
|
||||
|
||||
RootControl.AddChild(inventoryContainer);
|
||||
|
||||
LayoutContainer.SetGrowHorizontal(inventoryContainer, LayoutContainer.GrowDirection.Begin);
|
||||
LayoutContainer.SetGrowVertical(inventoryContainer, LayoutContainer.GrowDirection.Begin);
|
||||
LayoutContainer.SetAnchorAndMarginPreset(inventoryContainer, LayoutContainer.LayoutPreset.BottomRight);
|
||||
|
||||
InventoryQuickButtonContainer = new MarginContainer
|
||||
{
|
||||
SizeFlagsVertical = Control.SizeFlags.ShrinkEnd
|
||||
};
|
||||
|
||||
_combatPanelContainer = new VBoxContainer
|
||||
{
|
||||
@@ -226,23 +276,40 @@ namespace Content.Client.UserInterface
|
||||
}
|
||||
};
|
||||
|
||||
LayoutContainer.SetGrowHorizontal(_combatPanelContainer, LayoutContainer.GrowDirection.Begin);
|
||||
LayoutContainer.SetGrowVertical(_combatPanelContainer, LayoutContainer.GrowDirection.Begin);
|
||||
LayoutContainer.SetAnchorAndMarginPreset(_combatPanelContainer, LayoutContainer.LayoutPreset.BottomRight);
|
||||
LayoutContainer.SetMarginBottom(_combatPanelContainer, -10f);
|
||||
RootControl.AddChild(_combatPanelContainer);
|
||||
|
||||
_combatModeButton.OnToggled += args => OnCombatModeChanged?.Invoke(args.Pressed);
|
||||
_targetingDoll.OnZoneChanged += args => OnTargetingZoneChanged?.Invoke(args);
|
||||
|
||||
inventoryContainer.Children.Add(InventoryQuickButtonContainer);
|
||||
inventoryContainer.Children.Add(_combatPanelContainer);
|
||||
|
||||
var centerBottomContainer = new HBoxContainer
|
||||
{
|
||||
SeparationOverride = 5
|
||||
};
|
||||
LayoutContainer.SetAnchorAndMarginPreset(centerBottomContainer, LayoutContainer.LayoutPreset.CenterBottom);
|
||||
LayoutContainer.SetGrowHorizontal(centerBottomContainer, LayoutContainer.GrowDirection.Both);
|
||||
LayoutContainer.SetGrowVertical(centerBottomContainer, LayoutContainer.GrowDirection.Begin);
|
||||
LayoutContainer.SetMarginBottom(centerBottomContainer, -10f);
|
||||
RootControl.AddChild(centerBottomContainer);
|
||||
|
||||
HandsContainer = new MarginContainer
|
||||
{
|
||||
SizeFlagsVertical = Control.SizeFlags.ShrinkEnd
|
||||
};
|
||||
|
||||
RootControl.AddChild(HandsContainer);
|
||||
|
||||
LayoutContainer.SetAnchorAndMarginPreset(HandsContainer, LayoutContainer.LayoutPreset.CenterBottom);
|
||||
LayoutContainer.SetGrowHorizontal(HandsContainer, LayoutContainer.GrowDirection.Both);
|
||||
LayoutContainer.SetGrowVertical(HandsContainer, LayoutContainer.GrowDirection.Begin);
|
||||
RightInventoryQuickButtonContainer = new MarginContainer
|
||||
{
|
||||
SizeFlagsVertical = Control.SizeFlags.ShrinkEnd
|
||||
};
|
||||
LeftInventoryQuickButtonContainer = new MarginContainer
|
||||
{
|
||||
SizeFlagsVertical = Control.SizeFlags.ShrinkEnd
|
||||
};
|
||||
centerBottomContainer.AddChild(LeftInventoryQuickButtonContainer);
|
||||
centerBottomContainer.AddChild(HandsContainer);
|
||||
centerBottomContainer.AddChild(RightInventoryQuickButtonContainer);
|
||||
|
||||
SuspicionContainer = new MarginContainer
|
||||
{
|
||||
@@ -251,13 +318,15 @@ namespace Content.Client.UserInterface
|
||||
|
||||
RootControl.AddChild(SuspicionContainer);
|
||||
|
||||
LayoutContainer.SetAnchorAndMarginPreset(SuspicionContainer, LayoutContainer.LayoutPreset.BottomLeft, margin: 10);
|
||||
LayoutContainer.SetAnchorAndMarginPreset(SuspicionContainer, LayoutContainer.LayoutPreset.BottomLeft,
|
||||
margin: 10);
|
||||
LayoutContainer.SetGrowHorizontal(SuspicionContainer, LayoutContainer.GrowDirection.End);
|
||||
LayoutContainer.SetGrowVertical(SuspicionContainer, LayoutContainer.GrowDirection.Begin);
|
||||
}
|
||||
|
||||
private void ButtonTutorialOnOnToggled()
|
||||
{
|
||||
_buttonTutorial.StyleClasses.Remove(TopButton.StyleClassRedTopButton);
|
||||
if (_tutorialWindow.IsOpen)
|
||||
{
|
||||
if (!_tutorialWindow.IsAtFront())
|
||||
@@ -330,6 +399,34 @@ namespace Content.Client.UserInterface
|
||||
|
||||
public Action<bool> CraftingButtonToggled { get; set; }
|
||||
|
||||
public bool ActionsButtonDown
|
||||
{
|
||||
get => _buttonActionsMenu.Pressed;
|
||||
set => _buttonActionsMenu.Pressed = value;
|
||||
}
|
||||
|
||||
public bool ActionsButtonVisible
|
||||
{
|
||||
get => _buttonActionsMenu.Visible;
|
||||
set => _buttonActionsMenu.Visible = value;
|
||||
}
|
||||
|
||||
public Action<bool> ActionsButtonToggled { get; set; }
|
||||
|
||||
public bool AdminButtonDown
|
||||
{
|
||||
get => _buttonAdminMenu.Pressed;
|
||||
set => _buttonAdminMenu.Pressed = value;
|
||||
}
|
||||
|
||||
public bool AdminButtonVisible
|
||||
{
|
||||
get => _buttonAdminMenu.Visible;
|
||||
set => _buttonAdminMenu.Visible = value;
|
||||
}
|
||||
|
||||
public Action<bool> AdminButtonToggled { get; set; }
|
||||
|
||||
public bool SandboxButtonDown
|
||||
{
|
||||
get => _buttonSandboxMenu.Pressed;
|
||||
@@ -344,94 +441,204 @@ namespace Content.Client.UserInterface
|
||||
|
||||
public Action<bool> SandboxButtonToggled { get; set; }
|
||||
|
||||
public sealed class TopButton : BaseButton
|
||||
public sealed class TopButton : ContainerButton
|
||||
{
|
||||
public const string StyleClassLabelTopButton = "topButtonLabel";
|
||||
public const string StyleClassRedTopButton = "topButtonLabel";
|
||||
private const float CustomTooltipDelay = 0.4f;
|
||||
|
||||
private static readonly Color ColorNormal = Color.FromHex("#7b7e9e");
|
||||
private static readonly Color ColorRedNormal = Color.FromHex("#FEFEFE");
|
||||
private static readonly Color ColorHovered = Color.FromHex("#9699bb");
|
||||
private static readonly Color ColorRedHovered = Color.FromHex("#FFFFFF");
|
||||
private static readonly Color ColorPressed = Color.FromHex("#789B8C");
|
||||
|
||||
private const float VertPad = 8f;
|
||||
|
||||
private Color NormalColor => HasStyleClass(StyleClassRedTopButton) ? ColorRedNormal : ColorNormal;
|
||||
private Color HoveredColor => HasStyleClass(StyleClassRedTopButton) ? ColorRedHovered : ColorHovered;
|
||||
|
||||
private readonly TextureRect _textureRect;
|
||||
private readonly Label _label;
|
||||
private readonly BoundKeyFunction _function;
|
||||
private readonly IInputManager _inputManager;
|
||||
|
||||
public TopButton(Texture texture, string keyName)
|
||||
public TopButton(Texture texture, BoundKeyFunction function, IInputManager inputManager)
|
||||
{
|
||||
ToggleMode = true;
|
||||
_function = function;
|
||||
_inputManager = inputManager;
|
||||
TooltipDelay = CustomTooltipDelay;
|
||||
|
||||
AddChild(new MarginContainer
|
||||
{
|
||||
MarginTopOverride = 4,
|
||||
Children =
|
||||
AddChild(
|
||||
new VBoxContainer
|
||||
{
|
||||
new VBoxContainer
|
||||
Children =
|
||||
{
|
||||
Children =
|
||||
new Control {CustomMinimumSize = (0, VertPad)},
|
||||
(_textureRect = new TextureRect
|
||||
{
|
||||
(_textureRect = new TextureRect
|
||||
{
|
||||
Texture = texture,
|
||||
SizeFlagsHorizontal = SizeFlags.ShrinkCenter,
|
||||
SizeFlagsVertical = SizeFlags.Expand | SizeFlags.ShrinkCenter,
|
||||
ModulateSelfOverride = ColorNormal,
|
||||
CustomMinimumSize = (0, 32),
|
||||
Stretch = TextureRect.StretchMode.KeepCentered
|
||||
}),
|
||||
(_label = new Label
|
||||
{
|
||||
Text = keyName,
|
||||
SizeFlagsHorizontal = SizeFlags.ShrinkCenter,
|
||||
ModulateSelfOverride = ColorNormal,
|
||||
StyleClasses = {StyleClassLabelTopButton}
|
||||
})
|
||||
}
|
||||
TextureScale = (0.5f, 0.5f),
|
||||
Texture = texture,
|
||||
SizeFlagsHorizontal = SizeFlags.ShrinkCenter,
|
||||
SizeFlagsVertical = SizeFlags.Expand | SizeFlags.ShrinkCenter,
|
||||
ModulateSelfOverride = NormalColor,
|
||||
Stretch = TextureRect.StretchMode.KeepCentered
|
||||
}),
|
||||
new Control {CustomMinimumSize = (0, VertPad)},
|
||||
(_label = new Label
|
||||
{
|
||||
Text = ShortKeyName(_function),
|
||||
SizeFlagsHorizontal = SizeFlags.ShrinkCenter,
|
||||
ModulateSelfOverride = NormalColor,
|
||||
StyleClasses = {StyleClassLabelTopButton}
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
DrawModeChanged();
|
||||
ToggleMode = true;
|
||||
}
|
||||
|
||||
protected override Vector2 CalculateMinimumSize()
|
||||
protected override void EnteredTree()
|
||||
{
|
||||
var styleSize = ActualStyleBox?.MinimumSize ?? Vector2.Zero;
|
||||
return (0, 4) + styleSize + base.CalculateMinimumSize();
|
||||
_inputManager.OnKeyBindingAdded += OnKeyBindingChanged;
|
||||
_inputManager.OnKeyBindingRemoved += OnKeyBindingChanged;
|
||||
}
|
||||
|
||||
protected override void Draw(DrawingHandleScreen handle)
|
||||
protected override void ExitedTree()
|
||||
{
|
||||
ActualStyleBox?.Draw(handle, PixelSizeBox);
|
||||
_inputManager.OnKeyBindingAdded -= OnKeyBindingChanged;
|
||||
_inputManager.OnKeyBindingRemoved -= OnKeyBindingChanged;
|
||||
}
|
||||
|
||||
private StyleBox ActualStyleBox
|
||||
|
||||
private void OnKeyBindingChanged(IKeyBinding obj)
|
||||
{
|
||||
get
|
||||
_label.Text = ShortKeyName(_function);
|
||||
}
|
||||
|
||||
private string ShortKeyName(BoundKeyFunction keyFunction)
|
||||
{
|
||||
// need to use shortened key names so they fit in the buttons.
|
||||
return TryGetShortKeyName(keyFunction, out var name) ? Loc.GetString(name) : " ";
|
||||
}
|
||||
|
||||
private bool TryGetShortKeyName(BoundKeyFunction keyFunction, out string name)
|
||||
{
|
||||
if (_inputManager.TryGetKeyBinding(keyFunction, out var binding))
|
||||
{
|
||||
TryGetStyleProperty(Button.StylePropertyStyleBox, out StyleBox ret);
|
||||
return ret;
|
||||
// can't possibly fit a modifier key in the top button, so omit it
|
||||
var key = binding.BaseKey;
|
||||
if (binding.Mod1 != Unknown || binding.Mod2 != Unknown ||
|
||||
binding.Mod3 != Unknown)
|
||||
{
|
||||
name = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
name = null;
|
||||
name = key switch
|
||||
{
|
||||
Apostrophe => "'",
|
||||
Comma => ",",
|
||||
Delete => "Del",
|
||||
Down => "Dwn",
|
||||
Escape => "Esc",
|
||||
Equal => "=",
|
||||
Home => "Hom",
|
||||
Insert => "Ins",
|
||||
Left => "Lft",
|
||||
Menu => "Men",
|
||||
Minus => "-",
|
||||
Num0 => "0",
|
||||
Num1 => "1",
|
||||
Num2 => "2",
|
||||
Num3 => "3",
|
||||
Num4 => "4",
|
||||
Num5 => "5",
|
||||
Num6 => "6",
|
||||
Num7 => "7",
|
||||
Num8 => "8",
|
||||
Num9 => "9",
|
||||
Pause => "||",
|
||||
Period => ".",
|
||||
Return => "Ret",
|
||||
Right => "Rgt",
|
||||
Slash => "/",
|
||||
Space => "Spc",
|
||||
Tab => "Tab",
|
||||
Tilde => "~",
|
||||
BackSlash => "\\",
|
||||
BackSpace => "Bks",
|
||||
LBracket => "[",
|
||||
MouseButton4 => "M4",
|
||||
MouseButton5 => "M5",
|
||||
MouseButton6 => "M6",
|
||||
MouseButton7 => "M7",
|
||||
MouseButton8 => "M8",
|
||||
MouseButton9 => "M9",
|
||||
MouseLeft => "ML",
|
||||
MouseMiddle => "MM",
|
||||
MouseRight => "MR",
|
||||
NumpadDecimal => "N.",
|
||||
NumpadDivide => "N/",
|
||||
NumpadEnter => "Ent",
|
||||
NumpadMultiply => "*",
|
||||
NumpadNum0 => "0",
|
||||
NumpadNum1 => "1",
|
||||
NumpadNum2 => "2",
|
||||
NumpadNum3 => "3",
|
||||
NumpadNum4 => "4",
|
||||
NumpadNum5 => "5",
|
||||
NumpadNum6 => "6",
|
||||
NumpadNum7 => "7",
|
||||
NumpadNum8 => "8",
|
||||
NumpadNum9 => "9",
|
||||
NumpadSubtract => "N-",
|
||||
PageDown => "PgD",
|
||||
PageUp => "PgU",
|
||||
RBracket => "]",
|
||||
SemiColon => ";",
|
||||
_ => DefaultShortKeyName(keyFunction)
|
||||
};
|
||||
return name != null;
|
||||
}
|
||||
|
||||
name = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void DrawModeChanged()
|
||||
private string DefaultShortKeyName(BoundKeyFunction keyFunction)
|
||||
{
|
||||
var name = FormattedMessage.EscapeText(_inputManager.GetKeyFunctionButtonString(keyFunction));
|
||||
return name.Length > 3 ? null : name;
|
||||
}
|
||||
|
||||
protected override void StylePropertiesChanged()
|
||||
{
|
||||
// colors of children depend on style, so ensure we update when style is changed
|
||||
base.StylePropertiesChanged();
|
||||
UpdateChildColors();
|
||||
}
|
||||
|
||||
private void UpdateChildColors()
|
||||
{
|
||||
if (_label == null || _textureRect == null) return;
|
||||
switch (DrawMode)
|
||||
{
|
||||
case DrawModeEnum.Normal:
|
||||
SetOnlyStylePseudoClass(Button.StylePseudoClassNormal);
|
||||
_textureRect.ModulateSelfOverride = ColorNormal;
|
||||
_label.ModulateSelfOverride = ColorNormal;
|
||||
_textureRect.ModulateSelfOverride = NormalColor;
|
||||
_label.ModulateSelfOverride = NormalColor;
|
||||
break;
|
||||
|
||||
case DrawModeEnum.Pressed:
|
||||
SetOnlyStylePseudoClass(Button.StylePseudoClassPressed);
|
||||
_textureRect.ModulateSelfOverride = ColorPressed;
|
||||
_label.ModulateSelfOverride = ColorPressed;
|
||||
break;
|
||||
|
||||
case DrawModeEnum.Hover:
|
||||
SetOnlyStylePseudoClass(Button.StylePseudoClassHover);
|
||||
_textureRect.ModulateSelfOverride = ColorHovered;
|
||||
_label.ModulateSelfOverride = ColorHovered;
|
||||
_textureRect.ModulateSelfOverride = HoveredColor;
|
||||
_label.ModulateSelfOverride = HoveredColor;
|
||||
break;
|
||||
|
||||
case DrawModeEnum.Disabled:
|
||||
@@ -439,15 +646,11 @@ namespace Content.Client.UserInterface
|
||||
}
|
||||
}
|
||||
|
||||
protected override void LayoutUpdateOverride()
|
||||
{
|
||||
var box = ActualStyleBox ?? new StyleBoxEmpty();
|
||||
var contentBox = box.GetContentBox(PixelSizeBox);
|
||||
|
||||
foreach (var child in Children)
|
||||
{
|
||||
FitChildInPixelBox(child, (UIBox2i) contentBox);
|
||||
}
|
||||
protected override void DrawModeChanged()
|
||||
{
|
||||
base.DrawModeChanged();
|
||||
UpdateChildColors();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
using Content.Shared.GameObjects.Components.Items;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Client.UserInterface
|
||||
{
|
||||
public class HandButton : ItemSlotButton
|
||||
{
|
||||
private bool _activeHand;
|
||||
private bool _highlighted;
|
||||
|
||||
public HandButton(Texture texture, Texture storageTexture, Texture blockedTexture, HandLocation location) : base(texture, storageTexture)
|
||||
{
|
||||
Location = location;
|
||||
@@ -21,5 +25,23 @@ namespace Content.Client.UserInterface
|
||||
|
||||
public HandLocation Location { get; }
|
||||
public TextureRect Blocked { get; }
|
||||
|
||||
public void SetActiveHand(bool active)
|
||||
{
|
||||
_activeHand = active;
|
||||
UpdateHighlight();
|
||||
}
|
||||
|
||||
public override void Highlight(bool highlight)
|
||||
{
|
||||
_highlighted = highlight;
|
||||
UpdateHighlight();
|
||||
}
|
||||
|
||||
private void UpdateHighlight()
|
||||
{
|
||||
// always stay highlighted if active
|
||||
base.Highlight(_activeHand || _highlighted);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Content.Client.GameObjects.Components.Items;
|
||||
using Content.Client.UserInterface.Stylesheets;
|
||||
using Content.Client.Utility;
|
||||
using Content.Shared.GameObjects.Components.Items;
|
||||
using Content.Shared.Input;
|
||||
@@ -21,8 +22,6 @@ namespace Content.Client.UserInterface
|
||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||
[Dependency] private readonly IItemSlotManager _itemSlotManager = default!;
|
||||
|
||||
private readonly TextureRect _activeHandRect;
|
||||
|
||||
private readonly Texture _leftHandTexture;
|
||||
private readonly Texture _middleHandTexture;
|
||||
private readonly Texture _rightHandTexture;
|
||||
@@ -52,24 +51,14 @@ namespace Content.Client.UserInterface
|
||||
Children =
|
||||
{
|
||||
(_topPanel = ItemStatusPanel.FromSide(HandLocation.Middle)),
|
||||
(_handsContainer = new HBoxContainer {SeparationOverride = 0})
|
||||
(_handsContainer = new HBoxContainer())
|
||||
}
|
||||
}),
|
||||
(_leftPanel = ItemStatusPanel.FromSide(HandLocation.Left))
|
||||
}
|
||||
});
|
||||
|
||||
var textureHandActive = _resourceCache.GetTexture("/Textures/Interface/Inventory/hand_active.png");
|
||||
|
||||
// Active hand
|
||||
_activeHandRect = new TextureRect
|
||||
{
|
||||
Texture = textureHandActive,
|
||||
TextureScale = (2, 2)
|
||||
};
|
||||
|
||||
_leftHandTexture = _resourceCache.GetTexture("/Textures/Interface/Inventory/hand_l.png");
|
||||
_middleHandTexture = _resourceCache.GetTexture("/Textures/Interface/Inventory/hand_middle.png");
|
||||
_middleHandTexture = _resourceCache.GetTexture("/Textures/Interface/Inventory/hand_l.png");
|
||||
_rightHandTexture = _resourceCache.GetTexture("/Textures/Interface/Inventory/hand_r.png");
|
||||
}
|
||||
|
||||
@@ -119,13 +108,6 @@ namespace Content.Client.UserInterface
|
||||
button.OnStoragePressed += args => _OnStoragePressed(args, slot);
|
||||
|
||||
_handsContainer.AddChild(button);
|
||||
|
||||
if (_activeHandRect.Parent == null)
|
||||
{
|
||||
button.AddChild(_activeHandRect);
|
||||
_activeHandRect.SetPositionInParent(1);
|
||||
}
|
||||
|
||||
hand.Button = button;
|
||||
}
|
||||
|
||||
@@ -135,11 +117,6 @@ namespace Content.Client.UserInterface
|
||||
|
||||
if (button != null)
|
||||
{
|
||||
if (button.Children.Contains(_activeHandRect))
|
||||
{
|
||||
button.RemoveChild(_activeHandRect);
|
||||
}
|
||||
|
||||
_handsContainer.RemoveChild(button);
|
||||
}
|
||||
}
|
||||
@@ -186,14 +163,8 @@ namespace Content.Client.UserInterface
|
||||
hand.Button!.Button.Texture = HandTexture(hand.Location);
|
||||
hand.Button!.SetPositionInParent(i);
|
||||
_itemSlotManager.SetItemSlot(hand.Button, hand.Entity);
|
||||
}
|
||||
|
||||
_activeHandRect.Parent?.RemoveChild(_activeHandRect);
|
||||
component.GetHand(component.ActiveIndex)?.Button?.AddChild(_activeHandRect);
|
||||
|
||||
if (hands.Length > 0)
|
||||
{
|
||||
_activeHandRect.SetPositionInParent(1);
|
||||
hand.Button!.SetActiveHand(component.ActiveIndex == hand.Name);
|
||||
}
|
||||
|
||||
_leftPanel.SetPositionFirst();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Content.Client.GameObjects.Components;
|
||||
using Content.Client.GameObjects.Components;
|
||||
using Content.Client.GameObjects.Components.Mobs;
|
||||
using Content.Client.Interfaces;
|
||||
using Content.Shared.GameTicking;
|
||||
@@ -21,6 +21,7 @@ using Robust.Shared.Localization.Macros;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Client.UserInterface.Stylesheets;
|
||||
|
||||
namespace Content.Client.UserInterface
|
||||
{
|
||||
@@ -43,6 +44,7 @@ namespace Content.Client.UserInterface
|
||||
private readonly Button _sexMaleButton;
|
||||
private readonly OptionButton _genderButton;
|
||||
private readonly OptionButton _clothingButton;
|
||||
private readonly OptionButton _backpackButton;
|
||||
private readonly HairStylePicker _hairPicker;
|
||||
private readonly FacialHairStylePicker _facialHairPicker;
|
||||
|
||||
@@ -333,6 +335,33 @@ namespace Content.Client.UserInterface
|
||||
}
|
||||
|
||||
#endregion Clothing
|
||||
|
||||
#region Backpack
|
||||
|
||||
{
|
||||
var panel = HighlightedContainer();
|
||||
var hBox = new HBoxContainer();
|
||||
var backpackLabel = new Label { Text = Loc.GetString("Backpack:") };
|
||||
|
||||
_backpackButton = new OptionButton();
|
||||
|
||||
_backpackButton.AddItem(Loc.GetString("Backpack"), (int) BackpackPreference.Backpack);
|
||||
_backpackButton.AddItem(Loc.GetString("Satchel"), (int) BackpackPreference.Satchel);
|
||||
_backpackButton.AddItem(Loc.GetString("Duffelbag"), (int) BackpackPreference.Duffelbag);
|
||||
|
||||
_backpackButton.OnItemSelected += args =>
|
||||
{
|
||||
_backpackButton.SelectId(args.Id);
|
||||
SetBackpack((BackpackPreference) args.Id);
|
||||
};
|
||||
|
||||
hBox.AddChild(backpackLabel);
|
||||
hBox.AddChild(_backpackButton);
|
||||
panel.AddChild(hBox);
|
||||
appearanceVBox.AddChild(panel);
|
||||
}
|
||||
|
||||
#endregion Clothing
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -669,6 +698,12 @@ namespace Content.Client.UserInterface
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
private void SetBackpack(BackpackPreference newBackpack)
|
||||
{
|
||||
Profile = Profile?.WithBackpackPreference(newBackpack);
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
IsDirty = false;
|
||||
@@ -723,6 +758,11 @@ namespace Content.Client.UserInterface
|
||||
_clothingButton.SelectId((int) Profile.Clothing);
|
||||
}
|
||||
|
||||
private void UpdateBackpackControls()
|
||||
{
|
||||
_backpackButton.SelectId((int) Profile.Backpack);
|
||||
}
|
||||
|
||||
private void UpdateHairPickers()
|
||||
{
|
||||
_hairPicker.SetData(
|
||||
@@ -754,6 +794,7 @@ namespace Content.Client.UserInterface
|
||||
UpdateSexControls();
|
||||
UpdateGenderControls();
|
||||
UpdateClothingControls();
|
||||
UpdateBackpackControls();
|
||||
UpdateAgeEdit();
|
||||
UpdateHairPickers();
|
||||
UpdateSaveButton();
|
||||
@@ -780,12 +821,12 @@ namespace Content.Client.UserInterface
|
||||
private class JobPrioritySelector : Control
|
||||
{
|
||||
public JobPrototype Job { get; }
|
||||
private readonly OptionButton _optionButton;
|
||||
private readonly RadioOptions<int> _optionButton;
|
||||
|
||||
public JobPriority Priority
|
||||
{
|
||||
get => (JobPriority) _optionButton.SelectedId;
|
||||
set => _optionButton.SelectId((int) value);
|
||||
get => (JobPriority) _optionButton.SelectedValue;
|
||||
set => _optionButton.SelectByValue((int) value);
|
||||
}
|
||||
|
||||
public event Action<JobPriority> PriorityChanged;
|
||||
@@ -793,7 +834,14 @@ namespace Content.Client.UserInterface
|
||||
public JobPrioritySelector(JobPrototype job)
|
||||
{
|
||||
Job = job;
|
||||
_optionButton = new OptionButton();
|
||||
_optionButton = new RadioOptions<int>(RadioOptionsLayout.Horizontal);
|
||||
|
||||
_optionButton.FirstButtonStyle = StyleBase.ButtonOpenRight;
|
||||
_optionButton.ButtonStyle = StyleBase.ButtonOpenBoth;
|
||||
_optionButton.LastButtonStyle = StyleBase.ButtonOpenLeft;
|
||||
|
||||
|
||||
// Text, Value
|
||||
_optionButton.AddItem(Loc.GetString("High"), (int) JobPriority.High);
|
||||
_optionButton.AddItem(Loc.GetString("Medium"), (int) JobPriority.Medium);
|
||||
_optionButton.AddItem(Loc.GetString("Low"), (int) JobPriority.Low);
|
||||
@@ -801,7 +849,7 @@ namespace Content.Client.UserInterface
|
||||
|
||||
_optionButton.OnItemSelected += args =>
|
||||
{
|
||||
_optionButton.SelectId(args.Id);
|
||||
_optionButton.Select(args.Id);
|
||||
PriorityChanged?.Invoke(Priority);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Content.Client.UserInterface.Stylesheets;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics.Shaders;
|
||||
using Robust.Client.UserInterface;
|
||||
@@ -26,11 +27,11 @@ namespace Content.Client.UserInterface
|
||||
|
||||
public bool EntityHover => HoverSpriteView.Sprite != null;
|
||||
public bool MouseIsHovering = false;
|
||||
private readonly ShaderInstance _highlightShader;
|
||||
|
||||
private readonly PanelContainer _highlightRect;
|
||||
|
||||
public ItemSlotButton(Texture texture, Texture storageTexture)
|
||||
{
|
||||
_highlightShader = IoCManager.Resolve<IPrototypeManager>().Index<ShaderPrototype>(HighlightShader).Instance();
|
||||
CustomMinimumSize = (64, 64);
|
||||
|
||||
AddChild(Button = new TextureRect
|
||||
@@ -40,6 +41,13 @@ namespace Content.Client.UserInterface
|
||||
MouseFilter = MouseFilterMode.Stop
|
||||
});
|
||||
|
||||
AddChild(_highlightRect = new PanelContainer
|
||||
{
|
||||
StyleClasses = { StyleNano.StyleClassHandSlotHighlight },
|
||||
CustomMinimumSize = (32, 32),
|
||||
Visible = false
|
||||
});
|
||||
|
||||
Button.OnKeyBindDown += OnButtonPressed;
|
||||
|
||||
AddChild(SpriteView = new SpriteView
|
||||
@@ -102,18 +110,16 @@ namespace Content.Client.UserInterface
|
||||
}
|
||||
}
|
||||
|
||||
public void Highlight(bool on)
|
||||
public virtual void Highlight(bool highlight)
|
||||
{
|
||||
// I make no claim that this actually looks good but it's a start.
|
||||
if (on)
|
||||
if (highlight)
|
||||
{
|
||||
Button.ShaderOverride = _highlightShader;
|
||||
_highlightRect.Visible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Button.ShaderOverride = null;
|
||||
_highlightRect.Visible = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void OnButtonPressed(GUIBoundKeyEventArgs args)
|
||||
|
||||
@@ -7,6 +7,7 @@ using Robust.Client.GameObjects.EntitySystems;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
using Robust.Client.Interfaces.Input;
|
||||
using Robust.Client.Interfaces.UserInterface;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.Input;
|
||||
@@ -25,6 +26,7 @@ namespace Content.Client.UserInterface
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly IInputManager _inputManager = default!;
|
||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
|
||||
[Dependency] private readonly IUserInterfaceManager _uiMgr = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
@@ -61,7 +63,7 @@ namespace Content.Client.UserInterface
|
||||
else if (args.Function == ContentKeyFunctions.OpenContextMenu)
|
||||
{
|
||||
_entitySystemManager.GetEntitySystem<VerbSystem>()
|
||||
.OpenContextMenu(item, new ScreenCoordinates(args.PointerLocation.Position));
|
||||
.OpenContextMenu(item, new ScreenCoordinates(_uiMgr.ScreenToUIPosition(args.PointerLocation)));
|
||||
}
|
||||
else if (args.Function == ContentKeyFunctions.ActivateItemInWorld)
|
||||
{
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Content.Client.UserInterface
|
||||
[ViewVariables]
|
||||
private IEntity? _entity;
|
||||
|
||||
public ItemStatusPanel(Texture texture, StyleBox.Margin margin)
|
||||
public ItemStatusPanel(Texture texture, StyleBox.Margin cutout, StyleBox.Margin flat, Label.AlignMode textAlign)
|
||||
{
|
||||
var panel = new StyleBoxTexture
|
||||
{
|
||||
@@ -40,7 +40,8 @@ namespace Content.Client.UserInterface
|
||||
};
|
||||
panel.SetContentMarginOverride(StyleBox.Margin.Vertical, 4);
|
||||
panel.SetContentMarginOverride(StyleBox.Margin.Horizontal, 6);
|
||||
panel.SetPatchMargin(margin, 13);
|
||||
panel.SetPatchMargin(flat, 2);
|
||||
panel.SetPatchMargin(cutout, 13);
|
||||
|
||||
AddChild(_panel = new PanelContainer
|
||||
{
|
||||
@@ -57,7 +58,8 @@ namespace Content.Client.UserInterface
|
||||
(_itemNameLabel = new Label
|
||||
{
|
||||
ClipText = true,
|
||||
StyleClasses = {StyleNano.StyleClassItemStatus}
|
||||
StyleClasses = {StyleNano.StyleClassItemStatus},
|
||||
Align = textAlign
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -78,27 +80,35 @@ namespace Content.Client.UserInterface
|
||||
public static ItemStatusPanel FromSide(HandLocation location)
|
||||
{
|
||||
string texture;
|
||||
StyleBox.Margin margin;
|
||||
StyleBox.Margin cutOut;
|
||||
StyleBox.Margin flat;
|
||||
Label.AlignMode textAlign;
|
||||
|
||||
switch (location)
|
||||
{
|
||||
case HandLocation.Left:
|
||||
texture = "/Textures/Interface/Nano/item_status_right.svg.96dpi.png";
|
||||
margin = StyleBox.Margin.Left | StyleBox.Margin.Top;
|
||||
cutOut = StyleBox.Margin.Left | StyleBox.Margin.Top;
|
||||
flat = StyleBox.Margin.Right | StyleBox.Margin.Bottom;
|
||||
textAlign = Label.AlignMode.Right;
|
||||
break;
|
||||
case HandLocation.Middle:
|
||||
texture = "/Textures/Interface/Nano/item_status_left.svg.96dpi.png";
|
||||
margin = StyleBox.Margin.Right | StyleBox.Margin.Top;
|
||||
texture = "/Textures/Interface/Nano/item_status_middle.svg.96dpi.png";
|
||||
cutOut = StyleBox.Margin.Right | StyleBox.Margin.Top;
|
||||
flat = StyleBox.Margin.Left | StyleBox.Margin.Bottom;
|
||||
textAlign = Label.AlignMode.Left;
|
||||
break;
|
||||
case HandLocation.Right:
|
||||
texture = "/Textures/Interface/Nano/item_status_left.svg.96dpi.png";
|
||||
margin = StyleBox.Margin.Right | StyleBox.Margin.Top;
|
||||
cutOut = StyleBox.Margin.Right | StyleBox.Margin.Top;
|
||||
flat = StyleBox.Margin.Left | StyleBox.Margin.Bottom;
|
||||
textAlign = Label.AlignMode.Left;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(location), location, null);
|
||||
}
|
||||
|
||||
return new ItemStatusPanel(ResC.GetTexture(texture), margin);
|
||||
return new ItemStatusPanel(ResC.GetTexture(texture), cutOut, flat, textAlign);
|
||||
}
|
||||
|
||||
public void Update(IEntity? entity)
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
public const string ButtonOpenRight = "OpenRight";
|
||||
public const string ButtonOpenLeft = "OpenLeft";
|
||||
public const string ButtonOpenBoth = "OpenBoth";
|
||||
public const string ButtonSquare = "ButtonSquare";
|
||||
|
||||
public const string ButtonCaution = "Caution";
|
||||
|
||||
@@ -28,6 +29,7 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
protected StyleBoxTexture BaseButtonOpenRight { get; }
|
||||
protected StyleBoxTexture BaseButtonOpenLeft { get; }
|
||||
protected StyleBoxTexture BaseButtonOpenBoth { get; }
|
||||
protected StyleBoxTexture BaseButtonSquare { get; }
|
||||
|
||||
protected StyleBase(IResourceCache resCache)
|
||||
{
|
||||
@@ -70,6 +72,15 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
BaseButtonOpenBoth.SetPadding(StyleBox.Margin.Right, 2);
|
||||
BaseButtonOpenBoth.SetPadding(StyleBox.Margin.Left, 1);
|
||||
|
||||
BaseButtonSquare = new StyleBoxTexture(BaseButton)
|
||||
{
|
||||
Texture = new AtlasTexture(buttonTex, UIBox2.FromDimensions((10, 0), (3, 24))),
|
||||
};
|
||||
BaseButtonSquare.SetPatchMargin(StyleBox.Margin.Horizontal, 0);
|
||||
BaseButtonSquare.SetContentMarginOverride(StyleBox.Margin.Horizontal, 8);
|
||||
BaseButtonSquare.SetPadding(StyleBox.Margin.Right, 2);
|
||||
BaseButtonSquare.SetPadding(StyleBox.Margin.Left, 1);
|
||||
|
||||
BaseRules = new[]
|
||||
{
|
||||
// Default font.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Content.Client.GameObjects.EntitySystems;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Client.Utility;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.UserInterface;
|
||||
@@ -15,6 +16,8 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
public sealed class StyleNano : StyleBase
|
||||
{
|
||||
public const string StyleClassBorderedWindowPanel = "BorderedWindowPanel";
|
||||
public const string StyleClassInventorySlotBackground = "InventorySlotBackground";
|
||||
public const string StyleClassHandSlotHighlight = "HandSlotHighlight";
|
||||
public const string StyleClassTransparentBorderedWindowPanel = "TransparentBorderedWindowPanel";
|
||||
public const string StyleClassHotbarPanel = "HotbarPanel";
|
||||
public const string StyleClassTooltipPanel = "tooltipBox";
|
||||
@@ -44,7 +47,9 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
public static readonly Color NanoGold = Color.FromHex("#A88B5E");
|
||||
|
||||
public static readonly Color ButtonColorDefault = Color.FromHex("#464966");
|
||||
public static readonly Color ButtonColorDefaultRed = Color.FromHex("#D43B3B");
|
||||
public static readonly Color ButtonColorHovered = Color.FromHex("#575b7f");
|
||||
public static readonly Color ButtonColorHoveredRed = Color.FromHex("#DF6B6B");
|
||||
public static readonly Color ButtonColorPressed = Color.FromHex("#3e6c45");
|
||||
public static readonly Color ButtonColorDisabled = Color.FromHex("#30313c");
|
||||
|
||||
@@ -100,6 +105,21 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
};
|
||||
borderedWindowBackground.SetPatchMargin(StyleBox.Margin.All, 2);
|
||||
|
||||
var invSlotBgTex = resCache.GetTexture("/Textures/Interface/Inventory/inv_slot_background.png");
|
||||
var invSlotBg = new StyleBoxTexture
|
||||
{
|
||||
Texture = invSlotBgTex,
|
||||
};
|
||||
invSlotBg.SetPatchMargin(StyleBox.Margin.All, 2);
|
||||
invSlotBg.SetContentMarginOverride(StyleBox.Margin.All, 0);
|
||||
|
||||
var handSlotHighlightTex = resCache.GetTexture("/Textures/Interface/Inventory/hand_slot_highlight.png");
|
||||
var handSlotHighlight = new StyleBoxTexture
|
||||
{
|
||||
Texture = handSlotHighlightTex,
|
||||
};
|
||||
handSlotHighlight.SetPatchMargin(StyleBox.Margin.All, 2);
|
||||
|
||||
var borderedTransparentWindowBackgroundTex = resCache.GetTexture("/Textures/Interface/Nano/transparent_window_background_bordered.png");
|
||||
var borderedTransparentWindowBackground = new StyleBoxTexture
|
||||
{
|
||||
@@ -162,6 +182,33 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
Modulate = ButtonColorPressed
|
||||
};
|
||||
|
||||
var buttonTex = resCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png");
|
||||
var topButtonBase = new StyleBoxTexture
|
||||
{
|
||||
Texture = buttonTex,
|
||||
};
|
||||
topButtonBase.SetPatchMargin(StyleBox.Margin.All, 10);
|
||||
topButtonBase.SetPadding(StyleBox.Margin.All, 0);
|
||||
topButtonBase.SetContentMarginOverride(StyleBox.Margin.All, 0);
|
||||
|
||||
var topButtonOpenRight = new StyleBoxTexture(topButtonBase)
|
||||
{
|
||||
Texture = new AtlasTexture(buttonTex, UIBox2.FromDimensions((0, 0), (14, 24))),
|
||||
};
|
||||
topButtonOpenRight.SetPatchMargin(StyleBox.Margin.Right, 0);
|
||||
|
||||
var topButtonOpenLeft = new StyleBoxTexture(topButtonBase)
|
||||
{
|
||||
Texture = new AtlasTexture(buttonTex, UIBox2.FromDimensions((10, 0), (14, 24))),
|
||||
};
|
||||
topButtonOpenLeft.SetPatchMargin(StyleBox.Margin.Left, 0);
|
||||
|
||||
var topButtonSquare = new StyleBoxTexture(topButtonBase)
|
||||
{
|
||||
Texture = new AtlasTexture(buttonTex, UIBox2.FromDimensions((10, 0), (3, 24))),
|
||||
};
|
||||
topButtonSquare.SetPatchMargin(StyleBox.Margin.Horizontal, 0);
|
||||
|
||||
var textureInvertedTriangle = resCache.GetTexture("/Textures/Interface/Nano/inverted_triangle.svg.png");
|
||||
|
||||
var lineEditTex = resCache.GetTexture("/Textures/Interface/Nano/lineedit.png");
|
||||
@@ -355,6 +402,20 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
{
|
||||
new StyleProperty(PanelContainer.StylePropertyPanel, borderedTransparentWindowBackground),
|
||||
}),
|
||||
// inventory slot background
|
||||
new StyleRule(
|
||||
new SelectorElement(null, new[] {StyleClassInventorySlotBackground}, null, null),
|
||||
new[]
|
||||
{
|
||||
new StyleProperty(PanelContainer.StylePropertyPanel, invSlotBg),
|
||||
}),
|
||||
// hand slot highlight
|
||||
new StyleRule(
|
||||
new SelectorElement(null, new[] {StyleClassHandSlotHighlight}, null, null),
|
||||
new[]
|
||||
{
|
||||
new StyleProperty(PanelContainer.StylePropertyPanel, handSlotHighlight),
|
||||
}),
|
||||
// Hotbar background
|
||||
new StyleRule(new SelectorElement(typeof(PanelContainer), new[] {StyleClassHotbarPanel}, null, null),
|
||||
new[]
|
||||
@@ -410,6 +471,10 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
.Class(ButtonOpenBoth)
|
||||
.Prop(ContainerButton.StylePropertyStyleBox, BaseButtonOpenBoth),
|
||||
|
||||
Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
|
||||
.Class(ButtonSquare)
|
||||
.Prop(ContainerButton.StylePropertyStyleBox, BaseButtonSquare),
|
||||
|
||||
new StyleRule(new SelectorElement(typeof(Label), new[] { Button.StyleClassButton }, null, null), new[]
|
||||
{
|
||||
new StyleProperty(Label.StylePropertyAlignMode, Label.AlignMode.Center),
|
||||
@@ -808,8 +873,43 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
}),
|
||||
|
||||
// Those top menu buttons.
|
||||
Element<GameHud.TopButton>()
|
||||
.Prop(Button.StylePropertyStyleBox, BaseButton),
|
||||
// these use slight variations on the various BaseButton styles so that the content within them appears centered,
|
||||
// which is NOT the case for the default BaseButton styles (OpenLeft/OpenRight adds extra padding on one of the sides
|
||||
// which makes the TopButton icons appear off-center, which we don't want).
|
||||
new StyleRule(
|
||||
new SelectorElement(typeof(GameHud.TopButton), new[] {ButtonSquare}, null, null),
|
||||
new[]
|
||||
{
|
||||
new StyleProperty(Button.StylePropertyStyleBox, topButtonSquare),
|
||||
}),
|
||||
|
||||
new StyleRule(
|
||||
new SelectorElement(typeof(GameHud.TopButton), new[] {ButtonOpenLeft}, null, null),
|
||||
new[]
|
||||
{
|
||||
new StyleProperty(Button.StylePropertyStyleBox, topButtonOpenLeft),
|
||||
}),
|
||||
|
||||
new StyleRule(
|
||||
new SelectorElement(typeof(GameHud.TopButton), new[] {ButtonOpenRight}, null, null),
|
||||
new[]
|
||||
{
|
||||
new StyleProperty(Button.StylePropertyStyleBox, topButtonOpenRight),
|
||||
}),
|
||||
|
||||
new StyleRule(
|
||||
new SelectorElement(typeof(GameHud.TopButton), null, null, new[] {Button.StylePseudoClassNormal}),
|
||||
new[]
|
||||
{
|
||||
new StyleProperty(Button.StylePropertyModulateSelf, ButtonColorDefault),
|
||||
}),
|
||||
|
||||
new StyleRule(
|
||||
new SelectorElement(typeof(GameHud.TopButton), new[] {GameHud.TopButton.StyleClassRedTopButton}, null, new[] {Button.StylePseudoClassNormal}),
|
||||
new[]
|
||||
{
|
||||
new StyleProperty(Button.StylePropertyModulateSelf, ButtonColorDefaultRed),
|
||||
}),
|
||||
|
||||
new StyleRule(
|
||||
new SelectorElement(typeof(GameHud.TopButton), null, null, new[] {Button.StylePseudoClassNormal}),
|
||||
@@ -832,6 +932,13 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
new StyleProperty(Button.StylePropertyModulateSelf, ButtonColorHovered),
|
||||
}),
|
||||
|
||||
new StyleRule(
|
||||
new SelectorElement(typeof(GameHud.TopButton), new[] {GameHud.TopButton.StyleClassRedTopButton}, null, new[] {Button.StylePseudoClassHover}),
|
||||
new[]
|
||||
{
|
||||
new StyleProperty(Button.StylePropertyModulateSelf, ButtonColorHoveredRed),
|
||||
}),
|
||||
|
||||
new StyleRule(
|
||||
new SelectorElement(typeof(Label), new[] {GameHud.TopButton.StyleClassLabelTopButton}, null, null),
|
||||
new[]
|
||||
|
||||
@@ -61,6 +61,10 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
.Class(ButtonOpenBoth)
|
||||
.Prop(ContainerButton.StylePropertyStyleBox, BaseButtonOpenBoth),
|
||||
|
||||
Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
|
||||
.Class(ButtonSquare)
|
||||
.Prop(ContainerButton.StylePropertyStyleBox, BaseButtonSquare),
|
||||
|
||||
// Colors for the buttons.
|
||||
Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
|
||||
.Pseudo(ContainerButton.StylePseudoClassNormal)
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace Content.Client.UserInterface.Suspicion
|
||||
public class SuspicionGui : Control
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
private readonly VBoxContainer _container;
|
||||
private readonly Button _roleButton;
|
||||
@@ -58,14 +57,11 @@ namespace Content.Client.UserInterface.Suspicion
|
||||
return;
|
||||
}
|
||||
|
||||
var allies = string.Join(", ",
|
||||
role.Allies.Select(uid => _entityManager.GetEntity(uid).Name));
|
||||
var allies = string.Join(", ", role.Allies.Select(tuple => tuple.name));
|
||||
var message = role.Allies.Count switch
|
||||
{
|
||||
0 => Loc.GetString("You have no allies"),
|
||||
1 => Loc.GetString("Your ally is {0}", allies),
|
||||
var n when n > 2 => Loc.GetString("Your allies are {0}", allies),
|
||||
_ => throw new ArgumentException($"Invalid number of allies: {role.Allies.Count}")
|
||||
var n => Loc.GetPluralString("Your ally is {0}", "Your allies are {0}", n, allies),
|
||||
};
|
||||
|
||||
role.Owner.PopupMessage(message);
|
||||
|
||||
@@ -4,6 +4,7 @@ using Content.Client;
|
||||
using Content.Client.Interfaces.Parallax;
|
||||
using Content.Server;
|
||||
using Content.Server.Interfaces.GameTicking;
|
||||
using Content.Shared;
|
||||
using NUnit.Framework;
|
||||
using Robust.Server.Interfaces.Maps;
|
||||
using Robust.Server.Interfaces.Timing;
|
||||
@@ -48,7 +49,7 @@ namespace Content.IntegrationTests
|
||||
|
||||
// Connecting to Discord is a massive waste of time.
|
||||
// Basically just makes the CI logs a mess.
|
||||
options.CVarOverrides["discord.enabled"] = "true";
|
||||
options.CVarOverrides["discord.enabled"] = "false";
|
||||
|
||||
return base.StartClient(options);
|
||||
}
|
||||
@@ -76,6 +77,9 @@ namespace Content.IntegrationTests
|
||||
});
|
||||
};
|
||||
|
||||
// Avoid funny race conditions with the database.
|
||||
options.CVarOverrides[CCVars.DatabaseSynchronous.Name] = "true";
|
||||
|
||||
return base.StartServer(options);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,9 +20,15 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
[TestOf(typeof(Threshold))]
|
||||
public class DestructibleTests : ContentIntegrationTest
|
||||
{
|
||||
private static readonly string SpawnedEntityId = "DestructibleTestsSpawnedEntity";
|
||||
private static readonly string DestructibleEntityId = "DestructibleTestsDestructibleEntity";
|
||||
private static readonly string DestructibleDestructionEntityId = "DestructibleTestsDestructibleDestructionEntity";
|
||||
|
||||
private static readonly string Prototypes = $@"
|
||||
- type: entity
|
||||
id: {SpawnedEntityId}
|
||||
name: {SpawnedEntityId}
|
||||
|
||||
- type: entity
|
||||
id: {DestructibleEntityId}
|
||||
name: {DestructibleEntityId}
|
||||
@@ -35,15 +41,35 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
50:
|
||||
triggersOnce: false
|
||||
behaviors:
|
||||
- !type:DoActsBehavior
|
||||
acts: [""Breakage""]
|
||||
- !type:PlaySoundBehavior
|
||||
sound: /Audio/Effects/woodhit.ogg
|
||||
- !type:SpawnEntitiesBehavior
|
||||
spawn:
|
||||
WoodPlank:
|
||||
{SpawnedEntityId}:
|
||||
min: 1
|
||||
max: 1
|
||||
- !type:DoActsBehavior
|
||||
acts: [""Breakage""]
|
||||
- type: TestThresholdListener
|
||||
|
||||
- type: entity
|
||||
id: {DestructibleDestructionEntityId}
|
||||
name: {DestructibleDestructionEntityId}
|
||||
components:
|
||||
- type: Damageable
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
50:
|
||||
behaviors:
|
||||
- !type:PlaySoundBehavior
|
||||
sound: /Audio/Effects/woodhit.ogg
|
||||
- !type:SpawnEntitiesBehavior
|
||||
spawn:
|
||||
{SpawnedEntityId}:
|
||||
min: 1
|
||||
max: 1
|
||||
- !type:DoActsBehavior # This must come last as it destroys the entity.
|
||||
acts: [""Destruction""]
|
||||
- type: TestThresholdListener
|
||||
";
|
||||
|
||||
@@ -147,15 +173,15 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
// Check that it matches the YAML prototype
|
||||
Assert.That(threshold.Behaviors, Has.Count.EqualTo(3));
|
||||
|
||||
var actsThreshold = (DoActsBehavior) threshold.Behaviors[0];
|
||||
var soundThreshold = (PlaySoundBehavior) threshold.Behaviors[1];
|
||||
var spawnThreshold = (SpawnEntitiesBehavior) threshold.Behaviors[2];
|
||||
var soundThreshold = (PlaySoundBehavior) threshold.Behaviors[0];
|
||||
var spawnThreshold = (SpawnEntitiesBehavior) threshold.Behaviors[1];
|
||||
var actsThreshold = (DoActsBehavior) threshold.Behaviors[2];
|
||||
|
||||
Assert.That(actsThreshold.Acts, Is.EqualTo(ThresholdActs.Breakage));
|
||||
Assert.That(soundThreshold.Sound, Is.EqualTo("/Audio/Effects/woodhit.ogg"));
|
||||
Assert.That(spawnThreshold.Spawn, Is.Not.Null);
|
||||
Assert.That(spawnThreshold.Spawn.Count, Is.EqualTo(1));
|
||||
Assert.That(spawnThreshold.Spawn.Single().Key, Is.EqualTo("WoodPlank"));
|
||||
Assert.That(spawnThreshold.Spawn.Single().Key, Is.EqualTo(SpawnedEntityId));
|
||||
Assert.That(spawnThreshold.Spawn.Single().Value.Min, Is.EqualTo(1));
|
||||
Assert.That(spawnThreshold.Spawn.Single().Value.Max, Is.EqualTo(1));
|
||||
Assert.That(threshold.Triggered, Is.True);
|
||||
@@ -202,16 +228,16 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
// Check that it matches the YAML prototype
|
||||
Assert.That(threshold.Behaviors, Has.Count.EqualTo(3));
|
||||
|
||||
actsThreshold = (DoActsBehavior) threshold.Behaviors[0];
|
||||
soundThreshold = (PlaySoundBehavior) threshold.Behaviors[1];
|
||||
spawnThreshold = (SpawnEntitiesBehavior) threshold.Behaviors[2];
|
||||
soundThreshold = (PlaySoundBehavior) threshold.Behaviors[0];
|
||||
spawnThreshold = (SpawnEntitiesBehavior) threshold.Behaviors[1];
|
||||
actsThreshold = (DoActsBehavior) threshold.Behaviors[2];
|
||||
|
||||
// Check that it matches the YAML prototype
|
||||
Assert.That(actsThreshold.Acts, Is.EqualTo(ThresholdActs.Breakage));
|
||||
Assert.That(soundThreshold.Sound, Is.EqualTo("/Audio/Effects/woodhit.ogg"));
|
||||
Assert.That(spawnThreshold.Spawn, Is.Not.Null);
|
||||
Assert.That(spawnThreshold.Spawn.Count, Is.EqualTo(1));
|
||||
Assert.That(spawnThreshold.Spawn.Single().Key, Is.EqualTo("WoodPlank"));
|
||||
Assert.That(spawnThreshold.Spawn.Single().Key, Is.EqualTo(SpawnedEntityId));
|
||||
Assert.That(spawnThreshold.Spawn.Single().Value.Min, Is.EqualTo(1));
|
||||
Assert.That(spawnThreshold.Spawn.Single().Value.Max, Is.EqualTo(1));
|
||||
Assert.That(threshold.Triggered, Is.True);
|
||||
@@ -254,16 +280,16 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
|
||||
Assert.That(threshold.Behaviors, Has.Count.EqualTo(3));
|
||||
|
||||
actsThreshold = (DoActsBehavior) threshold.Behaviors[0];
|
||||
soundThreshold = (PlaySoundBehavior) threshold.Behaviors[1];
|
||||
spawnThreshold = (SpawnEntitiesBehavior) threshold.Behaviors[2];
|
||||
soundThreshold = (PlaySoundBehavior) threshold.Behaviors[0];
|
||||
spawnThreshold = (SpawnEntitiesBehavior) threshold.Behaviors[1];
|
||||
actsThreshold = (DoActsBehavior) threshold.Behaviors[2];
|
||||
|
||||
// Check that it matches the YAML prototype
|
||||
Assert.That(actsThreshold.Acts, Is.EqualTo(ThresholdActs.Breakage));
|
||||
Assert.That(soundThreshold.Sound, Is.EqualTo("/Audio/Effects/woodhit.ogg"));
|
||||
Assert.That(spawnThreshold.Spawn, Is.Not.Null);
|
||||
Assert.That(spawnThreshold.Spawn.Count, Is.EqualTo(1));
|
||||
Assert.That(spawnThreshold.Spawn.Single().Key, Is.EqualTo("WoodPlank"));
|
||||
Assert.That(spawnThreshold.Spawn.Single().Key, Is.EqualTo(SpawnedEntityId));
|
||||
Assert.That(spawnThreshold.Spawn.Single().Value.Min, Is.EqualTo(1));
|
||||
Assert.That(spawnThreshold.Spawn.Single().Value.Max, Is.EqualTo(1));
|
||||
Assert.That(threshold.Triggered, Is.True);
|
||||
@@ -305,5 +331,84 @@ namespace Content.IntegrationTests.Tests.Destructible
|
||||
Assert.That(sThresholdListenerComponent.ThresholdsReached, Is.Empty);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task DestructibleDestructionTest()
|
||||
{
|
||||
var server = StartServerDummyTicker(new ServerContentIntegrationOption
|
||||
{
|
||||
ExtraPrototypes = Prototypes,
|
||||
ContentBeforeIoC = () =>
|
||||
{
|
||||
IoCManager.Resolve<IComponentFactory>().Register<TestThresholdListenerComponent>();
|
||||
}
|
||||
});
|
||||
|
||||
await server.WaitIdleAsync();
|
||||
|
||||
var sEntityManager = server.ResolveDependency<IEntityManager>();
|
||||
var sMapManager = server.ResolveDependency<IMapManager>();
|
||||
|
||||
IEntity sDestructibleEntity = null;
|
||||
IDamageableComponent sDamageableComponent = null;
|
||||
DestructibleComponent sDestructibleComponent = null;
|
||||
TestThresholdListenerComponent sThresholdListenerComponent = null;
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
var mapId = new MapId(1);
|
||||
var coordinates = new MapCoordinates(0, 0, mapId);
|
||||
sMapManager.CreateMap(mapId);
|
||||
|
||||
sDestructibleEntity = sEntityManager.SpawnEntity(DestructibleDestructionEntityId, coordinates);
|
||||
sDamageableComponent = sDestructibleEntity.GetComponent<IDamageableComponent>();
|
||||
sDestructibleComponent = sDestructibleEntity.GetComponent<DestructibleComponent>();
|
||||
sThresholdListenerComponent = sDestructibleEntity.GetComponent<TestThresholdListenerComponent>();
|
||||
});
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
var coordinates = sDestructibleEntity.Transform.Coordinates;
|
||||
|
||||
Assert.DoesNotThrow(() =>
|
||||
{
|
||||
Assert.True(sDamageableComponent.ChangeDamage(DamageClass.Brute, 50, true));
|
||||
});
|
||||
|
||||
Assert.That(sThresholdListenerComponent.ThresholdsReached.Count, Is.EqualTo(1));
|
||||
|
||||
var threshold = sThresholdListenerComponent.ThresholdsReached[0].Threshold;
|
||||
|
||||
Assert.That(threshold.Triggered, Is.True);
|
||||
Assert.That(threshold.Behaviors.Count, Is.EqualTo(3));
|
||||
|
||||
var spawnEntitiesBehavior = (SpawnEntitiesBehavior) threshold.Behaviors.Single(b => b is SpawnEntitiesBehavior);
|
||||
|
||||
Assert.That(spawnEntitiesBehavior.Spawn.Count, Is.EqualTo(1));
|
||||
Assert.That(spawnEntitiesBehavior.Spawn.Keys.Single(), Is.EqualTo(SpawnedEntityId));
|
||||
Assert.That(spawnEntitiesBehavior.Spawn.Values.Single(), Is.EqualTo(new MinMax {Min = 1, Max = 1}));
|
||||
|
||||
var entitiesInRange = sEntityManager.GetEntitiesInRange(coordinates, 2);
|
||||
var found = false;
|
||||
|
||||
foreach (var entity in entitiesInRange)
|
||||
{
|
||||
if (entity.Prototype == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entity.Prototype.Name != SpawnedEntityId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
Assert.That(found, Is.True);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,17 +54,21 @@ namespace Content.IntegrationTests.Tests
|
||||
}
|
||||
|
||||
Assert.Multiple(() => {
|
||||
Assert.That(one, Is.EqualTo(two));
|
||||
Assert.That(two, Is.EqualTo(one));
|
||||
var failed = TestContext.CurrentContext.Result.Assertions.FirstOrDefault();
|
||||
if (failed != null)
|
||||
{
|
||||
var path1 = Path.Combine(userData.RootDir!,rp1.ToRelativeSystemPath());
|
||||
var path2 = Path.Combine(userData.RootDir!,rp2.ToRelativeSystemPath());
|
||||
TestContext.AddTestAttachment(path1);
|
||||
TestContext.AddTestAttachment(path2);
|
||||
var oneTmp = Path.GetTempFileName();
|
||||
var twoTmp = Path.GetTempFileName();
|
||||
|
||||
File.WriteAllText(oneTmp, one);
|
||||
File.WriteAllText(twoTmp, two);
|
||||
|
||||
TestContext.AddTestAttachment(oneTmp, "First save file");
|
||||
TestContext.AddTestAttachment(twoTmp, "Second save file");
|
||||
TestContext.Error.WriteLine("Complete output:");
|
||||
TestContext.Error.WriteLine(path1);
|
||||
TestContext.Error.WriteLine(path2);
|
||||
TestContext.Error.WriteLine(oneTmp);
|
||||
TestContext.Error.WriteLine(twoTmp);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.GameObjects.EntitySystems.StationEvents;
|
||||
using NUnit.Framework;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
@@ -17,23 +17,27 @@ namespace Content.IntegrationTests.Tests.StationEvents
|
||||
|
||||
server.Assert(() =>
|
||||
{
|
||||
// Idle each event once
|
||||
// Idle each event
|
||||
var stationEventsSystem = EntitySystem.Get<StationEventSystem>();
|
||||
var dummyFrameTime = (float) IoCManager.Resolve<IGameTiming>().TickPeriod.TotalSeconds;
|
||||
|
||||
foreach (var stationEvent in stationEventsSystem.StationEvents)
|
||||
{
|
||||
stationEvent.Announce();
|
||||
stationEvent.Update(dummyFrameTime);
|
||||
stationEvent.Startup();
|
||||
stationEvent.Update(dummyFrameTime);
|
||||
stationEvent.Running = false;
|
||||
stationEvent.Shutdown();
|
||||
Assert.That(stationEvent.Occurrences == 1);
|
||||
// Due to timings some events might startup twice when in reality they wouldn't.
|
||||
Assert.That(stationEvent.Occurrences > 0);
|
||||
}
|
||||
|
||||
stationEventsSystem.Reset();
|
||||
|
||||
foreach (var stationEvent in stationEventsSystem.StationEvents)
|
||||
{
|
||||
Assert.That(stationEvent.Occurrences == 0);
|
||||
Assert.That(stationEvent.Occurrences, Is.EqualTo(0));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
575
Content.Server.Database/Migrations/Postgres/20210103151756_BackpackPreference.Designer.cs
generated
Normal file
575
Content.Server.Database/Migrations/Postgres/20210103151756_BackpackPreference.Designer.cs
generated
Normal file
@@ -0,0 +1,575 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using System.Net;
|
||||
using Content.Server.Database;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
namespace Content.Server.Database.Migrations.Postgres
|
||||
{
|
||||
[DbContext(typeof(PostgresServerDbContext))]
|
||||
[Migration("20210103151756_BackpackPreference")]
|
||||
partial class BackpackPreference
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.UseIdentityByDefaultColumns()
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63)
|
||||
.HasAnnotation("ProductVersion", "5.0.0");
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||
{
|
||||
b.Property<Guid>("UserId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.Property<int?>("AdminRankId")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("admin_rank_id");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("title");
|
||||
|
||||
b.HasKey("UserId");
|
||||
|
||||
b.HasIndex("AdminRankId");
|
||||
|
||||
b.ToTable("admin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("admin_flag_id")
|
||||
.UseIdentityByDefaultColumn();
|
||||
|
||||
b.Property<Guid>("AdminId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("admin_id");
|
||||
|
||||
b.Property<string>("Flag")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("flag");
|
||||
|
||||
b.Property<bool>("Negative")
|
||||
.HasColumnType("boolean")
|
||||
.HasColumnName("negative");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AdminId");
|
||||
|
||||
b.HasIndex("Flag", "AdminId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("admin_flag");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminRank", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("admin_rank_id")
|
||||
.UseIdentityByDefaultColumn();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("admin_rank");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("admin_rank_flag_id")
|
||||
.UseIdentityByDefaultColumn();
|
||||
|
||||
b.Property<int>("AdminRankId")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("admin_rank_id");
|
||||
|
||||
b.Property<string>("Flag")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("flag");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AdminRankId");
|
||||
|
||||
b.HasIndex("Flag", "AdminRankId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("admin_rank_flag");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("antag_id")
|
||||
.UseIdentityByDefaultColumn();
|
||||
|
||||
b.Property<string>("AntagName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("antag_name");
|
||||
|
||||
b.Property<int>("ProfileId")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("profile_id");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ProfileId", "AntagName")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("antag");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AssignedUserId", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("assigned_user_id_id")
|
||||
.UseIdentityByDefaultColumn();
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("user_name");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("UserName")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("assigned_user_id");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("job_id")
|
||||
.UseIdentityByDefaultColumn();
|
||||
|
||||
b.Property<string>("JobName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("job_name");
|
||||
|
||||
b.Property<int>("Priority")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("priority");
|
||||
|
||||
b.Property<int>("ProfileId")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("profile_id");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ProfileId");
|
||||
|
||||
b.ToTable("job");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.PostgresConnectionLog", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("connection_log_id")
|
||||
.UseIdentityByDefaultColumn();
|
||||
|
||||
b.Property<IPAddress>("Address")
|
||||
.IsRequired()
|
||||
.HasColumnType("inet")
|
||||
.HasColumnName("address");
|
||||
|
||||
b.Property<DateTime>("Time")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("time");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("user_name");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("connection_log");
|
||||
|
||||
b.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.PostgresPlayer", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("player_id")
|
||||
.UseIdentityByDefaultColumn();
|
||||
|
||||
b.Property<DateTime>("FirstSeenTime")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("first_seen_time");
|
||||
|
||||
b.Property<IPAddress>("LastSeenAddress")
|
||||
.IsRequired()
|
||||
.HasColumnType("inet")
|
||||
.HasColumnName("last_seen_address");
|
||||
|
||||
b.Property<DateTime>("LastSeenTime")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("last_seen_time");
|
||||
|
||||
b.Property<string>("LastSeenUserName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("last_seen_user_name");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("LastSeenUserName");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("player");
|
||||
|
||||
b.HasCheckConstraint("LastSeenAddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= last_seen_address");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.PostgresServerBan", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("server_ban_id")
|
||||
.UseIdentityByDefaultColumn();
|
||||
|
||||
b.Property<ValueTuple<IPAddress, int>?>("Address")
|
||||
.HasColumnType("inet")
|
||||
.HasColumnName("address");
|
||||
|
||||
b.Property<DateTime>("BanTime")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("ban_time");
|
||||
|
||||
b.Property<Guid?>("BanningAdmin")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("banning_admin");
|
||||
|
||||
b.Property<DateTime?>("ExpirationTime")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("expiration_time");
|
||||
|
||||
b.Property<string>("Reason")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("reason");
|
||||
|
||||
b.Property<Guid?>("UserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Address");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("server_ban");
|
||||
|
||||
b.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
|
||||
|
||||
b.HasCheckConstraint("HaveEitherAddressOrUserId", "address IS NOT NULL OR user_id IS NOT NULL");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.PostgresServerUnban", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("unban_id")
|
||||
.UseIdentityByDefaultColumn();
|
||||
|
||||
b.Property<int>("BanId")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("ban_id");
|
||||
|
||||
b.Property<DateTime>("UnbanTime")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("unban_time");
|
||||
|
||||
b.Property<Guid?>("UnbanningAdmin")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("unbanning_admin");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BanId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("server_unban");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Preference", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("preference_id")
|
||||
.UseIdentityByDefaultColumn();
|
||||
|
||||
b.Property<int>("SelectedCharacterSlot")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("selected_character_slot");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("preference");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("profile_id")
|
||||
.UseIdentityByDefaultColumn();
|
||||
|
||||
b.Property<int>("Age")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("age");
|
||||
|
||||
b.Property<string>("Backpack")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("backpack");
|
||||
|
||||
b.Property<string>("CharacterName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("char_name");
|
||||
|
||||
b.Property<string>("Clothing")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("clothing");
|
||||
|
||||
b.Property<string>("EyeColor")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("eye_color");
|
||||
|
||||
b.Property<string>("FacialHairColor")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("facial_hair_color");
|
||||
|
||||
b.Property<string>("FacialHairName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("facial_hair_name");
|
||||
|
||||
b.Property<string>("Gender")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("gender");
|
||||
|
||||
b.Property<string>("HairColor")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("hair_color");
|
||||
|
||||
b.Property<string>("HairName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("hair_name");
|
||||
|
||||
b.Property<int>("PreferenceId")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("preference_id");
|
||||
|
||||
b.Property<int>("PreferenceUnavailable")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("pref_unavailable");
|
||||
|
||||
b.Property<string>("Sex")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("sex");
|
||||
|
||||
b.Property<string>("SkinColor")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("skin_color");
|
||||
|
||||
b.Property<int>("Slot")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("slot");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PreferenceId");
|
||||
|
||||
b.HasIndex("Slot", "PreferenceId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("profile");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.AdminRank", "AdminRank")
|
||||
.WithMany("Admins")
|
||||
.HasForeignKey("AdminRankId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.Navigation("AdminRank");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.Admin", "Admin")
|
||||
.WithMany("Flags")
|
||||
.HasForeignKey("AdminId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Admin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.AdminRank", "Rank")
|
||||
.WithMany("Flags")
|
||||
.HasForeignKey("AdminRankId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Rank");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||
.WithMany("Antags")
|
||||
.HasForeignKey("ProfileId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Profile");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||
.WithMany("Jobs")
|
||||
.HasForeignKey("ProfileId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Profile");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.PostgresServerUnban", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.PostgresServerBan", "Ban")
|
||||
.WithOne("Unban")
|
||||
.HasForeignKey("Content.Server.Database.PostgresServerUnban", "BanId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Ban");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.Preference", "Preference")
|
||||
.WithMany("Profiles")
|
||||
.HasForeignKey("PreferenceId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Preference");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||
{
|
||||
b.Navigation("Flags");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminRank", b =>
|
||||
{
|
||||
b.Navigation("Admins");
|
||||
|
||||
b.Navigation("Flags");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.PostgresServerBan", b =>
|
||||
{
|
||||
b.Navigation("Unban");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Preference", b =>
|
||||
{
|
||||
b.Navigation("Profiles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||
{
|
||||
b.Navigation("Antags");
|
||||
|
||||
b.Navigation("Jobs");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Content.Server.Database.Migrations.Postgres
|
||||
{
|
||||
public partial class BackpackPreference : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "backpack",
|
||||
table: "profile",
|
||||
type: "text",
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "backpack",
|
||||
table: "profile");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -386,6 +386,11 @@ namespace Content.Server.Database.Migrations.Postgres
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("age");
|
||||
|
||||
b.Property<string>("Backpack")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("backpack");
|
||||
|
||||
b.Property<string>("CharacterName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
|
||||
542
Content.Server.Database/Migrations/Sqlite/20210103151752_BackpackPreference.Designer.cs
generated
Normal file
542
Content.Server.Database/Migrations/Sqlite/20210103151752_BackpackPreference.Designer.cs
generated
Normal file
@@ -0,0 +1,542 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Content.Server.Database;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
namespace Content.Server.Database.Migrations.Sqlite
|
||||
{
|
||||
[DbContext(typeof(SqliteServerDbContext))]
|
||||
[Migration("20210103151752_BackpackPreference")]
|
||||
partial class BackpackPreference
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "5.0.0");
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||
{
|
||||
b.Property<Guid>("UserId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.Property<int?>("AdminRankId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("admin_rank_id");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("title");
|
||||
|
||||
b.HasKey("UserId");
|
||||
|
||||
b.HasIndex("AdminRankId");
|
||||
|
||||
b.ToTable("admin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("admin_flag_id");
|
||||
|
||||
b.Property<Guid>("AdminId")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("admin_id");
|
||||
|
||||
b.Property<string>("Flag")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("flag");
|
||||
|
||||
b.Property<bool>("Negative")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("negative");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AdminId");
|
||||
|
||||
b.HasIndex("Flag", "AdminId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("admin_flag");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminRank", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("admin_rank_id");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("admin_rank");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("admin_rank_flag_id");
|
||||
|
||||
b.Property<int>("AdminRankId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("admin_rank_id");
|
||||
|
||||
b.Property<string>("Flag")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("flag");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AdminRankId");
|
||||
|
||||
b.HasIndex("Flag", "AdminRankId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("admin_rank_flag");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("antag_id");
|
||||
|
||||
b.Property<string>("AntagName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("antag_name");
|
||||
|
||||
b.Property<int>("ProfileId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("profile_id");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ProfileId", "AntagName")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("antag");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AssignedUserId", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("assigned_user_id_id");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("user_name");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("UserName")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("assigned_user_id");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("job_id");
|
||||
|
||||
b.Property<string>("JobName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("job_name");
|
||||
|
||||
b.Property<int>("Priority")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("priority");
|
||||
|
||||
b.Property<int>("ProfileId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("profile_id");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ProfileId");
|
||||
|
||||
b.ToTable("job");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Preference", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("preference_id");
|
||||
|
||||
b.Property<int>("SelectedCharacterSlot")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("selected_character_slot");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("preference");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("profile_id");
|
||||
|
||||
b.Property<int>("Age")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("age");
|
||||
|
||||
b.Property<string>("Backpack")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("backpack");
|
||||
|
||||
b.Property<string>("CharacterName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("char_name");
|
||||
|
||||
b.Property<string>("Clothing")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("clothing");
|
||||
|
||||
b.Property<string>("EyeColor")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("eye_color");
|
||||
|
||||
b.Property<string>("FacialHairColor")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("facial_hair_color");
|
||||
|
||||
b.Property<string>("FacialHairName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("facial_hair_name");
|
||||
|
||||
b.Property<string>("Gender")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("gender");
|
||||
|
||||
b.Property<string>("HairColor")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("hair_color");
|
||||
|
||||
b.Property<string>("HairName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("hair_name");
|
||||
|
||||
b.Property<int>("PreferenceId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("preference_id");
|
||||
|
||||
b.Property<int>("PreferenceUnavailable")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("pref_unavailable");
|
||||
|
||||
b.Property<string>("Sex")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("sex");
|
||||
|
||||
b.Property<string>("SkinColor")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("skin_color");
|
||||
|
||||
b.Property<int>("Slot")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("slot");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PreferenceId");
|
||||
|
||||
b.HasIndex("Slot", "PreferenceId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("profile");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.SqliteConnectionLog", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("connection_log_id");
|
||||
|
||||
b.Property<string>("Address")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("address");
|
||||
|
||||
b.Property<DateTime>("Time")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("time");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("user_name");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("connection_log");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.SqlitePlayer", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("player_id");
|
||||
|
||||
b.Property<DateTime>("FirstSeenTime")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("first_seen_time");
|
||||
|
||||
b.Property<string>("LastSeenAddress")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("last_seen_address");
|
||||
|
||||
b.Property<DateTime>("LastSeenTime")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("last_seen_time");
|
||||
|
||||
b.Property<string>("LastSeenUserName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("last_seen_user_name");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("LastSeenUserName");
|
||||
|
||||
b.ToTable("player");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.SqliteServerBan", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("ban_id");
|
||||
|
||||
b.Property<string>("Address")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("address");
|
||||
|
||||
b.Property<DateTime>("BanTime")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("ban_time");
|
||||
|
||||
b.Property<Guid?>("BanningAdmin")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("banning_admin");
|
||||
|
||||
b.Property<DateTime?>("ExpirationTime")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("expiration_time");
|
||||
|
||||
b.Property<string>("Reason")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("reason");
|
||||
|
||||
b.Property<Guid?>("UserId")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ban");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.SqliteServerUnban", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("unban_id");
|
||||
|
||||
b.Property<int>("BanId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("ban_id");
|
||||
|
||||
b.Property<DateTime>("UnbanTime")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("unban_time");
|
||||
|
||||
b.Property<Guid?>("UnbanningAdmin")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("unbanning_admin");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BanId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("unban");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.AdminRank", "AdminRank")
|
||||
.WithMany("Admins")
|
||||
.HasForeignKey("AdminRankId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.Navigation("AdminRank");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.Admin", "Admin")
|
||||
.WithMany("Flags")
|
||||
.HasForeignKey("AdminId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Admin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.AdminRank", "Rank")
|
||||
.WithMany("Flags")
|
||||
.HasForeignKey("AdminRankId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Rank");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||
.WithMany("Antags")
|
||||
.HasForeignKey("ProfileId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Profile");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||
.WithMany("Jobs")
|
||||
.HasForeignKey("ProfileId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Profile");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.Preference", "Preference")
|
||||
.WithMany("Profiles")
|
||||
.HasForeignKey("PreferenceId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Preference");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.SqliteServerUnban", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.SqliteServerBan", "Ban")
|
||||
.WithOne("Unban")
|
||||
.HasForeignKey("Content.Server.Database.SqliteServerUnban", "BanId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Ban");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||
{
|
||||
b.Navigation("Flags");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminRank", b =>
|
||||
{
|
||||
b.Navigation("Admins");
|
||||
|
||||
b.Navigation("Flags");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Preference", b =>
|
||||
{
|
||||
b.Navigation("Profiles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||
{
|
||||
b.Navigation("Antags");
|
||||
|
||||
b.Navigation("Jobs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.SqliteServerBan", b =>
|
||||
{
|
||||
b.Navigation("Unban");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Content.Server.Database.Migrations.Sqlite
|
||||
{
|
||||
public partial class BackpackPreference : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "backpack",
|
||||
table: "profile",
|
||||
type: "TEXT",
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "backpack",
|
||||
table: "profile");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,6 +223,11 @@ namespace Content.Server.Database.Migrations.Sqlite
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("age");
|
||||
|
||||
b.Property<string>("Backpack")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("backpack");
|
||||
|
||||
b.Property<string>("CharacterName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
@@ -99,6 +99,7 @@ namespace Content.Server.Database
|
||||
[Column("eye_color")] public string EyeColor { get; set; } = null!;
|
||||
[Column("skin_color")] public string SkinColor { get; set; } = null!;
|
||||
[Column("clothing")] public string Clothing { get; set; } = null!;
|
||||
[Column("backpack")] public string Backpack { get; set; } = null!;
|
||||
public List<Job> Jobs { get; } = new();
|
||||
public List<Antag> Antags { get; } = new();
|
||||
|
||||
|
||||
@@ -5,38 +5,36 @@ namespace Content.Server.AI.Operators
|
||||
{
|
||||
public abstract class AiOperator
|
||||
{
|
||||
public bool HasStartup => _hasStartup;
|
||||
private bool _hasStartup = false;
|
||||
private bool _hasShutdown = false;
|
||||
public bool HasStartup { get; private set; }
|
||||
|
||||
public bool HasShutdown { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Called once when the AiLogicProcessor starts this action
|
||||
/// </summary>
|
||||
public virtual bool TryStartup()
|
||||
/// <returns>true if it hasn't started up previously</returns>
|
||||
public virtual bool Startup()
|
||||
{
|
||||
// If we've already startup then no point continuing
|
||||
// This signals to the override that it's already startup
|
||||
// Should probably throw but it made some code elsewhere marginally easier
|
||||
if (_hasStartup)
|
||||
{
|
||||
if (HasStartup)
|
||||
return false;
|
||||
}
|
||||
|
||||
_hasStartup = true;
|
||||
|
||||
HasStartup = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called once when the AiLogicProcessor is done with this action if the outcome is successful or fails.
|
||||
/// </summary>
|
||||
public virtual void Shutdown(Outcome outcome)
|
||||
public virtual bool Shutdown(Outcome outcome)
|
||||
{
|
||||
if (_hasShutdown)
|
||||
{
|
||||
throw new InvalidOperationException("AiOperator has already shutdown");
|
||||
}
|
||||
if (HasShutdown)
|
||||
return false;
|
||||
|
||||
_hasShutdown = true;
|
||||
HasShutdown = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -53,4 +51,4 @@ namespace Content.Server.AI.Operators
|
||||
Continuing,
|
||||
Failed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,9 @@ namespace Content.Server.AI.Operators.Combat.Melee
|
||||
_burstTime = burstTime;
|
||||
}
|
||||
|
||||
public override bool TryStartup()
|
||||
public override bool Startup()
|
||||
{
|
||||
if (!base.TryStartup())
|
||||
if (!base.Startup())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -42,13 +42,17 @@ namespace Content.Server.AI.Operators.Combat.Melee
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Shutdown(Outcome outcome)
|
||||
public override bool Shutdown(Outcome outcome)
|
||||
{
|
||||
base.Shutdown(outcome);
|
||||
if (!base.Shutdown(outcome))
|
||||
return false;
|
||||
|
||||
if (_owner.TryGetComponent(out CombatModeComponent combatModeComponent))
|
||||
{
|
||||
combatModeComponent.IsInCombatMode = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override Outcome Execute(float frameTime)
|
||||
|
||||
@@ -22,9 +22,9 @@ namespace Content.Server.AI.Operators.Combat.Melee
|
||||
_burstTime = burstTime;
|
||||
}
|
||||
|
||||
public override bool TryStartup()
|
||||
public override bool Startup()
|
||||
{
|
||||
if (!base.TryStartup())
|
||||
if (!base.Startup())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -51,13 +51,17 @@ namespace Content.Server.AI.Operators.Combat.Melee
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Shutdown(Outcome outcome)
|
||||
public override bool Shutdown(Outcome outcome)
|
||||
{
|
||||
base.Shutdown(outcome);
|
||||
if (!base.Shutdown(outcome))
|
||||
return false;
|
||||
|
||||
if (_owner.TryGetComponent(out CombatModeComponent combatModeComponent))
|
||||
{
|
||||
combatModeComponent.IsInCombatMode = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override Outcome Execute(float frameTime)
|
||||
|
||||
@@ -21,9 +21,9 @@ namespace Content.Server.AI.Operators.Inventory
|
||||
_owner = owner;
|
||||
}
|
||||
|
||||
public override bool TryStartup()
|
||||
public override bool Startup()
|
||||
{
|
||||
if (!base.TryStartup())
|
||||
if (!base.Startup())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -40,12 +40,15 @@ namespace Content.Server.AI.Operators.Inventory
|
||||
return _target != null;
|
||||
}
|
||||
|
||||
public override void Shutdown(Outcome outcome)
|
||||
public override bool Shutdown(Outcome outcome)
|
||||
{
|
||||
base.Shutdown(outcome);
|
||||
if (!base.Shutdown(outcome))
|
||||
return false;
|
||||
|
||||
var blackboard = UtilityAiHelpers.GetBlackboard(_owner);
|
||||
|
||||
blackboard?.GetState<LastOpenedStorageState>().SetValue(null);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override Outcome Execute(float frameTime)
|
||||
|
||||
@@ -32,9 +32,9 @@ namespace Content.Server.AI.Operators.Movement
|
||||
_requiresInRangeUnobstructed = requiresInRangeUnobstructed;
|
||||
}
|
||||
|
||||
public override bool TryStartup()
|
||||
public override bool Startup()
|
||||
{
|
||||
if (!base.TryStartup())
|
||||
if (!base.Startup())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -45,11 +45,14 @@ namespace Content.Server.AI.Operators.Movement
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Shutdown(Outcome outcome)
|
||||
public override bool Shutdown(Outcome outcome)
|
||||
{
|
||||
base.Shutdown(outcome);
|
||||
if (!base.Shutdown(outcome))
|
||||
return false;
|
||||
|
||||
var steering = EntitySystem.Get<AiSteeringSystem>();
|
||||
steering.Unregister(_owner);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override Outcome Execute(float frameTime)
|
||||
|
||||
@@ -21,9 +21,9 @@ namespace Content.Server.AI.Operators.Movement
|
||||
DesiredRange = desiredRange;
|
||||
}
|
||||
|
||||
public override bool TryStartup()
|
||||
public override bool Startup()
|
||||
{
|
||||
if (!base.TryStartup())
|
||||
if (!base.Startup())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -34,11 +34,14 @@ namespace Content.Server.AI.Operators.Movement
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Shutdown(Outcome outcome)
|
||||
public override bool Shutdown(Outcome outcome)
|
||||
{
|
||||
base.Shutdown(outcome);
|
||||
if (!base.Shutdown(outcome))
|
||||
return false;
|
||||
|
||||
var steering = EntitySystem.Get<AiSteeringSystem>();
|
||||
steering.Unregister(_owner);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override Outcome Execute(float frameTime)
|
||||
|
||||
@@ -17,9 +17,9 @@ namespace Content.Server.AI.Operators.Sequences
|
||||
{
|
||||
return Outcome.Success;
|
||||
}
|
||||
|
||||
|
||||
var op = Sequence.Peek();
|
||||
op.TryStartup();
|
||||
op.Startup();
|
||||
var outcome = op.Execute(frameTime);
|
||||
|
||||
switch (outcome)
|
||||
@@ -35,10 +35,10 @@ namespace Content.Server.AI.Operators.Sequences
|
||||
op.Shutdown(outcome);
|
||||
Sequence.Clear();
|
||||
return Outcome.Failed;
|
||||
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace Content.Server.AI.Utility.Actions
|
||||
{
|
||||
Owner = owner;
|
||||
}
|
||||
|
||||
|
||||
public virtual void Shutdown() {}
|
||||
|
||||
/// <summary>
|
||||
@@ -78,7 +78,7 @@ namespace Content.Server.AI.Utility.Actions
|
||||
return Outcome.Success;
|
||||
}
|
||||
|
||||
op.TryStartup();
|
||||
op.Startup();
|
||||
var outcome = op.Execute(frameTime);
|
||||
|
||||
switch (outcome)
|
||||
@@ -116,7 +116,7 @@ namespace Content.Server.AI.Utility.Actions
|
||||
// Overall structure is based on Building a better centaur
|
||||
// Ideally we should early-out each action as cheaply as possible if it's not valid, thus
|
||||
// the finalScore can only go down over time.
|
||||
|
||||
|
||||
var finalScore = 1.0f;
|
||||
var minThreshold = min / Bonus;
|
||||
context.GetState<ConsiderationState>().SetValue(considerations.Count);
|
||||
|
||||
@@ -137,6 +137,8 @@ namespace Content.Server.AI.Utility.AiLogic
|
||||
{
|
||||
var currentOp = CurrentAction?.ActionOperators.Peek();
|
||||
currentOp?.Shutdown(Outcome.Failed);
|
||||
CurrentAction?.Shutdown();
|
||||
CurrentAction = null;
|
||||
}
|
||||
|
||||
public void MobStateChanged(MobStateChangedMessage message)
|
||||
|
||||
89
Content.Server/Actions/DisarmAction.cs
Normal file
89
Content.Server/Actions/DisarmAction.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.Components.GUI;
|
||||
using Content.Server.GameObjects.Components.Mobs;
|
||||
using Content.Server.GameObjects.Components.Pulling;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Server.Utility;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Content.Shared.GameObjects.Components.Pulling;
|
||||
using Content.Shared.GameObjects.EntitySystems.ActionBlocker;
|
||||
using Content.Shared.Interfaces;
|
||||
using Content.Shared.Utility;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Server.Interfaces.Player;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameObjects.Systems;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Random;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Server.Actions
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class DisarmAction : ITargetEntityAction
|
||||
{
|
||||
private float _failProb;
|
||||
private float _pushProb;
|
||||
private float _cooldown;
|
||||
|
||||
public void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
serializer.DataField(ref _failProb, "failProb", 0.4f);
|
||||
serializer.DataField(ref _pushProb, "pushProb", 0.4f);
|
||||
serializer.DataField(ref _cooldown, "cooldown", 1.5f);
|
||||
}
|
||||
|
||||
public void DoTargetEntityAction(TargetEntityActionEventArgs args)
|
||||
{
|
||||
var disarmedActs = args.Target.GetAllComponents<IDisarmedAct>().ToArray();
|
||||
|
||||
if (disarmedActs.Length == 0 || !args.Performer.InRangeUnobstructed(args.Target)) return;
|
||||
if (!args.Performer.TryGetComponent<SharedActionsComponent>(out var actions)) return;
|
||||
if (args.Target == args.Performer || !args.Performer.CanAttack()) return;
|
||||
|
||||
var random = IoCManager.Resolve<IRobustRandom>();
|
||||
var audio = EntitySystem.Get<AudioSystem>();
|
||||
var system = EntitySystem.Get<MeleeWeaponSystem>();
|
||||
|
||||
var angle = new Angle(args.Target.Transform.MapPosition.Position - args.Performer.Transform.MapPosition.Position);
|
||||
|
||||
actions.Cooldown(ActionType.Disarm, Cooldowns.SecondsFromNow(_cooldown));
|
||||
|
||||
if (random.Prob(_failProb))
|
||||
{
|
||||
audio.PlayFromEntity("/Audio/Weapons/punchmiss.ogg", args.Performer,
|
||||
AudioHelpers.WithVariation(0.025f));
|
||||
args.Performer.PopupMessageOtherClients(Loc.GetString("{0} fails to disarm {1}!", args.Performer.Name, args.Target.Name));
|
||||
args.Performer.PopupMessageCursor(Loc.GetString("You fail to disarm {0}!", args.Target.Name));
|
||||
system.SendLunge(angle, args.Performer);
|
||||
return;
|
||||
}
|
||||
|
||||
system.SendAnimation("disarm", angle, args.Performer, args.Performer, new []{ args.Target });
|
||||
|
||||
var eventArgs = new DisarmedActEventArgs() {Target = args.Target, Source = args.Performer, PushProbability = _pushProb};
|
||||
|
||||
// Sort by priority.
|
||||
Array.Sort(disarmedActs, (a, b) => a.Priority.CompareTo(b.Priority));
|
||||
|
||||
foreach (var disarmedAct in disarmedActs)
|
||||
{
|
||||
if (disarmedAct.Disarmed(eventArgs))
|
||||
return;
|
||||
}
|
||||
|
||||
audio.PlayFromEntity("/Audio/Effects/thudswoosh.ogg", args.Performer,
|
||||
AudioHelpers.WithVariation(0.025f));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using Content.Server.GameObjects.Components.Observer;
|
||||
using Content.Server.Commands.Observer;
|
||||
using Content.Server.GameObjects.Components.Observer;
|
||||
using Content.Server.Interfaces.GameTicking;
|
||||
using Content.Server.Players;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Server.Interfaces.Console;
|
||||
@@ -23,14 +25,15 @@ namespace Content.Server.Administration.Commands
|
||||
return;
|
||||
}
|
||||
|
||||
var mind = player.ContentData().Mind;
|
||||
var mind = player.ContentData()?.Mind;
|
||||
|
||||
if (mind == null)
|
||||
{
|
||||
shell.SendText(player, "You can't ghost here!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mind.VisitingEntity != null && mind.VisitingEntity.Prototype.ID == "AdminObserver")
|
||||
if (mind.VisitingEntity != null && mind.VisitingEntity.Prototype?.ID == "AdminObserver")
|
||||
{
|
||||
var visiting = mind.VisitingEntity;
|
||||
mind.UnVisit();
|
||||
@@ -38,13 +41,22 @@ namespace Content.Server.Administration.Commands
|
||||
}
|
||||
else
|
||||
{
|
||||
var canReturn = mind.CurrentEntity != null && !mind.CurrentEntity.HasComponent<GhostComponent>();
|
||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||
var ghost = entityManager.SpawnEntity("AdminObserver", player.AttachedEntity.Transform.MapPosition);
|
||||
if(canReturn)
|
||||
var canReturn = mind.CurrentEntity != null;
|
||||
var ghost = IoCManager.Resolve<IEntityManager>()
|
||||
.SpawnEntity("AdminObserver", player.AttachedEntity?.Transform.Coordinates
|
||||
?? IoCManager.Resolve<IGameTicker>().GetObserverSpawnPoint());
|
||||
|
||||
if (canReturn)
|
||||
{
|
||||
ghost.Name = mind.CharacterName;
|
||||
mind.Visit(ghost);
|
||||
}
|
||||
else
|
||||
{
|
||||
ghost.Name = player.Name;
|
||||
mind.TransferTo(ghost);
|
||||
}
|
||||
|
||||
ghost.GetComponent<GhostComponent>().CanReturnToBody = canReturn;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user