/// <summary>
        /// Harmony postfix to perform actions require after the level has loaded.
        /// </summary>
        public static void Postfix()
        {
            // Don't do anything if mod hasn't activated for whatever reason (mod conflict, harmony error, something else).
            if (!Loading.isModEnabled)
            {
                return;
            }

            // Report any 'soft' mod conflicts.
            if (Loading.softModConflct)
            {
                // Soft conflict detected - display warning notification for each one.
                foreach (string mod in ModUtils.conflictingModNames)
                {
                    if (mod.Equals("PTG") && ModSettings.dsaPTG == 0)
                    {
                        // Plop the Growables.
                        DontShowAgainMessageBox softConflictBox = MessageBoxBase.ShowModal <DontShowAgainMessageBox>();
                        softConflictBox.AddParas(Translations.Translate("PRR_CON_PTG0"), Translations.Translate("PRR_CON_PTG1"), Translations.Translate("PRR_CON_PTG2"));
                        softConflictBox.DSAButton.eventClicked += (component, clickEvent) => { ModSettings.dsaPTG = 1; SettingsUtils.SaveSettings(); };
                    }
                }
            }

            // Report any broken assets and remove from our prefab dictionary.
            foreach (BuildingInfo prefab in Loading.brokenPrefabs)
            {
                Logging.Error("broken prefab: ", prefab.name);
                Loading.xmlManager.prefabHash.Remove(prefab);
            }
            Loading.brokenPrefabs.Clear();

            // Init Ploppable Tool panel.
            PloppableTool.Initialize();

            // Add buttons to access building details from zoned building info panels.
            SettingsPanel.AddInfoPanelButtons();

            // Display update notification.
            try
            {
                WhatsNew.ShowWhatsNew();
            }
            catch (Exception e)
            {
                Logging.LogException(e, "exception showing WhatsNew panel");
            }

            // Set up options panel event handler.
            try
            {
                OptionsPanel.OptionsEventHook();
            }
            catch (Exception e)
            {
                Logging.LogException(e, "exception hooking options panel");
            }

            Logging.KeyMessage("loading complete");
        }
