diff --git a/layout/hud/map-info.xml b/layout/hud/map-info.xml
index 591071fa..089331a4 100644
--- a/layout/hud/map-info.xml
+++ b/layout/hud/map-info.xml
@@ -4,6 +4,7 @@
+
diff --git a/layout/hud/tab-menu.xml b/layout/hud/tab-menu.xml
index ef129ceb..c03bb2b4 100644
--- a/layout/hud/tab-menu.xml
+++ b/layout/hud/tab-menu.xml
@@ -5,6 +5,7 @@
+
diff --git a/layout/pages/loading-screen.xml b/layout/pages/loading-screen.xml
index 5be42979..72d28eb4 100644
--- a/layout/pages/loading-screen.xml
+++ b/layout/pages/loading-screen.xml
@@ -5,6 +5,7 @@
+
diff --git a/layout/pages/map-selector/map-selector.xml b/layout/pages/map-selector/map-selector.xml
index bdabe814..d1453c00 100644
--- a/layout/pages/map-selector/map-selector.xml
+++ b/layout/pages/map-selector/map-selector.xml
@@ -4,6 +4,7 @@
+
diff --git a/scripts/common/map-cache.js b/scripts/common/map-cache.js
new file mode 100644
index 00000000..a3ef7064
--- /dev/null
+++ b/scripts/common/map-cache.js
@@ -0,0 +1,32 @@
+/**
+ * Enum for track types
+ * @enum {number}
+ */
+const TrackType = {
+ MAIN: 0,
+ STAGE: 1,
+ BONUS: 2
+};
+
+/**
+ * Enum for map credits
+ * @enum {number}
+ */
+const MapCreditType = {
+ UNKNOWN: -1,
+ AUTHOR: 0,
+ CONTRIBUTOR: 1,
+ TESTER: 2,
+ SPECIAL_THANKS: 3
+};
+
+function getMainTrack(mapData, gamemode) {
+ return mapData.leaderboards.find(
+ (leaderboard) =>
+ leaderboard.gamemode === gamemode && leaderboard.trackType === TrackType.MAIN && leaderboard.style === 0
+ );
+}
+
+function getNumZones(mapData) {
+ return mapData.leaderboards.filter((leaderboard) => leaderboard.trackType === TrackType.STAGE).length;
+}
diff --git a/scripts/hud/map-info.js b/scripts/hud/map-info.js
index b651c5af..671f91a2 100644
--- a/scripts/hud/map-info.js
+++ b/scripts/hud/map-info.js
@@ -11,18 +11,20 @@ class HudMapInfo {
this.cachedInfoContainer.visible = true;
let authorString = '';
- for (const [i, item] of mapData['credits'].filter((x) => x.type === 'author').entries())
+ for (const [i, item] of mapData['credits'].filter((x) => x.type === MapCreditType.AUTHOR).entries())
authorString += (i > 0 ? ', ' : '') + item.user.alias;
const cp = $.GetContextPanel();
cp.SetDialogVariable('author', authorString);
- const mainTrack = mapData['mainTrack'];
- cp.SetDialogVariableInt('tier', mainTrack['difficulty']);
+ const mainTrack = getMainTrack(mapData, GameModeAPI.GetCurrentGameMode());
+ const numZones = getNumZones(mapData);
+
+ cp.SetDialogVariableInt('tier', mainTrack?.tier ?? 0);
cp.SetDialogVariable(
'zonetype',
- $.Localize(mainTrack['isLinear'] ? '#MapInfo_Type_Linear' : '#MapInfo_Type_Staged')
+ $.Localize(mainTrack?.isLinear ? '#MapInfo_Type_Linear' : '#MapInfo_Type_Staged')
);
- cp.SetDialogVariableInt('numzones', mainTrack['numZones']);
+ cp.SetDialogVariableInt('numzones', numZones);
} else {
this.cachedInfoContainer.visible = false;
}
diff --git a/scripts/hud/tab-menu.js b/scripts/hud/tab-menu.js
index 1e1d1895..a513c205 100644
--- a/scripts/hud/tab-menu.js
+++ b/scripts/hud/tab-menu.js
@@ -35,7 +35,7 @@ class HudTabMenu {
static setMapData(isOfficial) {
$.GetContextPanel().SetHasClass('hud-tab-menu--unofficial', !isOfficial);
- const img = GameModeInfoWithNull[GameModeAPI.GetCurrentGameMode()].shortName.toLowerCase();
+ const img = GameModeInfoWithNull[GameModeAPI.GetCurrentGameMode()].idName.toLowerCase();
this.panels.gamemodeImage.SetImage(`file://{images}/gamemodes/${img}.svg`);
@@ -51,7 +51,7 @@ class HudTabMenu {
// Delete existing name labels
for (const label of this.panels.credits.Children().slice(1) || []) label.DeleteAsync(0);
- const authorCredits = credits.filter((x) => x.type === 'author');
+ const authorCredits = credits.filter((x) => x.type === MapCreditType.AUTHOR);
for (const credit of authorCredits) {
const namePanel = $.CreatePanel('Label', this.panels.credits, '', {
@@ -87,13 +87,13 @@ class HudTabMenu {
static setMapStats(data) {
const cp = $.GetContextPanel();
- cp.SetDialogVariableInt('tier', data.mainTrack?.difficulty);
- cp.SetDialogVariable(
- 'type',
- $.Localize(data.mainTrack?.isLinear ? '#MapInfo_Type_Linear' : '#MapInfo_Type_Staged')
- );
- cp.SetDialogVariableInt('numzones', data.mainTrack?.numZones);
- cp.SetDialogVariableInt('runs', data.stats?.completes);
+ const mainTrack = getMainTrack(data, GameModeAPI.GetCurrentGameMode());
+ const numZones = getNumZones(data);
+
+ cp.SetDialogVariableInt('tier', mainTrack?.tier ?? 0);
+ cp.SetDialogVariable('type', $.Localize(mainTrack?.isLinear ? '#MapInfo_Type_Linear' : '#MapInfo_Type_Staged'));
+ cp.SetDialogVariableInt('numzones', numZones);
+ cp.SetDialogVariableInt('runs', data.stats?.completions);
}
static close() {
diff --git a/scripts/pages/loading-screen.js b/scripts/pages/loading-screen.js
index 2ccb62af..2b60e110 100644
--- a/scripts/pages/loading-screen.js
+++ b/scripts/pages/loading-screen.js
@@ -65,13 +65,16 @@ class LoadingScreen {
return;
}
+ const mainTrack = getMainTrack(mapData, GameModeAPI.GetCurrentGameMode());
+ const numZones = getNumZones(mapData);
+
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');
+ this.panels.cp.SetDialogVariableInt('tier', mainTrack?.tier ?? 0);
+ this.panels.cp.SetDialogVariableInt('numzones', numZones);
+ this.panels.cp.SetDialogVariable('tracktype', mainTrack?.isLinear ? 'Linear' : 'Staged');
let authorString = '';
- for (const [i, item] of mapData.credits.filter((x) => x.type === 'author').entries())
+ for (const [i, item] of mapData.credits.filter((x) => x.type === MapCreditType.AUTHOR).entries())
authorString += (i > 0 ? ', ' : '') + item.user.alias;
this.panels.cp.SetDialogVariable('author', authorString);
@@ -80,6 +83,6 @@ class LoadingScreen {
this.panels.tierAndType.visible = true;
this.panels.numZones.visible = true;
- this.panels.backgroundImage.SetImage(mapData.thumbnail.urlLarge);
+ this.panels.backgroundImage.SetImage(mapData.thumbnail.large);
}
}
diff --git a/scripts/pages/map-selector/map-entry.js b/scripts/pages/map-selector/map-entry.js
index 2c8db9af..25ab0d98 100644
--- a/scripts/pages/map-selector/map-entry.js
+++ b/scripts/pages/map-selector/map-entry.js
@@ -25,87 +25,74 @@ class MapEntry {
}
static showContextMenu() {
- const mapData = $.GetContextPanel().mapData;
- if (!mapData) return;
+ const { mapData, userMapData, isDownloading } = $.GetContextPanel();
+ if (!mapData || !userMapData) {
+ return;
+ }
const items = [];
- const isDownloading = $.GetContextPanel().isDownloading;
const mapID = mapData.id;
- if (mapData.inLibrary) {
- if (mapData.mapFileNeedsUpdate) {
- if (isDownloading) {
- items.push({
- label: $.Localize('#Action_CancelDownload'),
- icon: 'file://{images}/cancel.svg',
- style: 'icon-color-red',
-
- jsCallback: () => $.DispatchEvent('MapSelector_ShowConfirmCancelDownload', mapID)
- });
- } else if (MapCacheAPI.MapQueuedForDownload(mapID)) {
- items.push({
- label: $.Localize('#Action_RemoveFromQueue'),
- icon: 'file://{images}/playlist-remove.svg',
- style: 'icon-color-red',
- jsCallback: () => $.DispatchEvent('MapSelector_RemoveMapFromDownloadQueue', mapID)
- });
- } else {
- items.push({
- label: $.Localize('#Action_DownloadMap'),
- icon: 'file://{images}/play.svg',
- style: 'icon-color-mid-blue',
- jsCallback: () => $.DispatchEvent('MapSelector_TryPlayMap', mapID)
- });
+ if (userMapData.mapFileExists) {
+ items.push(
+ {
+ label: $.Localize('#Action_StartMap'),
+ icon: 'file://{images}/play.svg',
+ style: 'icon-color-green',
+ jsCallback: () => $.DispatchEvent('MapSelector_TryPlayMap', mapID)
+ },
+ // Gamemode override submenu
+ {
+ label: $.Localize('#Action_StartMapOverride'),
+ icon: 'file://{images}/alternative-mode.svg',
+ style: 'icon-color-green',
+ jsCallback: () => this.showGameModeOverrideMenu()
+ },
+ {
+ label: $.Localize('#Action_DeleteMap'),
+ icon: 'file://{images}/delete.svg',
+ style: 'icon-color-red',
+ jsCallback: () => $.DispatchEvent('MapSelector_DeleteMap', mapID)
}
+ );
+ } else {
+ if (isDownloading) {
+ items.push({
+ label: $.Localize('#Action_CancelDownload'),
+ icon: 'file://{images}/cancel.svg',
+ style: 'icon-color-red',
+ jsCallback: () => $.DispatchEvent('MapSelector_ShowConfirmCancelDownload', mapID)
+ });
+ } else if (MapCacheAPI.MapQueuedForDownload(mapID)) {
+ items.push({
+ label: $.Localize('#Action_RemoveFromQueue'),
+ icon: 'file://{images}/playlist-remove.svg',
+ style: 'icon-color-red',
+ jsCallback: () => $.DispatchEvent('MapSelector_RemoveMapFromDownloadQueue', mapID)
+ });
} else {
- items.push(
- {
- label: $.Localize('#Action_StartMap'),
- icon: 'file://{images}/play.svg',
- style: 'icon-color-green',
-
- jsCallback: () => $.DispatchEvent('MapSelector_TryPlayMap', mapID)
- },
-
- // Gamemode override submenu
- {
- label: $.Localize('#Action_StartMapOverride'),
- icon: 'file://{images}/alternative-mode.svg',
- style: 'icon-color-green',
- jsCallback: () => this.showGameModeOverrideMenu()
- }
- );
+ items.push({
+ label: $.Localize('#Action_DownloadMap'),
+ icon: 'file://{images}/play.svg',
+ style: 'icon-color-mid-blue',
+ jsCallback: () => $.DispatchEvent('MapSelector_TryPlayMap', mapID)
+ });
}
-
- items.push({
- label: $.Localize('#Action_DeleteMap'),
- icon: 'file://{images}/delete.svg',
- style: 'icon-color-red',
- jsCallback: () => $.DispatchEvent('MapSelector_ToggleMapStatus', mapID, true, false)
- });
- } else {
- items.push({
- label: $.Localize('#Action_DownloadMap'),
- icon: 'file://{images}/download.svg',
- style: 'icon-color-mid-blue',
- jsCallback: () => $.DispatchEvent('MapSelector_TryPlayMap', mapID)
- });
}
- if (mapData.isFavorited) {
+ if (userMapData.isFavorited) {
items.push({
label: $.Localize('#Action_RemoveFromFavorites'),
icon: 'file://{images}/favorite-remove.svg',
style: 'icon-color-yellow',
-
- jsCallback: () => $.DispatchEvent('MapSelector_ToggleMapStatus', mapID, false, false)
+ jsCallback: () => $.DispatchEvent('MapSelector_ToggleMapStatus', mapID, false)
});
} else {
items.push({
label: $.Localize('#Action_AddToFavorites'),
icon: 'file://{images}/star.svg',
style: 'icon-color-yellow',
- jsCallback: () => $.DispatchEvent('MapSelector_ToggleMapStatus', mapID, false, true)
+ jsCallback: () => $.DispatchEvent('MapSelector_ToggleMapStatus', mapID, true)
});
}
diff --git a/scripts/pages/map-selector/map-selector.js b/scripts/pages/map-selector/map-selector.js
index bb3c2a24..c66d1610 100644
--- a/scripts/pages/map-selector/map-selector.js
+++ b/scripts/pages/map-selector/map-selector.js
@@ -345,7 +345,7 @@ class MapSelection {
this.panels.credits.RemoveAndDeleteChildren();
// Find all authors
- const authorCredits = mapData.credits.filter((x) => x.type === 'author');
+ const authorCredits = mapData.credits.filter((x) => x.type === MapCreditType.AUTHOR);
const hasCredits = authorCredits.length > 0;