diff --git a/Content.Client/Guidebook/Controls/GuideMicrowaveEmbed.xaml.cs b/Content.Client/Guidebook/Controls/GuideMicrowaveEmbed.xaml.cs index e54892d634..5eb654f8ee 100644 --- a/Content.Client/Guidebook/Controls/GuideMicrowaveEmbed.xaml.cs +++ b/Content.Client/Guidebook/Controls/GuideMicrowaveEmbed.xaml.cs @@ -39,10 +39,10 @@ public sealed partial class GuideMicrowaveEmbed : PanelContainer, IDocumentTag, public GuideMicrowaveEmbed(string recipe) : this() { - GenerateControl(_prototype.Index(recipe)); + GenerateControl(_prototype.Index(recipe)); } - public GuideMicrowaveEmbed(FoodRecipePrototype recipe) : this() + public GuideMicrowaveEmbed(MicrowaveMealRecipePrototype recipe) : this() { GenerateControl(recipe); } @@ -66,7 +66,7 @@ public sealed partial class GuideMicrowaveEmbed : PanelContainer, IDocumentTag, return false; } - if (!_prototype.TryIndex(id, out var recipe)) + if (!_prototype.TryIndex(id, out var recipe)) { _sawmill.Error($"Specified recipe prototype \"{id}\" is not a valid recipe prototype"); return false; @@ -78,7 +78,7 @@ public sealed partial class GuideMicrowaveEmbed : PanelContainer, IDocumentTag, return true; } - private void GenerateHeader(FoodRecipePrototype recipe) + private void GenerateHeader(MicrowaveMealRecipePrototype recipe) { var entity = _prototype.Index(recipe.Result); @@ -89,9 +89,9 @@ public sealed partial class GuideMicrowaveEmbed : PanelContainer, IDocumentTag, ResultDescription.SetMarkup(entity.Description); } - private void GenerateSolidIngredients(FoodRecipePrototype recipe) + private void GenerateSolidIngredients(MicrowaveMealRecipePrototype recipe) { - foreach (var (product, amount) in recipe.IngredientsSolids.OrderByDescending(p => p.Value)) + foreach (var (product, amount) in recipe.Ingredients.Solids.OrderByDescending(p => p.Value)) { var ingredient = _prototype.Index(product); @@ -122,9 +122,9 @@ public sealed partial class GuideMicrowaveEmbed : PanelContainer, IDocumentTag, } } - private void GenerateLiquidIngredients(FoodRecipePrototype recipe) + private void GenerateLiquidIngredients(MicrowaveMealRecipePrototype recipe) { - foreach (var (product, amount) in recipe.IngredientsReagents.OrderByDescending(p => p.Value)) + foreach (var (product, amount) in recipe.Ingredients.Reagents.OrderByDescending(p => p.Value)) { var reagent = _prototype.Index(product); @@ -165,22 +165,58 @@ public sealed partial class GuideMicrowaveEmbed : PanelContainer, IDocumentTag, } } - private void GenerateIngredients(FoodRecipePrototype recipe) + private void GenerateStackIngredients(MicrowaveMealRecipePrototype recipe) + { + foreach (var (product, amount) in recipe.Ingredients.Stacks.OrderByDescending(p => p.Value)) + { + var stack = _prototype.Index(product); + + // stack icon + + IngredientsGrid.AddChild(new GuideEntityEmbed(stack.Spawn, false, false)); + + // stack name + + var stackName = Loc.GetString(stack.Name); + var stackNameMsg = new FormattedMessage(); + stackNameMsg.AddMarkupOrThrow(Loc.GetString("guidebook-microwave-stack-name-display", ("stack", stackName))); + stackNameMsg.Pop(); + + var stackNameLabel = new RichTextLabel(); + stackNameLabel.SetMessage(stackNameMsg); + + IngredientsGrid.AddChild(stackNameLabel); + + // stack quantity + + var stackQuantityMsg = new FormattedMessage(); + stackQuantityMsg.AddMarkupOrThrow(Loc.GetString("guidebook-microwave-stack-quantity-display", ("amount", amount))); + stackQuantityMsg.Pop(); + + var stackQuantityLabel = new RichTextLabel(); + stackQuantityLabel.SetMessage(stackQuantityMsg); + + IngredientsGrid.AddChild(stackQuantityLabel); + } + } + + private void GenerateIngredients(MicrowaveMealRecipePrototype recipe) { GenerateLiquidIngredients(recipe); + GenerateStackIngredients(recipe); GenerateSolidIngredients(recipe); } - private void GenerateCookTime(FoodRecipePrototype recipe) + private void GenerateCookTime(MicrowaveMealRecipePrototype recipe) { var msg = new FormattedMessage(); - msg.AddMarkupOrThrow(Loc.GetString("guidebook-microwave-cook-time", ("time", recipe.CookTime))); + msg.AddMarkupOrThrow(Loc.GetString("guidebook-microwave-cook-time", ("time", recipe.Time))); msg.Pop(); CookTimeLabel.SetMessage(msg); } - private void GenerateControl(FoodRecipePrototype recipe) + private void GenerateControl(MicrowaveMealRecipePrototype recipe) { GenerateHeader(recipe); GenerateIngredients(recipe); diff --git a/Content.Client/Guidebook/Controls/GuideMicrowaveGroupEmbed.cs b/Content.Client/Guidebook/Controls/GuideMicrowaveGroupEmbed.cs index 9fe70faaaa..584a2c3387 100644 --- a/Content.Client/Guidebook/Controls/GuideMicrowaveGroupEmbed.cs +++ b/Content.Client/Guidebook/Controls/GuideMicrowaveGroupEmbed.cs @@ -50,7 +50,7 @@ public sealed partial class GuideMicrowaveGroupEmbed : BoxContainer, IDocumentTa private void CreateEntries(string group) { - var prototypes = _prototype.EnumeratePrototypes() + var prototypes = _prototype.EnumeratePrototypes() .Where(p => p.Group.Equals(group)) .OrderBy(p => p.Name); diff --git a/Content.Client/Kitchen/EntitySystems/ClientMicrowaveSystem.cs b/Content.Client/Kitchen/EntitySystems/ClientMicrowaveSystem.cs new file mode 100644 index 0000000000..c2203b790b --- /dev/null +++ b/Content.Client/Kitchen/EntitySystems/ClientMicrowaveSystem.cs @@ -0,0 +1,52 @@ +using Content.Shared.Kitchen.Components; +using Content.Shared.Kitchen.EntitySystems; +using Robust.Client.Player; + +namespace Content.Client.Kitchen.EntitySystems; + +/// +public sealed partial class ClientMicrowaveSystem : MicrowaveSystem +{ + [Dependency] private IPlayerManager _player = default!; + [Dependency] private SharedUserInterfaceSystem _userInterface = default!; + + public override void UpdateUI(Entity microwave) + { + base.UpdateUI(microwave); + + if (!MicrowaveQuery.Resolve(microwave.Owner, ref microwave.Comp)) + return; + + if (_userInterface.TryGetOpenUi(microwave.Owner, MicrowaveUiKey.Key, out var bui)) + bui.Update(); + } + + protected override void ActivateMicrowaveCycle(Entity ent) + { + base.ActivateMicrowaveCycle(ent); + + if (!Timing.IsFirstTimePredicted) + return; + + var audioParams = ent.Comp.LoopingSound.Params; + audioParams = audioParams.WithLoop(true).WithMaxDistance(5); + + ent.Comp.PlayingStream ??= Audio.PlayLocal(ent.Comp.LoopingSound, ent, _player.LocalEntity, audioParams)?.Entity; + } + + protected override void DeactivateMicrowaveCycle(Entity ent) + { + base.DeactivateMicrowaveCycle(ent); + + // We have this check here so Audio.Stop doesn't mistakenly tell us that the entity has been deleted when it hasn't been!!! + if (!Timing.IsFirstTimePredicted) + return; + + ent.Comp.PlayingStream = Audio.Stop(ent.Comp.PlayingStream); + + foreach (var solid in GetMicrowaveContents(ent.AsNullable())) + { + RemComp(solid); + } + } +} diff --git a/Content.Client/Kitchen/UI/MicrowaveBoundUserInterface.cs b/Content.Client/Kitchen/UI/MicrowaveBoundUserInterface.cs index 643ac47054..2bd63e123b 100644 --- a/Content.Client/Kitchen/UI/MicrowaveBoundUserInterface.cs +++ b/Content.Client/Kitchen/UI/MicrowaveBoundUserInterface.cs @@ -1,151 +1,128 @@ -using Content.Shared.Chemistry.Reagent; using Content.Shared.Kitchen.Components; +using Content.Shared.Kitchen.EntitySystems; using JetBrains.Annotations; using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.UserInterface; -using Robust.Client.UserInterface.Controls; -using Robust.Shared.Timing; -namespace Content.Client.Kitchen.UI +namespace Content.Client.Kitchen.UI; + +[UsedImplicitly] +public sealed partial class MicrowaveBoundUserInterface(EntityUid owner, Enum uiKey) : BoundUserInterface(owner, uiKey) { - [UsedImplicitly] - public sealed class MicrowaveBoundUserInterface : BoundUserInterface + [Dependency] private SpriteSystem _sprite = default!; + [Dependency] private MicrowaveSystem _microwave = default!; + + [ViewVariables] + private MicrowaveMenu? _menu; + + [ViewVariables] + private readonly Dictionary _solids = new(); + + protected override void Open() { - [ViewVariables] - private MicrowaveMenu? _menu; + base.Open(); - [ViewVariables] - private readonly Dictionary _solids = new(); - - [ViewVariables] - private readonly Dictionary _reagents = new(); - - public MicrowaveBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) + _menu = this.CreateWindow(); + _menu.StartButton.OnPressed += _ => SendPredictedMessage(new MicrowaveStartCookMessage()); + _menu.EjectButton.OnPressed += _ => SendPredictedMessage(new MicrowaveEjectMessage()); + _menu.IngredientsList.OnItemSelected += args => { - } + SendPredictedMessage(new MicrowaveEjectSolidIndexedMessage(EntMan.GetNetEntity(_solids[args.ItemIndex]))); + }; - protected override void Open() + _menu.OnCookTimeSelected += (name, index, cookTime) => { - base.Open(); - _menu = this.CreateWindow(); - _menu.StartButton.OnPressed += _ => SendPredictedMessage(new MicrowaveStartCookMessage()); - _menu.EjectButton.OnPressed += _ => SendPredictedMessage(new MicrowaveEjectMessage()); - _menu.IngredientsList.OnItemSelected += args => - { - SendPredictedMessage(new MicrowaveEjectSolidIndexedMessage(EntMan.GetNetEntity(_solids[args.ItemIndex]))); - }; - - _menu.OnCookTimeSelected += (args, buttonIndex) => - { - var selectedCookTime = (uint) 0; - - if (args.Button is MicrowaveMenu.MicrowaveCookTimeButton microwaveCookTimeButton) - { - // args.Button is a MicrowaveCookTimeButton - var actualButton = (MicrowaveMenu.MicrowaveCookTimeButton) args.Button; - selectedCookTime = actualButton.CookTime == 0 ? 0 : actualButton.CookTime; - // SendMessage(new MicrowaveSelectCookTimeMessage((int) selectedCookTime / 5, actualButton.CookTime)); - SendPredictedMessage(new MicrowaveSelectCookTimeMessage((int) selectedCookTime / 5, actualButton.CookTime)); - - _menu.CookTimeInfoLabel.Text = Loc.GetString("microwave-bound-user-interface-cook-time-label", - ("time", selectedCookTime)); - } - else - { - // args.Button is a normal button aka instant cook button - SendPredictedMessage(new MicrowaveSelectCookTimeMessage((int) selectedCookTime, 0)); - - _menu.CookTimeInfoLabel.Text = Loc.GetString("microwave-bound-user-interface-cook-time-label", - ("time", Loc.GetString("microwave-menu-instant-button"))); - } - }; - } - - protected override void UpdateState(BoundUserInterfaceState state) - { - base.UpdateState(state); - if (state is not MicrowaveUpdateUserInterfaceState cState || _menu == null) - { - return; - } - - _menu.IsBusy = cState.IsMicrowaveBusy; - _menu.CurrentCooktimeEnd = cState.CurrentCookTimeEnd; - - _menu.ToggleBusyDisableOverlayPanel(cState.IsMicrowaveBusy || cState.ContainedSolids.Length == 0); - // TODO move this to a component state and ensure the net ids. - RefreshContentsDisplay(EntMan.GetEntityArray(cState.ContainedSolids)); - - //Set the cook time info label - var cookTime = cState.ActiveButtonIndex == 0 - ? Loc.GetString("microwave-menu-instant-button") - : cState.CurrentCookTime.ToString(); - - + SendPredictedMessage(new MicrowaveSelectCookTimeMessage(index, cookTime)); _menu.CookTimeInfoLabel.Text = Loc.GetString("microwave-bound-user-interface-cook-time-label", - ("time", cookTime)); - _menu.StartButton.Disabled = cState.IsMicrowaveBusy || cState.ContainedSolids.Length == 0; - _menu.EjectButton.Disabled = cState.IsMicrowaveBusy || cState.ContainedSolids.Length == 0; + ("time", name)); + }; + Update(); + } - //Set the correct button active button - if (cState.ActiveButtonIndex == 0) - { - _menu.InstantCookButton.Pressed = true; - } - else - { - var currentlySelectedTimeButton = (Button) _menu.CookTimeButtonVbox.GetChild(cState.ActiveButtonIndex - 1); - currentlySelectedTimeButton.Pressed = true; - } + public override void Update() + { + base.Update(); - //Set the "micowave light" ui color to indicate if the microwave is busy or not - if (cState.IsMicrowaveBusy && cState.ContainedSolids.Length > 0) - { - _menu.IngredientsPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = Color.FromHex("#947300") }; - } - else - { - _menu.IngredientsPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = Color.FromHex("#1B1B1E") }; - } - } + if (_menu is null || !EntMan.TryGetComponent(Owner, out var comp)) + return; - private void RefreshContentsDisplay(EntityUid[] containedSolids) + RefreshContentsDisplay(); + UpdateActiveDisplay(comp); + + // Update the currently-selected cook time label and button + var buttonIndex = comp.CurrentCookTimeButtonIndex; + if (_menu.TryGetCookTimeButton(buttonIndex, out var button)) + button.Pressed = true; + + var timeLabel = buttonIndex == 0 + ? Loc.GetString("microwave-menu-instant-button") + : comp.CurrentCookTimerTime.ToString(); + + _menu.CookTimeInfoLabel.Text = Loc.GetString("microwave-bound-user-interface-cook-time-label", + ("time", timeLabel)); + } + + /// + /// Update the state of various controls in this menu based on the active / empty status of the microwave. + /// + private void UpdateActiveDisplay(MicrowaveComponent? comp) + { + if (_menu is null) + return; + + // Disable various UI controls if the microwave is active or empty + var isActive = EntMan.TryGetComponent(Owner, out var activeComp); + var isEmpty = !_microwave.HasContents((Owner, comp)); + _menu.IsBusy = isActive; + _menu.ToggleBusyDisableOverlayPanel(isActive); + _menu.StartButton.Disabled = isActive || isEmpty; + _menu.EjectButton.Disabled = isActive || isEmpty; + + if (activeComp != null) + _menu.CurrentCooktimeEnd = activeComp.CookTimeEnd; + + // Set the "microwave light" panel color + _menu.SetIngredientPanelLight(isActive && !isEmpty); + } + + /// + /// Update the panel containing all of the microwave's contents. + /// + private void RefreshContentsDisplay() + { + if (_menu == null) + return; + + _solids.Clear(); + _menu.IngredientsList.Clear(); + foreach (var entity in _microwave.GetMicrowaveContents(Owner)) { - _reagents.Clear(); + if (EntMan.Deleted(entity)) + continue; - if (_menu == null) return; - - _solids.Clear(); - _menu.IngredientsList.Clear(); - foreach (var entity in containedSolids) - { - if (EntMan.Deleted(entity)) - { - return; - } - - // TODO just use sprite view - - Texture? texture; - if (EntMan.TryGetComponent(entity, out var iconComponent)) - { - texture = EntMan.System().GetIcon(iconComponent); - } - else if (EntMan.TryGetComponent(entity, out var spriteComponent)) - { - texture = spriteComponent.Icon?.Default; - } - else - { - continue; - } - - var solidItem = _menu.IngredientsList.AddItem(EntMan.GetComponent(entity).EntityName, texture); - var solidIndex = _menu.IngredientsList.IndexOf(solidItem); - _solids.Add(solidIndex, entity); - } + // TODO just use sprite view + var itemIcon = GetEntityIcon(entity); + var itemName = EntMan.GetComponent(entity).EntityName; + var solidItem = _menu.IngredientsList.AddItem(itemName, itemIcon); + var solidIndex = _menu.IngredientsList.IndexOf(solidItem); + _solids.Add(solidIndex, entity); } } + + /// + /// Get the texture associated with an ingredient. + /// + /// The ingredient entity. + private Texture? GetEntityIcon(EntityUid uid) + { + if (EntMan.TryGetComponent(uid, out var icon)) + return _sprite.GetIcon(icon); + + if (EntMan.TryGetComponent(uid, out var sprite)) + return sprite.Icon?.Default; + + return null; + } } diff --git a/Content.Client/Kitchen/UI/MicrowaveCookTimeButton.xaml b/Content.Client/Kitchen/UI/MicrowaveCookTimeButton.xaml new file mode 100644 index 0000000000..479ca641a2 --- /dev/null +++ b/Content.Client/Kitchen/UI/MicrowaveCookTimeButton.xaml @@ -0,0 +1,9 @@ + diff --git a/Content.Client/Kitchen/UI/MicrowaveCookTimeButton.xaml.cs b/Content.Client/Kitchen/UI/MicrowaveCookTimeButton.xaml.cs new file mode 100644 index 0000000000..f6152d5de3 --- /dev/null +++ b/Content.Client/Kitchen/UI/MicrowaveCookTimeButton.xaml.cs @@ -0,0 +1,39 @@ +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.Kitchen.UI; + +[GenerateTypedNameReferences] +public sealed partial class MicrowaveCookTimeButton : Button +{ + public event Action? OnCookTimeSelected; + private uint _cookTime = 0; + + public uint CookTime + { + get => _cookTime; + set + { + _cookTime = value; + UpdateLabel(); + } + } + + public MicrowaveCookTimeButton() + { + RobustXamlLoader.Load(this); + UpdateLabel(); + + OnPressed += _ => OnCookTimeSelected?.Invoke(Text ?? string.Empty, _cookTime); + } + + private void UpdateLabel() + { + var labelText = _cookTime == 0 + ? Loc.GetString("microwave-menu-instant-button") + : _cookTime.ToString(); + + Text = labelText; + } +} diff --git a/Content.Client/Kitchen/UI/MicrowaveMenu.xaml b/Content.Client/Kitchen/UI/MicrowaveMenu.xaml index a95d51af74..e60fbe8741 100644 --- a/Content.Client/Kitchen/UI/MicrowaveMenu.xaml +++ b/Content.Client/Kitchen/UI/MicrowaveMenu.xaml @@ -2,6 +2,7 @@ xmlns="https://spacestation14.io" xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls" xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client" + xmlns:kitchen="clr-namespace:Content.Client.Kitchen.UI" Title="{Loc 'microwave-menu-title'}" MinWidth="512" MinSize="512 256"> @@ -49,15 +50,11 @@ Align="Center" Modulate="#FFFFFF" VAlign="Center" /> - -