Пример #2
0
        /// <summary>
        /// Called by the game when level loading is complete.
        /// </summary>
        /// <param name="mode">Loading mode (e.g. game, editor, scenario, etc.)</param>
        public override void OnLevelLoaded(LoadMode mode)
        {
            // Alert the user to any mod conflicts.
            ModUtils.NotifyConflict();

            // Don't do anything further if mod hasn't activated (conflicting mod detected, or loading into editor instead of game).
            if (!isModEnabled)
            {
                return;
            }

            base.OnLevelLoaded(mode);

            // Don't do anything if in asset editor.
            if (mode == LoadMode.NewAsset || mode == LoadMode.LoadAsset)
            {
                return;
            }

            // Wait for loading to fully complete.
            while (!LoadingManager.instance.m_loadingComplete)
            {
            }

            // Check watchdog flag.
            if (!patchOperating)
            {
                // Patch wasn't operating; display warning notification and exit.
                HarmonyNotification notification = new HarmonyNotification();
                notification.Create();
                notification.Show();

                return;
            }

            // Init Ploppable Tool panel.
            PloppableTool.Initialize();

            // Add buttons to access building details from zoned building info panels.
            SettingsPanel.AddInfoPanelButtons();

            // Deactivate the ploppable panel as it starts hidden.  Don't need to deactivate the settings panel as it's not instantiated until first shown.
            PloppableTool.Instance.gameObject.SetActive(false);

            // Report any loading errors.
            Debugging.ReportErrors();

            Debugging.Message("loading complete");

            // Load settings file and check if we need to display update notification.
            settingsFile = Configuration <SettingsFile> .Load();

            if (settingsFile.NotificationVersion != 2)
            {
                // No update notification "Don't show again" flag found; show the notification.
                UpdateNotification notification = new UpdateNotification();
                notification.Create();
                notification.Show();
            }
        }
        /// <summary>
        /// Create the titlebar; we no longer use Start() as that's not sufficiently reliable (race conditions), and is no longer needed, with the new create/destroy process.
        /// </summary>
        public void Setup()
        {
            // Basic setup.
            width            = parent.width;
            height           = RICOSettingsPanel.titleHeight;
            isVisible        = true;
            canFocus         = true;
            isInteractive    = true;
            relativePosition = Vector3.zero;

            // Make it draggable.
            dragHandle                  = AddUIComponent <UIDragHandle>();
            dragHandle.width            = width - 50;
            dragHandle.height           = height;
            dragHandle.relativePosition = Vector3.zero;
            dragHandle.target           = parent;

            // Decorative icon (top-left).
            iconSprite = AddUIComponent <UISprite>();
            iconSprite.relativePosition = new Vector3(10, 5);
            iconSprite.spriteName       = "ToolbarIconZoomOutCity";
            UIUtils.ResizeIcon(iconSprite, new Vector2(30, 30));
            iconSprite.relativePosition = new Vector3(10, 5);

            // Titlebar label.
            titleLabel = AddUIComponent <UILabel>();
            titleLabel.relativePosition = new Vector3(50, 13);
            titleLabel.text             = "Ploppable RICO Revisited v" + PloppableRICOMod.Version;

            // Close button.
            closeButton = AddUIComponent <UIButton>();
            closeButton.relativePosition = new Vector3(width - 35, 2);
            closeButton.normalBgSprite   = "buttonclose";
            closeButton.hoveredBgSprite  = "buttonclosehover";
            closeButton.pressedBgSprite  = "buttonclosepressed";
            closeButton.eventClick      += (component, clickEvent) =>
            {
                SettingsPanel.Close();
            };
        }
        /// <summary>
        /// Draws the Ploppable Tool panel.
        /// </summary>
        private void DrawPloppablePanel()
        {
            // Check to make sure that we haven't already done this.
            if (PloppableButton == null)
            {
                // Set state flag; this is a new setup.
                hasShown = false;

                // Main button on ingame toolbar.
                PloppableButton                  = UIView.GetAView().FindUIComponent <UITabstrip>("MainToolstrip").AddUIComponent <UIButton>();
                PloppableButton.size             = new Vector2(43, 49);
                PloppableButton.normalBgSprite   = "ToolbarIconGroup6Normal";
                PloppableButton.normalFgSprite   = "IconPolicyBigBusiness";
                PloppableButton.focusedBgSprite  = "ToolbarIconGroup6Focused";
                PloppableButton.hoveredBgSprite  = "ToolbarIconGroup6Hovered";
                PloppableButton.pressedBgSprite  = "ToolbarIconGroup6Pressed";
                PloppableButton.disabledBgSprite = "ToolbarIconGroup6Disabled";
                PloppableButton.relativePosition = new Vector2(800, 0);
                PloppableButton.name             = "PloppableButton";

                // Event handler - show the Ploppable Tool panel when the button is clicked.
                PloppableButton.eventClick += (component, clickEvent) =>
                {
                    component.Focus();
                    buildingPanel.isVisible = true;
                };

                // Base panel.
                buildingPanel = UIView.GetAView().FindUIComponent("TSContainer").AddUIComponent <UIPanel>();
                buildingPanel.backgroundSprite = "SubcategoriesPanel";
                buildingPanel.isVisible        = false;
                buildingPanel.name             = "PloppableBuildingPanel";
                buildingPanel.size             = new Vector2(859, 109);
                buildingPanel.relativePosition = new Vector2(0, 0);

                // Tabstrip.
                Tabs                  = UIView.GetAView().FindUIComponent("PloppableBuildingPanel").AddUIComponent <UITabstrip>();
                Tabs.size             = new Vector2(832, 25);
                Tabs.relativePosition = new Vector2(13, -25);
                Tabs.pivot            = UIPivotPoint.BottomCenter;
                Tabs.padding          = new RectOffset(0, 3, 0, 0);

                // Get game sprite thumbnail atlas.
                UITextureAtlas gameIconAtlas = Resources.FindObjectsOfTypeAll <UITextureAtlas>().FirstOrDefault(a => a.name == "Thumbnails");

                // Scroll panel.
                AddScrollPanel();

                // Tabs.
                for (int i = 0; i <= NumTypes; i++)
                {
                    // Draw tabs in tabstrip.
                    TabButtons[i]                  = new UIButton();
                    TabButtons[i]                  = Tabs.AddUIComponent <UIButton>();
                    TabButtons[i].size             = new Vector2(46, 25);
                    TabButtons[i].normalBgSprite   = "SubBarButtonBase";
                    TabButtons[i].disabledBgSprite = "SubBarButtonBaseDisabled";
                    TabButtons[i].pressedBgSprite  = "SubBarButtonBasePressed";
                    TabButtons[i].hoveredBgSprite  = "SubBarButtonBaseHovered";
                    TabButtons[i].focusedBgSprite  = "SubBarButtonBaseFocused";
                    TabButtons[i].state            = UIButton.ButtonState.Normal;
                    TabButtons[i].name             = Names[i] + "Button";
                    TabButtons[i].tabStrip         = true;

                    TabSprites[i] = new UISprite();
                    TabSprites[i] = TabButtons[i].AddUIComponent <UISprite>();

                    // Standard "Vanilla" categories (low and high residential, low and high commercial, and offices) - use standard zoning icons from original vanilla release.
                    if (i <= 5)
                    {
                        TabSprites[i].atlas = gameIconAtlas;
                        SetTabSprite(TabSprites[i], "Zoning" + Names[i]);
                    }
                    else
                    {
                        // Other types don't have standard zoning icons; use policy icons instead.
                        SetTabSprite(TabSprites[i], "IconPolicy" + Names[i]);
                    }
                }

                // This can't happen in a loop, because the loop index is undefined after setup has occured (i.e. when the function is actually called).
                TabButtons[0].eventClick += (component, clickEvent) => TabClicked(0, TabSprites[0]);
                TabButtons[1].eventClick += (component, clickEvent) => TabClicked(1, TabSprites[1]);
                TabButtons[2].eventClick += (component, clickEvent) => TabClicked(2, TabSprites[2]);
                TabButtons[3].eventClick += (component, clickEvent) => TabClicked(3, TabSprites[3]);
                TabButtons[4].eventClick += (component, clickEvent) => TabClicked(4, TabSprites[4]);
                TabButtons[5].eventClick += (component, clickEvent) => TabClicked(5, TabSprites[5]);
                TabButtons[6].eventClick += (component, clickEvent) => TabClicked(6, TabSprites[6]);
                TabButtons[7].eventClick += (component, clickEvent) => TabClicked(7, TabSprites[7]);
                TabButtons[8].eventClick += (component, clickEvent) => TabClicked(8, TabSprites[8]);
                TabButtons[9].eventClick += (component, clickEvent) => TabClicked(9, TabSprites[9]);
                // Below are DLC categories - AD for first two, then GC for next 3.  Will be hidden if relevant DLC is not installed.
                TabButtons[10].eventClick += (component, clickEvent) => TabClicked(10, TabSprites[10]);
                TabButtons[11].eventClick += (component, clickEvent) => TabClicked(11, TabSprites[11]);
                TabButtons[12].eventClick += (component, clickEvent) => TabClicked(12, TabSprites[12]);
                TabButtons[13].eventClick += (component, clickEvent) => TabClicked(13, TabSprites[13]);
                TabButtons[14].eventClick += (component, clickEvent) => TabClicked(14, TabSprites[14]);

                // Activate low residential panel to start with (what the user sees on first opening the panel).
                //BuildingPanels[0].isVisible = true;

                // Hide AD tabs if AD is not installed.
                if (!Util.IsADinstalled())
                {
                    TabButtons[10].isVisible = false;
                    TabButtons[11].isVisible = false;
                }

                // Hide GC tabs if GC is not installed.
                if (!Util.IsGCinstalled())
                {
                    TabButtons[12].isVisible = false;
                    TabButtons[13].isVisible = false;
                    TabButtons[14].isVisible = false;
                }

                // Settings tab.
                showSettings                = UIUtils.CreateButton(Tabs);
                showSettings.size           = new Vector2(100, 25);
                showSettings.normalBgSprite = "SubBarButtonBase";
                showSettings.eventClick    += (component, clickEvent) =>
                {
                    SettingsPanel.Open(scrollPanel?.selectedItem?.prefab);
                };

                // Add UI text.
                SetText();


                // Toggle active state on visibility changed if we're using the UI speed boost (deactivating when hidden to minimise UI workload and impact on performance).
                buildingPanel.eventVisibilityChanged += (component, isVisible) =>
                {
                    // Additional check to allow for the case where speedboost has been deactivated mid-game while the panel was deactivated.
                    if ((ModSettings.speedBoost) || (isVisible && !buildingPanel.gameObject.activeSelf))
                    {
                        buildingPanel.gameObject.SetActive(isVisible);
                    }

                    // Other checks.
                    if (isVisible)
                    {
                        // If this is the first time we're visible, set the display to the initial default tab (low residential).
                        if (!hasShown)
                        {
                            // Set initial default tab.
                            TabClicked(0, _instance.TabSprites[0]);

                            // Done!
                            hasShown = true;
                        }
                        else
                        {
                            // Clear previous selection and refresh panel.
                            scrollPanel.selectedItem = null;
                            scrollPanel.Refresh();
                        }
                    }
                    else
                    {
                        // Destroy thumbnail renderer if we're no longer visible.
                        ThumbnailManager.Close();
                    }
                };
            }
        }
        /// <summary>
        /// Called by the game when level loading is complete.
        /// </summary>
        /// <param name="mode">Loading mode (e.g. game, editor, scenario, etc.)</param>
        public override void OnLevelLoaded(LoadMode mode)
        {
            // Alert the user to any mod conflicts.
            ModUtils.NotifyConflict();

            // Don't do anything further if mod hasn't activated (conflicting mod detected, or loading into editor instead of game).
            if (!isModEnabled)
            {
                return;
            }

            base.OnLevelLoaded(mode);

            // Don't do anything if in asset editor.
            if (mode == LoadMode.NewAsset || mode == LoadMode.LoadAsset)
            {
                return;
            }

            // Wait for loading to fully complete.
            while (!LoadingManager.instance.m_loadingComplete)
            {
            }

            // Check watchdog flag.
            if (!patchOperating)
            {
                // Patch wasn't operating; display warning notification and exit.
                HarmonyNotification notification = new HarmonyNotification();
                notification.Create();
                notification.Show();

                return;
            }

            // Report any broken assets and remove from our prefab dictionary.
            foreach (BuildingInfo prefab in brokenPrefabs)
            {
                Debugging.Message("broken prefab: " + prefab.name);
                xmlManager.prefabHash.Remove(prefab);
            }
            brokenPrefabs.Clear();

            // Init Ploppable Tool panel.
            PloppableTool.Initialize();

            // Add buttons to access building details from zoned building info panels.
            SettingsPanel.AddInfoPanelButtons();

            // Report any loading errors.
            Debugging.ReportErrors();

            Debugging.Message("loading complete");

            // Load settings file and check if we need to display update notification.
            if (UpdateNotification.notificationVersion != 3)
            {
                // No update notification "Don't show again" flag found; show the notification.
                UpdateNotification notification = new UpdateNotification();
                notification.Create();
                notification.Show();
            }

            // Set up options panel event handler.
            OptionsPanel.OptionsEventHook();
        }
