diff --git a/openrct2.vcxproj b/openrct2.vcxproj
index e104ee19a7..019cc6419d 100644
--- a/openrct2.vcxproj
+++ b/openrct2.vcxproj
@@ -264,7 +264,7 @@
-
+
diff --git a/openrct2.vcxproj.filters b/openrct2.vcxproj.filters
index eee82ee7c2..2e1f69fbca 100644
--- a/openrct2.vcxproj.filters
+++ b/openrct2.vcxproj.filters
@@ -561,6 +561,9 @@
Source
+
+ Source
+
@@ -845,6 +848,5 @@
Source
-
\ No newline at end of file
diff --git a/src/scenario.h b/src/scenario.h
index b547d1269a..d5ba798073 100644
--- a/src/scenario.h
+++ b/src/scenario.h
@@ -484,4 +484,7 @@ void scenario_success();
void scenario_success_submit_name(const char *name);
void scenario_autosave_check();
+bool scenario_get_index_and_source(const utf8 *name, scenario_source *source, sint32 *index);
+void scenario_normalise_name(utf8 *name);
+
#endif
diff --git a/src/scenario_list.c b/src/scenario_list.c
index a3b6e86b3a..ed7e7d747c 100644
--- a/src/scenario_list.c
+++ b/src/scenario_list.c
@@ -23,7 +23,6 @@
#include "platform/platform.h"
#include "util/util.h"
#include "scenario.h"
-#include "scenario_sources.h"
// Scenario list
int gScenarioListCount = 0;
@@ -39,9 +38,6 @@ static void scenario_list_add(const char *path);
static void scenario_list_sort();
static int scenario_list_sort_by_name(const void *a, const void *b);
static int scenario_list_sort_by_index(const void *a, const void *b);
-static sint32 get_scenario_index(utf8 *name);
-static void normalise_scenario_name(utf8 *name);
-static scenario_source source_by_index(sint32 index);
static bool scenario_scores_load();
static bool scenario_scores_legacy_load();
@@ -135,11 +131,14 @@ static void scenario_list_add(const utf8 *path)
safe_strncpy(newEntry->details, s6Info.details, sizeof(newEntry->details));
// Normalise the name to make the scenario as recognisable as possible.
- normalise_scenario_name(newEntry->name);
+ scenario_normalise_name(newEntry->name);
// Look up and store information regarding the origins of this scenario.
- newEntry->source_index = get_scenario_index(newEntry->name);
- newEntry->source_game = source_by_index(newEntry->source_index);
+ scenario_source source;
+ sint32 index;
+ scenario_get_index_and_source(newEntry->name, &source, &index);
+ newEntry->source_index = index;
+ newEntry->source_game = source;
}
void scenario_list_dispose()
@@ -182,63 +181,6 @@ static int scenario_list_sort_by_index(const void *a, const void *b)
return entryA->source_index - entryB->source_index;
}
-static sint32 get_scenario_index(utf8 *name)
-{
- for (sint32 i = 0; i < NUM_ORIGINAL_SCENARIOS; i++) {
- if (_strcmpi(original_scenario_names[i], name) == 0) {
- return i;
- }
- }
- return -1;
-}
-
-static void normalise_scenario_name(utf8 *name)
-{
- size_t nameLength = strlen(name);
-
- // Strip "RCT(1|2)? *" prefix off scenario names.
- if (nameLength >= 3 && (name[0] == 'R' && name[1] == 'C' && name[2] == 'T')) {
- if (nameLength >= 4 && (name[3] == '1' || name[3] == '2')) {
- log_verbose("Stripping RCT/1/2 from name: %s", name);
- safe_strncpy(name, name + 4, 64);
- } else {
- safe_strncpy(name, name + 3, 64);
- }
-
- safe_strtrimleft(name, name, 64);
- }
-
- // American scenario titles should be converted to British name
- // Don't worry, names will be translated using language packs later
- for (int i = 0; i < NUM_ALIASES; i++) {
- if (strcmp(scenario_aliases[(i * 2) + 1], name) == 0) {
- log_verbose("Found alias: %s; will treat as: %s", name, scenario_aliases[i * 2]);
- safe_strncpy(name, scenario_aliases[i * 2], 64);
- }
- }
-}
-
-static scenario_source source_by_index(sint32 index)
-{
- if (index >= SCENARIO_SOURCE_RCT1_INDEX && index < SCENARIO_SOURCE_RCT1_AA_INDEX) {
- return SCENARIO_SOURCE_RCT1;
- } else if (index >= SCENARIO_SOURCE_RCT1_AA_INDEX && index < SCENARIO_SOURCE_RCT1_LL_INDEX) {
- return SCENARIO_SOURCE_RCT1_AA;
- } else if (index >= SCENARIO_SOURCE_RCT1_LL_INDEX && index < SCENARIO_SOURCE_RCT2_INDEX) {
- return SCENARIO_SOURCE_RCT1_LL;
- } else if (index >= SCENARIO_SOURCE_RCT2_INDEX && index < SCENARIO_SOURCE_RCT2_WW_INDEX) {
- return SCENARIO_SOURCE_RCT2;
- } else if (index >= SCENARIO_SOURCE_RCT2_WW_INDEX && index < SCENARIO_SOURCE_RCT2_TT_INDEX) {
- return SCENARIO_SOURCE_RCT2_WW;
- } else if (index >= SCENARIO_SOURCE_RCT2_TT_INDEX && index < SCENARIO_SOURCE_REAL_INDEX) {
- return SCENARIO_SOURCE_RCT2_TT;
- } else if (index >= SCENARIO_SOURCE_REAL_INDEX && index < NUM_ORIGINAL_SCENARIOS) {
- return SCENARIO_SOURCE_REAL;
- } else {
- return SCENARIO_SOURCE_OTHER;
- }
-}
-
scenario_index_entry *scenario_list_find_by_path(const utf8 *path)
{
for (int i = 0; i < gScenarioListCount; i++) {
diff --git a/src/scenario_sources.c b/src/scenario_sources.c
new file mode 100644
index 0000000000..66c140e1ed
--- /dev/null
+++ b/src/scenario_sources.c
@@ -0,0 +1,248 @@
+#include "scenario.h"
+#include "util/util.h"
+
+typedef struct {
+ const utf8 *original;
+ const utf8 *alternative;
+} scenario_alias;
+
+const scenario_alias ScenarioAliases[] = {
+ { "Katie's Dreamland", "Katie's World" },
+ { "Pokey Park", "Dinky Park" },
+ { "White Water Park", "Aqua Park" },
+ { "Mystic Mountain", "Mothball Mountain" },
+ { "Paradise Pier", "Big Pier" },
+ { "Paradise Pier 2", "Big Pier 2" },
+};
+
+// RCT
+const utf8 * const ScenarioTitlesRCT1[] = {
+ "Forest Frontiers",
+ "Dynamite Dunes",
+ "Leafy Lake",
+ "Diamond Heights",
+ "Evergreen Gardens",
+ "Bumbly Beach",
+ "Trinity Islands",
+ "Katie's Dreamland",
+ "Pokey Park",
+ "White Water Park",
+ "Millennium Mines",
+ "Karts & Coasters",
+ "Mel's World",
+ "Mystic Mountain",
+ "Pacific Pyramids",
+ "Crumbly Woods",
+ "Paradise Pier",
+ "Lightning Peaks",
+ "Ivory Towers",
+ "Rainbow Valley",
+ "Thunder Rock",
+ "Mega Park",
+};
+
+// RCT: Added Attractions
+const utf8 * const ScenarioTitlesRCT1AA[] = {
+ "Whispering Cliffs",
+ "Three Monkeys Park",
+ "Canary Mines",
+ "Barony Bridge",
+ "Funtopia",
+ "Haunted Harbor",
+ "Fun Fortress",
+ "Future World",
+ "Gentle Glen",
+ "Jolly Jungle",
+ "Hydro Hills",
+ "Sprightly Park",
+ "Magic Quarters",
+ "Fruit Farm",
+ "Butterfly Dam",
+ "Coaster Canyon",
+ "Thunderstorm Park",
+ "Harmonic Hills",
+ "Roman Village",
+ "Swamp Cove",
+ "Adrenaline Heights",
+ "Utopia",
+ "Rotting Heights",
+ "Fiasco Forest",
+ "Pickle Park",
+ "Giggle Downs",
+ "Mineral Park",
+ "Coaster Crazy",
+ "Urban Park",
+ "Geoffrey Gardens",
+};
+
+// RCT: Loopy Landscapes
+const utf8 * const ScenarioTitlesRCT1LL[] = {
+ "Iceberg Islands",
+ "Volcania",
+ "Arid Heights",
+ "Razor Rocks",
+ "Crater Lake",
+ "Vertigo Views",
+ "Paradise Pier 2",
+ "Dragon's Cove",
+ "Good Knight Park",
+ "Wacky Warren",
+ "Grand Glacier",
+ "Crazy Craters",
+ "Dusty Desert",
+ "Woodworm Park",
+ "Icarus Park",
+ "Sunny Swamps",
+ "Frightmare Hills",
+ "Thunder Rocks",
+ "Octagon Park",
+ "Pleasure Island",
+ "Icicle Worlds",
+ "Tiny Towers",
+ "Southern Sands",
+ "Nevermore Park",
+ "Pacifica",
+ "Urban Jungle",
+ "Terror Town",
+ "Megaworld Park",
+ "Venus Ponds",
+ "Micro Park",
+};
+
+// RCT2
+const utf8 * const ScenarioTitlesRCT2[] = {
+ "Crazy Castle",
+ "Electric Fields",
+ "Factory Capers",
+ "Amity Airfield",
+ "Botany Breakers",
+ "Bumbly Bazaar",
+ "Dusty Greens",
+ "Fungus Woods",
+ "Gravity Gardens",
+ "Infernal Views",
+ "Alpine Adventures",
+ "Extreme Heights",
+ "Ghost Town",
+ "Lucky Lake",
+ "Rainbow Summit",
+};
+
+// RCT2: Wacky Worlds
+const utf8 * const ScenarioTitlesRCT2WW[] = {
+ "Africa - Victoria Falls",
+ "Asia - Great Wall of China Tourism Enhancement",
+ "North America - Grand Canyon",
+ "South America - Rio Carnival",
+ "Africa - African Diamond Mine",
+ "Asia - Maharaja Palace",
+ "Australasia - Ayers Rock",
+ "Europe - European Cultural Festival",
+ "North America - Rollercoaster Heaven",
+ "South America - Inca Lost City",
+ "Africa - Oasis",
+ "Antarctic - Ecological Salvage",
+ "Asia - Japanese Coastal Reclaim",
+ "Australasia - Fun at the Beach",
+ "Europe - Renovation",
+ "N. America - Extreme Hawaiian Island",
+ "South America - Rain Forest Plateau",
+};
+
+// RCT2: Time Twister
+const utf8 * const ScenarioTitlesRCT2TT[] = {
+ "Dark Age - Robin Hood",
+ "Prehistoric - After the Asteroid",
+ "Roaring Twenties - Prison Island",
+ "Rock 'n' Roll - Flower Power",
+ "Dark Age - Castle",
+ "Future - First Encounters",
+ "Mythological - Animatronic Film Set",
+ "Prehistoric - Jurassic Safari",
+ "Roaring Twenties - Schneider Cup",
+ "Future - Future World",
+ "Mythological - Cradle of Civilisation",
+ "Prehistoric - Stone Age",
+ "Roaring Twenties - Skyscrapers",
+ "Rock 'n' Roll - Rock 'n' Roll",
+};
+
+// Real parks
+const utf8 * const ScenarioTitlesRealParks[] = {
+ "Alton Towers",
+ "Heide-Park",
+ "Blackpool Pleasure Beach",
+ "Six Flags Belgium",
+ "Six Flags Great Adventure",
+ "Six Flags Holland",
+ "Six Flags Magic Mountain",
+ "Six Flags over Texas",
+};
+
+// Other parks
+const utf8 * const ScenarioTitlesRCT2BuildYourOwnParks[] = {
+ "Build your own Six Flags Belgium",
+ "Build your own Six Flags Great Adventure",
+ "Build your own Six Flags Holland",
+ "Build your own Six Flags Magic Mountain",
+ "Build your own Six Flags Park",
+ "Build your own Six Flags over Texas",
+};
+
+const struct {
+ int count;
+ const utf8 * const * titles;
+} ScenarioTitlesBySource[] = {
+ { countof(ScenarioTitlesRCT1), ScenarioTitlesRCT1 },
+ { countof(ScenarioTitlesRCT1AA), ScenarioTitlesRCT1AA },
+ { countof(ScenarioTitlesRCT1LL), ScenarioTitlesRCT1LL },
+ { countof(ScenarioTitlesRCT2), ScenarioTitlesRCT2 },
+ { countof(ScenarioTitlesRCT2WW), ScenarioTitlesRCT2WW },
+ { countof(ScenarioTitlesRCT2TT), ScenarioTitlesRCT2TT },
+ { countof(ScenarioTitlesRealParks), ScenarioTitlesRealParks },
+};
+
+bool scenario_get_index_and_source(const utf8 *name, scenario_source *source, sint32 *index)
+{
+ sint32 currentIndex = 0;
+ for (int i = 0; i < countof(ScenarioTitlesBySource); i++) {
+ for (int j = 0; j < ScenarioTitlesBySource[i].count; j++) {
+ if (_strcmpi(name, ScenarioTitlesBySource[i].titles[j]) == 0) {
+ *source = (scenario_source)i;
+ *index = currentIndex;
+ return true;
+ }
+ currentIndex++;
+ }
+ }
+
+ *source = SCENARIO_SOURCE_OTHER;
+ *index = -1;
+ return false;
+}
+
+void scenario_normalise_name(utf8 *name)
+{
+ size_t nameLength = strlen(name);
+
+ // Strip "RCT(1|2)? *" prefix off scenario names.
+ if (nameLength >= 3 && (name[0] == 'R' && name[1] == 'C' && name[2] == 'T')) {
+ if (nameLength >= 4 && (name[3] == '1' || name[3] == '2')) {
+ log_verbose("Stripping RCT/1/2 from name: %s", name);
+ safe_strncpy(name, name + 4, 64);
+ } else {
+ safe_strncpy(name, name + 3, 64);
+ }
+
+ safe_strtrimleft(name, name, 64);
+ }
+
+ // American scenario titles should be converted to British name
+ // Don't worry, names will be translated using language packs later
+ for (int i = 0; i < countof(ScenarioAliases); i++) {
+ if (strcmp(ScenarioAliases[i].alternative, name) == 0) {
+ log_verbose("Found alias: %s; will treat as: %s", name, ScenarioAliases[i].original);
+ safe_strncpy(name, ScenarioAliases[i].original, 64);
+ }
+ }
+}
diff --git a/src/scenario_sources.h b/src/scenario_sources.h
deleted file mode 100644
index 78efee823a..0000000000
--- a/src/scenario_sources.h
+++ /dev/null
@@ -1,171 +0,0 @@
-#define NUM_ORIGINAL_SCENARIOS 136
-#define NUM_ALIASES 6
-
-#define SCENARIO_SOURCE_RCT1_INDEX 0
-#define SCENARIO_SOURCE_RCT1_AA_INDEX 22
-#define SCENARIO_SOURCE_RCT1_LL_INDEX 52
-#define SCENARIO_SOURCE_RCT2_INDEX 82
-#define SCENARIO_SOURCE_RCT2_WW_INDEX 97
-#define SCENARIO_SOURCE_RCT2_TT_INDEX 114
-#define SCENARIO_SOURCE_REAL_INDEX 128
-
-const char * const scenario_aliases[NUM_ALIASES * 2] = {
- "Katie's Dreamland", "Katie's World",
- "Pokey Park", "Dinky Park",
- "White Water Park", "Aqua Park",
- "Mystic Mountain", "Mothball Mountain",
- "Paradise Pier", "Big Pier",
- "Paradise Pier 2", "Big Pier 2",
-};
-
-const char * const original_scenario_names[NUM_ORIGINAL_SCENARIOS] = {
- // RCT
- "Forest Frontiers",
- "Dynamite Dunes",
- "Leafy Lake",
- "Diamond Heights",
- "Evergreen Gardens",
- "Bumbly Beach",
- "Trinity Islands",
- "Katie's Dreamland",
- "Pokey Park",
- "White Water Park",
- "Millennium Mines",
- "Karts & Coasters",
- "Mel's World",
- "Mystic Mountain",
- "Pacific Pyramids",
- "Crumbly Woods",
- "Paradise Pier",
- "Lightning Peaks",
- "Ivory Towers",
- "Rainbow Valley",
- "Thunder Rock",
- "Mega Park",
-
- // RCT: Added Attractions
- "Whispering Cliffs",
- "Three Monkeys Park",
- "Canary Mines",
- "Barony Bridge",
- "Funtopia",
- "Haunted Harbor",
- "Fun Fortress",
- "Future World",
- "Gentle Glen",
- "Jolly Jungle",
- "Hydro Hills",
- "Sprightly Park",
- "Magic Quarters",
- "Fruit Farm",
- "Butterfly Dam",
- "Coaster Canyon",
- "Thunderstorm Park",
- "Harmonic Hills",
- "Roman Village",
- "Swamp Cove",
- "Adrenaline Heights",
- "Utopia Park",
- "Rotting Heights",
- "Fiasco Forest",
- "Pickle Park",
- "Giggle Downs",
- "Mineral Park",
- "Coaster Crazy",
- "Urban Park",
- "Geoffrey Gardens",
-
- // RCT: Loopy Landscapes
- "Iceberg Islands",
- "Volcania",
- "Arid Heights",
- "Razor Rocks",
- "Crater Lake",
- "Vertigo Views",
- "Paradise Pier 2",
- "Dragon's Cove",
- "Good Knight Park",
- "Wacky Warren",
- "Grand Glacier",
- "Crazy Craters",
- "Dusty Desert",
- "Woodworm Park",
- "Icarus Park",
- "Sunny Swamps",
- "Frightmare Hills",
- "Thunder Rocks",
- "Octagon Park",
- "Pleasure Island",
- "Icicle Worlds",
- "Tiny Towers",
- "Southern Sands",
- "Nevermore Park",
- "Pacifica",
- "Urban Jungle",
- "Terror Town",
- "Megaworld Park",
- "Venus Ponds",
- "Micro Park",
-
- // RCT2
- "Crazy Castle",
- "Electric Fields",
- "Factory Capers",
- "Amity Airfield",
- "Botany Breakers",
- "Bumbly Bazaar",
- "Dusty Greens",
- "Fungus Woods",
- "Gravity Gardens",
- "Infernal Views",
- "Alpine Adventures",
- "Extreme Heights",
- "Ghost Town",
- "Lucky Lake",
- "Rainbow Summit",
-
- // RCT2: Wacky Worlds
- "Africa - Victoria Falls",
- "Asia - Great Wall of China Tourism Enhancement",
- "North America - Grand Canyon",
- "South America - Rio Carnival",
- "Africa - African Diamond Mine",
- "Asia - Maharaja Palace",
- "Australasia - Ayers Rock",
- "Europe - European Cultural Festival",
- "North America - Rollercoaster Heaven",
- "South America - Inca Lost City",
- "Africa - Oasis",
- "Antarctic - Ecological Salvage",
- "Asia - Japanese Coastal Reclaim",
- "Australasia - Fun at the Beach",
- "Europe - Renovation",
- "N. America - Extreme Hawaiian Island",
- "South America - Rain Forest Plateau",
-
- // RCT2: Time Twister
- "Dark Age - Robin Hood",
- "Prehistoric - After the Asteroid",
- "Roaring Twenties - Prison Island",
- "Rock 'n' Roll - Flower Power",
- "Dark Age - Castle",
- "Future - First Encounters",
- "Mythological - Animatronic Film Set",
- "Prehistoric - Jurassic Safari",
- "Roaring Twenties - Schneider Cup",
- "Future - Future World",
- "Mythological - Cradle of Civilisation",
- "Prehistoric - Stone Age",
- "Roaring Twenties - Skyscrapers",
- "Rock 'n' Roll - Rock 'n' Roll",
-
- // Real parks
- "Alton Towers",
- "Heide-Park",
- "Blackpool Pleasure Beach",
- "Six Flags Belgium",
- "Six Flags Great Adventure",
- "Six Flags Holland",
- "Six Flags Magic Mountain",
- "Six Flags over Texas"
-};
diff --git a/src/windows/title_scenarioselect.c b/src/windows/title_scenarioselect.c
index c754a293e6..208b4ae989 100644
--- a/src/windows/title_scenarioselect.c
+++ b/src/windows/title_scenarioselect.c
@@ -505,12 +505,12 @@ static void initialise_list_items(rct_window *w)
// Category heading
rct_string_id headingStringId = STR_NONE;
if (gConfigGeneral.scenario_select_mode == SCENARIO_SELECT_MODE_ORIGIN) {
- if (currentHeading != scenario->category) {
+ if (w->selected_tab != 6 && currentHeading != scenario->category) {
currentHeading = scenario->category;
headingStringId = STR_BEGINNER_PARKS + currentHeading;
}
} else {
- if (currentHeading != scenario->source_game) {
+ if (w->selected_tab < 3 && currentHeading != scenario->source_game) {
currentHeading = scenario->source_game;
headingStringId = STR_SCENARIO_CATEGORY_RCT1 + currentHeading;
}