#region Copyright & License Information /* * Copyright (c) The OpenRA Developers and Contributors * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. For more * information, see COPYING. */ #endregion using System; using System.Collections.Generic; using System.Linq; using OpenRA.Mods.Common.Scripting; using OpenRA.Mods.Common.Traits; using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets.Logic { public enum IngameInfoPanel { AutoSelect, Map, Objectives, Debug, Chat, LobbbyOptions } sealed class GameInfoLogic : ChromeLogic { [FluentReference] const string Objectives = "menu-game-info.objectives"; [FluentReference] const string Briefing = "menu-game-info.briefing"; [FluentReference] const string Options = "menu-game-info.options"; [FluentReference] const string Debug = "menu-game-info.debug"; [FluentReference] const string Chat = "menu-game-info.chat"; readonly World world; readonly ModData modData; readonly Action hideMenu; readonly Action closeMenu; readonly IObjectivesPanel iop; IngameInfoPanel activePanel; readonly bool hasError; [ObjectCreator.UseCtor] public GameInfoLogic(Widget widget, ModData modData, World world, IngameInfoPanel initialPanel, Action hideMenu, Action closeMenu) { var panels = new Dictionary Setup)>() { { IngameInfoPanel.Objectives, ("OBJECTIVES_PANEL", Objectives, SetupObjectivesPanel) }, { IngameInfoPanel.Map, ("MAP_PANEL", Briefing, SetupMapPanel) }, { IngameInfoPanel.LobbbyOptions, ("LOBBY_OPTIONS_PANEL", Options, SetupLobbyOptionsPanel) }, { IngameInfoPanel.Debug, ("DEBUG_PANEL", Debug, SetupDebugPanel) }, { IngameInfoPanel.Chat, ("CHAT_PANEL", Chat, SetupChatPanel) } }; this.world = world; this.modData = modData; this.hideMenu = hideMenu; this.closeMenu = closeMenu; activePanel = initialPanel; var visiblePanels = new List(); // Objectives/Stats tab var scriptContext = world.WorldActor.TraitOrDefault(); hasError = scriptContext != null && scriptContext.FatalErrorOccurred; iop = world.WorldActor.TraitsImplementing().FirstOrDefault(); if (hasError || (iop != null && iop.PanelName != null)) visiblePanels.Add(IngameInfoPanel.Objectives); // Briefing tab var missionData = world.WorldActor.Info.TraitInfoOrDefault(); if (missionData != null && !string.IsNullOrEmpty(missionData.Briefing)) visiblePanels.Add(IngameInfoPanel.Map); // Lobby Options tab visiblePanels.Add(IngameInfoPanel.LobbbyOptions); // Debug/Cheats tab // Can't use DeveloperMode.Enabled because there is a hardcoded hack to *always* // enable developer mode for singleplayer games, but we only want to show the button // if it has been explicitly enabled var def = world.Map.Rules.Actors[SystemActors.Player].TraitInfo().CheckboxEnabled; var developerEnabled = world.LobbyInfo.GlobalSettings.OptionOrDefault("cheats", def); if (world.LocalPlayer != null && developerEnabled) visiblePanels.Add(IngameInfoPanel.Debug); if (world.LobbyInfo.NonBotClients.Count() > 1) visiblePanels.Add(IngameInfoPanel.Chat); var numTabs = visiblePanels.Count; var tabContainer = !hasError ? widget.GetOrNull($"TAB_CONTAINER_{numTabs}") : null; if (tabContainer != null) tabContainer.IsVisible = () => true; var chatPanel = widget.Get(panels[IngameInfoPanel.Chat].Panel); for (var i = 0; i < numTabs; i++) { var type = visiblePanels[i]; var (panel, label, setup) = panels[type]; var tabButton = tabContainer?.Get($"BUTTON{i + 1}"); if (tabButton != null) { var tabButtonText = FluentProvider.GetMessage(label); tabButton.GetText = () => tabButtonText; tabButton.OnClick = () => { if (activePanel == IngameInfoPanel.Chat) LeaveChatPanel(chatPanel); activePanel = type; }; tabButton.IsHighlighted = () => activePanel == type; } var panelContainer = widget.Get(panel); panelContainer.IsVisible = () => activePanel == type; setup(tabButton, panelContainer); if (activePanel == IngameInfoPanel.AutoSelect) activePanel = type; } var titleText = widget.Get("TITLE"); var mapTitle = world.Map.Title; var firstCategory = world.Map.Categories.FirstOrDefault(); if (firstCategory != null) mapTitle = firstCategory + ": " + mapTitle; titleText.GetText = () => mapTitle; } void SetupObjectivesPanel(ButtonWidget objectivesTabButton, Widget objectivesPanelContainer) { var panel = hasError ? "SCRIPT_ERROR_PANEL" : iop.PanelName; Game.LoadWidget(world, panel, objectivesPanelContainer, new WidgetArgs() { { "hideMenu", hideMenu }, { "closeMenu", closeMenu }, }); } void SetupMapPanel(ButtonWidget mapTabButton, Widget mapPanelContainer) { Game.LoadWidget(world, "MAP_PANEL", mapPanelContainer, new WidgetArgs()); } void SetupLobbyOptionsPanel(ButtonWidget mapTabButton, Widget optionsPanelContainer) { Game.LoadWidget(world, "LOBBY_OPTIONS_PANEL", optionsPanelContainer, new WidgetArgs() { { "getMap", (Func)(() => modData.MapCache[world.Map.Uid]) }, { "configurationDisabled", (Func)(() => true) } }); } void SetupDebugPanel(ButtonWidget debugTabButton, Widget debugPanelContainer) { if (debugTabButton != null) debugTabButton.IsDisabled = () => world.IsGameOver; Game.LoadWidget(world, "DEBUG_PANEL", debugPanelContainer, new WidgetArgs()); if (activePanel == IngameInfoPanel.AutoSelect) activePanel = IngameInfoPanel.Debug; } void SetupChatPanel(ButtonWidget chatTabButton, Widget chatPanelContainer) { if (chatTabButton != null) { var lastOnClick = chatTabButton.OnClick; chatTabButton.OnClick = () => { lastOnClick(); chatPanelContainer.Get("CHAT_TEXTFIELD").TakeKeyboardFocus(); }; } Game.LoadWidget(world, "CHAT_CONTAINER", chatPanelContainer, new WidgetArgs() { { "isMenuChat", true } }); } static void LeaveChatPanel(Widget chatPanelContainer) { chatPanelContainer.Get("CHAT_TEXTFIELD").YieldKeyboardFocus(); } } }