From f00d7daef565e21db23dd879233f4b9ff9a0c5d8 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 30 Apr 2016 13:27:12 +0100 Subject: [PATCH] fix track design preview, place and refactor --- src/interface/window.h | 2 +- src/ride/track_design.c | 242 +----------------- src/ride/track_design_save.c | 2 +- src/windows/install_track.c | 2 +- src/windows/track_list.c | 165 ++++++------ src/windows/track_place.c | 472 ++++++++++++++++------------------- 6 files changed, 312 insertions(+), 573 deletions(-) diff --git a/src/interface/window.h b/src/interface/window.h index c032310969..67eef73b6e 100644 --- a/src/interface/window.h +++ b/src/interface/window.h @@ -627,7 +627,7 @@ void ride_construction_toolupdate_construct(int screenX, int screenY); void ride_construction_tooldown_construct(int screenX, int screenY); void window_maze_construction_update_pressed_widgets(); -void window_track_place_open(); +void window_track_place_open(utf8 *tdPath); rct_window *window_new_ride_open(); rct_window *window_new_ride_open_research(); void window_install_track_open(const char* path); diff --git a/src/ride/track_design.c b/src/ride/track_design.c index 4751c7d9b7..efb2c20d56 100644 --- a/src/ride/track_design.c +++ b/src/ride/track_design.c @@ -274,159 +274,12 @@ void track_update_max_min_coordinates(sint16 x, sint16 y, sint16 z) } } -#ifdef ADSIASD - -void track_list_populate(ride_list_item item, uint8* track_list_cache){ - uint8* track_pointer = track_list_cache; - - int cur_track_entry_index = 0; - for (uint8 track_type = *track_pointer++; track_type != 0xFE; - track_pointer += strlen((const char *)track_pointer) + 1, - track_type = *track_pointer++){ - rct_object_entry* track_object = (rct_object_entry*)track_pointer; - track_pointer += sizeof(rct_object_entry); - - if (track_type != item.type){ - continue; - } - - uint8 entry_type, entry_index; - if (item.entry_index != 0xFF){ - - if (!find_object_in_entry_group(track_object, &entry_type, &entry_index))continue; - - if (item.entry_index != entry_index)continue; - } - else{ - if (find_object_in_entry_group(track_object, &entry_type, &entry_index)){ - if ((get_ride_entry(entry_index)->flags & (RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME | RIDE_ENTRY_FLAG_SEPARATE_RIDE)) && - !rideTypeShouldLoseSeparateFlag(get_ride_entry(entry_index))) - continue; - } - else{ - uint32* esi = sub_6AB49A(track_object); - if (esi == NULL) continue; - if (*esi & 0x1000000)continue; - } - } - - // If cur_track_entry_index is greater than max number of tracks - if (cur_track_entry_index >= 1000){ - RCT2_GLOBAL(0xF635ED, uint8) |= 1; - break; - } - - int track_entry_index = 0; - uint8 isBelow = 0; - for (; track_entry_index != cur_track_entry_index; track_entry_index++){ - if (strcicmp((const char *)track_pointer, &RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, const char)[track_entry_index * 128]) < 0){ - isBelow = 1; - break; - } - } - - if (isBelow == 1){ - memmove( - &RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8)[track_entry_index * 128 + 128], - &RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8)[track_entry_index * 128], - (cur_track_entry_index - track_entry_index) * 128); - } - - strcpy(&RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, char)[track_entry_index * 128], (const char *)track_pointer); - cur_track_entry_index++; - } - - RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8)[cur_track_entry_index * 128] = '\0'; -} - -/** - * - * rct2: 0x006CED50 - */ -void track_load_list(ride_list_item item) -{ - RCT2_GLOBAL(0xF635ED, uint8) = 0; - - if (item.type < 0x80){ - rct_ride_entry* ride_type = get_ride_entry(item.entry_index); - if (!(ride_type->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE) || rideTypeShouldLoseSeparateFlag(ride_type)){ - item.entry_index = 0xFF; - } - } - - int totalFiles; - - track_list_query_directory(&totalFiles); - - uint8* track_list_cache; - - if (item.type == 0xFC || !(track_list_cache = track_list_cache_load(totalFiles))){ - uint8* new_track_file; - - new_track_file = malloc(0x40000); - - uint8* new_file_pointer = new_track_file; - file_info enumFileInfo; - - int enumFileHandle = platform_enumerate_files_begin(RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char)); - if (enumFileHandle == INVALID_HANDLE) - { - free(new_file_pointer); - return; - } - - while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) { - if (new_file_pointer > new_track_file + 0x3FF00)break; - - char path[MAX_PATH]; - substitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), enumFileInfo.path); - - rct_track_td6* loaded_track = load_track_design(path); - if (loaded_track){ - *new_file_pointer++ = loaded_track->type; - } - else{ - *new_file_pointer++ = 0xFF; - // Garbage object - new_file_pointer += sizeof(rct_object_entry); - // Empty string - *new_file_pointer++ = '\0'; - // Unsure why it previously didn't continue on load fail?? - continue; - } - memcpy(new_file_pointer, &loaded_track->vehicle_object, sizeof(rct_object_entry)); - new_file_pointer += sizeof(rct_object_entry); - - int file_name_length = strlen(enumFileInfo.path); - strcpy((char *)new_file_pointer, enumFileInfo.path); - new_file_pointer += file_name_length + 1; - } - platform_enumerate_files_end(enumFileHandle); - - if (!track_list_cache_save(totalFiles, new_track_file, new_file_pointer - new_track_file)){ - log_error("Track list failed to save."); - return; - } - free(new_track_file); - - track_list_cache = track_list_cache_load(totalFiles); - if (!track_list_cache){ - log_error("Track list failed to load after new save"); - return; - } - } - - track_list_populate(item, track_list_cache); - free(track_list_cache); -} - -#endif - /** * * rct2: 0x006ABDB0 */ -void load_track_scenery_objects(){ +void load_track_scenery_objects() +{ uint8 entry_index = RCT2_GLOBAL(0xF44157, uint8); rct_object_entry_extended* object_entry = &object_entry_groups[0].entries[entry_index]; @@ -439,8 +292,8 @@ void load_track_scenery_objects(){ find_object_in_entry_group(copied_entry, &entry_type, &entry_index); RCT2_GLOBAL(0xF44157, uint8) = entry_index; - rct_track_td6* track_design = RCT2_ADDRESS(0x009D8178, rct_track_td6); - uint8* track_elements = RCT2_ADDRESS(0x9D821B, uint8); + rct_track_td6 *track_design = gActiveTrackDesign; + uint8 *track_elements = gActiveTrackDesign->elements; if (track_design->type == RIDE_TYPE_MAZE){ // Skip all of the maze track elements @@ -616,19 +469,14 @@ void track_mirror_maze(uint8** track_elements){ * * rct2: 0x006D2436 */ -void track_mirror(){ - uint8* track_elements = RCT2_ADDRESS(0x009D821B, uint8); - - rct_track_td6* track_design = RCT2_ADDRESS(0x009D8178, rct_track_td6); - - if (track_design->type == RIDE_TYPE_MAZE){ - track_mirror_maze(&track_elements); +void track_mirror() +{ + if (gActiveTrackDesign->type == RIDE_TYPE_MAZE) { + track_mirror_maze(gActiveTrackDesign->elements); + } else { + track_mirror_ride(gActiveTrackDesign->elements); } - else{ - track_mirror_ride(&track_elements); - } - - track_mirror_scenery(&track_elements); + track_mirror_scenery(gActiveTrackDesign->elements); } static void track_add_selection_tile(sint16 x, sint16 y) @@ -1468,7 +1316,7 @@ int sub_6D01B3(rct_track_td6 *td6, uint8 bl, uint8 rideIndex, int x, int y, int RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MAX, sint16) = z; RCT2_GLOBAL(0x00F44129, uint16) = 0; - uint8* track_elements = RCT2_ADDRESS(0x009D821B, uint8); + uint8* track_elements = td6->elements; uint8 track_place_success = 0; @@ -1722,72 +1570,6 @@ void draw_track_preview(rct_track_td6 *td6, uint8** preview) track_design_preview_restore_map(); } -#ifdef fsdfds - -/** - * - * I don't think preview is a necessary output argument. It can be obtained easily using the track design structure. - * rct2: 0x006D1DEC - */ -rct_track_design *track_get_info(int index, uint8** preview) -{ - rct_track_design *trackDesign; - uint8 *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8); - int i; - - trackDesign = NULL; - - // Check if track design has already been loaded - for (i = 0; i < 4; i++) { - if (index == RCT2_ADDRESS(RCT2_ADDRESS_TRACK_DESIGN_INDEX_CACHE, uint32)[i]) { - trackDesign = &RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, rct_track_design*)[i]; - break; - } - } - - if (trackDesign == NULL) { - // Load track design - i = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_NEXT_INDEX_CACHE, uint32)++; - if (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_NEXT_INDEX_CACHE, uint32) >= 4) - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_NEXT_INDEX_CACHE, uint32) = 0; - - RCT2_ADDRESS(RCT2_ADDRESS_TRACK_DESIGN_INDEX_CACHE, uint32)[i] = index; - - char track_path[MAX_PATH] = { 0 }; - substitute_path(track_path, (char*)RCT2_ADDRESS_TRACKS_PATH, (char *)trackDesignList + (index * 128)); - - rct_track_td6* loaded_track = NULL; - - log_verbose("Loading track: %s", trackDesignList + (index * 128)); - - if (!(loaded_track = load_track_design(track_path))) { - if (preview != NULL) *preview = NULL; - // Mark cache as empty. - RCT2_ADDRESS(RCT2_ADDRESS_TRACK_DESIGN_INDEX_CACHE, uint32)[i] = 0; - log_error("Failed to load track: %s", trackDesignList + (index * 128)); - return NULL; - } - - trackDesign = &RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, rct_track_design*)[i]; - - // Copy the track design apart from the preview image - memcpy(&trackDesign->track_td6, loaded_track, sizeof(rct_track_td6)); - // Load in a new preview image, calculate cost variable, calculate var_06 - draw_track_preview(&trackDesign->track_td6, (uint8**)trackDesign->preview); - - trackDesign->track_td6.cost = gTrackDesignCost; - trackDesign->track_td6.track_flags = RCT2_GLOBAL(0x00F44151, uint8) & 7; - } - - // Set preview to correct preview image based on rotation - if (preview != NULL) - *preview = trackDesign->preview[_currentTrackPieceDirection]; - - return trackDesign; -} - -#endif - /** * * rct2: 0x006D3664 diff --git a/src/ride/track_design_save.c b/src/ride/track_design_save.c index 03f4881019..70465cf432 100644 --- a/src/ride/track_design_save.c +++ b/src/ride/track_design_save.c @@ -785,7 +785,7 @@ static bool track_design_save_to_td6(rct_track_td6 *td6, uint8 rideIndex) td6->flags = 0; td6->flags2 = 0; - uint8 *trackElements = RCT2_ADDRESS(0x9D821B, uint8); + uint8 *trackElements = td6->elements; memset(trackElements, 0, 8000); if (td6->type == RIDE_TYPE_MAZE) { diff --git a/src/windows/install_track.c b/src/windows/install_track.c index d86d4ce8df..a88d0e1cd9 100644 --- a/src/windows/install_track.c +++ b/src/windows/install_track.c @@ -198,7 +198,7 @@ static void window_install_track_select(rct_window *w, int index) // window_error_open(STR_THIS_DESIGN_WILL_BE_BUILT_WITH_AN_ALTERNATIVE_VEHICLE_TYPE, -1); window_close(w); - window_track_place_open(); + window_track_place_open(NULL); } /** diff --git a/src/windows/track_list.c b/src/windows/track_list.c index e62fb15a22..51269ddbb4 100644 --- a/src/windows/track_list.c +++ b/src/windows/track_list.c @@ -100,40 +100,24 @@ static uint16 _loadedTrackDesignIndex; static rct_track_td6 _loadedTrackDesign; static uint8 _loadedTrackDesignPreview[4][TRACK_PREVIEW_IMAGE_SIZE]; +static void track_list_load_designs(ride_list_item item); +static bool track_list_load_design_for_preview(utf8 *path); + /** * * rct2: 0x006CF1A2 */ void window_track_list_open(ride_list_item item) { - rct_window *w; - int x, y; - void *mem; - window_close_construction_windows(); _window_track_list_item = item; + track_list_load_designs(item); - char entry[9]; - const char *entryPtr = NULL; - if (item.type < 0x80) { - rct_ride_entry *rideEntry = get_ride_entry(item.entry_index); - if ((rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE) && !rideTypeShouldLoseSeparateFlag(rideEntry)) { - get_ride_entry_name(entry, item.entry_index); - entryPtr = entry; - } - } - _trackDesignsCount = track_design_index_get_for_ride(&_trackDesigns, item.type, entryPtr); - - if (RCT2_GLOBAL(0x00F635ED, uint8) & 1) + if (RCT2_GLOBAL(0x00F635ED, uint8) & 1) { window_error_open(STR_WARNING, STR_TOO_MANY_TRACK_DESIGNS_OF_THIS_TYPE); + } - mem = malloc(1285292); - if (mem == NULL) - return; - - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, void*) = mem; - // reset_track_list_cache(); - + int x, y; if (gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER) { x = gScreenWidth / 2 - 300; y = max(28, gScreenHeight / 2 - 200); @@ -141,7 +125,7 @@ void window_track_list_open(ride_list_item item) x = 0; y = 29; } - w = window_create( + rct_window *w = window_create( x, y, 600, @@ -161,6 +145,24 @@ void window_track_list_open(ride_list_item item) _currentTrackPieceDirection = 2; } +/** + * + * rct2: 0x006CFD76 + */ +static void window_track_list_close(rct_window *w) +{ + // Dispose loaded track + SafeFree(_loadedTrackDesign.elements); + + // Dispose track list + for (size_t i = 0; i < _trackDesignsCount; i++) { + free(_trackDesigns[i].name); + free(_trackDesigns[i].path); + } + SafeFree(_trackDesigns); + _trackDesignsCount = 0; +} + /** * * rct2: 0x006CFB82 @@ -200,21 +202,12 @@ static void window_track_list_select(rct_window *w, int index) return; } - // if (!load_track_design(tdRef->path)) { - // w->track_list.var_480 = 0xFFFF; - // window_invalidate(w); - // return; - // } + if (_loadedTrackDesignIndex != -1 && _loadedTrackDesign.track_flags & 4) { + window_error_open(STR_THIS_DESIGN_WILL_BE_BUILT_WITH_AN_ALTERNATIVE_VEHICLE_TYPE, STR_NONE); + } - // rct_track_design *trackDesign = track_get_info(index, NULL); - // if (trackDesign != NULL) { - // if (trackDesign->track_td6.track_flags & 4) { - // window_error_open(STR_THIS_DESIGN_WILL_BE_BUILT_WITH_AN_ALTERNATIVE_VEHICLE_TYPE, STR_NONE); - // } - // - // window_close(w); - // window_track_place_open(); - // } + window_close(w); + window_track_place_open(tdRef->path); } static int window_track_list_get_list_item_index_from_position(int x, int y) @@ -232,22 +225,6 @@ static int window_track_list_get_list_item_index_from_position(int x, int y) return index; } -/** - * - * rct2: 0x006CFD76 - */ -static void window_track_list_close(rct_window *w) -{ - for (size_t i = 0; i < _trackDesignsCount; i++) { - free(_trackDesigns[i].name); - free(_trackDesigns[i].path); - } - free(_trackDesigns); - _trackDesignsCount = 0; - - free(RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, void*)); -} - /** * * rct2: 0x006CFA31 @@ -388,16 +365,9 @@ static void window_track_list_invalidate(rct_window *w) */ static void window_track_list_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_widget *widget; - uint8 *image; - uint16 holes, speed, drops, dropHeight, inversions; - fixed32_2dp rating; - int trackIndex, x, y, colour, gForces, airTime; - rct_g1_element tmpElement, *substituteElement; - window_draw_widgets(w, dpi); - trackIndex = w->track_list.var_482; + int trackIndex = w->track_list.var_482; if (gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER) { if (_trackDesignsCount == 0 || trackIndex == -1) { return; @@ -407,36 +377,32 @@ static void window_track_list_paint(rct_window *w, rct_drawpixelinfo *dpi) } // Track preview - widget = &window_track_list_widgets[WIDX_TRACK_PREVIEW]; + int x, y, colour; + rct_widget *widget = &window_track_list_widgets[WIDX_TRACK_PREVIEW]; x = w->x + widget->left + 1; y = w->y + widget->top + 1; colour = ColourMapA[w->colours[0]].darkest; gfx_fill_rect(dpi, x, y, x + 369, y + 216, colour); rct_track_td6 *td6 = &_loadedTrackDesign; - gActiveTrackDesign = td6; if (_loadedTrackDesignIndex != trackIndex) { - if (!track_design_open(td6, _trackDesigns[trackIndex].path)) { + uint8 *path = _trackDesigns[trackIndex].path; + if (track_list_load_design_for_preview(path)) { + _loadedTrackDesignIndex = trackIndex; + } else { + _loadedTrackDesignIndex = -1; return; } - - // Load in a new preview image, calculate cost variable, calculate var_06 - draw_track_preview(td6, (uint8**)_loadedTrackDesignPreview); - - td6->cost = gTrackDesignCost; - td6->track_flags = RCT2_GLOBAL(0x00F44151, uint8) & 7; - - _loadedTrackDesignIndex = trackIndex; } - image = _loadedTrackDesignPreview[_currentTrackPieceDirection]; + uint8 *image = _loadedTrackDesignPreview[_currentTrackPieceDirection]; // trackDesign = track_get_info(trackIndex, &image); // if (trackDesign == NULL) { // return; // } - substituteElement = &g1Elements[0]; - tmpElement = *substituteElement; + rct_g1_element *substituteElement = &g1Elements[0]; + rct_g1_element tmpElement = *substituteElement; substituteElement->offset = image; substituteElement->width = 370; substituteElement->height = 217; @@ -475,7 +441,7 @@ static void window_track_list_paint(rct_window *w, rct_drawpixelinfo *dpi) y = w->y + widget->bottom + 2; // Stats - rating = td6->excitement * 10; + fixed32_2dp rating = td6->excitement * 10; gfx_draw_string_left(dpi, STR_TRACK_LIST_EXCITEMENT_RATING, &rating, 0, x, y); y += 10; @@ -490,12 +456,12 @@ static void window_track_list_paint(rct_window *w, rct_drawpixelinfo *dpi) if (td6->type != RIDE_TYPE_MAZE) { if (td6->type == RIDE_TYPE_MINI_GOLF) { // Holes - holes = td6->holes & 0x1F; + uint16 holes = td6->holes & 0x1F; gfx_draw_string_left(dpi, STR_HOLES, &holes, 0, x, y); y += 10; } else { // Maximum speed - speed = ((td6->max_speed << 16) * 9) >> 18; + uint16 speed = ((td6->max_speed << 16) * 9) >> 18; gfx_draw_string_left(dpi, STR_MAX_SPEED, &speed, 0, x, y); y += 10; @@ -514,7 +480,7 @@ static void window_track_list_paint(rct_window *w, rct_drawpixelinfo *dpi) if (ride_type_has_flag(td6->type, RIDE_TYPE_FLAG_HAS_G_FORCES)) { // Maximum positive vertical Gs - gForces = td6->max_positive_vertical_g * 32; + int gForces = td6->max_positive_vertical_g * 32; gfx_draw_string_left(dpi, STR_MAX_POSITIVE_VERTICAL_G, &gForces, 0, x, y); y += 10; @@ -532,7 +498,7 @@ static void window_track_list_paint(rct_window *w, rct_drawpixelinfo *dpi) if (td6->version_and_colour_scheme / 4 >= 2) { if (td6->total_air_time != 0) { // Total air time - airTime = td6->total_air_time * 25; + int airTime = td6->total_air_time * 25; gfx_draw_string_left(dpi, STR_TOTAL_AIR_TIME, &airTime, 0, x, y); y += 10; } @@ -541,18 +507,18 @@ static void window_track_list_paint(rct_window *w, rct_drawpixelinfo *dpi) if (ride_type_has_flag(td6->type, RIDE_TYPE_FLAG_HAS_DROPS)) { // Drops - drops = td6->drops & 0x3F; + uint16 drops = td6->drops & 0x3F; gfx_draw_string_left(dpi, STR_DROPS, &drops, 0, x, y); y += 10; // Drop height is multiplied by 0.75 - dropHeight = (td6->highest_drop_height + (td6->highest_drop_height / 2)) / 2; + uint16 dropHeight = (td6->highest_drop_height + (td6->highest_drop_height / 2)) / 2; gfx_draw_string_left(dpi, STR_HIGHEST_DROP_HEIGHT, &drops, 0, x, y); y += 10; } if (td6->type != RIDE_TYPE_MINI_GOLF) { - inversions = td6->inversions & 0x1F; + uint16 inversions = td6->inversions & 0x1F; if (inversions != 0) { // Inversions gfx_draw_string_left(dpi, STR_INVERSIONS, &inversions, 0, x, y); @@ -633,3 +599,34 @@ static void window_track_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, y += 10; } } + +static void track_list_load_designs(ride_list_item item) +{ + char entry[9]; + const char *entryPtr = NULL; + if (item.type < 0x80) { + rct_ride_entry *rideEntry = get_ride_entry(item.entry_index); + if ((rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE) && !rideTypeShouldLoseSeparateFlag(rideEntry)) { + get_ride_entry_name(entry, item.entry_index); + entryPtr = entry; + } + } + _trackDesignsCount = track_design_index_get_for_ride(&_trackDesigns, item.type, entryPtr); +} + +static bool track_list_load_design_for_preview(utf8 *path) +{ + // Dispose currently loaded track + SafeFree(_loadedTrackDesign.elements); + + if (track_design_open(&_loadedTrackDesign, path)) { + // Load in a new preview image, calculate cost variable, calculate var_06 + gActiveTrackDesign = &_loadedTrackDesign; + draw_track_preview(&_loadedTrackDesign, (uint8**)_loadedTrackDesignPreview); + + _loadedTrackDesign.cost = gTrackDesignCost; + _loadedTrackDesign.track_flags = RCT2_GLOBAL(0x00F44151, uint8) & 7; + return true; + } + return false; +} diff --git a/src/windows/track_place.c b/src/windows/track_place.c index 7da0445c3a..c1e47804d3 100644 --- a/src/windows/track_place.c +++ b/src/windows/track_place.c @@ -105,6 +105,15 @@ static sint16 _window_track_place_last_valid_y; static sint16 _window_track_place_last_valid_z; static money32 _window_track_place_last_cost; +static void window_track_place_clear_provisional(); +static int window_track_place_get_base_z(int x, int y); +static void window_track_place_attempt_placement(int x, int y, int z, int bl, money32 *cost, uint8 *rideIndex); + +static void window_track_place_clear_mini_preview(); +static void window_track_place_draw_mini_preview(); +static void window_track_place_draw_mini_preview_track(int pass, rct_xy16 origin, rct_xy16 *min, rct_xy16 *max); +static void window_track_place_draw_mini_preview_maze(int pass, rct_xy16 origin, rct_xy16 *min, rct_xy16 *max); + /** * * rct2: 0x006D182E @@ -116,262 +125,22 @@ static void window_track_place_clear_mini_preview() #define swap(x, y) x = x ^ y; y = x ^ y; x = x ^ y; -/** - * - * rct2: 0x006D1845 - */ -static void window_track_place_draw_mini_preview() -{ - rct_track_td6 *track = RCT2_ADDRESS(0x009D8178, rct_track_td6); - uint8 *pixel, colour, bits; - int i, rotation, pass, x, y, pixelX, pixelY, originX, originY, minX, minY, maxX, maxY; - rct_maze_element *mazeElement; - rct_track_element *trackElement; - const rct_preview_track *trackBlock; - - window_track_place_clear_mini_preview(); - - minX = 0; - minY = 0; - maxX = 0; - maxY = 0; - - // First pass is used to determine the width and height of the image so it can centre it - for (pass = 0; pass < 2; pass++) { - originX = 0; - originY = 0; - if (pass == 1) { - originX -= ((maxX + minX) >> 6) << 5; - originY -= ((maxY + minY) >> 6) << 5; - } - - if (track->type != RIDE_TYPE_MAZE) { - #pragma region Track - - rotation = _currentTrackPieceDirection + get_current_rotation(); - trackElement = RCT2_ADDRESS(0x009D821B, rct_track_element); - - while (trackElement->type != 255) { - int trackType = trackElement->type; - if (trackType == 101) - trackType = 255; - - // Station track is a lighter colour - colour = RCT2_ADDRESS(0x0099BA64, uint8)[trackType * 16] & 0x10 ? 222 : 218; - - // Follow a single track piece shape - trackBlock = TrackBlocks[trackType]; - while (trackBlock->index != 255) { - x = originX; - y = originY; - - switch (rotation & 3) { - case 0: - x += trackBlock->x; - y += trackBlock->y; - break; - case 1: - x += trackBlock->y; - y -= trackBlock->x; - break; - case 2: - x -= trackBlock->x; - y -= trackBlock->y; - break; - case 3: - x -= trackBlock->y; - y += trackBlock->x; - break; - } - - if (pass == 0) { - minX = min(minX, x); - maxX = max(maxX, x); - minY = min(minY, y); - maxY = max(maxY, y); - } else { - pixelX = 80 + ((y / 32) - (x / 32)) * 4; - pixelY = 38 + ((y / 32) + (x / 32)) * 2; - if (pixelX >= 0 && pixelY >= 0 && pixelX <= 160 && pixelY <= 75) { - pixel = &_window_track_place_mini_preview[pixelY * TRACK_MINI_PREVIEW_WIDTH + pixelX]; - - bits = trackBlock->var_08 << (rotation & 3); - bits = (bits & 0x0F) | ((bits & 0xF0) >> 4); - - for (i = 0; i < 4; i++) { - if (bits & 1) pixel[338 + i] = colour; - if (bits & 2) pixel[168 + i] = colour; - if (bits & 4) pixel[ 2 + i] = colour; - if (bits & 8) pixel[172 + i] = colour; - } - } - } - trackBlock++; - } - - // Change rotation and next position based on track curvature - rotation &= 3; - const rct_track_coordinates* track_coordinate = &TrackCoordinates[trackType]; - - trackType *= 10; - switch (rotation) { - case 0: - originX += track_coordinate->x; - originY += track_coordinate->y; - break; - case 1: - originX += track_coordinate->y; - originY -= track_coordinate->x; - break; - case 2: - originX -= track_coordinate->x; - originY -= track_coordinate->y; - break; - case 3: - originX -= track_coordinate->y; - originY += track_coordinate->x; - break; - } - rotation += track_coordinate->rotation_end - track_coordinate->rotation_begin; - rotation &= 3; - if (track_coordinate->rotation_end & 4) - rotation |= 4; - if (!(rotation & 4)) { - originX += TileDirectionDelta[rotation].x; - originY += TileDirectionDelta[rotation].y; - } - trackElement++; - } - - #pragma endregion - } else { - #pragma region Maze - - rotation = (_currentTrackPieceDirection + get_current_rotation()) & 3; - mazeElement = RCT2_ADDRESS(0x009D821B, rct_maze_element); - while (mazeElement->all != 0) { - x = mazeElement->x * 32; - y = mazeElement->y * 32; - switch (rotation) { - case 1: - x = -x; - swap(x, y); - break; - case 2: - x = -x; - y = -y; - break; - case 3: - x = -x; - swap(x, y); - break; - } - x += originX; - y += originY; - - // Entrance or exit is a lighter colour - colour = mazeElement->type == 8 || mazeElement->type == 128 ? 222 : 218; - - if (pass == 0) { - minX = min(minX, x); - maxX = max(maxX, x); - minY = min(minY, y); - maxY = max(maxY, y); - } else { - pixelX = 80 + ((y / 32) - (x / 32)) * 4; - pixelY = 38 + ((y / 32) + (x / 32)) * 2; - if (pixelX <= 160 && pixelY <= 75) { - pixel = &_window_track_place_mini_preview[pixelY * TRACK_MINI_PREVIEW_WIDTH + pixelX]; - - for (i = 0; i < 4; i++) { - pixel[338 + i] = colour; - pixel[168 + i] = colour; - pixel[ 2 + i] = colour; - pixel[172 + i] = colour; - } - } - } - mazeElement++; - } - - #pragma endregion - } - } -} - -/** - * - * rct2: 0x006D017F - */ -static void window_track_place_clear_provisional() -{ - if (_window_track_place_last_was_valid) { - sub_6D01B3( - gActiveTrackDesign, - PTD_OPERATION_CLEAR_OUTLINES, - RCT2_GLOBAL(0x00F440EB, uint8), - _window_track_place_last_valid_x, - _window_track_place_last_valid_y, - _window_track_place_last_valid_z - ); - _window_track_place_last_was_valid = 0; - } -} - -/** - * - * rct2: 0x006D17C6 - */ -static int window_track_place_get_base_z(int x, int y) -{ - rct_map_element *mapElement; - int z; - - mapElement = map_get_surface_element_at(x >> 5, y >> 5); - z = mapElement->base_height * 8; - - // Increase Z above slope - if (mapElement->properties.surface.slope & 0x0F) { - z += 16; - - // Increase Z above double slope - if (mapElement->properties.surface.slope & 0x10) - z += 16; - } - - // Increase Z above water - if (mapElement->properties.surface.terrain & 0x1F) - z = max(z, (mapElement->properties.surface.terrain & 0x1F) << 4); - - return z + sub_6D01B3(gActiveTrackDesign, PTD_OPERATION_GET_PLACE_Z, 0, x, y, z); -} - -static void window_track_place_attempt_placement(int x, int y, int z, int bl, money32 *cost, uint8 *rideIndex) -{ - int eax, ebx, ecx, edx, esi, edi, ebp; - money32 result; - - edx = esi = ebp = 0; - eax = x; - ebx = bl; - ecx = y; - edi = z; - result = game_do_command_p(GAME_COMMAND_PLACE_TRACK_DESIGN, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - - if (cost != NULL) *cost = result; - if (rideIndex != NULL) *rideIndex = edi & 0xFF; -} - /** * * rct2: 0x006CFCA0 */ -void window_track_place_open() +void window_track_place_open(utf8 *tdPath) { rct_window *w; window_close_construction_windows(); + gActiveTrackDesign = malloc(sizeof(rct_track_td6)); + if (!track_design_open(gActiveTrackDesign, tdPath)) { + SafeFree(gActiveTrackDesign); + return; + } + _window_track_place_mini_preview = malloc(TRACK_MINI_PREVIEW_SIZE); window_track_place_clear_mini_preview(); @@ -408,7 +177,8 @@ static void window_track_place_close(rct_window *w) map_invalidate_map_selection_tiles(); RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~6; hide_gridlines(); - free(_window_track_place_mini_preview); + SafeFree(_window_track_place_mini_preview); + SafeFree(gActiveTrackDesign); } /** @@ -588,21 +358,82 @@ static void window_track_place_invalidate(rct_window *w) colour_scheme_update(w); } +/** + * + * rct2: 0x006D017F + */ +static void window_track_place_clear_provisional() +{ + if (_window_track_place_last_was_valid) { + sub_6D01B3( + gActiveTrackDesign, + PTD_OPERATION_CLEAR_OUTLINES, + RCT2_GLOBAL(0x00F440EB, uint8), + _window_track_place_last_valid_x, + _window_track_place_last_valid_y, + _window_track_place_last_valid_z + ); + _window_track_place_last_was_valid = 0; + } +} + +/** + * + * rct2: 0x006D17C6 + */ +static int window_track_place_get_base_z(int x, int y) +{ + rct_map_element *mapElement; + int z; + + mapElement = map_get_surface_element_at(x >> 5, y >> 5); + z = mapElement->base_height * 8; + + // Increase Z above slope + if (mapElement->properties.surface.slope & 0x0F) { + z += 16; + + // Increase Z above double slope + if (mapElement->properties.surface.slope & 0x10) + z += 16; + } + + // Increase Z above water + if (mapElement->properties.surface.terrain & 0x1F) + z = max(z, (mapElement->properties.surface.terrain & 0x1F) << 4); + + return z + sub_6D01B3(gActiveTrackDesign, PTD_OPERATION_GET_PLACE_Z, 0, x, y, z); +} + +static void window_track_place_attempt_placement(int x, int y, int z, int bl, money32 *cost, uint8 *rideIndex) +{ + int eax, ebx, ecx, edx, esi, edi, ebp; + money32 result; + + edx = esi = ebp = 0; + eax = x; + ebx = bl; + ecx = y; + edi = z; + result = game_do_command_p(GAME_COMMAND_PLACE_TRACK_DESIGN, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + + if (cost != NULL) *cost = result; + if (rideIndex != NULL) *rideIndex = edi & 0xFF; +} + /** * * rct2: 0x006CFD9D */ static void window_track_place_paint(rct_window *w, rct_drawpixelinfo *dpi) { - rct_drawpixelinfo clippedDpi; - rct_g1_element tmpElement, *substituteElement; - window_draw_widgets(w, dpi); // Draw mini tile preview + rct_drawpixelinfo clippedDpi; if (clip_drawpixelinfo(&clippedDpi, dpi, w->x + 4, w->y + 18, 168, 78)) { - substituteElement = &g1Elements[0]; - tmpElement = *substituteElement; + rct_g1_element *substituteElement = &g1Elements[0]; + rct_g1_element tmpElement = *substituteElement; substituteElement->offset = _window_track_place_mini_preview; substituteElement->width = TRACK_MINI_PREVIEW_WIDTH; substituteElement->height = TRACK_MINI_PREVIEW_HEIGHT; @@ -614,7 +445,136 @@ static void window_track_place_paint(rct_window *w, rct_drawpixelinfo *dpi) } // Price - if (_window_track_place_last_cost != MONEY32_UNDEFINED) - if (!(gParkFlags & PARK_FLAGS_NO_MONEY)) - gfx_draw_string_centred(dpi, STR_COST_LABEL, w->x + 88, w->y + 94, 0, &_window_track_place_last_cost); + if (_window_track_place_last_cost != MONEY32_UNDEFINED && !(gParkFlags & PARK_FLAGS_NO_MONEY)) { + gfx_draw_string_centred(dpi, STR_COST_LABEL, w->x + 88, w->y + 94, 0, &_window_track_place_last_cost); + } +} + +/** + * + * rct2: 0x006D1845 + */ +static void window_track_place_draw_mini_preview() +{ + window_track_place_clear_mini_preview(); + + bool isMaze = gActiveTrackDesign->type == RIDE_TYPE_MAZE; + + // First pass is used to determine the width and height of the image so it can centre it + rct_xy16 min = { 0, 0 }; + rct_xy16 max = { 0, 0 }; + for (int pass = 0; pass < 2; pass++) { + rct_xy16 origin = { 0, 0 }; + if (pass == 1) { + origin.x -= ((max.x + min.x) >> 6) << 5; + origin.y -= ((max.y + min.y) >> 6) << 5; + } + + if (isMaze) { + window_track_place_draw_mini_preview_maze(pass, origin, &min, &max); + } else { + window_track_place_draw_mini_preview_track(pass, origin, &min, &max); + } + } +} + +static void window_track_place_draw_mini_preview_track(int pass, rct_xy16 origin, rct_xy16 *min, rct_xy16 *max) +{ + int rotation = _currentTrackPieceDirection + get_current_rotation(); + rct_track_element *trackElement = (rct_track_element*)gActiveTrackDesign->elements; + + while (trackElement->type != 255) { + int trackType = trackElement->type; + if (trackType == TRACK_ELEM_INVERTED_90_DEG_UP_TO_FLAT_QUARTER_LOOP) { + trackType = 255; + } + + // Station track is a lighter colour + uint8 colour = RCT2_ADDRESS(0x0099BA64, uint8)[trackType * 16] & 0x10 ? 222 : 218; + + // Follow a single track piece shape + const rct_preview_track *trackBlock = TrackBlocks[trackType]; + while (trackBlock->index != 255) { + sint16 x = origin.x; + sint16 y = origin.y; + map_offset_with_rotation(&x, &y, trackBlock->x, trackBlock->y, rotation); + + if (pass == 0) { + min->x = min(min->x, x); + max->x = max(max->x, x); + min->y = min(min->y, y); + max->y = max(max->y, y); + } else { + int pixelX = 80 + ((y / 32) - (x / 32)) * 4; + int pixelY = 38 + ((y / 32) + (x / 32)) * 2; + if (pixelX >= 0 && pixelY >= 0 && pixelX <= 160 && pixelY <= 75) { + uint8 *pixel = &_window_track_place_mini_preview[pixelY * TRACK_MINI_PREVIEW_WIDTH + pixelX]; + + uint8 bits = trackBlock->var_08 << (rotation & 3); + bits = (bits & 0x0F) | ((bits & 0xF0) >> 4); + + for (int i = 0; i < 4; i++) { + if (bits & 1) pixel[338 + i] = colour; + if (bits & 2) pixel[168 + i] = colour; + if (bits & 4) pixel[ 2 + i] = colour; + if (bits & 8) pixel[172 + i] = colour; + } + } + } + trackBlock++; + } + + // Change rotation and next position based on track curvature + rotation &= 3; + const rct_track_coordinates* track_coordinate = &TrackCoordinates[trackType]; + + trackType *= 10; + map_offset_with_rotation(&origin.x, &origin.y, track_coordinate->x, track_coordinate->y, rotation); + rotation += track_coordinate->rotation_end - track_coordinate->rotation_begin; + rotation &= 3; + if (track_coordinate->rotation_end & 4) + rotation |= 4; + if (!(rotation & 4)) { + origin.x += TileDirectionDelta[rotation].x; + origin.y += TileDirectionDelta[rotation].y; + } + trackElement++; + } +} + +static void window_track_place_draw_mini_preview_maze(int pass, rct_xy16 origin, rct_xy16 *min, rct_xy16 *max) +{ + int rotation = (_currentTrackPieceDirection + get_current_rotation()) & 3; + rct_maze_element *mazeElement = gActiveTrackDesign->elements; + while (mazeElement->all != 0) { + sint16 x = mazeElement->x * 32; + sint16 y = mazeElement->y * 32; + rotate_map_coordinates(&x, &y, rotation); + + x += origin.x; + y += origin.y; + + // Entrance or exit is a lighter colour + uint8 colour = mazeElement->type == 8 || mazeElement->type == 128 ? 222 : 218; + + if (pass == 0) { + min->x = min(min->x, x); + max->x = max(max->x, x); + min->y = min(min->y, y); + max->y = max(max->y, y); + } else { + int pixelX = 80 + ((y / 32) - (x / 32)) * 4; + int pixelY = 38 + ((y / 32) + (x / 32)) * 2; + if (pixelX <= 160 && pixelY <= 75) { + uint8 *pixel = &_window_track_place_mini_preview[pixelY * TRACK_MINI_PREVIEW_WIDTH + pixelX]; + for (int i = 0; i < 4; i++) { + pixel[338 + i] = colour; + pixel[168 + i] = colour; + pixel[ 2 + i] = colour; + pixel[172 + i] = colour; + } + } + } + mazeElement++; + } }