From 6d6a05da52cb506b20a24280b94abe4f34ec8f79 Mon Sep 17 00:00:00 2001 From: Jeremy Lorelli Date: Mon, 18 Mar 2024 00:10:32 -0700 Subject: [PATCH] feat: Add portal 2-like loading screen --- layout/pages/loading-screen.xml | 44 +++++++---- scripts/pages/loading-screen.js | 129 ++++++++++++++++--------------- styles/pages/loading-screen.scss | 84 +++++++++++++++++--- 3 files changed, 164 insertions(+), 93 deletions(-) diff --git a/layout/pages/loading-screen.xml b/layout/pages/loading-screen.xml index e9e72c2d..e898eb68 100644 --- a/layout/pages/loading-screen.xml +++ b/layout/pages/loading-screen.xml @@ -8,24 +8,34 @@ - - + + - - - - - - - - - + + + + + + + + + diff --git a/scripts/pages/loading-screen.js b/scripts/pages/loading-screen.js index a08f73b9..30bfe101 100644 --- a/scripts/pages/loading-screen.js +++ b/scripts/pages/loading-screen.js @@ -1,80 +1,81 @@ 'use strict'; -class LoadingScreen { - static panels = { - /** @type {Panel} @static */ - cp: $.GetContextPanel(), - /** @type {Image} @static */ - backgroundImage: $('#BackgroundImage'), - /** @type {ProgressBar} @static */ - progressBar: $('#ProgressBar'), - /** @type {Label} @static */ - mapName: $('#MapName'), - /** @type {Label} @static */ - author: $('#Author'), - /** @type {Label} @static */ - tierAndType: $('#TierAndType'), - /** @type {Label} @static */ - numZones: $('#NumZones') - }; - - static { - $.RegisterForUnhandledEvent('UnloadLoadingScreenAndReinit', this.init.bind(this)); - - $.RegisterEventHandler( - 'PanelLoaded', - this.panels.backgroundImage, - () => (this.panels.backgroundImage.visible = true) - ); - $.RegisterEventHandler( - 'ImageFailedLoad', - this.panels.backgroundImage, - () => (this.panels.backgroundImage.visible = false) - ); - } +class LoadingScreenController { + static lastLoadedMapName = ''; static init() { - this.panels.progressBar.value = 0; - this.panels.mapName.visible = false; - this.panels.author.visible = false; - this.panels.tierAndType.visible = false; - this.panels.numZones.visible = false; - this.panels.backgroundImage.visible = false; + $('#ProgressBar').value = 0; + $.GetContextPanel() + .FindChildInLayoutFile('BackgroundMapImage1') + .RemoveClass('loadingscreen__backgroundhideanim'); + $.GetContextPanel().FindChildInLayoutFile('BackgroundMapImage2').visible = false; } - static updateLoadingScreenInfo(mapName) { - if (!mapName) return; - - const mapData = MapCacheAPI.GetCurrentMapData(); + static updateLoadingScreenInfoRepeater() { + // Progress bar will be 1.0 when loading finishes and is then reset to 0.0 + if ($.GetContextPanel().FindChildInLayoutFile('BackgroundMapImage2').visible) return; - if (!mapData) { - // No data to go off of, just set the map name and hide the rest - this.panels.cp.SetDialogVariable('mapname', mapName); - this.panels.mapName.visible = true; + if ($('#ProgressBar').value > 0.35) { + $.GetContextPanel() + .FindChildInLayoutFile('BackgroundMapImage1') + .AddClass('loadingscreen__backgroundhideanim'); + $.GetContextPanel().FindChildInLayoutFile('BackgroundMapImage2').visible = true; + return; + } - this.panels.author.visible = false; - this.panels.tierAndType.visible = false; - this.panels.numZones.visible = false; - this.panels.backgroundImage.SetImage(''); + // Rechecking every 8th of a second is OK, it doesn't need to be anything crazy + $.Schedule(0.125, LoadingScreenController.updateLoadingScreenInfoRepeater); + } - return; + static updateLoadingScreenInfo(mapName) { + function getMapImage(map, number) { + const base = 'file://{materials}/vgui/loading_screens/loadingscreen_'; + if (map.startsWith('e1912')) return base + 'e1912_1_widescreen.vtf'; + else if (map.startsWith('sp_a1')) return base + 'a1_' + number + '_widescreen.vtf'; + else if (map.startsWith('sp_a2')) return base + 'a2_' + number + '_widescreen.vtf'; + else if (map.startsWith('sp_a3')) return base + 'a3_' + number + '_widescreen.vtf'; + else if (map.startsWith('sp_a4')) return base + 'a4_' + number + '_widescreen.vtf'; + else if (map.startsWith('sp_a5')) return base + 'a5_1_widescreen.vtf'; + else if (map.startsWith('mp')) return base + 'coop_' + number + '_widescreen.vtf'; + // if map is empty, we are reloading the current map + // todo: the aperture logo loading screens don't map exactly to the acts, + // act 3 in particular has two different aperture logo loading screens. + // fixing this will probably involve making a variable storing every + // map name in the game to map it to the right loading screen. + // in the meantime, this looks pretty good + else if (LoadingScreenController.lastLoadedMapName.startsWith('sp_a1')) + return base + 'default_a_' + number + '_widescreen.vtf'; + else if (LoadingScreenController.lastLoadedMapName.startsWith('sp_a2')) + return base + 'default_b_' + number + '_widescreen.vtf'; + else if (LoadingScreenController.lastLoadedMapName.startsWith('sp_a3')) + return base + 'default_c_' + number + '_widescreen.vtf'; + else if (LoadingScreenController.lastLoadedMapName.startsWith('sp_a4')) + return base + 'default_e_' + number + '_widescreen.vtf'; + else if (LoadingScreenController.lastLoadedMapName.startsWith('sp_a5')) return base + 'a5_1_widescreen.vtf'; + else return base + 'default_b_' + number + '_widescreen.vtf'; } - this.panels.cp.SetDialogVariable('mapname', mapData.name); - this.panels.cp.SetDialogVariableInt('tier', mapData.mainTrack.difficulty); - this.panels.cp.SetDialogVariableInt('numzones', mapData.mainTrack.numZones); - this.panels.cp.SetDialogVariable('tracktype', mapData.mainTrack.isLinear ? 'Linear' : 'Staged'); + if (mapName.length > 0) LoadingScreenController.lastLoadedMapName = mapName; - let authorString = ''; - for (const [i, item] of mapData.credits.filter((x) => x.type === 'author').entries()) - authorString += (i > 0 ? ', ' : '') + item.user.alias; - this.panels.cp.SetDialogVariable('author', authorString); + let imageNumber1, imageNumber2; + if (mapName.startsWith('mp')) { + imageNumber1 = Math.floor(Math.random() * 3) + 1; + imageNumber2 = imageNumber1 + 1; + } else { + imageNumber1 = 1; + imageNumber2 = 4; + } - this.panels.mapName.visible = true; - this.panels.author.visible = true; - this.panels.tierAndType.visible = true; - this.panels.numZones.visible = true; + const bgImage1 = $.GetContextPanel().FindChildInLayoutFile('BackgroundMapImage1'); + bgImage1.SetImage(getMapImage(mapName, imageNumber1)); + bgImage1.visible = true; + $.GetContextPanel().FindChildInLayoutFile('BackgroundMapImage2').SetImage(getMapImage(mapName, imageNumber2)); - this.panels.backgroundImage.SetImage(mapData.thumbnail.urlLarge); + $.Schedule(0.125, LoadingScreenController.updateLoadingScreenInfoRepeater); + } + + static { + $.RegisterForUnhandledEvent('UnloadLoadingScreenAndReinit', LoadingScreenController.init); + $.RegisterForUnhandledEvent('PopulateLoadingScreen', LoadingScreenController.updateLoadingScreenInfo); } } diff --git a/styles/pages/loading-screen.scss b/styles/pages/loading-screen.scss index f1971cfd..4c1f7581 100644 --- a/styles/pages/loading-screen.scss +++ b/styles/pages/loading-screen.scss @@ -1,6 +1,63 @@ .loadingscreen { width: 100%; height: 100%; + background-color: rgba(255, 255, 255, 0.01); + transform: scale3d(1, 1, 1); + opacity: 1; + + &__background { + width: 100%; + height: 100%; + } + + &__background-image1 { + z-index: -1; + } + + &__background-image4 { + z-index: -4; + } + + &__contents { + opacity: 1; + + transition-property: height, opacity; + transition-duration: 0.5s; + transition-timing-function: ease-in-out; + } + + &__show { + animation-name: loadingscreen__show-animation; + animation-duration: 0.65s; + animation-timing-function: ease-in-out; + animation-iteration-count: 1; + animation-fill-mode: both; + } + + &__logo { + vertical-align: top; + horizontal-align: right; + width: 100px; + margin-right: 52px; + margin-top: 52px; + } + + &__backgroundhideanim { + animation-name: loading-screen-background-hide-anim; + animation-duration: 0.8s; + animation-timing-function: linear; + animation-iteration-count: 1; + animation-fill-mode: forwards; + } + + &__progressbar { + width: 45%; + height: 10px; + background-color: #00a2ff44; + vertical-align: bottom; + margin-bottom: 52px; + horizontal-align: center; + } &__details { flow-children: none; @@ -28,18 +85,6 @@ horizontal-align: right; } - &__tip { - vertical-align: bottom; - horizontal-align: center; - margin-bottom: 100px; - } - - &__progressbar { - width: 100%; - height: 20px; - box-shadow: none; - } - &__status-label { vertical-align: bottom; horizontal-align: left; @@ -78,3 +123,18 @@ opacity: 0; } } + +@keyframes loading-screen-background-hide-anim { + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + } +} + +// Assigned to the progress bar by Panorama internally +.ProgressBarLeft { + background-color: #ff9a00; +}