diff --git a/data/title/achilleshiel.sv6 b/data/title/achilleshiel.sv6
new file mode 100644
index 0000000000..24ce7be588
Binary files /dev/null and b/data/title/achilleshiel.sv6 differ
diff --git a/data/title/faas.sv6 b/data/title/faas.sv6
new file mode 100644
index 0000000000..bb7ce80cb7
Binary files /dev/null and b/data/title/faas.sv6 differ
diff --git a/data/title/mci.sv6 b/data/title/mci.sv6
new file mode 100644
index 0000000000..95008afc08
Binary files /dev/null and b/data/title/mci.sv6 differ
diff --git a/data/title/pfckrutonium1.sv6 b/data/title/pfckrutonium1.sv6
new file mode 100644
index 0000000000..25ba708455
Binary files /dev/null and b/data/title/pfckrutonium1.sv6 differ
diff --git a/data/title/pfckrutonium2.sv6 b/data/title/pfckrutonium2.sv6
new file mode 100644
index 0000000000..59de4c0c38
Binary files /dev/null and b/data/title/pfckrutonium2.sv6 differ
diff --git a/data/title/poke.sv6 b/data/title/poke.sv6
new file mode 100644
index 0000000000..f9702ff6dc
Binary files /dev/null and b/data/title/poke.sv6 differ
diff --git a/data/title/rid6.sv6 b/data/title/rid6.sv6
new file mode 100644
index 0000000000..c83a3af928
Binary files /dev/null and b/data/title/rid6.sv6 differ
diff --git a/data/title/script.txt b/data/title/script.txt
new file mode 100644
index 0000000000..e9651aeb15
--- /dev/null
+++ b/data/title/script.txt
@@ -0,0 +1,90 @@
+# OpenRCT2 0.0.2 Title Sequence Script
+# Arranged by IntelOrca
+
+# PFCKrutonium
+LOAD pfckrutonium1.sv6
+LOCATION 7 41
+WAIT 15
+LOCATION 49 15
+ROTATE 1
+WAIT 10
+
+# Achilleshiel
+LOAD achilleshiel.sv6
+LOCATION 25 77
+WAIT 10
+
+LOCATION 36 58
+ROTATE 3
+WAIT 12
+
+LOCATION 64 40
+ROTATE 1
+WAIT 8
+
+# PFCKrutonium
+LOAD pfckrutonium2.sv6
+LOCATION 116 58
+WAIT 14
+
+ROTATE 1
+WAIT 12
+
+# Shotguns (http://www.nedesigns.com/park/3107/rougarou/)
+LOAD shotguns.sv6
+LOCATION 20 13
+WAIT 16
+
+# Faas (http://www.nedesigns.com/park/2996/lucky-lake-amusement-park/)
+LOAD faas.sv6
+LOCATION 42 11
+WAIT 10
+
+LOCATION 30 18
+ROTATE 1
+WAIT 16
+
+LOCATION 17 71
+ROTATE 2
+WAIT 12
+
+LOCATION 88 68
+WAIT 12
+
+# MCI (http://www.nedesigns.com/park/2973/maerchen-paradies/)
+LOAD mci.sv6
+LOCATION 46 60
+WAIT 16
+
+LOCATION 78 43
+ROTATE 2
+WAIT 12
+
+LOCATION 76 32
+ROTATE 1
+WAIT 8
+
+# Ride6 (http://www.nedesigns.com/park/2545/banana-valley/)
+LOAD rid6.sv6
+LOCATION 56 34
+WAIT 10
+
+LOCATION 48 4
+WAIT 4
+
+LOCATION 10 29
+ROTATE 1
+WAIT 12
+
+# Poke (http://www.nedesigns.com/park/2967/mystic-mountain/)
+LOAD poke.sv6
+LOCATION 43 83
+WAIT 16
+
+LOCATION 63 35
+ROTATE 3
+WAIT 12
+
+LOCATION 12 47
+ROTATE 3
+WAIT 20
\ No newline at end of file
diff --git a/data/title/shotguns.sv6 b/data/title/shotguns.sv6
new file mode 100644
index 0000000000..a40b6425a4
Binary files /dev/null and b/data/title/shotguns.sv6 differ
diff --git a/projects/openrct2.vcxproj b/projects/openrct2.vcxproj
index 9295f82d6c..3e8b0c411a 100644
--- a/projects/openrct2.vcxproj
+++ b/projects/openrct2.vcxproj
@@ -333,6 +333,10 @@
true
winmm.lib;sdl2.lib;Dsound.lib;%(AdditionalDependencies)
+
+ "$(TargetDir)\openrct2.exe" sprite build "$(SolutionDir)\..\Data\g2.dat" "$(SolutionDir)\..\Resources\g2\"
+xcopy /YS "$(SolutionDir)\..\Data" "$(TargetDir)\Data"
+
@@ -361,7 +365,7 @@
"$(TargetDir)\openrct2.exe" sprite build "$(SolutionDir)\..\Data\g2.dat" "$(SolutionDir)\..\Resources\g2\"
-xcopy /Y "$(SolutionDir)\..\Data\*.*" "$(TargetDir)\Data\"
+xcopy /YS "$(SolutionDir)\..\Data" "$(TargetDir)\Data"
Build g2.dat and copy the Data directory.
@@ -400,7 +404,7 @@ xcopy /Y "$(SolutionDir)\..\Data\*.*" "$(TargetDir)\Data\"
"$(TargetDir)\openrct2.exe" sprite build "$(SolutionDir)\..\Data\g2.dat" "$(SolutionDir)\..\Resources\g2\"
-xcopy /Y "$(SolutionDir)\..\Data\*.*" "$(TargetDir)\Data\"
+xcopy /YS "$(SolutionDir)\..\Data" "$(TargetDir)\Data"
Build g2.dat and copy the Data directory.
diff --git a/src/config.c b/src/config.c
index 03e80495ea..9105d3f9ed 100644
--- a/src/config.c
+++ b/src/config.c
@@ -177,6 +177,7 @@ config_property_definition _generalDefinitions[] = {
{ offsetof(general_configuration, date_format), "date_format", CONFIG_VALUE_TYPE_UINT8, DATE_FORMAT_DMY, _dateFormatEnum },
{ offsetof(general_configuration, auto_staff_placement), "auto_staff", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL },
{ offsetof(general_configuration, last_run_version), "last_run_version", CONFIG_VALUE_TYPE_STRING, { .value_string = NULL }, NULL },
+ { offsetof(general_configuration, title_sequence), "title_sequence", CONFIG_VALUE_TYPE_UINT8, TITLE_SEQUENCE_OPENRCT2, NULL },
};
config_property_definition _interfaceDefinitions[] = {
diff --git a/src/config.h b/src/config.h
index 50ab7e7c95..d9fcd3ae62 100644
--- a/src/config.h
+++ b/src/config.h
@@ -103,6 +103,15 @@ enum {
DATE_FORMAT_MDY
};
+enum {
+ TITLE_SEQUENCE_RCT1,
+ TITLE_SEQUENCE_RCT1_AA,
+ TITLE_SEQUENCE_RCT1_AA_LL,
+ TITLE_SEQUENCE_RCT2,
+ TITLE_SEQUENCE_OPENRCT2,
+ TITLE_SEQUENCE_RANDOM
+};
+
typedef struct {
uint8 play_intro;
uint8 confirmation_prompt;
@@ -134,6 +143,7 @@ typedef struct {
uint8 date_format;
uint8 auto_staff_placement;
utf8string last_run_version;
+ uint8 title_sequence;
} general_configuration;
typedef struct {
diff --git a/src/game.c b/src/game.c
index 4c52a69f61..1245676d68 100644
--- a/src/game.c
+++ b/src/game.c
@@ -601,9 +601,8 @@ static void load_landscape()
*
* rct2: 0x00675E1B
*/
-int game_load_save(const char *path)
+int game_load_sv6(const char *path)
{
- rct_window *mainWindow;
FILE *file;
int i, j;
@@ -672,8 +671,7 @@ int game_load_save(const char *path)
RCT2_GLOBAL(0x14241BC, uint32) = 0;
RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~INPUT_FLAG_5;
}
- title_load();
- rct2_endupdate();
+
return 0;//This never gets called
}
@@ -681,6 +679,23 @@ int game_load_save(const char *path)
reset_loaded_objects();
map_update_tile_pointers();
reset_0x69EBE4();
+ return 1;
+}
+
+/**
+ *
+ * rct2: 0x00675E1B
+ */
+int game_load_save(const char *path)
+{
+ rct_window *mainWindow;
+
+ if (!game_load_sv6(path)) {
+ title_load();
+ rct2_endupdate();
+ return 0;
+ }
+
RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_PLAYING;
viewport_init_all();
game_create_windows();
diff --git a/src/game.h b/src/game.h
index e06a29f18b..219689e810 100644
--- a/src/game.h
+++ b/src/game.h
@@ -107,6 +107,7 @@ void game_increase_game_speed();
void game_reduce_game_speed();
void game_load_or_quit_no_save_prompt();
+int game_load_sv6(const char *path);
int game_load_save(const char *path);
void game_pause_toggle(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp);
void pause_toggle();
diff --git a/src/interface/window.c b/src/interface/window.c
index 13014556e4..2c210a78ac 100644
--- a/src/interface/window.c
+++ b/src/interface/window.c
@@ -1401,26 +1401,31 @@ void window_rotate_camera(rct_window *w)
reset_all_sprite_quadrant_placements();
}
-/**
- *
- * rct2: 0x006887A6
- */
-void window_zoom_in(rct_window *w)
+void window_zoom_set(rct_window *w, int zoomLevel)
{
rct_viewport* v = w->viewport;
-
- // Prevent zooming more than possible.
- if (v->zoom <= 0) {
+
+ zoomLevel = clamp(0, zoomLevel, 3);
+ if (v->zoom == zoomLevel)
return;
+
+ // Zoom in
+ while (v->zoom > zoomLevel) {
+ v->zoom--;
+ w->saved_view_x += v->view_width / 4;
+ w->saved_view_y += v->view_height / 4;
+ v->view_width /= 2;
+ v->view_height /= 2;
}
- v->zoom--;
-
- v->view_width /= 2;
- v->view_height /= 2;
-
- w->saved_view_x += v->view_width >> 1;
- w->saved_view_y += v->view_height >> 1;
+ // Zoom out
+ while (v->zoom < zoomLevel) {
+ v->zoom++;
+ w->saved_view_x -= v->view_width / 2;
+ w->saved_view_y -= v->view_height / 2;
+ v->view_width *= 2;
+ v->view_height *= 2;
+ }
// HACK: Prevents the redraw from failing when there is
// a window on top of the viewport.
@@ -1428,34 +1433,22 @@ void window_zoom_in(rct_window *w)
window_invalidate(w);
}
+/**
+ *
+ * rct2: 0x006887A6
+ */
+void window_zoom_in(rct_window *w)
+{
+ window_zoom_set(w, w->viewport->zoom - 1);
+}
+
/**
*
* rct2: 0x006887E0
*/
void window_zoom_out(rct_window *w)
{
- rct_viewport* v = w->viewport;
-
- // Prevent zooming more than possible.
- if (v->zoom >= 3) {
- return;
- }
-
- v->zoom++;
-
- int width = v->view_width;
- int height = v->view_height;
-
- v->view_width *= 2;
- v->view_height *= 2;
-
- w->saved_view_x -= width / 2;
- w->saved_view_y -= height >> 1;
-
- // HACK: Prevents the redraw from failing when there is
- // a window on top of the viewport.
- window_bring_to_front(w);
- window_invalidate(w);
+ window_zoom_set(w, w->viewport->zoom + 1);
}
/**
diff --git a/src/interface/window.h b/src/interface/window.h
index 89f7d394ab..6196f8fb67 100644
--- a/src/interface/window.h
+++ b/src/interface/window.h
@@ -492,6 +492,7 @@ rct_window *window_get_main();
void window_scroll_to_viewport(rct_window *w);
void window_scroll_to_location(rct_window *w, int x, int y, int z);
void window_rotate_camera(rct_window *w);
+void window_zoom_set(rct_window *w, int zoomLevel);
void window_zoom_in(rct_window *w);
void window_zoom_out(rct_window *w);
diff --git a/src/localisation/string_ids.h b/src/localisation/string_ids.h
index 491b9524b6..b1170543fe 100644
--- a/src/localisation/string_ids.h
+++ b/src/localisation/string_ids.h
@@ -1512,6 +1512,14 @@ enum {
STR_CHANGELOG_TITLE = 5344,
+ STR_TITLE_SEQUENCE = 5304,
+ STR_TITLE_SEQUENCE_RCT1 = 5305,
+ STR_TITLE_SEQUENCE_RCT1_AA = 5306,
+ STR_TITLE_SEQUENCE_RCT1_AA_LL = 5307,
+ STR_TITLE_SEQUENCE_RCT2 = 5308,
+ STR_TITLE_SEQUENCE_OPENRCT2 = 5309,
+ STR_TITLE_SEQUENCE_RANDOM = 5310,
+
// Have to include resource strings (from scenarios and objects) for the time being now that language is partially working
STR_COUNT = 32768
};
diff --git a/src/title.c b/src/title.c
index 5b9a1939e4..4f710188a1 100644
--- a/src/title.c
+++ b/src/title.c
@@ -36,33 +36,37 @@
#include "openrct2.h"
#include "ride/ride.h"
#include "scenario.h"
+#include "util/util.h"
#include "world/climate.h"
#include "world/map.h"
#include "world/park.h"
#include "world/scenery.h"
#include "world/sprite.h"
-static const int gOldMusic = 0;
static const int gRandomShowcase = 0;
#pragma region Showcase script
enum {
TITLE_SCRIPT_WAIT,
- TITLE_SCRIPT_LOAD,
+ TITLE_SCRIPT_LOADMM,
TITLE_SCRIPT_LOCATION,
TITLE_SCRIPT_ROTATE,
+ TITLE_SCRIPT_ZOOM,
TITLE_SCRIPT_RESTART,
+ TITLE_SCRIPT_LOAD
};
#define WAIT(t) TITLE_SCRIPT_WAIT, t
-#define LOAD() TITLE_SCRIPT_LOAD
+#define LOADMM() TITLE_SCRIPT_LOADMM
#define LOCATION(x, y) TITLE_SCRIPT_LOCATION, x, y
#define ROTATE(n) TITLE_SCRIPT_ROTATE, n
+#define ZOOM(d) TITLE_SCRIPT_ZOOM, d
#define RESTART() TITLE_SCRIPT_RESTART
+#define LOAD(i) TITLE_SCRIPT_LOAD, i
static const uint8 _magicMountainScript[] = {
- LOAD(),
+ LOADMM(),
LOCATION(210, 112), WAIT(13),
ROTATE(1), LOCATION(210, 112), WAIT(14),
ROTATE(3), LOCATION(167, 180), WAIT(12),
@@ -74,12 +78,13 @@ static const uint8 _magicMountainScript[] = {
RESTART(),
};
+static uint8* _loadedScript;
static const uint8* _currentScript;
+static int _scriptNoLoadsSinceRestart;
static int _scriptWaitCounter;
static void title_init_showcase();
static void title_update_showcase();
-static void title_play_music();
static uint8 *generate_random_script();
@@ -87,6 +92,8 @@ static uint8 *generate_random_script();
static void title_create_windows();
+static uint8 *title_script_load();
+
/**
*
* rct2: 0x0068E8DA
@@ -153,101 +160,204 @@ static void title_create_windows()
*/
static void title_init_showcase()
{
+ _scriptNoLoadsSinceRestart = 1;
+
+ SafeFree(_loadedScript);
+
_currentScript = _magicMountainScript;
- if (gRandomShowcase)
- _currentScript = generate_random_script();
+ switch (gConfigGeneral.title_sequence) {
+ case TITLE_SEQUENCE_OPENRCT2:
+ _loadedScript = title_script_load();
+ if (_loadedScript != NULL)
+ _currentScript = _loadedScript;
+ break;
+ case TITLE_SEQUENCE_RANDOM:
+ _loadedScript = generate_random_script();
+ _currentScript = _loadedScript;
+ break;
+ }
+
_scriptWaitCounter = 0;
title_update_showcase();
}
+static int title_load_park(const char *path)
+{
+ rct_window* w;
+ int successfulLoad;
+
+ successfulLoad = _strcmpi(path_get_extension(path), ".sv6") == 0 ?
+ game_load_sv6(path) :
+ scenario_load(path);
+
+ if (!successfulLoad)
+ return 0;
+
+ w = window_get_main();
+ w->viewport_target_sprite = -1;
+ w->saved_view_x = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_X, sint16);
+ w->saved_view_y = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_Y, sint16);
+
+ {
+ char _cl = (RCT2_GLOBAL(0x0138869E, sint16) & 0xFF) - w->viewport->zoom;
+ w->viewport->zoom = RCT2_GLOBAL(0x0138869E, sint16) & 0xFF;
+ *((char*)(&RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, sint32))) = RCT2_GLOBAL(0x0138869E, sint16) >> 8;
+ if (_cl != 0) {
+ if (_cl < 0) {
+ _cl = -_cl;
+ w->viewport->view_width >>= _cl;
+ w->viewport->view_height >>= _cl;
+ } else {
+ w->viewport->view_width <<= _cl;
+ w->viewport->view_height <<= _cl;
+ }
+ }
+ w->saved_view_x -= w->viewport->view_width >> 1;
+ w->saved_view_y -= w->viewport->view_height >> 1;
+ }
+
+ window_invalidate(w);
+ reset_all_sprite_quadrant_placements();
+ window_new_ride_init_vars();
+ if (_strcmpi(path_get_extension(path), ".sv6") != 0)
+ sub_684AC3();
+ RCT2_CALLPROC_EBPSAFE(0x006DFEE4);
+ news_item_init_queue();
+ gfx_invalidate_screen();
+ RCT2_GLOBAL(0x009DEA66, sint16) = 0;
+ RCT2_GLOBAL(0x009DEA5C, sint16) = 0x0D6D8;
+ return 1;
+}
+
+static void title_skip_opcode()
+{
+ uint8 script_opcode;
+
+ script_opcode = *_currentScript++;
+ switch (script_opcode) {
+ case TITLE_SCRIPT_WAIT:
+ _currentScript++;
+ break;
+ case TITLE_SCRIPT_LOADMM:
+ _currentScript++;
+ break;
+ case TITLE_SCRIPT_LOCATION:
+ _currentScript++;
+ _currentScript++;
+ break;
+ case TITLE_SCRIPT_ROTATE:
+ _currentScript++;
+ break;
+ case TITLE_SCRIPT_RESTART:
+ break;
+ case TITLE_SCRIPT_LOAD:
+ do {
+ _currentScript++;
+ } while (*(_currentScript - 1) != 0);
+ break;
+ }
+}
+
+static void title_do_next_script_opcode()
+{
+ int i;
+ short x, y, z;
+ uint8 script_opcode, script_operand;
+ rct_window* w;
+
+ script_opcode = *_currentScript++;
+ switch (script_opcode) {
+ case TITLE_SCRIPT_WAIT:
+ _scriptWaitCounter = (*_currentScript++) * 32;
+ break;
+ case TITLE_SCRIPT_LOADMM:
+ if (!title_load_park(get_file_path(PATH_ID_SIXFLAGS_MAGICMOUNTAIN))) {
+ log_fatal("OpenRCT2 can not currently cope when unable to load title screen scenario.");
+ exit(-1);
+ }
+ break;
+ case TITLE_SCRIPT_LOCATION:
+ x = (*_currentScript++) * 32 + 16;
+ y = (*_currentScript++) * 32 + 16;
+ z = map_element_height(x, y);
+
+ // Update viewport
+ w = window_get_main();
+ if (w != NULL) {
+ window_scroll_to_location(w, x, y, z);
+ w->flags &= ~WF_SCROLLING_TO_LOCATION;
+ viewport_update_position(w);
+ }
+ break;
+ case TITLE_SCRIPT_ROTATE:
+ script_operand = (*_currentScript++);
+ w = window_get_main();
+ if (w != NULL)
+ for (i = 0; i < script_operand; i++)
+ window_rotate_camera(w);
+ break;
+ case TITLE_SCRIPT_ZOOM:
+ script_operand = (*_currentScript++);
+ w = window_get_main();
+ if (w != NULL && w->viewport != NULL)
+ window_zoom_set(w, script_operand);
+ break;
+ case TITLE_SCRIPT_RESTART:
+ _scriptNoLoadsSinceRestart = 1;
+ _currentScript = _loadedScript;
+ if (gRandomShowcase) {
+ if (_currentScript != NULL)
+ free((uint8*)_currentScript);
+ _currentScript = generate_random_script();
+ }
+ break;
+ case TITLE_SCRIPT_LOAD:
+ {
+ const uint8 *loadPtr;
+ char *ch, filename[32], path[MAX_PATH];
+
+ loadPtr = _currentScript - 1;
+
+ // Get filename
+ ch = filename;
+ do {
+ *ch++ = *_currentScript++;
+ } while (*(_currentScript - 1) != 0);
+
+ // Construct full relative path
+ sprintf(path, "data%ctitle%c%s", platform_get_path_separator(), platform_get_path_separator(), filename);
+ if (title_load_park(path)) {
+ _scriptNoLoadsSinceRestart = 0;
+ } else {
+ script_opcode = *_currentScript;
+ while (script_opcode != TITLE_SCRIPT_LOADMM && script_opcode != TITLE_SCRIPT_LOAD && script_opcode != TITLE_SCRIPT_RESTART) {
+ title_skip_opcode();
+ script_opcode = *_currentScript;
+ }
+
+ if (script_opcode == TITLE_SCRIPT_RESTART && _scriptNoLoadsSinceRestart) {
+ if (_currentScript != _magicMountainScript) {
+ _currentScript = _magicMountainScript;
+ } else {
+ log_fatal("OpenRCT2 can not currently cope when unable to load title screen scenario.");
+ exit(-1);
+ }
+ }
+ }
+ }
+ break;
+ }
+}
+
/**
*
* rct2: 0x00678761
*/
static void title_update_showcase()
{
- rct_window* w;
- uint8 script_opcode, script_operand;
- short x, y, z;
- int i;
-
if (_scriptWaitCounter <= 0) {
do {
- script_opcode = *_currentScript++;
- switch (script_opcode) {
- case TITLE_SCRIPT_WAIT:
- _scriptWaitCounter = (*_currentScript++) * 32;
- break;
- case TITLE_SCRIPT_LOAD:
- if (scenario_load(get_file_path(PATH_ID_SIXFLAGS_MAGICMOUNTAIN))) {
- log_verbose("loaded title scenario");
- } else {
- load_palette();
- title_create_windows();
- }
-
- w = window_get_main();
- w->viewport_target_sprite = -1;
- w->saved_view_x = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_X, sint16);
- w->saved_view_y = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_Y, sint16);
-
- {
- char _cl = (RCT2_GLOBAL(0x0138869E, sint16) & 0xFF) - w->viewport->zoom;
- w->viewport->zoom = RCT2_GLOBAL(0x0138869E, sint16) & 0xFF;
- *((char*)(&RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, sint32))) = RCT2_GLOBAL(0x0138869E, sint16) >> 8;
- if (_cl != 0) {
- if (_cl < 0) {
- _cl = -_cl;
- w->viewport->view_width >>= _cl;
- w->viewport->view_height >>= _cl;
- } else {
- w->viewport->view_width <<= _cl;
- w->viewport->view_height <<= _cl;
- }
- }
- w->saved_view_x -= w->viewport->view_width >> 1;
- w->saved_view_y -= w->viewport->view_height >> 1;
- }
-
- window_invalidate(w);
- reset_all_sprite_quadrant_placements();
- window_new_ride_init_vars();
- sub_684AC3();
- scenery_set_default_placement_configuration();
- news_item_init_queue();
- gfx_invalidate_screen();
- RCT2_GLOBAL(0x009DEA66, sint16) = 0;
- RCT2_GLOBAL(0x009DEA5C, sint16) = 0x0D6D8;
- break;
- case TITLE_SCRIPT_LOCATION:
- x = (*_currentScript++) * 32 + 16;
- y = (*_currentScript++) * 32 + 16;
- z = map_element_height(x, y);
-
- // Update viewport
- w = window_get_main();
- if (w != NULL) {
- window_scroll_to_location(w, x, y, z);
- w->flags &= ~0x08;
- viewport_update_position(w);
- }
- break;
- case TITLE_SCRIPT_ROTATE:
- script_operand = (*_currentScript++);
- w = window_get_main();
- if (w != NULL)
- for (i = 0; i < script_operand; i++)
- window_rotate_camera(w);
- break;
- case TITLE_SCRIPT_RESTART:
- _currentScript = _magicMountainScript;
- if (gRandomShowcase) {
- if (_currentScript != NULL)
- free((uint8*)_currentScript);
- _currentScript = generate_random_script();
- }
- break;
- }
+ title_do_next_script_opcode();
} while (_scriptWaitCounter == 0);
}
@@ -279,7 +389,7 @@ void title_update()
if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) == 0) {
title_update_showcase();
game_logic_update();
- start_title_music();//title_play_music();
+ start_title_music();
}
RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~0x80;
@@ -304,38 +414,6 @@ void title_update()
}
}
-/**
- *
- * rct2: 0x00678761
- */
-// this doesn't seem like it is 0x00678761, supposed to be 0x006BD0F8?
-static void title_play_music()
-{
- RCT2_CALLPROC_EBPSAFE(0x006BD0F8); // play title screen music
-
- if (!(RCT2_GLOBAL(0x009AF284, uint32) & 1) || !(RCT2_GLOBAL(0x009AF59D, uint8) & 1)) {
- if (RCT2_GLOBAL(0x009AF600, uint8) != 0)
- stop_title_music();
- return;
- }
-
- if (RCT2_GLOBAL(0x009AF600, uint8) != 0)
- return;
-
- // Play old title music
- char musicPath[_MAX_PATH];
- strcpy(musicPath, get_file_path(PATH_ID_CSS17));
- if (gOldMusic) {
- strcpy(musicPath, RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH, char));
- strcat(musicPath, "\\data\\css50.dat");
- }
-
- if (sound_channel_load_file2(3, musicPath, 0)) // play music
- sound_channel_play(3, 1, 0, 0, 0);
-
- RCT2_GLOBAL(0x009AF600, uint8) = 1;
-}
-
static uint8 *generate_random_script()
{
int i, j;
@@ -364,3 +442,113 @@ static uint8 *generate_random_script()
return script;
}
+
+#pragma region Load script.txt
+
+static void title_script_get_line(FILE *file, char *parts)
+{
+ int i, c, part, cindex, whitespace, comment;
+
+ for (i = 0; i < 3; i++)
+ parts[i * 32] = 0;
+
+ part = 0;
+ cindex = 0;
+ whitespace = 1;
+ comment = 0;
+ for (;;) {
+ c = fgetc(file);
+ if (c == '\n' || c == '\r' || c == EOF) {
+ parts[part * 32 + cindex] = 0;
+ return;
+ } else if (c == '#') {
+ parts[part * 32 + cindex] = 0;
+ comment = 1;
+ } else if (c == ' ' && !comment) {
+ if (!whitespace) {
+ parts[part * 32 + cindex] = 0;
+ part++;
+ cindex = 0;
+ }
+ } else if (!comment) {
+ whitespace = 0;
+ if (cindex < 31) {
+ parts[part * 32 + cindex] = c;
+ cindex++;
+ }
+ }
+ }
+}
+
+static uint8 *title_script_load()
+{
+ FILE *file;
+ char parts[3 * 32], *token, *part1, *part2, *src;
+
+ char path[] = "data/title/script.txt";
+
+ log_verbose("loading title script, %s", path);
+ file = fopen(path, "r");
+ if (file == NULL) {
+ log_error("unable to load title script");
+ return NULL;
+ }
+
+ uint8 *binaryScript = (uint8*)malloc(1024 * 8);
+ if (binaryScript == NULL) {
+ fclose(file);
+
+ log_error("unable to allocate memory for script");
+ return NULL;
+ }
+
+ uint8 *scriptPtr = binaryScript;
+
+ do {
+ title_script_get_line(file, parts);
+
+ token = &parts[0 * 32];
+ part1 = &parts[1 * 32];
+ part2 = &parts[2 * 32];
+
+ if (token[0] != 0) {
+ if (_stricmp(token, "LOAD") == 0) {
+ src = part1;
+ *scriptPtr++ = TITLE_SCRIPT_LOAD;
+ do {
+ *scriptPtr++ = *src++;
+ } while (*(src - 1) != 0);
+ } else if (_stricmp(token, "LOCATION") == 0) {
+ *scriptPtr++ = TITLE_SCRIPT_LOCATION;
+ *scriptPtr++ = atoi(part1) & 0xFF;
+ *scriptPtr++ = atoi(part2) & 0xFF;
+ } else if (_stricmp(token, "ROTATE") == 0) {
+ *scriptPtr++ = TITLE_SCRIPT_ROTATE;
+ *scriptPtr++ = atoi(part1) & 0xFF;
+ } else if (_stricmp(token, "ZOOM") == 0) {
+ *scriptPtr++ = TITLE_SCRIPT_ZOOM;
+ *scriptPtr++ = atoi(part1) & 0xFF;
+ } else if (_stricmp(token, "WAIT") == 0) {
+ *scriptPtr++ = TITLE_SCRIPT_WAIT;
+ *scriptPtr++ = atoi(part1) & 0xFF;
+ } else {
+ log_error("unknown token, %s", token);
+ return NULL;
+ }
+ }
+ } while (!feof(file));
+ fclose(file);
+
+ *scriptPtr++ = TITLE_SCRIPT_RESTART;
+
+ int scriptLength = (int)(scriptPtr - binaryScript);
+ binaryScript = realloc(binaryScript, scriptLength);
+ if (binaryScript == NULL) {
+ log_error("unable to reallocate memory for script");
+ return NULL;
+ }
+
+ return binaryScript;
+}
+
+#pragma endregion
diff --git a/src/util/util.c b/src/util/util.c
index d6b176c24f..8194f87cba 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -56,6 +56,15 @@ const char *path_get_filename(const char *path)
return result;
}
+const char *path_get_extension(const char *path)
+{
+ const char *ch = path;
+ while (*ch != '.' && *ch != 0) {
+ ch++;
+ }
+ return ch;
+}
+
void path_set_extension(char *path, const char *extension)
{
char *ch = path;
diff --git a/src/util/util.h b/src/util/util.h
index 79ef842153..1e776d0b23 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -28,6 +28,7 @@ int metres_to_feet(int metres);
int mph_to_kmph(int mph);
const char *path_get_filename(const char *path);
+const char *path_get_extension(const char *path);
void path_set_extension(char *path, const char *extension);
void path_remove_extension(char *path);
long fsize(FILE *fp);
diff --git a/src/windows/options.c b/src/windows/options.c
index 5642fe426e..fb46b70615 100644
--- a/src/windows/options.c
+++ b/src/windows/options.c
@@ -122,6 +122,8 @@ enum WINDOW_OPTIONS_WIDGET_IDX {
WIDX_TEST_UNFINISHED_TRACKS,
WIDX_AUTO_STAFF_PLACEMENT,
WIDX_DEBUGGING_TOOLS,
+ WIDX_TITLE_SEQUENCE,
+ WIDX_TITLE_SEQUENCE_DROPDOWN,
// Twitch
WIDX_CHANNEL_BUTTON = WIDX_PAGE_START,
@@ -214,6 +216,8 @@ static rct_widget window_options_misc_widgets[] = {
{ WWT_CHECKBOX, 2, 10, 299, 114, 125, 5155, 5156 }, // test unfinished tracks
{ WWT_CHECKBOX, 2, 10, 299, 129, 140, 5343, STR_NONE }, // auto staff placement
{ WWT_CHECKBOX, 2, 10, 299, 144, 155, 5150, STR_NONE }, // enabled debugging tools
+ { WWT_DROPDOWN, 1, 155, 299, 158, 169, STR_NONE, STR_NONE },
+ { WWT_DROPDOWN_BUTTON, 1, 288, 298, 159, 168, 876, STR_NONE },
{ WIDGETS_END },
};
@@ -358,7 +362,9 @@ static uint32 window_options_page_enabled_widgets[] = {
(1 << WIDX_ALLOW_SUBTYPE_SWITCHING) |
(1 << WIDX_TEST_UNFINISHED_TRACKS) |
(1 << WIDX_AUTO_STAFF_PLACEMENT) |
- (1 << WIDX_DEBUGGING_TOOLS),
+ (1 << WIDX_DEBUGGING_TOOLS) |
+ (1 << WIDX_TITLE_SEQUENCE) |
+ (1 << WIDX_TITLE_SEQUENCE_DROPDOWN),
MAIN_OPTIONS_ENABLED_WIDGETS |
(1 << WIDX_CHANNEL_BUTTON) |
@@ -778,6 +784,17 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget*
window_options_show_dropdown(w, widget, AUTOSAVE_NEVER + 1);
gDropdownItemsChecked = 1 << gConfigGeneral.autosave_frequency;
break;
+ case WIDX_TITLE_SEQUENCE_DROPDOWN:
+ gDropdownItemsFormat[0] = 1142;
+ gDropdownItemsArgs[0] = STR_TITLE_SEQUENCE_RCT2;
+ gDropdownItemsFormat[1] = 1142;
+ gDropdownItemsArgs[1] = STR_TITLE_SEQUENCE_OPENRCT2;
+ window_options_show_dropdown(w, widget, 2);
+ if (gConfigGeneral.title_sequence == TITLE_SEQUENCE_RCT2)
+ gDropdownItemsChecked = 1 << 0;
+ else if (gConfigGeneral.title_sequence == TITLE_SEQUENCE_OPENRCT2)
+ gDropdownItemsChecked = 1 << 1;
+ break;
}
break;
@@ -948,6 +965,14 @@ static void window_options_dropdown()
window_invalidate(w);
}
break;
+ case WIDX_TITLE_SEQUENCE_DROPDOWN:
+ if (dropdownIndex != gConfigGeneral.title_sequence) {
+ if (dropdownIndex == 0) gConfigGeneral.title_sequence = TITLE_SEQUENCE_RCT2;
+ else if (dropdownIndex == 1) gConfigGeneral.title_sequence = TITLE_SEQUENCE_OPENRCT2;
+ config_save_default();
+ window_invalidate(w);
+ }
+ break;
}
break;
@@ -1117,6 +1142,8 @@ static void window_options_invalidate()
window_options_misc_widgets[WIDX_TEST_UNFINISHED_TRACKS].type = WWT_CHECKBOX;
window_options_misc_widgets[WIDX_AUTO_STAFF_PLACEMENT].type = WWT_CHECKBOX;
window_options_misc_widgets[WIDX_DEBUGGING_TOOLS].type = WWT_CHECKBOX;
+ window_options_misc_widgets[WIDX_TITLE_SEQUENCE].type = WWT_DROPDOWN;
+ window_options_misc_widgets[WIDX_TITLE_SEQUENCE_DROPDOWN].type = WWT_DROPDOWN_BUTTON;
break;
case WINDOW_OPTIONS_PAGE_TWITCH:
@@ -1238,6 +1265,16 @@ static void window_options_paint()
w->x + window_options_misc_widgets[WIDX_AUTOSAVE].left + 1,
w->y + window_options_misc_widgets[WIDX_AUTOSAVE].top
);
+
+ gfx_draw_string_left(dpi, STR_TITLE_SEQUENCE, w, w->colours[1], w->x + 10, w->y + window_options_misc_widgets[WIDX_TITLE_SEQUENCE].top + 1);
+ gfx_draw_string_left(
+ dpi,
+ STR_TITLE_SEQUENCE_RCT1 + gConfigGeneral.title_sequence,
+ NULL,
+ w->colours[1],
+ w->x + window_options_misc_widgets[WIDX_TITLE_SEQUENCE].left + 1,
+ w->y + window_options_misc_widgets[WIDX_TITLE_SEQUENCE].top
+ );
break;
}
}