From dde9611343d4a278600a09443170a780229293ac Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Sat, 25 Apr 2015 11:21:08 +0100 Subject: [PATCH 01/23] Added td4 booster check. Small refactor to use known structures --- src/rct1.h | 4 ++++ src/ride/track.c | 40 ++++++++++++++++++++++++++++++---------- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/rct1.h b/src/rct1.h index 039ab3121e..c6f4b2fd49 100644 --- a/src/rct1.h +++ b/src/rct1.h @@ -298,6 +298,10 @@ enum { RCT1_RIDE_TYPE_LEMONADE_STALL }; +enum{ + RCT1_TRACK_ELEM_BOOSTER = 100 +}; + typedef struct{ uint8 type; // 0x00 uint8 vehicle_type; // 0x01 diff --git a/src/ride/track.c b/src/ride/track.c index d9d4f2f96e..7fa812690b 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -454,6 +454,23 @@ static void read(void *dst, char **src, int length) *src += length; } +/* rct2: 0x00677530 + * Returns 1 if it has booster track elements + */ +uint8 td4_track_has_boosters(rct_track_td6* track_design, uint8* track_elements){ + if (track_design->type == RCT1_RIDE_TYPE_HEDGE_MAZE) + return 0; + + rct_track_element* track_element = (rct_track_element*)track_elements; + + for (; track_element->type != 0xFF; track_element++){ + if (track_element->type == RCT1_TRACK_ELEM_BOOSTER) + return 1; + } + + return 0; +} + /** * * rct2: 0x0067726A @@ -535,20 +552,21 @@ rct_track_td6* load_track_design(const char *path) // Set any element passed the tracks to 0xFF if (track_design->type == RIDE_TYPE_MAZE) { - uint32* maze_element = (uint32*)track_elements; - while (*maze_element != 0) { + rct_maze_element* maze_element = (rct_maze_element*)track_elements; + while (maze_element->all != 0) { maze_element++; } maze_element++; memset(maze_element, 255, final_track_element_location - (uint8*)maze_element); - } else { - uint8* track_element = track_elements; - while (*track_element != 255) { - track_element += 2; } - track_element++; - memset(track_element, 255, final_track_element_location - track_element); - } + else { + rct_track_element* track_element = (rct_track_element*)track_elements; + while (track_element->type != 255) { + track_element++; + } + memset(((uint8*)track_element) + 1, 255, final_track_element_location - (uint8*)track_element); + + } // Edit the colours to use the new versions // Unsure why it is 67 @@ -565,7 +583,9 @@ rct_track_td6* load_track_design(const char *path) // Highest drop height is 1bit = 1/3 a meter in td4 // Not sure if this is correct?? track_design->highest_drop_height >>= 1; - if (0x100 & RCT2_CALLPROC_X(0x00677530, 0, 0, 0, 0, 0, 0, 0)) + + // If it has boosters then sadly track has to be discarded. + if (td4_track_has_boosters(track_design, track_elements)) track_design->type = RIDE_TYPE_NULL; if (track_design->type == RCT1_RIDE_TYPE_STEEL_MINI_ROLLER_COASTER) From f6f671e27fc5fa104a0696cd94359914998fd9fc Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Sun, 26 Apr 2015 12:33:00 +0100 Subject: [PATCH 02/23] Started .TD6 creation function. Labelled known offsets from compare to ride structure. --- src/rct1.h | 5 +++ src/ride/ride.c | 4 +- src/ride/ride.h | 3 +- src/ride/track.c | 80 ++++++++++++++++++++++++++++++++----- src/ride/track.h | 30 +++++++------- src/ride/vehicle.h | 6 +++ src/windows/install_track.c | 9 +++-- src/windows/track_list.c | 11 ++--- 8 files changed, 111 insertions(+), 37 deletions(-) diff --git a/src/rct1.h b/src/rct1.h index c6f4b2fd49..2412eceb06 100644 --- a/src/rct1.h +++ b/src/rct1.h @@ -302,6 +302,11 @@ enum{ RCT1_TRACK_ELEM_BOOSTER = 100 }; +enum{ + RCT1_RIDE_MODE_POWERED_LAUNCH = 3, + +}; + typedef struct{ uint8 type; // 0x00 uint8 vehicle_type; // 0x01 diff --git a/src/ride/ride.c b/src/ride/ride.c index 395223874e..8a8f51c5d4 100644 --- a/src/ride/ride.c +++ b/src/ride/ride.c @@ -2094,8 +2094,8 @@ track_colour ride_get_track_colour(rct_ride *ride, int colourScheme) vehicle_colour ride_get_vehicle_colour(rct_ride *ride, int vehicleIndex) { vehicle_colour result; - result.main = ride->vehicle_colours[vehicleIndex] & 0xFF; - result.additional_1 = ride->vehicle_colours[vehicleIndex] >> 8; + result.main = ride->vehicle_colours[vehicleIndex].body_colour; + result.additional_1 = ride->vehicle_colours[vehicleIndex].trim_colour; result.additional_2 = ride->vehicle_colours_extended[vehicleIndex]; return result; } diff --git a/src/ride/ride.h b/src/ride/ride.h index ce89235380..64931ecd08 100644 --- a/src/ride/ride.h +++ b/src/ride/ride.h @@ -24,6 +24,7 @@ #include "../common.h" #include "../peep/peep.h" #include "../world/map.h" +#include "vehicle.h" typedef fixed16_2dp ride_rating; @@ -138,7 +139,7 @@ typedef struct { uint16 pad_002; uint8 mode; // 0x004 uint8 colour_scheme_type; // 0x005 - uint16 vehicle_colours[32]; // 0x006 + rct_vehicle_colour vehicle_colours[32]; // 0x006 uint8 pad_046[0x03]; // 0 = closed, 1 = open, 2 = test uint8 status; // 0x049 diff --git a/src/ride/track.c b/src/ride/track.c index 7fa812690b..cfef660c1e 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -522,7 +522,7 @@ rct_track_td6* load_track_design(const char *path) // Read start of track_design read(track_design, &src, 32); - uint8 version = track_design->var_07 >> 2; + uint8 version = track_design->version_and_colour_scheme >> 2; if (version > 2){ free(decoded); @@ -595,11 +595,11 @@ rct_track_td6* load_track_design(const char *path) track_design->type = RIDE_TYPE_WOODEN_ROLLER_COASTER; if (track_design->type == RIDE_TYPE_CORKSCREW_ROLLER_COASTER) { - if (track_design->var_06 == 3) - track_design->var_06 = 35; + if (track_design->ride_mode == RCT1_RIDE_MODE_POWERED_LAUNCH) + track_design->ride_mode = RIDE_MODE_POWERED_LAUNCH; if (track_design->vehicle_type == 79) { - if (track_design->var_06 == 2) - track_design->var_06 = 1; + if (track_design->ride_mode == 2) + track_design->ride_mode = 1; } } @@ -619,7 +619,7 @@ rct_track_td6* load_track_design(const char *path) track_design->space_required_x = 255; track_design->space_required_y = 255; - track_design->var_A2 = 5; + track_design->lift_hill_speed_num_circuits = 5; } track_design->var_50 = min( @@ -820,7 +820,7 @@ int sub_6D2189(int* cost, uint8* ride_id){ user_string_free(old_name); } - uint8 version = track_design->var_07 >> 2; + uint8 version = track_design->version_and_colour_scheme >> 2; if (version == 2){ ride->entrance_style = track_design->entrance_style; @@ -1066,7 +1066,7 @@ rct_track_design *track_get_info(int index, uint8** preview) //RCT2_CALLPROC_X(0x006D1EF0, 0, 0, 0, 0, 0, (int)&trackDesign->preview, 0); trackDesign->track_td6.cost = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_COST, money32); - trackDesign->track_td6.var_06 = RCT2_GLOBAL(0x00F44151, uint8) & 7; + trackDesign->track_td6.track_flags = RCT2_GLOBAL(0x00F44151, uint8) & 7; } // Set preview to correct preview image based on rotation @@ -1295,6 +1295,61 @@ int copy_scenery_to_track(uint8** track_pointer){ return 1; } +int sub_6CE44F(rct_ride* ride){ + rct_track_td6* track_design = RCT2_ADDRESS(0x009D8178, rct_track_td6); + + track_design->type = ride->type; + rct_object_entry_extended* object = &object_entry_groups[OBJECT_TYPE_RIDE].entries[ride->subtype]; + + // Note we are only copying rct_object_entry in size and + // not the extended as we don't need the chunk size. + memcpy(&track_design->vehicle_object, object, sizeof(rct_object_entry)); + + track_design->ride_mode = ride->mode; + + track_design->version_and_colour_scheme = + (ride->colour_scheme_type & 3) | + (1 << 3); // Version .TD6 + + for (int i = 0; i < 32; ++i){ + track_design->vehicle_colours[i] = ride->vehicle_colours[i]; + track_design->vehicle_additional_colour[i] = ride->vehicle_colours_extended[i]; + } + + for (int i = 0; i < 4; ++i){ + track_design->track_spine_colour[i] = ride->track_colour_main[i]; + track_design->track_rail_colour[i] = ride->track_colour_additional[i]; + track_design->track_support_colour[i] = ride->track_colour_supports[i]; + } + + track_design->depart_flags = ride->depart_flags; + track_design->number_of_trains = ride->num_vehicles; + track_design->number_of_cars_per_train = ride->num_cars_per_train; + track_design->min_waiting_time = ride->min_waiting_time; + track_design->max_waiting_time = ride->max_waiting_time; + track_design->var_50 = ride->var_0D0; + track_design->lift_hill_speed_num_circuits = + ride->lift_hill_speed | + (ride->num_circuits << 5); + + track_design->entrance_style = ride->entrance_style; + track_design->max_speed = (sint8)(ride->max_speed / 65536); + track_design->average_speed = (sint8)(ride->average_speed / 65536); + track_design->ride_length = ride_get_total_length(ride) / 65536; + track_design->max_positive_vertical_g = ride->max_positive_vertical_g / 32; + track_design->max_negative_vertical_g = ride->max_negative_vertical_g / 32; + track_design->max_lateral_g = ride->max_lateral_g / 32; + track_design->inversions = ride->inversions; + track_design->drops = ride->drops; + track_design->highest_drop_height = ride->highest_drop_height; + + uint16 total_air_time = (ride->total_air_time * 123) / 1024; + if (total_air_time > 255) + total_air_time = 0; + track_design->total_air_time = (uint8)total_air_time; + //6ce5fd +} + /* rct2: 0x006D2804 & 0x006D264D */ int save_track_design(uint8 rideIndex){ rct_ride* ride = GET_RIDE(rideIndex); @@ -1314,11 +1369,16 @@ int save_track_design(uint8 rideIndex){ return 0; } - if (RCT2_CALLPROC_X(0x006CE44F, 0, 0, 0, rideIndex, 0, 0, 0) & 0x100){ + if (sub_6CE44F(ride)){ window_error_open(3346, RCT2_GLOBAL(0x141E9AC, rct_string_id)); return 0; } + //if (RCT2_CALLPROC_X(0x006CE44F, 0, 0, 0, rideIndex, 0, 0, 0) & 0x100){ + // window_error_open(3346, RCT2_GLOBAL(0x141E9AC, rct_string_id)); + // return 0; + //} + uint8* track_pointer = RCT2_GLOBAL(0x00F44058, uint8*); if (RCT2_GLOBAL(0x009DEA6F, uint8) & 1){ if (!copy_scenery_to_track(&track_pointer)) @@ -1430,7 +1490,7 @@ rct_track_design *temp_track_get_info(char* path, uint8** preview) //RCT2_CALLPROC_X(0x006D1EF0, 0, 0, 0, 0, 0, (int)&trackDesign->preview, 0); trackDesign->track_td6.cost = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_COST, money32); - trackDesign->track_td6.var_06 = RCT2_GLOBAL(0x00F44151, uint8) & 7; + trackDesign->track_td6.track_flags = RCT2_GLOBAL(0x00F44151, uint8) & 7; } // Set preview to correct preview image based on rotation diff --git a/src/ride/track.h b/src/ride/track.h index 29aad1a2dd..68ee024230 100644 --- a/src/ride/track.h +++ b/src/ride/track.h @@ -92,12 +92,6 @@ enum{ #define TRACK_PREVIEW_IMAGE_SIZE (370 * 217) -/* size: 0x2 */ -typedef struct{ - uint8 body_colour; - uint8 trim_colour; -} rct_track_vehicle_colour; - /** * Track design structure. * size: 0x4E72B @@ -106,9 +100,14 @@ typedef struct { uint8 type; // 0x00 uint8 vehicle_type; money32 cost; // 0x02 - uint8 var_06; - uint8 var_07; - rct_track_vehicle_colour vehicle_colours[32]; // 0x08 + union{ + // After loading the track this is converted to + // a flags register + uint8 ride_mode; // 0x06 + uint8 track_flags; // 0x06 + }; + uint8 version_and_colour_scheme; // 0x07 0b0000_VVCC + rct_vehicle_colour vehicle_colours[32]; // 0x08 union{ uint8 pad_48; uint8 track_spine_colour_rct1; // 0x48 @@ -121,16 +120,17 @@ typedef struct { uint8 total_air_time; // 0x4A uint8 track_support_colour_rct1; // 0x4A }; - uint8 pad_4B; + uint8 depart_flags; // 0x4B uint8 number_of_trains; // 0x4C uint8 number_of_cars_per_train; // 0x4D - uint8 pad_4E[2]; + uint8 min_waiting_time; // 0x4E + uint8 max_waiting_time; // 0x4F uint8 var_50; - uint8 max_speed; // 0x51 - uint8 average_speed; // 0x52 + sint8 max_speed; // 0x51 + sint8 average_speed; // 0x52 uint16 ride_length; // 0x53 uint8 max_positive_vertical_g; // 0x55 - sint8 max_negitive_vertical_g; // 0x56 + sint8 max_negative_vertical_g; // 0x56 uint8 max_lateral_g; // 0x57 union { uint8 inversions; // 0x58 @@ -150,7 +150,7 @@ typedef struct { uint8 space_required_x; // 0x80 uint8 space_required_y; // 0x81 uint8 vehicle_additional_colour[32]; // 0x82 - uint8 var_A2; + uint8 lift_hill_speed_num_circuits; // 0xA2 0bCCCL_LLLL } rct_track_td6; typedef struct{ diff --git a/src/ride/vehicle.h b/src/ride/vehicle.h index 28f853ba13..866f52cc08 100644 --- a/src/ride/vehicle.h +++ b/src/ride/vehicle.h @@ -23,6 +23,12 @@ #include "../common.h" +/* size: 0x2 */ +typedef struct{ + uint8 body_colour; + uint8 trim_colour; +} rct_vehicle_colour; + typedef struct { uint8 sprite_identifier; // 0x00 uint8 var_01; diff --git a/src/windows/install_track.c b/src/windows/install_track.c index 7cdb6d7a1e..922ed382f7 100644 --- a/src/windows/install_track.c +++ b/src/windows/install_track.c @@ -201,7 +201,7 @@ static void window_install_track_select(rct_window *w, int index) trackDesign = track_get_info(index, NULL); if (trackDesign == NULL) return; - if (trackDesign->track_td6.var_06 & 4) + if (trackDesign->track_td6.track_flags & 4) window_error_open(STR_THIS_DESIGN_WILL_BE_BUILT_WITH_AN_ALTERNATIVE_VEHICLE_TYPE, -1); window_close(w); @@ -339,7 +339,7 @@ static void window_install_track_paint() RCT2_GLOBAL(0x00F44153, uint8) = 0; // Warnings - if (track_td6->var_06 & 1) { + if (track_td6->track_flags & 1) { RCT2_GLOBAL(0x00F44153, uint8) = 1; if (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_SCENERY_TOGGLE, uint8) == 0) { // Scenery not available @@ -408,7 +408,7 @@ static void window_install_track_paint() y += 10; // Maximum negative verical Gs - gForces = track_td6->max_negitive_vertical_g * 32; + gForces = track_td6->max_negative_vertical_g * 32; gfx_draw_string_left(dpi, STR_MAX_NEGATIVE_VERTICAL_G, &gForces, 0, x, y); y += 10; @@ -417,7 +417,8 @@ static void window_install_track_paint() gfx_draw_string_left(dpi, STR_MAX_LATERAL_G, &gForces, 0, x, y); y += 10; - if (track_td6->var_07 / 4 >= 2) { + // If .TD6 + if (track_td6->version_and_colour_scheme / 4 >= 2) { if (track_td6->total_air_time != 0) { // Total air time airTime = track_td6->total_air_time * 25; diff --git a/src/windows/track_list.c b/src/windows/track_list.c index 9267c94fc3..f36aa355ea 100644 --- a/src/windows/track_list.c +++ b/src/windows/track_list.c @@ -190,7 +190,7 @@ static void window_track_list_select(rct_window *w, int index) trackDesign = track_get_info(index, NULL); if (trackDesign == NULL) return; - if (trackDesign->track_td6.var_06 & 4) + if (trackDesign->track_td6.track_flags & 4) window_error_open(STR_THIS_DESIGN_WILL_BE_BUILT_WITH_AN_ALTERNATIVE_VEHICLE_TYPE, -1); window_close(w); @@ -436,13 +436,13 @@ static void window_track_list_paint() RCT2_GLOBAL(0x00F44153, uint8) = 0; // Warnings - if ((track_td6->var_06 & 4) && !(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER)) { + if ((track_td6->track_flags & 4) && !(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER)) { // Vehicle design not available gfx_draw_string_centred_clipped(dpi, STR_VEHICLE_DESIGN_UNAVAILABLE, NULL, 0, x, y, 368); y -= 10; } - if (track_td6->var_06 & 1) { + if (track_td6->track_flags & 1) { RCT2_GLOBAL(0x00F44153, uint8) = 1; if (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_SCENERY_TOGGLE, uint8) == 0) { // Scenery not available @@ -509,7 +509,7 @@ static void window_track_list_paint() y += 10; // Maximum negative verical Gs - gForces = track_td6->max_negitive_vertical_g * 32; + gForces = track_td6->max_negative_vertical_g * 32; gfx_draw_string_left(dpi, STR_MAX_NEGATIVE_VERTICAL_G, &gForces, 0, x, y); y += 10; @@ -518,7 +518,8 @@ static void window_track_list_paint() gfx_draw_string_left(dpi, STR_MAX_LATERAL_G, &gForces, 0, x, y); y += 10; - if (track_td6->var_07 / 4 >= 2) { + // If .TD6 + if (track_td6->version_and_colour_scheme / 4 >= 2) { if (track_td6->total_air_time != 0) { // Total air time airTime = track_td6->total_air_time * 25; From 9051f1352045f72d320d161e048717c8bf5ff5e0 Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Sun, 26 Apr 2015 16:09:16 +0100 Subject: [PATCH 03/23] Implemented sub_6c683d This is some sort of function that gets the map element of the first part of a track segment. It is also used to update the flashing colour when in construct mode --- src/ride/ride.c | 166 ++++++++++++++++++++++++++++++-- src/ride/ride.h | 2 +- src/ride/ride_ratings.c | 11 ++- src/ride/ride_ratings.h | 1 + src/ride/track.c | 75 +++++++++++++-- src/ride/track.h | 2 +- src/windows/ride_construction.c | 2 +- 7 files changed, 238 insertions(+), 21 deletions(-) diff --git a/src/ride/ride.c b/src/ride/ride.c index 8a8f51c5d4..90be7e46a4 100644 --- a/src/ride/ride.c +++ b/src/ride/ride.c @@ -769,10 +769,164 @@ static void ride_remove_peeps(int rideIndex) ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN; } -int sub_6C683D(int* x, int* y, int z, int direction, int type, int esi, int edi, int ebp) +int sub_6C683D(int* x, int* y, int* z, int direction, int type, uint16 extra_params, rct_map_element* output_element, uint16 flags) { - int ebx = (direction << 8) | type; - return RCT2_CALLFUNC_X(0x006C683D, x, &ebx, y, &z, &esi, &edi, &ebp)&0x100; + //int ebx = (direction << 8) | type; + //return RCT2_CALLFUNC_X(0x006C683D, x, &ebx, y, &z, &esi, &edi, &ebp)&0x100; + + rct_map_element* map_element = map_get_first_element_at(*x / 32, *y / 32); + rct_map_element* success_map = NULL; + + do{ + if (map_element->base_height != *z / 8) + continue; + + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_TRACK) + continue; + + if ((map_element->type & MAP_ELEMENT_DIRECTION_MASK) != direction) + continue; + + if (type != map_element->properties.track.type) + continue; + + success_map = map_element; + if (!(map_element->properties.track.sequence & 0xF)) + break; + }while(!map_element_is_last_for_tile(map_element++)); + + map_element = success_map; + + if (map_element == NULL){ + return 1; + } + + // Possibly z should be &0xF8 + rct_ride* ride = GET_RIDE(map_element->properties.track.ride_index); + rct_preview_track *trackBlock; + + if (RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride->type * 2] & RIDE_TYPE_FLAG_SELLS_FOOD){ + trackBlock = RCT2_ADDRESS(0x00994A38, rct_preview_track*)[type]; + } + else{ + trackBlock = RCT2_ADDRESS(0x00994638, rct_preview_track*)[type]; + } + + int sequence = map_element->properties.track.sequence & 0xF; + + uint8 map_direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK; + + switch (map_direction){ + case MAP_ELEMENT_DIRECTION_WEST: + *x -= trackBlock[sequence].x; + *y -= trackBlock[sequence].y; + break; + case MAP_ELEMENT_DIRECTION_NORTH: + *x -= trackBlock[sequence].y; + *y += trackBlock[sequence].x; + break; + case MAP_ELEMENT_DIRECTION_EAST: + *x += trackBlock[sequence].x; + *y += trackBlock[sequence].y; + break; + case MAP_ELEMENT_DIRECTION_SOUTH: + *x += trackBlock[sequence].y; + *y -= trackBlock[sequence].x; + break; + } + + *z -= trackBlock[sequence].z; + + int start_x = *x, start_y = *y, start_z = *z; + + *z += trackBlock[0].z; + + for (int i = 0; trackBlock[i].var_00 != 0xFF; ++i){ + int cur_x = start_x, cur_y = start_y, cur_z = start_z; + + switch (map_direction){ + case MAP_ELEMENT_DIRECTION_WEST: + cur_x += trackBlock[i].x; + cur_y += trackBlock[i].y; + break; + case MAP_ELEMENT_DIRECTION_NORTH: + cur_x += trackBlock[i].y; + cur_y -= trackBlock[i].x; + break; + case MAP_ELEMENT_DIRECTION_EAST: + cur_x -= trackBlock[i].x; + cur_y -= trackBlock[i].y; + break; + case MAP_ELEMENT_DIRECTION_SOUTH: + cur_x -= trackBlock[i].y; + cur_y += trackBlock[i].x; + break; + } + + cur_z += trackBlock[i].z; + + map_invalidate_tile_full(cur_x, cur_y); + + map_element = map_get_first_element_at(cur_x / 32, cur_y / 32); + success_map = NULL; + + do{ + if (map_element->base_height != cur_z / 8) + continue; + + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_TRACK) + continue; + + if ((map_element->type & MAP_ELEMENT_DIRECTION_MASK) != direction) + continue; + + if ((map_element->properties.track.sequence & 0xF) != trackBlock[i].var_00) + continue; + + if (type == map_element->properties.track.type) + { + success_map = map_element; + break; + } + } while (!map_element_is_last_for_tile(map_element++)); + + if (success_map == NULL){ + return 1; + } + + if (i == 0) + output_element = map_element; + + if (flags & (1 << 0)){ + // Quadrant related ?? + map_element->type &= ~(1 << 6); + } + + if (flags & (1 << 1)){ + // Quadrant related ?? + map_element->type |= (1 << 6); + } + + if (flags & (1 << 2)){ + map_element->properties.track.colour &= 0xFC; + map_element->properties.track.colour |= extra_params & 0xFF; + } + + if (flags & (1 << 5)){ + map_element->properties.track.colour &= 0x0F; + map_element->properties.track.colour |= (extra_params & 0xFF) << 4; + } + + if (flags & (1 << 3)){ + map_element->properties.track.colour |= (1 << 3); + } + + if (flags & (1 << 4)){ + map_element->properties.track.colour &= 0xF7; + } + } + + return 0; } void sub_6C96C0() @@ -785,11 +939,11 @@ void sub_6C9627() switch (RCT2_GLOBAL(0x00F440A6, uint8)) { case 3: { - int x = RCT2_GLOBAL(0x00F440A8, uint16), y = RCT2_GLOBAL(0x00F440AA, uint16); + int x = RCT2_GLOBAL(0x00F440A8, uint16), y = RCT2_GLOBAL(0x00F440AA, uint16), z = RCT2_GLOBAL(0x00F440AC, uint16); sub_6C683D( &x, &y, - RCT2_GLOBAL(0x00F440AC, uint16), + &z, RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) & 3, RCT2_GLOBAL(0x00F440AF, uint8), 0, @@ -969,7 +1123,7 @@ int ride_modify(rct_xy_element *input) direction = mapElement.element->type & 3; type = mapElement.element->properties.track.type; - if (sub_6C683D(&x, &y, z, direction, type, 0, 0, 0)) + if (sub_6C683D(&x, &y, &z, direction, type, 0, 0, 0)) return 0; RCT2_GLOBAL(0x00F440A7, uint8) = rideIndex; diff --git a/src/ride/ride.h b/src/ride/ride.h index 64931ecd08..16751dd589 100644 --- a/src/ride/ride.h +++ b/src/ride/ride.h @@ -754,7 +754,7 @@ void ride_breakdown_add_news_item(int rideIndex); rct_peep *ride_find_closest_mechanic(rct_ride *ride, int forInspection); int sub_6CC3FB(int rideIndex); void sub_6C9627(); -int sub_6C683D(int* x, int* y, int z, int direction, int type, int esi, int edi, int ebp); +int sub_6C683D(int* x, int* y, int* z, int direction, int type, uint16 extra_params, rct_map_element* output_element, uint16 flags); void ride_set_map_tooltip(rct_map_element *mapElement); int ride_music_params_update(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint16 sampleRate, uint32 position, uint8 *tuneId); void ride_music_update_final(); diff --git a/src/ride/ride_ratings.c b/src/ride/ride_ratings.c index 7907654c97..b8d934d554 100644 --- a/src/ride/ride_ratings.c +++ b/src/ride/ride_ratings.c @@ -51,18 +51,19 @@ static void loc_6B5BB2(); static void ride_ratings_calculate(rct_ride *ride); static void ride_ratings_calculate_value(rct_ride *ride); -static int sub_6C6402(rct_map_element *mapElement, int *x, int *y, int *z) +int sub_6C6402(rct_map_element **mapElement, int *x, int *y, int *z) { int eax, ebx, ecx, edx, esi, edi, ebp; eax = *x; ecx = *y; - esi = (int)mapElement; - RCT2_CALLFUNC_X(0x006C6402, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + esi = (int)*mapElement; + int result = RCT2_CALLFUNC_X(0x006C6402, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); *x = *((uint16*)&eax); *y = *((uint16*)&ecx); *z = *((uint8*)&edx); - return 1; + *mapElement = (rct_map_element*)esi; + return result & (0x100); } /** @@ -338,7 +339,7 @@ static void ride_ratings_update_state_5() x = RCT2_GLOBAL(0x0138B584, uint16); y = RCT2_GLOBAL(0x0138B586, uint16); - if (!sub_6C6402(mapElement, &x, &y, &z)) { + if (!sub_6C6402(&mapElement, &x, &y, &z)) { _rideRatingsState = RIDE_RATINGS_STATE_CALCULATE; return; } diff --git a/src/ride/ride_ratings.h b/src/ride/ride_ratings.h index 5baa99e2e9..467b2c23a8 100644 --- a/src/ride/ride_ratings.h +++ b/src/ride/ride_ratings.h @@ -25,5 +25,6 @@ #include "ride.h" void ride_ratings_update_all(); +int sub_6C6402(rct_map_element **mapElement, int *x, int *y, int *z); #endif \ No newline at end of file diff --git a/src/ride/track.c b/src/ride/track.c index cfef660c1e..7afc2e8276 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -29,6 +29,7 @@ #include "../util/util.h" #include "../world/park.h" #include "../windows/error.h" +#include "ride_ratings.h" #include "ride.h" #include "track.h" @@ -1295,7 +1296,8 @@ int copy_scenery_to_track(uint8** track_pointer){ return 1; } -int sub_6CE44F(rct_ride* ride){ +int sub_6CE44F(uint8 rideIndex){ + rct_ride* ride = GET_RIDE(rideIndex); rct_track_td6* track_design = RCT2_ADDRESS(0x009D8178, rct_track_td6); track_design->type = ride->type; @@ -1307,8 +1309,8 @@ int sub_6CE44F(rct_ride* ride){ track_design->ride_mode = ride->mode; - track_design->version_and_colour_scheme = - (ride->colour_scheme_type & 3) | + track_design->version_and_colour_scheme = + (ride->colour_scheme_type & 3) | (1 << 3); // Version .TD6 for (int i = 0; i < 32; ++i){ @@ -1328,8 +1330,8 @@ int sub_6CE44F(rct_ride* ride){ track_design->min_waiting_time = ride->min_waiting_time; track_design->max_waiting_time = ride->max_waiting_time; track_design->var_50 = ride->var_0D0; - track_design->lift_hill_speed_num_circuits = - ride->lift_hill_speed | + track_design->lift_hill_speed_num_circuits = + ride->lift_hill_speed | (ride->num_circuits << 5); track_design->entrance_style = ride->entrance_style; @@ -1347,7 +1349,66 @@ int sub_6CE44F(rct_ride* ride){ if (total_air_time > 255) total_air_time = 0; track_design->total_air_time = (uint8)total_air_time; - //6ce5fd + + track_design->excitement = ride->ratings.excitement / 10; + track_design->intensity = ride->ratings.intensity / 10; + track_design->nausea = ride->ratings.nausea / 10; + + track_design->upkeep_cost = ride->upkeep_cost; + track_design->cost = 0; + track_design->var_6C = 0; + + if (ride->lifecycle_flags & RIDE_LIFECYCLE_SIX_FLAGS) + track_design->var_6C |= (1 << 31); + + uint8* track_elements = RCT2_ADDRESS(0x9D821B, uint8); + memset(track_elements, 0, 8000); + + if (track_design->type == RIDE_TYPE_MAZE){ + //6CEAAE + } + + rct_xy_element trackElement; + if (sub_6CAF80(rideIndex, &trackElement) == 0){ + RCT2_GLOBAL(0x00141E9AC, uint16) = 3347; + return 0; + } + + int x = trackElement.x, y = trackElement.y, z = 0; + rct_map_element* map_element = trackElement.element; + + //6ce69e + + if (!(sub_6C6402(&map_element, &x, &y, &z))){ + trackElement.element = map_element; + trackElement.x = x; + trackElement.y = y; + rct_map_element* initial_map = map_element; + do { + x = trackElement.x; + y = trackElement.y; + map_element = trackElement.element; + if (sub_6C6402(&map_element, &x, &y, &z)){ + break; + } + trackElement.x = x; + trackElement.y = y; + trackElement.element = map_element; + } while (initial_map != trackElement.element); + } + + z = map_element->base_height * 8; + uint8 track_type = map_element->properties.track.type; + uint8 direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK; + RCT2_GLOBAL(0x00F4414D, uint8) = direction; + + if (sub_6C683D(&trackElement.x, &trackElement.y, &z, direction, track_type, 0, 0, 0)){ + RCT2_GLOBAL(0x00141E9AC, uint16) = 3347; + return 0; + } + + + } /* rct2: 0x006D2804 & 0x006D264D */ @@ -1369,7 +1430,7 @@ int save_track_design(uint8 rideIndex){ return 0; } - if (sub_6CE44F(ride)){ + if (!sub_6CE44F(rideIndex)){ window_error_open(3346, RCT2_GLOBAL(0x141E9AC, rct_string_id)); return 0; } diff --git a/src/ride/track.h b/src/ride/track.h index 68ee024230..7e1a431b5b 100644 --- a/src/ride/track.h +++ b/src/ride/track.h @@ -141,7 +141,7 @@ typedef struct { uint8 excitement; // 0x5B uint8 intensity; // 0x5C uint8 nausea; // 0x5D - uint8 pad_5E[2]; + money16 upkeep_cost; // 0x5E uint8 track_spine_colour[4]; // 0x60 uint8 track_rail_colour[4]; // 0x64 uint8 track_support_colour[4]; // 0x68 diff --git a/src/windows/ride_construction.c b/src/windows/ride_construction.c index 4486c5a9a5..15eaef3b6d 100644 --- a/src/windows/ride_construction.c +++ b/src/windows/ride_construction.c @@ -322,7 +322,7 @@ void window_construction_mouseup_demolish(rct_window* w){ ecx = RCT2_GLOBAL(0xF440AA, uint16), edx = RCT2_GLOBAL(0xF440AC, uint16); - sub_6C683D(&eax, &ecx, edx, RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8), RCT2_GLOBAL(0xF440AF, uint8) & 0x3FF, 0, 0, 0); + sub_6C683D(&eax, &ecx, &edx, RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8), RCT2_GLOBAL(0xF440AF, uint8) & 0x3FF, 0, 0, 0); } int ride_id = RCT2_GLOBAL(0xF440A7, uint8); From 7418c74c9ac4b26392136dbebc92d88f0278936d Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Sun, 26 Apr 2015 22:06:08 +0100 Subject: [PATCH 04/23] Finished save track for tracked rides. Still needs mazes to be done. No noticable bugs so far. --- src/ride/ride.c | 15 +++- src/ride/ride.h | 2 +- src/ride/track.c | 213 ++++++++++++++++++++++++++++++++++++++++++++++- src/ride/track.h | 8 ++ 4 files changed, 232 insertions(+), 6 deletions(-) diff --git a/src/ride/ride.c b/src/ride/ride.c index 90be7e46a4..9ea03a1874 100644 --- a/src/ride/ride.c +++ b/src/ride/ride.c @@ -769,7 +769,16 @@ static void ride_remove_peeps(int rideIndex) ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN; } -int sub_6C683D(int* x, int* y, int* z, int direction, int type, uint16 extra_params, rct_map_element* output_element, uint16 flags) +/* rct2: 0x006C683D + * ax : x + * bx : direction << 8, type + * cx : y + * dx : z + * si : extra_params + * di : output_element + * bp : flags + */ +int sub_6C683D(int* x, int* y, int* z, int direction, int type, uint16 extra_params, rct_map_element** output_element, uint16 flags) { //int ebx = (direction << 8) | type; //return RCT2_CALLFUNC_X(0x006C683D, x, &ebx, y, &z, &esi, &edi, &ebp)&0x100; @@ -894,8 +903,8 @@ int sub_6C683D(int* x, int* y, int* z, int direction, int type, uint16 extra_par return 1; } - if (i == 0) - output_element = map_element; + if (i == 0 && output_element != NULL) + *output_element = map_element; if (flags & (1 << 0)){ // Quadrant related ?? diff --git a/src/ride/ride.h b/src/ride/ride.h index 16751dd589..7a196a843a 100644 --- a/src/ride/ride.h +++ b/src/ride/ride.h @@ -754,7 +754,7 @@ void ride_breakdown_add_news_item(int rideIndex); rct_peep *ride_find_closest_mechanic(rct_ride *ride, int forInspection); int sub_6CC3FB(int rideIndex); void sub_6C9627(); -int sub_6C683D(int* x, int* y, int* z, int direction, int type, uint16 extra_params, rct_map_element* output_element, uint16 flags); +int sub_6C683D(int* x, int* y, int* z, int direction, int type, uint16 extra_params, rct_map_element** output_element, uint16 flags); void ride_set_map_tooltip(rct_map_element *mapElement); int ride_music_params_update(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint16 sampleRate, uint32 position, uint8 *tuneId); void ride_music_update_final(); diff --git a/src/ride/track.c b/src/ride/track.c index 7afc2e8276..9e1c8f2562 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -32,6 +32,7 @@ #include "ride_ratings.h" #include "ride.h" #include "track.h" +#include "track_data.h" /** * @@ -745,7 +746,7 @@ void load_track_scenery_objects(){ track_elements++; // Skip entrance exit elements - while (*track_elements != 255) track_elements += 6; + while (*track_elements != 255) track_elements += sizeof(rct_track_entrance); track_elements++; } @@ -1402,13 +1403,221 @@ int sub_6CE44F(uint8 rideIndex){ uint8 direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK; RCT2_GLOBAL(0x00F4414D, uint8) = direction; - if (sub_6C683D(&trackElement.x, &trackElement.y, &z, direction, track_type, 0, 0, 0)){ + if (sub_6C683D(&trackElement.x, &trackElement.y, &z, direction, track_type, 0, &trackElement.element, 0)){ RCT2_GLOBAL(0x00141E9AC, uint16) = 3347; return 0; } + rct_track_coordinates *trackCoordinates = &TrackCoordinates[trackElement.element->properties.track.type]; + // Used in the following loop to know when we have + // completed all of the elements and are back at the + // start. + rct_map_element* initial_map = trackElement.element; + sint16 start_x = trackElement.x; + sint16 start_y = trackElement.y; + sint16 start_z = z + trackCoordinates->z_negative; + RCT2_GLOBAL(0x00F44142, sint16) = start_x; + RCT2_GLOBAL(0x00F44144, sint16) = start_y; + RCT2_GLOBAL(0x00F44146, sint16) = start_z; + rct_track_element* track = (rct_track_element*)track_elements; + do{ + track->type = trackElement.element->properties.track.type; + if (track->type == 0xFF) + track->type = 101; + + if (track->type == TRACK_ELEM_LEFT_VERTICAL_LOOP || + track->type == TRACK_ELEM_RIGHT_VERTICAL_LOOP) + track_design->cost |= (1 << 7); + + if (track->type == TRACK_ELEM_LEFT_TWIST_DOWN_TO_UP || + track->type == TRACK_ELEM_RIGHT_TWIST_DOWN_TO_UP || + track->type == TRACK_ELEM_LEFT_TWIST_UP_TO_DOWN || + track->type == TRACK_ELEM_RIGHT_TWIST_UP_TO_DOWN) + track_design->cost |= (1 << 17); + + if (track->type == TRACK_ELEM_LEFT_BARREL_ROLL_UP_TO_DOWN || + track->type == TRACK_ELEM_RIGHT_BARREL_ROLL_UP_TO_DOWN || + track->type == TRACK_ELEM_LEFT_BARREL_ROLL_DOWN_TO_UP || + track->type == TRACK_ELEM_RIGHT_BARREL_ROLL_DOWN_TO_UP) + track_design->cost |= (1 << 29); + + if (track->type == TRACK_ELEM_HALF_LOOP_UP || + track->type == TRACK_ELEM_HALF_LOOP_DOWN) + track_design->cost |= (1 << 18); + + if (track->type == TRACK_ELEM_LEFT_CORKSCREW_UP || + track->type == TRACK_ELEM_RIGHT_CORKSCREW_UP || + track->type == TRACK_ELEM_LEFT_CORKSCREW_DOWN || + track->type == TRACK_ELEM_RIGHT_CORKSCREW_DOWN) + track_design->cost |= (1 << 19); + + if (track->type == TRACK_ELEM_WATER_SPLASH) + track_design->cost |= (1 << 27); + + if (track->type == TRACK_ELEM_POWERED_LIFT) + track_design->cost |= (1 << 30); + + if (track->type == TRACK_ELEM_LEFT_LARGE_HALF_LOOP_UP || + track->type == TRACK_ELEM_RIGHT_LARGE_HALF_LOOP_UP || + track->type == TRACK_ELEM_RIGHT_LARGE_HALF_LOOP_DOWN || + track->type == TRACK_ELEM_LEFT_LARGE_HALF_LOOP_DOWN) + track_design->cost |= (1 << 31); + + if (track->type == TRACK_ELEM_LOG_FLUME_REVERSER) + track_design->cost |= (1 << 1); + + uint8 bh; + if (track->type == TRACK_ELEM_BRAKES){ + bh = trackElement.element->properties.track.sequence >> 4; + } + else{ + bh = trackElement.element->properties.track.colour >> 4; + } + + uint8 flags = trackElement.element->type & (1 << 7) | bh; + flags |= (trackElement.element->properties.track.colour & 3) << 4; + + if (RCT2_ADDRESS(0x0097D4F2, uint16)[ride->type * 4] & (1 << 3) && + trackElement.element->properties.track.colour & (1<<2)){ + flags |= (1 << 6); + } + + track->flags = flags; + track++; + + if (!track_get_next(&trackElement, &trackElement)) + break; + + z = trackElement.element->base_height * 8; + direction = trackElement.element->type & MAP_ELEMENT_DIRECTION_MASK; + track_type = trackElement.element->properties.track.type; + + if (sub_6C683D(&trackElement.x, &trackElement.y, &z, direction, track_type, 0, &trackElement.element, 0)) + break; + + } while (trackElement.element != initial_map); + + track_elements = (uint8*)track; + // Mark the elements as finished. + *track_elements++ = 0xFF; + + rct_track_entrance* entrance = (rct_track_entrance*)track_elements; + + // First entrances, second exits + for (int i = 0; i < 2; ++i){ + + for (int station_index = 0; station_index < 4; ++station_index){ + + z = ride->station_heights[station_index]; + + uint16 location; + if (i == 0)location = ride->entrances[station_index]; + else location = ride->exits[station_index]; + + if (location == 0xFFFF) + continue; + + x = (location & 0xFF) * 32; + y = ((location & 0xFF00) >> 8) * 32; + + map_element = map_get_first_element_at(x / 32, y / 32); + + do{ + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_ENTRANCE) + continue; + if (map_element->base_height == z) + break; + } while (!map_element_is_last_for_tile(map_element++)); + // Add something that stops this from walking off the end + + uint8 entrance_direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK; + entrance_direction -= RCT2_GLOBAL(0x00F4414D, uint8); + entrance_direction &= MAP_ELEMENT_DIRECTION_MASK; + + entrance->direction = entrance_direction; + + x -= RCT2_GLOBAL(0x00F44142, sint16); + y -= RCT2_GLOBAL(0x00F44144, sint16); + + switch (RCT2_GLOBAL(0x00F4414D, uint8)){ + case MAP_ELEMENT_DIRECTION_WEST: + // Nothing required + break; + case MAP_ELEMENT_DIRECTION_NORTH: + { + int temp_y = -y; + y = x; + x = temp_y; + } + break; + case MAP_ELEMENT_DIRECTION_EAST: + x = -x; + y = -y; + break; + case MAP_ELEMENT_DIRECTION_SOUTH: + { + int temp_x = -x; + x = y; + y = temp_x; + } + break; + } + + entrance->x = x; + entrance->y = y; + + z *= 8; + z -= RCT2_GLOBAL(0x00F44146, sint16); + z /= 8; + + if (z > 127 || z < -126){ + RCT2_GLOBAL(0x00141E9AC, uint16) = 3347; + return 0; + } + + if (z == 0xFF) + z = 0x80; + + entrance->z = z; + + // If this is the exit version + if (i == 1){ + entrance->direction |= (1 << 7); + } + entrance++; + } + } + + track_elements = (uint8*)entrance; + *track_elements++ = 0xFF; + *track_elements++ = 0xFF; + + RCT2_GLOBAL(0x00F44058, uint8*) = track_elements; + + // Previously you had to save start_x, y, z but + // no need since global vars not used + sub_6D01B3(0, 4096, 4096, 0); + + RCT2_GLOBAL(0x009DE58A, sint16) &= 0xFFF9; + RCT2_GLOBAL(0x009DE58A, sint16) &= 0xFFF7; + + x = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) - + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16); + + y = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) - + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16); + + x /= 32; + y /= 32; + x++; + y++; + + track_design->space_required_x = x; + track_design->space_required_y = y; + + return 1; } /* rct2: 0x006D2804 & 0x006D264D */ diff --git a/src/ride/track.h b/src/ride/track.h index 7e1a431b5b..a31ee756a9 100644 --- a/src/ride/track.h +++ b/src/ride/track.h @@ -80,6 +80,14 @@ typedef struct{ uint8 secondary_colour; // 0x15 }rct_track_scenery; +/* Track Entrance entry size: 0x6 */ +typedef struct{ + sint8 z; + uint8 direction; // 0x01 + sint16 x; // 0x02 + sint16 y; // 0x04 +}rct_track_entrance; + enum{ TRACK_ELEMENT_FLAG_CHAIN_LIFT = (1<<7), TRACK_ELEMENT_FLAG_INVERTED = (1<<6), From 64374e5ac4c6a981297d2dbbc94f84277728fa36 Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Tue, 28 Apr 2015 18:42:21 +0100 Subject: [PATCH 05/23] Added maze to td6 code. Small refactor of td6 struct to use flags with a note. Refactor to split up td6 creation code --- src/ride/track.c | 318 ++++++++++++++++++++++++++++++++++++----------- src/ride/track.h | 16 ++- 2 files changed, 257 insertions(+), 77 deletions(-) diff --git a/src/ride/track.c b/src/ride/track.c index 9e1c8f2562..83b8110db2 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -1297,86 +1297,180 @@ int copy_scenery_to_track(uint8** track_pointer){ return 1; } -int sub_6CE44F(uint8 rideIndex){ +/* rct2: 0x006CEAAE */ +int maze_ride_to_td6(uint8 rideIndex, rct_track_td6* track_design, uint8* track_elements){ + rct_map_element* map_element; + uint8 map_found = 0; + + sint16 start_x, start_y; + + for (start_y = 0; start_y < 8192; start_y += 32){ + for (start_x = 0; start_x < 8192; start_x += 32){ + map_element = map_get_first_element_at(start_x / 32, start_y / 32); + + do{ + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_TRACK) + continue; + if (map_element->properties.track.ride_index == rideIndex){ + map_found = 1; + break; + } + } while (!map_element_is_last_for_tile(map_element++)); + + if (map_found) + break; + } + if (map_found) + break; + } + + if (map_found == 0){ + RCT2_GLOBAL(0x00141E9AC, uint16) = 3347; + return 0; + } + + RCT2_GLOBAL(0x00F44142, sint16) = start_x; + RCT2_GLOBAL(0x00F44144, sint16) = start_y; + RCT2_GLOBAL(0x00F44146, sint16) = map_element->base_height * 8; + + rct_maze_element* maze = (rct_maze_element*)track_elements; + + // x is defined here as we can start the search + // on tile start_x, start_y but then the next row + // must restart on 0 + for (sint16 y = start_y, x = start_x; y < 8192; y += 32){ + for (; x < 8192; x += 32){ + map_element = map_get_first_element_at(x / 32, y / 32); + + do{ + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_TRACK) + continue; + if (map_element->properties.track.ride_index != rideIndex) + continue; + + maze->maze_entry = map_element->properties.track.maze_entry; + maze->x = (x - start_x) / 32; + maze->y = (y - start_y) / 32; + maze++; + + if (maze >= RCT2_ADDRESS(0x009DA151, rct_maze_element)){ + RCT2_GLOBAL(0x00141E9AC, uint16) = 3347; + return 0; + } + } while (!map_element_is_last_for_tile(map_element++)); + + } + x = 0; + } + rct_ride* ride = GET_RIDE(rideIndex); - rct_track_td6* track_design = RCT2_ADDRESS(0x009D8178, rct_track_td6); + uint16 location = ride->entrances[0]; - track_design->type = ride->type; - rct_object_entry_extended* object = &object_entry_groups[OBJECT_TYPE_RIDE].entries[ride->subtype]; - - // Note we are only copying rct_object_entry in size and - // not the extended as we don't need the chunk size. - memcpy(&track_design->vehicle_object, object, sizeof(rct_object_entry)); - - track_design->ride_mode = ride->mode; - - track_design->version_and_colour_scheme = - (ride->colour_scheme_type & 3) | - (1 << 3); // Version .TD6 - - for (int i = 0; i < 32; ++i){ - track_design->vehicle_colours[i] = ride->vehicle_colours[i]; - track_design->vehicle_additional_colour[i] = ride->vehicle_colours_extended[i]; + if (location == 0xFFFF){ + RCT2_GLOBAL(0x00141E9AC, uint16) = 3347; + return 0; } - for (int i = 0; i < 4; ++i){ - track_design->track_spine_colour[i] = ride->track_colour_main[i]; - track_design->track_rail_colour[i] = ride->track_colour_additional[i]; - track_design->track_support_colour[i] = ride->track_colour_supports[i]; + sint16 x = (location & 0xFF) * 32; + sint16 y = ((location & 0xFF00) >> 8) * 32; + + map_element = map_get_first_element_at(x / 32, y / 32); + + do{ + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_ENTRANCE) + continue; + if (map_element->properties.entrance.type != ENTRANCE_TYPE_RIDE_ENTRANCE) + continue; + if (map_element->properties.entrance.ride_index == rideIndex) + break; + } while (!map_element_is_last_for_tile(map_element++)); + // Add something that stops this from walking off the end + + uint8 entrance_direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK; + maze->unk_2 = entrance_direction; + maze->type = 8; + + maze->x = (sint8)((x - start_x) / 32); + maze->y = (sint8)((y - start_y) / 32); + + maze++; + + location = ride->exits[0]; + + if (location == 0xFFFF){ + RCT2_GLOBAL(0x00141E9AC, uint16) = 3347; + return 0; } - track_design->depart_flags = ride->depart_flags; - track_design->number_of_trains = ride->num_vehicles; - track_design->number_of_cars_per_train = ride->num_cars_per_train; - track_design->min_waiting_time = ride->min_waiting_time; - track_design->max_waiting_time = ride->max_waiting_time; - track_design->var_50 = ride->var_0D0; - track_design->lift_hill_speed_num_circuits = - ride->lift_hill_speed | - (ride->num_circuits << 5); + x = (location & 0xFF) * 32; + y = ((location & 0xFF00) >> 8) * 32; - track_design->entrance_style = ride->entrance_style; - track_design->max_speed = (sint8)(ride->max_speed / 65536); - track_design->average_speed = (sint8)(ride->average_speed / 65536); - track_design->ride_length = ride_get_total_length(ride) / 65536; - track_design->max_positive_vertical_g = ride->max_positive_vertical_g / 32; - track_design->max_negative_vertical_g = ride->max_negative_vertical_g / 32; - track_design->max_lateral_g = ride->max_lateral_g / 32; - track_design->inversions = ride->inversions; - track_design->drops = ride->drops; - track_design->highest_drop_height = ride->highest_drop_height; + map_element = map_get_first_element_at(x / 32, y / 32); - uint16 total_air_time = (ride->total_air_time * 123) / 1024; - if (total_air_time > 255) - total_air_time = 0; - track_design->total_air_time = (uint8)total_air_time; + do{ + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_ENTRANCE) + continue; + if (map_element->properties.entrance.type != ENTRANCE_TYPE_RIDE_EXIT) + continue; + if (map_element->properties.entrance.ride_index == rideIndex) + break; + } while (!map_element_is_last_for_tile(map_element++)); + // Add something that stops this from walking off the end - track_design->excitement = ride->ratings.excitement / 10; - track_design->intensity = ride->ratings.intensity / 10; - track_design->nausea = ride->ratings.nausea / 10; + uint8 exit_direction = map_element->type & MAP_ELEMENT_DIRECTION_MASK; + maze->unk_2 = exit_direction; + maze->type = 0x80; - track_design->upkeep_cost = ride->upkeep_cost; - track_design->cost = 0; - track_design->var_6C = 0; + maze->x = (sint8)((x - start_x) / 32); + maze->y = (sint8)((y - start_y) / 32); - if (ride->lifecycle_flags & RIDE_LIFECYCLE_SIX_FLAGS) - track_design->var_6C |= (1 << 31); + maze++; - uint8* track_elements = RCT2_ADDRESS(0x9D821B, uint8); - memset(track_elements, 0, 8000); + maze->all = 0; + maze++; - if (track_design->type == RIDE_TYPE_MAZE){ - //6CEAAE - } + track_elements = (uint8*)maze; + *track_elements++ = 0xFF; + + RCT2_GLOBAL(0x00F44058, uint8*) = track_elements; + + // Previously you had to save start_x, y, z but + // no need since global vars not used + sub_6D01B3(0, 4096, 4096, 0); + + RCT2_GLOBAL(0x009DE58A, sint16) &= 0xFFF9; + RCT2_GLOBAL(0x009DE58A, sint16) &= 0xFFF7; + + x = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) - + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16); + + y = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) - + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16); + + x /= 32; + y /= 32; + x++; + y++; + + track_design->space_required_x = (uint8)x; + track_design->space_required_y = (uint8)y; + + return 1; +} + +/* rct2: 0x006CE68D */ +int tracked_ride_to_td6(uint8 rideIndex, rct_track_td6* track_design, uint8* track_elements){ + rct_ride* ride = GET_RIDE(rideIndex); rct_xy_element trackElement; + if (sub_6CAF80(rideIndex, &trackElement) == 0){ RCT2_GLOBAL(0x00141E9AC, uint16) = 3347; return 0; } int x = trackElement.x, y = trackElement.y, z = 0; - rct_map_element* map_element = trackElement.element; + rct_map_element* map_element = trackElement.element; //6ce69e @@ -1408,7 +1502,7 @@ int sub_6CE44F(uint8 rideIndex){ return 0; } - rct_track_coordinates *trackCoordinates = &TrackCoordinates[trackElement.element->properties.track.type]; + const rct_track_coordinates *trackCoordinates = &TrackCoordinates[trackElement.element->properties.track.type]; // Used in the following loop to know when we have // completed all of the elements and are back at the // start. @@ -1429,44 +1523,44 @@ int sub_6CE44F(uint8 rideIndex){ if (track->type == TRACK_ELEM_LEFT_VERTICAL_LOOP || track->type == TRACK_ELEM_RIGHT_VERTICAL_LOOP) - track_design->cost |= (1 << 7); + track_design->flags |= (1 << 7); if (track->type == TRACK_ELEM_LEFT_TWIST_DOWN_TO_UP || track->type == TRACK_ELEM_RIGHT_TWIST_DOWN_TO_UP || track->type == TRACK_ELEM_LEFT_TWIST_UP_TO_DOWN || track->type == TRACK_ELEM_RIGHT_TWIST_UP_TO_DOWN) - track_design->cost |= (1 << 17); + track_design->flags |= (1 << 17); if (track->type == TRACK_ELEM_LEFT_BARREL_ROLL_UP_TO_DOWN || track->type == TRACK_ELEM_RIGHT_BARREL_ROLL_UP_TO_DOWN || track->type == TRACK_ELEM_LEFT_BARREL_ROLL_DOWN_TO_UP || track->type == TRACK_ELEM_RIGHT_BARREL_ROLL_DOWN_TO_UP) - track_design->cost |= (1 << 29); + track_design->flags |= (1 << 29); if (track->type == TRACK_ELEM_HALF_LOOP_UP || track->type == TRACK_ELEM_HALF_LOOP_DOWN) - track_design->cost |= (1 << 18); + track_design->flags |= (1 << 18); if (track->type == TRACK_ELEM_LEFT_CORKSCREW_UP || track->type == TRACK_ELEM_RIGHT_CORKSCREW_UP || track->type == TRACK_ELEM_LEFT_CORKSCREW_DOWN || track->type == TRACK_ELEM_RIGHT_CORKSCREW_DOWN) - track_design->cost |= (1 << 19); + track_design->flags |= (1 << 19); if (track->type == TRACK_ELEM_WATER_SPLASH) - track_design->cost |= (1 << 27); + track_design->flags |= (1 << 27); if (track->type == TRACK_ELEM_POWERED_LIFT) - track_design->cost |= (1 << 30); + track_design->flags |= (1 << 30); if (track->type == TRACK_ELEM_LEFT_LARGE_HALF_LOOP_UP || track->type == TRACK_ELEM_RIGHT_LARGE_HALF_LOOP_UP || track->type == TRACK_ELEM_RIGHT_LARGE_HALF_LOOP_DOWN || track->type == TRACK_ELEM_LEFT_LARGE_HALF_LOOP_DOWN) - track_design->cost |= (1 << 31); + track_design->flags |= (1 << 31); if (track->type == TRACK_ELEM_LOG_FLUME_REVERSER) - track_design->cost |= (1 << 1); + track_design->flags |= (1 << 1); uint8 bh; if (track->type == TRACK_ELEM_BRAKES){ @@ -1476,11 +1570,11 @@ int sub_6CE44F(uint8 rideIndex){ bh = trackElement.element->properties.track.colour >> 4; } - uint8 flags = trackElement.element->type & (1 << 7) | bh; + uint8 flags = trackElement.element->type & (1 << 7) | bh; flags |= (trackElement.element->properties.track.colour & 3) << 4; if (RCT2_ADDRESS(0x0097D4F2, uint16)[ride->type * 4] & (1 << 3) && - trackElement.element->properties.track.colour & (1<<2)){ + trackElement.element->properties.track.colour & (1 << 2)){ flags |= (1 << 6); } @@ -1493,7 +1587,7 @@ int sub_6CE44F(uint8 rideIndex){ z = trackElement.element->base_height * 8; direction = trackElement.element->type & MAP_ELEMENT_DIRECTION_MASK; track_type = trackElement.element->properties.track.type; - + if (sub_6C683D(&trackElement.x, &trackElement.y, &z, direction, track_type, 0, &trackElement.element, 0)) break; @@ -1603,7 +1697,7 @@ int sub_6CE44F(uint8 rideIndex){ RCT2_GLOBAL(0x009DE58A, sint16) &= 0xFFF9; RCT2_GLOBAL(0x009DE58A, sint16) &= 0xFFF7; - x = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) - + x = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16); y = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) - @@ -1620,6 +1714,82 @@ int sub_6CE44F(uint8 rideIndex){ return 1; } +/* rct2: 0x006CE44F */ +int ride_to_td6(uint8 rideIndex){ + rct_ride* ride = GET_RIDE(rideIndex); + rct_track_td6* track_design = RCT2_ADDRESS(0x009D8178, rct_track_td6); + + track_design->type = ride->type; + rct_object_entry_extended* object = &object_entry_groups[OBJECT_TYPE_RIDE].entries[ride->subtype]; + + // Note we are only copying rct_object_entry in size and + // not the extended as we don't need the chunk size. + memcpy(&track_design->vehicle_object, object, sizeof(rct_object_entry)); + + track_design->ride_mode = ride->mode; + + track_design->version_and_colour_scheme = + (ride->colour_scheme_type & 3) | + (1 << 3); // Version .TD6 + + for (int i = 0; i < 32; ++i){ + track_design->vehicle_colours[i] = ride->vehicle_colours[i]; + track_design->vehicle_additional_colour[i] = ride->vehicle_colours_extended[i]; + } + + for (int i = 0; i < 4; ++i){ + track_design->track_spine_colour[i] = ride->track_colour_main[i]; + track_design->track_rail_colour[i] = ride->track_colour_additional[i]; + track_design->track_support_colour[i] = ride->track_colour_supports[i]; + } + + track_design->depart_flags = ride->depart_flags; + track_design->number_of_trains = ride->num_vehicles; + track_design->number_of_cars_per_train = ride->num_cars_per_train; + track_design->min_waiting_time = ride->min_waiting_time; + track_design->max_waiting_time = ride->max_waiting_time; + track_design->var_50 = ride->var_0D0; + track_design->lift_hill_speed_num_circuits = + ride->lift_hill_speed | + (ride->num_circuits << 5); + + track_design->entrance_style = ride->entrance_style; + track_design->max_speed = (sint8)(ride->max_speed / 65536); + track_design->average_speed = (sint8)(ride->average_speed / 65536); + track_design->ride_length = ride_get_total_length(ride) / 65536; + track_design->max_positive_vertical_g = ride->max_positive_vertical_g / 32; + track_design->max_negative_vertical_g = ride->max_negative_vertical_g / 32; + track_design->max_lateral_g = ride->max_lateral_g / 32; + track_design->inversions = ride->inversions; + track_design->drops = ride->drops; + track_design->highest_drop_height = ride->highest_drop_height; + + uint16 total_air_time = (ride->total_air_time * 123) / 1024; + if (total_air_time > 255) + total_air_time = 0; + track_design->total_air_time = (uint8)total_air_time; + + track_design->excitement = ride->ratings.excitement / 10; + track_design->intensity = ride->ratings.intensity / 10; + track_design->nausea = ride->ratings.nausea / 10; + + track_design->upkeep_cost = ride->upkeep_cost; + track_design->flags = 0; + track_design->var_6C = 0; + + if (ride->lifecycle_flags & RIDE_LIFECYCLE_SIX_FLAGS) + track_design->var_6C |= (1 << 31); + + uint8* track_elements = RCT2_ADDRESS(0x9D821B, uint8); + memset(track_elements, 0, 8000); + + if (track_design->type == RIDE_TYPE_MAZE){ + return maze_ride_to_td6(rideIndex, track_design, track_elements); + } + + return tracked_ride_to_td6(rideIndex, track_design, track_elements); +} + /* rct2: 0x006D2804 & 0x006D264D */ int save_track_design(uint8 rideIndex){ rct_ride* ride = GET_RIDE(rideIndex); @@ -1639,7 +1809,7 @@ int save_track_design(uint8 rideIndex){ return 0; } - if (!sub_6CE44F(rideIndex)){ + if (!ride_to_td6(rideIndex)){ window_error_open(3346, RCT2_GLOBAL(0x141E9AC, rct_string_id)); return 0; } diff --git a/src/ride/track.h b/src/ride/track.h index a31ee756a9..8b0e4c869f 100644 --- a/src/ride/track.h +++ b/src/ride/track.h @@ -57,8 +57,13 @@ typedef struct { struct { sint8 x; sint8 y; - uint8 unk_2; - uint8 type; + union{ + uint16 maze_entry; + struct{ + uint8 unk_2; + uint8 type; + }; + }; }; }; } rct_maze_element; @@ -107,7 +112,12 @@ enum{ typedef struct { uint8 type; // 0x00 uint8 vehicle_type; - money32 cost; // 0x02 + union{ + // After loading the track this is converted to + // a cost but before its a flags register + money32 cost; // 0x02 + uint32 flags; // 0x02 + }; union{ // After loading the track this is converted to // a flags register From 66de066901835271f8f6fe4e9e8282579ab48c44 Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Tue, 28 Apr 2015 20:29:03 +0100 Subject: [PATCH 06/23] Added save_track_file. Fixed bugs. Encountered bug where incorrect tracks would be displayed if the loading process failed. Added checksum validation to loading code. Increased the max rle length to match rct2. --- src/ride/track.c | 39 ++++++++++++++++++++++++++++++++++----- src/util/sawyercoding.c | 41 +++++++++++++++++++++++++++++++++++++++-- src/util/sawyercoding.h | 2 ++ 3 files changed, 75 insertions(+), 7 deletions(-) diff --git a/src/ride/track.c b/src/ride/track.c index 83b8110db2..62d3de6608 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -508,7 +508,10 @@ rct_track_td6* load_track_design(const char *path) // Validate the checksum // Not the same checksum algorithm as scenarios and saved games - // sub_6770C1(); + if (!sawyercoding_validate_track_checksum(fpBuffer, fpLength)){ + log_error("Track checksum failed."); + return 0; + } // Decode the track data decoded = malloc(0x10000); @@ -1055,6 +1058,8 @@ rct_track_design *track_get_info(int index, uint8** preview) 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; } @@ -1790,6 +1795,33 @@ int ride_to_td6(uint8 rideIndex){ return tracked_ride_to_td6(rideIndex, track_design, track_elements); } +/* rct2: 0x006771DC but not really its branched from that + * quite far. + */ +int save_track_to_file(rct_track_td6* track_design, char* path){ + window_close_construction_windows(); + + uint8* track_file = malloc(0x8000); + + int length = sawyercoding_encode_td6((char*)track_design, track_file, 0x609F); + + FILE *file; + + log_verbose("saving track %s", path); + file = fopen(path, "wb"); + if (file == NULL) { + free(track_file); + log_error("Failed to save %s", path); + return 0; + } + + fwrite(track_file, length, 1, file); + fclose(file); + free(track_file); + + return 1; +} + /* rct2: 0x006D2804 & 0x006D264D */ int save_track_design(uint8 rideIndex){ rct_ride* ride = GET_RIDE(rideIndex); @@ -1859,10 +1891,7 @@ int save_track_design(uint8 rideIndex){ return 1; } - // Until 0x006771DC is finished we required to copy the path name. - strcpy(RCT2_ADDRESS(0x141EF68, char), path); - // This is the function that actually saves the track to a file - RCT2_CALLPROC_EBPSAFE(0x006771DC); + save_track_to_file(RCT2_ADDRESS(0x009D8178, rct_track_td6), path); ride_list_item item = { .type = 0xFC, .entry_index = 0 }; track_load_list(item); diff --git a/src/util/sawyercoding.c b/src/util/sawyercoding.c index 1388085d32..4caa61697d 100644 --- a/src/util/sawyercoding.c +++ b/src/util/sawyercoding.c @@ -225,6 +225,43 @@ int sawyercoding_decode_td6(char *src, char *dst, int length) return decode_chunk_rle(src, dst, length - 4); } +int sawyercoding_encode_td6(char* src, char* dst, int length){ + int output_length = encode_chunk_rle(src, dst, length); + + uint32 checksum = 0; + for (int i = 0; i < output_length; i++){ + uint8 new_byte = ((checksum & 0xFF) + dst[i]) & 0xFF; + checksum = (checksum & 0xFFFFFF00) + new_byte; + checksum = rol32(checksum, 3); + } + checksum -= 0x1D4C1; + + *((uint32*)&dst[output_length]) = checksum; + output_length += 4; + return output_length; +} + +/* Based off of rct2: 0x006770C1 */ +int sawyercoding_validate_track_checksum(char* src, int length){ + uint32 file_checksum = *((uint32*)&src[length - 4]); + + uint32 checksum = 0; + for (int i = 0; i < length - 4; i++){ + uint8 new_byte = ((checksum & 0xFF) + src[i]) & 0xFF; + checksum = (checksum & 0xFFFFFF00) + new_byte; + checksum = rol32(checksum, 3); + } + + if (checksum - 0x1D4C1 == file_checksum) + return 1; // .TD6 + else if (checksum - 0x1A67C == file_checksum) + return 1; // .TD4 + else if (checksum - 0x1A650 == file_checksum) + return 1; // .TD4 + else + return 0; +} + #pragma region Decoding /** @@ -318,14 +355,14 @@ static int encode_chunk_rle(char *src_buffer, char *dst_buffer, int length) while (src < end_src - 1){ - if ((count && *src == src[1]) || count > 120){ + if ((count && *src == src[1]) || count > 125){ *dst++ = count - 1; for (; count != 0; --count){ *dst++ = *src_norm_start++; } } if (*src == src[1]){ - for (; (count < 120) && ((src + count) < end_src); count++){ + for (; (count < 125) && ((src + count) < end_src); count++){ if (*src != src[count]) break; } *dst++ = 257 - count; diff --git a/src/util/sawyercoding.h b/src/util/sawyercoding.h index f05727180f..a1c702b334 100644 --- a/src/util/sawyercoding.h +++ b/src/util/sawyercoding.h @@ -55,6 +55,8 @@ int sawyercoding_decode_sv4(char *src, char *dst, int length); int sawyercoding_decode_sc4(char *src, char *dst, int length); int sawyercoding_encode_sv4(char *src, char *dst, int length); int sawyercoding_decode_td6(char *src, char *dst, int length); +int sawyercoding_encode_td6(char* src, char* dst, int length); +int sawyercoding_validate_track_checksum(char* src, int length); int sawyercoding_detect_file_type(char *src, int length); From 822c3f6932e117a19de788d0b1decfd9679a840a Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Wed, 29 Apr 2015 19:49:49 +0100 Subject: [PATCH 07/23] Added game_command_place_track Requires extensive testing. Fixed a bug in the tracks.idx that would cause crash on track load fail. --- src/game.c | 5 +- src/game.h | 2 +- src/ride/track.c | 155 ++++++++++++++++++++++++++++++++++++-- src/ride/track.h | 1 + src/windows/track_place.c | 2 +- 5 files changed, 155 insertions(+), 10 deletions(-) diff --git a/src/game.c b/src/game.c index 8d1f6a2473..a5f141b3e5 100644 --- a/src/game.c +++ b/src/game.c @@ -41,6 +41,7 @@ #include "ride/ride.h" #include "ride/ride_ratings.h" #include "ride/vehicle.h" +#include "ride/track.h" #include "scenario.h" #include "title.h" #include "tutorial.h" @@ -921,7 +922,7 @@ static uint32 game_do_command_table[58] = { 0, 0, 0, - 0x006D13FE, + 0, 0, 0x006CDEE4, 0, // 50 @@ -984,7 +985,7 @@ static GAME_COMMAND_POINTER* new_game_command_table[58] = { game_command_remove_large_scenery, game_command_set_current_loan, game_command_set_research_funding, - game_command_emptysub, + game_command_place_track, game_command_start_campaign, game_command_emptysub, game_command_place_banner, // 50 diff --git a/src/game.h b/src/game.h index a60d5cd648..4f736ede2b 100644 --- a/src/game.h +++ b/src/game.h @@ -71,7 +71,7 @@ enum GAME_COMMAND { GAME_COMMAND_REMOVE_LARGE_SCENERY, GAME_COMMAND_SET_CURRENT_LOAN, // 45 GAME_COMMAND_SET_RESEARCH_FUNDING, // 46 - GAME_COMMAND_47, + GAME_COMMAND_PLACE_TRACK, GAME_COMMAND_START_MARKETING_CAMPAIGN, // 48 GAME_COMMAND_49, GAME_COMMAND_PLACE_BANNER, // New banner? (possibly scenery) diff --git a/src/ride/track.c b/src/ride/track.c index 62d3de6608..306e6343fe 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -421,7 +421,9 @@ void track_load_list(ride_list_item item) *new_file_pointer++ = loaded_track->type; } else{ - *new_file_pointer++ = 0xFF; + //*new_file_pointer++ = 0xFF; + // 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); @@ -1846,11 +1848,6 @@ int save_track_design(uint8 rideIndex){ return 0; } - //if (RCT2_CALLPROC_X(0x006CE44F, 0, 0, 0, rideIndex, 0, 0, 0) & 0x100){ - // window_error_open(3346, RCT2_GLOBAL(0x141E9AC, rct_string_id)); - // return 0; - //} - uint8* track_pointer = RCT2_GLOBAL(0x00F44058, uint8*); if (RCT2_GLOBAL(0x009DEA6F, uint8) & 1){ if (!copy_scenery_to_track(&track_pointer)) @@ -2026,4 +2023,150 @@ int install_track(char* source_path, char* dest_name){ subsitute_path(dest_path, RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), dest_name); return platform_file_copy(source_path, dest_path); +} + +/* rct2: 0x006D13FE */ +void game_command_place_track(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp){ + int x = *eax; + int y = *ecx; + int z = *edi; + uint8 flags = *ebx; + + RCT2_GLOBAL(0x009DEA5E, sint16) = x + 16; + RCT2_GLOBAL(0x009DEA60, sint16) = y + 16; + RCT2_GLOBAL(0x009DEA62, sint16) = z; + + if (!(flags & (1 << 3))){ + if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) != 0){ + RCT2_GLOBAL(0x00141E9AC, rct_string_id) = 2214; + *ebx = MONEY32_UNDEFINED; + return; + } + } + + rct_track_td6* track_design = RCT2_ADDRESS(0x009D8178, rct_track_td6); + rct_object_entry* ride_object = &track_design->vehicle_object; + + uint8 entry_type, entry_index; + if (!find_object_in_entry_group(ride_object, &entry_type, &entry_index)){ + entry_index = 0xFF; + } + + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 988; + int rideIndex = 0; + { + int _eax = 0, + _ebx = GAME_COMMAND_FLAG_APPLY, + _ecx = 0, + _edx = track_design->type | (entry_index << 8), + _esi = GAME_COMMAND_6, + _edi = 0, + _ebp = 0; + game_do_command_p(GAME_COMMAND_6, &_eax, &_ebx, &_ecx, &_edx, &_esi, &_edi, &_ebp); + if (_ebx == MONEY32_UNDEFINED){ + *ebx = MONEY32_UNDEFINED; + RCT2_GLOBAL(0x00141F56C, uint8) = 0; + RCT2_GLOBAL(0x00F44121, money32) = MONEY32_UNDEFINED; + return; + } + rideIndex = _edi & 0xFF; + } + + money32 cost = 0; + if (!(flags & GAME_COMMAND_FLAG_APPLY)){ + RCT2_GLOBAL(0x00F44150, uint8) = 0; + cost = sub_6D01B3(1 | (rideIndex << 8), x, y, z); + if (RCT2_GLOBAL(0x00F4414E, uint8) & (1 << 1)){ + RCT2_GLOBAL(0x00F44150, uint8) |= 1 << 7; + cost = sub_6D01B3(0x81 | (rideIndex << 8), x, y, z); + } + } + else{ + uint8 bl = 0; + if (flags & (1 << 6)){ + bl = 4; + } + else{ + bl = 2; + } + bl |= RCT2_GLOBAL(0x00F44150, uint8); + cost = sub_6D01B3(bl | (rideIndex << 8), x, y, z); + } + + if (cost == MONEY32_UNDEFINED || + !(flags & GAME_COMMAND_FLAG_APPLY)){ + rct_string_id error_reason = RCT2_GLOBAL(0x00141E9AC, rct_string_id); + game_do_command(0, GAME_COMMAND_FLAG_APPLY, 0, rideIndex, GAME_COMMAND_7, 0, 0); + *ebx = cost; + RCT2_GLOBAL(0x00141E9AC, rct_string_id) = error_reason; + RCT2_GLOBAL(0x00141F56C, uint8) = 0; + RCT2_GLOBAL(0x00F44121, money32) = cost; + return; + } + + if (entry_index != 0xFF){ + game_do_command(0, GAME_COMMAND_FLAG_APPLY | (2 << 8), 0, rideIndex | (entry_index << 8), GAME_COMMAND_9, 0, 0); + } + + game_do_command(0, GAME_COMMAND_FLAG_APPLY | (track_design->ride_mode << 8), 0, rideIndex | (0 << 8), GAME_COMMAND_SET_RIDE_SETTING, 0, 0); + + game_do_command(0, GAME_COMMAND_FLAG_APPLY | (0 << 8), 0, rideIndex | (track_design->number_of_trains << 8), GAME_COMMAND_9, 0, 0); + + game_do_command(0, GAME_COMMAND_FLAG_APPLY | (1 << 8), 0, rideIndex | (track_design->number_of_cars_per_train << 8), GAME_COMMAND_9, 0, 0); + + game_do_command(0, GAME_COMMAND_FLAG_APPLY | (track_design->depart_flags << 8), 0, rideIndex | (1 << 8), GAME_COMMAND_SET_RIDE_SETTING, 0, 0); + + game_do_command(0, GAME_COMMAND_FLAG_APPLY | (track_design->min_waiting_time << 8), 0, rideIndex | (2 << 8), GAME_COMMAND_SET_RIDE_SETTING, 0, 0); + + game_do_command(0, GAME_COMMAND_FLAG_APPLY | (track_design->max_waiting_time << 8), 0, rideIndex | (3 << 8), GAME_COMMAND_SET_RIDE_SETTING, 0, 0); + + game_do_command(0, GAME_COMMAND_FLAG_APPLY | (track_design->var_50 << 8), 0, rideIndex | (4 << 8), GAME_COMMAND_SET_RIDE_SETTING, 0, 0); + + game_do_command(0, GAME_COMMAND_FLAG_APPLY | ((track_design->lift_hill_speed_num_circuits & 0x1F) << 8), 0, rideIndex | (8 << 8), GAME_COMMAND_SET_RIDE_SETTING, 0, 0); + + uint8 num_circuits = track_design->lift_hill_speed_num_circuits >> 5; + if (num_circuits == 0) num_circuits = 1; + game_do_command(0, GAME_COMMAND_FLAG_APPLY | (num_circuits << 8), 0, rideIndex | (9 << 8), GAME_COMMAND_SET_RIDE_SETTING, 0, 0); + + rct_ride* ride = GET_RIDE(rideIndex); + + ride->lifecycle_flags |= RIDE_LIFECYCLE_18; + + if (track_design->var_6C & (1 << 31)){ + ride->lifecycle_flags |= RIDE_LIFECYCLE_SIX_FLAGS; + } + + ride->colour_scheme_type = track_design->version_and_colour_scheme & 3; + + uint8 version = track_design->version_and_colour_scheme >> 2; + if (version >= 2){ + ride->entrance_style = track_design->entrance_style; + } + + if (version > 1){ + for (int i = 0; i < 4; ++i){ + ride->track_colour_main[i] = track_design->track_spine_colour[i]; + ride->track_colour_additional[i] = track_design->track_rail_colour[i]; + ride->track_colour_supports[i] = track_design->track_support_colour[i]; + } + } + else{ + for (int i = 0; i < 4; ++i){ + ride->track_colour_main[i] = track_design->track_spine_colour_rct1; + ride->track_colour_additional[i] = track_design->track_rail_colour_rct1; + ride->track_colour_supports[i] = track_design->track_support_colour_rct1; + } + } + + for (int i = 0; i < 32; ++i){ + ride->vehicle_colours[i].body_colour = track_design->vehicle_colours[i].body_colour; + ride->vehicle_colours[i].trim_colour = track_design->vehicle_colours[i].trim_colour; + ride->vehicle_colours_extended[i] = track_design->vehicle_additional_colour[i]; + } + + ride_set_name(rideIndex, RCT2_ADDRESS(0x009E3504,const char)); + + RCT2_GLOBAL(0x00141F56C, uint8) = 0; + *ebx = RCT2_GLOBAL(0x00F44121, money32); + *edi = rideIndex; } \ No newline at end of file diff --git a/src/ride/track.h b/src/ride/track.h index 8b0e4c869f..52ebb2c361 100644 --- a/src/ride/track.h +++ b/src/ride/track.h @@ -439,5 +439,6 @@ int sub_6D01B3(int bl, int x, int y, int z); int save_track_design(uint8 rideIndex); int install_track(char* source_path, char* dest_name); void window_track_list_format_name(char *dst, const char *src, char colour, char quotes); +void game_command_place_track(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); #endif diff --git a/src/windows/track_place.c b/src/windows/track_place.c index 9b8d777689..c8fb185a79 100644 --- a/src/windows/track_place.c +++ b/src/windows/track_place.c @@ -354,7 +354,7 @@ static void window_track_place_attempt_placement(int x, int y, int z, int bl, mo ebx = bl; ecx = y; edi = z; - result = game_do_command_p(GAME_COMMAND_47, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + result = game_do_command_p(GAME_COMMAND_PLACE_TRACK, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); if (cost != NULL) *cost = result; if (rideIndex != NULL) *rideIndex = edi & 0xFF; From 7d13cb9ac3888a9ef31233dfe4c8a6081a46b95d Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Thu, 30 Apr 2015 17:56:14 +0100 Subject: [PATCH 08/23] Started track_place --- src/ride/track.c | 137 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/src/ride/track.c b/src/ride/track.c index 306e6343fe..bb7418114e 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -773,13 +773,150 @@ void load_track_scenery_objects(){ * the track preview window to place the whole track. * Depending on the value of bl it modifies the function. * bl == 0, Draw outlines on the ground +* bl == 1, +* bl == 2, * bl == 3, Returns the z value of a succesful placement. Only lower 16 bits are the value, the rest may be garbage? +* bl == 4, * bl == 5, Returns cost to create the track. All 32 bits are used. Places the track. (used by the preview) * bl == 6, Clear white outlined track. * rct2: 0x006D01B3 */ int sub_6D01B3(int bl, int x, int y, int z) { + RCT2_GLOBAL(0x00F4414E, uint8) = bl & 0x80; + RCT2_GLOBAL(0x00F440D4, uint8) = bl & 0x7F; + if (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_SCENERY_TOGGLE, uint8) != 0){ + RCT2_GLOBAL(0x00F4414E, uint8) |= 0x80; + } + RCT2_GLOBAL(0x00F440A7, uint8) = (bl >> 8) & 0xFF; + + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MIN, sint16) = z; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MAX, sint16) = z; + + RCT2_GLOBAL(0x00F44129, uint16) = 0; + + rct_track_td6* track_design = RCT2_ADDRESS(0x009D8178, rct_track_td6); + if (track_design->type == RIDE_TYPE_MAZE){ + // 0x006D1011 + } + + RCT2_GLOBAL(0x00F44142, sint16) = x; + RCT2_GLOBAL(0x00F44144, sint16) = y; + RCT2_GLOBAL(0x00F44146, sint16) = z; + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 0){ + gMapSelectionTiles->x = -1; + RCT2_GLOBAL(0x009DEA48, sint16) = x; + RCT2_GLOBAL(0x009DEA4A, sint16) = y; + + RCT2_GLOBAL(0x009DEA4C, sint16) = map_element_height(x, y) & 0xFFFF; + RCT2_GLOBAL(0x009DEA4E, uint8) = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); + } + + RCT2_GLOBAL(0x00F440D5, uint8) = 0; + uint8 rotation = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); + + uint8* track_elements = RCT2_ADDRESS(0x009D821B, uint8); + + rct_track_element* track = (rct_track_element*)track_elements; + for (; track->type != 0xFF; track++){ + + uint8 track_type = track->type; + if (track_type == TRACK_ELEM_INVERTED_90_DEG_UP_TO_FLAT_QUARTER_LOOP) + track_type = 0xFF; + + if (x < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16) = x; + } + + if (x > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) = x; + } + + if (y < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16) = y; + } + + if (y > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) = y; + } + + if (z < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MIN, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MIN, sint16) = z; + } + + if (z > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MAX, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MAX, sint16) = z; + } + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 0){ + for (rct_preview_track* trackBlock = RCT2_ADDRESS(0x00994638, rct_preview_track*)[track_type]; + trackBlock->var_00 != 0xFF; + trackBlock++){ + + switch (rotation & 3){ + case MAP_ELEMENT_DIRECTION_WEST: + x += trackBlock->x; + y += trackBlock->y; + break; + case MAP_ELEMENT_DIRECTION_NORTH: + x += trackBlock->y; + y -= trackBlock->x; + break; + case MAP_ELEMENT_DIRECTION_EAST: + x -= trackBlock->x; + y -= trackBlock->y; + break; + case MAP_ELEMENT_DIRECTION_SOUTH: + x -= trackBlock->y; + y += trackBlock->x; + break; + } + + if (x < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16) = x; + } + + if (x > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) = x; + } + + if (y < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16) = y; + } + + if (y > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) = y; + } + + uint8 new_tile = 1; + rct_xy16* selectionTile = gMapSelectionTiles; + for (; selectionTile->x != -1; selectionTile++){ + if (selectionTile->x == x && selectionTile->y == y){ + new_tile = 0; + break; + } + if (selectionTile + 1 >= &gMapSelectionTiles[300]){ + new_tile = 0; + break; + } + } + if (new_tile){ + selectionTile->x = x; + selectionTile->y = y; + selectionTile++; + selectionTile->x = -1; + } + } + } + + //6d03d8 + } + int eax, ebx, ecx, edx, esi, edi, ebp; eax = x; ebx = bl; From f3677469647ee9afaa119f1b52e16d9da3428f7a Mon Sep 17 00:00:00 2001 From: Duncan Date: Fri, 1 May 2015 12:52:46 +0100 Subject: [PATCH 09/23] Fix small mistake in flags --- src/ride/track.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ride/track.c b/src/ride/track.c index bb7418114e..f371f8385c 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -1704,7 +1704,7 @@ int tracked_ride_to_td6(uint8 rideIndex, rct_track_td6* track_design, uint8* tra track_design->flags |= (1 << 31); if (track->type == TRACK_ELEM_LOG_FLUME_REVERSER) - track_design->flags |= (1 << 1); + track_design->var_6C |= (1 << 1); uint8 bh; if (track->type == TRACK_ELEM_BRAKES){ @@ -2306,4 +2306,4 @@ void game_command_place_track(int* eax, int* ebx, int* ecx, int* edx, int* esi, RCT2_GLOBAL(0x00141F56C, uint8) = 0; *ebx = RCT2_GLOBAL(0x00F44121, money32); *edi = rideIndex; -} \ No newline at end of file +} From a8912e069640096f3f3e1f1188b8b2824ed7e112 Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Fri, 1 May 2015 18:34:46 +0100 Subject: [PATCH 10/23] Added more of track_place --- src/ride/track.c | 71 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 20 deletions(-) diff --git a/src/ride/track.c b/src/ride/track.c index f371f8385c..06a966479c 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -857,46 +857,49 @@ int sub_6D01B3(int bl, int x, int y, int z) for (rct_preview_track* trackBlock = RCT2_ADDRESS(0x00994638, rct_preview_track*)[track_type]; trackBlock->var_00 != 0xFF; trackBlock++){ + rct_xy16 tile; + tile.x = x; + tile.y = y; switch (rotation & 3){ case MAP_ELEMENT_DIRECTION_WEST: - x += trackBlock->x; - y += trackBlock->y; + tile.x += trackBlock->x; + tile.y += trackBlock->y; break; case MAP_ELEMENT_DIRECTION_NORTH: - x += trackBlock->y; - y -= trackBlock->x; + tile.x += trackBlock->y; + tile.y -= trackBlock->x; break; case MAP_ELEMENT_DIRECTION_EAST: - x -= trackBlock->x; - y -= trackBlock->y; + tile.x -= trackBlock->x; + tile.y -= trackBlock->y; break; case MAP_ELEMENT_DIRECTION_SOUTH: - x -= trackBlock->y; - y += trackBlock->x; + tile.x -= trackBlock->y; + tile.y += trackBlock->x; break; } - if (x < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16)){ - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16) = x; + if (tile.x < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16) = tile.x; } - if (x > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16)){ - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) = x; + if (tile.x > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) = tile.x; } - if (y < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16)){ - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16) = y; + if (tile.y < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16) = tile.y; } - if (y > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16)){ - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) = y; + if (tile.y > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) = tile.y; } uint8 new_tile = 1; rct_xy16* selectionTile = gMapSelectionTiles; for (; selectionTile->x != -1; selectionTile++){ - if (selectionTile->x == x && selectionTile->y == y){ + if (selectionTile->x == tile.x && selectionTile->y == tile.y){ new_tile = 0; break; } @@ -906,15 +909,43 @@ int sub_6D01B3(int bl, int x, int y, int z) } } if (new_tile){ - selectionTile->x = x; - selectionTile->y = y; + selectionTile->x = tile.x; + selectionTile->y = tile.y; selectionTile++; selectionTile->x = -1; } } } - //6d03d8 + if (RCT2_GLOBAL(0x00F440D4, uint8) == 6){ + const rct_track_coordinates* track_coordinates = &TrackCoordinates[track_type]; + + //di + int temp_z = z; + temp_z -= track_coordinates->z_negative; + rct_preview_track* trackBlock = RCT2_ADDRESS(0x00994638, rct_preview_track*)[track_type]; + + temp_z += trackBlock->z; + // rotation in bh + // track_type in dl + game_do_command(x, 0x69 | (rotation & 3) << 8, y, track_type, GAME_COMMAND_4, temp_z, 0); + } + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1 || + RCT2_GLOBAL(0x00F440D4, uint8) == 2 || + RCT2_GLOBAL(0x00F440D4, uint8) == 4 || + RCT2_GLOBAL(0x00F440D4, uint8) == 5){ + const rct_track_coordinates* track_coordinates = &TrackCoordinates[track_type]; + + //di + int temp_z = z; + temp_z -= track_coordinates->z_negative; + uint32 edi = ((track->flags & 0xF) << 17) | + ((track->flags & 0xF) << 28) | + (((track->flags >> 4) & 0x3) << 24); + + //6d0496 + } } int eax, ebx, ecx, edx, esi, edi, ebp; From 69c708b75d2ea867f3f8207632a09bf8cdf9805e Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Sat, 2 May 2015 23:22:45 +0100 Subject: [PATCH 11/23] Added more to track_place --- src/ride/track.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 2 deletions(-) diff --git a/src/ride/track.c b/src/ride/track.c index 06a966479c..a7588c2dcb 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -930,7 +930,7 @@ int sub_6D01B3(int bl, int x, int y, int z) // track_type in dl game_do_command(x, 0x69 | (rotation & 3) << 8, y, track_type, GAME_COMMAND_4, temp_z, 0); } - + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1 || RCT2_GLOBAL(0x00F440D4, uint8) == 2 || RCT2_GLOBAL(0x00F440D4, uint8) == 4 || @@ -944,9 +944,129 @@ int sub_6D01B3(int bl, int x, int y, int z) ((track->flags & 0xF) << 28) | (((track->flags >> 4) & 0x3) << 24); - //6d0496 + int edx = RCT2_GLOBAL(0x00F440A7, uint8) | (track_type << 8); + + if (track->flags & 0x80)edx |= 0x10000; + if (track->flags & 0x40)edx |= 0x20000; + + uint8 bl = 1; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 5)bl = 41; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 105; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1)bl = 0; + + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 927; + money32 cost = game_do_command(x, bl, y, edx, GAME_COMMAND_3, edi, 0); + RCT2_GLOBAL(0x00F440D5, money32) += cost; + + if (cost == MONEY32_UNDEFINED){ + RCT2_GLOBAL(0x00F440D5, money32) = cost; + // 0x006D0FE6 + break; + } + } + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 3){ + for (rct_preview_track* trackBlock = RCT2_ADDRESS(0x00994638, rct_preview_track*)[track_type]; + trackBlock->var_00 != 0xFF; + trackBlock++){ + rct_xy16 tile; + tile.x = x; + tile.y = y; + + switch (rotation & 3){ + case MAP_ELEMENT_DIRECTION_WEST: + tile.x += trackBlock->x; + tile.y += trackBlock->y; + break; + case MAP_ELEMENT_DIRECTION_NORTH: + tile.x += trackBlock->y; + tile.y -= trackBlock->x; + break; + case MAP_ELEMENT_DIRECTION_EAST: + tile.x -= trackBlock->x; + tile.y -= trackBlock->y; + break; + case MAP_ELEMENT_DIRECTION_SOUTH: + tile.x -= trackBlock->y; + tile.y += trackBlock->x; + break; + } + + if (tile.x > 0x1FFF) + continue; + + if (tile.y > 0x1FFF) + continue; + + rct_map_element* map_element = map_get_surface_element_at(tile.x / 32, tile.y / 32); + + int height = map_element->base_height * 8; + if (map_element->properties.surface.slope & 0xF){ + height += 16; + if (map_element->properties.surface.slope & 0x10){ + height += 16; + } + } + + uint8 water_height = 16 * map_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK; + if (water_height){ + if (water_height > height){ + height = water_height; + } + } + int temp_z = z + RCT2_GLOBAL(0x00F440D5, sint16); + temp_z -= height; + + if (temp_z < 0){ + RCT2_GLOBAL(0x00F440D5, sint16) -= temp_z; + } + } + } + + const rct_track_coordinates* track_coordinates = &TrackCoordinates[track_type]; + + switch (rotation & 3){ + case 0: + x += track_coordinates->x; + y += track_coordinates->y; + break; + case 1: + x += track_coordinates->y; + y -= track_coordinates->x; + break; + case 2: + x -= track_coordinates->x; + y -= track_coordinates->y; + break; + case 3: + x -= track_coordinates->y; + y += track_coordinates->x; + break; + } + + z -= track_coordinates->z_negative; + z += track_coordinates->z_positive; + + rotation += track_coordinates->rotation_positive - track_coordinates->rotation_negative; + rotation &= 3; + if (track_coordinates->rotation_positive & (1 << 2)) + rotation |= (1 << 2); + + if (!(rotation & (1 << 2))){ + x += RCT2_ADDRESS(0x00993CCC, sint16)[rotation]; + y += RCT2_ADDRESS(0x00993CCE, sint16)[rotation]; } } + //0x6D06D8 + + //0x6D0FE6 + if (RCT2_GLOBAL(0x00F440D4, uint8) == 0){ + RCT2_GLOBAL(0x009DE58A, uint16) |= 0x6; + RCT2_GLOBAL(0x009DE58A, uint16) &= ~(1<<3); + map_invalidate_map_selection_tiles(); + } + + return RCT2_GLOBAL(0x00F440D5, uint32); int eax, ebx, ecx, edx, esi, edi, ebp; eax = x; From 01eb40de085123d010be5ec8fb48d0705d2fd052 Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Sun, 3 May 2015 11:11:32 +0100 Subject: [PATCH 12/23] Fix bugs in ride placement Tracks should now place and remove correctly. Next task will be entrances/exits followed by scenery. --- src/ride/ride.c | 2 +- src/ride/track.c | 30 +++++++++++++++++++++--------- src/ride/track.h | 2 +- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/ride/ride.c b/src/ride/ride.c index 9ea03a1874..ba190de0af 100644 --- a/src/ride/ride.c +++ b/src/ride/ride.c @@ -3872,7 +3872,7 @@ void game_command_demolish_ride(int *eax, int *ebx, int *ecx, int *edx, int *esi RCT2_CALLPROC_X(0x00696707, 0, 0, 0, ride_id, 0, 0, 0); *ebx = ride_get_refund_price(ride_id); - RCT2_CALLPROC(0x006CB945); + RCT2_CALLPROC_X(0x006CB945, 0, 0, 0, ride_id, 0, 0, 0); news_item_disable_news(NEWS_ITEM_RIDE, ride_id); for(int i = 0; i < MAX_BANNERS; i++){ diff --git a/src/ride/track.c b/src/ride/track.c index a7588c2dcb..0340e7223f 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -817,7 +817,7 @@ int sub_6D01B3(int bl, int x, int y, int z) RCT2_GLOBAL(0x009DEA4E, uint8) = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); } - RCT2_GLOBAL(0x00F440D5, uint8) = 0; + RCT2_GLOBAL(0x00F440D5, uint32) = 0; uint8 rotation = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); uint8* track_elements = RCT2_ADDRESS(0x009D821B, uint8); @@ -928,7 +928,7 @@ int sub_6D01B3(int bl, int x, int y, int z) temp_z += trackBlock->z; // rotation in bh // track_type in dl - game_do_command(x, 0x69 | (rotation & 3) << 8, y, track_type, GAME_COMMAND_4, temp_z, 0); + game_do_command(x, 0x69 | ((rotation & 3) << 8), y, track_type, GAME_COMMAND_4, temp_z, 0); } if (RCT2_GLOBAL(0x00F440D4, uint8) == 1 || @@ -942,7 +942,8 @@ int sub_6D01B3(int bl, int x, int y, int z) temp_z -= track_coordinates->z_negative; uint32 edi = ((track->flags & 0xF) << 17) | ((track->flags & 0xF) << 28) | - (((track->flags >> 4) & 0x3) << 24); + (((track->flags >> 4) & 0x3) << 24)| + (temp_z & 0xFFFF); int edx = RCT2_GLOBAL(0x00F440A7, uint8) | (track_type << 8); @@ -955,7 +956,7 @@ int sub_6D01B3(int bl, int x, int y, int z) if (RCT2_GLOBAL(0x00F440D4, uint8) == 1)bl = 0; RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 927; - money32 cost = game_do_command(x, bl, y, edx, GAME_COMMAND_3, edi, 0); + money32 cost = game_do_command(x, bl | (rotation << 8), y, edx, GAME_COMMAND_3, edi, 0); RCT2_GLOBAL(0x00F440D5, money32) += cost; if (cost == MONEY32_UNDEFINED){ @@ -1024,7 +1025,7 @@ int sub_6D01B3(int bl, int x, int y, int z) } const rct_track_coordinates* track_coordinates = &TrackCoordinates[track_type]; - + rotation &= 3; switch (rotation & 3){ case 0: x += track_coordinates->x; @@ -1053,20 +1054,31 @@ int sub_6D01B3(int bl, int x, int y, int z) rotation |= (1 << 2); if (!(rotation & (1 << 2))){ - x += RCT2_ADDRESS(0x00993CCC, sint16)[rotation]; - y += RCT2_ADDRESS(0x00993CCE, sint16)[rotation]; + x += RCT2_ADDRESS(0x00993CCC, sint16)[rotation * 2]; + y += RCT2_ADDRESS(0x00993CCE, sint16)[rotation * 2]; } } //0x6D06D8 + // 0x6D093D + if (RCT2_GLOBAL(0x00F440D4, uint8) == 6){ + RCT2_CALLPROC_X(0x006CB945, 0, 0, 0, RCT2_GLOBAL(0x00F440A7, uint8), 0, 0, 0); + rct_ride* ride = GET_RIDE(RCT2_GLOBAL(0x00F440A7, uint8)); + user_string_free(ride->name); + ride->type = RIDE_TYPE_NULL; + } + //0x06D0964 + //0x6D0FE6 if (RCT2_GLOBAL(0x00F440D4, uint8) == 0){ RCT2_GLOBAL(0x009DE58A, uint16) |= 0x6; - RCT2_GLOBAL(0x009DE58A, uint16) &= ~(1<<3); + RCT2_GLOBAL(0x009DE58A, uint16) &= ~(1 << 3); map_invalidate_map_selection_tiles(); } - return RCT2_GLOBAL(0x00F440D5, uint32); + if (bl == 3) + return RCT2_GLOBAL(0x00F440D5, sint16); + return RCT2_GLOBAL(0x00F440D5, money32); int eax, ebx, ecx, edx, esi, edi, ebp; eax = x; diff --git a/src/ride/track.h b/src/ride/track.h index 52ebb2c361..d687046020 100644 --- a/src/ride/track.h +++ b/src/ride/track.h @@ -42,7 +42,7 @@ typedef struct { uint8 var_00; sint16 x; // 0x01 sint16 y; // 0x03 - uint16 z; + sint16 z; uint8 pad_07; uint8 var_08; uint8 var_09; From d7db2e27e065d0804dd5c3c8819b718c80781c9b Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Sun, 3 May 2015 13:57:24 +0100 Subject: [PATCH 13/23] Added entrance/exit placement. --- src/ride/track.c | 163 +++++++++++++++++++++++++++++++++++--- src/ride/track.h | 2 +- src/windows/track_place.c | 9 ++- 3 files changed, 160 insertions(+), 14 deletions(-) diff --git a/src/ride/track.c b/src/ride/track.c index 0340e7223f..4725a97d57 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -781,14 +781,14 @@ void load_track_scenery_objects(){ * bl == 6, Clear white outlined track. * rct2: 0x006D01B3 */ -int sub_6D01B3(int bl, int x, int y, int z) +int sub_6D01B3(uint8 bl, uint8 rideIndex, int x, int y, int z) { RCT2_GLOBAL(0x00F4414E, uint8) = bl & 0x80; RCT2_GLOBAL(0x00F440D4, uint8) = bl & 0x7F; if (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_SCENERY_TOGGLE, uint8) != 0){ RCT2_GLOBAL(0x00F4414E, uint8) |= 0x80; } - RCT2_GLOBAL(0x00F440A7, uint8) = (bl >> 8) & 0xFF; + RCT2_GLOBAL(0x00F440A7, uint8) = rideIndex; RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16) = x; RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) = x; @@ -962,6 +962,7 @@ int sub_6D01B3(int bl, int x, int y, int z) if (cost == MONEY32_UNDEFINED){ RCT2_GLOBAL(0x00F440D5, money32) = cost; // 0x006D0FE6 + return cost; break; } } @@ -1058,7 +1059,151 @@ int sub_6D01B3(int bl, int x, int y, int z) y += RCT2_ADDRESS(0x00993CCE, sint16)[rotation * 2]; } } + + // Entrance elements //0x6D06D8 + track_elements = (uint8*)track + 1; + rct_track_entrance* entrance = (rct_track_entrance*)track_elements; + for (; entrance->z != -1; entrance++){ + rotation = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); + x = entrance->x; + y = entrance->y; + + switch (rotation & 3){ + case MAP_ELEMENT_DIRECTION_WEST: + break; + case MAP_ELEMENT_DIRECTION_NORTH:{ + int temp_x = -x; + x = y; + y = temp_x; + } + break; + case MAP_ELEMENT_DIRECTION_EAST: + x = -x; + y = -y; + break; + case MAP_ELEMENT_DIRECTION_SOUTH:{ + int temp_y = -y; + y = x; + x = temp_y; + } + break; + } + + x += RCT2_GLOBAL(0x00F44142, sint16); + y += RCT2_GLOBAL(0x00F44144, sint16); + + + if (x < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16) = x; + } + + if (x > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) = x; + } + + if (y < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16) = y; + } + + if (y > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) = y; + } + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 0){ + uint8 new_tile = 1; + rct_xy16* selectionTile = gMapSelectionTiles; + for (; selectionTile->x != -1; selectionTile++){ + if (selectionTile->x == x && selectionTile->y == y){ + new_tile = 0; + break; + } + if (selectionTile + 1 >= &gMapSelectionTiles[300]){ + new_tile = 0; + break; + } + } + if (new_tile){ + selectionTile->x = x; + selectionTile->y = y; + selectionTile++; + selectionTile->x = -1; + } + } + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1 || + RCT2_GLOBAL(0x00F440D4, uint8) == 2 || + RCT2_GLOBAL(0x00F440D4, uint8) == 4 || + RCT2_GLOBAL(0x00F440D4, uint8) == 5){ + + //bh + rotation += entrance->direction; + rotation &= 3; + + //dh rideIndex is dl + uint8 is_exit = 0; + if (entrance->direction & (1 << 7)){ + is_exit = 1; + } + + if (RCT2_GLOBAL(0x00F440D4, uint8) != 1){ + rct_xy16 tile; + tile.x = x + RCT2_ADDRESS(0x00993CCC, sint16)[rotation * 2]; + tile.y = y + RCT2_ADDRESS(0x00993CCE, sint16)[rotation * 2]; + + rct_map_element* map_element = map_get_first_element_at(tile.x / 32, tile.y / 32); + z = RCT2_GLOBAL(0x00F44146, sint16) / 8; + + z += (entrance->z & (1 << 7)) ? -1 : entrance->z; + + do{ + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_TRACK) + continue; + if (map_element->base_height != z) + continue; + + int di = (map_element->properties.track.sequence >> 4) & 0x7; + uint8 bl = 1; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 5)bl = 41; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 105; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1)bl = 0; + + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 927; + money32 cost = game_do_command(x, bl | (rotation << 8), y, rideIndex | (is_exit << 8), GAME_COMMAND_12, di, 0); + RCT2_GLOBAL(0x00F440D5, money32) += cost; + + if (cost == MONEY32_UNDEFINED){ + RCT2_GLOBAL(0x00F440D5, money32) = cost; + return cost; + // 0x006D0FE6 + break; + } + RCT2_GLOBAL(0x00F4414E, uint8) |= (1 << 0); + break; + } while (!map_element_is_last_for_tile(map_element++)); + } + else{ + //dl + z = (entrance->z & (1 << 7)) ? -1 : entrance->z; + z *= 8; + z += RCT2_GLOBAL(0x00F44146, sint16); + z /= 16; + + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 927; + money32 cost = game_do_command(x, 0 | (rotation << 8), y, z | (is_exit << 8), GAME_COMMAND_12, -1, 0); + RCT2_GLOBAL(0x00F440D5, money32) += cost; + + if (cost == MONEY32_UNDEFINED){ + RCT2_GLOBAL(0x00F440D5, money32) = cost; + return cost; + // 0x006D0FE6 + break; + } + RCT2_GLOBAL(0x00F4414E, uint8) |= (1 << 0); + } + } + } + // 0x6D093D if (RCT2_GLOBAL(0x00F440D4, uint8) == 6){ @@ -1151,7 +1296,7 @@ int sub_6D2189(int* cost, uint8* ride_id){ int map_size = RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE, uint16) << 4; RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8) = 0; - int z = sub_6D01B3(3, map_size, map_size, 16); + int z = sub_6D01B3(3, 0, map_size, map_size, 16); if (RCT2_GLOBAL(0xF4414E, uint8) & 4){ RCT2_GLOBAL(0xF44151, uint8) |= 2; @@ -1164,7 +1309,7 @@ int sub_6D2189(int* cost, uint8* ride_id){ bl |= 0x80; RCT2_GLOBAL(0xF44151, uint8) |= 1; } - edi = sub_6D01B3((*ride_id << 8) | bl, map_size, map_size, z); + edi = sub_6D01B3(bl, *ride_id, map_size, map_size, z); RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) = backup_park_flags; if (edi != MONEY32_UNDEFINED){ @@ -1743,7 +1888,7 @@ int maze_ride_to_td6(uint8 rideIndex, rct_track_td6* track_design, uint8* track_ // Previously you had to save start_x, y, z but // no need since global vars not used - sub_6D01B3(0, 4096, 4096, 0); + sub_6D01B3(0, 0, 4096, 4096, 0); RCT2_GLOBAL(0x009DE58A, sint16) &= 0xFFF9; RCT2_GLOBAL(0x009DE58A, sint16) &= 0xFFF7; @@ -1999,7 +2144,7 @@ int tracked_ride_to_td6(uint8 rideIndex, rct_track_td6* track_design, uint8* tra // Previously you had to save start_x, y, z but // no need since global vars not used - sub_6D01B3(0, 4096, 4096, 0); + sub_6D01B3(0, 0, 4096, 4096, 0); RCT2_GLOBAL(0x009DE58A, sint16) &= 0xFFF9; RCT2_GLOBAL(0x009DE58A, sint16) &= 0xFFF7; @@ -2375,10 +2520,10 @@ void game_command_place_track(int* eax, int* ebx, int* ecx, int* edx, int* esi, money32 cost = 0; if (!(flags & GAME_COMMAND_FLAG_APPLY)){ RCT2_GLOBAL(0x00F44150, uint8) = 0; - cost = sub_6D01B3(1 | (rideIndex << 8), x, y, z); + cost = sub_6D01B3(1, rideIndex, x, y, z); if (RCT2_GLOBAL(0x00F4414E, uint8) & (1 << 1)){ RCT2_GLOBAL(0x00F44150, uint8) |= 1 << 7; - cost = sub_6D01B3(0x81 | (rideIndex << 8), x, y, z); + cost = sub_6D01B3(0x81, rideIndex, x, y, z); } } else{ @@ -2390,7 +2535,7 @@ void game_command_place_track(int* eax, int* ebx, int* ecx, int* edx, int* esi, bl = 2; } bl |= RCT2_GLOBAL(0x00F44150, uint8); - cost = sub_6D01B3(bl | (rideIndex << 8), x, y, z); + cost = sub_6D01B3(bl, rideIndex, x, y, z); } if (cost == MONEY32_UNDEFINED || diff --git a/src/ride/track.h b/src/ride/track.h index d687046020..534b64504a 100644 --- a/src/ride/track.h +++ b/src/ride/track.h @@ -435,7 +435,7 @@ int track_rename(const char *text); int track_delete(); void reset_track_list_cache(); int track_is_connected_by_shape(rct_map_element *a, rct_map_element *b); -int sub_6D01B3(int bl, int x, int y, int z); +int sub_6D01B3(uint8 bl, uint8 rideIndex, int x, int y, int z); int save_track_design(uint8 rideIndex); int install_track(char* source_path, char* dest_name); void window_track_list_format_name(char *dst, const char *src, char colour, char quotes); diff --git a/src/windows/track_place.c b/src/windows/track_place.c index c8fb185a79..da72df7855 100644 --- a/src/windows/track_place.c +++ b/src/windows/track_place.c @@ -308,7 +308,8 @@ static void window_track_place_clear_provisional() { if (_window_track_place_last_was_valid) { sub_6D01B3( - (RCT2_GLOBAL(0x00F440EB, uint8) << 8) | 6, + 6, + RCT2_GLOBAL(0x00F440EB, uint8), _window_track_place_last_valid_x, _window_track_place_last_valid_y, _window_track_place_last_valid_z @@ -342,7 +343,7 @@ static int window_track_place_get_base_z(int x, int y) if (mapElement->properties.surface.terrain & 0x1F) z = max(z, (mapElement->properties.surface.terrain & 0x1F) << 4); - return z + sub_6D01B3(3, x, y, z); + return z + sub_6D01B3(3, 0, x, y, z); } static void window_track_place_attempt_placement(int x, int y, int z, int bl, money32 *cost, uint8 *rideIndex) @@ -477,7 +478,7 @@ static void window_track_place_toolupdate() // Check if tool map position has changed since last update if (x == _window_track_place_last_x && y == _window_track_place_last_y) { - sub_6D01B3(0, x, y, 0); + sub_6D01B3(0, 0, x, y, 0); return; } @@ -510,7 +511,7 @@ static void window_track_place_toolupdate() widget_invalidate(w, WIDX_PRICE); } - sub_6D01B3(0, x, y, z); + sub_6D01B3(0, 0, x, y, z); } /** From 054bc8cac205a9829162e658980bb597ce7fea56 Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Sun, 3 May 2015 17:06:27 +0100 Subject: [PATCH 14/23] Started scenery placement --- src/ride/track.c | 221 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 184 insertions(+), 37 deletions(-) diff --git a/src/ride/track.c b/src/ride/track.c index 4725a97d57..d218cf82eb 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -28,6 +28,7 @@ #include "../util/sawyercoding.h" #include "../util/util.h" #include "../world/park.h" +#include "../world/footpath.h" #include "../windows/error.h" #include "ride_ratings.h" #include "ride.h" @@ -421,7 +422,11 @@ void track_load_list(ride_list_item item) *new_file_pointer++ = loaded_track->type; } else{ - //*new_file_pointer++ = 0xFF; + *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; } @@ -725,47 +730,181 @@ void blank_map(){ /* rct2: 0x006ABDB0 */ 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]; +uint8 entry_index = RCT2_GLOBAL(0xF44157, uint8); +rct_object_entry_extended* object_entry = &object_entry_groups[0].entries[entry_index]; - rct_object_entry* copied_entry = RCT2_ADDRESS(0xF43414, rct_object_entry); - memcpy(copied_entry, object_entry, sizeof(rct_object_entry)); +rct_object_entry* copied_entry = RCT2_ADDRESS(0xF43414, rct_object_entry); +memcpy(copied_entry, object_entry, sizeof(rct_object_entry)); - object_unload_all(); - object_load(-1, copied_entry, 0); - uint8 entry_type; - find_object_in_entry_group(copied_entry, &entry_type, &entry_index); - RCT2_GLOBAL(0xF44157, uint8) = entry_index; +object_unload_all(); +object_load(-1, copied_entry, 0); +uint8 entry_type; +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 = RCT2_ADDRESS(0x009D8178, rct_track_td6); +uint8* track_elements = RCT2_ADDRESS(0x9D821B, uint8); - if (track_design->type == RIDE_TYPE_MAZE){ - // Skip all of the maze track elements - while (*(uint32*)track_elements != 0)track_elements += sizeof(rct_maze_element); - track_elements += sizeof(rct_maze_element); - } - else{ - // Skip track_elements - while (*track_elements != 255) track_elements += sizeof(rct_track_element); - track_elements++; - - // Skip entrance exit elements - while (*track_elements != 255) track_elements += sizeof(rct_track_entrance); - track_elements++; +if (track_design->type == RIDE_TYPE_MAZE){ + // Skip all of the maze track elements + while (*(uint32*)track_elements != 0)track_elements += sizeof(rct_maze_element); + track_elements += sizeof(rct_maze_element); +} +else{ + // Skip track_elements + while (*track_elements != 255) track_elements += sizeof(rct_track_element); + track_elements++; + + // Skip entrance exit elements + while (*track_elements != 255) track_elements += sizeof(rct_track_entrance); + track_elements++; +} + +while (*track_elements != 255){ + rct_track_scenery* scenery_entry = (rct_track_scenery*)track_elements; + + if (!find_object_in_entry_group(&scenery_entry->scenery_object, &entry_type, &entry_index)){ + object_load(-1, &scenery_entry->scenery_object, 0); } + // Skip object and location/direction/colour + track_elements += sizeof(rct_track_scenery); +} - while (*track_elements != 255){ - rct_track_scenery* scenery_entry = (rct_track_scenery*)track_elements; +reset_loaded_objects(); +} - if (!find_object_in_entry_group(&scenery_entry->scenery_object, &entry_type, &entry_index)){ - object_load(-1, &scenery_entry->scenery_object, 0); +/* rct2: 0x006D0964 */ +int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int originX, int originY, int originZ){ + RCT2_GLOBAL(0x00F44050, rct_track_scenery*) = scenery_start; + + // mode + RCT2_GLOBAL(0x00F44154, uint8) = 0; + + for (uint8 mode = 0; mode <= 1; mode++){ + if (scenery_start->scenery_object.flags & 0xFF != 0xFF) + RCT2_GLOBAL(0x00F4414E, uint8) |= 1 << 2; + + if (RCT2_GLOBAL(0x00F4414E, uint8) & (1 << 7)) + continue; + + for (rct_track_scenery* scenery = scenery_start; scenery->scenery_object.flags & 0xFF != 0xFF; scenery++){ + continue; + + uint8 rotation = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); + + rct_xy8 tile = { .x = originX / 32, .y = originY / 32 }; + switch (rotation & 3){ + case MAP_ELEMENT_DIRECTION_WEST: + tile.x += scenery->x; + tile.y += scenery->y; + break; + case MAP_ELEMENT_DIRECTION_NORTH: + tile.x += scenery->y; + tile.y -= scenery->x; + break; + case MAP_ELEMENT_DIRECTION_EAST: + tile.x -= scenery->x; + tile.y -= scenery->y; + break; + case MAP_ELEMENT_DIRECTION_SOUTH: + tile.x -= scenery->y; + tile.y += scenery->x; + break; + } + + rct_xy16 mapCoord = { .x = tile.x * 32, .y = tile.y * 32 }; + if (mapCoord.x < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16) = mapCoord.x; + } + + if (mapCoord.x > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) = mapCoord.x; + } + + if (mapCoord.y < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16) = mapCoord.y; + } + + if (mapCoord.y > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) = mapCoord.y; + } + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 0 && + mode == 0){ + uint8 new_tile = 1; + rct_xy16* selectionTile = gMapSelectionTiles; + for (; selectionTile->x != -1; selectionTile++){ + if (selectionTile->x == tile.x && selectionTile->y == tile.y){ + new_tile = 0; + break; + } + if (selectionTile + 1 >= &gMapSelectionTiles[300]){ + new_tile = 0; + break; + } + } + if (new_tile){ + selectionTile->x = tile.x; + selectionTile->y = tile.y; + selectionTile++; + selectionTile->x = -1; + } + } + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 6 && + mode == 0){ + + uint8 entry_type, entry_index; + if (!find_object_in_entry_group(&scenery->scenery_object, &entry_type, &entry_index)){ + entry_type = scenery->scenery_object.flags & 0xF; + if (entry_type != OBJECT_TYPE_PATHS) + entry_type = 0xFF; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8)&SCREEN_FLAGS_TRACK_DESIGNER) + entry_type = 0xFF; + + entry_index = 0; + for (rct_path_type* path = g_pathTypeEntries; + entry_index < object_entry_group_counts[OBJECT_TYPE_PATHS]; + path = g_pathTypeEntries[entry_index], entry_index++){ + + if (path == (rct_path_type*)-1) + continue; + if (path->flags & (1 << 2)) + continue; + } + + if (entry_index == object_entry_group_counts[OBJECT_TYPE_PATHS]) + entry_type = 0xFF; + } + int z; + switch (entry_type){ + case OBJECT_TYPE_SMALL_SCENERY: + //6d0b51 + break; + case OBJECT_TYPE_LARGE_SCENERY: + //6d0bc6 + break; + case OBJECT_TYPE_WALLS: + z = (scenery->z * 8 + originZ) / 8; + game_do_command( + mapCoord.x, + 0x69, + mapCoord.y, + (z << 8) | ((rotation + scenery->flags) & 0x3), + GAME_COMMAND_REMOVE_FENCE, + 0, + 0); + break; + case OBJECT_TYPE_PATHS: + z = (scenery->z * 8 + originZ) / 8; + footpath_remove(mapCoord.x, mapCoord.y, z, 0x69); + break; + } + } + + // 6d0bf7 } - // Skip object and location/direction/colour - track_elements += sizeof(rct_track_scenery); } - - reset_loaded_objects(); } /** @@ -1204,15 +1343,23 @@ int sub_6D01B3(uint8 bl, uint8 rideIndex, int x, int y, int z) } } - - // 0x6D093D if (RCT2_GLOBAL(0x00F440D4, uint8) == 6){ RCT2_CALLPROC_X(0x006CB945, 0, 0, 0, RCT2_GLOBAL(0x00F440A7, uint8), 0, 0, 0); rct_ride* ride = GET_RIDE(RCT2_GLOBAL(0x00F440A7, uint8)); user_string_free(ride->name); ride->type = RIDE_TYPE_NULL; - } - //0x06D0964 + } + track_elements = (uint8*)entrance + 1; + + // Scenery elements + rct_track_scenery* scenery = (rct_track_scenery*)track_elements; + + track_place_scenery( + scenery, + rideIndex, + RCT2_GLOBAL(0x00F44142, sint16), + RCT2_GLOBAL(0x00F44144, sint16), + RCT2_GLOBAL(0x00F44146, sint16)); //0x6D0FE6 if (RCT2_GLOBAL(0x00F440D4, uint8) == 0){ From 49e02fdab82f6ef0ec3631b4307d01d3610bb4db Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Sun, 3 May 2015 20:31:02 +0100 Subject: [PATCH 15/23] Added more of scenery place --- src/ride/track.c | 49 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/src/ride/track.c b/src/ride/track.c index d218cf82eb..30f0ef7225 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -28,6 +28,7 @@ #include "../util/sawyercoding.h" #include "../util/util.h" #include "../world/park.h" +#include "../world/scenery.h" #include "../world/footpath.h" #include "../windows/error.h" #include "ride_ratings.h" @@ -879,10 +880,46 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o int z; switch (entry_type){ case OBJECT_TYPE_SMALL_SCENERY: - //6d0b51 + //bl + rotation += scenery->flags; + rotation &= 3; + + //bh + uint8 quadrant = (scenery->flags >> 2) + rotation; + quadrant &= 3; + quadrant <<= 6; + + uint8 bh = rotation | (quadrant << 6) | 0xC; + + rct_scenery_entry* small_scenery = g_smallSceneryEntries[entry_index]; + if (!(small_scenery->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE) && + (small_scenery->small_scenery.flags & SMALL_SCENERY_FLAG9)){ + bh = bh; + } + else if (small_scenery->small_scenery.flags & (SMALL_SCENERY_FLAG9 | SMALL_SCENERY_FLAG21 | SMALL_SCENERY_FLAG20)){ + bh &= 0x3F; + } + + z = (scenery->z * 8 + originZ) / 8; + game_do_command( + mapCoord.x, + 0x69 | bh << 8, + mapCoord.y, + (entry_index << 8) | z, + GAME_COMMAND_REMOVE_SCENERY, + 0, + 0); break; case OBJECT_TYPE_LARGE_SCENERY: - //6d0bc6 + z = (scenery->z * 8 + originZ) / 8; + game_do_command( + mapCoord.x, + 0x69 | (((rotation + scenery->flags) & 0x3) << 8), + mapCoord.y, + z, + GAME_COMMAND_REMOVE_LARGE_SCENERY, + 0, + 0); break; case OBJECT_TYPE_WALLS: z = (scenery->z * 8 + originZ) / 8; @@ -902,7 +939,13 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o } } - // 6d0bf7 + if (RCT2_GLOBAL(0x00F440D4, uint8) == 3){ + int z = scenery->z * 8 + originZ; + if (z < RCT2_GLOBAL(0x00F44129, sint16)){ + RCT2_GLOBAL(0x00F44129, sint16) = z; + } + } + // 6d0c23 } } } From ed685688e223d29b1dfd748cb4659027bb3e53a0 Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Mon, 4 May 2015 18:08:22 +0100 Subject: [PATCH 16/23] More scenery_place. There is a bug in the path code --- src/ride/track.c | 122 +++++++++++++++++++++++++++++++++++++++++-- src/world/footpath.c | 3 +- src/world/footpath.h | 2 + src/world/map.c | 16 ++++++ src/world/map.h | 1 + 5 files changed, 139 insertions(+), 5 deletions(-) diff --git a/src/ride/track.c b/src/ride/track.c index 30f0ef7225..3d6457cbb6 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -788,8 +788,7 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o if (RCT2_GLOBAL(0x00F4414E, uint8) & (1 << 7)) continue; - for (rct_track_scenery* scenery = scenery_start; scenery->scenery_object.flags & 0xFF != 0xFF; scenery++){ - continue; + for (rct_track_scenery* scenery = scenery_start; (scenery->scenery_object.flags & 0xFF) != 0xFF; scenery++){ uint8 rotation = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); @@ -945,7 +944,124 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o RCT2_GLOBAL(0x00F44129, sint16) = z; } } - // 6d0c23 + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1 || + RCT2_GLOBAL(0x00F440D4, uint8) == 2 || + RCT2_GLOBAL(0x00F440D4, uint8) == 3 || + RCT2_GLOBAL(0x00F440D4, uint8) == 4 || + RCT2_GLOBAL(0x00F440D4, uint8) == 5){ + + uint8 entry_type, entry_index; + if (!find_object_in_entry_group(&scenery->scenery_object, &entry_type, &entry_index)){ + entry_type = scenery->scenery_object.flags & 0xF; + if (entry_type != OBJECT_TYPE_PATHS){ + RCT2_GLOBAL(0x00F4414E, uint8) |= 1 << 1; + continue; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8)&SCREEN_FLAGS_TRACK_DESIGNER){ + RCT2_GLOBAL(0x00F4414E, uint8) |= 1 << 1; + continue; + } + + entry_index = 0; + for (rct_path_type* path = g_pathTypeEntries; + entry_index < object_entry_group_counts[OBJECT_TYPE_PATHS]; + path = g_pathTypeEntries[entry_index], entry_index++){ + + if (path == (rct_path_type*)-1) + continue; + if (path->flags & (1 << 2)) + continue; + } + + if (entry_index == object_entry_group_counts[OBJECT_TYPE_PATHS]){ + RCT2_GLOBAL(0x00F4414E, uint8) |= 1 << 1; + continue; + } + } + + money32 cost; + + switch (entry_type){ + case OBJECT_TYPE_SMALL_SCENERY: + //6d0e74 + break; + case OBJECT_TYPE_LARGE_SCENERY: + //6d0f0f + break; + case OBJECT_TYPE_WALLS: + //6d0ddf + break; + case OBJECT_TYPE_PATHS: + if (RCT2_GLOBAL(0x00F440D4, uint8) == 3) + continue; + + sint16 z = (scenery->z * 8 + originZ) / 8; + + if (mode == 0){ + if (scenery->flags & (1 << 7)){ + //dh + entry_index |= (1 << 7); + } + + uint8 bh = ((scenery->flags & 0xF) << rotation); + uint8 bl = bh >> 4; + bh = (bh | bl) & 0xF; + bl = (((scenery->flags >> 5) + rotation) & 3) << 5; + bh |= bl; + + bh |= scenery->flags & 0x90; + + bl = 1; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 5)bl = 41; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 105; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1)bl = 0; + + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 927; + cost = game_do_command(mapCoord.x, bl | (bh << 8), mapCoord.y, z, GAME_COMMAND_18, 0, 0); + } + else{ + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1) + continue; + + rct_map_element* map_element = map_get_path_element_at(mapCoord.x / 32, mapCoord.y / 32, z); + + if (map_element == NULL) + continue; + + RCT2_CALLPROC_EBPSAFE(0x006A7594); + sub_6A6AA7(mapCoord.x, mapCoord.y, map_element); + + uint8 bl = 1; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 5)bl = 41; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 105; + + sub_6A6C66(mapCoord.x, mapCoord.y, map_element, bl); + sub_6A759F(); + continue; + } + break; + default: + RCT2_GLOBAL(0x00F4414E, uint8) |= 1 << 1; + continue; + break; + } + RCT2_GLOBAL(0x00F440D5, money32) += cost; + if (RCT2_GLOBAL(0x00F440D4, uint8) != 2){ + if (cost == MONEY32_UNDEFINED){ + RCT2_GLOBAL(0x00F440D5, money32) = MONEY32_UNDEFINED; + } + } + + if (RCT2_GLOBAL(0x00F440D5, money32) != MONEY32_UNDEFINED) + continue; + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 2) + continue; + + return; + } } } } diff --git a/src/world/footpath.c b/src/world/footpath.c index e853ac5645..6c937d7d93 100644 --- a/src/world/footpath.c +++ b/src/world/footpath.c @@ -28,8 +28,7 @@ void sub_673883(int x, int y, int z); void sub_69A48B(int x, int y, int z); -void sub_6A6C66(int x, int y, rct_map_element *mapElement, int flags); -void sub_6A759F(); + enum { FOOTPATH_CONSTRUCTION_FLAG_ALLOW_DURING_PAUSED = 1 << 3 diff --git a/src/world/footpath.h b/src/world/footpath.h index 3745ae05d2..a088e99df7 100644 --- a/src/world/footpath.h +++ b/src/world/footpath.h @@ -49,5 +49,7 @@ void footpath_provisional_update(); void footpath_get_coordinates_from_pos(int screenX, int screenY, int *x, int *y, int *direction, rct_map_element **mapElement); void footpath_bridge_get_info_from_pos(int screenX, int screenY, int *x, int *y, int *direction, rct_map_element **mapElement); void sub_673883(int x, int y, int z); +void sub_6A6C66(int x, int y, rct_map_element *mapElement, int flags); +void sub_6A759F(); #endif diff --git a/src/world/map.c b/src/world/map.c index 2fa984c2a3..5c45910260 100644 --- a/src/world/map.c +++ b/src/world/map.c @@ -174,6 +174,22 @@ rct_map_element *map_get_surface_element_at(int x, int y) return mapElement; } +rct_map_element* map_get_path_element_at(int x, int y, int z){ + rct_map_element *mapElement = map_get_first_element_at(x, y); + + uint8 mapFound = 0; + // Find the path element at known z + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_PATH) + continue; + if (mapElement->base_height != z) + continue; + + return mapElement; + } while (!map_element_is_last_for_tile(mapElement++)); + + return NULL; +} /** * * rct2: 0x0068AB4C diff --git a/src/world/map.h b/src/world/map.h index 6791dae208..98257aef27 100644 --- a/src/world/map.h +++ b/src/world/map.h @@ -256,6 +256,7 @@ void map_element_set_terrain(rct_map_element *element, int terrain); void map_element_set_terrain_edge(rct_map_element *element, int terrain); int map_height_from_slope(int x, int y, int slope); rct_map_element *map_get_surface_element_at(int x, int y); +rct_map_element* map_get_path_element_at(int x, int y, int z); int map_element_height(int x, int y); void sub_68B089(); int map_coord_is_connected(int x, int y, int z, uint8 faceDirection); From 9603e358343b9b17a7e89d62e4e51714e42cf579 Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Tue, 5 May 2015 20:07:35 +0100 Subject: [PATCH 17/23] Fix bugs in path placement --- src/ride/track.c | 89 +++++++++++++++++++++++++----------------------- src/ride/track.h | 2 +- 2 files changed, 47 insertions(+), 44 deletions(-) diff --git a/src/ride/track.c b/src/ride/track.c index 3d6457cbb6..6949129411 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -731,47 +731,47 @@ void blank_map(){ /* rct2: 0x006ABDB0 */ 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]; + uint8 entry_index = RCT2_GLOBAL(0xF44157, uint8); + rct_object_entry_extended* object_entry = &object_entry_groups[0].entries[entry_index]; -rct_object_entry* copied_entry = RCT2_ADDRESS(0xF43414, rct_object_entry); -memcpy(copied_entry, object_entry, sizeof(rct_object_entry)); + rct_object_entry* copied_entry = RCT2_ADDRESS(0xF43414, rct_object_entry); + memcpy(copied_entry, object_entry, sizeof(rct_object_entry)); -object_unload_all(); -object_load(-1, copied_entry, 0); -uint8 entry_type; -find_object_in_entry_group(copied_entry, &entry_type, &entry_index); -RCT2_GLOBAL(0xF44157, uint8) = entry_index; + object_unload_all(); + object_load(-1, copied_entry, 0); + uint8 entry_type; + 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 = RCT2_ADDRESS(0x009D8178, rct_track_td6); + uint8* track_elements = RCT2_ADDRESS(0x9D821B, uint8); -if (track_design->type == RIDE_TYPE_MAZE){ - // Skip all of the maze track elements - while (*(uint32*)track_elements != 0)track_elements += sizeof(rct_maze_element); - track_elements += sizeof(rct_maze_element); -} -else{ - // Skip track_elements - while (*track_elements != 255) track_elements += sizeof(rct_track_element); - track_elements++; - - // Skip entrance exit elements - while (*track_elements != 255) track_elements += sizeof(rct_track_entrance); - track_elements++; -} - -while (*track_elements != 255){ - rct_track_scenery* scenery_entry = (rct_track_scenery*)track_elements; - - if (!find_object_in_entry_group(&scenery_entry->scenery_object, &entry_type, &entry_index)){ - object_load(-1, &scenery_entry->scenery_object, 0); + if (track_design->type == RIDE_TYPE_MAZE){ + // Skip all of the maze track elements + while (*(uint32*)track_elements != 0)track_elements += sizeof(rct_maze_element); + track_elements += sizeof(rct_maze_element); } - // Skip object and location/direction/colour - track_elements += sizeof(rct_track_scenery); -} + else{ + // Skip track_elements + while (*track_elements != 255) track_elements += sizeof(rct_track_element); + track_elements++; -reset_loaded_objects(); + // Skip entrance exit elements + while (*track_elements != 255) track_elements += sizeof(rct_track_entrance); + track_elements++; + } + + while (*track_elements != 255){ + rct_track_scenery* scenery_entry = (rct_track_scenery*)track_elements; + + if (!find_object_in_entry_group(&scenery_entry->scenery_object, &entry_type, &entry_index)){ + object_load(-1, &scenery_entry->scenery_object, 0); + } + // Skip object and location/direction/colour + track_elements += sizeof(rct_track_scenery); + } + + reset_loaded_objects(); } /* rct2: 0x006D0964 */ @@ -782,7 +782,7 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o RCT2_GLOBAL(0x00F44154, uint8) = 0; for (uint8 mode = 0; mode <= 1; mode++){ - if (scenery_start->scenery_object.flags & 0xFF != 0xFF) + if ((scenery_start->scenery_object.flags & 0xFF) != 0xFF) RCT2_GLOBAL(0x00F4414E, uint8) |= 1 << 2; if (RCT2_GLOBAL(0x00F4414E, uint8) & (1 << 7)) @@ -863,7 +863,7 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o entry_type = 0xFF; entry_index = 0; - for (rct_path_type* path = g_pathTypeEntries; + for (rct_path_type* path = g_pathTypeEntries[0]; entry_index < object_entry_group_counts[OBJECT_TYPE_PATHS]; path = g_pathTypeEntries[entry_index], entry_index++){ @@ -939,7 +939,7 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o } if (RCT2_GLOBAL(0x00F440D4, uint8) == 3){ - int z = scenery->z * 8 + originZ; + int z = scenery->z * 8 + RCT2_GLOBAL(0x00F440D5, sint16); if (z < RCT2_GLOBAL(0x00F44129, sint16)){ RCT2_GLOBAL(0x00F44129, sint16) = z; } @@ -965,7 +965,7 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o } entry_index = 0; - for (rct_path_type* path = g_pathTypeEntries; + for (rct_path_type* path = g_pathTypeEntries[0]; entry_index < object_entry_group_counts[OBJECT_TYPE_PATHS]; path = g_pathTypeEntries[entry_index], entry_index++){ @@ -985,12 +985,15 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o switch (entry_type){ case OBJECT_TYPE_SMALL_SCENERY: + cost = 0; //6d0e74 break; case OBJECT_TYPE_LARGE_SCENERY: + cost = 0; //6d0f0f break; case OBJECT_TYPE_WALLS: + cost = 0; //6d0ddf break; case OBJECT_TYPE_PATHS: @@ -1019,7 +1022,7 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o if (RCT2_GLOBAL(0x00F440D4, uint8) == 1)bl = 0; RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 927; - cost = game_do_command(mapCoord.x, bl | (bh << 8), mapCoord.y, z, GAME_COMMAND_18, 0, 0); + cost = game_do_command(mapCoord.x, bl | (bh << 8), mapCoord.y, z | (entry_index << 8), GAME_COMMAND_18, 0, 0); } else{ if (RCT2_GLOBAL(0x00F440D4, uint8) == 1) @@ -1060,7 +1063,7 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o if (RCT2_GLOBAL(0x00F440D4, uint8) == 2) continue; - return; + return 0; } } } @@ -1452,7 +1455,7 @@ int sub_6D01B3(uint8 bl, uint8 rideIndex, int x, int y, int z) rct_map_element* map_element = map_get_first_element_at(tile.x / 32, tile.y / 32); z = RCT2_GLOBAL(0x00F44146, sint16) / 8; - z += (entrance->z & (1 << 7)) ? -1 : entrance->z; + z += (entrance->z == (sint8)0x80) ? -1 : entrance->z; do{ if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_TRACK) @@ -1482,7 +1485,7 @@ int sub_6D01B3(uint8 bl, uint8 rideIndex, int x, int y, int z) } else{ //dl - z = (entrance->z & (1 << 7)) ? -1 : entrance->z; + z = (entrance->z == (sint8)0x80) ? -1 : entrance->z; z *= 8; z += RCT2_GLOBAL(0x00F44146, sint16); z /= 16; diff --git a/src/ride/track.h b/src/ride/track.h index 534b64504a..79dae5ae36 100644 --- a/src/ride/track.h +++ b/src/ride/track.h @@ -79,7 +79,7 @@ typedef struct{ rct_object_entry scenery_object; // 0x00 uint8 x; // 0x10 uint8 y; // 0x11 - uint8 z; // 0x12 + sint8 z; // 0x12 uint8 flags; // 0x13 direction quadrant tertiary colour uint8 primary_colour; // 0x14 uint8 secondary_colour; // 0x15 From ac55dd3e042bbb8202a62d09f68724d225b8223d Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Wed, 6 May 2015 17:58:23 +0100 Subject: [PATCH 18/23] Add wall scenery support --- src/ride/track.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/ride/track.c b/src/ride/track.c index 6949129411..44d40296a7 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -982,6 +982,7 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o } money32 cost; + sint16 z; switch (entry_type){ case OBJECT_TYPE_SMALL_SCENERY: @@ -993,14 +994,40 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o //6d0f0f break; case OBJECT_TYPE_WALLS: - cost = 0; - //6d0ddf + if (mode != 0) + continue; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 3) + continue; + + z = scenery->z * 8 + originZ; + rotation += scenery->flags; + rotation &= 3; + + uint8 bl = 1; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 5)bl = 0xA9; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 105; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1)bl = 0; + + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 1811; + + cost = game_do_command( + mapCoord.x, + bl | (entry_index << 8), + mapCoord.y, + rotation | (scenery->primary_colour << 8), + GAME_COMMAND_41, + z, + scenery->secondary_colour | ((scenery->flags & 0xFC) << 6) + ); + + if (cost == MONEY32_UNDEFINED) + cost = 0; break; case OBJECT_TYPE_PATHS: if (RCT2_GLOBAL(0x00F440D4, uint8) == 3) continue; - sint16 z = (scenery->z * 8 + originZ) / 8; + z = (scenery->z * 8 + originZ) / 8; if (mode == 0){ if (scenery->flags & (1 << 7)){ From 1f02b47a6c2dcbe91ab71fdc34bdb3e5de14f04c Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Mon, 11 May 2015 19:00:43 +0100 Subject: [PATCH 19/23] Implemented large/small scenery placement. Fix bugs. There was a bug that was causing track creation to place scenery items in the incorrect location. This was caused by assuming a global variable was no longer in use. --- src/ride/track.c | 85 +++++++++++++++++++++++++++++++++++++++--------- src/ride/track.h | 4 +-- 2 files changed, 72 insertions(+), 17 deletions(-) diff --git a/src/ride/track.c b/src/ride/track.c index 44d40296a7..76f9f19cd6 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -884,18 +884,17 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o rotation &= 3; //bh - uint8 quadrant = (scenery->flags >> 2) + rotation; + uint8 quadrant = (scenery->flags >> 2) + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); quadrant &= 3; - quadrant <<= 6; - uint8 bh = rotation | (quadrant << 6) | 0xC; + uint8 bh = rotation | (quadrant << 6) | MAP_ELEMENT_TYPE_SCENERY; rct_scenery_entry* small_scenery = g_smallSceneryEntries[entry_index]; if (!(small_scenery->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE) && (small_scenery->small_scenery.flags & SMALL_SCENERY_FLAG9)){ bh = bh; } - else if (small_scenery->small_scenery.flags & (SMALL_SCENERY_FLAG9 | SMALL_SCENERY_FLAG21 | SMALL_SCENERY_FLAG20)){ + else if (small_scenery->small_scenery.flags & (SMALL_SCENERY_FLAG9 | SMALL_SCENERY_FLAG24 | SMALL_SCENERY_FLAG25)){ bh &= 0x3F; } @@ -983,15 +982,68 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o money32 cost; sint16 z; + uint8 bl; switch (entry_type){ case OBJECT_TYPE_SMALL_SCENERY: - cost = 0; - //6d0e74 + if (mode != 0) + continue; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 3) + continue; + + rotation += scenery->flags; + rotation &= 3; + z = scenery->z * 8 + originZ; + uint8 quadrant = ((scenery->flags >> 2) + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8)) & 3; + + bl = 0x81; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 5)bl = 0xA9; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 0xE9; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1)bl = 0x80; + + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 1161; + + cost = game_do_command( + mapCoord.x, + bl | (entry_index << 8), + mapCoord.y, + quadrant | (scenery->primary_colour << 8), + GAME_COMMAND_15, + rotation | (scenery->secondary_colour << 16), + z + ); + + if (cost == MONEY32_UNDEFINED) + cost = 0; break; case OBJECT_TYPE_LARGE_SCENERY: - cost = 0; - //6d0f0f + if (mode != 0) + continue; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 3) + continue; + + rotation += scenery->flags; + rotation &= 3; + + z = scenery->z * 8 + originZ; + + bl = 0x81; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 5)bl = 0xA9; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 0xE9; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1)bl = 0x80; + + cost = game_do_command( + mapCoord.x, + bl | (rotation << 8), + mapCoord.y, + scenery->primary_colour | (scenery->secondary_colour << 8), + GAME_COMMAND_43, + entry_index, + z + ); + + if (cost == MONEY32_UNDEFINED) + cost = 0; break; case OBJECT_TYPE_WALLS: if (mode != 0) @@ -1003,7 +1055,7 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o rotation += scenery->flags; rotation &= 3; - uint8 bl = 1; + bl = 1; if (RCT2_GLOBAL(0x00F440D4, uint8) == 5)bl = 0xA9; if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 105; if (RCT2_GLOBAL(0x00F440D4, uint8) == 1)bl = 0; @@ -1036,7 +1088,7 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o } uint8 bh = ((scenery->flags & 0xF) << rotation); - uint8 bl = bh >> 4; + bl = bh >> 4; bh = (bh | bl) & 0xF; bl = (((scenery->flags >> 5) + rotation) & 3) << 5; bh |= bl; @@ -1063,7 +1115,7 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o RCT2_CALLPROC_EBPSAFE(0x006A7594); sub_6A6AA7(mapCoord.x, mapCoord.y, map_element); - uint8 bl = 1; + bl = 1; if (RCT2_GLOBAL(0x00F440D4, uint8) == 5)bl = 41; if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 105; @@ -2027,8 +2079,8 @@ int copy_scenery_to_track(uint8** track_pointer){ track_scenery->flags &= 0xF0; track_scenery->flags |= (direction & 3) | ((quadrant & 3) << 2); } - int x = track_scenery->x * 32 - RCT2_GLOBAL(0x00F44142, sint16); - int y = track_scenery->y * 32 - RCT2_GLOBAL(0x00F44144, sint16); + int x = ((uint8)track_scenery->x) * 32 - RCT2_GLOBAL(0x00F44142, sint16); + int y = ((uint8)track_scenery->y) * 32 - RCT2_GLOBAL(0x00F44144, sint16); switch (RCT2_GLOBAL(0x00F4414D, uint8)){ case 0: @@ -2478,10 +2530,13 @@ int tracked_ride_to_td6(uint8 rideIndex, rct_track_td6* track_design, uint8* tra RCT2_GLOBAL(0x00F44058, uint8*) = track_elements; - // Previously you had to save start_x, y, z but - // no need since global vars not used sub_6D01B3(0, 0, 4096, 4096, 0); + // Resave global vars for scenery reasons. + RCT2_GLOBAL(0x00F44142, sint16) = start_x; + RCT2_GLOBAL(0x00F44144, sint16) = start_y; + RCT2_GLOBAL(0x00F44146, sint16) = start_z; + RCT2_GLOBAL(0x009DE58A, sint16) &= 0xFFF9; RCT2_GLOBAL(0x009DE58A, sint16) &= 0xFFF7; diff --git a/src/ride/track.h b/src/ride/track.h index 79dae5ae36..18db3dbe53 100644 --- a/src/ride/track.h +++ b/src/ride/track.h @@ -77,8 +77,8 @@ typedef struct{ /* Track Scenery entry size: 0x16 */ typedef struct{ rct_object_entry scenery_object; // 0x00 - uint8 x; // 0x10 - uint8 y; // 0x11 + sint8 x; // 0x10 + sint8 y; // 0x11 sint8 z; // 0x12 uint8 flags; // 0x13 direction quadrant tertiary colour uint8 primary_colour; // 0x14 From fbdc2dad7bdb8b1cc3ea8423c7f216c3ef36a78d Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Tue, 12 May 2015 17:34:36 +0100 Subject: [PATCH 20/23] Added start of maze placement. Refactored slightly. --- src/ride/track.c | 305 ++++++++++++++++++++++++++++------------------- 1 file changed, 181 insertions(+), 124 deletions(-) diff --git a/src/ride/track.c b/src/ride/track.c index 76f9f19cd6..1d22c2da89 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -774,6 +774,32 @@ void load_track_scenery_objects(){ reset_loaded_objects(); } +void track_update_max_min_coordinates(sint16 x, sint16 y, sint16 z){ + if (x < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16) = x; + } + + if (x > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) = x; + } + + if (y < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16) = y; + } + + if (y > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) = y; + } + + if (z < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MIN, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MIN, sint16) = z; + } + + if (z > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MAX, sint16)){ + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MAX, sint16) = z; + } +} + /* rct2: 0x006D0964 */ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int originX, int originY, int originZ){ RCT2_GLOBAL(0x00F44050, rct_track_scenery*) = scenery_start; @@ -813,21 +839,7 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o } rct_xy16 mapCoord = { .x = tile.x * 32, .y = tile.y * 32 }; - if (mapCoord.x < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16)){ - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16) = mapCoord.x; - } - - if (mapCoord.x > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16)){ - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) = mapCoord.x; - } - - if (mapCoord.y < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16)){ - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16) = mapCoord.y; - } - - if (mapCoord.y > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16)){ - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) = mapCoord.y; - } + track_update_max_min_coordinates(mapCoord.x, mapCoord.y, originZ); if (RCT2_GLOBAL(0x00F440D4, uint8) == 0 && mode == 0){ @@ -1146,44 +1158,98 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o } } } + return 1; } -/** -* Places a virtual track. This can involve highlighting the surface tiles and showing the track layout. It is also used by -* the track preview window to place the whole track. -* Depending on the value of bl it modifies the function. -* bl == 0, Draw outlines on the ground -* bl == 1, -* bl == 2, -* bl == 3, Returns the z value of a succesful placement. Only lower 16 bits are the value, the rest may be garbage? -* bl == 4, -* bl == 5, Returns cost to create the track. All 32 bits are used. Places the track. (used by the preview) -* bl == 6, Clear white outlined track. -* rct2: 0x006D01B3 -*/ -int sub_6D01B3(uint8 bl, uint8 rideIndex, int x, int y, int z) +int track_place_maze(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** track_elements) { - RCT2_GLOBAL(0x00F4414E, uint8) = bl & 0x80; - RCT2_GLOBAL(0x00F440D4, uint8) = bl & 0x7F; - if (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_SCENERY_TOGGLE, uint8) != 0){ - RCT2_GLOBAL(0x00F4414E, uint8) |= 0x80; - } - RCT2_GLOBAL(0x00F440A7, uint8) = rideIndex; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 0){ + gMapSelectionTiles->x = -1; + RCT2_GLOBAL(0x009DEA48, sint16) = x; + RCT2_GLOBAL(0x009DEA4A, sint16) = y; - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16) = x; - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) = x; - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16) = y; - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) = y; - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MIN, sint16) = z; - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MAX, sint16) = z; - - RCT2_GLOBAL(0x00F44129, uint16) = 0; - - rct_track_td6* track_design = RCT2_ADDRESS(0x009D8178, rct_track_td6); - if (track_design->type == RIDE_TYPE_MAZE){ - // 0x006D1011 + RCT2_GLOBAL(0x009DEA4C, sint16) = map_element_height(x, y) & 0xFFFF; + RCT2_GLOBAL(0x009DEA4E, uint8) = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); } + uint8 rotation = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); + + rct_maze_element* maze = (rct_maze_element*)(*track_elements); + for (; maze->all != 0; maze++){ + + rct_xy16 mapCoord = { .x = maze->x * 32, .y = maze->y * 32 }; + + switch (rotation & 3){ + case MAP_ELEMENT_DIRECTION_WEST: + break; + case MAP_ELEMENT_DIRECTION_NORTH:{ + int temp_x = -mapCoord.x; + mapCoord.x = mapCoord.y; + mapCoord.y = temp_x; + } + break; + case MAP_ELEMENT_DIRECTION_EAST: + mapCoord.x = -mapCoord.x; + mapCoord.y = -mapCoord.y; + break; + case MAP_ELEMENT_DIRECTION_SOUTH:{ + int temp_y = -mapCoord.y; + mapCoord.y = mapCoord.x; + mapCoord.x = temp_y; + } + break; + } + + mapCoord.x += x; + mapCoord.y += y; + + RCT2_GLOBAL(0x00F44142, sint16) = mapCoord.x; + RCT2_GLOBAL(0x00F44144, sint16) = mapCoord.y; + + track_update_max_min_coordinates(mapCoord.x, mapCoord.y, z); + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 0){ + uint8 new_tile = 1; + rct_xy16* selectionTile = gMapSelectionTiles; + for (; selectionTile->x != -1; selectionTile++){ + if (selectionTile->x == mapCoord.x && selectionTile->y == mapCoord.y){ + new_tile = 0; + break; + } + if (selectionTile + 1 >= &gMapSelectionTiles[300]){ + new_tile = 0; + break; + } + } + if (new_tile){ + selectionTile->x = mapCoord.x; + selectionTile->y = mapCoord.y; + selectionTile++; + selectionTile->x = -1; + } + } + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1 || + RCT2_GLOBAL(0x00F440D4, uint8) == 2 || + RCT2_GLOBAL(0x00F440D4, uint8) == 4 || + RCT2_GLOBAL(0x00F440D4, uint8) == 5){ + switch (maze->type){ + case 0x80: + // exit + break; + case 0x08: + // entrance + break; + default: + + break; + } + } + } +} + +int track_place_ride(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** track_elements) +{ RCT2_GLOBAL(0x00F44142, sint16) = x; RCT2_GLOBAL(0x00F44144, sint16) = y; RCT2_GLOBAL(0x00F44146, sint16) = z; @@ -1200,38 +1266,14 @@ int sub_6D01B3(uint8 bl, uint8 rideIndex, int x, int y, int z) RCT2_GLOBAL(0x00F440D5, uint32) = 0; uint8 rotation = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); - uint8* track_elements = RCT2_ADDRESS(0x009D821B, uint8); - - rct_track_element* track = (rct_track_element*)track_elements; + rct_track_element* track = (rct_track_element*)(*track_elements); for (; track->type != 0xFF; track++){ uint8 track_type = track->type; if (track_type == TRACK_ELEM_INVERTED_90_DEG_UP_TO_FLAT_QUARTER_LOOP) track_type = 0xFF; - if (x < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16)){ - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16) = x; - } - - if (x > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16)){ - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) = x; - } - - if (y < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16)){ - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16) = y; - } - - if (y > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16)){ - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) = y; - } - - if (z < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MIN, sint16)){ - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MIN, sint16) = z; - } - - if (z > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MAX, sint16)){ - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MAX, sint16) = z; - } + track_update_max_min_coordinates(x, y, z); if (RCT2_GLOBAL(0x00F440D4, uint8) == 0){ for (rct_preview_track* trackBlock = RCT2_ADDRESS(0x00994638, rct_preview_track*)[track_type]; @@ -1260,21 +1302,7 @@ int sub_6D01B3(uint8 bl, uint8 rideIndex, int x, int y, int z) break; } - if (tile.x < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16)){ - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16) = tile.x; - } - - if (tile.x > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16)){ - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) = tile.x; - } - - if (tile.y < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16)){ - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16) = tile.y; - } - - if (tile.y > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16)){ - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) = tile.y; - } + track_update_max_min_coordinates(tile.x, tile.y, z); uint8 new_tile = 1; rct_xy16* selectionTile = gMapSelectionTiles; @@ -1322,7 +1350,7 @@ int sub_6D01B3(uint8 bl, uint8 rideIndex, int x, int y, int z) temp_z -= track_coordinates->z_negative; uint32 edi = ((track->flags & 0xF) << 17) | ((track->flags & 0xF) << 28) | - (((track->flags >> 4) & 0x3) << 24)| + (((track->flags >> 4) & 0x3) << 24) | (temp_z & 0xFFFF); int edx = RCT2_GLOBAL(0x00F440A7, uint8) | (track_type << 8); @@ -1341,9 +1369,7 @@ int sub_6D01B3(uint8 bl, uint8 rideIndex, int x, int y, int z) if (cost == MONEY32_UNDEFINED){ RCT2_GLOBAL(0x00F440D5, money32) = cost; - // 0x006D0FE6 - return cost; - break; + return 0; } } @@ -1442,8 +1468,8 @@ int sub_6D01B3(uint8 bl, uint8 rideIndex, int x, int y, int z) // Entrance elements //0x6D06D8 - track_elements = (uint8*)track + 1; - rct_track_entrance* entrance = (rct_track_entrance*)track_elements; + *track_elements = (uint8*)track + 1; + rct_track_entrance* entrance = (rct_track_entrance*)(*track_elements); for (; entrance->z != -1; entrance++){ rotation = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); x = entrance->x; @@ -1474,21 +1500,7 @@ int sub_6D01B3(uint8 bl, uint8 rideIndex, int x, int y, int z) y += RCT2_GLOBAL(0x00F44144, sint16); - if (x < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16)){ - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16) = x; - } - - if (x > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16)){ - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) = x; - } - - if (y < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16)){ - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16) = y; - } - - if (y > RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16)){ - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) = y; - } + track_update_max_min_coordinates(x, y, z); if (RCT2_GLOBAL(0x00F440D4, uint8) == 0){ uint8 new_tile = 1; @@ -1554,9 +1566,7 @@ int sub_6D01B3(uint8 bl, uint8 rideIndex, int x, int y, int z) if (cost == MONEY32_UNDEFINED){ RCT2_GLOBAL(0x00F440D5, money32) = cost; - return cost; - // 0x006D0FE6 - break; + return 0; } RCT2_GLOBAL(0x00F4414E, uint8) |= (1 << 0); break; @@ -1575,9 +1585,7 @@ int sub_6D01B3(uint8 bl, uint8 rideIndex, int x, int y, int z) if (cost == MONEY32_UNDEFINED){ RCT2_GLOBAL(0x00F440D5, money32) = cost; - return cost; - // 0x006D0FE6 - break; + return 0; } RCT2_GLOBAL(0x00F4414E, uint8) |= (1 << 0); } @@ -1589,19 +1597,68 @@ int sub_6D01B3(uint8 bl, uint8 rideIndex, int x, int y, int z) rct_ride* ride = GET_RIDE(RCT2_GLOBAL(0x00F440A7, uint8)); user_string_free(ride->name); ride->type = RIDE_TYPE_NULL; - } - track_elements = (uint8*)entrance + 1; + } + *track_elements = ((uint8*)(entrance)) + 1; + + return 1; +} + +/** +* Places a virtual track. This can involve highlighting the surface tiles and showing the track layout. It is also used by +* the track preview window to place the whole track. +* Depending on the value of bl it modifies the function. +* bl == 0, Draw outlines on the ground +* bl == 1, +* bl == 2, +* bl == 3, Returns the z value of a succesful placement. Only lower 16 bits are the value, the rest may be garbage? +* bl == 4, +* bl == 5, Returns cost to create the track. All 32 bits are used. Places the track. (used by the preview) +* bl == 6, Clear white outlined track. +* rct2: 0x006D01B3 +*/ +int sub_6D01B3(uint8 bl, uint8 rideIndex, int x, int y, int z) +{ + RCT2_GLOBAL(0x00F4414E, uint8) = bl & 0x80; + RCT2_GLOBAL(0x00F440D4, uint8) = bl & 0x7F; + if (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_SCENERY_TOGGLE, uint8) != 0){ + RCT2_GLOBAL(0x00F4414E, uint8) |= 0x80; + } + RCT2_GLOBAL(0x00F440A7, uint8) = rideIndex; + + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MAX, sint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MIN, sint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Y_MAX, sint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MIN, sint16) = z; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MAX, sint16) = z; + + RCT2_GLOBAL(0x00F44129, uint16) = 0; + uint8* track_elements = RCT2_ADDRESS(0x009D821B, uint8); + + rct_track_td6* track_design = RCT2_ADDRESS(0x009D8178, rct_track_td6); + uint8 track_place_success = 0; + + if (track_design->type == RIDE_TYPE_MAZE){ + track_place_success = track_place_maze(x, y, z, rideIndex, &track_elements); + } + else{ + track_place_success = track_place_ride(x, y, z, rideIndex, &track_elements); + } // Scenery elements rct_track_scenery* scenery = (rct_track_scenery*)track_elements; - track_place_scenery( - scenery, - rideIndex, - RCT2_GLOBAL(0x00F44142, sint16), - RCT2_GLOBAL(0x00F44144, sint16), - RCT2_GLOBAL(0x00F44146, sint16)); - + if (track_place_success){ + if (!track_place_scenery( + scenery, + rideIndex, + RCT2_GLOBAL(0x00F44142, sint16), + RCT2_GLOBAL(0x00F44144, sint16), + RCT2_GLOBAL(0x00F44146, sint16))){ + return RCT2_GLOBAL(0x00F440D5, money32); + } + } + //0x6D0FE6 if (RCT2_GLOBAL(0x00F440D4, uint8) == 0){ RCT2_GLOBAL(0x009DE58A, uint16) |= 0x6; From 88a43b34b0bbda04e60e1d0431aacbd04b71bda8 Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Wed, 13 May 2015 19:18:34 +0100 Subject: [PATCH 21/23] Finish maze track placement Fixed bugs related with maze placement as well. --- src/ride/track.c | 106 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 98 insertions(+), 8 deletions(-) diff --git a/src/ride/track.c b/src/ride/track.c index 1d22c2da89..a99fc1b884 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -1172,11 +1172,11 @@ int track_place_maze(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** trac RCT2_GLOBAL(0x009DEA4E, uint8) = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); } - uint8 rotation = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); + RCT2_GLOBAL(0x00F440D5, uint32) = 0; rct_maze_element* maze = (rct_maze_element*)(*track_elements); for (; maze->all != 0; maze++){ - + uint8 rotation = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint8); rct_xy16 mapCoord = { .x = maze->x * 32, .y = maze->y * 32 }; switch (rotation & 3){ @@ -1203,9 +1203,6 @@ int track_place_maze(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** trac mapCoord.x += x; mapCoord.y += y; - RCT2_GLOBAL(0x00F44142, sint16) = mapCoord.x; - RCT2_GLOBAL(0x00F44144, sint16) = mapCoord.y; - track_update_max_min_coordinates(mapCoord.x, mapCoord.y, z); if (RCT2_GLOBAL(0x00F440D4, uint8) == 0){ @@ -1233,19 +1230,112 @@ int track_place_maze(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** trac RCT2_GLOBAL(0x00F440D4, uint8) == 2 || RCT2_GLOBAL(0x00F440D4, uint8) == 4 || RCT2_GLOBAL(0x00F440D4, uint8) == 5){ + + uint8 bl; + money32 cost = 0; + uint16 maze_entry; + switch (maze->type){ - case 0x80: - // exit - break; case 0x08: // entrance + rotation += maze->unk_2; + rotation &= 3; + + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 927; + + bl = 1; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 0x69; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1){ + cost = game_do_command(mapCoord.x, 0 | rotation << 8, mapCoord.y, (z / 16) & 0xFF, GAME_COMMAND_12, -1, 0); + } + else{ + cost = game_do_command(mapCoord.x, bl | rotation << 8, mapCoord.y, rideIndex, GAME_COMMAND_12, 0, 0); + } + if (cost != MONEY32_UNDEFINED){ + RCT2_GLOBAL(0x00F4414E, uint8) |= (1 << 0); + } + break; + case 0x80: + // exit + rotation += maze->unk_2; + rotation &= 3; + + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 927; + + bl = 1; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 0x69; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1){ + cost = game_do_command(mapCoord.x, 0 | rotation << 8, mapCoord.y, ((z / 16) & 0xFF) | (1 << 8), GAME_COMMAND_12, -1, 0); + } + else{ + cost = game_do_command(mapCoord.x, bl | rotation << 8, mapCoord.y, rideIndex | (1 << 8), GAME_COMMAND_12, 0, 0); + } + if (cost != MONEY32_UNDEFINED){ + RCT2_GLOBAL(0x00F4414E, uint8) |= (1 << 0); + } break; default: + maze_entry = rol16(maze->maze_entry, rotation * 4); + bl = 1; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 5)bl = 0x29; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 0x69; + if (RCT2_GLOBAL(0x00F440D4, uint8) == 1)bl = 0; + + RCT2_GLOBAL(0x00141E9AE, rct_string_id) = 927; + + cost = game_do_command(mapCoord.x, bl | (maze_entry & 0xFF) << 8, mapCoord.y, rideIndex | (maze_entry & 0xFF00), GAME_COMMAND_49, z, 0); break; } + + RCT2_GLOBAL(0x00F440D5, money32) += cost; + + if (cost == MONEY32_UNDEFINED){ + RCT2_GLOBAL(0x00F440D5, money32) = cost; + return 0; + } + } + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 3){ + if (mapCoord.x > 0x1FFF) + continue; + if (mapCoord.y > 0x1FFF) + continue; + + rct_map_element* map_element = map_get_surface_element_at(mapCoord.x / 32, mapCoord.y / 32); + + sint16 map_height = map_element->base_height * 8; + + if (map_element->properties.surface.slope & 0xF){ + map_height += 16; + if (map_element->properties.surface.slope & 0x10){ + map_height += 16; + } + } + + if (map_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK){ + sint16 water_height = map_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK; + water_height *= 16; + if (water_height > map_height) + map_height = water_height; + } + + sint16 temp_z = z + RCT2_GLOBAL(0x00F440D5, sint16) - map_height; + if (temp_z < 0) + RCT2_GLOBAL(0x00F440D5, sint16) -= temp_z; } } + + if (RCT2_GLOBAL(0x00F440D4, uint8) == 6){ + game_do_command(0, 0x69, 0, rideIndex, GAME_COMMAND_7, 0, 0); + } + + RCT2_GLOBAL(0x00F44142, sint16) = x; + RCT2_GLOBAL(0x00F44144, sint16) = y; + RCT2_GLOBAL(0x00F44146, sint16) = z; + + *track_elements = (uint8*)maze + 4; + return 1; } int track_place_ride(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint8** track_elements) From caa6547650d3eab9f05d121a0ec84f02077662e1 Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Wed, 13 May 2015 20:15:48 +0100 Subject: [PATCH 22/23] Started implementing track_mirror. Ride and maze mirror already works. Scenery still requires work. --- src/ride/track.c | 70 ++++++++++++++++++++++++++++++++++++++- src/ride/track.h | 1 + src/windows/track_place.c | 2 +- 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/src/ride/track.c b/src/ride/track.c index a99fc1b884..fce13d3152 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -721,7 +721,7 @@ void blank_map(){ map_element->flags = MAP_ELEMENT_FLAG_LAST_TILE; map_element->base_height = 2; map_element->clearance_height = 0; - map_element->properties.surface.slope = 0; + map_element->properties.surface.slope = 0; map_element->properties.surface.terrain = 0; map_element->properties.surface.grass_length = 1; map_element->properties.surface.ownership = OWNERSHIP_OWNED; @@ -774,6 +774,74 @@ void load_track_scenery_objects(){ reset_loaded_objects(); } +/* rct2: 0x006D247A */ +void track_mirror_scenery(uint8** track_elements){ + rct_track_scenery* scenery = (rct_track_scenery*)*track_elements; + for (; (scenery->scenery_object.flags & 0xFF) != 0xFF; scenery++){ + //0x006d2484 + } +} + +/* rct2: 0x006D2443 */ +void track_mirror_ride(uint8** track_elements){ + rct_track_element* track = (rct_track_element*)*track_elements; + for (; track->type != 0xFF; track++){ + track->type = RCT2_ADDRESS(0x0099EA1C, uint8)[track->type]; + } + *track_elements = (uint8*)track + 1; + + rct_track_entrance* entrance = (rct_track_entrance*)*track_elements; + for (; entrance->z != -1; entrance++){ + entrance->y = -entrance->y; + if (entrance->direction & 1){ + entrance->direction ^= (1 << 1); + } + } + *track_elements = (uint8*)entrance + 1; +} + +/* rct2: 0x006D25FA */ +void track_mirror_maze(uint8** track_elements){ + rct_maze_element* maze = (rct_maze_element*)*track_elements; + for (; maze->all != 0; maze++){ + maze->y = -maze->y; + + if (maze->type == 0x8 || maze->type == 0x80){ + if (maze->unk_2 & 1){ + maze->unk_2 ^= (1 << 1); + } + continue; + } + + uint16 maze_entry = maze->maze_entry; + uint16 new_entry = 0; + for (uint8 position = bitscanforward(maze_entry); + position != 0xFF; + position = bitscanforward(maze_entry)){ + maze_entry &= ~(1 << position); + new_entry |= (1 << RCT2_ADDRESS(0x00993EDC, uint8)[position]); + } + maze->maze_entry = new_entry; + } + *track_elements = (uint8*)maze + 4; +} + +/* 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); + } + else{ + track_mirror_ride(&track_elements); + } + + track_mirror_scenery(&track_elements); +} + void track_update_max_min_coordinates(sint16 x, sint16 y, sint16 z){ if (x < RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16)){ RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_X_MIN, sint16) = x; diff --git a/src/ride/track.h b/src/ride/track.h index 18db3dbe53..cac426850a 100644 --- a/src/ride/track.h +++ b/src/ride/track.h @@ -433,6 +433,7 @@ rct_track_design *temp_track_get_info(char* path, uint8** preview); rct_track_td6* load_track_design(const char *path); int track_rename(const char *text); int track_delete(); +void track_mirror(); void reset_track_list_cache(); int track_is_connected_by_shape(rct_map_element *a, rct_map_element *b); int sub_6D01B3(uint8 bl, uint8 rideIndex, int x, int y, int z); diff --git a/src/windows/track_place.c b/src/windows/track_place.c index da72df7855..6ac32ddad2 100644 --- a/src/windows/track_place.c +++ b/src/windows/track_place.c @@ -428,7 +428,7 @@ static void window_track_place_mouseup() window_track_place_draw_mini_preview(); break; case WIDX_MIRROR: - RCT2_CALLPROC_EBPSAFE(0x006D2436); + track_mirror(); RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint16) = (-RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_ROTATION, uint16)) & 3; window_invalidate(w); _window_track_place_last_x = 0xFFFF; From aacdc12733dc0e0b10c84cb97bbf82bdd8ebffe7 Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Thu, 14 May 2015 18:00:49 +0100 Subject: [PATCH 23/23] Finished mirror code. --- src/ride/track.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/src/ride/track.c b/src/ride/track.c index fce13d3152..a808878544 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -778,7 +778,88 @@ void load_track_scenery_objects(){ void track_mirror_scenery(uint8** track_elements){ rct_track_scenery* scenery = (rct_track_scenery*)*track_elements; for (; (scenery->scenery_object.flags & 0xFF) != 0xFF; scenery++){ - //0x006d2484 + uint8 entry_type, entry_index; + if (!find_object_in_entry_group(&scenery->scenery_object, &entry_type, &entry_index)){ + entry_type = scenery->scenery_object.flags & 0xF; + if (entry_type != OBJECT_TYPE_PATHS) + continue; + } + + rct_scenery_entry* scenery_entry = (rct_scenery_entry*)object_entry_groups[entry_type].chunks[entry_index]; + + switch (entry_type){ + case OBJECT_TYPE_LARGE_SCENERY: + { + sint16 x1 = 0, x2 = 0, y1 = 0, y2 = 0; + for (rct_large_scenery_tile* tile = scenery_entry->large_scenery.tiles; + tile->x_offset != -1; + tile++) + { + if (x1 > tile->x_offset) + x1 = tile->x_offset; + if (x2 < tile->x_offset) + x2 = tile->x_offset; + if (y1 > tile->y_offset) + y1 = tile->y_offset; + if (y2 > tile->y_offset) + y2 = tile->y_offset; + } + + switch (scenery->flags & 3){ + case 0: + scenery->y = (-(scenery->y * 32 + y1) - y2) / 32; + break; + case 1: + scenery->x = (scenery->x * 32 + y2 + y1) / 32; + scenery->y = (-(scenery->y * 32)) / 32; + scenery->flags ^= (1 << 1); + break; + case 2: + scenery->y = (-(scenery->y * 32 - y2) + y1) / 32; + break; + case 3: + scenery->x = (scenery->x * 32 - y2 - y1) / 32; + scenery->y = (-(scenery->y * 32)) / 32; + scenery->flags ^= (1 << 1); + break; + } + break; + } + case OBJECT_TYPE_SMALL_SCENERY: + scenery->y = -scenery->y; + + if (scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG9){ + scenery->flags ^= (1 << 0); + if (!(scenery_entry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE)){ + scenery->flags ^= (1 << 2); + } + break; + } + if (scenery->flags & (1 << 0)) + scenery->flags ^= (1 << 1); + + scenery->flags ^= (1 << 2); + break; + + case OBJECT_TYPE_WALLS: + scenery->y = -scenery->y; + if (scenery->flags & (1 << 0)) + scenery->flags ^= (1 << 1); + break; + + case OBJECT_TYPE_PATHS: + scenery->y = -scenery->y; + + if (scenery->flags & (1 << 5)){ + scenery->flags ^= (1 << 6); + } + + uint8 flags = scenery->flags; + flags = ((flags& (1 << 3)) >> 2) | ((flags & (1 << 1)) << 2); + scenery->flags &= 0xF5; + scenery->flags |= flags; + } + } }