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; } }