diff --git a/data/language/english_uk.txt b/data/language/english_uk.txt index 4c6e9b01a0..67c7fd53df 100644 --- a/data/language/english_uk.txt +++ b/data/language/english_uk.txt @@ -3710,5 +3710,68 @@ STR_5373 :Name {STRINGID} STR_5374 :Date {STRINGID} STR_5375 :{UP} STR_5376 :{DOWN} -#Strings 5377-5440 Reserved +STR_5377 :{SMALLFONT}{BLACK}Saves +STR_5378 :{SMALLFONT}{BLACK}Script +STR_5379 :{SMALLFONT}{BLACK}Skip to next wait command +STR_5380 :{SMALLFONT}{BLACK}Start playing title sequence +STR_5381 :{SMALLFONT}{BLACK}Stop playing title sequence +STR_5382 :{SMALLFONT}{BLACK}Restart title sequence +STR_5383 :{SMALLFONT}{BLACK}Create a new title sequence based on the current one +STR_5384 :{SMALLFONT}{BLACK}Delete the current title sequence +STR_5385 :{SMALLFONT}{BLACK}Rename the current title sequence +STR_5386 :{SMALLFONT}{BLACK}Insert a new command +STR_5387 :{SMALLFONT}{BLACK}Edit the selected command +STR_5388 :{SMALLFONT}{BLACK}Delete the selected command +STR_5389 :{SMALLFONT}{BLACK}Skip to the selected command in the title sequence +STR_5390 :{SMALLFONT}{BLACK}Move the selected command down +STR_5391 :{SMALLFONT}{BLACK}Move the selected command up +STR_5392 :{SMALLFONT}{BLACK}Add a save to the title sequence +STR_5393 :{SMALLFONT}{BLACK}Remove the selected save from the title sequence +STR_5394 :{SMALLFONT}{BLACK}Rename the selected save +STR_5395 :{SMALLFONT}{BLACK}Load the selected save in game +STR_5396 :{SMALLFONT}{BLACK}Reload the title sequence if changes have been made to it outside of the game +STR_5397 :Can only be used on the title screen +STR_5398 :Cannot edit title sequence while it's playing +STR_5399 :Press the stop button to coninue editing +STR_5400 :Can't change this title sequence +STR_5401 :Create a new title sequence to make changes to +STR_5402 :Failed to load title sequence +STR_5403 :There may be no Load or Wait command or a save may be invalid +STR_5404 :Name already exists +STR_5405 :Enter a name for the save +STR_5406 :Enter a name for the title sequence +STR_5407 :Add +STR_5408 :Remove +STR_5409 :Insert +STR_5410 :Edit +STR_5411 :Reload +STR_5412 :Skip to +STR_5413 :Load +STR_5414 :Load{MOVE_X}{87}Six Flags Magic Mountain.SC6 +STR_5415 :Load{MOVE_X}{87}{STRING} +STR_5416 :Load{MOVE_X}{87}No save selected +STR_5417 :Location +STR_5418 :Location{MOVE_X}{87}{COMMA16} {COMMA16} +STR_5419 :Rotate +STR_5420 :Rotate{MOVE_X}{87}{COMMA16} +STR_5421 :Zoom +STR_5422 :Zoom{MOVE_X}{87}{COMMA16} +STR_5423 :Wait +STR_5424 :Wait{MOVE_X}{87}{COMMA16} +STR_5425 :Restart +STR_5426 :End +STR_5427 :Coordinates: +STR_5428 :Counter-clockwise rotations: +STR_5429 :Zoom level: +STR_5430 :Seconds to wait: +STR_5431 :Save to load: +STR_5432 :Command: +STR_5433 :Title Sequences +STR_5434 :Command Editor +STR_5435 :Rename save +STR_5436 :Edit Title Sequences... +STR_5437 :No save selected +STR_5438 :Can't make changes while command editor is open +STR_5439 :A restart is used without a wait command +STR_5440 : STR_5441 :{SMALLFONT}{BLACK}Identifies rides by track type,{NEWLINE}so vehicles can be changed{NEWLINE}afterwards, like in RCT1. Only{NEWLINE}toggleable in the title screen. diff --git a/data/title/achilleshiel.sv6 b/data/title/openrct2/achilleshiel.sv6 similarity index 100% rename from data/title/achilleshiel.sv6 rename to data/title/openrct2/achilleshiel.sv6 diff --git a/data/title/faas.sv6 b/data/title/openrct2/faas.sv6 similarity index 100% rename from data/title/faas.sv6 rename to data/title/openrct2/faas.sv6 diff --git a/data/title/mci.sv6 b/data/title/openrct2/mci.sv6 similarity index 100% rename from data/title/mci.sv6 rename to data/title/openrct2/mci.sv6 diff --git a/data/title/pfckrutonium1.sv6 b/data/title/openrct2/pfckrutonium1.sv6 similarity index 100% rename from data/title/pfckrutonium1.sv6 rename to data/title/openrct2/pfckrutonium1.sv6 diff --git a/data/title/pfckrutonium2.sv6 b/data/title/openrct2/pfckrutonium2.sv6 similarity index 100% rename from data/title/pfckrutonium2.sv6 rename to data/title/openrct2/pfckrutonium2.sv6 diff --git a/data/title/poke.sv6 b/data/title/openrct2/poke.sv6 similarity index 100% rename from data/title/poke.sv6 rename to data/title/openrct2/poke.sv6 diff --git a/data/title/rid6.sv6 b/data/title/openrct2/rid6.sv6 similarity index 100% rename from data/title/rid6.sv6 rename to data/title/openrct2/rid6.sv6 diff --git a/data/title/script.txt b/data/title/openrct2/script.txt similarity index 98% rename from data/title/script.txt rename to data/title/openrct2/script.txt index 861dbd25e8..aa50e18dd7 100644 --- a/data/title/script.txt +++ b/data/title/openrct2/script.txt @@ -103,4 +103,6 @@ WAIT 12 LOCATION 12 47 ROTATE 3 -WAIT 20 \ No newline at end of file +WAIT 20 + +RESTART \ No newline at end of file diff --git a/data/title/shotguns.sv6 b/data/title/openrct2/shotguns.sv6 similarity index 100% rename from data/title/shotguns.sv6 rename to data/title/openrct2/shotguns.sv6 diff --git a/data/title/triggerdeath.sv6 b/data/title/openrct2/triggerdeath.sv6 similarity index 100% rename from data/title/triggerdeath.sv6 rename to data/title/openrct2/triggerdeath.sv6 diff --git a/data/title/rct2/script.txt b/data/title/rct2/script.txt new file mode 100644 index 0000000000..3f4e303f7b --- /dev/null +++ b/data/title/rct2/script.txt @@ -0,0 +1,34 @@ +# RollerCoaster Tycoon 2 Title Sequence + +LOADMM + +LOCATION 210 112 +WAIT 13 + +ROTATE 1 +LOCATION 210 112 +WAIT 14 + +ROTATE 3 +LOCATION 167 180 +WAIT 12 + +ROTATE 1 +LOCATION 155 189 +WAIT 12 + +LOCATION 106 39 +WAIT 12 + +LOCATION 182 50 +WAIT 12 + +ROTATE 3 +LOCATION 209 47 +WAIT 12 + +ROTATE 1 +LOCATION 159 93 +WAIT 12 + +RESTART diff --git a/projects/openrct2.vcxproj b/projects/openrct2.vcxproj index 3e8b0c411a..c9f50a1a2a 100644 --- a/projects/openrct2.vcxproj +++ b/projects/openrct2.vcxproj @@ -51,6 +51,7 @@ + @@ -90,6 +91,11 @@ + + + + + @@ -198,6 +204,7 @@ + diff --git a/projects/openrct2.vcxproj.filters b/projects/openrct2.vcxproj.filters index fad60aeef3..24bc550445 100644 --- a/projects/openrct2.vcxproj.filters +++ b/projects/openrct2.vcxproj.filters @@ -480,6 +480,15 @@ Source\Windows + + Source\Windows + + + Source\Interface + + + Source\Windows + @@ -704,5 +713,8 @@ Test\Ride + + Source\Interface + \ No newline at end of file diff --git a/projects/~AutoRecover.openrct2.vcxproj b/projects/~AutoRecover.openrct2.vcxproj new file mode 100644 index 0000000000..de18e4d204 --- /dev/null +++ b/projects/~AutoRecover.openrct2.vcxproj @@ -0,0 +1,423 @@ + + + + + + + + + + Debug + Win32 + + + Release with Tests + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {074dc930-05c6-4b7f-b5dd-dd237e6e44db} + + + + {D24D94F6-2A74-480C-B512-629C306CE92F} + openrct2 + openrct2 + + + + DynamicLibrary + true + v120 + MultiByte + + + DynamicLibrary + false + v120 + true + MultiByte + + + DynamicLibrary + false + v120 + true + MultiByte + + + + + + + + + + + + + + + + $(SolutionDir)..\lodepng;$(SolutionDir)..\sdl\include;$(SolutionDir)..\libspeex;$(IncludePath) + $(SolutionDir)..\sdl\lib\x86;$(LibraryPath) + $(SolutionDir)..\build\$(Configuration)\ + $(SolutionDir)..\obj\$(ProjectName)\$(Configuration)\ + + + $(SolutionDir)..\lib;$(SolutionDir)..\lib\libspeex;$(SolutionDir)..\lib\sdl\include;$(SolutionDir)..\lib\libcurl\include;$(SolutionDir)..\lib\jansson;$(SolutionDir)..\lib\cutest;$(IncludePath) + $(SolutionDir)..\lib\sdl\lib\x86;$(SolutionDir)..\lib\libcurl\lib;$(LibraryPath) + $(SolutionDir)..\build\$(Configuration)\ + $(SolutionDir)..\obj\$(ProjectName)\$(Configuration)\ + + + + + $(SolutionDir)..\lib;$(SolutionDir)..\lib\libspeex;$(SolutionDir)..\lib\sdl\include;$(SolutionDir)..\lib\libcurl\include;$(SolutionDir)..\lib\jansson;$(SolutionDir)..\lib\cutest;$(IncludePath) + $(SolutionDir)..\lib\sdl\lib\x86;$(SolutionDir)..\lib\libcurl\lib;$(LibraryPath) + $(SolutionDir)..\build\Release\ + $(SolutionDir)..\obj\$(ProjectName)\Release\ + + + + + Level3 + Disabled + true + 1Byte + _CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;_USE_MATH_DEFINES;%(PreprocessorDefinitions) + MultiThreaded + + + 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" + + + + + Level3 + Disabled + true + true + + + MultiThreaded + 1Byte + 4013 + + + false + _CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;_USE_MATH_DEFINES;CURL_STATICLIB;%(PreprocessorDefinitions) + $(IntDir)fake\%(RelativeDir) + true + + + true + true + true + winmm.lib;sdl2.lib;Dsound.lib;%(AdditionalDependencies) + /ignore:4099 %(AdditionalOptions) + + + "$(TargetDir)\openrct2.exe" sprite build "$(SolutionDir)\..\Data\g2.dat" "$(SolutionDir)\..\Resources\g2\" +xcopy /YS "$(SolutionDir)\..\Data" "$(TargetDir)\Data" + Build g2.dat and copy the Data directory. + + + + + + + + + + + + + Level3 + Disabled + true + true + + + MultiThreaded + 1Byte + 4013 + + + false + _CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;_USE_MATH_DEFINES;CURL_STATICLIB;ENABLE_TESTS;%(PreprocessorDefinitions) + $(IntDir)fake\%(RelativeDir) + true + + + true + true + true + winmm.lib;sdl2.lib;Dsound.lib;%(AdditionalDependencies) + /ignore:4099 %(AdditionalOptions) + + + "$(TargetDir)\openrct2.exe" sprite build "$(SolutionDir)\..\Data\g2.dat" "$(SolutionDir)\..\Resources\g2\" +xcopy /YS "$(SolutionDir)\..\Data" "$(TargetDir)\Data" + Build g2.dat and copy the Data directory. + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/g2/29.png b/resources/g2/29.png new file mode 100644 index 0000000000..a95bea0673 Binary files /dev/null and b/resources/g2/29.png differ diff --git a/resources/g2/30.png b/resources/g2/30.png new file mode 100644 index 0000000000..4038923eaf Binary files /dev/null and b/resources/g2/30.png differ diff --git a/resources/g2/31.png b/resources/g2/31.png new file mode 100644 index 0000000000..06b5f195c9 Binary files /dev/null and b/resources/g2/31.png differ diff --git a/resources/g2/32.png b/resources/g2/32.png new file mode 100644 index 0000000000..84d69e2337 Binary files /dev/null and b/resources/g2/32.png differ diff --git a/src/config.c b/src/config.c index 6f3c74ab3a..551dcb0e1d 100644 --- a/src/config.c +++ b/src/config.c @@ -25,6 +25,7 @@ #include "util/util.h" #include "interface/themes.h" #include "openrct2.h" +#include "interface/title_sequences.h" // Magic number for original game cfg file static const int MagicNumber = 0x0003113A; @@ -179,7 +180,6 @@ 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 }, { offsetof(general_configuration, invert_viewport_drag), "invert_viewport_drag", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, { offsetof(general_configuration, load_save_sort), "load_save_sort", CONFIG_VALUE_TYPE_UINT8, SORT_NAME_ASCENDING, NULL }, }; @@ -190,7 +190,8 @@ config_property_definition _interfaceDefinitions[] = { { offsetof(interface_configuration, toolbar_show_cheats), "toolbar_show_cheats", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, { offsetof(interface_configuration, select_by_track_type), "select_by_track_type", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, { offsetof(interface_configuration, console_small_font), "console_small_font", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL }, - { offsetof(interface_configuration, current_theme_preset), "current_theme", CONFIG_VALUE_TYPE_STRING, { .value_string = "*RCT2" }, NULL }, + { offsetof(interface_configuration, current_theme_preset), "current_theme", CONFIG_VALUE_TYPE_STRING, { .value_string = "*RCT2" }, NULL }, + { offsetof(interface_configuration, current_title_sequence_preset), "current_title_sequence", CONFIG_VALUE_TYPE_STRING, { .value_string = "*OPENRCT2" },NULL }, }; config_property_definition _soundDefinitions[] = { @@ -234,6 +235,7 @@ sound_configuration gConfigSound; cheat_configuration gConfigCheat; twitch_configuration gConfigTwitch; themes_configuration gConfigThemes; +title_sequences_configuration gConfigTitleSequences; bool config_open(const utf8string path); bool config_save(const utf8string path); @@ -1398,4 +1400,244 @@ static theme_property_definition *themes_get_property_def(theme_section_definiti return NULL; } +#pragma endregion + +#pragma region Title Sequences + +static void title_sequence_open(const char *path, const char *customName); + +void title_sequences_set_default() +{ + char path[MAX_PATH]; + char sep = platform_get_path_separator(); + + platform_get_user_directory(path, "title sequences"); + platform_ensure_directory_exists(path); + + gConfigTitleSequences.presets = malloc(0); + gConfigTitleSequences.num_presets = 0; + + // Load OpenRCT2 title sequence + sprintf(path, "%s%c%s%c%s%c%s%c", gExePath, sep, "data", sep, "title", sep, "rct2", sep); + title_sequence_open(path, language_get_string(5308)); + + // Load OpenRCT2 title sequence + sprintf(path, "%s%c%s%c%s%c%s%c", gExePath, sep, "data", sep, "title", sep, "openrct2", sep); + title_sequence_open(path, language_get_string(5309)); +} + +void title_sequences_load_presets() +{ + utf8 path[MAX_PATH], titleDir[MAX_PATH]; + int dirEnumHandle, i; + + // Find all directories in the title sequences folder + platform_get_user_directory(path, "title sequences"); + dirEnumHandle = platform_enumerate_directories_begin(path); + while (platform_enumerate_directories_next(dirEnumHandle, titleDir)) { + platform_get_user_directory(path, "title sequences"); + strcat(path, titleDir); + title_sequence_open(path, NULL); + } + platform_enumerate_directories_end(dirEnumHandle); + + // Check which title sequence is the current one + if (_stricmp(gConfigInterface.current_title_sequence_preset, "*RCT2") == 0) { + gCurrentTitleSequence = 0; + } + else if (_stricmp(gConfigInterface.current_title_sequence_preset, "*OPENRCT2") == 0) { + gCurrentTitleSequence = 1; + } + else { + for (i = TITLE_SEQUENCE_DEFAULT_PRESETS; i < gConfigTitleSequences.num_presets; i++) { + if (_stricmp(gConfigInterface.current_title_sequence_preset, gConfigTitleSequences.presets[i].name) == 0) { + gCurrentTitleSequence = i; + break; + } + } + if (i == gConfigTitleSequences.num_presets) { + gCurrentTitleSequence = 0; + } + } + gCurrentPreviewTitleSequence = gCurrentTitleSequence; +} + +static void title_sequence_open(const char *path, const char *customName) +{ + utf8 titlePath[MAX_PATH], scriptPath[MAX_PATH]; + file_info fileInfo; + FILE *file; + int fileEnumHandle, i, preset; + char parts[3 * 128], *token, *part1, *part2; + char separator = platform_get_path_separator(); + + // Check for the script file + strcpy(scriptPath, path); + strcat(scriptPath, "script.txt"); + if (!platform_file_exists(scriptPath)) { + // No script file, title sequence is invalid + return; + } + + // Check if the preset is already loaded + // No nead to read the first two presets as they're hardcoded in + for (preset = 0; preset < gConfigTitleSequences.num_presets; preset++) { + if (_stricmp(path, gConfigTitleSequences.presets[preset].name) == 0) { + return; + } + } + // Otherwise allocate one + if (preset == gConfigTitleSequences.num_presets) { + gConfigTitleSequences.num_presets++; + gConfigTitleSequences.presets = realloc(gConfigTitleSequences.presets, sizeof(title_sequence) * (size_t)gConfigTitleSequences.num_presets); + + if (customName == NULL) { + char nameBuffer[MAX_PATH], *name; + strcpy(nameBuffer, path); + name = nameBuffer + strlen(nameBuffer) - 1; + while (*name == '\\' || *name == '/') { + *name = 0; + name--; + } + while (*(name - 1) != '\\' && *(name - 1) != '/') { + name--; + } + strcpy(gConfigTitleSequences.presets[preset].name, name); + gConfigTitleSequences.presets[preset].path[0] = 0; + } + else { + strcpy(gConfigTitleSequences.presets[preset].name, customName); + strcpy(gConfigTitleSequences.presets[preset].path, path); + } + + gConfigTitleSequences.presets[preset].saves = malloc(0); + gConfigTitleSequences.presets[preset].commands = malloc(0); + gConfigTitleSequences.presets[preset].num_saves = 0; + gConfigTitleSequences.presets[preset].num_commands = 0; + } + + // Get the save file list + strcpy(titlePath, path); + strcat(titlePath, "*.sv6"); + fileEnumHandle = platform_enumerate_files_begin(titlePath); + while (platform_enumerate_files_next(fileEnumHandle, &fileInfo)) { + gConfigTitleSequences.presets[preset].num_saves++; + gConfigTitleSequences.presets[preset].saves = realloc(gConfigTitleSequences.presets[preset].saves, sizeof(char[TITLE_SEQUENCE_MAX_SAVE_LENGTH]) * (size_t)gConfigTitleSequences.presets[preset].num_saves); + strcpy(gConfigTitleSequences.presets[preset].saves[gConfigTitleSequences.presets[preset].num_saves - 1], fileInfo.path); + } + platform_enumerate_files_end(fileEnumHandle); + strcpy(titlePath, path); + strcat(titlePath, "*.sc6"); + fileEnumHandle = platform_enumerate_files_begin(titlePath); + while (platform_enumerate_files_next(fileEnumHandle, &fileInfo)) { + gConfigTitleSequences.presets[preset].num_saves++; + gConfigTitleSequences.presets[preset].saves = realloc(gConfigTitleSequences.presets[preset].saves, sizeof(char[TITLE_SEQUENCE_MAX_SAVE_LENGTH]) * (size_t)gConfigTitleSequences.presets[preset].num_saves); + strcpy(gConfigTitleSequences.presets[preset].saves[gConfigTitleSequences.presets[preset].num_saves - 1], fileInfo.path); + } + platform_enumerate_files_end(fileEnumHandle); + + // Load the script file + file = fopen(scriptPath, "r"); + + do { + title_script_get_line(file, parts); + + token = &parts[0 * 128]; + part1 = &parts[1 * 128]; + part2 = &parts[2 * 128]; + title_command command; + command.command = 0xFF; + + if (token[0] != 0) { + if (_stricmp(token, "LOAD") == 0) { + command.command = TITLE_SCRIPT_LOAD; + command.saveIndex = 0xFF; + for (i = 0; i < gConfigTitleSequences.presets[preset].num_saves && command.saveIndex == 0xFF; i++) { + if (_stricmp(part1, gConfigTitleSequences.presets[preset].saves[i]) == 0) + command.saveIndex = i; + } + } else if (_stricmp(token, "LOCATION") == 0) { + command.command = TITLE_SCRIPT_LOCATION; + command.x = atoi(part1) & 0xFF; + command.y = atoi(part2) & 0xFF; + } else if (_stricmp(token, "ROTATE") == 0) { + command.command = TITLE_SCRIPT_ROTATE; + command.rotations = atoi(part1) & 0xFF; + } else if (_stricmp(token, "ZOOM") == 0) { + command.command = TITLE_SCRIPT_ZOOM; + command.zoom = atoi(part1) & 0xFF; + } else if (_stricmp(token, "WAIT") == 0) { + command.command = TITLE_SCRIPT_WAIT; + command.seconds = atoi(part1) & 0xFF; + } else if (_stricmp(token, "RESTART") == 0) { + command.command = TITLE_SCRIPT_RESTART; + } else if (_stricmp(token, "END") == 0) { + command.command = TITLE_SCRIPT_END; + } else if (_stricmp(token, "LOADMM") == 0) { + command.command = TITLE_SCRIPT_LOADMM; + } + } + if (command.command != 0xFF) { + gConfigTitleSequences.presets[preset].num_commands++; + gConfigTitleSequences.presets[preset].commands = realloc(gConfigTitleSequences.presets[preset].commands, sizeof(title_command) * (size_t)gConfigTitleSequences.presets[preset].num_commands); + gConfigTitleSequences.presets[preset].commands[gConfigTitleSequences.presets[preset].num_commands - 1] = command; + } + } while (!feof(file)); + fclose(file); +} + +void title_sequence_save_preset_script(int preset) +{ + utf8 path[MAX_PATH]; + FILE *file; + int i; + char separator = platform_get_path_separator(); + + + platform_get_user_directory(path, "title sequences"); + strcat(path, path_get_filename(gConfigTitleSequences.presets[preset].name)); + strncat(path, &separator, 1); + strcat(path, "script.txt"); + + file = fopen(path, "wb"); + if (file == NULL) { + log_error("Unable to write to script file."); + return; + } + + for (i = 0; i < gConfigTitleSequences.presets[preset].num_commands; i++) { + title_command *command = &gConfigTitleSequences.presets[preset].commands[i]; + switch (command->command) { + case TITLE_SCRIPT_LOAD: + if (command->saveIndex == 0xFF) + fprintf(file, "LOAD \r\n"); + else + fprintf(file, "LOAD %s\r\n", gConfigTitleSequences.presets[preset].saves[command->saveIndex]); + break; + case TITLE_SCRIPT_LOCATION: + fprintf(file, "LOCATION %i %i\r\n", command->x, command->y); + break; + case TITLE_SCRIPT_ROTATE: + fprintf(file, "ROTATE %i\r\n", command->rotations); + break; + case TITLE_SCRIPT_ZOOM: + fprintf(file, "ZOOM %i\r\n", command->zoom); + break; + case TITLE_SCRIPT_WAIT: + fprintf(file, "WAIT %i\r\n\r\n", command->seconds); + break; + case TITLE_SCRIPT_RESTART: + fprintf(file, "RESTART\r\n"); + break; + case TITLE_SCRIPT_END: + fprintf(file, "END\r\n"); + break; + + } + } + + fclose(file); +} + + #pragma endregion diff --git a/src/config.h b/src/config.h index b7469a7ab9..60a95d9022 100644 --- a/src/config.h +++ b/src/config.h @@ -150,7 +150,6 @@ typedef struct { uint8 date_format; uint8 auto_staff_placement; utf8string last_run_version; - uint8 title_sequence; uint8 invert_viewport_drag; uint8 load_save_sort; } general_configuration; @@ -162,6 +161,7 @@ typedef struct { uint8 select_by_track_type; uint8 console_small_font; utf8string current_theme_preset; + utf8string current_title_sequence_preset; } interface_configuration; typedef struct { @@ -218,6 +218,36 @@ typedef struct { uint16 num_presets; } themes_configuration; +#define TITLE_SEQUENCE_MAX_SAVE_LENGTH 51 + +typedef struct { + uint8 command; + union { + uint8 saveIndex; // LOAD (this index is internal only) + uint8 x; // LOCATION + uint8 rotations; // ROTATE (counter-clockwise) + uint8 zoom; // ZOOM + uint8 seconds; // WAIT + }; + uint8 y; // LOCATION +} title_command; + +typedef struct { + char name[256]; + char path[MAX_PATH]; // Needed for non-modifiable presets + char (*saves)[TITLE_SEQUENCE_MAX_SAVE_LENGTH]; + title_command *commands; + uint8 num_saves; + uint16 num_commands; + +} title_sequence; + +typedef struct { + title_sequence *presets; + uint16 num_presets; + +} title_sequences_configuration; + typedef struct { uint8 key; uint8 modifier; @@ -229,6 +259,7 @@ extern sound_configuration gConfigSound; extern cheat_configuration gConfigCheat; extern twitch_configuration gConfigTwitch; extern themes_configuration gConfigThemes; +extern title_sequences_configuration gConfigTitleSequences; extern uint16 gShortcutKeys[SHORTCUT_COUNT]; @@ -248,4 +279,8 @@ void themes_set_default(); void themes_load_presets(); bool themes_save_preset(int preset); +void title_sequences_set_default(); +void title_sequences_load_presets(); +void title_sequence_save_preset_script(int preset); + #endif diff --git a/src/input.c b/src/input.c index 3bffaed02c..2d4ea19218 100644 --- a/src/input.c +++ b/src/input.c @@ -533,6 +533,7 @@ static void input_scroll_continue(rct_window *w, int widgetIndex, int state, int { rct_widget *widget; int scroll_part, scroll_id; + int x2, y2; widget = &w->widgets[widgetIndex]; if (widgetIndex != RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DOWN_WIDGETINDEX, uint32)){ @@ -548,7 +549,7 @@ static void input_scroll_continue(rct_window *w, int widgetIndex, int state, int return; } - widget_scroll_get_part(w, widget, x, y, &x, &y, &scroll_part, &scroll_id); + widget_scroll_get_part(w, widget, x, y, &x2, &y2, &scroll_part, &scroll_id); if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SCROLL_AREA, uint16) == SCROLL_PART_HSCROLLBAR_THUMB){ int temp_x = x; @@ -566,6 +567,9 @@ static void input_scroll_continue(rct_window *w, int widgetIndex, int state, int return; } + x = x2; + y = y2; + if (scroll_part != RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SCROLL_AREA, uint16)){ invalidate_scroll(); return; diff --git a/src/interface/console.c b/src/interface/console.c index 5baddb4d65..71f32c03c9 100644 --- a/src/interface/console.c +++ b/src/interface/console.c @@ -846,6 +846,8 @@ static int cc_open(const char **argv, int argc) { window_options_open(); } else if (strcmp(argv[0], "themes") == 0) { window_themes_open(); + } else if (strcmp(argv[0], "title_sequences") == 0) { + window_title_editor_open(0); } else if (invalidTitle) { console_writeline_error("Cannot open this window in the title screen."); } else { @@ -898,7 +900,8 @@ char* console_window_table[] = { "inventions_list", "scenario_options", "options", - "themes" + "themes", + "title_sequences" }; console_command console_command_table[] = { diff --git a/src/interface/themes.c b/src/interface/themes.c index dc22390267..2fe2d20e6e 100644 --- a/src/interface/themes.c +++ b/src/interface/themes.c @@ -83,6 +83,7 @@ theme_window_definition gThemeWindowDefinitions[] = { { WC_STAFF, "staff", 5207, COLOURS_3(1, 4, 4) }, { WC_EDITOR_TRACK_BOTTOM_TOOLBAR, "editor_track_bottom_toolbar", 5247, COLOURS_3(135, 135, 135) }, { WC_EDITOR_SCENARIO_BOTTOM_TOOLBAR, "editor_scenario_bottom_toolbar", 5248, COLOURS_3(150, 150, 141) }, + { WC_TITLE_EDITOR, "title_sequences", 5433, COLOURS_3(1, 15, 15) }, }; #define COLOURS_RCT1(c0, c1, c2, c3, c4, c5) { { (c0), (c1), (c2), (c3), (c4), (c5) } } @@ -232,10 +233,10 @@ void theme_rename_preset(int preset, const char *newName) strcat(dest, ".ini"); platform_file_move(src, dest); - strcpy(gConfigThemes.presets[gCurrentTheme].name, newName); + strcpy(gConfigThemes.presets[preset].name, newName); if (preset == gCurrentTheme) { - gConfigInterface.current_theme_preset = gConfigThemes.presets[gCurrentTheme].name; + gConfigInterface.current_theme_preset = gConfigThemes.presets[preset].name; } } } diff --git a/src/interface/title_sequences.c b/src/interface/title_sequences.c new file mode 100644 index 0000000000..dce6d9bb01 --- /dev/null +++ b/src/interface/title_sequences.c @@ -0,0 +1,367 @@ +/***************************************************************************** +* Copyright (c) 2014 Ted John, Peter Hill +* OpenRCT2, an open source clone of Roller Coaster Tycoon 2. +* +* This file is part of OpenRCT2. +* +* OpenRCT2 is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*****************************************************************************/ + +#include "../localisation/string_ids.h" +#include "window.h" +#include "title_sequences.h" +#include "../title.h" +#include "../util/util.h" + + +uint16 gCurrentTitleSequence; +uint16 gCurrentPreviewTitleSequence; + +title_command TitleScriptMakeCommand(int command, int parameter1, int parameter2) +{ + title_command titleCommand = { (uint8)command, (uint8)parameter1, (uint8)parameter2 }; + return titleCommand; +} + +bool title_sequence_name_exists(const char *name) +{ + for (int i = 0; i < gConfigTitleSequences.num_presets; i++) { + if (_stricmp(gConfigTitleSequences.presets[i].name, name) == 0) + return true; + } + return false; +} + +bool title_sequence_save_exists(int preset, const char *name) +{ + utf8 newName[MAX_PATH]; + char *extension = (char*)path_get_extension(name); + strcpy(newName, name); + if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0) + strcat(newName, ".sv6"); + for (int i = 0; i < gConfigTitleSequences.presets[preset].num_saves; i++) { + if (_stricmp(gConfigTitleSequences.presets[preset].saves[i], newName) == 0) + return true; + } + return false; +} + + +void title_sequence_change_preset(int preset) +{ + if (preset >= 0 && preset < gConfigTitleSequences.num_presets) { + switch (preset) { + case 0: + gConfigInterface.current_title_sequence_preset = "*RCT2"; + break; + case 1: + gConfigInterface.current_title_sequence_preset = "*OPENRCT2"; + break; + default: + gConfigInterface.current_title_sequence_preset = gConfigTitleSequences.presets[preset].name; + break; + } + gCurrentPreviewTitleSequence = preset; + } + window_invalidate_all(); + + // Switch to (and restart) this title sequence if it's valid + title_refresh_sequence(); +} + +void title_sequence_create_preset(const char *name) +{ + if (filename_valid_characters(name) && !title_sequence_name_exists(name)) { + int preset = gConfigTitleSequences.num_presets; + gConfigTitleSequences.num_presets++; + gConfigTitleSequences.presets = realloc(gConfigTitleSequences.presets, sizeof(title_sequence) * (size_t)gConfigTitleSequences.num_presets); + strcpy(gConfigTitleSequences.presets[preset].name, name); + gConfigTitleSequences.presets[preset].path[0] = 0; + + gConfigTitleSequences.presets[preset].saves = malloc(0); + gConfigTitleSequences.presets[preset].commands = malloc(0); + gConfigTitleSequences.presets[preset].num_saves = 0; + gConfigTitleSequences.presets[preset].num_commands = 0; + + // Create the folder + utf8 path[MAX_PATH]; + platform_get_user_directory(path, "title sequences"); + strcat(path, gConfigTitleSequences.presets[preset].name); + platform_file_delete(path); + platform_ensure_directory_exists(path); + + title_sequence_save_preset_script(preset); + title_sequence_change_preset(preset); + } +} + +void title_sequence_duplicate_preset(int duplicate, const char *name) +{ + if (duplicate >= 0 && duplicate < gConfigTitleSequences.num_presets && filename_valid_characters(name) && !title_sequence_name_exists(name)) { + int preset = gConfigTitleSequences.num_presets; + gConfigTitleSequences.num_presets++; + gConfigTitleSequences.presets = realloc(gConfigTitleSequences.presets, sizeof(title_sequence) * (size_t)gConfigTitleSequences.num_presets); + strcpy(gConfigTitleSequences.presets[preset].name, name); + gConfigTitleSequences.presets[preset].path[0] = 0; + + size_t savesSize = sizeof(char[TITLE_SEQUENCE_MAX_SAVE_LENGTH]) * gConfigTitleSequences.presets[duplicate].num_saves; + size_t commandsSize = sizeof(title_command) * gConfigTitleSequences.presets[duplicate].num_commands; + gConfigTitleSequences.presets[preset].saves = malloc(savesSize); + gConfigTitleSequences.presets[preset].commands = malloc(commandsSize); + memcpy(gConfigTitleSequences.presets[preset].saves, gConfigTitleSequences.presets[duplicate].saves, savesSize); + memcpy(gConfigTitleSequences.presets[preset].commands, gConfigTitleSequences.presets[duplicate].commands, commandsSize); + gConfigTitleSequences.presets[preset].num_saves = gConfigTitleSequences.presets[duplicate].num_saves; + gConfigTitleSequences.presets[preset].num_commands = gConfigTitleSequences.presets[duplicate].num_commands; + + bool loadmm = false; + for (int i = 0; i < gConfigTitleSequences.presets[preset].num_commands; i++) { + if (gConfigTitleSequences.presets[preset].commands[i].command == TITLE_SCRIPT_LOADMM) { + loadmm = true; + gConfigTitleSequences.presets[preset].commands[i].command = TITLE_SCRIPT_LOAD; + gConfigTitleSequences.presets[preset].commands[i].saveIndex = gConfigTitleSequences.presets[duplicate].num_saves; + } + } + + // Create the folder + utf8 path[MAX_PATH], srcPath[MAX_PATH]; + platform_get_user_directory(path, "title sequences"); + strcat(path, gConfigTitleSequences.presets[preset].name); + platform_file_delete(path); + platform_ensure_directory_exists(path); + + // Copy the saves + char separator = platform_get_path_separator(); + for (int i = 0; i < gConfigTitleSequences.presets[preset].num_saves; i++) { + if (gConfigTitleSequences.presets[duplicate].path[0]) { + strcpy(srcPath, gConfigTitleSequences.presets[duplicate].path); + strcat(srcPath, gConfigTitleSequences.presets[duplicate].saves[i]); + } + else { + platform_get_user_directory(srcPath, "title sequences"); + strcat(srcPath, gConfigTitleSequences.presets[duplicate].name); + strncat(srcPath, &separator, 1); + strcat(srcPath, gConfigTitleSequences.presets[duplicate].saves[i]); + } + platform_get_user_directory(path, "title sequences"); + strcat(path, gConfigTitleSequences.presets[preset].name); + strncat(path, &separator, 1); + strcat(path, gConfigTitleSequences.presets[preset].saves[i]); + + platform_file_copy(srcPath, path); + } + + if (loadmm) { + title_sequence_add_save(preset, get_file_path(PATH_ID_SIXFLAGS_MAGICMOUNTAIN), "Six Flags Magic Mountain.SC6"); + } + + title_sequence_save_preset_script(preset); + //title_sequence_change_preset(preset); + gCurrentTitleSequence = preset; + } +} + +void title_sequence_delete_preset(int preset) +{ + if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets) { + // Delete the folder + utf8 path[MAX_PATH]; + char separator = platform_get_path_separator(); + platform_get_user_directory(path, "title sequences"); + strcat(path, gConfigTitleSequences.presets[preset].name); + if (!platform_directory_delete(path)) { + log_error("Failed to delete directory: \"%s\"", path); + } + + free(gConfigTitleSequences.presets[preset].saves); + free(gConfigTitleSequences.presets[preset].commands); + + for (int i = preset; i < gConfigTitleSequences.num_presets - 1; i++) { + gConfigTitleSequences.presets[i] = gConfigTitleSequences.presets[i + 1]; + } + gConfigTitleSequences.num_presets--; + gConfigTitleSequences.presets = realloc(gConfigTitleSequences.presets, sizeof(title_sequence) * (size_t)gConfigTitleSequences.num_presets); + + gCurrentTitleSequence--; + if (gCurrentPreviewTitleSequence > preset) + title_sequence_change_preset(gCurrentPreviewTitleSequence - 1); + else if (gCurrentPreviewTitleSequence == preset) + title_sequence_change_preset(0); + } +} + +void title_sequence_rename_preset(int preset, const char *newName) +{ + if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets && filename_valid_characters(newName) && !title_sequence_name_exists(newName)) { + // Rename the folder + utf8 src[MAX_PATH], dest[MAX_PATH]; + platform_get_user_directory(src, "title sequences"); + platform_get_user_directory(dest, "title sequences"); + strcat(src, gConfigTitleSequences.presets[preset].name); + strcat(dest, newName); + platform_file_move(src, dest); + + strcpy(gConfigTitleSequences.presets[preset].name, newName); + + // Rename the config preset name if needed + if (preset == gCurrentPreviewTitleSequence) { + gConfigInterface.current_title_sequence_preset = gConfigTitleSequences.presets[preset].name; + } + } +} + + +void title_sequence_add_save(int preset, const char *path, const char *newName) +{ + utf8 newPath[MAX_PATH]; + char *extension = (char*)path_get_extension(newName); + strcpy(newPath, newName); + if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0) + strcat(newPath, ".sv6"); + if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets && filename_valid_characters(newPath) && !title_sequence_save_exists(preset, newPath) && platform_file_exists(path)) { + // Copy the save file + char separator = platform_get_path_separator(); + platform_get_user_directory(newPath, "title sequences"); + strcat(newPath, gConfigTitleSequences.presets[preset].name); + strncat(newPath, &separator, 1); + strcat(newPath, newName); + // Add the appropriate extension if needed + if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0) + strcat(newPath, ".sv6"); + platform_file_copy(path, newPath); + + gConfigTitleSequences.presets[preset].num_saves++; + gConfigTitleSequences.presets[preset].saves = realloc(gConfigTitleSequences.presets[preset].saves, sizeof(char[TITLE_SEQUENCE_MAX_SAVE_LENGTH]) * (size_t)gConfigTitleSequences.presets[preset].num_saves); + + strcpy(gConfigTitleSequences.presets[preset].saves[gConfigTitleSequences.presets[preset].num_saves - 1], newName); + // Add the appropriate extension if needed + if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0) + strcat(gConfigTitleSequences.presets[preset].saves[gConfigTitleSequences.presets[preset].num_saves - 1], ".sv6"); + } +} + +void title_sequence_remove_save(int preset, int index) +{ + if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets && index >= 0 && index < gConfigTitleSequences.presets[preset].num_saves) { + // Delete the save file + char separator = platform_get_path_separator(); + utf8 path[MAX_PATH]; + platform_get_user_directory(path, "title sequences"); + strcat(path, gConfigTitleSequences.presets[preset].name); + strncat(path, &separator, 1); + strcat(path, gConfigTitleSequences.presets[preset].saves[index]); + platform_file_delete(path); + + // Remove all references to this save in the commands and decrement save indecies + for (int i = 0; i < gConfigTitleSequences.presets[preset].num_commands; i++) { + if (gConfigTitleSequences.presets[preset].commands[i].command == TITLE_SCRIPT_LOAD) { + if (gConfigTitleSequences.presets[preset].commands[i].saveIndex == index) + gConfigTitleSequences.presets[preset].commands[i].saveIndex = 0xFF; + else if (gConfigTitleSequences.presets[preset].commands[i].saveIndex > index && gConfigTitleSequences.presets[preset].commands[i].saveIndex != 0xFF) + gConfigTitleSequences.presets[preset].commands[i].saveIndex--; + } + } + + for (int i = index; i < gConfigTitleSequences.presets[preset].num_saves - 1; i++) { + strcpy(gConfigTitleSequences.presets[preset].saves[i], gConfigTitleSequences.presets[preset].saves[i + 1]); + } + gConfigTitleSequences.presets[preset].num_saves--; + gConfigTitleSequences.presets[preset].saves = realloc(gConfigTitleSequences.presets[preset].saves, sizeof(char[TITLE_SEQUENCE_MAX_SAVE_LENGTH]) * (size_t)gConfigTitleSequences.presets[preset].num_saves); + title_sequence_save_preset_script(preset); + } +} + +void title_sequence_rename_save(int preset, int index, const char *newName) +{ + if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets && index >= 0 && index < gConfigTitleSequences.presets[preset].num_saves && + filename_valid_characters(newName) && !title_sequence_save_exists(preset, newName)) { + + // Rename the save file + char separator = platform_get_path_separator(); + utf8 src[MAX_PATH], dest[MAX_PATH]; + platform_get_user_directory(src, "title sequences"); + platform_get_user_directory(dest, "title sequences"); + strcat(src, gConfigTitleSequences.presets[preset].name); + strcat(dest, gConfigTitleSequences.presets[preset].name); + strncat(src, &separator, 1); + strncat(dest, &separator, 1); + strcat(src, gConfigTitleSequences.presets[preset].saves[index]); + strcat(dest, newName); + // Add the appropriate extension if needed + char *extension = (char*)path_get_extension(newName); + if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0) + strcat(dest, ".sv6"); + platform_file_move(src, dest); + + strcpy(gConfigTitleSequences.presets[preset].saves[index], newName); + // Add the appropriate extension if needed + if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0) + strcat(gConfigTitleSequences.presets[preset].saves[index], ".sv6"); + title_sequence_save_preset_script(preset); + } +} + + +void title_sequence_add_command(int preset, title_command command) +{ + if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets) { + gConfigTitleSequences.presets[preset].commands = realloc(gConfigTitleSequences.presets[preset].commands, sizeof(title_command) * (size_t)(gConfigTitleSequences.presets[preset].num_commands + 1)); + gConfigTitleSequences.presets[preset].commands[gConfigTitleSequences.presets[preset].num_commands] = command; + gConfigTitleSequences.presets[preset].num_commands++; + title_sequence_save_preset_script(preset); + } +} +void title_sequence_insert_command(int preset, int index, title_command command) +{ + if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets && index >= 0 && index <= gConfigTitleSequences.presets[preset].num_commands) { + gConfigTitleSequences.presets[preset].commands = realloc(gConfigTitleSequences.presets[preset].commands, sizeof(title_command) * (size_t)(gConfigTitleSequences.presets[preset].num_commands + 1)); + for (int i = gConfigTitleSequences.presets[preset].num_commands; i > index; i--) { + gConfigTitleSequences.presets[preset].commands[i] = gConfigTitleSequences.presets[preset].commands[i - 1]; + } + gConfigTitleSequences.presets[preset].commands[index] = command; + gConfigTitleSequences.presets[preset].num_commands++; + title_sequence_save_preset_script(preset); + } +} + +void title_sequence_delete_command(int preset, int index) +{ + if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets && index >= 0 && index < gConfigTitleSequences.presets[preset].num_commands) { + for (int i = index; i < gConfigTitleSequences.presets[preset].num_commands - 1; i++) { + gConfigTitleSequences.presets[preset].commands[i] = gConfigTitleSequences.presets[preset].commands[i + 1]; + } + gConfigTitleSequences.presets[preset].num_commands--; + gConfigTitleSequences.presets[preset].commands = realloc(gConfigTitleSequences.presets[preset].commands, sizeof(title_command) * (size_t)gConfigTitleSequences.presets[preset].num_commands); + title_sequence_save_preset_script(preset); + } +} + +void title_sequence_move_down_command(int preset, int index) +{ + if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets && index >= 0 && index + 1 < gConfigTitleSequences.presets[preset].num_commands) { + title_command command = gConfigTitleSequences.presets[preset].commands[index]; + gConfigTitleSequences.presets[preset].commands[index] = gConfigTitleSequences.presets[preset].commands[index + 1]; + gConfigTitleSequences.presets[preset].commands[index + 1] = command; + title_sequence_save_preset_script(preset); + } +} + +void title_sequence_move_up_command(int preset, int index) +{ + if (preset >= TITLE_SEQUENCE_DEFAULT_PRESETS && preset < gConfigTitleSequences.num_presets && index > 0 && index < gConfigTitleSequences.presets[preset].num_commands) { + title_command command = gConfigTitleSequences.presets[preset].commands[index]; + gConfigTitleSequences.presets[preset].commands[index] = gConfigTitleSequences.presets[preset].commands[index - 1]; + gConfigTitleSequences.presets[preset].commands[index - 1] = command; + title_sequence_save_preset_script(preset); + } +} diff --git a/src/interface/title_sequences.h b/src/interface/title_sequences.h new file mode 100644 index 0000000000..3c46ebbda2 --- /dev/null +++ b/src/interface/title_sequences.h @@ -0,0 +1,68 @@ +/***************************************************************************** +* Copyright (c) 2014 Ted John, Peter Hill, Duncan Frost +* OpenRCT2, an open source clone of Roller Coaster Tycoon 2. +* +* This file is part of OpenRCT2. +* +* OpenRCT2 is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*****************************************************************************/ + +#ifndef _TITLE_SEQUENCES_H_ +#define _TITLE_SEQUENCES_H_ + +#include "../common.h" +#include "window.h" +#include "../config.h" +#include "../title.h" + +#define TITLE_SEQUENCE_DEFAULT_PRESETS 2 + +title_command TitleScriptMakeCommand(int command, int parameter1, int parameter2); + +#define TITLE_WAIT(t) TitleScriptMakeCommand(TITLE_SCRIPT_WAIT, t, 0) +#define TITLE_LOADMM() TitleScriptMakeCommand(TITLE_SCRIPT_LOADMM, 0, 0) +#define TITLE_LOCATION(x, y) TitleScriptMakeCommand(TITLE_SCRIPT_LOCATION, x, y) +#define TITLE_ROTATE(n) TitleScriptMakeCommand(TITLE_SCRIPT_ROTATE, n, 0) +#define TITLE_ZOOM(d) TitleScriptMakeCommand(TITLE_SCRIPT_ZOOM, d, 0) +#define TITLE_RESTART() TitleScriptMakeCommand(TITLE_SCRIPT_RESTART, 0, 0) +#define TITLE_LOAD(i) TitleScriptMakeCommand(TITLE_SCRIPT_LOAD, i, 0) + +// The index of the current title sequence being edited +extern uint16 gCurrentTitleSequence; +// The index of the current title sequence being shown +extern uint16 gCurrentPreviewTitleSequence; + +bool title_sequence_name_exists(const char *name); +bool title_sequence_save_exists(int preset, const char *name); + +// Presets +void title_sequence_change_preset(int preset); +void title_sequence_create_preset(const char *name); +void title_sequence_duplicate_preset(int duplicate, const char *name); +void title_sequence_delete_preset(int preset); +void title_sequence_rename_preset(int preset, const char *newName); + +// Saves +void title_sequence_add_save(int preset, const char *path, const char *newName); +void title_sequence_remove_save(int preset, int index); +void title_sequence_rename_save(int preset, int index, const char *newName); + +// Commands +void title_sequence_add_command(int preset, title_command command); +void title_sequence_insert_command(int preset, int index, title_command command); +void title_sequence_delete_command(int preset, int index); +void title_sequence_move_down_command(int preset, int index); +void title_sequence_move_up_command(int preset, int index); + +#endif \ No newline at end of file diff --git a/src/interface/window.c b/src/interface/window.c index 5a88d463f1..bdd5084f98 100644 --- a/src/interface/window.c +++ b/src/interface/window.c @@ -46,6 +46,7 @@ char gTextBoxInput[512] = { 0 }; int gMaxTextBoxInputLength = 0; int gTextBoxFrameNo = 0; bool gUsingWidgetTextBox = 0; +bool gLoadSaveTitleSequenceSave = 0; // converted from uint16 values at 0x009A41EC - 0x009A4230 // these are percentage coordinates of the viewport to center to, if a window is obscuring a location, the next is tried @@ -2486,6 +2487,7 @@ void window_cancel_textbox() gCurrentTextBox.window.classification, gCurrentTextBox.window.number ); + window_event_textinput_call(w, gCurrentTextBox.widget_index, NULL); gCurrentTextBox.window.classification = 255; gCurrentTextBox.window.number = 0; platform_stop_text_input(); diff --git a/src/interface/window.h b/src/interface/window.h index 30527bda51..9aee92e59a 100644 --- a/src/interface/window.h +++ b/src/interface/window.h @@ -414,6 +414,8 @@ enum { WC_THEMES = 119, WC_TILE_INSPECTOR = 120, WC_CHANGELOG = 121, + WC_TITLE_EDITOR = 122, + WC_TITLE_COMMAND_EDITOR = 123, // Only used for colour schemes WC_STAFF = 220, @@ -444,9 +446,11 @@ enum { LOADSAVETYPE_GAME = 0 << 1, LOADSAVETYPE_LANDSCAPE = 1 << 1, LOADSAVETYPE_SCENARIO = 2 << 1, - LOADSAVETYPE_TRACK = 3 << 1, + LOADSAVETYPE_TRACK = 3 << 1 }; +extern bool gLoadSaveTitleSequenceSave; + // rct2: 0x01420078 extern rct_window* g_window_list; @@ -580,6 +584,8 @@ void window_publisher_credits_open(); void window_track_manage_open(); void window_viewport_open(); void window_themes_open(); +void window_title_editor_open(int tab); +void window_title_command_editor_open(int command, bool insert); void window_tile_inspector_open(); void window_text_input_open(rct_window* call_w, int call_widget, rct_string_id title, rct_string_id description, rct_string_id existing_text, uint32 existing_args, int maxLength); void window_text_input_raw_open(rct_window* call_w, int call_widget, rct_string_id title, rct_string_id description, utf8string existing_text, int maxLength); diff --git a/src/openrct2.c b/src/openrct2.c index 83875fa3d6..d5589b8d0e 100644 --- a/src/openrct2.c +++ b/src/openrct2.c @@ -30,6 +30,7 @@ #include "platform/platform.h" #include "util/sawyercoding.h" #include "world/mapgen.h" +#include "title.h" int gOpenRCT2StartupAction = STARTUP_ACTION_TITLE; char gOpenRCT2StartupActionPath[512] = { 0 }; @@ -174,6 +175,8 @@ bool openrct2_initialise() themes_set_default(); themes_load_presets(); + title_sequences_set_default(); + title_sequences_load_presets(); if (!rct2_init()) return false; diff --git a/src/platform/platform.h b/src/platform/platform.h index 2b103f9955..3a6c7c6ba9 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -90,6 +90,7 @@ int platform_directory_exists(const char *path); int platform_original_game_data_exists(const char *path); time_t platform_file_get_modified_time(char* path); int platform_ensure_directory_exists(const char *path); +int platform_directory_delete(const char *path); int platform_lock_single_instance(); int platform_enumerate_files_begin(const char *pattern); int platform_enumerate_files_next(int handle, file_info *outFileInfo); diff --git a/src/platform/windows.c b/src/platform/windows.c index 97b0005157..df02a1fb3c 100644 --- a/src/platform/windows.c +++ b/src/platform/windows.c @@ -116,6 +116,28 @@ int platform_ensure_directory_exists(const char *path) return CreateDirectory(path, NULL); } +int platform_directory_delete(const char *path) +{ + char pszFrom[MAX_PATH]; + strcpy(pszFrom, path); + // Needs to be double-null terminated for some weird reason + pszFrom[strlen(path) + 1] = 0; + + SHFILEOPSTRUCTA fileop; + fileop.hwnd = NULL; // no status display + fileop.wFunc = FO_DELETE; // delete operation + fileop.pFrom = pszFrom; // source file name as double null terminated string + fileop.pTo = NULL; // no destination needed + fileop.fFlags = FOF_NOCONFIRMATION|FOF_SILENT; // do not prompt the user + + fileop.fAnyOperationsAborted = FALSE; + fileop.lpszProgressTitle = NULL; + fileop.hNameMappings = NULL; + + int ret = SHFileOperationA(&fileop); + return (ret == 0); +} + int platform_lock_single_instance() { HANDLE mutex, status; diff --git a/src/rct2.c b/src/rct2.c index 75d2a20421..0b3068ebe5 100644 --- a/src/rct2.c +++ b/src/rct2.c @@ -345,7 +345,7 @@ void rct2_update_2() // Screens if (RCT2_GLOBAL(RCT2_ADDRESS_RUN_INTRO_TICK_PART, uint8) != 0) intro_update(); - else if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 1) + else if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) title_update(); else game_update(); diff --git a/src/sprites.h b/src/sprites.h index b30b07c0a6..1118cd3f7f 100644 --- a/src/sprites.h +++ b/src/sprites.h @@ -380,6 +380,11 @@ enum { SPR_G2_RCT1_OPEN_BUTTON_1 = SPR_G2_BEGIN + 26, SPR_G2_RCT1_OPEN_BUTTON_2 = SPR_G2_BEGIN + 27, SPR_G2_RCT1_OPEN_BUTTON_3 = SPR_G2_BEGIN + 28, + + SPR_G2_TITLE_RESTART = SPR_G2_BEGIN + 29, + SPR_G2_TITLE_STOP = SPR_G2_BEGIN + 30, + SPR_G2_TITLE_PLAY = SPR_G2_BEGIN + 31, + SPR_G2_TITLE_SKIP = SPR_G2_BEGIN + 32, }; #endif diff --git a/src/title.c b/src/title.c index 0950d16453..8104d7f90c 100644 --- a/src/title.c +++ b/src/title.c @@ -42,21 +42,18 @@ #include "world/park.h" #include "world/scenery.h" #include "world/sprite.h" +#include "title.h" +#include "interface/title_sequences.h" +#include "windows/error.h" static const int gRandomShowcase = 0; +sint32 gTitleScriptCommand = -1; +uint8 gTitleScriptSave = 0xFF; +sint32 gTitleScriptSkipTo = -1; +sint32 gTitleScriptSkipLoad = -1; #pragma region Showcase script -enum { - TITLE_SCRIPT_WAIT, - 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 LOADMM() TITLE_SCRIPT_LOADMM #define LOCATION(x, y) TITLE_SCRIPT_LOCATION, x, y @@ -82,6 +79,7 @@ static uint8* _loadedScript; static const uint8* _currentScript; static int _scriptNoLoadsSinceRestart; static int _scriptWaitCounter; +static int _scriptCurrentPreset; static void title_init_showcase(); static void title_update_showcase(); @@ -162,7 +160,7 @@ static void title_create_windows() */ static void title_init_showcase() { - _scriptNoLoadsSinceRestart = 1; + /*_scriptNoLoadsSinceRestart = 1; SafeFree(_loadedScript); @@ -179,7 +177,8 @@ static void title_init_showcase() break; } - _scriptWaitCounter = 0; + _scriptWaitCounter = 0;*/ + title_refresh_sequence(); title_update_showcase(); } @@ -236,6 +235,7 @@ static void title_skip_opcode() uint8 script_opcode; script_opcode = *_currentScript++; + gTitleScriptCommand++; switch (script_opcode) { case TITLE_SCRIPT_WAIT: _currentScript++; @@ -266,9 +266,30 @@ static void title_do_next_script_opcode() short x, y, z; uint8 script_opcode, script_operand; rct_window* w; - - script_opcode = *_currentScript++; + gTitleScriptCommand++; + if (*(_currentScript - 1) != TITLE_SCRIPT_END) + script_opcode = *_currentScript++; + else + script_opcode = *_currentScript; + if (gTitleScriptSkipTo != -1) { + if (gTitleScriptSkipTo == gTitleScriptCommand) { + gTitleScriptSkipTo = -1; + gTitleScriptSkipLoad = -1; + } + else if (gTitleScriptSkipLoad == gTitleScriptCommand) { + gTitleScriptSkipLoad = -1; + } + else if (gTitleScriptSkipLoad != -1) { + gTitleScriptCommand--; + _currentScript--; + title_skip_opcode(); + return; + } + } switch (script_opcode) { + case TITLE_SCRIPT_END: + _scriptWaitCounter = 1; + break; case TITLE_SCRIPT_WAIT: _scriptWaitCounter = (*_currentScript++) * 32; break; @@ -277,6 +298,7 @@ static void title_do_next_script_opcode() log_fatal("OpenRCT2 can not currently cope when unable to load title screen scenario."); exit(-1); } + gTitleScriptSave = 0xFF; break; case TITLE_SCRIPT_LOCATION: x = (*_currentScript++) * 32 + 16; @@ -306,6 +328,8 @@ static void title_do_next_script_opcode() break; case TITLE_SCRIPT_RESTART: _scriptNoLoadsSinceRestart = 1; + gTitleScriptCommand = -1; + gTitleScriptSave = 0xFF; _currentScript = _loadedScript; if (gRandomShowcase) { if (_currentScript != NULL) @@ -317,6 +341,7 @@ static void title_do_next_script_opcode() { const uint8 *loadPtr; char *ch, filename[32], path[MAX_PATH]; + char separator = platform_get_path_separator(); loadPtr = _currentScript - 1; @@ -327,19 +352,38 @@ static void title_do_next_script_opcode() } while (*(_currentScript - 1) != 0); // Construct full relative path - sprintf(path, "%s%cData%ctitle%c%s", gExePath, platform_get_path_separator(), platform_get_path_separator(), platform_get_path_separator(), filename); + if (gConfigTitleSequences.presets[_scriptCurrentPreset].path[0]) { + strcpy(path, gConfigTitleSequences.presets[_scriptCurrentPreset].path); + } + else { + platform_get_user_directory(path, "title sequences"); + strcat(path, gConfigTitleSequences.presets[_scriptCurrentPreset].name); + strncat(path, &separator, 1); + } + + strcat(path, filename); if (title_load_park(path)) { _scriptNoLoadsSinceRestart = 0; + gTitleScriptSave = gConfigTitleSequences.presets[gCurrentPreviewTitleSequence].commands[gTitleScriptCommand].saveIndex; } else { + log_error("Failed to load: \"%s\" for the title sequence.", path); script_opcode = *_currentScript; - while (script_opcode != TITLE_SCRIPT_LOADMM && script_opcode != TITLE_SCRIPT_LOAD && script_opcode != TITLE_SCRIPT_RESTART) { + while (script_opcode != TITLE_SCRIPT_LOADMM && script_opcode != TITLE_SCRIPT_LOAD && script_opcode != TITLE_SCRIPT_RESTART && script_opcode != TITLE_SCRIPT_END) { title_skip_opcode(); script_opcode = *_currentScript; } - if (script_opcode == TITLE_SCRIPT_RESTART && _scriptNoLoadsSinceRestart) { + if ((script_opcode == TITLE_SCRIPT_RESTART || script_opcode == TITLE_SCRIPT_END) && _scriptNoLoadsSinceRestart) { if (_currentScript != _magicMountainScript) { + _scriptNoLoadsSinceRestart = 1; + gTitleScriptCommand = -1; + gTitleScriptSave = 0xFF; _currentScript = _magicMountainScript; + gCurrentPreviewTitleSequence = 0; + gTitleScriptSkipTo = -1; + gTitleScriptSkipLoad = -1; + _scriptCurrentPreset = 0; + //window_invalidate_by_class(WC_TITLE_EDITOR); } else { log_fatal("OpenRCT2 can not currently cope when unable to load title screen scenario."); exit(-1); @@ -349,6 +393,7 @@ static void title_do_next_script_opcode() } break; } + window_invalidate_by_class(WC_TITLE_EDITOR); } /** @@ -357,13 +402,28 @@ static void title_do_next_script_opcode() */ static void title_update_showcase() { - if (_scriptWaitCounter <= 0) { + // Loop used for scene skip functionality + // Only loop here when the appropriate save hasn't been loaded yet since no game updates are required + do { do { - title_do_next_script_opcode(); - } while (_scriptWaitCounter == 0); - } + if (_scriptWaitCounter <= 0) { + do { + title_do_next_script_opcode(); + } while (_scriptWaitCounter == 0); + } - _scriptWaitCounter--; + if (gTitleScriptSkipTo != -1 && gTitleScriptSkipLoad != -1) + _scriptWaitCounter = 0; + else if (*(_currentScript - 1) != TITLE_SCRIPT_END) + _scriptWaitCounter--; + } while (gTitleScriptSkipTo != -1 && gTitleScriptSkipLoad != -1); + + if (gTitleScriptSkipTo != -1 && gTitleScriptSkipLoad == -1) { + game_logic_update(); + update_palette_effects(); + update_rain_animation(); + } + } while (gTitleScriptSkipTo != -1 && gTitleScriptSkipLoad == -1); } static void DrawOpenRCT2(int x, int y) @@ -455,37 +515,45 @@ static uint8 *generate_random_script() #pragma region Load script.txt -static void title_script_get_line(FILE *file, char *parts) +void title_script_get_line(FILE *file, char *parts) { - int i, c, part, cindex, whitespace, comment; + int i, c, part, cindex, whitespace, comment, load; for (i = 0; i < 3; i++) - parts[i * 32] = 0; + parts[i * 128] = 0; part = 0; cindex = 0; whitespace = 1; comment = 0; - for (;;) { + load = 0; + for (; part < 3;) { c = fgetc(file); if (c == '\n' || c == '\r' || c == EOF) { - parts[part * 32 + cindex] = 0; + parts[part * 128 + cindex] = 0; return; } else if (c == '#') { - parts[part * 32 + cindex] = 0; + parts[part * 128 + cindex] = 0; comment = 1; - } else if (c == ' ' && !comment) { + } else if (c == ' ' && !comment && !load) { if (!whitespace) { - parts[part * 32 + cindex] = 0; + if (part == 0 && cindex == 4 && _strnicmp(parts, "LOAD", 4) == 0) + load = true; + parts[part * 128 + cindex] = 0; part++; cindex = 0; } } else if (!comment) { whitespace = 0; - if (cindex < 31) { - parts[part * 32 + cindex] = c; + if (cindex < 127) { + parts[part * 128 + cindex] = c; cindex++; } + else { + parts[part * 128 + cindex] = 0; + part++; + cindex = 0; + } } } } @@ -493,7 +561,7 @@ static void title_script_get_line(FILE *file, char *parts) static uint8 *title_script_load() { FILE *file; - char parts[3 * 32], *token, *part1, *part2, *src; + char parts[3 * 128], *token, *part1, *part2, *src; char path[MAX_PATH]; char filePath[] = "data/title/script.txt"; @@ -519,9 +587,9 @@ static uint8 *title_script_load() do { title_script_get_line(file, parts); - token = &parts[0 * 32]; - part1 = &parts[1 * 32]; - part2 = &parts[2 * 32]; + token = &parts[0 * 128]; + part1 = &parts[1 * 128]; + part2 = &parts[2 * 128]; if (token[0] != 0) { if (_stricmp(token, "LOAD") == 0) { @@ -564,3 +632,103 @@ static uint8 *title_script_load() } #pragma endregion + +bool title_refresh_sequence() +{ + _scriptCurrentPreset = gCurrentPreviewTitleSequence; + title_sequence *title = &gConfigTitleSequences.presets[_scriptCurrentPreset]; + + bool hasLoad = false, hasInvalidSave = false, hasWait = false, hasRestart = false; + for (int i = 0; i < title->num_commands && !hasInvalidSave; i++) { + if (title->commands[i].command == TITLE_SCRIPT_LOAD) { + if (title->commands[i].saveIndex == 0xFF) + hasInvalidSave = true; + hasLoad = true; + } + else if (title->commands[i].command == TITLE_SCRIPT_LOADMM) { + hasLoad = true; + } + else if (title->commands[i].command == TITLE_SCRIPT_WAIT) { + hasWait = true; + } + else if (title->commands[i].command == TITLE_SCRIPT_RESTART) { + hasRestart = true; + break; + } + else if (title->commands[i].command == TITLE_SCRIPT_END) { + break; + } + } + if (hasLoad && (hasWait || !hasRestart) && !hasInvalidSave) { + uint8 *src, *scriptPtr, *binaryScript; + binaryScript = malloc(1024 * 8); + scriptPtr = binaryScript; + + for (int i = 0; i < title->num_commands; i++) { + *scriptPtr++ = title->commands[i].command; + switch (title->commands[i].command) { + case TITLE_SCRIPT_LOAD: + src = title->saves[title->commands[i].saveIndex]; + do { + *scriptPtr++ = *src++; + } while (*(src - 1) != 0); + break; + case TITLE_SCRIPT_LOCATION: + *scriptPtr++ = title->commands[i].x; + *scriptPtr++ = title->commands[i].y; + break; + case TITLE_SCRIPT_ROTATE: + *scriptPtr++ = title->commands[i].rotations; + break; + case TITLE_SCRIPT_ZOOM: + *scriptPtr++ = title->commands[i].zoom; + break; + case TITLE_SCRIPT_WAIT: + *scriptPtr++ = title->commands[i].seconds; + break; + } + } + + *scriptPtr++ = TITLE_SCRIPT_END; + + int scriptLength = (int)(scriptPtr - binaryScript); + binaryScript = realloc(binaryScript, scriptLength); + + _scriptNoLoadsSinceRestart = 1; + if (_loadedScript != _magicMountainScript) + SafeFree(_loadedScript); + _loadedScript = binaryScript; + _currentScript = binaryScript; + _scriptWaitCounter = 0; + gTitleScriptCommand = -1; + gTitleScriptSave = 0xFF; + title_update_showcase(); + gfx_invalidate_screen(); + + return true; + } + log_error("Failed to load title sequence, hasLoad: %i, hasWait: %i, hasRestart: %i, hasInvalidSave: %i", hasLoad, hasWait, hasRestart, hasInvalidSave); + window_error_open(5402, (!hasWait && hasRestart) ? 5439 : STR_NONE); + _scriptNoLoadsSinceRestart = 1; + if (_loadedScript != _magicMountainScript) + SafeFree(_loadedScript); + _scriptCurrentPreset = 0; + _currentScript = _magicMountainScript; + _scriptWaitCounter = 0; + gTitleScriptCommand = -1; + gTitleScriptSave = 0xFF; + gCurrentPreviewTitleSequence = 0; + window_invalidate_by_class(WC_OPTIONS); + window_invalidate_by_class(WC_TITLE_EDITOR); + title_update_showcase(); + gfx_invalidate_screen(); + return false; +} + +void title_skip_from_beginning() +{ + _scriptNoLoadsSinceRestart = 1; + gTitleScriptCommand = -1; + gTitleScriptSave = 0xFF; + _currentScript = _loadedScript; +} diff --git a/src/title.h b/src/title.h index 33897b12e7..a174d222f0 100644 --- a/src/title.h +++ b/src/title.h @@ -21,7 +21,28 @@ #ifndef _TITLE_H_ #define _TITLE_H_ +enum { + TITLE_SCRIPT_WAIT, + TITLE_SCRIPT_LOADMM, + TITLE_SCRIPT_LOCATION, + TITLE_SCRIPT_ROTATE, + TITLE_SCRIPT_ZOOM, + TITLE_SCRIPT_RESTART, + TITLE_SCRIPT_LOAD, + TITLE_SCRIPT_END, + TITLE_SCRIPT_LOOP, + TITLE_SCRIPT_ENDLOOP +} TITLE_SCRIPT_COMMANDS; + +extern sint32 gTitleScriptCommand; +extern uint8 gTitleScriptSave; +extern sint32 gTitleScriptSkipTo; +extern sint32 gTitleScriptSkipLoad; + void title_load(); void title_update(); +void title_skip_from_beginning(); +void title_script_get_line(FILE *file, char *parts); +bool title_refresh_sequence(); #endif diff --git a/src/util/util.c b/src/util/util.c index bf856238fa..b015c1c98f 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -41,6 +41,16 @@ int mph_to_kmph(int mph) return (mph * 1648) / 1024; } +bool filename_valid_characters(const char *filename) +{ + for (int i = 0; filename[i] != '\0'; i++) { + if (filename[i] == '\\' || filename[i] == '/' || filename[i] == ':' || filename[i] == '?' || + filename[i] == '*' || filename[i] == '<' || filename[i] == '>' || filename[i] == '|') + return false; + } + return true; +} + const char *path_get_filename(const char *path) { const char *result, *ch; diff --git a/src/util/util.h b/src/util/util.h index e8d8cca36d..18e594d741 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -27,6 +27,8 @@ int squaredmetres_to_squaredfeet(int squaredMetres); int metres_to_feet(int metres); int mph_to_kmph(int mph); +bool filename_valid_characters(const char *filename); + const char *path_get_filename(const char *path); const char *path_get_extension(const char *path); void path_set_extension(char *path, const char *newExtension); diff --git a/src/windows/loadsave.c b/src/windows/loadsave.c index 0d3e733e5c..5b83b99b58 100644 --- a/src/windows/loadsave.c +++ b/src/windows/loadsave.c @@ -30,6 +30,7 @@ #include "../title.h" #include "../windows/error.h" #include "../interface/themes.h" +#include "../interface/title_sequences.h" #include "../util/util.h" #pragma region Widgets @@ -144,6 +145,7 @@ static rct_window *window_overwrite_prompt_open(const char *name, const char *pa rct_window *window_loadsave_open(int type, char *defaultName) { + gLoadSaveTitleSequenceSave = false; char path[MAX_PATH], *ch; int includeNewItem; rct_window* w; @@ -432,10 +434,25 @@ static void window_loadsave_textinput() int i, overwrite; window_textinput_get_registers(w, widgetIndex, result, text); - + if (!result || text[0] == 0) return; + if (gLoadSaveTitleSequenceSave) { + if (filename_valid_characters(text)) { + if (!title_sequence_save_exists(gCurrentTitleSequence, text)) { + title_sequence_add_save(gCurrentTitleSequence, path, text); + } + else { + window_error_open(5404, STR_NONE); + } + } + else { + window_error_open(5243, STR_NONE); + } + return; + } + strncpy(path, _directory, sizeof(path)); strncat(path, text, sizeof(path)); strncat(path, _extension, sizeof(path)); @@ -747,7 +764,22 @@ static void window_loadsave_select(rct_window *w, const char *path) { switch (_loadsaveType) { case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME) : - if (game_load_save(path)) { + if (gLoadSaveTitleSequenceSave) { + utf8 newName[MAX_PATH]; + char *extension = (char*)path_get_extension(path_get_filename(path)); + strcpy(newName, path_get_filename(path)); + if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0) + strcat(newName, ".sv6"); + if (title_sequence_save_exists(gCurrentTitleSequence, newName)) { + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32) = (uint32)&_listItems[w->selected_list_item].name; + window_text_input_open(w, WIDX_SCROLL, 5435, 5404, 1170, (uint32)_listItems[w->selected_list_item].name, TITLE_SEQUENCE_MAX_SAVE_LENGTH - 1); + } + else { + title_sequence_add_save(gCurrentTitleSequence, path, newName); + window_close(w); + } + } + else if (game_load_save(path)) { window_close(w); gfx_invalidate_screen(); rct2_endupdate(); diff --git a/src/windows/options.c b/src/windows/options.c index 1222cfb96b..341d98ec95 100644 --- a/src/windows/options.c +++ b/src/windows/options.c @@ -41,6 +41,8 @@ #include "dropdown.h" #include "error.h" #include "../interface/themes.h" +#include "../interface/title_sequences.h" +#include "../title.h" enum WINDOW_OPTIONS_PAGE { WINDOW_OPTIONS_PAGE_DISPLAY, @@ -125,6 +127,7 @@ enum WINDOW_OPTIONS_WIDGET_IDX { WIDX_DEBUGGING_TOOLS, WIDX_TITLE_SEQUENCE, WIDX_TITLE_SEQUENCE_DROPDOWN, + WIDX_TITLE_SEQUENCE_BUTTON, // Twitch WIDX_CHANNEL_BUTTON = WIDX_PAGE_START, @@ -136,7 +139,7 @@ enum WINDOW_OPTIONS_WIDGET_IDX { }; #define WW 310 -#define WH 183 +#define WH 194 #define MAIN_OPTIONS_WIDGETS \ { WWT_FRAME, 0, 0, WW-1, 0, WH-1, STR_NONE, STR_NONE }, \ @@ -220,6 +223,7 @@ static rct_widget window_options_misc_widgets[] = { { 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 }, + { WWT_DROPDOWN_BUTTON, 1, 26, 185, 174, 185, 5436, STR_NONE }, // Title sequences button { WIDGETS_END }, }; @@ -367,7 +371,8 @@ static uint32 window_options_page_enabled_widgets[] = { (1 << WIDX_AUTO_STAFF_PLACEMENT) | (1 << WIDX_DEBUGGING_TOOLS) | (1 << WIDX_TITLE_SEQUENCE) | - (1 << WIDX_TITLE_SEQUENCE_DROPDOWN), + (1 << WIDX_TITLE_SEQUENCE_DROPDOWN) | + (1 << WIDX_TITLE_SEQUENCE_BUTTON), MAIN_OPTIONS_ENABLED_WIDGETS | (1 << WIDX_CHANNEL_BUTTON) | @@ -553,6 +558,8 @@ static void window_options_mouseup() config_save_default(); window_invalidate(w); break; + case WIDX_TITLE_SEQUENCE_BUTTON: + window_title_editor_open(0); } break; @@ -793,7 +800,7 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget* gDropdownItemsChecked = 1 << gConfigGeneral.autosave_frequency; break; case WIDX_TITLE_SEQUENCE_DROPDOWN: - gDropdownItemsFormat[0] = 1142; + /* gDropdownItemsFormat[0] = 1142; gDropdownItemsArgs[0] = STR_TITLE_SEQUENCE_RCT2; gDropdownItemsFormat[1] = 1142; gDropdownItemsArgs[1] = STR_TITLE_SEQUENCE_OPENRCT2; @@ -803,6 +810,26 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget* else if (gConfigGeneral.title_sequence == TITLE_SEQUENCE_OPENRCT2) gDropdownItemsChecked = 1 << 1; break; + case WIDX_THEMES_DROPDOWN:*/ + num_items = gConfigTitleSequences.num_presets; + + for (i = 0; i < num_items; i++) { + gDropdownItemsFormat[i] = 2777; + gDropdownItemsArgs[i] = (uint64)&gConfigTitleSequences.presets[i].name; + } + + window_dropdown_show_text_custom_width( + w->x + widget->left, + w->y + widget->top, + widget->bottom - widget->top + 1, + w->colours[1], + DROPDOWN_FLAG_STAY_OPEN, + num_items, + widget->right - widget->left - 3 + ); + + gDropdownItemsChecked = 1 << (gCurrentPreviewTitleSequence); + break; } break; @@ -974,9 +1001,9 @@ static void window_options_dropdown() } 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; + if (dropdownIndex != gCurrentPreviewTitleSequence) { + title_sequence_change_preset(dropdownIndex); + title_refresh_sequence(); config_save_default(); window_invalidate(w); } @@ -1157,6 +1184,7 @@ static void window_options_invalidate() 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; + window_options_misc_widgets[WIDX_TITLE_SEQUENCE_BUTTON].type = WWT_DROPDOWN_BUTTON; break; case WINDOW_OPTIONS_PAGE_TWITCH: @@ -1280,15 +1308,17 @@ static void window_options_paint() w->x + window_options_misc_widgets[WIDX_AUTOSAVE].left + 1, w->y + window_options_misc_widgets[WIDX_AUTOSAVE].top ); - + + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32) = (uint32)&gConfigTitleSequences.presets[gCurrentPreviewTitleSequence].name; 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( + gfx_draw_string_left_clipped( dpi, - STR_TITLE_SEQUENCE_RCT1 + gConfigGeneral.title_sequence, - NULL, + 1170, + (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, w->colours[1], w->x + window_options_misc_widgets[WIDX_TITLE_SEQUENCE].left + 1, - w->y + window_options_misc_widgets[WIDX_TITLE_SEQUENCE].top + w->y + window_options_misc_widgets[WIDX_TITLE_SEQUENCE].top, + window_options_misc_widgets[WIDX_TITLE_SEQUENCE_DROPDOWN].left - window_options_misc_widgets[WIDX_TITLE_SEQUENCE].left - 4 ); break; } diff --git a/src/windows/themes.c b/src/windows/themes.c index 265da25fb9..c6fa4ab4ba 100644 --- a/src/windows/themes.c +++ b/src/windows/themes.c @@ -34,6 +34,7 @@ #include "dropdown.h" #include "../interface/themes.h" #include "error.h" +#include "../util/util.h" enum { WINDOW_THEMES_TAB_SETTINGS, @@ -240,6 +241,7 @@ static rct_windowclass window_themes_tab_5_classes[] = { static rct_windowclass window_themes_tab_6_classes[] = { WC_CHEATS, WC_THEMES, + WC_TITLE_EDITOR, WC_OPTIONS, WC_KEYBOARD_SHORTCUT_LIST, WC_CHANGE_KEYBOARD_SHORTCUT, @@ -728,15 +730,6 @@ void window_themes_scrollmouseover() { // return; } -static bool valid_characters(const char *name) -{ - for (int i = 0; name[i] != '\0'; i++) { - if (name[i] == '\\' || name[i] == '/' || name[i] == ':' || name[i] == '?' || name[i] == '*' || name[i] == '<' || name[i] == '>' || name[i] == '|') - return false; - } - return true; -} - static void window_themes_textinput() { rct_window *w; @@ -752,7 +745,7 @@ static void window_themes_textinput() switch (widgetIndex) { case WIDX_THEMES_DUPLICATE_BUTTON: case WIDX_THEMES_RENAME_BUTTON: - if (valid_characters(text)) { + if (filename_valid_characters(text)) { bool nameTaken = false; for (int i = 0; i < gConfigThemes.num_presets; i++) { if (strcmp(gConfigThemes.presets[i].name, text) == 0) { diff --git a/src/windows/title_command_editor.c b/src/windows/title_command_editor.c new file mode 100644 index 0000000000..0977790c96 --- /dev/null +++ b/src/windows/title_command_editor.c @@ -0,0 +1,522 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#include "../addresses.h" +#include "../input.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../interface/viewport.h" +#include "../localisation/localisation.h" +#include "../sprites.h" +#include "../world/map.h" +#include "../game.h" +#include "../interface/themes.h" +#include "../interface/title_sequences.h" +#include "../title.h" +#include "dropdown.h" + +typedef struct { + uint8 command; + rct_string_id nameStringId; + rct_string_id descStringId; +} TITLE_COMMAND_ORDER; + +TITLE_COMMAND_ORDER window_title_command_editor_orders[] = { + { TITLE_SCRIPT_LOAD, 5413, 5431 }, + { TITLE_SCRIPT_LOCATION, 5417, 5427 }, + { TITLE_SCRIPT_ROTATE, 5419, 5428 }, + { TITLE_SCRIPT_ZOOM, 5421, 5429 }, + { TITLE_SCRIPT_WAIT, 5423, 5430 }, + { TITLE_SCRIPT_RESTART, 5425, STR_NONE }, + { TITLE_SCRIPT_END, 5426, STR_NONE }, +}; + +#define NUM_COMMANDS 7 + +enum WINDOW_WATER_WIDGET_IDX { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_COMMAND, + WIDX_COMMAND_DROPDOWN, + WIDX_TEXTBOX_FULL, + WIDX_TEXTBOX_X, + WIDX_TEXTBOX_Y, + WIDX_SAVE, + WIDX_SAVE_DROPDOWN, + WIDX_OKAY, + WIDX_CANCEL +}; + +#define WW 200 +#define WH 120 +#define BY 32 +#define BY2 70 +#define WS 16 +#define WHA ((WW-WS*2)/2) + +static bool _window_title_command_editor_insert; +static int _window_title_command_editor_index; +static char textbox1Buffer[50]; +static char textbox2Buffer[50]; +static title_command command = { 6, 0, 0 }; + +static rct_widget window_title_command_editor_widgets[] = { + { WWT_FRAME, 1, 0, WW-1, 0, WH-1, -1, STR_NONE }, // panel / background + { WWT_CAPTION, 1, 1, WW-2, 1, 14, 5434, STR_WINDOW_TITLE_TIP }, // title bar + { WWT_CLOSEBOX, 1, WW-13, WW-3, 2, 13, 824, STR_CLOSE_WINDOW_TIP }, // close x button + { WWT_DROPDOWN, 1, WS, WW-WS-1, BY, BY+11, STR_NONE, STR_NONE }, // Command dropdown + { WWT_DROPDOWN_BUTTON, 1, WW-WS-12, WW-WS-2, BY+1, BY+10, 876, STR_NONE }, + { WWT_TEXT_BOX, 1, WS, WW-WS-1, BY2, BY2+11, (uint32)textbox1Buffer, STR_NONE }, // full textbox + + { WWT_TEXT_BOX, 1, WS, WS+WHA-4, BY2, BY2+11, (uint32)textbox1Buffer, STR_NONE }, // x textbox + { WWT_TEXT_BOX, 1, WS+WHA+3, WW-WS-1, BY2, BY2+11, (uint32)textbox2Buffer, STR_NONE }, // y textbox + + { WWT_DROPDOWN, 1, 16, WW-17, BY2, BY2+11, STR_NONE, STR_NONE }, // Save dropdown + { WWT_DROPDOWN_BUTTON, 1, WW-28, WW-18, BY2+1, BY2+10, 876, STR_NONE }, + + { WWT_DROPDOWN_BUTTON, 1, 10, 80, WH-21, WH-10, STR_OK, STR_NONE }, // OKAY + { WWT_DROPDOWN_BUTTON, 1, WW-80, WW-10, WH-21, WH-10, STR_CANCEL, STR_NONE }, // Cancel + + { WIDGETS_END }, +}; + +static void window_title_command_editor_emptysub() { } +static void window_title_command_editor_close(); +static void window_title_command_editor_mouseup(); +static void window_title_command_editor_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); +static void window_title_command_editor_dropdown(); +static void window_title_command_editor_update(); +static void window_title_command_editor_invalidate(); +static void window_title_command_editor_paint(); +static void window_title_command_editor_textinput(); +static void window_title_command_editor_inputsize(rct_window *w); +static int get_command_info_index(int index); +static TITLE_COMMAND_ORDER get_command_info(int index); +static rct_xy16 get_location(); + +static void* window_title_command_editor_events[] = { + window_title_command_editor_close, + window_title_command_editor_mouseup, + window_title_command_editor_emptysub, + window_title_command_editor_mousedown, + window_title_command_editor_dropdown, + window_title_command_editor_emptysub, + window_title_command_editor_update, + window_title_command_editor_emptysub, + window_title_command_editor_emptysub, + window_title_command_editor_emptysub, + window_title_command_editor_emptysub, + window_title_command_editor_emptysub, + window_title_command_editor_emptysub, + window_title_command_editor_emptysub, + window_title_command_editor_emptysub, + window_title_command_editor_emptysub, + window_title_command_editor_emptysub, + window_title_command_editor_emptysub, + window_title_command_editor_emptysub, + window_title_command_editor_textinput, + window_title_command_editor_emptysub, + window_title_command_editor_emptysub, + window_title_command_editor_emptysub, + window_title_command_editor_emptysub, + window_title_command_editor_emptysub, + window_title_command_editor_invalidate, + window_title_command_editor_paint, + window_title_command_editor_emptysub +}; + +static int get_command_info_index(int index) +{ + for (int i = 0; i < NUM_COMMANDS; i++) { + if (window_title_command_editor_orders[i].command == index) + return i; + } + return 0; +} + +static TITLE_COMMAND_ORDER get_command_info(int index) +{ + for (int i = 0; i < NUM_COMMANDS; i++) { + if (window_title_command_editor_orders[i].command == index) + return window_title_command_editor_orders[i]; + } + return window_title_command_editor_orders[0]; +} + +static rct_xy16 get_location() +{ + rct_xy16 mapCoord = { 0 }; + rct_window *w = window_get_main(); + if (w != NULL) { + int interactionType; + rct_map_element *mapElement; + + get_map_coordinates_from_pos(w->viewport->view_width / 2, w->viewport->view_height / 2, VIEWPORT_INTERACTION_MASK_TERRAIN, &mapCoord.x, &mapCoord.y, &interactionType, &mapElement, NULL); + mapCoord.x -= 16; + mapCoord.x /= 32; + mapCoord.y -= 16; + mapCoord.y /= 32; + mapCoord.x++; + mapCoord.y++; + } + return mapCoord; +} + +void window_title_command_editor_open(int index, bool insert) +{ + rct_window* window; + + // Check if window is already open + if (window_find_by_class(WC_TITLE_COMMAND_EDITOR) != NULL) + return; + + window = window_create_centred( + WW, + WH, + (uint32*)window_title_command_editor_events, + WC_TITLE_COMMAND_EDITOR, + WF_STICK_TO_FRONT + ); + window->widgets = window_title_command_editor_widgets; + window->enabled_widgets = + (1 << WIDX_CLOSE) | + (1 << WIDX_COMMAND) | + (1 << WIDX_COMMAND_DROPDOWN) | + (1 << WIDX_TEXTBOX_FULL) | + (1 << WIDX_TEXTBOX_X) | + (1 << WIDX_TEXTBOX_Y) | + (1 << WIDX_SAVE) | + (1 << WIDX_SAVE_DROPDOWN) | + (1 << WIDX_OKAY) | + (1 << WIDX_CANCEL); + window_init_scroll_widgets(window); + + _window_title_command_editor_index = index; + _window_title_command_editor_insert = insert; + if (!insert) { + command = gConfigTitleSequences.presets[gCurrentTitleSequence].commands[index]; + } + + switch (command.command) { + case TITLE_SCRIPT_LOAD: + if (command.saveIndex >= gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands) + command.saveIndex = 0xFF; + break; + case TITLE_SCRIPT_LOCATION: + _itoa(command.x, textbox1Buffer, 10); + _itoa(command.y, textbox2Buffer, 10); + break; + case TITLE_SCRIPT_ROTATE: + case TITLE_SCRIPT_ZOOM: + case TITLE_SCRIPT_WAIT: + _itoa(command.rotations, textbox1Buffer, 10); + break; + } +} + +static void window_title_command_editor_close() +{ + rct_window *w; + + window_get_register(w); +} + +static void window_title_command_editor_mouseup() +{ + rct_window *w, *title_editor_w; + short widgetIndex; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + case WIDX_CANCEL: + window_close(w); + break; + case WIDX_TEXTBOX_FULL: + window_start_textbox(w, widgetIndex, 1170, (uint32)textbox1Buffer, 4); + break; + case WIDX_TEXTBOX_X: + window_start_textbox(w, widgetIndex, 1170, (uint32)textbox1Buffer, 4); + break; + case WIDX_TEXTBOX_Y: + window_start_textbox(w, widgetIndex, 1170, (uint32)textbox2Buffer, 4); + break; + case WIDX_OKAY: + if (_window_title_command_editor_insert) { + title_sequence_insert_command(gCurrentTitleSequence, _window_title_command_editor_index, command); + } + else { + gConfigTitleSequences.presets[gCurrentTitleSequence].commands[_window_title_command_editor_index] = command; + title_sequence_save_preset_script(gCurrentTitleSequence); + } + title_editor_w = window_find_by_class(WC_TITLE_EDITOR); + if (title_editor_w != NULL) + title_editor_w->selected_list_item = _window_title_command_editor_index; + window_close(w); + break; + } +} + + +static void window_title_command_editor_mousedown(int widgetIndex, rct_window* w, rct_widget* widget) +{ + int num_items, i; + + widget--; + switch (widgetIndex) { + case WIDX_COMMAND_DROPDOWN: + num_items = NUM_COMMANDS; + for (i = 0; i < num_items; i++) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = window_title_command_editor_orders[i].nameStringId; + } + + window_dropdown_show_text_custom_width( + w->x + widget->left, + w->y + widget->top, + widget->bottom - widget->top + 1, + w->colours[1], + DROPDOWN_FLAG_STAY_OPEN, + num_items, + widget->right - widget->left - 3 + ); + + gDropdownItemsChecked = 1 << get_command_info_index(command.command); + break; + case WIDX_SAVE_DROPDOWN: + num_items = gConfigTitleSequences.presets[gCurrentTitleSequence].num_saves; + for (i = 0; i < num_items; i++) { + gDropdownItemsFormat[i] = 2777; + gDropdownItemsArgs[i] = (uint64)&gConfigTitleSequences.presets[gCurrentTitleSequence].saves[i]; + } + + window_dropdown_show_text_custom_width( + w->x + widget->left, + w->y + widget->top, + widget->bottom - widget->top + 1, + w->colours[1], + DROPDOWN_FLAG_STAY_OPEN, + num_items, + widget->right - widget->left - 3 + ); + + gDropdownItemsChecked = 1 << (command.saveIndex); + break; + } +} + +static void window_title_command_editor_dropdown() +{ + rct_window* w; + short widgetIndex, dropdownIndex; + rct_xy16 mapCoord; + + window_dropdown_get_registers(w, widgetIndex, dropdownIndex); + + if (dropdownIndex == -1) + return; + + switch (widgetIndex) { + case WIDX_COMMAND_DROPDOWN: + if (dropdownIndex == get_command_info_index(command.command)) + break; + command.command = window_title_command_editor_orders[dropdownIndex].command; + switch (command.command) { + case TITLE_SCRIPT_LOCATION: + mapCoord = get_location(); + command.x = (uint8)mapCoord.x; + command.y = (uint8)mapCoord.y; + _itoa(command.x, textbox1Buffer, 10); + _itoa(command.y, textbox2Buffer, 10); + break; + case TITLE_SCRIPT_ROTATE: + command.rotations = 1; + _itoa(command.rotations, textbox1Buffer, 10); + break; + case TITLE_SCRIPT_ZOOM: + command.zoom = 0; + _itoa(command.zoom, textbox1Buffer, 10); + break; + case TITLE_SCRIPT_WAIT: + command.seconds = 10; + _itoa(command.seconds, textbox1Buffer, 10); + break; + case TITLE_SCRIPT_LOAD: + command.saveIndex = 0; + if (command.saveIndex >= gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands) + command.saveIndex = 0xFF; + break; + } + window_invalidate(w); + break; + case WIDX_SAVE_DROPDOWN: + if (dropdownIndex == command.saveIndex) + break; + command.saveIndex = (uint8)dropdownIndex; + window_invalidate(w); + break; + } +} + +static void window_title_command_editor_textinput() +{ + uint8 result; + short widgetIndex; + rct_window *w; + char *text, * end; + int value; + + window_textinput_get_registers(w, widgetIndex, result, text); + + value = strtol(widgetIndex != WIDX_TEXTBOX_Y ? textbox1Buffer : textbox2Buffer, &end, 10); + if (value < 0) value = 0; + if (value > 255) value = 255; + switch (widgetIndex) { + case WIDX_TEXTBOX_FULL: + if (!result) { + if (*end == '\0') { + if (command.command == TITLE_SCRIPT_ROTATE) { + if (value > 3) value = 3; + } + else if (command.command == TITLE_SCRIPT_ZOOM) { + if (value > 3) value = 3; + } + command.rotations = (uint8)value; + } + _itoa(command.rotations, textbox1Buffer, 10); + window_invalidate(w); + } + else { + strcpy(textbox1Buffer, text); + } + break; + case WIDX_TEXTBOX_X: + if (!result) { + if (*end == '\0') + command.x = (uint8)value; + _itoa(command.x, textbox1Buffer, 10); + window_invalidate(w); + } + else { + strcpy(textbox1Buffer, text); + } + break; + case WIDX_TEXTBOX_Y: + if (!result) { + if (*end == '\0') + command.y = (uint8)value; + _itoa(command.y, textbox2Buffer, 10); + window_invalidate(w); + } + else { + strcpy(textbox2Buffer, text); + } + break; + } +} + +static void window_title_command_editor_update(rct_window *w) +{ + if (gCurrentTextBox.window.classification == w->classification && + gCurrentTextBox.window.number == w->number) { + window_update_textbox_caret(); + widget_invalidate(w, gCurrentTextBox.widget_index); + } +} + +static void window_title_command_editor_invalidate() +{ + rct_window *w; + + window_get_register(w); + colour_scheme_update_by_class(w, WC_TITLE_EDITOR); + + window_title_command_editor_widgets[WIDX_TEXTBOX_FULL].type = WWT_EMPTY; + window_title_command_editor_widgets[WIDX_TEXTBOX_X].type = WWT_EMPTY; + window_title_command_editor_widgets[WIDX_TEXTBOX_Y].type = WWT_EMPTY; + window_title_command_editor_widgets[WIDX_SAVE].type = WWT_EMPTY; + window_title_command_editor_widgets[WIDX_SAVE_DROPDOWN].type = WWT_EMPTY; + switch (command.command) { + case TITLE_SCRIPT_LOAD: + window_title_command_editor_widgets[WIDX_SAVE].type = WWT_DROPDOWN; + window_title_command_editor_widgets[WIDX_SAVE_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + break; + case TITLE_SCRIPT_LOCATION: + window_title_command_editor_widgets[WIDX_TEXTBOX_X].type = WWT_TEXT_BOX; + window_title_command_editor_widgets[WIDX_TEXTBOX_Y].type = WWT_TEXT_BOX; + break; + case TITLE_SCRIPT_ROTATE: + case TITLE_SCRIPT_ZOOM: + case TITLE_SCRIPT_WAIT: + window_title_command_editor_widgets[WIDX_TEXTBOX_FULL].type = WWT_TEXT_BOX; + break; + } +} + +static void window_title_command_editor_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + + gfx_draw_string_left(dpi, 5432, NULL, w->colours[1], w->x + WS, w->y + BY - 14); + gfx_draw_string_left(dpi, get_command_info(command.command).descStringId, NULL, w->colours[1], w->x + WS, w->y + BY2 - 14); + + gfx_draw_string_left_clipped( + dpi, + get_command_info(command.command).nameStringId, + NULL, + w->colours[1], + w->x + w->widgets[WIDX_COMMAND].left + 1, + w->y + w->widgets[WIDX_COMMAND].top, + w->widgets[WIDX_COMMAND_DROPDOWN].left - w->widgets[WIDX_COMMAND].left - 4 + ); + + if (command.command == TITLE_SCRIPT_LOAD) { + if (command.saveIndex == 0xFF) { + gfx_draw_string_left_clipped( + dpi, + 5437, + NULL, + w->colours[1], + w->x + w->widgets[WIDX_SAVE].left + 1, + w->y + w->widgets[WIDX_SAVE].top, + w->widgets[WIDX_SAVE_DROPDOWN].left - w->widgets[WIDX_SAVE].left - 4 + ); + } + else { + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32) = (uint32)&gConfigTitleSequences.presets[gCurrentTitleSequence].saves[command.saveIndex]; + gfx_draw_string_left_clipped( + dpi, + 1170, + (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, + w->colours[1], + w->x + w->widgets[WIDX_SAVE].left + 1, + w->y + w->widgets[WIDX_SAVE].top, + w->widgets[WIDX_SAVE_DROPDOWN].left - w->widgets[WIDX_SAVE].left - 4 + ); + } + } +} diff --git a/src/windows/title_editor.c b/src/windows/title_editor.c new file mode 100644 index 0000000000..49a2089fb0 --- /dev/null +++ b/src/windows/title_editor.c @@ -0,0 +1,1023 @@ +/***************************************************************************** +* Copyright (c) 2014 Maciek Baron, Dániel Tar +* OpenRCT2, an open source clone of Roller Coaster Tycoon 2. +* +* This file is part of OpenRCT2. +* +* OpenRCT2 is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*****************************************************************************/ + +#include "../addresses.h" +#include "../config.h" +#include "../game.h" +#include "../drawing/drawing.h" +#include "../input.h" +#include "../interface/viewport.h" +#include "../interface/widget.h" +#include "../interface/window.h" +#include "../localisation/localisation.h" +#include "../peep/peep.h" +#include "../peep/staff.h" +#include "../world/sprite.h" +#include "dropdown.h" +#include "../interface/themes.h" +#include "../sprites.h" +#include "../title.h" +#include "../interface/title_sequences.h" +#include "error.h" +#include "../scenario.h" +#include "../util/util.h" + +enum { + WINDOW_TITLE_EDITOR_TAB_PRESETS, + WINDOW_TITLE_EDITOR_TAB_SAVES, + WINDOW_TITLE_EDITOR_TAB_SCRIPT, + WINDOW_TITLE_EDITOR_TAB_COUNT +} WINDOW_TITLE_EDITOR_TAB; + +static void window_title_editor_emptysub() { } +static void window_title_editor_close(); +static void window_title_editor_mouseup(); +static void window_title_editor_resize(); +static void window_title_editor_mousedown(int widgetIndex, rct_window*w, rct_widget* widget); +static void window_title_editor_dropdown(); +static void window_title_editor_update(rct_window *w); +static void window_title_editor_scrollgetsize(); +static void window_title_editor_scrollmousedown(); +static void window_title_editor_scrollmouseover(); +static void window_title_editor_textinput(); +static void window_title_editor_tooltip(); +static void window_title_editor_invalidate(); +static void window_title_editor_paint(); +static void window_title_editor_scrollpaint(); +static void window_title_editor_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w); + +static void* window_title_editor_events[] = { + window_title_editor_close, + window_title_editor_mouseup, + window_title_editor_resize, + window_title_editor_mousedown, + window_title_editor_dropdown, + window_title_editor_emptysub, + window_title_editor_update, + window_title_editor_emptysub, + window_title_editor_emptysub, + window_title_editor_emptysub, + window_title_editor_emptysub, + window_title_editor_emptysub, + window_title_editor_emptysub, + window_title_editor_emptysub, + window_title_editor_emptysub, + window_title_editor_scrollgetsize, + window_title_editor_scrollmousedown, + window_title_editor_emptysub, + window_title_editor_scrollmouseover, + window_title_editor_textinput, + window_title_editor_emptysub, + window_title_editor_emptysub, + window_title_editor_tooltip, + window_title_editor_emptysub, + window_title_editor_emptysub, + window_title_editor_invalidate, + window_title_editor_paint, + window_title_editor_scrollpaint, +}; + +enum WINDOW_TITLE_EDITOR_WIDGET_IDX { + WIDX_TITLE_EDITOR_BACKGROUND, + WIDX_TITLE_EDITOR_TITLE, + WIDX_TITLE_EDITOR_CLOSE, + WIDX_TITLE_EDITOR_TAB_CONTENT_PANEL, + WIDX_TITLE_EDITOR_PRESETS_TAB, + WIDX_TITLE_EDITOR_SAVES_TAB, + WIDX_TITLE_EDITOR_SCRIPT_TAB, + WIDX_TITLE_EDITOR_LIST, + + // Presets Tab + WIDX_TITLE_EDITOR_PRESETS, + WIDX_TITLE_EDITOR_PRESETS_DROPDOWN, + WIDX_TITLE_EDITOR_DUPLICATE_BUTTON, + WIDX_TITLE_EDITOR_DELETE_BUTTON, + WIDX_TITLE_EDITOR_RENAME_BUTTON, + + // Saves Tab + WIDX_TITLE_EDITOR_ADD, + WIDX_TITLE_EDITOR_REMOVE, + WIDX_TITLE_EDITOR_RENAME, + WIDX_TITLE_EDITOR_LOAD, + + // Script Tab + WIDX_TITLE_EDITOR_INSERT, + WIDX_TITLE_EDITOR_EDIT, + WIDX_TITLE_EDITOR_DELETE, + //WIDX_TITLE_EDITOR_RELOAD, + WIDX_TITLE_EDITOR_SKIP_TO, + + WIDX_TITLE_EDITOR_MOVE_UP, + WIDX_TITLE_EDITOR_MOVE_DOWN, + + WIDX_TITLE_EDITOR_REPLAY, + WIDX_TITLE_EDITOR_STOP, + WIDX_TITLE_EDITOR_PLAY, + WIDX_TITLE_EDITOR_SKIP, +}; + +// Increase BW if certain launguages do not fit +// BW should be a multiple of 4 +#define WW 320 +#define WH 270 +#define BX 8 +#define BW 72 +#define BY 52 +#define BH 63 +#define BS 18 +#define ROW_HEIGHT 11 +#define SCROLL_WIDTH 350 + +static rct_widget window_title_editor_widgets[] = { + { WWT_FRAME, 0, 0, WW-1, 0, 106, 0x0FFFFFFFF, STR_NONE }, // panel / background + { WWT_CAPTION, 0, 1, WW-2, 1, 14, 5433, STR_WINDOW_TITLE_TIP }, // title bar + { WWT_CLOSEBOX, 0, WW-13, WW-3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close button + { WWT_RESIZE, 1, 0, WW-1, 43, 106, 0x0FFFFFFFF, STR_NONE }, // tab content panel + { WWT_TAB, 1, 3, 33, 17, 43, 0x02000144E, 5235 }, // presets tab + { WWT_TAB, 1, 34, 64, 17, 43, 0x02000144E, 5377 }, // saves tab + { WWT_TAB, 1, 65, 95, 17, 43, 0x02000144E, 5378 }, // script tab + { WWT_SCROLL, 1, BX+BW+9,WW-4, 48, WH-4, 3, STR_NONE }, // command/save list + + // Presets Tab + { WWT_DROPDOWN, 1, 125, 299, 60, 71, STR_NONE, STR_NONE }, // Preset title sequences + { WWT_DROPDOWN_BUTTON, 1, 288, 298, 61, 70, 876, STR_NONE }, + { WWT_DROPDOWN_BUTTON, 1, 10, 100, 82, 93, 5239, 5383 }, // Duplicate button + { WWT_DROPDOWN_BUTTON, 1, 110, 200, 82, 93, 3349, 5384 }, // Delete button + { WWT_DROPDOWN_BUTTON, 1, 210, 300, 82, 93, 3348, 5385 }, // Rename button + + // Saves Tab + { WWT_DROPDOWN_BUTTON, 1, BX, BX+BW-1,BY, BH, 5407, 5392 }, // Add + { WWT_DROPDOWN_BUTTON, 1, BX, BX+BW-1,BY+(BS*1), BH+(BS*1), 5408, 5393 }, // Remove + { WWT_DROPDOWN_BUTTON, 1, BX, BX+BW-1,BY+(BS*2), BH+(BS*2), 3348, 5394 }, // Rename + { WWT_DROPDOWN_BUTTON, 1, BX, BX+BW-1,BY+(BS*3), BH+(BS*3), 5413, 5395 }, // Load + + // Script Tab + { WWT_DROPDOWN_BUTTON, 1, BX, BX+BW-1,BY, BH, 5409, 5386 }, // Insert + { WWT_DROPDOWN_BUTTON, 1, BX, BX+BW-1,BY+(BS*1), BH+(BS*1), 5410, 5387 }, // Edit + { WWT_DROPDOWN_BUTTON, 1, BX, BX+BW-1,BY+(BS*2), BH+(BS*2), 3349, 5388 }, // Delete + //{ WWT_DROPDOWN_BUTTON, 1, BX, BX+BW-1,BY+(BS*3), BH+(BS*3), 5411, 5396 }, // Reload + { WWT_DROPDOWN_BUTTON, 1, BX, BX+BW-1,BY+(BS*3), BH+(BS*3), 5412, 5389 }, // Skip to + + { WWT_DROPDOWN_BUTTON, 1, BX, BX+BW/2-1,BY+(BS*5),BH+(BS*5), 5375, 5390 }, // Move down + { WWT_DROPDOWN_BUTTON, 1, BX+BW/2,BX+BW-1,BY+(BS*5), BH+(BS*5), 5376, 5391 }, // Move up + + { WWT_IMGBTN, 1, BX, BX+BW/4-1, WH-32, WH-16, SPR_G2_TITLE_RESTART, 5382 }, // Replay + { WWT_IMGBTN, 1, BX+BW/4,BX+BW/2-1, WH-32, WH-16, SPR_G2_TITLE_STOP, 5381 }, // Stop + { WWT_IMGBTN, 1, BX+BW/2,BX+BW*3/4-1,WH-32, WH-16, SPR_G2_TITLE_PLAY, 5380 }, // Play + { WWT_IMGBTN, 1, BX+BW*3/4,BX+BW, WH-32, WH-16, SPR_G2_TITLE_SKIP, 5379 }, // Skip + + { WIDGETS_END }, +}; + +static sint16 _window_title_editor_highlighted_index; + + +static int window_title_editor_tab_animation_loops[] = { + 64, + 1, + 28 +}; +static int window_title_editor_tab_animation_divisor[] = { + 4, + 1, + 4 +}; +static int window_title_editor_tab_sprites[] = { + SPR_TAB_RIDE_0, + 5183, + SPR_TAB_STATS_0 +}; + +static void window_title_editor_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w) +{ + int sprite_idx; + int x, y; + + for (int i = 0; i < WINDOW_TITLE_EDITOR_TAB_COUNT; i++) { + x = 0; + y = 0; + sprite_idx = window_title_editor_tab_sprites[i]; + if (w->selected_tab == i) + sprite_idx += w->frame_no / window_title_editor_tab_animation_divisor[w->selected_tab]; + if (i == 1) { + x = 4; + y = 1; + } + gfx_draw_sprite(dpi, sprite_idx, w->x + w->widgets[WIDX_TITLE_EDITOR_PRESETS_TAB + i].left + x, w->y + w->widgets[WIDX_TITLE_EDITOR_PRESETS_TAB + i].top + y, 0); + } +} + +void window_title_editor_open(int tab) +{ + rct_window* window; + + // Check if window is already open + window = window_bring_to_front_by_class(WC_TITLE_EDITOR); + if (window != NULL) + return; + + window = window_create_auto_pos(WW, 107, (uint32*)window_title_editor_events, WC_TITLE_EDITOR, WF_10 | WF_RESIZABLE); + window->widgets = window_title_editor_widgets; + window->enabled_widgets = + (1 << WIDX_TITLE_EDITOR_CLOSE) | + (1 << WIDX_TITLE_EDITOR_PRESETS_TAB) | + (1 << WIDX_TITLE_EDITOR_SAVES_TAB) | + (1 << WIDX_TITLE_EDITOR_SCRIPT_TAB) | + + (1 << WIDX_TITLE_EDITOR_PRESETS) | + (1 << WIDX_TITLE_EDITOR_PRESETS_DROPDOWN) | + (1 << WIDX_TITLE_EDITOR_DUPLICATE_BUTTON) | + (1 << WIDX_TITLE_EDITOR_DELETE_BUTTON) | + (1 << WIDX_TITLE_EDITOR_RENAME_BUTTON) | + + (1 << WIDX_TITLE_EDITOR_ADD) | + (1 << WIDX_TITLE_EDITOR_REMOVE) | + (1 << WIDX_TITLE_EDITOR_RENAME) | + (1 << WIDX_TITLE_EDITOR_LOAD) | + + (1 << WIDX_TITLE_EDITOR_INSERT) | + (1 << WIDX_TITLE_EDITOR_EDIT) | + (1 << WIDX_TITLE_EDITOR_DELETE) | + //(1 << WIDX_TITLE_EDITOR_RELOAD) | + (1 << WIDX_TITLE_EDITOR_SKIP_TO) | + (1 << WIDX_TITLE_EDITOR_MOVE_DOWN) | + (1 << WIDX_TITLE_EDITOR_MOVE_UP) | + + (1 << WIDX_TITLE_EDITOR_PLAY) | + (1 << WIDX_TITLE_EDITOR_STOP) | + (1 << WIDX_TITLE_EDITOR_REPLAY) | + (1 << WIDX_TITLE_EDITOR_SKIP); + + window_init_scroll_widgets(window); + window->list_information_type = 0; + + window->selected_tab = tab; + window->selected_list_item = -1; + _window_title_editor_highlighted_index = -1; + window->scrolls[0].v_top = 0; + window->scrolls[0].h_left = 0; + + window->min_width = WW; + window->min_height = WH; + window->max_width = 500; + window->max_height = 450; + +} + +void window_title_editor_close() { + rct_window *w, *command_editor_w, *load_save_w; + + window_get_register(w); + + // Close the related windows + command_editor_w = window_find_by_class(WC_TITLE_COMMAND_EDITOR); + load_save_w = window_find_by_class(WC_LOADSAVE); + if (command_editor_w) + window_close(command_editor_w); + if (load_save_w && gLoadSaveTitleSequenceSave) + window_close(load_save_w); +} + +static void window_title_editor_mouseup() +{ + short widgetIndex; + rct_window *w; + char path[MAX_PATH]; + char separator = platform_get_path_separator(); + int defaultPreset, playing, inTitle, i, commandEditorOpen; + window_widget_get_registers(w, widgetIndex); + + defaultPreset = (gCurrentTitleSequence < TITLE_SEQUENCE_DEFAULT_PRESETS); + playing = (gCurrentTitleSequence == gCurrentPreviewTitleSequence) && ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) == SCREEN_FLAGS_TITLE_DEMO); + inTitle = ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) == SCREEN_FLAGS_TITLE_DEMO); + commandEditorOpen = (window_find_by_class(WC_TITLE_COMMAND_EDITOR) != NULL); + switch (widgetIndex) { + case WIDX_TITLE_EDITOR_CLOSE: + window_close(w); + break; + case WIDX_TITLE_EDITOR_DUPLICATE_BUTTON: + commandEditorOpen *= 2; + if (!commandEditorOpen) + window_text_input_open(w, widgetIndex, 5239, 5406, 1170, (uint32)&gConfigTitleSequences.presets[gCurrentTitleSequence].name, 64); + break; + case WIDX_TITLE_EDITOR_DELETE_BUTTON: + defaultPreset *= 2; commandEditorOpen *= 2; + if (!defaultPreset && !commandEditorOpen) + title_sequence_delete_preset(gCurrentTitleSequence); + break; + case WIDX_TITLE_EDITOR_RENAME_BUTTON: + defaultPreset *= 2; commandEditorOpen *= 2; + if (!defaultPreset && !commandEditorOpen) + window_text_input_open(w, widgetIndex, 3348, 5406, 1170, (uint32)&gConfigTitleSequences.presets[gCurrentTitleSequence].name, 64); + break; + case WIDX_TITLE_EDITOR_ADD: + defaultPreset *= 2; playing *= 2; commandEditorOpen *= 2; + if (!defaultPreset && !playing && !commandEditorOpen) { + window_loadsave_open(LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME, NULL); + gLoadSaveTitleSequenceSave = true; + } + break; + case WIDX_TITLE_EDITOR_REMOVE: + defaultPreset *= 2; playing *= 2; commandEditorOpen *= 2; + if (!defaultPreset && !playing && !commandEditorOpen) { + if (w->selected_list_item != -1) { + title_sequence_remove_save(gCurrentTitleSequence, w->selected_list_item); + if (w->selected_list_item > 0) + w->selected_list_item--; + else if (w->selected_list_item > gConfigTitleSequences.presets[gCurrentTitleSequence].num_saves) + w->selected_list_item = gConfigTitleSequences.presets[gCurrentTitleSequence].num_saves - 1; + } + } + break; + case WIDX_TITLE_EDITOR_RENAME: + defaultPreset *= 2; playing *= 2; commandEditorOpen *= 2; + if (!defaultPreset && !playing && !commandEditorOpen) { + if (w->selected_list_item != -1) + window_text_input_open(w, widgetIndex, 5435, 5405, 1170, (uint32)gConfigTitleSequences.presets[gCurrentTitleSequence].saves[w->selected_list_item], TITLE_SEQUENCE_MAX_SAVE_LENGTH - 1); + } + break; + case WIDX_TITLE_EDITOR_LOAD: + if (w->selected_list_item != -1) { + if (gConfigTitleSequences.presets[gCurrentTitleSequence].path[0]) { + strcpy(path, gConfigTitleSequences.presets[gCurrentTitleSequence].path); + } + else { + platform_get_user_directory(path, "title sequences"); + strcat(path, gConfigTitleSequences.presets[gCurrentTitleSequence].name); + strncat(path, &separator, 1); + } + + strcat(path, gConfigTitleSequences.presets[gCurrentTitleSequence].saves[w->selected_list_item]); + game_load_save(path); + window_title_editor_open(1); + } + break; + case WIDX_TITLE_EDITOR_INSERT: + defaultPreset *= 2; playing *= 2; commandEditorOpen *= 2; + if (!defaultPreset && !playing && !commandEditorOpen) { + if (w->selected_list_item != -1) + window_title_command_editor_open(w->selected_list_item + 1, true); + else + window_title_command_editor_open(gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands, true); + } + break; + case WIDX_TITLE_EDITOR_EDIT: + defaultPreset *= 2; playing *= 2; commandEditorOpen *= 2; + if (!defaultPreset && !playing && !commandEditorOpen) { + if (w->selected_list_item != -1) + window_title_command_editor_open(w->selected_list_item, false); + } + break; + case WIDX_TITLE_EDITOR_DELETE: + defaultPreset *= 2; playing *= 2; commandEditorOpen *= 2; + if (!defaultPreset && !playing && !commandEditorOpen) { + if (w->selected_list_item != -1) { + title_sequence_delete_command(gCurrentTitleSequence, w->selected_list_item); + if (w->selected_list_item > 0) + w->selected_list_item--; + else if (w->selected_list_item > gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands) + w->selected_list_item = gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands - 1; + } + } + break; + /*case WIDX_TITLE_EDITOR_RELOAD: + playing *= 2; commandEditorOpen *= 2; + if (!playing && !commandEditorOpen) { + //title_sequence_open + } + break;*/ + case WIDX_TITLE_EDITOR_SKIP_TO: + if (playing && w->selected_list_item != -1) { + if (gTitleScriptCommand > w->selected_list_item) { + title_skip_from_beginning(); + } + if (gTitleScriptCommand != w->selected_list_item) { + for (i = gTitleScriptCommand + 1; i < gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands; i++) { + if (gConfigTitleSequences.presets[gCurrentTitleSequence].commands[i].command == TITLE_SCRIPT_LOAD || + gConfigTitleSequences.presets[gCurrentTitleSequence].commands[i].command == TITLE_SCRIPT_LOADMM) { + gTitleScriptSkipLoad = i; + } + if (i == w->selected_list_item) { + gTitleScriptSkipTo = i; + break; + } + } + } + } + break; + case WIDX_TITLE_EDITOR_MOVE_DOWN: + defaultPreset *= 2; playing *= 2; commandEditorOpen *= 2; + if (!defaultPreset && !playing && !commandEditorOpen) { + if (w->selected_list_item != -1 && w->selected_list_item < gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands - 1) { + title_sequence_move_down_command(gCurrentTitleSequence, w->selected_list_item); + w->selected_list_item++; + } + } + break; + case WIDX_TITLE_EDITOR_MOVE_UP: + defaultPreset *= 2; playing *= 2; commandEditorOpen *= 2; + if (!defaultPreset && !playing && !commandEditorOpen) { + if (w->selected_list_item != -1 && w->selected_list_item > 0) { + title_sequence_move_up_command(gCurrentTitleSequence, w->selected_list_item); + w->selected_list_item--; + } + } + break; + case WIDX_TITLE_EDITOR_REPLAY: + if (playing) { + title_refresh_sequence(); + } + break; + case WIDX_TITLE_EDITOR_STOP: + if (playing) { + gCurrentPreviewTitleSequence = 0; + title_refresh_sequence(); + } + break; + case WIDX_TITLE_EDITOR_PLAY: + if (gCurrentTitleSequence != gCurrentPreviewTitleSequence && inTitle) { + gCurrentPreviewTitleSequence = gCurrentTitleSequence; + title_refresh_sequence(); + } + break; + case WIDX_TITLE_EDITOR_SKIP: + if (playing) { + for (i = gTitleScriptCommand + 1; i < gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands; i++) { + if (gConfigTitleSequences.presets[gCurrentTitleSequence].commands[i].command == TITLE_SCRIPT_LOAD || + gConfigTitleSequences.presets[gCurrentTitleSequence].commands[i].command == TITLE_SCRIPT_LOADMM) { + gTitleScriptSkipLoad = i; + } + else if (gConfigTitleSequences.presets[gCurrentTitleSequence].commands[i].command == TITLE_SCRIPT_WAIT || + gConfigTitleSequences.presets[gCurrentTitleSequence].commands[i].command == TITLE_SCRIPT_END) { + gTitleScriptSkipTo = i; + break; + } + else if (gConfigTitleSequences.presets[gCurrentTitleSequence].commands[i].command == TITLE_SCRIPT_RESTART) { + gTitleScriptSkipLoad = -1; + gTitleScriptSkipTo = -1; + title_refresh_sequence(); + } + } + if (i == gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands && i - 1 > gTitleScriptCommand) { + gTitleScriptSkipTo = i - 1; + gTitleScriptSkipLoad = -1; + } + } + break; + } + if (defaultPreset == 2) + window_error_open(5400, STR_NONE); + else if (commandEditorOpen == 2) + window_error_open(5438, STR_NONE); + else if (playing == 2) + window_error_open(5398, 5399); +} + +static void window_title_editor_resize() +{ + rct_window *w; + + window_get_register(w); + + if (w->selected_tab == WINDOW_TITLE_EDITOR_TAB_PRESETS) { + w->min_width = WW; + w->min_height = 107; + w->max_width = WW; + w->max_height = 107; + + if (w->width < w->min_width) { + w->width = w->min_width; + gfx_invalidate_screen(); + } + if (w->height < w->min_height) { + w->height = w->min_height; + gfx_invalidate_screen(); + } + if (w->width > w->max_width) { + w->width = w->max_width; + gfx_invalidate_screen(); + } + if (w->height > w->max_height) { + w->height = w->max_height; + gfx_invalidate_screen(); + } + } + else { + w->min_width = WW; + w->min_height = WH; + w->max_width = 500; + w->max_height = 580; + + if (w->width < w->min_width) { + w->width = w->min_width; + window_invalidate(w); + } + if (w->height < w->min_height) { + w->height = w->min_height; + window_invalidate(w); + } + if (w->width > w->max_width) { + w->width = w->max_width; + window_invalidate(w); + } + if (w->height > w->max_height) { + w->height = w->max_height; + window_invalidate(w); + } + } +} + +static void window_title_editor_mousedown(int widgetIndex, rct_window* w, rct_widget* widget) +{ + short newSelectedTab; + int num_items, i; + + switch (widgetIndex) { + case WIDX_TITLE_EDITOR_PRESETS_TAB: + case WIDX_TITLE_EDITOR_SAVES_TAB: + case WIDX_TITLE_EDITOR_SCRIPT_TAB: + newSelectedTab = widgetIndex - WIDX_TITLE_EDITOR_PRESETS_TAB; + if (w->selected_tab == newSelectedTab) + break; + w->selected_tab = newSelectedTab; + w->selected_list_item = -1; + _window_title_editor_highlighted_index = -1; + w->scrolls[0].v_top = 0; + w->frame_no = 0; + window_event_resize_call(w); + window_invalidate(w); + break; + case WIDX_TITLE_EDITOR_PRESETS_DROPDOWN: + if (window_find_by_class(WC_TITLE_COMMAND_EDITOR) != NULL) { + window_error_open(5438, STR_NONE); + } + else { + num_items = gConfigTitleSequences.num_presets; + + widget--; + for (i = 0; i < num_items; i++) { + gDropdownItemsFormat[i] = 2777; + gDropdownItemsArgs[i] = (uint64)&gConfigTitleSequences.presets[i].name; + } + + window_dropdown_show_text_custom_width( + w->x + widget->left, + w->y + widget->top, + widget->bottom - widget->top + 1, + w->colours[1], + DROPDOWN_FLAG_STAY_OPEN, + num_items, + widget->right - widget->left - 3 + ); + + gDropdownItemsChecked = 1 << (gCurrentTitleSequence); + } + break; + } +} + +static void window_title_editor_dropdown() +{ + rct_window* w; + short widgetIndex, dropdownIndex; + + window_dropdown_get_registers(w, widgetIndex, dropdownIndex); + + if (dropdownIndex == -1) + return; + + switch (widgetIndex) { + case WIDX_TITLE_EDITOR_PRESETS_DROPDOWN: + gCurrentTitleSequence = dropdownIndex; + window_invalidate(w); + break; + } +} + +void window_title_editor_update(rct_window *w) +{ + w->frame_no++; + if (w->frame_no >= window_title_editor_tab_animation_loops[w->selected_tab]) + w->frame_no = 0; + + if (!widget_is_highlighted(w, WIDX_TITLE_EDITOR_LIST)) { + _window_title_editor_highlighted_index = -1; + widget_invalidate(w, WIDX_TITLE_EDITOR_LIST); + } + + widget_invalidate(w, WIDX_TITLE_EDITOR_PRESETS_TAB + w->selected_tab); +} + +void window_title_editor_scrollgetsize() +{ + int i, width, height; + uint16 lineCount; + rct_window *w; + + window_get_register(w); + + lineCount = 1; + if (w->selected_tab == WINDOW_TITLE_EDITOR_TAB_SAVES) + lineCount = gConfigTitleSequences.presets[gCurrentTitleSequence].num_saves; + else if (w->selected_tab == WINDOW_TITLE_EDITOR_TAB_SCRIPT) + lineCount = gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands; + + height = lineCount * ROW_HEIGHT; + i = height - window_title_editor_widgets[WIDX_TITLE_EDITOR_LIST].bottom + window_title_editor_widgets[WIDX_TITLE_EDITOR_LIST].top + 21; + if (i < 0) + i = 0; + if (i < w->scrolls[0].v_top) { + w->scrolls[0].v_top = i; + window_invalidate(w); + } + + width = SCROLL_WIDTH; + window_scrollsize_set_registers(width, height); +} + +void window_title_editor_scrollmousedown() { + int index; + short x, y, scrollIndex; + rct_window *w; + + window_scrollmouse_get_registers(w, scrollIndex, x, y); + + index = y / ROW_HEIGHT; + w->selected_list_item = -1; + switch (w->selected_tab) { + case WINDOW_TITLE_EDITOR_TAB_SAVES: + if (index < gConfigTitleSequences.presets[gCurrentTitleSequence].num_saves) { + w->selected_list_item = index; + widget_invalidate(w, WIDX_TITLE_EDITOR_LIST); + } + break; + case WINDOW_TITLE_EDITOR_TAB_SCRIPT: + if (index < gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands) { + w->selected_list_item = index; + widget_invalidate(w, WIDX_TITLE_EDITOR_LIST); + } + break; + } +} + +void window_title_editor_scrollmouseover() { + int index; + short x, y, scrollIndex; + rct_window *w; + sint16 oldHighlightedIndex; + + window_scrollmouse_get_registers(w, scrollIndex, x, y); + + index = y / ROW_HEIGHT; + switch (w->selected_tab) { + oldHighlightedIndex = _window_title_editor_highlighted_index; + _window_title_editor_highlighted_index = -1; + case WINDOW_TITLE_EDITOR_TAB_SAVES: + if (index < gConfigTitleSequences.presets[gCurrentTitleSequence].num_saves) + _window_title_editor_highlighted_index = (sint16)index; + break; + case WINDOW_TITLE_EDITOR_TAB_SCRIPT: + if (index < gConfigTitleSequences.presets[gCurrentTitleSequence].num_commands) + _window_title_editor_highlighted_index = (sint16)index; + break; + } + // This check is disabled since for some reason it creates a problem with highlighting index 1 + //if (oldHighlightedIndex != _window_title_editor_highlighted_index) { + widget_invalidate(w, WIDX_TITLE_EDITOR_LIST); + //} +} + +static void window_title_editor_textinput() +{ + rct_window *w; + short widgetIndex; + uint8 result; + char *text; + + window_textinput_get_registers(w, widgetIndex, result, text); + + if (!result || text[0] == 0) + return; + + switch (widgetIndex) { + case WIDX_TITLE_EDITOR_DUPLICATE_BUTTON: + case WIDX_TITLE_EDITOR_RENAME_BUTTON: + if (filename_valid_characters(text)) { + if (!title_sequence_name_exists(text)) { + if (widgetIndex == WIDX_TITLE_EDITOR_DUPLICATE_BUTTON) { + title_sequence_duplicate_preset(gCurrentTitleSequence, text); + } + else { + title_sequence_rename_preset(gCurrentTitleSequence, text); + } + config_save_default(); + window_invalidate(w); + } + else { + window_error_open(5404, STR_NONE); + } + } + else { + window_error_open(5243, STR_NONE); + } + break; + case WIDX_TITLE_EDITOR_RENAME: + if (filename_valid_characters(text)) { + if (!title_sequence_save_exists(gCurrentTitleSequence, text)) { + title_sequence_rename_save(gCurrentTitleSequence, w->selected_list_item, text); + title_sequence_save_preset_script(gCurrentTitleSequence); + window_invalidate(w); + } + else { + window_error_open(5404, STR_NONE); + } + } + else { + window_error_open(5243, STR_NONE); + } + break; + } +} + +void window_title_editor_tooltip() +{ + RCT2_GLOBAL(0x013CE952, uint16) = STR_LIST; +} + +void window_title_editor_invalidate() +{ + rct_window *w; + + window_get_register(w); + colour_scheme_update(w); + + int pressed_widgets = w->pressed_widgets & 0xFFFFFF8F; + uint8 widgetIndex = w->selected_tab + 4; + + w->pressed_widgets = pressed_widgets | (1 << widgetIndex); + + window_title_editor_widgets[WIDX_TITLE_EDITOR_LIST].type = WWT_EMPTY; + + window_title_editor_widgets[WIDX_TITLE_EDITOR_PRESETS].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_PRESETS_DROPDOWN].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_DUPLICATE_BUTTON].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_DELETE_BUTTON].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_RENAME_BUTTON].type = WWT_EMPTY; + + window_title_editor_widgets[WIDX_TITLE_EDITOR_ADD].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_REMOVE].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_RENAME].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_LOAD].type = WWT_EMPTY; + + window_title_editor_widgets[WIDX_TITLE_EDITOR_INSERT].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_EDIT].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_DELETE].type = WWT_EMPTY; + //window_title_editor_widgets[WIDX_TITLE_EDITOR_RELOAD].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_SKIP_TO].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_MOVE_UP].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_MOVE_DOWN].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_PLAY].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_STOP].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_REPLAY].type = WWT_EMPTY; + window_title_editor_widgets[WIDX_TITLE_EDITOR_SKIP].type = WWT_EMPTY; + + switch (w->selected_tab) { + case WINDOW_TITLE_EDITOR_TAB_PRESETS: + window_title_editor_widgets[WIDX_TITLE_EDITOR_PRESETS].type = WWT_DROPDOWN; + window_title_editor_widgets[WIDX_TITLE_EDITOR_PRESETS_DROPDOWN].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_DUPLICATE_BUTTON].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_DELETE_BUTTON].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_RENAME_BUTTON].type = WWT_DROPDOWN_BUTTON; + break; + case WINDOW_TITLE_EDITOR_TAB_SAVES: + window_title_editor_widgets[WIDX_TITLE_EDITOR_LIST].type = WWT_SCROLL; + window_title_editor_widgets[WIDX_TITLE_EDITOR_ADD].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_REMOVE].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_RENAME].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_LOAD].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_PLAY].type = WWT_IMGBTN; + window_title_editor_widgets[WIDX_TITLE_EDITOR_STOP].type = WWT_IMGBTN; + window_title_editor_widgets[WIDX_TITLE_EDITOR_REPLAY].type = WWT_IMGBTN; + window_title_editor_widgets[WIDX_TITLE_EDITOR_SKIP].type = WWT_IMGBTN; + break; + case WINDOW_TITLE_EDITOR_TAB_SCRIPT: + window_title_editor_widgets[WIDX_TITLE_EDITOR_LIST].type = WWT_SCROLL; + window_title_editor_widgets[WIDX_TITLE_EDITOR_INSERT].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_EDIT].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_DELETE].type = WWT_DROPDOWN_BUTTON; + //window_title_editor_widgets[WIDX_TITLE_EDITOR_RELOAD].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_SKIP_TO].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_MOVE_UP].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_MOVE_DOWN].type = WWT_DROPDOWN_BUTTON; + window_title_editor_widgets[WIDX_TITLE_EDITOR_PLAY].type = WWT_IMGBTN; + window_title_editor_widgets[WIDX_TITLE_EDITOR_STOP].type = WWT_IMGBTN; + window_title_editor_widgets[WIDX_TITLE_EDITOR_REPLAY].type = WWT_IMGBTN; + window_title_editor_widgets[WIDX_TITLE_EDITOR_SKIP].type = WWT_IMGBTN; + break; + } + + window_title_editor_widgets[WIDX_TITLE_EDITOR_BACKGROUND].right = w->width - 1; + window_title_editor_widgets[WIDX_TITLE_EDITOR_BACKGROUND].bottom = w->height - 1; + window_title_editor_widgets[WIDX_TITLE_EDITOR_TAB_CONTENT_PANEL].right = w->width - 1; + window_title_editor_widgets[WIDX_TITLE_EDITOR_TAB_CONTENT_PANEL].bottom = w->height - 1; + window_title_editor_widgets[WIDX_TITLE_EDITOR_TITLE].right = w->width - 2; + window_title_editor_widgets[WIDX_TITLE_EDITOR_CLOSE].left = w->width - 2 - 0x0B; + window_title_editor_widgets[WIDX_TITLE_EDITOR_CLOSE].right = w->width - 2 - 0x0B + 0x0A; + window_title_editor_widgets[WIDX_TITLE_EDITOR_LIST].right = w->width - 4; + window_title_editor_widgets[WIDX_TITLE_EDITOR_LIST].bottom = w->height - 16; + + window_title_editor_widgets[WIDX_TITLE_EDITOR_REPLAY].top = w->height - 32; + window_title_editor_widgets[WIDX_TITLE_EDITOR_REPLAY].bottom = w->height - 16; + window_title_editor_widgets[WIDX_TITLE_EDITOR_STOP].top = w->height - 32; + window_title_editor_widgets[WIDX_TITLE_EDITOR_STOP].bottom = w->height - 16; + window_title_editor_widgets[WIDX_TITLE_EDITOR_PLAY].top = w->height - 32; + window_title_editor_widgets[WIDX_TITLE_EDITOR_PLAY].bottom = w->height - 16; + window_title_editor_widgets[WIDX_TITLE_EDITOR_SKIP].top = w->height - 32; + window_title_editor_widgets[WIDX_TITLE_EDITOR_SKIP].bottom = w->height - 16; + + int defaultPreset, playing, inTitle; + + defaultPreset = (gCurrentTitleSequence < TITLE_SEQUENCE_DEFAULT_PRESETS); + playing = (gCurrentTitleSequence == gCurrentPreviewTitleSequence) && ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) == SCREEN_FLAGS_TITLE_DEMO); + inTitle = ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) == SCREEN_FLAGS_TITLE_DEMO); + + if (!inTitle) + w->disabled_widgets |= (1 << WIDX_TITLE_EDITOR_PLAY); + else + w->disabled_widgets &= ~(1 << WIDX_TITLE_EDITOR_PLAY); + if (!playing) + w->disabled_widgets |= (1 << WIDX_TITLE_EDITOR_REPLAY) | (1 << WIDX_TITLE_EDITOR_STOP) | (1 << WIDX_TITLE_EDITOR_SKIP) | (1 << WIDX_TITLE_EDITOR_SKIP_TO); + else + w->disabled_widgets &= ~((1 << WIDX_TITLE_EDITOR_REPLAY) | (1 << WIDX_TITLE_EDITOR_STOP) | (1 << WIDX_TITLE_EDITOR_SKIP) | (1 << WIDX_TITLE_EDITOR_SKIP_TO)); +} + +void window_title_editor_paint() { + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + // Widgets + window_draw_widgets(w, dpi); + window_title_editor_draw_tab_images(dpi, w); + + // Draw strings + switch (w->selected_tab) { + case WINDOW_TITLE_EDITOR_TAB_PRESETS: + + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32) = (uint32)&gConfigTitleSequences.presets[gCurrentTitleSequence].name; + gfx_draw_string_left(dpi, 5304, NULL, w->colours[1], w->x + 10, w->y + window_title_editor_widgets[WIDX_TITLE_EDITOR_PRESETS].top + 1); + gfx_draw_string_left_clipped( + dpi, + 1170, + (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, + w->colours[1], + w->x + window_title_editor_widgets[WIDX_TITLE_EDITOR_PRESETS].left + 1, + w->y + window_title_editor_widgets[WIDX_TITLE_EDITOR_PRESETS].top, + w->x + window_title_editor_widgets[WIDX_TITLE_EDITOR_PRESETS_DROPDOWN].left - window_title_editor_widgets[WIDX_TITLE_EDITOR_PRESETS].left - 4 + ); + + break; + case WINDOW_TITLE_EDITOR_TAB_SAVES: + + break; + case WINDOW_TITLE_EDITOR_TAB_SCRIPT: + + break; + } +} + +void window_title_editor_scrollpaint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + char buffer[256]; + bool selected, hover, error, inTitle; + int y, x, x2, width; + + window_paint_get_registers(w, dpi); + + gfx_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width - 1, dpi->y + dpi->height - 1, ((char*)0x0141FC48)[w->colours[1] * 8]); + + title_sequence *title = &gConfigTitleSequences.presets[gCurrentTitleSequence]; + + inTitle = ((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TITLE_DEMO) == SCREEN_FLAGS_TITLE_DEMO); + y = 0; x = 0; x2 = 0; width = 0; + width = w->widgets[WIDX_TITLE_EDITOR_LIST].right - w->widgets[WIDX_TITLE_EDITOR_LIST].left; + if (w->selected_tab == WINDOW_TITLE_EDITOR_TAB_SAVES) { + + for (int i = 0; i < title->num_saves; i++, y += ROW_HEIGHT) { + selected = false; + hover = false; + if (i == w->selected_list_item) { + selected = true; + gfx_fill_rect(dpi, x, y, x + SCROLL_WIDTH + 100, y + ROW_HEIGHT - 1, RCT2_GLOBAL(0x0141FC46 + (w->colours[1] * 8), uint8)); + } + else if (i == _window_title_editor_highlighted_index || (i == gTitleScriptSave && inTitle && gCurrentTitleSequence == gCurrentPreviewTitleSequence)) { + hover = true; + gfx_fill_rect(dpi, x, y, x + SCROLL_WIDTH + 100, y + ROW_HEIGHT - 1, RCT2_GLOBAL(0x0141FC47 + (w->colours[1] * 8), uint8)); + } + else if (i & 1) { + gfx_fill_rect(dpi, x, y, x + SCROLL_WIDTH + 100, y + ROW_HEIGHT - 1, RCT2_GLOBAL(0x0141FC4A + (w->colours[1] * 8), uint8) | 0x1000000); + } + + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32) = (uint32)&title->saves[i]; + if (selected || hover) { + format_string(buffer, 1170, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS); + } + else { + format_string(buffer + 1, 1170, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS); + buffer[0] = FORMAT_BLACK; + } + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32) = (uint32)&buffer; + gfx_draw_string_left(dpi, 1170, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, w->colours[1], x + 5, y); + } + } + else if (w->selected_tab == WINDOW_TITLE_EDITOR_TAB_SCRIPT) { + + x2 = 92; + for (int i = 0; i < title->num_commands; i++, y += ROW_HEIGHT) { + title_command *command = &title->commands[i]; + selected = false; + hover = false; + error = false; + if (i == w->selected_list_item) { + selected = true; + gfx_fill_rect(dpi, x, y, x + SCROLL_WIDTH + 100, y + ROW_HEIGHT - 1, RCT2_GLOBAL(0x0141FC46 + (w->colours[1] * 8), uint8)); + } + else if (i == (int)_window_title_editor_highlighted_index || (i == gTitleScriptCommand && inTitle && gCurrentTitleSequence == gCurrentPreviewTitleSequence)) { + hover = true; + gfx_fill_rect(dpi, x, y, x + SCROLL_WIDTH + 100, y + ROW_HEIGHT - 1, RCT2_GLOBAL(0x0141FC47 + (w->colours[1] * 8), uint8)); + } + else if (i & 1) { + gfx_fill_rect(dpi, x, y, x + SCROLL_WIDTH + 100, y + ROW_HEIGHT - 1, RCT2_GLOBAL(0x0141FC4A + (w->colours[1] * 8), uint8) | 0x1000000); + } + + rct_string_id commandName; + switch (command->command) { + case TITLE_SCRIPT_LOAD: + commandName = 5415; + if (command->saveIndex == 0xFF) { + commandName = 5416; + error = true; + } + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32) = (uint32)&title->saves[command->saveIndex]; + break; + case TITLE_SCRIPT_LOADMM: + commandName = 5414; + break; + case TITLE_SCRIPT_LOCATION: + commandName = 5418; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint16) = command->x; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 2, uint16) = command->y; + break; + case TITLE_SCRIPT_ROTATE: + commandName = 5420; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint16) = command->rotations; + break; + case TITLE_SCRIPT_ZOOM: + commandName = 5422; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint16) = command->zoom; + break; + case TITLE_SCRIPT_WAIT: + commandName = 5424; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint16) = command->seconds; + break; + case TITLE_SCRIPT_RESTART: + commandName = 5425; + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint16) = command->zoom; + break; + case TITLE_SCRIPT_END: + commandName = 5426; + break; + } + + if ((selected || hover) && !error) { + format_string(buffer, commandName, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS); + } + else { + format_string(buffer + 1, commandName, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS); + buffer[0] = (error ? ((selected || hover) ? FORMAT_LIGHTPINK : FORMAT_RED) : FORMAT_BLACK); + } + RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32) = (uint32)&buffer; + gfx_draw_string_left(dpi, 1170, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, w->colours[1], x + 5, y); + } + } +} \ No newline at end of file