Пример #6
0
        /// <summary>
        /// Initialises the individual display item (as blank).
        /// </summary>
        public void Init()
        {
            component.text = string.Empty;

            // Basic layout.
            component.tooltipAnchor       = UITooltipAnchor.Anchored;
            component.horizontalAlignment = UIHorizontalAlignment.Center;
            component.verticalAlignment   = UIVerticalAlignment.Middle;
            component.pivot = UIPivotPoint.TopCenter;
            component.foregroundSpriteMode = UIForegroundSpriteMode.Fill;
            component.group = component.parent;

            // Hide the "can't afford" big red crossout that's shown by default.
            UIComponent uIComponent = (component.childCount <= 0) ? null : component.components[0];

            if (uIComponent != null)
            {
                uIComponent.isVisible = false;
            }

            // Information label - building name.
            nameLabel                  = component.AddUIComponent <UILabel>();
            nameLabel.textScale        = 0.6f;
            nameLabel.useDropShadow    = true;
            nameLabel.dropShadowColor  = new Color32(80, 80, 80, 255);
            nameLabel.dropShadowOffset = new Vector2(2, -2);
            nameLabel.autoSize         = false;
            nameLabel.autoHeight       = true;
            nameLabel.wordWrap         = true;
            nameLabel.width            = component.width - 10;
            nameLabel.isVisible        = true;
            nameLabel.relativePosition = new Vector3(5, 5);

            // Information label - building level.
            levelLabel                  = component.AddUIComponent <UILabel>();
            levelLabel.textScale        = 0.6f;
            levelLabel.useDropShadow    = true;
            levelLabel.dropShadowColor  = new Color32(80, 80, 80, 255);
            levelLabel.dropShadowOffset = new Vector2(2, -2);
            levelLabel.autoSize         = true;
            levelLabel.isVisible        = true;
            levelLabel.anchor           = UIAnchorStyle.Bottom | UIAnchorStyle.Left;
            levelLabel.relativePosition = new Vector3(5, component.height - 10);

            // Information label - building size.
            sizeLabel                  = component.AddUIComponent <UILabel>();
            sizeLabel.textScale        = 0.6f;
            sizeLabel.useDropShadow    = true;
            sizeLabel.dropShadowColor  = new Color32(80, 80, 80, 255);
            sizeLabel.dropShadowOffset = new Vector2(2, -2);
            sizeLabel.autoSize         = true;
            sizeLabel.isVisible        = true;
            sizeLabel.anchor           = UIAnchorStyle.Bottom | UIAnchorStyle.Left;

            // Tooltip.
            component.eventMouseHover += (component, mouseEvent) =>
            {
                // Reset the tooltip before showing each time, as sometimes it gets clobbered either by the game or another mod.
                component.tooltip = BuildingTooltip(currentData);
            };

            // Double-click to open building's settings.
            component.eventDoubleClick += (component, mouseEvent) =>
            {
                SettingsPanel.Open(currentData.prefab);
            };
        }
        /// <summary>
        /// Draws the Ploppable Tool panel.
        /// </summary>
        private void DrawPloppablePanel()
        {
            // Check to make sure that we haven't already done this.
            if (PloppableButton == null)
            {
                // Main button on ingame toolbar.
                PloppableButton                  = UIView.GetAView().FindUIComponent <UITabstrip>("MainToolstrip").AddUIComponent <UIButton>();
                PloppableButton.size             = new Vector2(43, 49);
                PloppableButton.normalBgSprite   = "ToolbarIconGroup6Normal";
                PloppableButton.normalFgSprite   = "IconPolicyBigBusiness";
                PloppableButton.focusedBgSprite  = "ToolbarIconGroup6Focused";
                PloppableButton.hoveredBgSprite  = "ToolbarIconGroup6Hovered";
                PloppableButton.pressedBgSprite  = "ToolbarIconGroup6Pressed";
                PloppableButton.disabledBgSprite = "ToolbarIconGroup6Disabled";
                PloppableButton.relativePosition = new Vector2(800, 0);
                PloppableButton.name             = "PloppableButton";
                PloppableButton.tooltip          = Translations.Translate("PRR_NAME");

                // Event handler - show the Ploppable Tool panel when the button is clicked.
                PloppableButton.eventClick += (component, clickEvent) =>
                {
                    component.Focus();
                    BuildingPanel.isVisible = true;
                };

                // Base panel.
                BuildingPanel = UIView.GetAView().FindUIComponent("TSContainer").AddUIComponent <UIPanel>();
                BuildingPanel.backgroundSprite = "SubcategoriesPanel";
                BuildingPanel.isVisible        = false;
                BuildingPanel.name             = "PloppableBuildingPanel";
                BuildingPanel.size             = new Vector2(859, 109);
                BuildingPanel.relativePosition = new Vector2(0, 0);

                // Tabstrip.
                Tabs                  = UIView.GetAView().FindUIComponent("PloppableBuildingPanel").AddUIComponent <UITabstrip>();
                Tabs.size             = new Vector2(832, 25);
                Tabs.relativePosition = new Vector2(13, -25);
                Tabs.pivot            = UIPivotPoint.BottomCenter;
                Tabs.padding          = new RectOffset(0, 3, 0, 0);

                // Get game sprite thumbnail atlas.
                UITextureAtlas gameIconAtlas = Resources.FindObjectsOfTypeAll <UITextureAtlas>().FirstOrDefault(a => a.name == "Thumbnails");

                // Scrollable panels.
                for (int i = 0; i <= NumTypes; i++)
                {
                    // Basic setup.
                    BuildingPanels[i]                                     = new UIScrollablePanel();
                    BuildingPanels[i]                                     = BuildingPanel.AddUIComponent <UIScrollablePanel>();
                    BuildingPanels[i].size                                = new Vector2(763, 109);
                    BuildingPanels[i].relativePosition                    = new Vector2(50, 0);
                    BuildingPanels[i].name                                = Names[i] + "Panel";
                    BuildingPanels[i].isVisible                           = false;
                    BuildingPanels[i].autoLayout                          = true;
                    BuildingPanels[i].autoLayoutStart                     = LayoutStart.BottomLeft;
                    BuildingPanels[i].builtinKeyNavigation                = true;
                    BuildingPanels[i].autoLayoutDirection                 = LayoutDirection.Horizontal;
                    BuildingPanels[i].clipChildren                        = true;
                    BuildingPanels[i].freeScroll                          = false;
                    BuildingPanels[i].horizontalScrollbar                 = new UIScrollbar();
                    BuildingPanels[i].scrollWheelAmount                   = 109;
                    BuildingPanels[i].horizontalScrollbar.stepSize        = 1f;
                    BuildingPanels[i].horizontalScrollbar.incrementAmount = 109f;
                    BuildingPanels[i].scrollWithArrowKeys                 = true;

                    // Draw tabs in tabstrip.
                    TabButtons[i]                  = new UIButton();
                    TabButtons[i]                  = Tabs.AddUIComponent <UIButton>();
                    TabButtons[i].size             = new Vector2(46, 25);
                    TabButtons[i].normalBgSprite   = "SubBarButtonBase";
                    TabButtons[i].disabledBgSprite = "SubBarButtonBaseDisabled";
                    TabButtons[i].pressedBgSprite  = "SubBarButtonBasePressed";
                    TabButtons[i].hoveredBgSprite  = "SubBarButtonBaseHovered";
                    TabButtons[i].focusedBgSprite  = "SubBarButtonBaseFocused";
                    TabButtons[i].state            = UIButton.ButtonState.Normal;
                    TabButtons[i].name             = Names[i] + "Button";
                    TabButtons[i].tabStrip         = true;

                    TabSprites[i] = new UISprite();
                    TabSprites[i] = TabButtons[i].AddUIComponent <UISprite>();

                    // Standard "Vanilla" categories (low and high residential, low and high commercial, and offices) - use standard zoning icons from original vanilla release.
                    if (i <= 5)
                    {
                        TabSprites[i].atlas = gameIconAtlas;
                        SetTabSprite(TabSprites[i], "Zoning" + Names[i]);
                    }
                    else
                    {
                        // Other types don't have standard zoning icons; use policy icons instead.
                        SetTabSprite(TabSprites[i], "IconPolicy" + Names[i]);
                    }
                }

                // 'Left' and 'Right' buttons to croll panel.
                LeftButton  = BuildingPanel.AddUIComponent <UIButton>();
                RightButton = BuildingPanel.AddUIComponent <UIButton>();

                LeftButton.size  = new Vector2(32, 32);
                RightButton.size = new Vector2(32, 32);

                LeftButton.normalBgSprite   = "ArrowLeft";
                LeftButton.pressedBgSprite  = "ArrowLeftPressed";
                LeftButton.hoveredBgSprite  = "ArrowLeftHovered";
                LeftButton.disabledBgSprite = "ArrowLeftDisabled";

                LeftButton.relativePosition  = new Vector3(16, 33);
                RightButton.relativePosition = new Vector3(812, 33);

                RightButton.normalBgSprite   = "ArrowRight";
                RightButton.pressedBgSprite  = "ArrowRightPressed";
                RightButton.hoveredBgSprite  = "ArrowRightHovered";
                RightButton.disabledBgSprite = "ArrowRightDisabled";

                // Initialise current selection to first panel.
                currentSelection = BuildingPanels[0];

                // Event handlers.
                RightButton.eventClick += (component, clickEvent) => ArrowClicked(component);
                LeftButton.eventClick  += (component, clickEvent) => ArrowClicked(component);

                // Show left/right scroll buttons if we've got more than seven buttons, otherwise hide.
                if (BuildingPanels[0].childCount > 7)
                {
                    LeftButton.isVisible  = true;
                    RightButton.isVisible = true;
                }
                else
                {
                    LeftButton.isVisible  = false;
                    RightButton.isVisible = false;
                }

                // This can't happen in a loop, because the loop index is undefined after setup has occured (i.e. when the function is actually called).
                TabButtons[0].eventClick += (component, clickEvent) => TabClicked(BuildingPanels[0], TabSprites[0]);
                TabButtons[1].eventClick += (component, clickEvent) => TabClicked(BuildingPanels[1], TabSprites[1]);
                TabButtons[2].eventClick += (component, clickEvent) => TabClicked(BuildingPanels[2], TabSprites[2]);
                TabButtons[3].eventClick += (component, clickEvent) => TabClicked(BuildingPanels[3], TabSprites[3]);
                TabButtons[4].eventClick += (component, clickEvent) => TabClicked(BuildingPanels[4], TabSprites[4]);
                TabButtons[5].eventClick += (component, clickEvent) => TabClicked(BuildingPanels[5], TabSprites[5]);
                TabButtons[6].eventClick += (component, clickEvent) => TabClicked(BuildingPanels[6], TabSprites[6]);
                TabButtons[7].eventClick += (component, clickEvent) => TabClicked(BuildingPanels[7], TabSprites[7]);
                TabButtons[8].eventClick += (component, clickEvent) => TabClicked(BuildingPanels[8], TabSprites[8]);
                TabButtons[9].eventClick += (component, clickEvent) => TabClicked(BuildingPanels[9], TabSprites[9]);
                // Below are DLC categories - AD for first two, then GC for next 3.  Will be hidden if relevant DLC is not installed.
                TabButtons[10].eventClick += (component, clickEvent) => TabClicked(BuildingPanels[10], TabSprites[10]);
                TabButtons[11].eventClick += (component, clickEvent) => TabClicked(BuildingPanels[11], TabSprites[11]);
                TabButtons[12].eventClick += (component, clickEvent) => TabClicked(BuildingPanels[12], TabSprites[12]);
                TabButtons[13].eventClick += (component, clickEvent) => TabClicked(BuildingPanels[13], TabSprites[13]);
                TabButtons[14].eventClick += (component, clickEvent) => TabClicked(BuildingPanels[14], TabSprites[14]);

                // Activate low residential panel to start with (what the user sees on first opening the panel).
                BuildingPanels[0].isVisible = true;

                // Hide AD tabs if AD is not installed.
                if (!Util.isADinstalled())
                {
                    TabButtons[10].isVisible = false;
                    TabButtons[11].isVisible = false;
                }

                // Hide GC tabs if GC is not installed.
                if (!Util.isGCinstalled())
                {
                    TabButtons[12].isVisible = false;
                    TabButtons[13].isVisible = false;
                    TabButtons[14].isVisible = false;
                }

                // Settings tab.
                showSettings                = UIUtils.CreateButton(Tabs);
                showSettings.size           = new Vector2(80, 25);
                showSettings.normalBgSprite = "SubBarButtonBase";
                showSettings.eventClick    += (component, clickEvent) => SettingsPanel.Open();

                // Add UI text.
                SetText();

                // Toggle active state on visibility changed (deactivating when hidden to minimise UI workload and impact on performance).
                BuildingPanel.eventVisibilityChanged += (component, isVisible) =>
                {
                    BuildingPanel.gameObject.SetActive(isVisible);
                };
            }
        }