From b7470447e8a8c329df94733eac2787555dadab90 Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Mon, 2 Feb 2015 18:43:02 +0000 Subject: [PATCH 1/4] Refactor track_list using TD4 knowledge --- src/rct1.h | 134 ++++++++++++++++++++++++++++++++++++++ src/ride/track.c | 124 ++++++++++++++++++++--------------- src/ride/track.h | 31 ++++++--- src/windows/track_list.c | 73 +++++++++++---------- src/windows/track_place.c | 2 +- 5 files changed, 266 insertions(+), 98 deletions(-) diff --git a/src/rct1.h b/src/rct1.h index cbcb265f4e..466e5fc184 100644 --- a/src/rct1.h +++ b/src/rct1.h @@ -209,5 +209,139 @@ typedef struct { uint32 expansion_pack_checksum; } rct1_s4; +enum { + RCT1_RIDE_TYPE_NULL = 255, + RCT1_RIDE_TYPE_WOODEN_ROLLER_COASTER = 0, + RCT1_RIDE_TYPE_STAND_UP_STEEL_ROLLER_COASTER, + RCT1_RIDE_TYPE_SUSPENDED_ROLLER_COASTER, + RCT1_RIDE_TYPE_INVERTED_ROLLER_COASTER, + RCT1_RIDE_TYPE_STEEL_MINI_ROLLER_COASTER, + RCT1_RIDE_TYPE_MINIATURE_RAILROAD, + RCT1_RIDE_TYPE_MONORAIL, + RCT1_RIDE_TYPE_SUSPENDED_SINGLE_RAIL_ROLLER_COASTER, + RCT1_RIDE_TYPE_BOAT_HIRE, + RCT1_RIDE_TYPE_WOODEN_CRAZY_RODENT_ROLLER_COASTER, + RCT1_RIDE_TYPE_SINGLE_RAIL_ROLLER_COASTER, + RCT1_RIDE_TYPE_CAR_RIDE, + RCT1_RIDE_TYPE_WHOA_BELLY, + RCT1_RIDE_TYPE_BOBSLED_ROLLER_COASTER, + RCT1_RIDE_TYPE_OBSERVATION_TOWER, + RCT1_RIDE_TYPE_STEEL_ROLLER_COASTER, + RCT1_RIDE_TYPE_WATER_SLIDE, + RCT1_RIDE_TYPE_MINE_TRAIN_ROLLER_COASTER, + RCT1_RIDE_TYPE_CHAIRLIFT, + RCT1_RIDE_TYPE_STEEL_CORKSCREW_ROLLER_COASTER, + RCT1_RIDE_TYPE_HEDGE_MAZE, + RCT1_RIDE_TYPE_SPIRAL_SLIDE, + RCT1_RIDE_TYPE_GO_KARTS, + RCT1_RIDE_TYPE_LOG_FLUME, + RCT1_RIDE_TYPE_RIVER_RAPIDS, + RCT1_RIDE_TYPE_BUMPER_CARS, + RCT1_RIDE_TYPE_SWINGING_SHIP, + RCT1_RIDE_TYPE_SWINGING_INVERTER_SHIP, + RCT1_RIDE_TYPE_ICE_CREAM_STALL, + RCT1_RIDE_TYPE_FRIES_STALL, + RCT1_RIDE_TYPE_DRINK_STALL, + RCT1_RIDE_TYPE_COTTON_CANDY_STALL, + RCT1_RIDE_TYPE_BURGER_BAR, + RCT1_RIDE_TYPE_MERRY_GO_ROUND, + RCT1_RIDE_TYPE_BALLOON_STALL, + RCT1_RIDE_TYPE_INFORMATION_KIOSK, + RCT1_RIDE_TYPE_BATHROOM, + RCT1_RIDE_TYPE_FERRIS_WHEEL, + RCT1_RIDE_TYPE_MOTION_SIMULATOR, + RCT1_RIDE_TYPE_3D_CINEMA, + RCT1_RIDE_TYPE_GRAVITRON, + RCT1_RIDE_TYPE_SPACE_RINGS, + RCT1_RIDE_TYPE_REVERSE_WHOA_BELLY_ROLLER_COASTER, + RCT1_RIDE_TYPE_SOUVENIR_STALL, + RCT1_RIDE_TYPE_VERTICAL_ROLLER_COASTER, + RCT1_RIDE_TYPE_PIZZA_STALL, + RCT1_RIDE_TYPE_SCRAMBLED_EGGS, + RCT1_RIDE_TYPE_HAUNTED_HOUSE, + RCT1_RIDE_TYPE_POPCORN_STALL, + RCT1_RIDE_TYPE_CIRCUS_SHOW, + RCT1_RIDE_TYPE_GHOST_TRAIN, + RCT1_RIDE_TYPE_STEEL_TWISTER_ROLLER_COASTER, + RCT1_RIDE_TYPE_WOODEN_TWISTER_ROLLER_COASTER, + RCT1_RIDE_TYPE_WOODEN_SIDE_FRICTION_ROLLER_COASTER, + RCT1_RIDE_TYPE_STEEL_WILD_MOUSE_ROLLER_COASTER, + RCT1_RIDE_TYPE_HOT_DOG_STALL, + RCT1_RIDE_TYPE_EXOTIC_SEA_FOOD_STALL, + RCT1_RIDE_TYPE_HAT_STALL, + RCT1_RIDE_TYPE_CANDY_APPLE_STAND, + RCT1_RIDE_TYPE_VIRGINIA_REEL, + RCT1_RIDE_TYPE_RIVER_RIDE, + RCT1_RIDE_TYPE_CYCLE_MONORAIL, + RCT1_RIDE_TYPE_FLYING_ROLLER_COASTER, + RCT1_RIDE_TYPE_SUSPENDED_MONORAIL, + RCT1_RIDE_TYPE_40, + RCT1_RIDE_TYPE_WOODEN_REVERSER_ROLLER_COASTER, + RCT1_RIDE_TYPE_HEARTLINE_TWISTER_ROLLER_COASTER, + RCT1_RIDE_TYPE_MINIATURE_GOLF, + RCT1_RIDE_TYPE_44, + RCT1_RIDE_TYPE_ROTO_DROP, + RCT1_RIDE_TYPE_FLYING_SAUCERS, + RCT1_RIDE_TYPE_CROOKED_HOUSE, + RCT1_RIDE_TYPE_CYCLE_RAILWAY, + RCT1_RIDE_TYPE_SUSPENDED_LOOPING_ROLLER_COASTER, + RCT1_RIDE_TYPE_WATER_COASTER, + RCT1_RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER, + RCT1_RIDE_TYPE_INVERTED_WILD_MOUSE_COASTER, + RCT1_RIDE_TYPE_JET_SKIS, + RCT1_RIDE_TYPE_T_SHIRT_STALL, + RCT1_RIDE_TYPE_RAFT_RIDE, + RCT1_RIDE_TYPE_DOUGHNUT_SHOP, + RCT1_RIDE_TYPE_ENTERPRISE, + RCT1_RIDE_TYPE_COFFEE_SHOP, + RCT1_RIDE_TYPE_FRIED_CHICKEN_STALL, + RCT1_RIDE_TYPE_LEMONADE_STALL +}; + +typedef struct{ + uint8 type; // 0x00 + uint8 vehicle_type; // 0x01 + uint32 special_track_flags; // 0x02 + uint8 operating_mode; // 0x06 + uint8 vehicle_colour_version; // 0x07 Vehicle colour type in first two bits, Version in bits 3,4 + uint8 body_trim_colour[24]; // 0x08 + uint8 track_spine_colour_rct1; // 0x20 + uint8 track_rail_colour_rct1; // 0x21 + uint8 track_support_colour_rct1; // 0x22 + uint8 departure_control_flags; // 0x23 + uint8 number_of_trains; // 0x24 + uint8 cars_per_train; // 0x25 + uint8 min_wait_time; // 0x26 + uint8 max_wait_time; // 0x27 + uint8 speed; // 0x28 + uint8 max_speed; // 0x29 + uint8 average_speed; // 0x2A + uint16 ride_length; // 0x2B + uint8 max_positive_vertical_g; // 0x2D + uint8 max_negitive_vertical_g; // 0x2E + uint8 max_lateral_g; // 0x2F + union { + uint8 inversions; // 0x30 + uint8 holes; // 0x30 + }; + uint8 drops; // 0x31 + uint8 highest_drop_height; // 0x32 + uint8 excitement; // 0x33 + uint8 intensity; // 0x34 + uint8 nausea; // 0x35 + uint8 pad_36[2]; + union{ + uint16 start_track_data_original; // 0x38 + uint8 track_spine_colour[4]; // 0x38 + }; + uint8 track_rail_colour[4]; // 0x3C + union{ + uint8 track_support_colour[4]; // 0x40 + uint8 wall_type[4]; // 0x40 + }; + uint8 pad_41[0x83]; + uint16 start_track_data_AA_CF; // 0xC4 +}rct_track_td4; // Information based off RCTTechDepot + #endif \ No newline at end of file diff --git a/src/ride/track.c b/src/ride/track.c index c3956d0ab8..60e9df1cfe 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -22,6 +22,7 @@ #include "../platform/osinterface.h" #include "../util/sawyercoding.h" #include "../util/util.h" +#include "../rct1.h" #include "ride.h" #include "track.h" @@ -240,7 +241,7 @@ static void read(void *dst, void **src, int length) * rct2: 0x0067726A * path: 0x0141EF68 */ -rct_track_design* load_track_design(const char *path) +rct_track_td6* load_track_design(const char *path) { FILE *fp; long fpLength; @@ -270,72 +271,87 @@ rct_track_design* load_track_design(const char *path) realloc(decoded, decodedLength); free(fpBuffer); - rct_track_design* track_design = RCT2_ADDRESS(0x009D8178, rct_track_design); + rct_track_td6* track_design = RCT2_ADDRESS(0x009D8178, rct_track_td6); // Read decoded data src = decoded; - // Clear top of track_design as this is not loaded from the file - memset(&track_design->pad_60, 0, 67); + // Clear top of track_design as this is not loaded from the td4 files + memset(&track_design->track_spine_colour, 0, 67); // Read start of track_design read(track_design, &src, 32); - uint8 al = track_design->var_07 >> 2; - if (al >= 2) - read(&track_design->pad_20, &src, 40); + uint8 version = track_design->var_07 >> 2; + + if (version > 2){ + free(decoded); + return NULL; + } + + // In td6 there are 32 sets of two byte vehicle colour specifiers + // In td4 there are 12 sets so the remaining 20 need to be read. + if (version == 2) + read(&track_design->vehicle_colours[12], &src, 40); read(&track_design->pad_48, &src, 24); - al = track_design->var_07 >> 2; - if (al != 0) - read(&track_design->pad_60, &src, al == 1 ? 140 : 67); - read(&track_design->preview, &src, 24572); - al = track_design->var_07 >> 2; - if (al < 2) { - if (track_design->type == RIDE_TYPE_MAZE) { - edi = (uint8*)(&track_design->preview); - while (*edi != 0) { - edi += 4; - } - edi += 4; - memset(edi, 255, ((uint8*)&track_design->pad_9F) - edi); - } else { - edi = (uint8*)(&track_design->preview); - while (*edi != 255) { - edi += 2; - } - edi++; - memset(edi, 255, ((uint8*)&track_design->pad_9F) - edi); - } - } + // In td4 (version AA/CF) and td6 both start actual track data at 0xA3 + if (version > 0) + read(&track_design->track_spine_colour, &src, version == 1 ? 140 : 67); + + uint8* track_elements = RCT2_ADDRESS(0x9D821B, uint8); + // Read the actual track data. + read(track_elements, &src, 24572); + + uint8* final_track_element_location = track_elements + 24572; free(decoded); - // - al = track_design->var_07 >> 2; - if (al > 2) - return NULL; + // td4 files require some work to be recognised as td6. + if (version < 2) { - if (al <= 1) { - edi = (uint8*)&track_design->pad_08; + // 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) { + 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); + } + + // Edit the colours to use the new versions + // Unsure why it is 67 + edi = (uint8*)&track_design->vehicle_colours; for (i = 0; i < 67; i++) *edi++ = RCT2_ADDRESS(0x0097F0BC, uint8)[*edi]; - edi = (uint8*)&track_design->pad_60; + // Edit the colours to use the new versions + edi = (uint8*)&track_design->track_spine_colour; for (i = 0; i < 12; i++) *edi++ = RCT2_ADDRESS(0x0097F0BC, uint8)[*edi]; + // Highest drop height is 1bit = 3/4 a meter in td6 + // Highest drop height is 1bit = 1/3 a meter in td4 + // Not sure if this is correct?? track_design->highest_drop_height >>= 1; - if (!RCT2_CALLPROC_X(0x00677530, 0, 0, 0, 0, 0, 0, 0)) - track_design->type = 255; - - if (track_design->type == RIDE_TYPE_JUNIOR_ROLLER_COASTER) + if (0x100 & RCT2_CALLPROC_X(0x00677530, 0, 0, 0, 0, 0, 0, 0)) track_design->type = RIDE_TYPE_NULL; - if (track_design->type == RIDE_TYPE_SPIRAL_ROLLER_COASTER) + if (track_design->type == RCT1_RIDE_TYPE_STEEL_MINI_ROLLER_COASTER) + track_design->type = RIDE_TYPE_NULL; + + if (track_design->type == RCT1_RIDE_TYPE_WOODEN_ROLLER_COASTER) 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->var_01 == 79) { + if (track_design->vehicle_type == 79) { if (track_design->var_06 == 2) track_design->var_06 = 1; } @@ -345,15 +361,15 @@ rct_track_design* load_track_design(const char *path) if (track_design->type == RIDE_TYPE_MAZE) { vehicle_object = RCT2_ADDRESS(0x0097F66C, rct_object_entry); } else { - int var_01 = track_design->var_01; - if (var_01 == 3 && track_design->type == 3) - var_01 = 80; - vehicle_object = &RCT2_ADDRESS(0x0097F0DC, rct_object_entry)[var_01]; + int vehicle_type = track_design->vehicle_type; + if (vehicle_type == 3 && track_design->type == RIDE_TYPE_INVERTED_ROLLER_COASTER) + vehicle_type = 80; + vehicle_object = &RCT2_ADDRESS(0x0097F0DC, rct_object_entry)[vehicle_type]; } memcpy(&track_design->vehicle_object, vehicle_object, sizeof(rct_object_entry)); for (i = 0; i < 32; i++) - track_design->pad_82[i] = track_design->pad_08[1 + i * 2]; + track_design->vehicle_additional_colour[i] = track_design->vehicle_colours[i].trim_colour; track_design->space_required_x = 255; track_design->space_required_y = 255; @@ -409,25 +425,25 @@ rct_track_design *track_get_info(int index, uint8** preview) char track_path[MAX_PATH] = { 0 }; subsitute_path(track_path, (char*)RCT2_ADDRESS_TRACKS_PATH, trackDesignList + (index * 128)); - rct_track_design* loaded_design = NULL; + rct_track_td6* loaded_track = NULL; log_verbose("Loading track: %s", trackDesignList + (index * 128)); - if (!(loaded_design = load_track_design(track_path))) { + if (!(loaded_track = load_track_design(track_path))) { if (preview != NULL) *preview = NULL; log_error("Failed to load track: %s", trackDesignList + (index * 128)); return NULL; } trackDesign = &RCT2_GLOBAL(RCT2_ADDRESS_TRACK_LIST, rct_track_design*)[i]; - + // Copy the track design apart from the preview image - memcpy(trackDesign, loaded_design, 163); + memcpy(&trackDesign->track_td6, loaded_track, sizeof(rct_track_td6)); // Load in a new preview image, calculate cost variable, calculate var_06 RCT2_CALLPROC_X(0x006D1EF0, 0, 0, 0, 0, 0, (int)&trackDesign->preview, 0); - trackDesign->cost = RCT2_GLOBAL(0x00F4411D, money32); - trackDesign->var_06 = RCT2_GLOBAL(0x00F44151, uint8) & 7; + trackDesign->track_td6.cost = RCT2_GLOBAL(0x00F4411D, money32); + trackDesign->track_td6.var_06 = RCT2_GLOBAL(0x00F44151, uint8) & 7; } // Set preview to correct preview image based on rotation @@ -453,4 +469,4 @@ int track_rename(const char *text) int track_delete() { return (RCT2_CALLPROC_X(0x006D3761, 0, 0, 0, 0, 0, 0, 0) & 0x100) != 0; -} \ No newline at end of file +} diff --git a/src/ride/track.h b/src/ride/track.h index 10d66427e7..7f62f0547d 100644 --- a/src/ride/track.h +++ b/src/ride/track.h @@ -37,21 +37,29 @@ typedef struct { #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 */ typedef struct { uint8 type; // 0x00 - uint8 var_01; + uint8 vehicle_type; money32 cost; // 0x02 uint8 var_06; uint8 var_07; - uint8 pad_08[0x18]; - uint8 pad_20[40]; + rct_track_vehicle_colour vehicle_colours[32]; // 0x08 uint8 pad_48[2]; uint8 total_air_time; // 0x4A - uint8 pad_4B[0x05]; + uint8 pad_4B; + uint8 number_of_trains; // 0x4C + uint8 number_of_cars_per_train; // 0x4D + uint8 pad_4E[2]; uint8 var_50; uint8 max_speed; // 0x51 uint8 average_speed; // 0x52 @@ -69,17 +77,23 @@ typedef struct { uint8 intensity; // 0x5C uint8 nausea; // 0x5D uint8 pad_5E[2]; - uint8 pad_60[0xC]; + uint8 track_spine_colour[4]; // 0x60 + uint8 track_rail_colour[4]; // 0x64 + uint8 track_support_colour[4]; // 0x68 uint32 var_6C; rct_object_entry vehicle_object; // 0x70 uint8 space_required_x; // 0x80 uint8 space_required_y; // 0x81 - uint8 pad_82[0x1D]; - uint8 pad_9F[3]; + uint8 vehicle_additional_colour[32]; // 0x82 uint8 var_A2; +} rct_track_td6; + +typedef struct{ + rct_track_td6 track_td6; uint8 preview[4][TRACK_PREVIEW_IMAGE_SIZE]; // 0xA3 } rct_track_design; + enum { TRACK_NONE = 0, @@ -140,8 +154,9 @@ enum { void track_load_list(ride_list_item item); int sub_67726A(const char *path); rct_track_design *track_get_info(int index, uint8** preview); +rct_track_td6* load_track_design(const char *path); int track_rename(const char *text); int track_delete(); void reset_track_list_cache(); -#endif \ No newline at end of file +#endif diff --git a/src/windows/track_list.c b/src/windows/track_list.c index c996df281b..adec00a66a 100644 --- a/src/windows/track_list.c +++ b/src/windows/track_list.c @@ -182,18 +182,19 @@ static void window_track_list_select(rct_window *w, int index) (char*)0x009BC313, trackDesignItem, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER ? - 0 : - FORMAT_WHITE - ); + 0 : + FORMAT_WHITE + ); - subsitute_path((char*)0x0141EF68, (char*)RCT2_ADDRESS_TRACKS_PATH, trackDesignItem); + char track_path[MAX_PATH] = { 0 }; + subsitute_path(track_path, (char*)RCT2_ADDRESS_TRACKS_PATH, trackDesignItem); if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) { window_track_manage_open(); return; } - if (!RCT2_CALLPROC_X(0x0067726A, 0, 0, 0, 0, 0, 0, 0)) { + if (!load_track_design(track_path)) { w->track_list.var_480 = 0xFFFF; window_invalidate(w); return; @@ -201,7 +202,7 @@ static void window_track_list_select(rct_window *w, int index) trackDesign = track_get_info(index, NULL); if (trackDesign == NULL) return; - if (trackDesign->var_06 & 4) + if (trackDesign->track_td6.var_06 & 4) window_error_open(STR_THIS_DESIGN_WILL_BE_BUILT_WITH_AN_ALTERNATIVE_VEHICLE_TYPE, -1); window_close(w); @@ -429,6 +430,8 @@ static void window_track_list_paint() if (trackDesign == NULL) return; + rct_track_td6* track_td6 = &trackDesign->track_td6; + subsituteElement = &g1Elements[0]; tmpElement = *subsituteElement; subsituteElement->offset = image; @@ -445,13 +448,13 @@ static void window_track_list_paint() RCT2_GLOBAL(0x00F44153, uint8) = 0; // Warnings - if ((trackDesign->var_06 & 4) && !(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER)) { + if ((track_td6->var_06 & 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 (trackDesign->var_06 & 1) { + if (track_td6->var_06 & 1) { RCT2_GLOBAL(0x00F44153, uint8) = 1; if (RCT2_GLOBAL(0x00F44152, uint8) == 0) { // Scenery not available @@ -468,89 +471,89 @@ static void window_track_list_paint() x = w->x + widget->left + 1; y = w->y + widget->bottom + 2; - if (trackDesign->var_6C & 0x80000000) { + if (track_td6->var_6C & 0x80000000) { // Six flags logo gfx_draw_sprite(dpi, SPR_SIX_FLAGS, w->x + widget->right - 50, y + 4, 0); } // Stats - rating = trackDesign->excitement * 10; + rating = track_td6->excitement * 10; gfx_draw_string_left(dpi, STR_TRACK_LIST_EXCITEMENT_RATING, &rating, 0, x, y); y += 10; - rating = trackDesign->intensity * 10; + rating = track_td6->intensity * 10; gfx_draw_string_left(dpi, STR_TRACK_LIST_INTENSITY_RATING, &rating, 0, x, y); y += 10; - rating = trackDesign->nausea * 10; + rating = track_td6->nausea * 10; gfx_draw_string_left(dpi, STR_TRACK_LIST_NAUSEA_RATING, &rating, 0, x, y); y += 14; - if (trackDesign->type != RIDE_TYPE_MAZE) { - if (trackDesign->type == RIDE_TYPE_MINI_GOLF) { + if (track_td6->type != RIDE_TYPE_MAZE) { + if (track_td6->type == RIDE_TYPE_MINI_GOLF) { // Holes - holes = trackDesign->holes & 0x1F; + holes = track_td6->holes & 0x1F; gfx_draw_string_left(dpi, STR_HOLES, &holes, 0, x, y); y += 10; } else { // Maximum speed - speed = ((trackDesign->max_speed << 16) * 9) >> 18; + speed = ((track_td6->max_speed << 16) * 9) >> 18; gfx_draw_string_left(dpi, STR_MAX_SPEED, &speed, 0, x, y); y += 10; // Average speed - speed = ((trackDesign->average_speed << 16) * 9) >> 18; + speed = ((track_td6->average_speed << 16) * 9) >> 18; gfx_draw_string_left(dpi, STR_AVERAGE_SPEED, &speed, 0, x, y); y += 10; } // Ride length RCT2_GLOBAL(0x013CE952 + 0, uint16) = 1345; - RCT2_GLOBAL(0x013CE952 + 2, uint16) = trackDesign->ride_length; + RCT2_GLOBAL(0x013CE952 + 2, uint16) = track_td6->ride_length; gfx_draw_string_left_clipped(dpi, STR_TRACK_LIST_RIDE_LENGTH, (void*)0x013CE952, 0, x, y, 214); y += 10; } - if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (trackDesign->type * 8), uint32) & 0x80) { + if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (track_td6->type * 8), uint32) & 0x80) { // Maximum positive vertical Gs - gForces = trackDesign->max_positive_vertical_g * 32; + gForces = track_td6->max_positive_vertical_g * 32; gfx_draw_string_left(dpi, STR_MAX_POSITIVE_VERTICAL_G, &gForces, 0, x, y); y += 10; // Maximum negative verical Gs - gForces = trackDesign->max_negitive_vertical_g * 32; + gForces = track_td6->max_negitive_vertical_g * 32; gfx_draw_string_left(dpi, STR_MAX_NEGATIVE_VERTICAL_G, &gForces, 0, x, y); y += 10; // Maximum lateral Gs - gForces = trackDesign->max_lateral_g * 32; + gForces = track_td6->max_lateral_g * 32; gfx_draw_string_left(dpi, STR_MAX_LATERAL_G, &gForces, 0, x, y); y += 10; - if (trackDesign->var_07 / 4 >= 2) { - if (trackDesign->total_air_time != 0) { + if (track_td6->var_07 / 4 >= 2) { + if (track_td6->total_air_time != 0) { // Total air time - airTime = trackDesign->total_air_time * 25; + airTime = track_td6->total_air_time * 25; gfx_draw_string_left(dpi, STR_TOTAL_AIR_TIME, &airTime, 0, x, y); y += 10; } } } - if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (trackDesign->type * 8), uint32) & 0x400) { + if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (track_td6->type * 8), uint32) & 0x400) { // Drops - drops = trackDesign->drops & 0x3F; + drops = track_td6->drops & 0x3F; gfx_draw_string_left(dpi, STR_DROPS, &drops, 0, x, y); y += 10; // Drop height is multiplied by 0.75 - dropHeight = (trackDesign->highest_drop_height + (trackDesign->highest_drop_height / 2)) / 2; + dropHeight = (track_td6->highest_drop_height + (track_td6->highest_drop_height / 2)) / 2; gfx_draw_string_left(dpi, STR_HIGHEST_DROP_HEIGHT, &drops, 0, x, y); y += 10; } - if (trackDesign->type != RIDE_TYPE_MINI_GOLF) { - inversions = trackDesign->inversions & 0x1F; + if (track_td6->type != RIDE_TYPE_MINI_GOLF) { + inversions = track_td6->inversions & 0x1F; if (inversions != 0) { // Inversions gfx_draw_string_left(dpi, STR_INVERSIONS, &inversions, 0, x, y); @@ -559,16 +562,16 @@ static void window_track_list_paint() } y += 4; - if (trackDesign->space_required_x != 0xFF) { + if (track_td6->space_required_x != 0xFF) { // Space required - RCT2_GLOBAL(0x013CE952 + 0, uint16) = trackDesign->space_required_x; - RCT2_GLOBAL(0x013CE952 + 2, uint16) = trackDesign->space_required_y; + RCT2_GLOBAL(0x013CE952 + 0, uint16) = track_td6->space_required_x; + RCT2_GLOBAL(0x013CE952 + 2, uint16) = track_td6->space_required_y; gfx_draw_string_left(dpi, STR_TRACK_LIST_SPACE_REQUIRED, (void*)0x013CE952, 0, x, y); y += 10; } - if (trackDesign->cost != 0) { - gfx_draw_string_left(dpi, STR_TRACK_LIST_COST_AROUND, &trackDesign->cost, 0, x, y); + if (track_td6->cost != 0) { + gfx_draw_string_left(dpi, STR_TRACK_LIST_COST_AROUND, &track_td6->cost, 0, x, y); y += 14; } } diff --git a/src/windows/track_place.c b/src/windows/track_place.c index 6f935f2b48..42bf35cc40 100644 --- a/src/windows/track_place.c +++ b/src/windows/track_place.c @@ -171,7 +171,7 @@ static void window_track_place_draw_mini_preview() originY -= ((maxY + minY) >> 6) << 5; } - if (design->type != RIDE_TYPE_MAZE) { + if (design->track_td6.type != RIDE_TYPE_MAZE) { #pragma region Track rotation = RCT2_GLOBAL(0x00F440AE, uint8) + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32); From 186499c0eb75acbdccb630394ec93d1b20c62c2d Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Mon, 2 Feb 2015 18:44:19 +0000 Subject: [PATCH 2/4] Finished track_load_list. Requires refactor. --- src/object.h | 1 + src/object_list.c | 24 ++++++ src/ride/track.c | 188 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 212 insertions(+), 1 deletion(-) diff --git a/src/object.h b/src/object.h index 70be1a0f5a..df094c0f4e 100644 --- a/src/object.h +++ b/src/object.h @@ -87,6 +87,7 @@ int object_calculate_checksum(const rct_object_entry *entry, const char *data, i int object_paint(int type, int eax, int ebx, int ecx, int edx, int esi, int edi, int ebp); rct_object_entry *object_get_next(rct_object_entry *entry); int sub_6A9F42(FILE *file, rct_object_entry* entry); +int find_object_in_entry_group(rct_object_entry* entry, uint8* entry_type, uint8* entry_index); rct_object_entry *object_list_find(rct_object_entry *entry); diff --git a/src/object_list.c b/src/object_list.c index 2edf1c88fa..ee2df5d343 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -488,6 +488,30 @@ void object_list_create_hash_table() } } +/* 0x006A9DA1 + * bl = entry_index + * ecx = entry_type + */ +int find_object_in_entry_group(rct_object_entry* entry, uint8* entry_type, uint8* entry_index){ + *entry_type = entry->flags & 0xF; + + rct_object_entry_group entry_group = object_entry_groups[*entry_type]; + for (*entry_index = 0; + *entry_index < object_entry_group_counts[*entry_type]; + ++(*entry_index), + entry_group.chunks++, + entry_group.entries++){ + + if (*entry_group.chunks == (uint8*)-1) continue; + + if (object_entry_compare((rct_object_entry*)entry_group.entries, entry))break; + } + + if (*entry_index == object_entry_group_counts[*entry_type])return 0; + return 1; +} + + rct_object_entry *object_list_find(rct_object_entry *entry) { uint32 hash = object_get_hash_code(entry); diff --git a/src/ride/track.c b/src/ride/track.c index 60e9df1cfe..911712b9ce 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -25,6 +25,7 @@ #include "../rct1.h" #include "ride.h" #include "track.h" +#include "../platform/platform.h" /** * @@ -221,13 +222,198 @@ const rct_trackdefinition gTrackDefinitions[] = { { TRACK_HALF_LOOP_2, TRACK_DOWN_25, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_UPSIDE_DOWN, TRACK_HALF_LOOP_DOWN }, // ELEM_LEFT_LARGE_HALF_LOOP_DOWN }; +uint32* sub_6AB49A(rct_object_entry* entry){ + rct_object_entry* object_list_entry = object_list_find(entry); + + if (object_list_entry == NULL) return NULL; + + // Return the address of the last value of the list entry + return (((uint32*)object_get_next(object_list_entry)) - 1); +} + /** * * rct2: 0x006CED50 */ void track_load_list(ride_list_item item) { - RCT2_CALLPROC_X(0x006CED50, 0, 0, 0, *((uint16*)&item), 0, 0, 0); + RCT2_GLOBAL(0xF635ED, uint8) = 0; + + if (item.type < 0x80){ + rct_ride_type* ride_type = gRideTypeList[item.entry_index]; + if (!(ride_type->var_008 & 0x2000)){ + item.entry_index = 0xFF; + } + } + + int enumFileHandle, totalFiles; + file_info enumFileInfo; + + totalFiles = 0; + + // Enumerate through each track in the directory + enumFileHandle = platform_enumerate_files_begin(RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char)); + if (enumFileHandle == INVALID_HANDLE) + return; + + while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) { + totalFiles++; + } + platform_enumerate_files_end(enumFileHandle); + + const char* tracks_path = get_file_path(PATH_ID_TRACKSIDX); + + FILE* file; + + file = fopen(tracks_path, "rb"); + + if (file == NULL){ + log_error("Failed to find tracks.idx"); + } + else{ + RCT2_GLOBAL(0xF44125, FILE*) = file; + if (item.type != 0xFC){ + uint8 track_file_count; + fread(&track_file_count, 1, 1, file); + rewind(file); + if (track_file_count == totalFiles){ + //0x6CF060 assume skip remaking tracks.idx + } + } + } + fclose(file); + + uint8* new_track_file; + + new_track_file = malloc(0x40000); + + uint8* new_file_pointer = new_track_file; + *(uint32*)new_file_pointer = totalFiles; + new_file_pointer += 4; + + enumFileHandle = platform_enumerate_files_begin(RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char)); + if (enumFileHandle == INVALID_HANDLE) + return; + + while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) { + if (new_file_pointer > new_track_file + 0x3FF04)break; + + char path[MAX_PATH]; + subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), enumFileInfo.path); + + rct_track_td6* loaded_track = load_track_design(path); + if (loaded_track){ + *new_file_pointer++ = loaded_track->type; + } + else{ + *new_file_pointer++ = 0xFF; + } + memcpy(new_file_pointer, &loaded_track->vehicle_object, sizeof(rct_object_entry)); + new_file_pointer += sizeof(rct_object_entry); + + int file_name_length = strlen(enumFileInfo.path); + strcpy(new_file_pointer, enumFileInfo.path); + new_file_pointer += file_name_length + 1; + } + platform_enumerate_files_end(enumFileHandle); + + *new_file_pointer++ = 0xFE; + + file = fopen(tracks_path, "wb"); + if (file == NULL) { + log_error("Failed to save %s", tracks_path); + } + else{ + fwrite(new_track_file, (new_file_pointer - new_track_file), 1, file); + fclose(file); + } + + free(new_track_file); + + file = fopen(tracks_path, "rb"); + // 0x006CF060 see above. + int file_size = fsize(file); + uint8* track_idx_file = malloc(file_size); + fread(track_idx_file, file_size, 1, file); + + // +4 Skip number of elements + uint8* track_pointer = track_idx_file + 4; + uint8* track_design_list_entry = RCT2_ADDRESS(0xF441EC, uint8); + + for (uint8 track_type = *track_pointer++; track_type != 0xFE; + track_pointer += strlen(track_pointer) + 1, + track_type = *track_pointer++){ + rct_object_entry* track_object = (rct_object_entry*)track_pointer; + track_pointer += sizeof(rct_object_entry); + + if (track_type != item.type){ + continue; + } + + uint8 entry_type, entry_index; + if (item.entry_index != 0xFF){ + + if (!find_object_in_entry_group(track_object, &entry_type, &entry_index))continue; + + if (item.entry_index != entry_index)continue; + } + else{ + if (find_object_in_entry_group(track_object, &entry_type, &entry_index)){ + if (track_object->flags & 0x3000)continue; + } + else{ + uint32* esi = sub_6AB49A(track_object); + if (esi == NULL) continue; + if (*esi & 0x1000000)continue; + } + } + + if (track_design_list_entry >= RCT2_ADDRESS(0xF635EC, uint8)){ + RCT2_GLOBAL(0xF635ED, uint8) |= 1; + break; + } + + uint8* edi = RCT2_ADDRESS(0xF441EC, uint8); + uint8 isBelow; + for (; edi != track_design_list_entry; edi += 128){ + //edx + uint8* current_entry = edi; + //ebx + uint8* track_name = track_pointer; + isBelow = 0; + + while (1){ + uint8 character = *track_name++; + if (character >= 'a' || character < 'z')character += 0xE0; + uint8 entry_char = *current_entry++; + if (entry_char >= 'a' || entry_char < 'z')entry_char += 0xE0; + if (character == entry_char && character != 0)continue; + + if (character == 0){ + isBelow = -1; + break; + } + if (character < entry_char) isBelow = 1; + break; + } + if (isBelow == 1) break; + } + + if (isBelow == 1){ + uint8* edx = track_design_list_entry; + + while (edx >= edi){ + edx[128] = *edx--; + } + } + uint8* track_name = track_pointer; + while (*edi++ = *track_name++); + track_design_list_entry += 128; + continue; + } + + fclose(file); + //RCT2_CALLPROC_X(0x006CED50, 0, 0, 0, *((uint16*)&item), 0, 0, 0); } static void read(void *dst, void **src, int length) From fc8728aa9de0c6784f73d1c127297a30ab99f8e1 Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Mon, 2 Feb 2015 18:49:07 +0000 Subject: [PATCH 3/4] Refactor of editor window. Added object_selection_close and load_selected_objects. Fix small display bugs. --- src/addresses.h | 1 + src/object.h | 1 + src/object_list.c | 4 +- src/ride/track.c | 9 +- src/windows/editor_object_selection.c | 170 +++++++++++++++++++++++++- src/windows/track_list.c | 6 +- 6 files changed, 181 insertions(+), 10 deletions(-) diff --git a/src/addresses.h b/src/addresses.h index 5eed5c0e08..9ccb46f65d 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -129,6 +129,7 @@ #define RCT2_ADDRESS_RIDE_ENTRIES 0x009ACFA4 #define RCT2_ADDRESS_INSTALLED_OBJECT_LIST 0x009ADAE8 +#define RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST 0x009ADAEC #define RCT2_ADDRESS_CURRENT_SOUND_DEVICE 0x009AF280 diff --git a/src/object.h b/src/object.h index df094c0f4e..239ce2658b 100644 --- a/src/object.h +++ b/src/object.h @@ -87,6 +87,7 @@ int object_calculate_checksum(const rct_object_entry *entry, const char *data, i int object_paint(int type, int eax, int ebx, int ecx, int edx, int esi, int edi, int ebp); rct_object_entry *object_get_next(rct_object_entry *entry); int sub_6A9F42(FILE *file, rct_object_entry* entry); +void sub_6A9FC0(); int find_object_in_entry_group(rct_object_entry* entry, uint8* entry_type, uint8* entry_index); rct_object_entry *object_list_find(rct_object_entry *entry); diff --git a/src/object_list.c b/src/object_list.c index ee2df5d343..b2f4edf889 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -136,7 +136,7 @@ void sub_6A9FC0() for (int j = 0; j < object_entry_group_counts[type]; j++){ uint8* chunk = object_entry_groups[type].chunks[j]; if (chunk != (uint8*)-1) - object_paint(type, 0, 0, 0, 0, (int)chunk, 0, 0); + object_paint(type, 0, j, type, 0, (int)chunk, 0, 0); } } } @@ -488,7 +488,7 @@ void object_list_create_hash_table() } } -/* 0x006A9DA1 +/* 0x006A9DA2 * bl = entry_index * ecx = entry_type */ diff --git a/src/ride/track.c b/src/ride/track.c index 911712b9ce..3451388645 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -277,11 +277,12 @@ void track_load_list(ride_list_item item) fread(&track_file_count, 1, 1, file); rewind(file); if (track_file_count == totalFiles){ - //0x6CF060 assume skip remaking tracks.idx + fclose(file); + goto finish_creating_tracks_idx; } } + fclose(file); } - fclose(file); uint8* new_track_file; @@ -330,6 +331,7 @@ void track_load_list(ride_list_item item) free(new_track_file); +finish_creating_tracks_idx: file = fopen(tracks_path, "rb"); // 0x006CF060 see above. int file_size = fsize(file); @@ -359,7 +361,7 @@ void track_load_list(ride_list_item item) } else{ if (find_object_in_entry_group(track_object, &entry_type, &entry_index)){ - if (track_object->flags & 0x3000)continue; + if (GET_RIDE_ENTRY(entry_index)->var_008 & 0x3000)continue; } else{ uint32* esi = sub_6AB49A(track_object); @@ -412,6 +414,7 @@ void track_load_list(ride_list_item item) continue; } + *track_design_list_entry = '\0'; fclose(file); //RCT2_CALLPROC_X(0x006CED50, 0, 0, 0, *((uint16*)&item), 0, 0, 0); } diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index b7f21646c2..a68c18d77e 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -23,6 +23,9 @@ #include "../interface/widget.h" #include "../interface/window.h" #include "../object.h" +#include "../audio/audio.h" +#include "../ride/track.h" +#include "error.h" #pragma region Widgets @@ -55,9 +58,11 @@ enum WINDOW_STAFF_LIST_WIDGET_IDX { static void window_editor_object_selection_emptysub() { } static void window_editor_object_selection_mouseup(); +static void window_editor_object_selection_scroll_mousedown(); +static void window_editor_object_selection_close(); static void* window_editor_object_selection_events[] = { - (void*)0x006AB199, + window_editor_object_selection_close, (void*)window_editor_object_selection_mouseup, (void*)window_editor_object_selection_emptysub, (void*)window_editor_object_selection_emptysub, @@ -73,7 +78,7 @@ static void* window_editor_object_selection_events[] = { (void*)window_editor_object_selection_emptysub, (void*)window_editor_object_selection_emptysub, (void*)0x006AB031, - (void*)0x006AB0B6, + window_editor_object_selection_scroll_mousedown, (void*)window_editor_object_selection_emptysub, (void*)0x006AB079, (void*)window_editor_object_selection_emptysub, @@ -106,6 +111,10 @@ void window_editor_object_selection_open() RCT2_CALLPROC_EBPSAFE(0x006AB211); RCT2_CALLPROC_EBPSAFE(0x006AA770); + // HACK REMOVE WHEN ALL OBJECT_LOAD CALLS FINISHED + // Force Expansion Packs to always pass tests on object load + RCT2_GLOBAL(0x9AB4C0, uint16) = 0xFF; + window = window_create( RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) / 2 - 300, max(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) / 2 - 200, 28), @@ -194,4 +203,161 @@ static void window_editor_object_set_page(rct_window *w, int page) w->scrolls[0].v_top = 0; RCT2_CALLPROC_EBPSAFE(0x006A982D); // object_free_scenario_text(); window_invalidate(w); +} + +/* rct2: 0x006AA703 + * Takes the y coordinate of the clicked on scroll list + * and converts this into an object selection. + * Returns the position in the list. + * Object_selection_flags, installed_entry also populated + */ +int get_object_from_object_selection(uint8 object_type, int y, uint8* object_selection_flags, rct_object_entry** installed_entry){ + *installed_entry = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + int object_count = 0; + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i){ + if (((*installed_entry)->flags & 0xF) == object_type){ + if (!(*selection_flags & 0x20)){ + y -= 12; + *object_selection_flags = *selection_flags; + if (y < 0)return object_count; + object_count++; + } + } + + *installed_entry = object_get_next(*installed_entry); + selection_flags++; + } + return -1; +} + +/* rct2: 0x006D33E2 */ +void sub_6d33e2(){ + RCT2_GLOBAL(0x1357404, sint32) = -1; + RCT2_GLOBAL(0x1357408, sint32) = -1; + RCT2_GLOBAL(0x135740C, sint32) = -1; + RCT2_GLOBAL(0x1357410, sint32) = -1; + + for (int i = 0; i < 128; ++i){ + RCT2_ADDRESS(0x1357444, uint32)[i] = RCT2_ADDRESS(0x97C468, uint32)[i]; + RCT2_ADDRESS(0x1357644, uint32)[i] = RCT2_ADDRESS(0x97C5D4, uint32)[i]; + } + + for (int i = 0; i < 8; ++i){ + RCT2_ADDRESS(0x1357424, sint32)[i] = -1; + } + + RCT2_GLOBAL(0x141F570, uint8) = 7; + + int entry_index = 0; + for (; ((int)object_entry_groups[0].chunks[entry_index]) == -1; ++entry_index); + + //RCT2_GLOBAL(0xF44157, uint8) = entry_index; + + rct_ride_type* ride_entry = GET_RIDE_ENTRY(entry_index); + uint8* ride_type_array = &ride_entry->var_00C; + + int ride_type; + for (int i = 0; (ride_type = ride_type_array[i]) == 0xFF; i++); + //RCT2_GLOBAL(0xF44158, uint8) = ride_type; + + ride_list_item item = { ride_type, entry_index }; + track_load_list(item); + window_track_list_open(item); +} + +/* rct2: 0x006AB0B6 */ +static void window_editor_object_selection_scroll_mousedown(){ + short x, y, scrollIndex; + rct_window *w; + + window_scrollmouse_get_registers(w, scrollIndex, x, y); + + uint8 object_selection_flags; + rct_object_entry* installed_entry; + int selected_object = get_object_from_object_selection((w->selected_tab & 0xFF), y, &object_selection_flags, &installed_entry); + if (selected_object == -1) return; + + if (object_selection_flags & 0x20)return; + + window_invalidate(w); + + sound_play_panned(SOUND_CLICK_1, RCT2_GLOBAL(0x142406C,uint32), 0, 0, 0); + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER){ + if (RCT2_CALLPROC_X(0x6AB54F, 0, 1, 0, 0, 0, 0, (int)installed_entry) & 0x100)return; + + window_close(w); + + //This function calls window_track_list_open + sub_6d33e2(); + return; + } + + int ebx = 6; + // If already selected + if (!(object_selection_flags & 1)) + ebx = 7; + + RCT2_GLOBAL(0xF43411, uint8) = 0; + if (0x100 & RCT2_CALLPROC_X(0x6AB54F, 0, ebx, 0, 0, 0, 0, (int)installed_entry)){ + + rct_string_id error_title; + if (ebx & 1) + error_title = 3176; + else + error_title = 3177; + + window_error_open(error_title, RCT2_GLOBAL(0x141E9AC, uint16)); + return; + } + + if (!RCT2_GLOBAL(0xF43411, uint8) & 1)return; + + window_error_open(3374, 3375); +} + +/* rct2:0x006ABBBE */ +static void editor_load_selected_objects(){ + uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + rct_object_entry* installed_entry = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + + if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32) == 0)return; + + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i != 0; --i, selection_flags++){ + + if (*selection_flags & 1){ + + uint8 entry_index, entry_type; + if (!find_object_in_entry_group(installed_entry, &entry_type, &entry_index)){ + int chunk_size; + if (!object_load(-1, installed_entry, &chunk_size)){ + log_error("Failed to load entry %.8s", installed_entry->name); + } + } + } + + installed_entry = object_get_next(installed_entry); + } +} + +/* rct2: 0x006AB199 */ +static void window_editor_object_selection_close(){ + rct_window* w; + window_get_register(w); + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & + (SCREEN_FLAGS_SCENARIO_EDITOR | + SCREEN_FLAGS_TRACK_MANAGER | + SCREEN_FLAGS_TRACK_MANAGER)) + )return; + + RCT2_CALLPROC_EBPSAFE(0x6ABB66); + editor_load_selected_objects(); + sub_6A9FC0(); + RCT2_CALLPROC_EBPSAFE(0x6A982D); + RCT2_CALLPROC_EBPSAFE(0x6AB316); + RCT2_CALLPROC_EBPSAFE(0x685675); + RCT2_CALLPROC_EBPSAFE(0x68585B); + window_new_ride_init_vars(); } \ No newline at end of file diff --git a/src/windows/track_list.c b/src/windows/track_list.c index adec00a66a..758473269a 100644 --- a/src/windows/track_list.c +++ b/src/windows/track_list.c @@ -136,7 +136,7 @@ void window_track_list_open(ride_list_item item) x = 0; y = 29; } - w = window_create(0, 29, 600, 400, (uint32*)window_track_list_events, WC_TRACK_DESIGN_LIST, 0); + w = window_create(x, y, 600, 400, (uint32*)window_track_list_events, WC_TRACK_DESIGN_LIST, 0); w->widgets = window_track_list_widgets; w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_ROTATE) | (1 << WIDX_TOGGLE_SCENERY); window_init_scroll_widgets(w); @@ -144,7 +144,7 @@ void window_track_list_open(ride_list_item item) w->colours[1] = 26; w->colours[2] = 26; w->track_list.var_480 = 0xFFFF; - w->track_list.var_482 = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER ? 1 : 0; + w->track_list.var_482 = RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER ? 0 : 1; w->track_list.var_484 = 0; RCT2_GLOBAL(0x00F44152, uint8) = 0; window_push_others_right(w); @@ -618,9 +618,9 @@ static void window_track_list_scrollpaint() stringId2 = STR_BUILD_CUSTOM_DESIGN; gfx_draw_string_left(dpi, stringId, &stringId2, 0, x, y - 1); y += 10; + i++; } - i++; while (*trackDesignItem != 0) { if (y + 10 >= dpi->y && y < dpi->y + dpi->height) { if (i == w->track_list.var_482) { From 1fc525214d2bd4456e70b8c9c98cbe03203b959c Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Mon, 2 Feb 2015 18:52:50 +0000 Subject: [PATCH 4/4] Refactor track_load. Relabeled address' --- src/addresses.h | 7 +- src/ride/track.c | 292 +++++++++++++++++++++------------------ src/util/util.c | 10 ++ src/util/util.h | 1 + src/windows/track_list.c | 14 +- 5 files changed, 179 insertions(+), 145 deletions(-) diff --git a/src/addresses.h b/src/addresses.h index 9ccb46f65d..a0965b6896 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -254,10 +254,11 @@ #define RCT2_ADDRESS_STAFF_HIGHLIGHTED_INDEX 0x00F43908 -#define RCT2_ADDRESS_TRACK_LIST 0x00F44105 -#define RCT2_ADDRESS_TRACK_LIST_CACHE 0x00F44109 -#define RCT2_ADDRESS_TRACK_LIST_NEXT_INDEX 0x00F44119 +#define RCT2_ADDRESS_TRACK_DESIGN_CACHE 0x00F44105 +#define RCT2_ADDRESS_TRACK_DESIGN_INDEX_CACHE 0x00F44109 +#define RCT2_ADDRESS_TRACK_DESIGN_NEXT_INDEX_CACHE 0x00F44119 +#define RCT2_ADDRESS_TRACK_LIST 0x00F441EC #define RCT2_ADDRESS_CURRENT_MONTH_YEAR 0x00F663A8 #define RCT2_ADDRESS_CURRENT_MONTH_TICKS 0x00F663AA diff --git a/src/ride/track.c b/src/ride/track.c index 3451388645..44a079cf13 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -231,25 +231,18 @@ uint32* sub_6AB49A(rct_object_entry* entry){ return (((uint32*)object_get_next(object_list_entry)) - 1); } -/** - * - * rct2: 0x006CED50 - */ -void track_load_list(ride_list_item item) +static void get_track_idx_path(char *path) { - RCT2_GLOBAL(0xF635ED, uint8) = 0; + char *homePath = osinterface_get_orct2_homefolder(); + sprintf(path, "%s%c%s", homePath, osinterface_get_path_separator(), "Tracks.IDX"); + free(homePath); +} - if (item.type < 0x80){ - rct_ride_type* ride_type = gRideTypeList[item.entry_index]; - if (!(ride_type->var_008 & 0x2000)){ - item.entry_index = 0xFF; - } - } - - int enumFileHandle, totalFiles; +static void track_list_query_directory(int *outTotalFiles){ + int enumFileHandle; file_info enumFileInfo; - totalFiles = 0; + *outTotalFiles = 0; // Enumerate through each track in the directory enumFileHandle = platform_enumerate_files_begin(RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char)); @@ -257,92 +250,67 @@ void track_load_list(ride_list_item item) return; while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) { - totalFiles++; + (*outTotalFiles)++; } platform_enumerate_files_end(enumFileHandle); +} - const char* tracks_path = get_file_path(PATH_ID_TRACKSIDX); +static int track_list_cache_save(int fileCount, uint8* track_list_cache, uint32 track_list_size){ + char path[MAX_PATH]; + FILE *file; - FILE* file; - - file = fopen(tracks_path, "rb"); - - if (file == NULL){ - log_error("Failed to find tracks.idx"); - } - else{ - RCT2_GLOBAL(0xF44125, FILE*) = file; - if (item.type != 0xFC){ - uint8 track_file_count; - fread(&track_file_count, 1, 1, file); - rewind(file); - if (track_file_count == totalFiles){ - fclose(file); - goto finish_creating_tracks_idx; - } - } - fclose(file); - } - - uint8* new_track_file; - - new_track_file = malloc(0x40000); - - uint8* new_file_pointer = new_track_file; - *(uint32*)new_file_pointer = totalFiles; - new_file_pointer += 4; - - enumFileHandle = platform_enumerate_files_begin(RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char)); - if (enumFileHandle == INVALID_HANDLE) - return; - - while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) { - if (new_file_pointer > new_track_file + 0x3FF04)break; - - char path[MAX_PATH]; - subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), enumFileInfo.path); - - rct_track_td6* loaded_track = load_track_design(path); - if (loaded_track){ - *new_file_pointer++ = loaded_track->type; - } - else{ - *new_file_pointer++ = 0xFF; - } - memcpy(new_file_pointer, &loaded_track->vehicle_object, sizeof(rct_object_entry)); - new_file_pointer += sizeof(rct_object_entry); - - int file_name_length = strlen(enumFileInfo.path); - strcpy(new_file_pointer, enumFileInfo.path); - new_file_pointer += file_name_length + 1; - } - platform_enumerate_files_end(enumFileHandle); - - *new_file_pointer++ = 0xFE; - - file = fopen(tracks_path, "wb"); + log_verbose("saving track list cache (tracks.idx)"); + get_track_idx_path(path); + file = fopen(path, "wb"); if (file == NULL) { - log_error("Failed to save %s", tracks_path); - } - else{ - fwrite(new_track_file, (new_file_pointer - new_track_file), 1, file); - fclose(file); + log_error("Failed to save %s", path); + return 0; } - free(new_track_file); + fwrite(&fileCount, sizeof(int), 1, file); + fwrite(track_list_cache, track_list_size, 1, file); + uint8 last_entry = 0xFE; + fwrite(&last_entry, 1, 1, file); + fclose(file); + return 1; +} -finish_creating_tracks_idx: - file = fopen(tracks_path, "rb"); - // 0x006CF060 see above. - int file_size = fsize(file); - uint8* track_idx_file = malloc(file_size); - fread(track_idx_file, file_size, 1, file); +static uint8* track_list_cache_load(int totalFiles){ + char path[MAX_PATH]; + FILE *file; - // +4 Skip number of elements - uint8* track_pointer = track_idx_file + 4; - uint8* track_design_list_entry = RCT2_ADDRESS(0xF441EC, uint8); + log_verbose("loading track list cache (tracks.idx)"); + get_track_idx_path(path); + file = fopen(path, "rb"); + if (file == NULL) { + log_error("Failed to load %s", path); + return 0; + } - for (uint8 track_type = *track_pointer++; track_type != 0xFE; + uint8* track_list_cache; + uint32 fileCount; + // Remove 4 for the file count variable + long track_list_size = fsize(file) - 4; + + if (track_list_size < 0) return 0; + + fread(&fileCount, 4, 1, file); + + if (fileCount != totalFiles){ + log_verbose("Track file count is different."); + return 0; + } + + track_list_cache = malloc(track_list_size); + fread(track_list_cache, track_list_size, 1, file); + return track_list_cache; +} + +void track_list_populate(ride_list_item item, uint8* track_list_cache){ + uint8* track_pointer = track_list_cache; + + uint8 cur_track_entry_index = 0; + for (uint8 track_type = *track_pointer++; track_type != 0xFE; track_pointer += strlen(track_pointer) + 1, track_type = *track_pointer++){ rct_object_entry* track_object = (rct_object_entry*)track_pointer; @@ -370,52 +338,106 @@ finish_creating_tracks_idx: } } - if (track_design_list_entry >= RCT2_ADDRESS(0xF635EC, uint8)){ + // If cur_track_entry_index is greater than max number of tracks + if (cur_track_entry_index >= 1000){ RCT2_GLOBAL(0xF635ED, uint8) |= 1; break; } - uint8* edi = RCT2_ADDRESS(0xF441EC, uint8); - uint8 isBelow; - for (; edi != track_design_list_entry; edi += 128){ - //edx - uint8* current_entry = edi; - //ebx - uint8* track_name = track_pointer; - isBelow = 0; - - while (1){ - uint8 character = *track_name++; - if (character >= 'a' || character < 'z')character += 0xE0; - uint8 entry_char = *current_entry++; - if (entry_char >= 'a' || entry_char < 'z')entry_char += 0xE0; - if (character == entry_char && character != 0)continue; - - if (character == 0){ - isBelow = -1; - break; - } - if (character < entry_char) isBelow = 1; + uint8 track_entry_index = 0; + uint8 isBelow = 0; + for (; track_entry_index != cur_track_entry_index; track_entry_index++){ + if (strcicmp(track_pointer, &RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8)[track_entry_index * 128]) < 0){ + isBelow = 1; break; } - if (isBelow == 1) break; } if (isBelow == 1){ - uint8* edx = track_design_list_entry; - - while (edx >= edi){ - edx[128] = *edx--; - } + memmove( + &RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8)[track_entry_index * 128 + 128], + &RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8)[track_entry_index * 128], + (cur_track_entry_index - track_entry_index) * 128); } - uint8* track_name = track_pointer; - while (*edi++ = *track_name++); - track_design_list_entry += 128; - continue; + + strcpy(&RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8)[track_entry_index * 128], track_pointer); + cur_track_entry_index++; } - *track_design_list_entry = '\0'; - fclose(file); + RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8)[cur_track_entry_index * 128] = '\0'; + free(track_list_cache); +} + +/** + * + * rct2: 0x006CED50 + */ +void track_load_list(ride_list_item item) +{ + RCT2_GLOBAL(0xF635ED, uint8) = 0; + + if (item.type < 0x80){ + rct_ride_type* ride_type = gRideTypeList[item.entry_index]; + if (!(ride_type->var_008 & 0x2000)){ + item.entry_index = 0xFF; + } + } + + int totalFiles; + + track_list_query_directory(&totalFiles); + + uint8* track_list_cache; + + if (item.type == 0xFC || !(track_list_cache = track_list_cache_load(totalFiles))){ + uint8* new_track_file; + + new_track_file = malloc(0x40000); + + uint8* new_file_pointer = new_track_file; + file_info enumFileInfo; + + int enumFileHandle = platform_enumerate_files_begin(RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char)); + if (enumFileHandle == INVALID_HANDLE) + return; + + while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) { + if (new_file_pointer > new_track_file + 0x3FF00)break; + + char path[MAX_PATH]; + subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), enumFileInfo.path); + + rct_track_td6* loaded_track = load_track_design(path); + if (loaded_track){ + *new_file_pointer++ = loaded_track->type; + } + else{ + *new_file_pointer++ = 0xFF; + } + memcpy(new_file_pointer, &loaded_track->vehicle_object, sizeof(rct_object_entry)); + new_file_pointer += sizeof(rct_object_entry); + + int file_name_length = strlen(enumFileInfo.path); + strcpy(new_file_pointer, enumFileInfo.path); + new_file_pointer += file_name_length + 1; + } + platform_enumerate_files_end(enumFileHandle); + + if (!track_list_cache_save(totalFiles, new_track_file, new_file_pointer - new_track_file)){ + log_error("Track list failed to save."); + return; + } + free(new_track_file); + + track_list_cache = track_list_cache_load(totalFiles); + if (!track_list_cache){ + log_error("Track list failed to load after new save"); + return; + } + } + + track_list_populate(item, track_list_cache); + free(track_list_cache); //RCT2_CALLPROC_X(0x006CED50, 0, 0, 0, *((uint16*)&item), 0, 0, 0); } @@ -575,11 +597,11 @@ rct_track_td6* load_track_design(const char *path) /* rct2: 0x006D1DCE*/ void reset_track_list_cache(){ - int* track_list_cache = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST_CACHE, int); + int* track_list_cache = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_DESIGN_INDEX_CACHE, int); for (int i = 0; i < 4; ++i){ track_list_cache[i] = -1; } - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_LIST_NEXT_INDEX, uint32) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_NEXT_INDEX_CACHE, uint32) = 0; } /** @@ -590,26 +612,26 @@ void reset_track_list_cache(){ rct_track_design *track_get_info(int index, uint8** preview) { rct_track_design *trackDesign; - uint8 *trackDesignList = (uint8*)0x00F441EC; + uint8 *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8); int i; trackDesign = NULL; // Check if track design has already been loaded for (i = 0; i < 4; i++) { - if (index == RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST_CACHE, uint32)[i]) { - trackDesign = &RCT2_GLOBAL(RCT2_ADDRESS_TRACK_LIST, rct_track_design*)[i]; + if (index == RCT2_ADDRESS(RCT2_ADDRESS_TRACK_DESIGN_INDEX_CACHE, uint32)[i]) { + trackDesign = &RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, rct_track_design*)[i]; break; } } if (trackDesign == NULL) { // Load track design - i = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_LIST_NEXT_INDEX, uint32)++; - if (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_LIST_NEXT_INDEX, uint32) >= 4) - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_LIST_NEXT_INDEX, uint32) = 0; + i = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_NEXT_INDEX_CACHE, uint32)++; + if (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_NEXT_INDEX_CACHE, uint32) >= 4) + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_NEXT_INDEX_CACHE, uint32) = 0; - RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST_CACHE, uint32)[i] = index; + RCT2_ADDRESS(RCT2_ADDRESS_TRACK_DESIGN_INDEX_CACHE, uint32)[i] = index; char track_path[MAX_PATH] = { 0 }; subsitute_path(track_path, (char*)RCT2_ADDRESS_TRACKS_PATH, trackDesignList + (index * 128)); @@ -624,7 +646,7 @@ rct_track_design *track_get_info(int index, uint8** preview) return NULL; } - trackDesign = &RCT2_GLOBAL(RCT2_ADDRESS_TRACK_LIST, rct_track_design*)[i]; + trackDesign = &RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, rct_track_design*)[i]; // Copy the track design apart from the preview image memcpy(&trackDesign->track_td6, loaded_track, sizeof(rct_track_td6)); diff --git a/src/util/util.c b/src/util/util.c index 8abdaca2ca..dffbb8a5ee 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -75,4 +75,14 @@ int bitscanforward(int source) return i; return -1; +} + +/* case insensitve compare */ +int strcicmp(char const *a, char const *b) +{ + for (;; a++, b++) { + int d = tolower(*a) - tolower(*b); + if (d != 0 || !*a) + return d; + } } \ No newline at end of file diff --git a/src/util/util.h b/src/util/util.h index 82098918be..ac62a3ad79 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -31,5 +31,6 @@ void path_set_extension(char *path, const char *extension); long fsize(FILE *fp); int bitscanforward(int source); +int strcicmp(char const *a, char const *b); #endif diff --git a/src/windows/track_list.c b/src/windows/track_list.c index 758473269a..bda822fcc4 100644 --- a/src/windows/track_list.c +++ b/src/windows/track_list.c @@ -126,7 +126,7 @@ void window_track_list_open(ride_list_item item) if (mem == NULL) return; - RCT2_GLOBAL(RCT2_ADDRESS_TRACK_LIST, void*) = mem; + RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, void*) = mem; reset_track_list_cache(); if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) { @@ -157,7 +157,7 @@ void window_track_list_open(ride_list_item item) */ static void window_track_list_select(rct_window *w, int index) { - uint8 *trackDesignItem, *trackDesignList = (uint8*)0x00F441EC; + uint8 *trackDesignItem, *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8); rct_track_design *trackDesign; w->track_list.var_480 = index; @@ -212,7 +212,7 @@ static void window_track_list_select(rct_window *w, int index) static int window_track_list_get_list_item_index_from_position(int x, int y) { int index; - uint8 *trackDesignItem, *trackDesignList = (uint8*)0x00F441EC; + uint8 *trackDesignItem, *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8); index = 0; if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER)) { @@ -238,7 +238,7 @@ static int window_track_list_get_list_item_index_from_position(int x, int y) */ static void window_track_list_close() { - free(RCT2_GLOBAL(RCT2_ADDRESS_TRACK_LIST, void*)); + free(RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, void*)); } /** @@ -282,7 +282,7 @@ static void window_track_list_scrollgetsize() { rct_window *w; int width, height; - uint8 *trackDesignItem, *trackDesignList = (uint8*)0x00F441EC; + uint8 *trackDesignItem, *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8); window_get_register(w); @@ -401,7 +401,7 @@ static void window_track_list_paint() rct_drawpixelinfo *dpi; rct_widget *widget; rct_track_design *trackDesign = NULL; - uint8 *image, *trackDesignList = (uint8*)0x00F441EC; + uint8 *image, *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8); uint16 holes, speed, drops, dropHeight, inversions; fixed32_2dp rating; int trackIndex, x, y, colour, gForces, airTime; @@ -586,7 +586,7 @@ static void window_track_list_scrollpaint() rct_drawpixelinfo *dpi; rct_string_id stringId, stringId2; int i, x, y, colour; - uint8 *trackDesignItem, *trackDesignList = (uint8*)0x00F441EC; + uint8 *trackDesignItem, *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8); window_paint_get_registers(w, dpi);