Merge branch 'master' into 2020-04-28-tool-component
This commit is contained in:
@@ -19,6 +19,12 @@ namespace Content.Client.Chat
|
||||
{
|
||||
internal sealed class ChatManager : IChatManager
|
||||
{
|
||||
private struct SpeechBubbleData
|
||||
{
|
||||
public string Message;
|
||||
public SpeechBubble.SpeechType Type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The max amount of chars allowed to fit in a single speech bubble.
|
||||
/// </summary>
|
||||
@@ -117,7 +123,7 @@ namespace Content.Client.Chat
|
||||
|
||||
var msg = queueData.MessageQueue.Dequeue();
|
||||
|
||||
queueData.TimeLeft += BubbleDelayBase + msg.Length * BubbleDelayFactor;
|
||||
queueData.TimeLeft += BubbleDelayBase + msg.Message.Length * BubbleDelayFactor;
|
||||
|
||||
// We keep the queue around while it has 0 items. This allows us to keep the timer.
|
||||
// When the timer hits 0 and there's no messages left, THEN we can clear it up.
|
||||
@@ -211,19 +217,19 @@ namespace Content.Client.Chat
|
||||
case OOCAlias:
|
||||
{
|
||||
var conInput = text.Substring(1);
|
||||
_console.ProcessCommand($"ooc \"{conInput}\"");
|
||||
_console.ProcessCommand($"ooc \"{CommandParsing.Escape(conInput)}\"");
|
||||
break;
|
||||
}
|
||||
case MeAlias:
|
||||
{
|
||||
var conInput = text.Substring(1);
|
||||
_console.ProcessCommand($"me \"{conInput}\"");
|
||||
_console.ProcessCommand($"me \"{CommandParsing.Escape(conInput)}\"");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
var conInput = _currentChatBox.DefaultChatFormat != null
|
||||
? string.Format(_currentChatBox.DefaultChatFormat, text)
|
||||
? string.Format(_currentChatBox.DefaultChatFormat, CommandParsing.Escape(text))
|
||||
: text;
|
||||
_console.ProcessCommand(conInput);
|
||||
break;
|
||||
@@ -291,13 +297,23 @@ namespace Content.Client.Chat
|
||||
WriteChatMessage(storedMessage);
|
||||
|
||||
// Local messages that have an entity attached get a speech bubble.
|
||||
if ((msg.Channel == ChatChannel.Local || msg.Channel == ChatChannel.Dead) && msg.SenderEntity != default)
|
||||
if (msg.SenderEntity == default)
|
||||
return;
|
||||
|
||||
switch (msg.Channel)
|
||||
{
|
||||
AddSpeechBubble(msg);
|
||||
case ChatChannel.Local:
|
||||
case ChatChannel.Dead:
|
||||
AddSpeechBubble(msg, SpeechBubble.SpeechType.Say);
|
||||
break;
|
||||
|
||||
case ChatChannel.Emotes:
|
||||
AddSpeechBubble(msg, SpeechBubble.SpeechType.Emote);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void AddSpeechBubble(MsgChatMessage msg)
|
||||
private void AddSpeechBubble(MsgChatMessage msg, SpeechBubble.SpeechType speechType)
|
||||
{
|
||||
if (!_entityManager.TryGetEntity(msg.SenderEntity, out var entity))
|
||||
{
|
||||
@@ -305,8 +321,18 @@ namespace Content.Client.Chat
|
||||
return;
|
||||
}
|
||||
|
||||
var messages = SplitMessage(msg.Message);
|
||||
|
||||
foreach (var message in messages)
|
||||
{
|
||||
EnqueueSpeechBubble(entity, message, speechType);
|
||||
}
|
||||
}
|
||||
|
||||
private List<string> SplitMessage(string msg)
|
||||
{
|
||||
// Split message into words separated by spaces.
|
||||
var words = msg.Message.Split(' ');
|
||||
var words = msg.Split(' ');
|
||||
var messages = new List<string>();
|
||||
var currentBuffer = new List<string>();
|
||||
|
||||
@@ -346,13 +372,10 @@ namespace Content.Client.Chat
|
||||
messages.Add(string.Join(" ", currentBuffer));
|
||||
}
|
||||
|
||||
foreach (var message in messages)
|
||||
{
|
||||
EnqueueSpeechBubble(entity, message);
|
||||
}
|
||||
return messages;
|
||||
}
|
||||
|
||||
private void EnqueueSpeechBubble(IEntity entity, string contents)
|
||||
private void EnqueueSpeechBubble(IEntity entity, string contents, SpeechBubble.SpeechType speechType)
|
||||
{
|
||||
if (!_queuedSpeechBubbles.TryGetValue(entity.Uid, out var queueData))
|
||||
{
|
||||
@@ -360,12 +383,16 @@ namespace Content.Client.Chat
|
||||
_queuedSpeechBubbles.Add(entity.Uid, queueData);
|
||||
}
|
||||
|
||||
queueData.MessageQueue.Enqueue(contents);
|
||||
queueData.MessageQueue.Enqueue(new SpeechBubbleData
|
||||
{
|
||||
Message = contents,
|
||||
Type = speechType,
|
||||
});
|
||||
}
|
||||
|
||||
private void CreateSpeechBubble(IEntity entity, string contents)
|
||||
private void CreateSpeechBubble(IEntity entity, SpeechBubbleData speechData)
|
||||
{
|
||||
var bubble = new SpeechBubble(contents, entity, _eyeManager, this);
|
||||
var bubble = SpeechBubble.CreateSpeechBubble(speechData.Type, speechData.Message, entity, _eyeManager, this);
|
||||
|
||||
if (_activeSpeechBubbles.TryGetValue(entity.Uid, out var existing))
|
||||
{
|
||||
@@ -405,7 +432,7 @@ namespace Content.Client.Chat
|
||||
/// </summary>
|
||||
public float TimeLeft { get; set; }
|
||||
|
||||
public Queue<string> MessageQueue { get; } = new Queue<string>();
|
||||
public Queue<SpeechBubbleData> MessageQueue { get; } = new Queue<SpeechBubbleData>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Client.Interfaces.Chat;
|
||||
using System;
|
||||
using Content.Client.Interfaces.Chat;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
@@ -9,8 +10,14 @@ using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client.Chat
|
||||
{
|
||||
public class SpeechBubble : Control
|
||||
public abstract class SpeechBubble : Control
|
||||
{
|
||||
public enum SpeechType
|
||||
{
|
||||
Emote,
|
||||
Say
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The total time a speech bubble stays on screen.
|
||||
/// </summary>
|
||||
@@ -38,6 +45,21 @@ namespace Content.Client.Chat
|
||||
|
||||
public float ContentHeight { get; private set; }
|
||||
|
||||
public static SpeechBubble CreateSpeechBubble(SpeechType type, string text, IEntity senderEntity, IEyeManager eyeManager, IChatManager chatManager)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case SpeechType.Emote:
|
||||
return new EmoteSpeechBubble(text, senderEntity, eyeManager, chatManager);
|
||||
|
||||
case SpeechType.Say:
|
||||
return new SaySpeechBubble(text, senderEntity, eyeManager, chatManager);
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public SpeechBubble(string text, IEntity senderEntity, IEyeManager eyeManager, IChatManager chatManager)
|
||||
{
|
||||
_chatManager = chatManager;
|
||||
@@ -47,27 +69,18 @@ namespace Content.Client.Chat
|
||||
// Use text clipping so new messages don't overlap old ones being pushed up.
|
||||
RectClipContent = true;
|
||||
|
||||
var label = new RichTextLabel
|
||||
{
|
||||
MaxWidth = 256,
|
||||
};
|
||||
label.SetMessage(text);
|
||||
var bubble = BuildBubble(text);
|
||||
|
||||
var panel = new PanelContainer
|
||||
{
|
||||
StyleClasses = { "tooltipBox" },
|
||||
Children = { label },
|
||||
ModulateSelfOverride = Color.White.WithAlpha(0.75f)
|
||||
};
|
||||
|
||||
AddChild(panel);
|
||||
AddChild(bubble);
|
||||
|
||||
ForceRunStyleUpdate();
|
||||
|
||||
ContentHeight = panel.CombinedMinimumSize.Y;
|
||||
ContentHeight = bubble.CombinedMinimumSize.Y;
|
||||
_verticalOffsetAchieved = -ContentHeight;
|
||||
}
|
||||
|
||||
protected abstract Control BuildBubble(string text);
|
||||
|
||||
protected override Vector2 CalculateMinimumSize()
|
||||
{
|
||||
return (base.CalculateMinimumSize().X, 0);
|
||||
@@ -134,4 +147,57 @@ namespace Content.Client.Chat
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class EmoteSpeechBubble : SpeechBubble
|
||||
|
||||
{
|
||||
public EmoteSpeechBubble(string text, IEntity senderEntity, IEyeManager eyeManager, IChatManager chatManager)
|
||||
: base(text, senderEntity, eyeManager, chatManager)
|
||||
{
|
||||
}
|
||||
|
||||
protected override Control BuildBubble(string text)
|
||||
{
|
||||
var label = new RichTextLabel
|
||||
{
|
||||
MaxWidth = 256,
|
||||
};
|
||||
label.SetMessage(text);
|
||||
|
||||
var panel = new PanelContainer
|
||||
{
|
||||
StyleClasses = { "speechBox", "emoteBox" },
|
||||
Children = { label },
|
||||
ModulateSelfOverride = Color.White.WithAlpha(0.75f)
|
||||
};
|
||||
|
||||
return panel;
|
||||
}
|
||||
}
|
||||
|
||||
public class SaySpeechBubble : SpeechBubble
|
||||
{
|
||||
public SaySpeechBubble(string text, IEntity senderEntity, IEyeManager eyeManager, IChatManager chatManager)
|
||||
: base(text, senderEntity, eyeManager, chatManager)
|
||||
{
|
||||
}
|
||||
|
||||
protected override Control BuildBubble(string text)
|
||||
{
|
||||
var label = new RichTextLabel
|
||||
{
|
||||
MaxWidth = 256,
|
||||
};
|
||||
label.SetMessage(text);
|
||||
|
||||
var panel = new PanelContainer
|
||||
{
|
||||
StyleClasses = { "speechBox", "sayBox" },
|
||||
Children = { label },
|
||||
ModulateSelfOverride = Color.White.WithAlpha(0.75f)
|
||||
};
|
||||
|
||||
return panel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace Content.Client
|
||||
IoCManager.Register<IClientPreferencesManager, ClientPreferencesManager>();
|
||||
IoCManager.Register<IItemSlotManager, ItemSlotManager>();
|
||||
IoCManager.Register<IStylesheetManager, StylesheetManager>();
|
||||
IoCManager.Register<IScreenshotHook, ScreenshotHook>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Client.Interfaces;
|
||||
using Content.Client.UserInterface.Stylesheets;
|
||||
using Content.Shared;
|
||||
using Robust.Client.Interfaces.Console;
|
||||
using Robust.Client.Interfaces.Graphics.ClientEye;
|
||||
@@ -57,7 +58,11 @@ namespace Content.Client
|
||||
|
||||
public void PopupMessage(ScreenCoordinates coordinates, string message)
|
||||
{
|
||||
var label = new PopupLabel {Text = message};
|
||||
var label = new PopupLabel
|
||||
{
|
||||
Text = message,
|
||||
StyleClasses = { StyleNano.StyleClassPopupMessage },
|
||||
};
|
||||
var minimumSize = label.CombinedMinimumSize;
|
||||
LayoutContainer.SetPosition(label, label.InitialPos = coordinates.Position - minimumSize / 2);
|
||||
_userInterfaceManager.PopupRoot.AddChild(label);
|
||||
|
||||
@@ -12,9 +12,11 @@ using Content.Client.UserInterface.Stylesheets;
|
||||
using Content.Shared.GameObjects.Components;
|
||||
using Content.Shared.GameObjects.Components.Cargo;
|
||||
using Content.Shared.GameObjects.Components.Chemistry;
|
||||
using Content.Shared.GameObjects.Components.Gravity;
|
||||
using Content.Shared.GameObjects.Components.Markers;
|
||||
using Content.Shared.GameObjects.Components.Research;
|
||||
using Content.Shared.GameObjects.Components.VendingMachines;
|
||||
using Content.Shared.Kitchen;
|
||||
using Robust.Client;
|
||||
using Robust.Client.Interfaces;
|
||||
using Robust.Client.Interfaces.Graphics.Overlays;
|
||||
@@ -142,7 +144,7 @@ namespace Content.Client
|
||||
"Mop",
|
||||
"Bucket",
|
||||
"Puddle",
|
||||
"CanSpill",
|
||||
"CanSpill"
|
||||
};
|
||||
|
||||
foreach (var ignoreName in registerIgnore)
|
||||
@@ -160,6 +162,8 @@ namespace Content.Client
|
||||
factory.Register<SharedWiresComponent>();
|
||||
factory.Register<SharedCargoConsoleComponent>();
|
||||
factory.Register<SharedReagentDispenserComponent>();
|
||||
factory.Register<SharedMicrowaveComponent>();
|
||||
factory.Register<SharedGravityGeneratorComponent>();
|
||||
|
||||
prototypes.RegisterIgnore("material");
|
||||
prototypes.RegisterIgnore("reaction"); //Chemical reactions only needed by server. Reactions checks are server-side.
|
||||
@@ -178,6 +182,7 @@ namespace Content.Client
|
||||
IoCManager.Resolve<IParallaxManager>().LoadParallax();
|
||||
IoCManager.Resolve<IBaseClient>().PlayerJoinedServer += SubscribePlayerAttachmentEvents;
|
||||
IoCManager.Resolve<IStylesheetManager>().Initialize();
|
||||
IoCManager.Resolve<IScreenshotHook>().Initialize();
|
||||
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
using System;
|
||||
using Content.Shared.GameObjects.Components.Gravity;
|
||||
using Robust.Client.GameObjects.Components.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Gravity
|
||||
{
|
||||
public class GravityGeneratorBoundUserInterface: BoundUserInterface
|
||||
{
|
||||
private GravityGeneratorWindow _window;
|
||||
|
||||
public bool IsOn;
|
||||
|
||||
public GravityGeneratorBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base (owner, uiKey)
|
||||
{
|
||||
SendMessage(new SharedGravityGeneratorComponent.GeneratorStatusRequestMessage());
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
IsOn = false;
|
||||
|
||||
_window = new GravityGeneratorWindow(this);
|
||||
|
||||
_window.Switch.OnPressed += (args) =>
|
||||
{
|
||||
SendMessage(new SharedGravityGeneratorComponent.SwitchGeneratorMessage(!IsOn));
|
||||
SendMessage(new SharedGravityGeneratorComponent.GeneratorStatusRequestMessage());
|
||||
};
|
||||
|
||||
_window.OpenCentered();
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
|
||||
var castState = (SharedGravityGeneratorComponent.GeneratorState) state;
|
||||
IsOn = castState.On;
|
||||
_window.UpdateButton();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (!disposing) return;
|
||||
|
||||
_window?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public class GravityGeneratorWindow : SS14Window
|
||||
{
|
||||
public Label Status;
|
||||
|
||||
public Button Switch;
|
||||
|
||||
public GravityGeneratorBoundUserInterface Owner;
|
||||
|
||||
public GravityGeneratorWindow(GravityGeneratorBoundUserInterface gravityGeneratorInterface = null)
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
Owner = gravityGeneratorInterface;
|
||||
|
||||
Title = Loc.GetString("Gravity Generator Control");
|
||||
|
||||
var vBox = new VBoxContainer
|
||||
{
|
||||
CustomMinimumSize = new Vector2(250, 100)
|
||||
};
|
||||
Status = new Label
|
||||
{
|
||||
Text = Loc.GetString("Current Status: " + (Owner.IsOn ? "On" : "Off")),
|
||||
FontColorOverride = Owner.IsOn ? Color.ForestGreen : Color.Red
|
||||
};
|
||||
Switch = new Button
|
||||
{
|
||||
Text = Loc.GetString(Owner.IsOn ? "Turn Off" : "Turn On"),
|
||||
TextAlign = Label.AlignMode.Center,
|
||||
CustomMinimumSize = new Vector2(150, 60)
|
||||
};
|
||||
|
||||
vBox.AddChild(Status);
|
||||
vBox.AddChild(Switch);
|
||||
|
||||
Contents.AddChild(vBox);
|
||||
}
|
||||
|
||||
public void UpdateButton()
|
||||
{
|
||||
Status.Text = Loc.GetString("Current Status: " + (Owner.IsOn ? "On" : "Off"));
|
||||
Status.FontColorOverride = Owner.IsOn ? Color.ForestGreen : Color.Red;
|
||||
Switch.Text = Loc.GetString(Owner.IsOn ? "Turn Off" : "Turn On");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,13 +114,13 @@ namespace Content.Client.GameObjects
|
||||
}
|
||||
}
|
||||
|
||||
protected override void HandleInventoryKeybind(BaseButton.ButtonEventArgs args, Slots slot)
|
||||
protected override void HandleInventoryKeybind(GUIBoundKeyEventArgs args, Slots slot)
|
||||
{
|
||||
if (!_inventoryButtons.TryGetValue(slot, out var buttons))
|
||||
return;
|
||||
if (!Owner.TryGetSlot(slot, out var item))
|
||||
return;
|
||||
if (_itemSlotManager.OnButtonPressed(args.Event, item))
|
||||
if (_itemSlotManager.OnButtonPressed(args, item))
|
||||
return;
|
||||
|
||||
base.HandleInventoryKeybind(args, slot);
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Shared.GameObjects.Components.Inventory;
|
||||
using Content.Shared.Input;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
@@ -62,39 +63,35 @@ namespace Content.Client.GameObjects
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void HandleInventoryKeybind(BaseButton.ButtonEventArgs args, EquipmentSlotDefines.Slots slot)
|
||||
protected virtual void HandleInventoryKeybind(GUIBoundKeyEventArgs args, EquipmentSlotDefines.Slots slot)
|
||||
{
|
||||
if (args.Event.CanFocus)
|
||||
if (args.Function == EngineKeyFunctions.UIClick)
|
||||
{
|
||||
UseItemOnInventory(args, slot);
|
||||
UseItemOnInventory(slot);
|
||||
}
|
||||
}
|
||||
|
||||
protected void AddToInventory(BaseButton.ButtonEventArgs args, EquipmentSlotDefines.Slots slot)
|
||||
protected void AddToInventory(GUIBoundKeyEventArgs args, EquipmentSlotDefines.Slots slot)
|
||||
{
|
||||
if (!args.Event.CanFocus)
|
||||
if (args.Function != EngineKeyFunctions.UIClick)
|
||||
{
|
||||
return;
|
||||
}
|
||||
args.Button.Pressed = false;
|
||||
|
||||
Owner.SendEquipMessage(slot);
|
||||
}
|
||||
|
||||
protected void UseItemOnInventory(BaseButton.ButtonEventArgs args, EquipmentSlotDefines.Slots slot)
|
||||
protected void UseItemOnInventory(EquipmentSlotDefines.Slots slot)
|
||||
{
|
||||
args.Button.Pressed = false;
|
||||
|
||||
Owner.SendUseMessage(slot);
|
||||
}
|
||||
|
||||
protected void OpenStorage(BaseButton.ButtonEventArgs args, EquipmentSlotDefines.Slots slot)
|
||||
protected void OpenStorage(GUIBoundKeyEventArgs args, EquipmentSlotDefines.Slots slot)
|
||||
{
|
||||
if (!args.Event.CanFocus && args.Event.Function != ContentKeyFunctions.ActivateItemInWorld)
|
||||
if (args.Function != EngineKeyFunctions.UIClick && args.Function != ContentKeyFunctions.ActivateItemInWorld)
|
||||
{
|
||||
return;
|
||||
}
|
||||
args.Button.Pressed = false;
|
||||
|
||||
Owner.SendOpenStorageUIMessage(slot);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
using Robust.Client.GameObjects.Components.UserInterface;
|
||||
using Content.Shared.Kitchen;
|
||||
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Shared.Chemistry;
|
||||
using Robust.Shared.GameObjects;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
|
||||
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Kitchen
|
||||
{
|
||||
public class MicrowaveBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IEntityManager _entityManager;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager;
|
||||
#pragma warning restore 649
|
||||
private MicrowaveMenu _menu;
|
||||
|
||||
private Dictionary<int, EntityUid> _solids = new Dictionary<int, EntityUid>();
|
||||
private Dictionary<int, Solution.ReagentQuantity> _reagents =new Dictionary<int, Solution.ReagentQuantity>();
|
||||
|
||||
public MicrowaveBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner,uiKey)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
_menu = new MicrowaveMenu(this);
|
||||
_menu.OpenCentered();
|
||||
_menu.OnClose += Close;
|
||||
_menu.StartButton.OnPressed += args => SendMessage(new SharedMicrowaveComponent.MicrowaveStartCookMessage());
|
||||
_menu.EjectButton.OnPressed += args => SendMessage(new SharedMicrowaveComponent.MicrowaveEjectMessage());
|
||||
_menu.IngredientsList.OnItemSelected += args =>
|
||||
{
|
||||
SendMessage(new SharedMicrowaveComponent.MicrowaveEjectSolidIndexedMessage(_solids[args.ItemIndex]));
|
||||
|
||||
};
|
||||
|
||||
_menu.IngredientsListReagents.OnItemSelected += args =>
|
||||
{
|
||||
SendMessage(
|
||||
new SharedMicrowaveComponent.MicrowaveVaporizeReagentIndexedMessage(_reagents[args.ItemIndex]));
|
||||
};
|
||||
|
||||
_menu.OnCookTimeSelected += args =>
|
||||
{
|
||||
var actualButton = args.Button as Button;
|
||||
var newTime = (uint) int.Parse(actualButton.Text);
|
||||
_menu.VisualCookTime = newTime;
|
||||
SendMessage(new SharedMicrowaveComponent.MicrowaveSelectCookTimeMessage(newTime));
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (!disposing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_solids?.Clear();
|
||||
_menu?.Dispose();
|
||||
}
|
||||
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
if (!(state is MicrowaveUpdateUserInterfaceState cstate))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RefreshContentsDisplay(cstate.ReagentsReagents, cstate.ContainedSolids);
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void RefreshContentsDisplay(IReadOnlyList<Solution.ReagentQuantity> reagents, List<EntityUid> solids)
|
||||
{
|
||||
_reagents.Clear();
|
||||
_menu.IngredientsListReagents.Clear();
|
||||
foreach (var reagent in reagents)
|
||||
{
|
||||
_prototypeManager.TryIndex(reagent.ReagentId, out ReagentPrototype proto);
|
||||
var reagentAdded = _menu.IngredientsListReagents.AddItem($"{reagent.Quantity} {proto.Name}");
|
||||
var reagentIndex = _menu.IngredientsListReagents.IndexOf(reagentAdded);
|
||||
_reagents.Add(reagentIndex, reagent);
|
||||
}
|
||||
|
||||
_solids.Clear();
|
||||
_menu.IngredientsList.Clear();
|
||||
foreach (var entityID in solids)
|
||||
{
|
||||
var entity = _entityManager.GetEntity(entityID);
|
||||
|
||||
if (entity.TryGetComponent(out IconComponent icon))
|
||||
{
|
||||
var solidItem = _menu.IngredientsList.AddItem(entity.Name, icon.Icon.Default);
|
||||
|
||||
var solidIndex = _menu.IngredientsList.IndexOf(solidItem);
|
||||
_solids.Add(solidIndex, entityID);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
206
Content.Client/GameObjects/Components/Kitchen/MicrowaveMenu.cs
Normal file
206
Content.Client/GameObjects/Components/Kitchen/MicrowaveMenu.cs
Normal file
@@ -0,0 +1,206 @@
|
||||
using System;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Kitchen
|
||||
{
|
||||
public class MicrowaveMenu : SS14Window
|
||||
{
|
||||
protected override Vector2? CustomSize => (512, 256);
|
||||
|
||||
private MicrowaveBoundUserInterface Owner { get; set; }
|
||||
|
||||
public event Action<BaseButton.ButtonEventArgs> OnCookTimeSelected;
|
||||
|
||||
public uint VisualCookTime = 1;
|
||||
|
||||
public Button StartButton { get;}
|
||||
public Button EjectButton { get;}
|
||||
|
||||
public PanelContainer TimerFacePlate { get; }
|
||||
|
||||
public ButtonGroup CookTimeButtonGroup { get; }
|
||||
private VBoxContainer CookTimeButtonVbox { get; }
|
||||
|
||||
public ItemList IngredientsList { get;}
|
||||
|
||||
public ItemList IngredientsListReagents { get; }
|
||||
private Label _cookTimeInfoLabel { get; }
|
||||
|
||||
public MicrowaveMenu(MicrowaveBoundUserInterface owner = null)
|
||||
{
|
||||
Owner = owner;
|
||||
Title = Loc.GetString("Microwave");
|
||||
var hSplit = new HBoxContainer
|
||||
{
|
||||
SizeFlagsHorizontal = SizeFlags.Fill,
|
||||
SizeFlagsVertical = SizeFlags.Fill
|
||||
};
|
||||
|
||||
IngredientsListReagents = new ItemList
|
||||
{
|
||||
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
SelectMode = ItemList.ItemListSelectMode.Button,
|
||||
SizeFlagsStretchRatio = 2,
|
||||
CustomMinimumSize = (100,128)
|
||||
};
|
||||
|
||||
IngredientsList = new ItemList
|
||||
{
|
||||
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
SelectMode = ItemList.ItemListSelectMode.Button,
|
||||
SizeFlagsStretchRatio = 2,
|
||||
CustomMinimumSize = (100,128)
|
||||
};
|
||||
|
||||
hSplit.AddChild(IngredientsListReagents);
|
||||
//Padding between the lists.
|
||||
hSplit.AddChild(new Control
|
||||
{
|
||||
CustomMinimumSize = (0,5),
|
||||
});
|
||||
|
||||
hSplit.AddChild(IngredientsList);
|
||||
|
||||
var vSplit = new VBoxContainer
|
||||
{
|
||||
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
};
|
||||
|
||||
hSplit.AddChild(vSplit);
|
||||
|
||||
var buttonGridContainer = new VBoxContainer
|
||||
{
|
||||
Align = BoxContainer.AlignMode.Center,
|
||||
SizeFlagsStretchRatio = 3
|
||||
};
|
||||
|
||||
StartButton = new Button
|
||||
{
|
||||
Text = Loc.GetString("Start"),
|
||||
TextAlign = Label.AlignMode.Center,
|
||||
|
||||
};
|
||||
|
||||
EjectButton = new Button
|
||||
{
|
||||
Text = Loc.GetString("Eject All Contents"),
|
||||
ToolTip = Loc.GetString("This vaporizes all reagents, but ejects any solids."),
|
||||
TextAlign = Label.AlignMode.Center,
|
||||
};
|
||||
|
||||
buttonGridContainer.AddChild(StartButton);
|
||||
buttonGridContainer.AddChild(EjectButton);
|
||||
vSplit.AddChild(buttonGridContainer);
|
||||
|
||||
//Padding
|
||||
vSplit.AddChild(new Control
|
||||
{
|
||||
CustomMinimumSize = (0, 15),
|
||||
SizeFlagsVertical = SizeFlags.Fill,
|
||||
});
|
||||
|
||||
CookTimeButtonGroup = new ButtonGroup();
|
||||
CookTimeButtonVbox = new VBoxContainer
|
||||
{
|
||||
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||
Align = BoxContainer.AlignMode.Center,
|
||||
};
|
||||
|
||||
var index = 0;
|
||||
for (var i = 0; i <= 12; i++)
|
||||
{
|
||||
var newButton = new Button
|
||||
{
|
||||
Text = (index <= 0 ? 1 : index).ToString(),
|
||||
TextAlign = Label.AlignMode.Center,
|
||||
Group = CookTimeButtonGroup,
|
||||
};
|
||||
CookTimeButtonVbox.AddChild(newButton);
|
||||
newButton.OnPressed += args =>
|
||||
{
|
||||
OnCookTimeSelected?.Invoke(args);
|
||||
_cookTimeInfoLabel.Text = $"{Loc.GetString("COOK TIME")}: {VisualCookTime}";
|
||||
};
|
||||
index+=5;
|
||||
}
|
||||
|
||||
var cookTimeOneSecondButton = (Button)CookTimeButtonVbox.GetChild(0);
|
||||
cookTimeOneSecondButton.Pressed = true;
|
||||
|
||||
_cookTimeInfoLabel = new Label
|
||||
{
|
||||
Text = Loc.GetString($"COOK TIME: {VisualCookTime}"),
|
||||
Align = Label.AlignMode.Center,
|
||||
Modulate = Color.White,
|
||||
SizeFlagsVertical = SizeFlags.ShrinkCenter
|
||||
};
|
||||
|
||||
var innerTimerPanel = new PanelContainer
|
||||
{
|
||||
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||
ModulateSelfOverride = Color.Red,
|
||||
CustomMinimumSize = (100, 128),
|
||||
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.Black.WithAlpha(0.5f)},
|
||||
|
||||
Children =
|
||||
{
|
||||
|
||||
new VBoxContainer
|
||||
{
|
||||
|
||||
Children =
|
||||
{
|
||||
|
||||
new PanelContainer
|
||||
{
|
||||
PanelOverride = new StyleBoxFlat(){BackgroundColor = Color.Gray.WithAlpha(0.2f)},
|
||||
|
||||
Children =
|
||||
{
|
||||
_cookTimeInfoLabel
|
||||
}
|
||||
},
|
||||
|
||||
new ScrollContainer()
|
||||
{
|
||||
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||
|
||||
Children =
|
||||
{
|
||||
CookTimeButtonVbox,
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
TimerFacePlate = new PanelContainer()
|
||||
{
|
||||
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
Children =
|
||||
{
|
||||
|
||||
innerTimerPanel
|
||||
},
|
||||
};
|
||||
|
||||
vSplit.AddChild(TimerFacePlate);
|
||||
Contents.AddChild(hSplit);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using Content.Client.GameObjects.Components.Sound;
|
||||
using Content.Shared.GameObjects.Components.Power;
|
||||
using Content.Shared.GameObjects.Components.Sound;
|
||||
using Content.Shared.Kitchen;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Log;
|
||||
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Kitchen
|
||||
{
|
||||
public sealed class MicrowaveVisualizer : AppearanceVisualizer
|
||||
{
|
||||
private SoundComponent _soundComponent;
|
||||
private const string MicrowaveSoundLoop = "/Audio/machines/microwave_loop.ogg";
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
var sprite = component.Owner.GetComponent<ISpriteComponent>();
|
||||
_soundComponent ??= component.Owner.GetComponent<SoundComponent>();
|
||||
if (!component.TryGetData(PowerDeviceVisuals.VisualState, out MicrowaveVisualState state))
|
||||
{
|
||||
state = MicrowaveVisualState.Idle;
|
||||
}
|
||||
switch (state)
|
||||
{
|
||||
case MicrowaveVisualState.Idle:
|
||||
sprite.LayerSetState(MicrowaveVisualizerLayers.Base, "mw");
|
||||
sprite.LayerSetState(MicrowaveVisualizerLayers.BaseUnlit, "mw_unlit");
|
||||
_soundComponent.StopAllSounds();
|
||||
break;
|
||||
|
||||
case MicrowaveVisualState.Cooking:
|
||||
sprite.LayerSetState(MicrowaveVisualizerLayers.Base, "mw");
|
||||
sprite.LayerSetState(MicrowaveVisualizerLayers.BaseUnlit, "mw_running_unlit");
|
||||
var audioParams = AudioParams.Default;
|
||||
audioParams.Loop = true;
|
||||
var schedSound = new ScheduledSound();
|
||||
schedSound.Filename = MicrowaveSoundLoop;
|
||||
schedSound.AudioParams = audioParams;
|
||||
_soundComponent.AddScheduledSound(schedSound);
|
||||
break;
|
||||
|
||||
default:
|
||||
Logger.Debug($"Something terrible happened in {this}");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
var glowingPartsVisible = !(component.TryGetData(PowerDeviceVisuals.Powered, out bool powered) && !powered);
|
||||
sprite.LayerSetVisible(MicrowaveVisualizerLayers.BaseUnlit, glowingPartsVisible);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private enum MicrowaveVisualizerLayers
|
||||
{
|
||||
Base,
|
||||
BaseUnlit
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -15,7 +15,7 @@ namespace Content.Client.GameObjects.Components.Sound
|
||||
[RegisterComponent]
|
||||
public class SoundComponent : SharedSoundComponent
|
||||
{
|
||||
private readonly List<ScheduledSound> _schedules = new List<ScheduledSound>();
|
||||
private readonly Dictionary<ScheduledSound, IPlayingAudioStream> _audioStreams = new Dictionary<ScheduledSound, IPlayingAudioStream>();
|
||||
private AudioSystem _audioSystem;
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IRobustRandom _random;
|
||||
@@ -23,26 +23,27 @@ namespace Content.Client.GameObjects.Components.Sound
|
||||
|
||||
public override void StopAllSounds()
|
||||
{
|
||||
foreach (var schedule in _schedules)
|
||||
foreach (var kvp in _audioStreams)
|
||||
{
|
||||
schedule.Play = false;
|
||||
kvp.Key.Play = false;
|
||||
kvp.Value.Stop();
|
||||
}
|
||||
_schedules.Clear();
|
||||
_audioStreams.Clear();
|
||||
}
|
||||
|
||||
public override void StopScheduledSound(string filename)
|
||||
{
|
||||
foreach (var schedule in _schedules.ToArray())
|
||||
foreach (var kvp in _audioStreams)
|
||||
{
|
||||
if (schedule.Filename != filename) continue;
|
||||
schedule.Play = false;
|
||||
_schedules.Remove(schedule);
|
||||
if (kvp.Key.Filename != filename) continue;
|
||||
kvp.Key.Play = false;
|
||||
kvp.Value.Stop();
|
||||
_audioStreams.Remove(kvp.Key);
|
||||
}
|
||||
}
|
||||
|
||||
public override void AddScheduledSound(ScheduledSound schedule)
|
||||
{
|
||||
_schedules.Add(schedule);
|
||||
Play(schedule);
|
||||
}
|
||||
|
||||
@@ -54,16 +55,11 @@ namespace Content.Client.GameObjects.Components.Sound
|
||||
{
|
||||
if (!schedule.Play) return; // We make sure this hasn't changed.
|
||||
if (_audioSystem == null) _audioSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AudioSystem>();
|
||||
_audioSystem.Play(schedule.Filename, Owner, schedule.AudioParams);
|
||||
_audioStreams.Add(schedule,_audioSystem.Play(schedule.Filename, Owner, schedule.AudioParams));
|
||||
|
||||
if (schedule.Times == 0)
|
||||
{
|
||||
_schedules.Remove(schedule);
|
||||
return;
|
||||
}
|
||||
if (schedule.Times == 0) return;
|
||||
|
||||
if (schedule.Times > 0)
|
||||
schedule.Times--;
|
||||
if (schedule.Times > 0) schedule.Times--;
|
||||
|
||||
Play(schedule);
|
||||
});
|
||||
|
||||
@@ -25,8 +25,6 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
[UsedImplicitly]
|
||||
public sealed class CombatModeSystem : SharedCombatModeSystem
|
||||
{
|
||||
private const float AttackTimeThreshold = 0.15f;
|
||||
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IGameHud _gameHud;
|
||||
[Dependency] private readonly IPlayerManager _playerManager;
|
||||
@@ -37,9 +35,6 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
|
||||
private InputSystem _inputSystem;
|
||||
|
||||
public bool UseOrAttackIsDown { get; private set; }
|
||||
private float _timeHeld;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -48,10 +43,8 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
_gameHud.OnTargetingZoneChanged = OnTargetingZoneChanged;
|
||||
|
||||
_inputSystem = EntitySystemManager.GetEntitySystem<InputSystem>();
|
||||
_inputSystem.BindMap.BindFunction(ContentKeyFunctions.UseOrAttack, new InputHandler(this));
|
||||
_inputSystem.BindMap.BindFunction(ContentKeyFunctions.ToggleCombatMode,
|
||||
InputCmdHandler.FromDelegate(CombatModeToggled));
|
||||
_overlayManager.AddOverlay(new CombatModeOverlay(this));
|
||||
}
|
||||
|
||||
private void CombatModeToggled(ICommonSession session)
|
||||
@@ -60,20 +53,10 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
{
|
||||
EntityManager.RaisePredictiveEvent(
|
||||
new CombatModeSystemMessages.SetCombatModeActiveMessage(!IsInCombatMode()));
|
||||
|
||||
// Just in case.
|
||||
UseOrAttackIsDown = false;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
|
||||
_overlayManager.RemoveOverlay(nameof(CombatModeOverlay));
|
||||
}
|
||||
|
||||
private bool IsInCombatMode()
|
||||
public bool IsInCombatMode()
|
||||
{
|
||||
var entity = _playerManager.LocalPlayer.ControlledEntity;
|
||||
if (entity == null || !entity.TryGetComponent(out CombatModeComponent combatMode))
|
||||
@@ -92,104 +75,6 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
private void OnCombatModeChanged(bool obj)
|
||||
{
|
||||
EntityManager.RaisePredictiveEvent(new CombatModeSystemMessages.SetCombatModeActiveMessage(obj));
|
||||
|
||||
// Just in case.
|
||||
UseOrAttackIsDown = false;
|
||||
}
|
||||
|
||||
private bool HandleInputMessage(ICommonSession session, InputCmdMessage message)
|
||||
{
|
||||
if (!(message is FullInputCmdMessage msg))
|
||||
return false;
|
||||
|
||||
void SendMsg(BoundKeyFunction function, BoundKeyState state)
|
||||
{
|
||||
var functionId = _inputManager.NetworkBindMap.KeyFunctionID(function);
|
||||
|
||||
var sendMsg = new FullInputCmdMessage(msg.Tick, functionId, state,
|
||||
msg.Coordinates, msg.ScreenCoordinates, msg.Uid);
|
||||
_inputSystem.HandleInputCommand(session, function, sendMsg);
|
||||
}
|
||||
|
||||
// If we are not in combat mode, relay it as a regular Use instead.
|
||||
if (!IsInCombatMode())
|
||||
{
|
||||
SendMsg(EngineKeyFunctions.Use, msg.State);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (msg.State == BoundKeyState.Down)
|
||||
{
|
||||
UseOrAttackIsDown = true;
|
||||
_timeHeld = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Up.
|
||||
if (UseOrAttackIsDown && _timeHeld >= AttackTimeThreshold)
|
||||
{
|
||||
// Attack.
|
||||
SendMsg(ContentKeyFunctions.Attack, BoundKeyState.Down);
|
||||
SendMsg(ContentKeyFunctions.Attack, BoundKeyState.Up);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use.
|
||||
SendMsg(EngineKeyFunctions.Use, BoundKeyState.Down);
|
||||
SendMsg(EngineKeyFunctions.Use, BoundKeyState.Up);
|
||||
}
|
||||
|
||||
UseOrAttackIsDown = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void FrameUpdate(float frameTime)
|
||||
{
|
||||
if (UseOrAttackIsDown)
|
||||
{
|
||||
_timeHeld += frameTime;
|
||||
}
|
||||
}
|
||||
|
||||
// Custom input handler type so we get the ENTIRE InputCmdMessage.
|
||||
private sealed class InputHandler : InputCmdHandler
|
||||
{
|
||||
private readonly CombatModeSystem _combatModeSystem;
|
||||
|
||||
public InputHandler(CombatModeSystem combatModeSystem)
|
||||
{
|
||||
_combatModeSystem = combatModeSystem;
|
||||
}
|
||||
|
||||
public override bool HandleCmdMessage(ICommonSession session, InputCmdMessage message)
|
||||
{
|
||||
return _combatModeSystem.HandleInputMessage(session, message);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class CombatModeOverlay : Overlay
|
||||
{
|
||||
private readonly CombatModeSystem _system;
|
||||
|
||||
public CombatModeOverlay(CombatModeSystem system) : base(nameof(CombatModeOverlay))
|
||||
{
|
||||
_system = system;
|
||||
}
|
||||
|
||||
protected override void Draw(DrawingHandleBase handle)
|
||||
{
|
||||
var screenHandle = (DrawingHandleScreen) handle;
|
||||
|
||||
var mousePos = IoCManager.Resolve<IInputManager>().MouseScreenPosition;
|
||||
|
||||
if (_system.UseOrAttackIsDown && _system._timeHeld > AttackTimeThreshold)
|
||||
{
|
||||
var tex = ResC.GetTexture($"/Textures/Objects/Tools/toolbox_r.png");
|
||||
|
||||
screenHandle.DrawTextureRect(tex, UIBox2.FromDimensions(mousePos, tex.Size * 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,8 +39,8 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
base.Update(frameTime);
|
||||
|
||||
var canFireSemi = _isFirstShot;
|
||||
var state = _inputSystem.CmdStates.GetState(ContentKeyFunctions.Attack);
|
||||
if (!_combatModeSystem.UseOrAttackIsDown && state != BoundKeyState.Down)
|
||||
var state = _inputSystem.CmdStates.GetState(EngineKeyFunctions.Use);
|
||||
if (!_combatModeSystem.IsInCombatMode() || state != BoundKeyState.Down)
|
||||
{
|
||||
_isFirstShot = true;
|
||||
_blocked = false;
|
||||
|
||||
@@ -150,7 +150,10 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
if (verb.RequireInteractionRange && !VerbUtility.InVerbUseRange(user, entity))
|
||||
continue;
|
||||
|
||||
var disabled = verb.GetVisibility(user, component) != VerbVisibility.Visible;
|
||||
if (VerbUtility.IsVerbInvisible(verb, user, component, out var vis))
|
||||
continue;
|
||||
|
||||
var disabled = vis != VerbVisibility.Visible;
|
||||
var category = verb.GetCategory(user, component);
|
||||
|
||||
|
||||
@@ -166,7 +169,10 @@ namespace Content.Client.GameObjects.EntitySystems
|
||||
if (globalVerb.RequireInteractionRange && !VerbUtility.InVerbUseRange(user, entity))
|
||||
continue;
|
||||
|
||||
var disabled = globalVerb.GetVisibility(user, entity) != VerbVisibility.Visible;
|
||||
if (VerbUtility.IsVerbInvisible(globalVerb, user, entity, out var vis))
|
||||
continue;
|
||||
|
||||
var disabled = vis != VerbVisibility.Visible;
|
||||
var category = globalVerb.GetCategory(user, entity);
|
||||
|
||||
if(!buttons.ContainsKey(category))
|
||||
|
||||
@@ -15,7 +15,8 @@ namespace Content.Client.Input
|
||||
common.AddFunction(ContentKeyFunctions.FocusChat);
|
||||
common.AddFunction(ContentKeyFunctions.ExamineEntity);
|
||||
common.AddFunction(ContentKeyFunctions.OpenTutorial);
|
||||
common.AddFunction(ContentKeyFunctions.UseOrAttack);
|
||||
common.AddFunction(ContentKeyFunctions.TakeScreenshot);
|
||||
common.AddFunction(ContentKeyFunctions.TakeScreenshotNoUI);
|
||||
|
||||
var human = contexts.GetContext("human");
|
||||
human.AddFunction(ContentKeyFunctions.SwapHands);
|
||||
@@ -27,9 +28,11 @@ namespace Content.Client.Input
|
||||
human.AddFunction(ContentKeyFunctions.OpenContextMenu);
|
||||
human.AddFunction(ContentKeyFunctions.OpenCraftingMenu);
|
||||
human.AddFunction(ContentKeyFunctions.OpenInventoryMenu);
|
||||
human.AddFunction(ContentKeyFunctions.SmartEquipBackpack);
|
||||
human.AddFunction(ContentKeyFunctions.SmartEquipBelt);
|
||||
human.AddFunction(ContentKeyFunctions.MouseMiddle);
|
||||
human.AddFunction(ContentKeyFunctions.ToggleCombatMode);
|
||||
human.AddFunction(ContentKeyFunctions.Attack);
|
||||
human.AddFunction(ContentKeyFunctions.WideAttack);
|
||||
|
||||
var ghost = contexts.New("ghost", "common");
|
||||
ghost.AddFunction(EngineKeyFunctions.MoveUp);
|
||||
|
||||
85
Content.Client/ScreenshotHook.cs
Normal file
85
Content.Client/ScreenshotHook.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Shared.Input;
|
||||
using Robust.Client.Interfaces.Graphics;
|
||||
using Robust.Client.Interfaces.Input;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Interfaces.Resources;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Utility;
|
||||
using SixLabors.ImageSharp;
|
||||
|
||||
namespace Content.Client
|
||||
{
|
||||
internal class ScreenshotHook : IScreenshotHook
|
||||
{
|
||||
private static readonly ResourcePath BaseScreenshotPath = new ResourcePath("/Screenshots");
|
||||
|
||||
[Dependency] private readonly IInputManager _inputManager = default;
|
||||
[Dependency] private readonly IClyde _clyde = default;
|
||||
[Dependency] private readonly IResourceManager _resourceManager = default;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_inputManager.SetInputCommand(ContentKeyFunctions.TakeScreenshot, InputCmdHandler.FromDelegate(_ =>
|
||||
{
|
||||
Take(ScreenshotType.AfterUI);
|
||||
}));
|
||||
|
||||
_inputManager.SetInputCommand(ContentKeyFunctions.TakeScreenshotNoUI, InputCmdHandler.FromDelegate(_ =>
|
||||
{
|
||||
Take(ScreenshotType.BeforeUI);
|
||||
}));
|
||||
}
|
||||
|
||||
private async void Take(ScreenshotType type)
|
||||
{
|
||||
var screenshot = await _clyde.ScreenshotAsync(type);
|
||||
|
||||
var time = DateTime.Now.ToString("yyyy-M-dd_HH.mm.ss");
|
||||
|
||||
if (!_resourceManager.UserData.IsDir(BaseScreenshotPath))
|
||||
{
|
||||
_resourceManager.UserData.CreateDir(BaseScreenshotPath);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
var filename = time;
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
filename = $"{filename}-{i}";
|
||||
}
|
||||
|
||||
await using var file =
|
||||
_resourceManager.UserData.Open(BaseScreenshotPath / $"{filename}.png", FileMode.CreateNew);
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
// Saving takes forever, so don't hang the game on it.
|
||||
screenshot.SaveAsPng(file);
|
||||
});
|
||||
|
||||
Logger.InfoS("screenshot", "Screenshot taken as {0}.png", filename);
|
||||
return;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Logger.WarningS("screenshot", "Failed to save screenshot, retrying?:\n{0}", e);
|
||||
}
|
||||
}
|
||||
|
||||
Logger.ErrorS("screenshot", "Unable to save screenshot.");
|
||||
}
|
||||
}
|
||||
|
||||
public interface IScreenshotHook
|
||||
{
|
||||
void Initialize();
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Timing;
|
||||
@@ -57,10 +58,10 @@ namespace Content.Client.UserInterface
|
||||
|
||||
AddChild(hBox);
|
||||
|
||||
_leftButton.OnPressed += args => HandKeyBindDown(args.Event, HandNameLeft);
|
||||
_leftButton.OnStoragePressed += args => _OnStoragePressed(args.Event, HandNameLeft);
|
||||
_rightButton.OnPressed += args => HandKeyBindDown(args.Event, HandNameRight);
|
||||
_rightButton.OnStoragePressed += args => _OnStoragePressed(args.Event, HandNameRight);
|
||||
_leftButton.OnPressed += args => HandKeyBindDown(args, HandNameLeft);
|
||||
_leftButton.OnStoragePressed += args => _OnStoragePressed(args, HandNameLeft);
|
||||
_rightButton.OnPressed += args => HandKeyBindDown(args, HandNameRight);
|
||||
_rightButton.OnStoragePressed += args => _OnStoragePressed(args, HandNameRight);
|
||||
|
||||
// Active hand
|
||||
_leftButton.AddChild(ActiveHandRect = new TextureRect
|
||||
@@ -118,31 +119,34 @@ namespace Content.Client.UserInterface
|
||||
|
||||
private void HandKeyBindDown(GUIBoundKeyEventArgs args, string handIndex)
|
||||
{
|
||||
args.Handle();
|
||||
|
||||
if (!TryGetHands(out var hands))
|
||||
return;
|
||||
|
||||
if (args.Function == ContentKeyFunctions.MouseMiddle)
|
||||
{
|
||||
hands.SendChangeHand(handIndex);
|
||||
args.Handle();
|
||||
return;
|
||||
}
|
||||
|
||||
var entity = hands.GetEntity(handIndex);
|
||||
if (entity == null)
|
||||
{
|
||||
if (args.CanFocus && hands.ActiveIndex != handIndex)
|
||||
if (args.Function == EngineKeyFunctions.UIClick && hands.ActiveIndex != handIndex)
|
||||
{
|
||||
hands.SendChangeHand(handIndex);
|
||||
args.Handle();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (_itemSlotManager.OnButtonPressed(args, entity))
|
||||
{
|
||||
args.Handle();
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.CanFocus)
|
||||
if (args.Function == EngineKeyFunctions.UIClick)
|
||||
{
|
||||
if (hands.ActiveIndex == handIndex)
|
||||
{
|
||||
@@ -152,13 +156,14 @@ namespace Content.Client.UserInterface
|
||||
{
|
||||
hands.AttackByInHand(handIndex);
|
||||
}
|
||||
args.Handle();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void _OnStoragePressed(GUIBoundKeyEventArgs args, string handIndex)
|
||||
{
|
||||
if (!args.CanFocus)
|
||||
if (args.Function != EngineKeyFunctions.UIClick)
|
||||
return;
|
||||
if (!TryGetHands(out var hands))
|
||||
return;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using Content.Shared.Input;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Maths;
|
||||
@@ -8,26 +10,26 @@ namespace Content.Client.GameObjects
|
||||
{
|
||||
public sealed class ItemSlotButton : MarginContainer
|
||||
{
|
||||
public BaseButton Button { get; }
|
||||
public TextureRect Button { get; }
|
||||
public SpriteView SpriteView { get; }
|
||||
public BaseButton StorageButton { get; }
|
||||
public TextureRect CooldownCircle { get; }
|
||||
|
||||
public Action<BaseButton.ButtonEventArgs> OnPressed { get; set; }
|
||||
public Action<BaseButton.ButtonEventArgs> OnStoragePressed { get; set; }
|
||||
public Action<GUIBoundKeyEventArgs> OnPressed { get; set; }
|
||||
public Action<GUIBoundKeyEventArgs> OnStoragePressed { get; set; }
|
||||
|
||||
public ItemSlotButton(Texture texture, Texture storageTexture)
|
||||
{
|
||||
CustomMinimumSize = (64, 64);
|
||||
|
||||
AddChild(Button = new TextureButton
|
||||
AddChild(Button = new TextureRect
|
||||
{
|
||||
TextureNormal = texture,
|
||||
Scale = (2, 2),
|
||||
EnableAllKeybinds = true
|
||||
Texture = texture,
|
||||
TextureScale = (2, 2),
|
||||
MouseFilter = MouseFilterMode.Stop
|
||||
});
|
||||
|
||||
Button.OnPressed += OnButtonPressed;
|
||||
Button.OnKeyBindDown += OnButtonPressed;
|
||||
|
||||
AddChild(SpriteView = new SpriteView
|
||||
{
|
||||
@@ -42,9 +44,16 @@ namespace Content.Client.GameObjects
|
||||
SizeFlagsHorizontal = SizeFlags.ShrinkEnd,
|
||||
SizeFlagsVertical = SizeFlags.ShrinkEnd,
|
||||
Visible = false,
|
||||
EnableAllKeybinds = true
|
||||
});
|
||||
|
||||
StorageButton.OnKeyBindDown += args =>
|
||||
{
|
||||
if (args.Function != EngineKeyFunctions.UIClick)
|
||||
{
|
||||
OnButtonPressed(args);
|
||||
}
|
||||
};
|
||||
|
||||
StorageButton.OnPressed += OnStorageButtonPressed;
|
||||
|
||||
AddChild(CooldownCircle = new TextureRect
|
||||
@@ -57,20 +66,20 @@ namespace Content.Client.GameObjects
|
||||
});
|
||||
}
|
||||
|
||||
private void OnButtonPressed(BaseButton.ButtonEventArgs args)
|
||||
private void OnButtonPressed(GUIBoundKeyEventArgs args)
|
||||
{
|
||||
OnPressed?.Invoke(args);
|
||||
}
|
||||
|
||||
private void OnStorageButtonPressed(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
if (args.Event.Function == EngineKeyFunctions.Use)
|
||||
if (args.Event.Function == EngineKeyFunctions.UIClick)
|
||||
{
|
||||
OnStoragePressed?.Invoke(args);
|
||||
OnStoragePressed?.Invoke(args.Event);
|
||||
}
|
||||
else
|
||||
{
|
||||
OnPressed?.Invoke(args);
|
||||
OnPressed?.Invoke(args.Event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,8 +65,6 @@ namespace Content.Client.UserInterface
|
||||
|
||||
public bool OnButtonPressed(GUIBoundKeyEventArgs args, IEntity item)
|
||||
{
|
||||
args.Handle();
|
||||
|
||||
if (item == null)
|
||||
return false;
|
||||
|
||||
@@ -99,6 +97,7 @@ namespace Content.Client.UserInterface
|
||||
{
|
||||
return false;
|
||||
}
|
||||
args.Handle();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
public const string StyleClassLabelSecondaryColor = "LabelSecondaryColor";
|
||||
public const string StyleClassLabelBig = "LabelBig";
|
||||
public const string StyleClassButtonBig = "ButtonBig";
|
||||
public const string StyleClassPopupMessage = "PopupMessage";
|
||||
|
||||
public static readonly Color NanoGold = Color.FromHex("#A88B5E");
|
||||
|
||||
@@ -41,7 +42,9 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
public StyleNano(IResourceCache resCache) : base(resCache)
|
||||
{
|
||||
var notoSans10 = resCache.GetFont("/Nano/NotoSans/NotoSans-Regular.ttf", 10);
|
||||
var notoSansItalic10 = resCache.GetFont("/Nano/NotoSans/NotoSans-Italic.ttf", 10);
|
||||
var notoSans12 = resCache.GetFont("/Nano/NotoSans/NotoSans-Regular.ttf", 12);
|
||||
var notoSansItalic12 = resCache.GetFont("/Nano/NotoSans/NotoSans-Italic.ttf", 12);
|
||||
var notoSansBold12 = resCache.GetFont("/Nano/NotoSans/NotoSans-Bold.ttf", 12);
|
||||
var notoSansDisplayBold14 = resCache.GetFont("/Fonts/NotoSansDisplay/NotoSansDisplay-Bold.ttf", 14);
|
||||
var notoSans16 = resCache.GetFont("/Nano/NotoSans/NotoSans-Regular.ttf", 16);
|
||||
@@ -449,6 +452,19 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
new StyleProperty(PanelContainer.StylePropertyPanel, tooltipBox)
|
||||
}),
|
||||
|
||||
new StyleRule(new SelectorElement(typeof(PanelContainer), new[] {"speechBox", "sayBox"}, null, null), new[]
|
||||
{
|
||||
new StyleProperty(PanelContainer.StylePropertyPanel, tooltipBox)
|
||||
}),
|
||||
|
||||
new StyleRule(new SelectorChild(
|
||||
new SelectorElement(typeof(PanelContainer), new[] {"speechBox", "emoteBox"}, null, null),
|
||||
new SelectorElement(typeof(RichTextLabel), null, null, null)),
|
||||
new[]
|
||||
{
|
||||
new StyleProperty("font", notoSansItalic12),
|
||||
}),
|
||||
|
||||
// Entity tooltip
|
||||
new StyleRule(
|
||||
new SelectorElement(typeof(PanelContainer), new[] {ExamineSystem.StyleClassEntityTooltip}, null,
|
||||
@@ -552,6 +568,14 @@ namespace Content.Client.UserInterface.Stylesheets
|
||||
new StyleProperty("font", notoSans16)
|
||||
}),
|
||||
|
||||
// Popup messages
|
||||
new StyleRule(new SelectorElement(typeof(Label), new[] {StyleClassPopupMessage}, null, null),
|
||||
new[]
|
||||
{
|
||||
new StyleProperty("font", notoSansItalic10),
|
||||
new StyleProperty("font-color", Color.LightGray),
|
||||
}),
|
||||
|
||||
//APC and SMES power state label colors
|
||||
new StyleRule(new SelectorElement(typeof(Label), new[] {StyleClassPowerStateNone}, null, null), new[]
|
||||
{
|
||||
|
||||
@@ -69,10 +69,14 @@ namespace Content.Client.UserInterface
|
||||
Switch hands: [color=#a4885c]{4}[/color]
|
||||
Use held item: [color=#a4885c]{5}[/color]
|
||||
Drop held item: [color=#a4885c]{6}[/color]
|
||||
Smart equip from backpack: [color=#a4885c]{24}[/color]
|
||||
Smart equip from belt: [color=#a4885c]{25}[/color]
|
||||
Open inventory: [color=#a4885c]{7}[/color]
|
||||
Open character window: [color=#a4885c]{8}[/color]
|
||||
Open crafting window: [color=#a4885c]{9}[/color]
|
||||
Focus chat: [color=#a4885c]{10}[/color]
|
||||
Use hand/object in hand: [color=#a4885c]{22}[/color]
|
||||
Do wide attack: [color=#a4885c]{23}[/color]
|
||||
Use targeted entity: [color=#a4885c]{11}[/color]
|
||||
Throw held item: [color=#a4885c]{12}[/color]
|
||||
Examine entity: [color=#a4885c]{13}[/color]
|
||||
@@ -102,16 +106,20 @@ Toggle sandbox window: [color=#a4885c]{21}[/color]",
|
||||
Key(ShowDebugMonitors),
|
||||
Key(OpenEntitySpawnWindow),
|
||||
Key(OpenTileSpawnWindow),
|
||||
Key(OpenSandboxWindow)));
|
||||
|
||||
//Gameplay
|
||||
VBox.AddChild(new Label { FontOverride = headerFont, Text = Loc.GetString("\nSandbox spawner", Key(OpenSandboxWindow)) });
|
||||
AddFormattedText(SandboxSpawnerContents);
|
||||
Key(OpenSandboxWindow),
|
||||
Key(Use),
|
||||
Key(WideAttack),
|
||||
Key(SmartEquipBackpack),
|
||||
Key(SmartEquipBelt)));
|
||||
|
||||
//Gameplay
|
||||
VBox.AddChild(new Label { FontOverride = headerFont, Text = "\nGameplay" });
|
||||
AddFormattedText(GameplayContents);
|
||||
|
||||
//Gameplay
|
||||
VBox.AddChild(new Label { FontOverride = headerFont, Text = Loc.GetString("\nSandbox spawner", Key(OpenSandboxWindow)) });
|
||||
AddFormattedText(SandboxSpawnerContents);
|
||||
|
||||
//Feedback
|
||||
VBox.AddChild(new Label { FontOverride = headerFont, Text = "\nFeedback" });
|
||||
AddFormattedText(FeedbackContents);
|
||||
|
||||
Reference in New Issue
Block a user