diff --git a/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs b/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs index bc6b4689af6..8f7d0fea243 100644 --- a/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs +++ b/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs @@ -8,189 +8,301 @@ // SPDX-License-Identifier: AGPL-3.0-or-later using System.Linq; +using Content.Client.Computer; using Content.Client.Stylesheets; +using Content.Client.UserInterface.Controls; using Content.Shared.CCVar; -using Content.Shared.Procedural; +using Content.Shared.Parallax.Biomes; +using Content.Shared.Salvage; using Content.Shared.Salvage.Expeditions; using Content.Shared.Salvage.Expeditions.Modifiers; -using JetBrains.Annotations; +using Content.Shared.Shuttles.BUIStates; +using Robust.Client.AutoGenerated; +using Robust.Client.Graphics; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; using Robust.Shared.Configuration; using Robust.Shared.Prototypes; +using Robust.Shared.Timing; +using Robust.Shared.Utility; namespace Content.Client.Salvage.UI; -[UsedImplicitly] -public sealed class SalvageExpeditionConsoleBoundUserInterface : BoundUserInterface +[GenerateTypedNameReferences] +public sealed partial class SalvageExpeditionWindow : FancyWindow, + IComputerWindow { - [ViewVariables] - private OfferingWindow? _window; + private readonly IConfigurationManager _cfgManager; + private readonly IGameTiming _timing; + private readonly IPrototypeManager _prototype; + private readonly SharedSalvageSystem _salvage; - [Dependency] private readonly IConfigurationManager _cfgManager = default!; - [Dependency] private readonly IEntityManager _entManager = default!; - [Dependency] private readonly IPrototypeManager _protoManager = default!; + public event Action? ClaimMission; + private bool _claimed; + private bool _cooldown; + private TimeSpan _nextOffer; - public SalvageExpeditionConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) + public SalvageExpeditionWindow() { - IoCManager.InjectDependencies(this); + RobustXamlLoader.Load(this); + _cfgManager = IoCManager.Resolve(); + _timing = IoCManager.Resolve(); + _prototype = IoCManager.Resolve(); + _salvage = IoCManager.Resolve().EntitySysManager.GetEntitySystem(); } - protected override void Open() + public void UpdateState(SalvageExpeditionConsoleState state) { - base.Open(); - _window = this.CreateWindowCenteredLeft(); - _window.Title = Loc.GetString("salvage-expedition-window-title"); - } - - protected override void UpdateState(BoundUserInterfaceState state) - { - base.UpdateState(state); - - if (state is not SalvageExpeditionConsoleState current || _window == null) - return; - - _window.Progression = null; - _window.Cooldown = TimeSpan.FromSeconds(_cfgManager.GetCVar(CCVars.SalvageExpeditionCooldown)); - _window.NextOffer = current.NextOffer; - _window.Claimed = current.Claimed; - _window.ClearOptions(); - var salvage = _entManager.System(); + _claimed = state.Claimed; + _cooldown = state.Cooldown; + _nextOffer = state.NextOffer; + Container.DisposeAllChildren(); - for (var i = 0; i < current.Missions.Count; i++) + for (var i = 0; i < state.Missions.Count; i++) { - var missionParams = current.Missions[i]; + var missionParams = state.Missions[i]; + var config = missionParams.MissionType; + var mission = _salvage.GetMission(missionParams.MissionType, missionParams.Difficulty, missionParams.Seed); - var offering = new OfferingWindowOption(); - offering.Title = Loc.GetString($"salvage-expedition-type"); + // Mission title + var missionStripe = new StripeBack() + { + Margin = new Thickness(0f, -5f, 0f, 0f) + }; - var difficultyId = "Moderate"; - var difficultyProto = _protoManager.Index(difficultyId); - // TODO: Selectable difficulty soon. - var mission = salvage.GetMission(difficultyProto, missionParams.Seed); + missionStripe.AddChild(new Label() + { + Text = Loc.GetString($"salvage-expedition-type-{config.ToString()}"), + HorizontalAlignment = HAlignment.Center, + Margin = new Thickness(0f, 5f, 0f, 5f), + }); + + var lBox = new BoxContainer() + { + Orientation = BoxContainer.LayoutOrientation.Vertical + }; // Difficulty // Details - offering.AddContent(new Label() + lBox.AddChild(new Label() { Text = Loc.GetString("salvage-expedition-window-difficulty") }); - var difficultyColor = difficultyProto.Color; + Color difficultyColor; + + switch (missionParams.Difficulty) + { + case DifficultyRating.Minimal: + difficultyColor = Color.FromHex("#52B4E996"); + break; + case DifficultyRating.Minor: + difficultyColor = Color.FromHex("#9FED5896"); + break; + case DifficultyRating.Moderate: + difficultyColor = Color.FromHex("#EFB34196"); + break; + case DifficultyRating.Hazardous: + difficultyColor = Color.FromHex("#DE3A3A96"); + break; + case DifficultyRating.Extreme: + difficultyColor = Color.FromHex("#D381C996"); + break; + default: + throw new ArgumentOutOfRangeException(); + } - offering.AddContent(new Label + lBox.AddChild(new Label { - Text = Loc.GetString("salvage-expedition-difficulty-Moderate"), + Text = Loc.GetString($"salvage-expedition-difficulty-{missionParams.Difficulty.ToString()}"), FontColorOverride = difficultyColor, - HorizontalAlignment = Control.HAlignment.Left, + HorizontalAlignment = HAlignment.Left, Margin = new Thickness(0f, 0f, 0f, 5f), }); - offering.AddContent(new Label + // Details + var details = _salvage.GetMissionDescription(mission); + + lBox.AddChild(new Label { - Text = Loc.GetString("salvage-expedition-difficulty-players"), - HorizontalAlignment = Control.HAlignment.Left, + Text = Loc.GetString("salvage-expedition-window-details") }); - offering.AddContent(new Label + lBox.AddChild(new Label { - Text = difficultyProto.RecommendedPlayers.ToString(), + Text = details, FontColorOverride = StyleNano.NanoGold, - HorizontalAlignment = Control.HAlignment.Left, + HorizontalAlignment = HAlignment.Left, Margin = new Thickness(0f, 0f, 0f, 5f), }); // Details - offering.AddContent(new Label + lBox.AddChild(new Label { Text = Loc.GetString("salvage-expedition-window-hostiles") }); var faction = mission.Faction; - offering.AddContent(new Label + lBox.AddChild(new Label { - Text = string.IsNullOrWhiteSpace(Loc.GetString(_protoManager.Index(faction).Description)) - ? LogAndReturnDefaultFactionDescription(faction) - : Loc.GetString(_protoManager.Index(faction).Description), + Text = faction, FontColorOverride = StyleNano.NanoGold, - HorizontalAlignment = Control.HAlignment.Left, + HorizontalAlignment = HAlignment.Left, Margin = new Thickness(0f, 0f, 0f, 5f), }); - string LogAndReturnDefaultFactionDescription(string faction) - { - Logger.Error($"Description is null or white space for SalvageFactionPrototype: {faction}"); - return Loc.GetString(_protoManager.Index(faction).ID); - } - - // Duration - offering.AddContent(new Label + lBox.AddChild(new Label { Text = Loc.GetString("salvage-expedition-window-duration") }); - offering.AddContent(new Label + lBox.AddChild(new Label { Text = mission.Duration.ToString(), FontColorOverride = StyleNano.NanoGold, - HorizontalAlignment = Control.HAlignment.Left, + HorizontalAlignment = HAlignment.Left, Margin = new Thickness(0f, 0f, 0f, 5f), }); // Biome - offering.AddContent(new Label + lBox.AddChild(new Label { Text = Loc.GetString("salvage-expedition-window-biome") }); var biome = mission.Biome; - offering.AddContent(new Label + lBox.AddChild(new Label { - Text = string.IsNullOrWhiteSpace(Loc.GetString(_protoManager.Index(biome).Description)) - ? LogAndReturnDefaultBiomDescription(biome) - : Loc.GetString(_protoManager.Index(biome).Description), + Text = Loc.GetString(_prototype.Index(biome).ID), FontColorOverride = StyleNano.NanoGold, - HorizontalAlignment = Control.HAlignment.Left, + HorizontalAlignment = HAlignment.Left, Margin = new Thickness(0f, 0f, 0f, 5f), }); - string LogAndReturnDefaultBiomDescription(string biome) - { - Logger.Error($"Description is null or white space for SalvageBiomeModPrototype: {biome}"); - return Loc.GetString(_protoManager.Index(biome).ID); - } - // Modifiers - offering.AddContent(new Label + lBox.AddChild(new Label { Text = Loc.GetString("salvage-expedition-window-modifiers") }); var mods = mission.Modifiers; - offering.AddContent(new Label + lBox.AddChild(new Label { Text = string.Join("\n", mods.Select(o => "- " + o)).TrimEnd(), FontColorOverride = StyleNano.NanoGold, - HorizontalAlignment = Control.HAlignment.Left, + HorizontalAlignment = HAlignment.Left, Margin = new Thickness(0f, 0f, 0f, 5f), }); - offering.ClaimPressed += args => + lBox.AddChild(new Label() + { + Text = Loc.GetString("salvage-expedition-window-rewards") + }); + + var rewards = new Dictionary(); + foreach (var reward in mission.Rewards) + { + var name = _prototype.Index(reward).Name; + var count = rewards.GetOrNew(name); + count++; + rewards[name] = count; + } + + // there will always be 3 or more rewards so no need for 0 check + lBox.AddChild(new Label() + { + Text = string.Join("\n", rewards.Select(o => "- " + o.Key + (o.Value > 1 ? $" x {o.Value}" : ""))).TrimEnd(), + FontColorOverride = StyleNano.ConcerningOrangeFore, + HorizontalAlignment = HAlignment.Left, + Margin = new Thickness(0f, 0f, 0f, 5f) + }); + + // Claim + var claimButton = new Button() + { + HorizontalExpand = true, + VerticalAlignment = VAlignment.Bottom, + Pressed = state.ActiveMission == missionParams.Index, + ToggleMode = true, + Disabled = state.Claimed || state.Cooldown, + }; + + claimButton.Label.Margin = new Thickness(0f, 5f); + + claimButton.OnPressed += args => + { + ClaimMission?.Invoke(missionParams.Index); + }; + + if (state.ActiveMission == missionParams.Index) + { + claimButton.Text = Loc.GetString("salvage-expedition-window-claimed"); + claimButton.AddStyleClass(StyleBase.ButtonCaution); + } + else + { + claimButton.Text = Loc.GetString("salvage-expedition-window-claim"); + } + + var box = new PanelContainer { - SendMessage(new ClaimSalvageMessage() + PanelOverride = new StyleBoxFlat(new Color(30, 30, 34)), + HorizontalExpand = true, + Margin = new Thickness(5f, 0f), + Children = { - Index = missionParams.Index, - }); + new BoxContainer + { + Orientation = BoxContainer.LayoutOrientation.Vertical, + Children = + { + missionStripe, + lBox, + new Control() {VerticalExpand = true}, + claimButton, + }, + Margin = new Thickness(5f, 5f) + } + } }; - offering.Claimed = current.ActiveMission == missionParams.Index; - offering.Disabled = current.Claimed || current.Cooldown; + LayoutContainer.SetAnchorPreset(box, LayoutContainer.LayoutPreset.Wide); + + Container.AddChild(box); + } + } + + protected override void FrameUpdate(FrameEventArgs args) + { + base.FrameUpdate(args); + + if (_claimed) + { + NextOfferBar.Value = 0f; + NextOfferText.Text = "00:00"; + return; + } + + var remaining = _nextOffer - _timing.CurTime; + + if (remaining < TimeSpan.Zero) + { + NextOfferBar.Value = 1f; + NextOfferText.Text = "00:00"; + } + else + { + var cooldown = _cooldown + ? TimeSpan.FromSeconds(_cfgManager.GetCVar(CCVars.SalvageExpeditionFailedCooldown)) + : TimeSpan.FromSeconds(_cfgManager.GetCVar(CCVars.SalvageExpeditionCooldown)); - _window.AddOption(offering); + NextOfferBar.Value = 1f - (float) (remaining / cooldown); + NextOfferText.Text = $"{remaining.Minutes:00}:{remaining.Seconds:00}"; } } -} \ No newline at end of file +} diff --git a/Content.Client/Salvage/UI/SalvageExpeditionWindow.xaml b/Content.Client/Salvage/UI/SalvageExpeditionWindow.xaml new file mode 100644 index 00000000000..e5920b02277 --- /dev/null +++ b/Content.Client/Salvage/UI/SalvageExpeditionWindow.xaml @@ -0,0 +1,40 @@ + + + + + + + + +