static void openrct2_copy_files_over(const utf8 *originalDirectory, const utf8 *newDirectory, const utf8 *extension) { utf8 *ch, filter[MAX_PATH], oldPath[MAX_PATH], newPath[MAX_PATH]; int fileEnumHandle; file_info fileInfo; if (!platform_ensure_directory_exists(newDirectory)) { log_error("Could not create directory %s.", newDirectory); return; } // Create filter path safe_strncpy(filter, originalDirectory, MAX_PATH); ch = strchr(filter, '*'); if (ch != NULL) *ch = 0; strcat(filter, "*"); strcat(filter, extension); fileEnumHandle = platform_enumerate_files_begin(filter); while (platform_enumerate_files_next(fileEnumHandle, &fileInfo)) { safe_strncpy(newPath, newDirectory, MAX_PATH); strcat(newPath, fileInfo.path); safe_strncpy(oldPath, originalDirectory, MAX_PATH); ch = strchr(oldPath, '*'); if (ch != NULL) *ch = 0; strcat(oldPath, fileInfo.path); if (!platform_file_exists(newPath)) platform_file_copy(oldPath, newPath, false); } platform_enumerate_files_end(fileEnumHandle); fileEnumHandle = platform_enumerate_directories_begin(originalDirectory); while (platform_enumerate_directories_next(fileEnumHandle, filter)) { safe_strncpy(newPath, newDirectory, MAX_PATH); strcat(newPath, filter); safe_strncpy(oldPath, originalDirectory, MAX_PATH); ch = strchr(oldPath, '*'); if (ch != NULL) *ch = 0; strcat(oldPath, filter); if (!platform_ensure_directory_exists(newPath)) { log_error("Could not create directory %s.", newPath); return; } openrct2_copy_files_over(oldPath, newPath, extension); } platform_enumerate_directories_end(fileEnumHandle); }
static void window_install_track_design(rct_window* w) { utf8 destPath[MAX_PATH]; platform_get_user_directory(destPath, "track", sizeof(destPath)); if (!platform_ensure_directory_exists(destPath)) { log_error("Unable to create directory '%s'", destPath); context_show_error(STR_CANT_SAVE_TRACK_DESIGN, STR_NONE); return; } safe_strcat_path(destPath, _trackName.c_str(), sizeof(destPath)); path_append_extension(destPath, ".td6", sizeof(destPath)); if (platform_file_exists(destPath)) { log_info("%s already exists, prompting user for a different track design name", destPath); context_show_error(STR_UNABLE_TO_INSTALL_THIS_TRACK_DESIGN, STR_NONE); window_text_input_raw_open( w, WIDX_INSTALL, STR_SELECT_NEW_NAME_FOR_TRACK_DESIGN, STR_AN_EXISTING_TRACK_DESIGN_ALREADY_HAS_THIS_NAME, _trackName.c_str(), 255); } else { if (track_repository_install(_trackPath.c_str())) { window_close(w); } else { context_show_error(STR_CANT_SAVE_TRACK_DESIGN, STR_NONE); } } }
static int screenshot_get_next_path(char *path, char *extension) { char *screenshotPath = osinterface_get_orct2_homesubfolder("screenshot"); if (!platform_ensure_directory_exists(screenshotPath)) { free(screenshotPath); fprintf(stderr, "Unable to save screenshots in OpenRCT2 screenshot directory.\n"); return -1; } int i; for (i = 1; i < 1000; i++) { RCT2_GLOBAL(0x013CE952, uint16) = i; // Glue together path and filename sprintf(path, "%s%cSCR%d%s", screenshotPath, osinterface_get_path_separator(), i, extension); if (!platform_file_exists(path)) { return i; } } free(screenshotPath); return -1; }
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); safe_strncpy(gConfigTitleSequences.presets[preset].name, name, TITLE_SEQUENCE_NAME_SIZE); 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); gCurrentTitleSequence = preset; } }
IPlatformEnvironment * SetupEnvironment() { utf8 userPath[MAX_PATH]; platform_resolve_openrct_data_path(); platform_resolve_user_data_path(); platform_get_user_directory(userPath, NULL, sizeof(userPath)); if (!platform_ensure_directory_exists(userPath)) { Console::Error::WriteLine("Could not create user directory (do you have write access to your documents folder?)"); return nullptr; } openrct2_set_exe_path(); config_set_defaults(); if (!config_open_default()) { if (!config_find_or_browse_install_directory()) { gConfigGeneral.last_run_version = String::Duplicate(OPENRCT2_VERSION); config_save_default(); utf8 path[MAX_PATH]; config_get_default_path(path, sizeof(path)); Console::Error::WriteLine("An RCT2 install directory must be specified! Please edit \"game_path\" in %s.", path); return nullptr; } config_save_default(); } if (!rct2_init_directories()) { return nullptr; } if (!rct2_startup_checks()) { return nullptr; } utf8 path[260]; std::string basePaths[4]; basePaths[(size_t)DIRBASE::RCT1] = String::ToStd(gConfigGeneral.rct1_path); basePaths[(size_t)DIRBASE::RCT2] = String::ToStd(gConfigGeneral.rct2_path); platform_get_openrct_data_path(path, sizeof(path)); basePaths[(size_t)DIRBASE::OPENRCT2] = std::string(path); platform_get_user_directory(path, nullptr, sizeof(path)); basePaths[(size_t)DIRBASE::USER] = std::string(path); IPlatformEnvironment * env = CreatePlatformEnvironment(basePaths); return env; }
/** * Default directory fallback is: * - (command line argument) * - <platform dependent> */ void platform_resolve_user_data_path() { if (gCustomUserDataPath[0] != 0) { if (!platform_ensure_directory_exists(gCustomUserDataPath)) { log_error("Failed to create directory \"%s\", make sure you have permissions.", gCustomUserDataPath); return; } char *path; if ((path = realpath(gCustomUserDataPath, NULL)) == NULL) { log_error("Could not resolve path \"%s\"", gCustomUserDataPath); return; } safe_strcpy(_userDataDirectoryPath, path, MAX_PATH); free(path); // Ensure path ends with separator path_end_with_separator(_userDataDirectoryPath, MAX_PATH); log_verbose("User data path resolved to: %s", _userDataDirectoryPath); if (!platform_directory_exists(_userDataDirectoryPath)) { log_error("Custom user data directory %s does not exist", _userDataDirectoryPath); } return; } char buffer[MAX_PATH]; log_verbose("buffer = '%s'", buffer); const char *homedir = getpwuid(getuid())->pw_dir; platform_posix_sub_user_data_path(buffer, MAX_PATH, homedir); log_verbose("OpenRCT2 user data directory = '%s'", buffer); sint32 len = strnlen(buffer, MAX_PATH); wchar_t *w_buffer = regular_to_wchar(buffer); w_buffer[len] = '\0'; utf8 *path = widechar_to_utf8(w_buffer); free(w_buffer); safe_strcpy(_userDataDirectoryPath, path, MAX_PATH); free(path); log_verbose("User data path resolved to: %s", _userDataDirectoryPath); }
int cmdline_for_sprite(const char **argv, int argc) { if (argc == 0) return -1; if (_strcmpi(argv[0], "details") == 0) { if (argc < 2) { fprintf(stderr, "usage: sprite details <spritefile> [idx]\n"); return -1; } else if (argc == 2) { const char *spriteFilePath = argv[1]; if (!sprite_file_open(spriteFilePath)) { fprintf(stderr, "Unable to open input sprite file.\n"); return -1; } printf("sprites: %d\n", spriteFileHeader.num_entries); printf("data size: %d\n", spriteFileHeader.total_size); sprite_file_close(); return 1; } else { const char *spriteFilePath = argv[1]; int spriteIndex = atoi(argv[2]); if (!sprite_file_open(spriteFilePath)) { fprintf(stderr, "Unable to open input sprite file.\n"); return -1; } if (spriteIndex < 0 || spriteIndex >= (int)spriteFileHeader.num_entries) { sprite_file_close(); fprintf(stderr, "Sprite #%d does not exist in sprite file.\n", spriteIndex); return -1; } rct_g1_element *g1 = &spriteFileEntries[spriteIndex]; printf("width: %d\n", g1->width); printf("height: %d\n", g1->height); printf("x offset: %d\n", g1->x_offset); printf("y offset: %d\n", g1->y_offset); printf("data offset: 0x%X\n", g1->offset); sprite_file_close(); return 1; } } else if (_strcmpi(argv[0], "export") == 0) { if (argc < 4) { fprintf(stderr, "usage: sprite export <spritefile> <idx> <output>\n"); return -1; } const char *spriteFilePath = argv[1]; int spriteIndex = atoi(argv[2]); const char *outputPath = argv[3]; if (!sprite_file_open(spriteFilePath)) { fprintf(stderr, "Unable to open input sprite file.\n"); return -1; } if (spriteIndex < 0 || spriteIndex >= (int)spriteFileHeader.num_entries) { fprintf(stderr, "Sprite #%d does not exist in sprite file.\n", spriteIndex); return -1; } if (!sprite_file_export(spriteIndex, outputPath)) { fprintf(stderr, "Could not export\n"); sprite_file_close(); return -1; } sprite_file_close(); return 1; } else if (_strcmpi(argv[0], "exportall") == 0) { if (argc < 3) { fprintf(stderr, "usage: sprite exportall <spritefile> <output directory>\n"); return -1; } const char *spriteFilePath = argv[1]; char outputPath[_MAX_PATH]; if (!sprite_file_open(spriteFilePath)) { fprintf(stderr, "Unable to open input sprite file.\n"); return -1; } if (!platform_ensure_directory_exists(argv[2])){ fprintf(stderr, "Unable to create directory.\n"); return -1; } int maxIndex = (int)spriteFileHeader.num_entries; int numbers = (int)floor(log(maxIndex)); strncpy(outputPath, argv[2], _MAX_PATH); int pathLen = strlen(outputPath); if (pathLen >= _MAX_PATH - numbers - 5){ fprintf(stderr, "Path too long.\n"); return -1; } for (int x = 0; x < numbers; x++){ outputPath[pathLen + x] = '0'; } strncpy(outputPath + pathLen + numbers, ".png", _MAX_PATH); for (int spriteIndex = 0; spriteIndex < maxIndex; spriteIndex++){ if (spriteIndex % 100 == 99){ // Status indicator printf("\r%d / %d, %d%%", spriteIndex, maxIndex, spriteIndex / maxIndex); } // Add to the index at the end of the file name char *counter = outputPath + pathLen + numbers - 1; (*counter)++; while (*counter > '9'){ *counter = '0'; counter--; (*counter)++; } if (!sprite_file_export(spriteIndex, outputPath)) { fprintf(stderr, "Could not export\n"); sprite_file_close(); return -1; } } sprite_file_close(); return 1; } else if (_strcmpi(argv[0], "create") == 0) { if (argc < 2) { fprintf(stderr, "usage: sprite create <spritefile>\n"); return -1; } const char *spriteFilePath = argv[1]; spriteFileHeader.num_entries = 0; spriteFileHeader.total_size = 0; sprite_file_save(spriteFilePath); sprite_file_close(); return 1; } else if (_strcmpi(argv[0], "append") == 0) { if (argc < 3) { fprintf(stderr, "usage: sprite append <spritefile> <input>\n"); return -1; } const char *spriteFilePath = argv[1]; const char *imagePath = argv[2]; rct_g1_element spriteElement; uint8 *buffer; int bufferLength; if (!sprite_file_import(imagePath, &spriteElement, &buffer, &bufferLength, sprite_mode)) return -1; if (!sprite_file_open(spriteFilePath)) { fprintf(stderr, "Unable to open input sprite file.\n"); return -1; } spriteFileHeader.num_entries++; spriteFileHeader.total_size += bufferLength; spriteFileEntries = realloc(spriteFileEntries, spriteFileHeader.num_entries * sizeof(rct_g1_element)); sprite_entries_make_relative(); spriteFileData = realloc(spriteFileData, spriteFileHeader.total_size); sprite_entries_make_absolute(); spriteFileEntries[spriteFileHeader.num_entries - 1] = spriteElement; memcpy(spriteFileData + (spriteFileHeader.total_size - bufferLength), buffer, bufferLength); spriteFileEntries[spriteFileHeader.num_entries - 1].offset = spriteFileData + (spriteFileHeader.total_size - bufferLength); free(buffer); if (!sprite_file_save(spriteFilePath)) return -1; return 1; } else if (_strcmpi(argv[0], "build") == 0) { if (argc < 3) { fprintf(stderr, "usage: sprite build <spritefile> <resourcedir> [silent]\n"); return -1; } const char *spriteFilePath = argv[1]; const char *resourcePath = argv[2]; char imagePath[MAX_PATH]; int resourceLength = strlen(resourcePath); bool silent = (argc >= 4 && strcmp(argv[3], "silent") == 0); bool fileExists = true; FILE *file; spriteFileHeader.num_entries = 0; spriteFileHeader.total_size = 0; sprite_file_save(spriteFilePath); fprintf(stderr, "Building: %s\n", spriteFilePath); int i = 0; do { // Create image path strcpy(imagePath, resourcePath); if (resourcePath[resourceLength - 1] == '/' || resourcePath[resourceLength - 1] == '\\') imagePath[resourceLength - 1] = 0; sprintf(imagePath, "%s%c%d.png", imagePath, platform_get_path_separator(), i); file = fopen(imagePath, "r"); if (file != NULL) { fclose(file); rct_g1_element spriteElement; uint8 *buffer; int bufferLength; if (!sprite_file_import(imagePath, &spriteElement, &buffer, &bufferLength, sprite_mode)) { fprintf(stderr, "Could not import image file: %s\nCanceling\n", imagePath); return -1; } if (!sprite_file_open(spriteFilePath)) { fprintf(stderr, "Unable to open sprite file: %s\nCanceling\n", spriteFilePath); return -1; } spriteFileHeader.num_entries++; spriteFileHeader.total_size += bufferLength; spriteFileEntries = realloc(spriteFileEntries, spriteFileHeader.num_entries * sizeof(rct_g1_element)); sprite_entries_make_relative(); spriteFileData = realloc(spriteFileData, spriteFileHeader.total_size); sprite_entries_make_absolute(); spriteFileEntries[spriteFileHeader.num_entries - 1] = spriteElement; memcpy(spriteFileData + (spriteFileHeader.total_size - bufferLength), buffer, bufferLength); spriteFileEntries[spriteFileHeader.num_entries - 1].offset = spriteFileData + (spriteFileHeader.total_size - bufferLength); free(buffer); if (!sprite_file_save(spriteFilePath)) { fprintf(stderr, "Could not save sprite file: %s\nCanceling\n", imagePath); return -1; } if (!silent) fprintf(stderr, "Added: %s\n", imagePath); } i++; } while (file != NULL); fprintf(stderr, "Finished\n", imagePath); return 1; } else { fprintf(stderr, "Unknown sprite command."); return 1; } }
bool openrct2_initialise() { utf8 userPath[MAX_PATH]; platform_resolve_user_data_path(); platform_get_user_directory(userPath, NULL); if (!platform_ensure_directory_exists(userPath)) { log_fatal("Could not create user directory (do you have write access to your documents folder?)"); return false; } if (!openrct2_setup_rct2_segment()) { log_fatal("Unable to load RCT2 data sector"); return false; } openrct2_set_exe_path(); config_set_defaults(); if (!config_open_default()) { if (!config_find_or_browse_install_directory()) { log_fatal("An RCT2 install directory must be specified!"); return false; } } gOpenRCT2ShowChangelog = true; if (gConfigGeneral.last_run_version != NULL && (strcmp(gConfigGeneral.last_run_version, OPENRCT2_VERSION) == 0)) gOpenRCT2ShowChangelog = false; gConfigGeneral.last_run_version = OPENRCT2_VERSION; config_save_default(); // TODO add configuration option to allow multiple instances // if (!gOpenRCT2Headless && !platform_lock_single_instance()) { // log_fatal("OpenRCT2 is already running."); // return false; // } get_system_info(); if (!gOpenRCT2Headless) { audio_init(); audio_get_devices(); } if (!language_open(gConfigGeneral.language)) { log_fatal("Failed to open language, exiting."); return false; } http_init(); themes_set_default(); themes_load_presets(); title_sequences_set_default(); title_sequences_load_presets(); openrct2_setup_rct2_hooks(); if (!rct2_init()) return false; chat_init(); openrct2_copy_original_user_files_over(); // TODO move to audio initialise function if (str_is_null_or_empty(gConfigSound.device)) { Mixer_Init(NULL); RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32) = 0; } else { Mixer_Init(gConfigSound.device); for (int i = 0; i < gAudioDeviceCount; i++) { if (strcmp(gAudioDevices[i].name, gConfigSound.device) == 0) { RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_SOUND_DEVICE, uint32) = i; } } } return true; }
bool EnsureThemeDirectoryExists() { utf8 path[MAX_PATH]; GetThemePath(path, sizeof(path)); return platform_ensure_directory_exists(path); }
rct_window *window_loadsave_open(int type, char *defaultName) { gLoadSaveCallback = NULL; gLoadSaveTitleSequenceSave = false; char path[MAX_PATH], *ch; int includeNewItem; rct_window* w; _type = type; _defaultName[0] = '\0'; if (!str_is_null_or_empty(defaultName)) { safe_strcpy(_defaultName, defaultName, sizeof(_defaultName)); } w = window_bring_to_front_by_class(WC_LOADSAVE); if (w == NULL) { w = window_create_centred(WW, WH, &window_loadsave_events, WC_LOADSAVE, WF_STICK_TO_FRONT); w->widgets = window_loadsave_widgets; w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_UP) | (1 << WIDX_NEW) | (1 << WIDX_SORT_NAME) | (1 << WIDX_SORT_DATE) | (1 << WIDX_BROWSE); w->colours[0] = 7; w->colours[1] = 7; w->colours[2] = 7; } _loadsaveType = type; switch (type & 0x0F) { case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME): w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_LOAD_GAME; break; case (LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME) : w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_SAVE_GAME; break; case (LOADSAVETYPE_LOAD | LOADSAVETYPE_LANDSCAPE) : w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_LOAD_LANDSCAPE; break; case (LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE) : w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_SAVE_LANDSCAPE; break; case (LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO) : w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_SAVE_SCENARIO; break; case (LOADSAVETYPE_LOAD | LOADSAVETYPE_TRACK) : w->widgets[WIDX_TITLE].image = STR_FILE_DIALOG_TITLE_INSTALL_NEW_TRACK_DESIGN; break; default: log_error("Unsupported load / save type: %d", type & 0x0F); return NULL; } w->no_list_items = 0; w->selected_list_item = -1; includeNewItem = (type & 0x01) == LOADSAVETYPE_SAVE; switch (type & 0x0E) { case LOADSAVETYPE_GAME: platform_get_user_directory(path, "save"); if (!platform_ensure_directory_exists(path)) { log_error("Unable to create save directory."); window_close(w); return NULL; } window_loadsave_populate_list(w, includeNewItem, path, ".sv6"); break; case LOADSAVETYPE_LANDSCAPE: platform_get_user_directory(path, "landscape"); if (!platform_ensure_directory_exists(path)) { log_error("Unable to create landscapes directory."); window_close(w); return NULL; } window_loadsave_populate_list(w, includeNewItem, path, ".sc6"); break; case LOADSAVETYPE_SCENARIO: platform_get_user_directory(path, "scenario"); if (!platform_ensure_directory_exists(path)) { log_error("Unable to create scenarios directory."); window_close(w); return NULL; } window_loadsave_populate_list(w, includeNewItem, path, ".sc6"); break; case LOADSAVETYPE_TRACK: /* Uncomment when user tracks are separated platform_get_user_directory(path, "tracks"); if (!platform_ensure_directory_exists(path)) { log_error("Unable to create tracks directory."); window_close(w); return NULL; } */ safe_strcpy(path, RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), MAX_PATH); ch = strchr(path, '*'); if (ch != NULL) *ch = 0; window_loadsave_populate_list(w, includeNewItem, path, ".td?"); break; } w->no_list_items = _listItemsCount; window_init_scroll_widgets(w); return w; }
sint32 cmdline_for_sprite(const char **argv, sint32 argc) { gOpenRCT2Headless = true; if (argc == 0) return -1; if (_strcmpi(argv[0], "details") == 0) { if (argc < 2) { fprintf(stdout, "usage: sprite details <spritefile> [idx]\n"); return -1; } else if (argc == 2) { const char *spriteFilePath = argv[1]; if (!sprite_file_open(spriteFilePath)) { fprintf(stderr, "Unable to open input sprite file.\n"); return -1; } printf("sprites: %u\n", spriteFileHeader.num_entries); printf("data size: %u\n", spriteFileHeader.total_size); sprite_file_close(); return 1; } else { const char *spriteFilePath = argv[1]; sint32 spriteIndex = atoi(argv[2]); if (!sprite_file_open(spriteFilePath)) { fprintf(stderr, "Unable to open input sprite file.\n"); return -1; } if (spriteIndex < 0 || spriteIndex >= (sint32)spriteFileHeader.num_entries) { sprite_file_close(); fprintf(stderr, "Sprite #%d does not exist in sprite file.\n", spriteIndex); return -1; } rct_g1_element *g1 = &spriteFileEntries[spriteIndex]; printf("width: %d\n", g1->width); printf("height: %d\n", g1->height); printf("x offset: %d\n", g1->x_offset); printf("y offset: %d\n", g1->y_offset); printf("data offset: %p\n", g1->offset); sprite_file_close(); return 1; } } else if (_strcmpi(argv[0], "export") == 0) { if (argc < 4) { fprintf(stdout, "usage: sprite export <spritefile> <idx> <output>\n"); return -1; } const char *spriteFilePath = argv[1]; sint32 spriteIndex = atoi(argv[2]); const char *outputPath = argv[3]; if (!sprite_file_open(spriteFilePath)) { fprintf(stderr, "Unable to open input sprite file.\n"); return -1; } if (spriteIndex < 0 || spriteIndex >= (sint32)spriteFileHeader.num_entries) { fprintf(stderr, "Sprite #%d does not exist in sprite file.\n", spriteIndex); return -1; } if (!sprite_file_export(spriteIndex, outputPath)) { fprintf(stderr, "Could not export\n"); sprite_file_close(); return -1; } sprite_file_close(); return 1; } else if (_strcmpi(argv[0], "exportall") == 0) { if (argc < 3) { fprintf(stdout, "usage: sprite exportall <spritefile> <output directory>\n"); return -1; } const char *spriteFilePath = argv[1]; char outputPath[MAX_PATH]; if (!sprite_file_open(spriteFilePath)) { fprintf(stderr, "Unable to open input sprite file.\n"); return -1; } safe_strcpy(outputPath, argv[2], MAX_PATH); path_end_with_separator(outputPath, MAX_PATH); if (!platform_ensure_directory_exists(outputPath)){ fprintf(stderr, "Unable to create directory.\n"); return -1; } sint32 maxIndex = (sint32)spriteFileHeader.num_entries; sint32 numbers = (sint32)floor(log(maxIndex)); size_t pathLen = strlen(outputPath); if (pathLen >= (size_t)(MAX_PATH - numbers - 5)) { fprintf(stderr, "Path too long.\n"); return -1; } for (sint32 x = 0; x < numbers; x++){ outputPath[pathLen + x] = '0'; } safe_strcpy(outputPath + pathLen + numbers, ".png", MAX_PATH - pathLen - numbers); for (sint32 spriteIndex = 0; spriteIndex < maxIndex; spriteIndex++){ if (spriteIndex % 100 == 99){ // Status indicator printf("\r%d / %d, %d%%", spriteIndex, maxIndex, spriteIndex / maxIndex); } // Add to the index at the end of the file name char *counter = outputPath + pathLen + numbers - 1; (*counter)++; while (*counter > '9'){ *counter = '0'; counter--; (*counter)++; } if (!sprite_file_export(spriteIndex, outputPath)) { fprintf(stderr, "Could not export\n"); sprite_file_close(); return -1; } } sprite_file_close(); return 1; } else if (_strcmpi(argv[0], "create") == 0) { if (argc < 2) { fprintf(stderr, "usage: sprite create <spritefile>\n"); return -1; } const char *spriteFilePath = argv[1]; spriteFileHeader.num_entries = 0; spriteFileHeader.total_size = 0; sprite_file_save(spriteFilePath); sprite_file_close(); return 1; } else if (_strcmpi(argv[0], "append") == 0) { if (argc != 3 && argc != 5) { fprintf(stderr, "usage: sprite append <spritefile> <input> [<x offset> <y offset>]\n"); return -1; } const char *spriteFilePath = argv[1]; const char *imagePath = argv[2]; sint16 x_offset = 0; sint16 y_offset = 0; if (argc == 5) { char *endptr; x_offset = strtol(argv[3], &endptr, 0); if (*endptr != 0) { fprintf(stderr, "X offset must be an integer\n"); return -1; } y_offset = strtol(argv[4], &endptr, 0); if (*endptr != 0) { fprintf(stderr, "Y offset must be an integer\n"); return -1; } } rct_g1_element spriteElement; uint8 *buffer; sint32 bufferLength; if (!sprite_file_import(imagePath, x_offset, y_offset, &spriteElement, &buffer, &bufferLength, gSpriteMode)) return -1; if (!sprite_file_open(spriteFilePath)) { fprintf(stderr, "Unable to open input sprite file.\n"); return -1; } spriteFileHeader.num_entries++; spriteFileHeader.total_size += bufferLength; spriteFileEntries = realloc(spriteFileEntries, spriteFileHeader.num_entries * sizeof(rct_g1_element)); sprite_entries_make_relative(); spriteFileData = realloc(spriteFileData, spriteFileHeader.total_size); sprite_entries_make_absolute(); spriteFileEntries[spriteFileHeader.num_entries - 1] = spriteElement; memcpy(spriteFileData + (spriteFileHeader.total_size - bufferLength), buffer, bufferLength); spriteFileEntries[spriteFileHeader.num_entries - 1].offset = spriteFileData + (spriteFileHeader.total_size - bufferLength); free(buffer); if (!sprite_file_save(spriteFilePath)) return -1; return 1; } else if (_strcmpi(argv[0], "build") == 0) { if (argc < 3) { fprintf(stdout, "usage: sprite build <spritefile> <sprite description file> [silent]\n"); return -1; } const char *spriteFilePath = argv[1]; const char *spriteDescriptionPath = argv[2]; char* directoryPath = path_get_directory(spriteDescriptionPath); json_error_t error; json_t* sprite_list=json_load_file(spriteDescriptionPath, JSON_REJECT_DUPLICATES, &error); if (sprite_list == NULL) { fprintf(stderr, "Error parsing sprite description file: %s at line %d column %d\n", error.text, error.line, error.column); return -1; } if (!json_is_array(sprite_list)) { fprintf(stderr, "Error: expected array\n"); json_decref(sprite_list); return -1; } bool silent = (argc >= 4 && strcmp(argv[3], "silent") == 0); spriteFileHeader.num_entries = 0; spriteFileHeader.total_size = 0; sprite_file_save(spriteFilePath); fprintf(stdout, "Building: %s\n", spriteFilePath); size_t i; json_t* sprite_description; json_array_foreach(sprite_list, i, sprite_description) { if(!json_is_object(sprite_description)) { fprintf(stderr, "Error: expected object for sprite %lu\n", (unsigned long)i); json_decref(sprite_list); return -1; } json_t* path = json_object_get(sprite_description,"path"); if(!path || !json_is_string(path)) { fprintf(stderr, "Error: no path provided for sprite %lu\n", (unsigned long)i); json_decref(sprite_list); return -1; } // Get x and y offsets, if present json_t* x_offset = json_object_get(sprite_description, "x_offset"); json_t* y_offset = json_object_get(sprite_description, "y_offset"); // Resolve absolute sprite path char *imagePath = platform_get_absolute_path(json_string_value(path), directoryPath); rct_g1_element spriteElement; uint8 *buffer; int bufferLength; if (!sprite_file_import(imagePath, x_offset==NULL ? 0 : json_integer_value(x_offset), y_offset==NULL ? 0 : json_integer_value(y_offset), &spriteElement, &buffer, &bufferLength, gSpriteMode)) { fprintf(stderr, "Could not import image file: %s\nCanceling\n", imagePath); json_decref(sprite_list); free(imagePath); return -1; } if (!sprite_file_open(spriteFilePath)) { fprintf(stderr, "Unable to open sprite file: %s\nCanceling\n", spriteFilePath); json_decref(sprite_list); free(imagePath); return -1; } spriteFileHeader.num_entries++; spriteFileHeader.total_size += bufferLength; spriteFileEntries = realloc(spriteFileEntries, spriteFileHeader.num_entries * sizeof(rct_g1_element)); sprite_entries_make_relative(); spriteFileData = realloc(spriteFileData, spriteFileHeader.total_size); sprite_entries_make_absolute(); spriteFileEntries[spriteFileHeader.num_entries - 1] = spriteElement; memcpy(spriteFileData + (spriteFileHeader.total_size - bufferLength), buffer, bufferLength); spriteFileEntries[spriteFileHeader.num_entries - 1].offset = spriteFileData + (spriteFileHeader.total_size - bufferLength); free(buffer); if (!sprite_file_save(spriteFilePath)) { fprintf(stderr, "Could not save sprite file: %s\nCanceling\n", imagePath); json_decref(sprite_list); free(imagePath); return -1; } if (!silent) fprintf(stdout, "Added: %s\n", imagePath); free(imagePath); sprite_file_close(); } json_decref(sprite_list); free(directoryPath); fprintf(stdout, "Finished\n"); return 1; } else {
static exitcode_t HandleCommandSetRCT2(CommandLineArgEnumerator * enumerator) { exitcode_t result = CommandLine::HandleCommandDefault(); if (result != EXITCODE_CONTINUE) { return result; } // Get the path that was passed const utf8 * rawPath; if (!enumerator->TryPopString(&rawPath)) { Console::Error::WriteLine("Expected a path."); return EXITCODE_FAIL; } utf8 path[MAX_PATH]; Path::GetAbsolute(path, sizeof(path), rawPath); // Check if path exists Console::WriteLine("Checking path..."); if (!platform_directory_exists(path)) { Console::Error::WriteLine("The path '%s' does not exist", path); return EXITCODE_FAIL; } // Check if g1.dat exists (naive but good check) Console::WriteLine("Checking g1.dat..."); utf8 pathG1Check[MAX_PATH]; String::Set(pathG1Check, sizeof(pathG1Check), path); Path::Append(pathG1Check, sizeof(pathG1Check), "Data"); Path::Append(pathG1Check, sizeof(pathG1Check), "g1.dat"); if (!platform_file_exists(pathG1Check)) { Console::Error::WriteLine("RCT2 path not valid."); Console::Error::WriteLine("Unable to find %s.", pathG1Check); return EXITCODE_FAIL; } // Check user path that will contain the config utf8 userPath[MAX_PATH]; platform_resolve_user_data_path(); platform_get_user_directory(userPath, NULL, sizeof(userPath)); if (!platform_ensure_directory_exists(userPath)) { Console::Error::WriteLine("Unable to access or create directory '%s'.", userPath); return EXITCODE_FAIL; } // Update RCT2 path in config config_set_defaults(); config_open_default(); String::DiscardDuplicate(&gConfigGeneral.rct2_path, path); if (config_save_default()) { Console::WriteFormat("Updating RCT2 path to '%s'.", path); Console::WriteLine(); Console::WriteLine("Updated config.ini"); return EXITCODE_OK; } else { Console::Error::WriteLine("Unable to update config.ini"); return EXITCODE_FAIL; } }
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); safe_strncpy(gConfigTitleSequences.presets[preset].name, name, TITLE_SEQUENCE_NAME_SIZE); 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]) { safe_strncpy(srcPath, gConfigTitleSequences.presets[duplicate].path, MAX_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, false); } 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); gCurrentTitleSequence = preset; } }