diff --git a/data/language/english_uk.txt b/data/language/english_uk.txt index 0faa5a9dad..e6683e72b9 100644 --- a/data/language/english_uk.txt +++ b/data/language/english_uk.txt @@ -3176,7 +3176,7 @@ STR_3168 :{WINDOW_COLOUR_2}Text: {BLACK}{STRINGID} STR_3169 :Data for the following object not found: STR_3170 :Not enough space for graphics STR_3171 :Too many objects of this type selected -STR_3172 :The following object must be selected first: +STR_3172 :The following object must be selected first: {STRING} STR_3173 :This object is currently in use STR_3174 :This object is required by another object STR_3175 :This object is always required diff --git a/src/addresses.h b/src/addresses.h index e74cede5f2..34a652bdd9 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -298,6 +298,8 @@ // 1 if custom objects installed, 0 otherwise #define RCT2_ADDRESS_CUSTOM_OBJECTS_INSTALLED 0x00F42BDA +#define RCT2_ADDRESS_SELECTED_OBJECTS_FILE_SIZE 0x00F4340D + #define RCT2_ADDRESS_VOLUME_ADJUST_ZOOM 0x00F438AC #define RCT2_ADDRESS_STAFF_HIGHLIGHTED_INDEX 0x00F43908 diff --git a/src/management/research.c b/src/management/research.c index f44ed4c5b2..383c21750a 100644 --- a/src/management/research.c +++ b/src/management/research.c @@ -434,6 +434,18 @@ static void research_insert_researched(int entryIndex, int category) } while (entryIndex != (researchItem++)->entryIndex); } +/* rct2: 0x006857CF */ +void research_remove(sint32 entryIndex){ + for (rct_research_item *researchItem = gResearchItems; researchItem->entryIndex != RESEARCHED_ITEMS_END; researchItem++){ + if (researchItem->entryIndex == entryIndex){ + do{ + *researchItem = *(researchItem + 1); + } while (researchItem++->entryIndex != RESEARCHED_ITEMS_END_2); + return; + } + } +} + void research_insert(int researched, int entryIndex, int category) { if (researched) diff --git a/src/management/research.h b/src/management/research.h index e26725b6db..f2a0d4b3f6 100644 --- a/src/management/research.h +++ b/src/management/research.h @@ -83,5 +83,6 @@ void research_set_priority(int activeCategories); void game_command_set_research_funding(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp); void research_finish_item(sint32 entryIndex); void research_insert(int researched, int entryIndex, int category); +void research_remove(sint32 entryIndex); #endif \ No newline at end of file diff --git a/src/object.c b/src/object.c index 0f83bab287..7e6609ec78 100644 --- a/src/object.c +++ b/src/object.c @@ -1619,7 +1619,7 @@ rct_object_entry *object_get_next(rct_object_entry *entry) // Skip size of chunk pos += 4; - // Skip + // Skip required objects pos += *pos * 16 + 1; // Skip theme objects diff --git a/src/object.h b/src/object.h index cfe41692d6..cf5b735d61 100644 --- a/src/object.h +++ b/src/object.h @@ -38,6 +38,17 @@ typedef enum{ OBJECT_TYPE_SCENARIO_TEXT }OBJECT_TYPE; +typedef enum{ + OBJECT_SELECTION_FLAG_SELECTED = (1 << 0), + OBJECT_SELECTION_FLAG_2 = (1 << 1), + OBJECT_SELECTION_FLAG_IN_USE = (1 << 2), + OBJECT_SELECTION_FLAG_REQUIRED = (1 << 3), + OBJECT_SELECTION_FLAG_ALWAYS_REQUIRED = (1 << 4), + OBJECT_SELECTION_FLAG_6 = (1 << 5), + OBJECT_SELECTION_FLAG_7 = (1 << 6), + OBJECT_SELECTION_FLAG_8 = (1 << 7), +}OBJECT_SELECTION_FLAGS; + /** * Object entry structure. * size: 0x10 @@ -101,6 +112,7 @@ rct_object_entry *object_get_next(rct_object_entry *entry); int write_object_file(FILE *file, rct_object_entry* entry); void reset_loaded_objects(); int find_object_in_entry_group(rct_object_entry* entry, uint8* entry_type, uint8* entry_index); +void object_create_identifier_name(uint8* string_buffer, rct_object_entry* object); rct_object_entry *object_list_find(rct_object_entry *entry); diff --git a/src/object_list.c b/src/object_list.c index 7c11b55a7b..e1493345ac 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -451,6 +451,30 @@ int check_object_entry(rct_object_entry *entry) return (0xFFFFFFFF & dwords[0] & dwords[1] & dwords[2] & dwords[3]) + 1 != 0; } +/* rct2: 0x006AB344 */ +void object_create_identifier_name(uint8* string_buffer, rct_object_entry* object){ + for (uint8 i = 0; i < 8; ++i){ + if (object->name[i] != ' '){ + *string_buffer++ = object->name[i]; + } + } + + *string_buffer++ = '/'; + + for (uint8 i = 0; i < 4; ++i){ + uint8 flag_part = (object->flags >> (i * 8)) & 0xFF; + *string_buffer++ = RCT2_ADDRESS(0x0098DA64, uint8)[flag_part >> 4]; + *string_buffer++ = RCT2_ADDRESS(0x0098DA64, uint8)[flag_part & 0xF]; + } + + for (uint8 i = 0; i < 4; ++i){ + uint8 checksum_part = (object->checksum >> (i * 8)) & 0xFF; + *string_buffer++ = RCT2_ADDRESS(0x0098DA64, uint8)[checksum_part >> 4]; + *string_buffer++ = RCT2_ADDRESS(0x0098DA64, uint8)[checksum_part & 0xF]; + } + *string_buffer++ = '\0'; +} + /* rct2: 0x675827 */ void set_load_objects_fail_reason(){ rct_object_entry* object = RCT2_ADDRESS(0x13CE952, rct_object_entry); @@ -463,7 +487,7 @@ void set_load_objects_fail_reason(){ format_string(string_buffer, 3323, 0); //Missing object data, ID: - RCT2_CALLPROC_X(0x6AB344, 0, 0, 0, 0, 0, (int)string_buffer, 0x13CE952); + object_create_identifier_name(string_buffer, object); RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 0xFF; RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16) = 3165; return; diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index 6697ec28cc..68a6c4cbc9 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -202,7 +202,8 @@ static void* window_editor_object_selection_events[] = { static void window_editor_object_set_page(rct_window *w, int page); static void window_editor_object_selection_set_pressed_tab(rct_window *w); static void window_editor_object_selection_select_default_objects(); -static int window_editor_object_selection_select_object(int flags, rct_object_entry *entry); +static void window_editor_object_selection_select_required_objects(); +static int window_editor_object_selection_select_object(uint8 bh, int flags, rct_object_entry *entry); static int get_object_from_object_selection(uint8 object_type, int y, uint8 *object_selection_flags, rct_object_entry **installed_entry); static void window_editor_object_selection_manage_tracks(); static void editor_load_selected_objects(); @@ -211,40 +212,46 @@ static bool filter_source(rct_object_entry *entry); static bool filter_chunks(rct_object_entry *entry, rct_object_filters *filter); static void filter_update_counts(); -static rct_object_entry DefaultSelectedObjects[] = { - // Objects that are always required - { 0x00000087, { "SCGTREES" }, 0 }, // Scenery: Trees - { 0x00000087, { "SCGSHRUB" }, 0 }, // Scenery: Shrubs and Ornaments - { 0x00000087, { "SCGGARDN" }, 0 }, // Scenery: Gardens - { 0x00000087, { "SCGFENCE" }, 0 }, // Scenery: Fences and Walls - { 0x00000087, { "SCGWALLS" }, 0 }, // Scenery: Walls and Roofs - { 0x00000087, { "SCGPATHX" }, 0 }, // Scenery: Signs and Items for Footpaths - { 0x00000085, { "TARMAC " }, 0 }, // Footpath: Tarmac +void reset_selected_object_count_and_size(); +void reset_required_object_flags(); +static int sub_6AB211(); +static rct_object_entry RequiredSelectedObjects[] = { + // Objects that are always required + { 0x00000087, { "SCGTREES" }, 0 }, // Scenery: Trees + { 0x00000087, { "SCGSHRUB" }, 0 }, // Scenery: Shrubs and Ornaments + { 0x00000087, { "SCGGARDN" }, 0 }, // Scenery: Gardens + { 0x00000087, { "SCGFENCE" }, 0 }, // Scenery: Fences and Walls + { 0x00000087, { "SCGWALLS" }, 0 }, // Scenery: Walls and Roofs + { 0x00000087, { "SCGPATHX" }, 0 }, // Scenery: Signs and Items for Footpaths + { 0x00000085, { "TARMAC " }, 0 }, // Footpath: Tarmac +}; + +static rct_object_entry DefaultSelectedObjects[] = { // An initial default selection - { 0x000080FF, { "TWIST1 " }, 0 }, // Ride: Twist - { 0x00008000, { "PTCT1 " }, 0 }, // Ride: Wooden Roller Coaster (Wooden Roller Coaster Trains) - { 0x00008000, { "ZLDB " }, 0 }, // Ride: Junior Roller Coaster (Ladybird Trains) - { 0x00008000, { "LFB1 " }, 0 }, // Ride: Log Flume - { 0x00008000, { "VCR " }, 0 }, // Ride: Vintage Cars - { 0x00008000, { "MGR1 " }, 0 }, // Ride: Merry-Go-Round - { 0x00008000, { "TLT1 " }, 0 }, // Ride: Restroom - { 0x00008000, { "ATM1 " }, 0 }, // Ride: Cash Machine - { 0x00008000, { "FAID1 " }, 0 }, // Ride: First Aid Room - { 0x00008000, { "INFOK " }, 0 }, // Ride: Information Kiosk - { 0x00008000, { "DRNKS " }, 0 }, // Ride: Drinks Stall - { 0x00008000, { "CNDYF " }, 0 }, // Ride: Cotten Candy Stall - { 0x00008000, { "BURGB " }, 0 }, // Ride: Burger Bar - { 0x00008000, { "BALLN " }, 0 }, // Ride: Balloon Stall - { 0x00008000, { "ARRT1 " }, 0 }, // Ride: Corkscrew Roller Coaster - { 0x00008000, { "RBOAT " }, 0 }, // Ride: Rowing Boats - { 0x00008800, { "PKENT1 " }, 0 }, // Park Entrace: Traditional Park Entrance - { 0x00008900, { "WTRCYAN " }, 0 }, // Water: Natural Water - { 0x00008500, { "TARMACB " }, 0 }, // Footpath: Brown Tarmac Footpath - { 0x00008500, { "PATHSPC " }, 0 }, // Footpath: Space Style Footpath - { 0x00008500, { "PATHDIR " }, 0 }, // Footpath: Dirt Footpath - { 0x00008500, { "PATHCRZ " }, 0 }, // Footpath: Crazy Paving Footpath - { 0x00008500, { "PATHASH " }, 0 }, // Footpath: Ash Footpath + { 0x00000080, { "TWIST1 " }, 0 }, // Ride: Twist + { 0x00000080, { "PTCT1 " }, 0 }, // Ride: Wooden Roller Coaster (Wooden Roller Coaster Trains) + { 0x00000080, { "ZLDB " }, 0 }, // Ride: Junior Roller Coaster (Ladybird Trains) + { 0x00000080, { "LFB1 " }, 0 }, // Ride: Log Flume + { 0x00000080, { "VCR " }, 0 }, // Ride: Vintage Cars + { 0x00000080, { "MGR1 " }, 0 }, // Ride: Merry-Go-Round + { 0x00000080, { "TLT1 " }, 0 }, // Ride: Restroom + { 0x00000080, { "ATM1 " }, 0 }, // Ride: Cash Machine + { 0x00000080, { "FAID1 " }, 0 }, // Ride: First Aid Room + { 0x00000080, { "INFOK " }, 0 }, // Ride: Information Kiosk + { 0x00000080, { "DRNKS " }, 0 }, // Ride: Drinks Stall + { 0x00000080, { "CNDYF " }, 0 }, // Ride: Cotten Candy Stall + { 0x00000080, { "BURGB " }, 0 }, // Ride: Burger Bar + { 0x00000080, { "BALLN " }, 0 }, // Ride: Balloon Stall + { 0x00000080, { "ARRT1 " }, 0 }, // Ride: Corkscrew Roller Coaster + { 0x00000080, { "RBOAT " }, 0 }, // Ride: Rowing Boats + { 0x00000088, { "PKENT1 " }, 0 }, // Park Entrace: Traditional Park Entrance + { 0x00000089, { "WTRCYAN " }, 0 }, // Water: Natural Water + { 0x00000085, { "TARMACB " }, 0 }, // Footpath: Brown Tarmac Footpath + { 0x00000085, { "PATHSPCE" }, 0 }, // Footpath: Space Style Footpath + { 0x00000085, { "PATHDIRT" }, 0 }, // Footpath: Dirt Footpath + { 0x00000085, { "PATHCRZY" }, 0 }, // Footpath: Crazy Paving Footpath + { 0x00000085, { "PATHASH " }, 0 }, // Footpath: Ash Footpath // The following are for all random map generation features to work out the box { 0x00000087, { "SCGJUNGL" }, 0 }, // Jungle Themeing @@ -264,12 +271,9 @@ void window_editor_object_selection_open() if (window != NULL) return; - RCT2_CALLPROC_EBPSAFE(0x006AB211); - RCT2_CALLPROC_EBPSAFE(0x006AA770); - - // Not really where its called, but easy way to change default objects for now - if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) - window_editor_object_selection_select_default_objects(); + if (!sub_6AB211()) + return; + reset_selected_object_count_and_size(); window = window_create_centred( 600, @@ -301,6 +305,316 @@ void window_editor_object_selection_open() window->var_494 = 0xFFFFFFFF; } +/* rct2: 0x006ABCD1 */ +static void setup_track_manager_objects(){ + uint8 ride_list[128] = { 0 }; + uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + rct_object_entry* installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + uint16 num_objects = 0; + + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i){ + uint8 object_type = installedObject->flags & 0xF; + if (object_type == OBJECT_TYPE_RIDE){ + *selection_flags |= OBJECT_SELECTION_FLAG_6; + + uint8* pos = (uint8*)installedObject; + // Skip sizeof(rct_object_entry) + pos += 16; + + // Skip filename + while (*pos++); + + // Skip no of images + pos += 4; + + // Skip name + while (*pos++); + + // Skip size of chunk + pos += 4; + + // Skip required objects + pos += *pos * 16 + 1; + + // Skip theme objects + pos += *pos * 16 + 1; + + for (uint8 j = 0; j < 3; j++){ + uint8 ride_type = pos[j]; + if (ride_type == 0xFF) + continue; + + if (!(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride_type * 2] & + RIDE_TYPE_FLAG_HAS_TRACK)) + continue; + + if (pos[3] & (1 << 0)){ + *selection_flags &= ~OBJECT_SELECTION_FLAG_6; + } + else if (ride_list[ride_type] & (1 << 0)){ + continue; + } + else{ + ride_list[ride_type] |= (1 << 0); + *selection_flags &= ~OBJECT_SELECTION_FLAG_6; + } + num_objects++; + break; + } + } + + installedObject = object_get_next(installedObject); + selection_flags++; + } + + RCT2_GLOBAL(0x00F43412, uint16) = num_objects; +} + +/* rct2: 0x006ABC1E */ +static void setup_track_designer_objects(){ + uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + rct_object_entry* installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + uint16 num_objects = 0; + + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i){ + uint8 object_type = installedObject->flags & 0xF; + if (object_type == OBJECT_TYPE_RIDE){ + *selection_flags |= OBJECT_SELECTION_FLAG_6; + + uint8* pos = (uint8*)installedObject; + // Skip sizeof(rct_object_entry) + pos += 16; + + // Skip filename + while (*pos++); + + // Skip no of images + pos += 4; + + // Skip name + while (*pos++); + + // Skip size of chunk + pos += 4; + + // Skip required objects + pos += *pos * 16 + 1; + + // Skip theme objects + pos += *pos * 16 + 1; + + for (uint8 j = 0; j < 3; j++){ + uint8 ride_type = pos[j]; + if (ride_type == 0xFF) + continue; + + if (!(RCT2_ADDRESS(0x0097D4F2, uint16)[ride_type * 4] & + (1 << 11))) + continue; + + *selection_flags &= ~OBJECT_SELECTION_FLAG_6; + num_objects++; + break; + } + } + + installedObject = object_get_next(installedObject); + selection_flags++; + } + + RCT2_GLOBAL(0x00F43412, uint16) = num_objects; +} + +/* rct2: 0x006AA82B */ +static void setup_in_use_selection_flags(){ + + for (uint8 object_type = 0; object_type < 11; object_type++){ + for (uint16 i = 0; i < object_entry_group_counts[object_type]; i++){ + RCT2_ADDRESS(0x0098DA38, uint8*)[object_type][i] = 0; + } + } + + for (uint8 object_type = 0; object_type < 11; object_type++){ + for (uint16 i = 0; i < object_entry_group_counts[object_type]; i++){ + if (object_entry_groups[object_type].chunks[i] != (uint8*)0xFFFFFFFF){ + RCT2_ADDRESS(0x0098DA38, uint8*)[object_type][i] |= (1 << 1); + } + } + } + + map_element_iterator iter; + map_element_iterator_begin(&iter); + do { + uint16 type; + uint8 path_additions; + rct_banner* banner; + + switch (map_element_get_type(iter.element)) { + default: + case MAP_ELEMENT_TYPE_SURFACE: + case MAP_ELEMENT_TYPE_TRACK: + break; + case MAP_ELEMENT_TYPE_PATH: + type = iter.element->properties.path.type; + RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_PATHS][type] |= (1 << 0); + + path_additions = iter.element->properties.path.additions & 0xF; + if (path_additions){ + path_additions--; + RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_PATH_BITS][path_additions] |= (1 << 0); + } + break; + case MAP_ELEMENT_TYPE_SCENERY: + type = iter.element->properties.scenery.type; + RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_SMALL_SCENERY][type] |= (1 << 0); + break; + case MAP_ELEMENT_TYPE_ENTRANCE: + if (iter.element->properties.entrance.type != ENTRANCE_TYPE_PARK_ENTRANCE) + break; + + RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_PARK_ENTRANCE][0] |= (1 << 0); + + type = iter.element->properties.entrance.path_type; + RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_PATHS][type] |= (1 << 0); + break; + case MAP_ELEMENT_TYPE_FENCE: + type = iter.element->properties.fence.type; + RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_WALLS][type] |= (1 << 0); + break; + case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: + type = iter.element->properties.scenerymultiple.type & 0x3FF; + RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_LARGE_SCENERY][type] |= (1 << 0); + break; + case MAP_ELEMENT_TYPE_BANNER: + banner = &gBanners[iter.element->properties.banner.index]; + type = banner->type; + RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_BANNERS][type] |= (1 << 0); + break; + } + } while (map_element_iterator_next(&iter)); + + for (uint8 ride_index = 0; ride_index < 0xFF; ride_index++){ + rct_ride* ride = GET_RIDE(ride_index); + if (ride->type == RIDE_TYPE_NULL) + continue; + + uint8 type = ride->subtype; + RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_RIDE][type] |= (1 << 0); + } + + uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + rct_object_entry* installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i){ + *selection_flags &= ~OBJECT_SELECTION_FLAG_IN_USE; + + uint8 entry_type, entry_index; + if (find_object_in_entry_group(installedObject, &entry_type, &entry_index)){ + if (RCT2_ADDRESS(0x0098DA38, uint8*)[entry_type][entry_index] & (1 << 0)){ + *selection_flags |= + OBJECT_SELECTION_FLAG_IN_USE | + OBJECT_SELECTION_FLAG_SELECTED; + } + if (RCT2_ADDRESS(0x0098DA38, uint8*)[entry_type][entry_index] & (1 << 1)){ + *selection_flags |= OBJECT_SELECTION_FLAG_SELECTED; + } + } + installedObject = object_get_next(installedObject); + selection_flags++; + } +} + +/* rct2: 0x006AB211 */ +static int sub_6AB211(){ + uint32 total_objects = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); + + RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*) = rct2_malloc(total_objects); + + if (RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*) == NULL){ + log_error("Failed to allocate memory for object flag list."); + return 0; + } + + memset(RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*), 0, total_objects); + for (uint8 object_type = 0; object_type < 11; object_type++){ + RCT2_ADDRESS(0x00F433F7, uint16)[object_type] = 0; + RCT2_ADDRESS(0x00F433E1, uint16)[object_type] = 0; + } + + rct_object_entry* installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i){ + uint8 object_type = installedObject->flags & 0xF; + RCT2_ADDRESS(0x00F433E1, uint16)[object_type]++; + + installedObject = object_get_next(installedObject); + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER){ + setup_track_designer_objects(); + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER){ + setup_track_manager_objects(); + } + + setup_in_use_selection_flags(); + reset_selected_object_count_and_size(); + + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER))){ + window_editor_object_selection_select_required_objects(); + + // To prevent it breaking in scenario mode. + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) + window_editor_object_selection_select_default_objects(); + } + + reset_required_object_flags(); + reset_selected_object_count_and_size(); + return 1; +} + +/* rct2: 0x006AB316 */ +static void editor_object_flags_free(){ + if (RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*) == NULL){ + return; + } + rct2_free(RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*)); + RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*) = NULL; +} + +/* rct2: 0x00685791 */ +void remove_selected_objects_from_research(rct_object_entry* installedObject){ + uint8 entry_type, entry_index; + if (!find_object_in_entry_group(installedObject, &entry_type, &entry_index)) + return; + + if (entry_type == OBJECT_TYPE_RIDE){ + rct_ride_type* rideEntry = (rct_ride_type*)object_entry_groups[entry_type].chunks[entry_index]; + research_remove(entry_index | rideEntry->ride_type[0] << 8 | 0x10000); + research_remove(entry_index | rideEntry->ride_type[1] << 8 | 0x10000); + research_remove(entry_index | rideEntry->ride_type[2] << 8 | 0x10000); + } + else if (entry_type == OBJECT_TYPE_SCENERY_SETS){ + research_remove(entry_index); + } +} + +/* rct2: 0x006ABB66 */ +void unload_selected_objects(){ + uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + rct_object_entry* installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i){ + if (*selection_flags & OBJECT_SELECTION_FLAG_SELECTED){ + remove_selected_objects_from_research(installedObject); + object_unload(0, (rct_object_entry_extended*)installedObject); + } + selection_flags++; + installedObject = object_get_next(installedObject); + } +} + /** * * rct2: 0x006AB199 @@ -313,11 +627,12 @@ static void window_editor_object_selection_close() //if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_EDITOR)) // return; - RCT2_CALLPROC_EBPSAFE(0x6ABB66); + unload_selected_objects(); editor_load_selected_objects(); reset_loaded_objects(); object_free_scenario_text(); - RCT2_CALLPROC_EBPSAFE(0x6AB316); + editor_object_flags_free(); + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_EDITOR) { research_populate_list_random(); research_remove_non_separate_vehicle_types(); @@ -521,7 +836,7 @@ static void window_editor_object_selection_scroll_mousedown() 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 || (object_selection_flags & 0x20)) + if (selected_object == -1 || (object_selection_flags & OBJECT_SELECTION_FLAG_6)) return; window_invalidate(w); @@ -530,7 +845,7 @@ static void window_editor_object_selection_scroll_mousedown() if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) { - if (!window_editor_object_selection_select_object(1, installed_entry)) + if (!window_editor_object_selection_select_object(0, 1, installed_entry)) return; // Close any other open windows such as options/colour schemes to prevent a crash. @@ -544,11 +859,11 @@ static void window_editor_object_selection_scroll_mousedown() int ebx = 6; // If already selected - if (!(object_selection_flags & 1)) + if (!(object_selection_flags & OBJECT_SELECTION_FLAG_SELECTED)) ebx = 7; RCT2_GLOBAL(0xF43411, uint8) = 0; - if (!window_editor_object_selection_select_object(ebx, installed_entry)) { + if (!window_editor_object_selection_select_object(0, ebx, installed_entry)) { rct_string_id error_title = ebx & 1 ? STR_UNABLE_TO_SELECT_THIS_OBJECT : STR_UNABLE_TO_DE_SELECT_THIS_OBJECT; @@ -580,7 +895,7 @@ static void window_editor_object_selection_scroll_mouseover() selectedObject = get_object_from_object_selection( w->selected_tab & 0xFF, y, &objectSelectionFlags, &installedEntry ); - if (objectSelectionFlags & 0x20) + if (objectSelectionFlags & OBJECT_SELECTION_FLAG_6) selectedObject = -1; if (selectedObject == w->selected_list_item) @@ -951,13 +1266,13 @@ static void window_editor_object_selection_scrollpaint() numObjects = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, sint32); entry = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); - itemFlags = RCT2_GLOBAL(0x009ADAEC, uint8*); + itemFlags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); y = 0; for (i = 0; i < numObjects; i++) { filter = get_object_filter(i); type = entry->flags & 0x0F; source = (entry->flags & 0xF0) >> 4; - if (type == w->selected_tab && !(*itemFlags & 0x20) && filter_source(entry) && filter_string(entry) && filter_chunks(entry, filter)) { + if (type == w->selected_tab && !(*itemFlags & OBJECT_SELECTION_FLAG_6) && filter_source(entry) && filter_string(entry) && filter_chunks(entry, filter)) { if (y + 12 >= dpi->y && y <= dpi->y + dpi->height) { // Draw checkbox if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) && !(*itemFlags & 0x20)) @@ -965,17 +1280,17 @@ static void window_editor_object_selection_scrollpaint() // Highlight background colour = 142; - if (entry == (rct_object_entry*)w->var_494 && !(*itemFlags & 0x20)) { + if (entry == (rct_object_entry*)w->var_494 && !(*itemFlags & OBJECT_SELECTION_FLAG_6)) { gfx_fill_rect(dpi, 0, y, w->width, y + 11, 0x2000031); colour = 14; } // Draw checkmark - if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) && (*itemFlags & 1)) { + if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) && (*itemFlags & OBJECT_SELECTION_FLAG_SELECTED)) { x = 2; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, sint16) = colour == 14 ? -2 : -1; colour2 = w->colours[1] & 0x7F; - if (*itemFlags & 0x1C) + if (*itemFlags & (OBJECT_SELECTION_FLAG_IN_USE | OBJECT_SELECTION_FLAG_REQUIRED | OBJECT_SELECTION_FLAG_ALWAYS_REQUIRED)) colour2 |= 0x40; gfx_draw_string(dpi, (char*)0x009DED72, colour2, x, y); @@ -992,10 +1307,11 @@ static void window_editor_object_selection_scrollpaint() *buffer = 0; } - if (*itemFlags & 0x20) { + if (*itemFlags & OBJECT_SELECTION_FLAG_6) { colour = w->colours[1] & 0x7F; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, sint16) = -1; - } else { + } + else { colour = 0; RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, sint16) = 224; } @@ -1032,27 +1348,361 @@ static void window_editor_object_selection_set_pressed_tab(rct_window *w) } /** - * - * rct2: 0x006AA7E9 - */ +* +* rct2: 0x006AA805 +*/ static void window_editor_object_selection_select_default_objects() { int i; - if (RCT2_GLOBAL(0x00F433F7, uint16) == 0) + if (RCT2_GLOBAL(0x00F433F7, uint16) != 0) return; for (i = 0; i < countof(DefaultSelectedObjects); i++) - window_editor_object_selection_select_object(7, &DefaultSelectedObjects[i]); + window_editor_object_selection_select_object(0, 7, &DefaultSelectedObjects[i]); +} + +/** + * + * rct2: 0x006AA7E9 + */ +static void window_editor_object_selection_select_required_objects() +{ + int i; + + for (i = 0; i < countof(RequiredSelectedObjects); i++) + window_editor_object_selection_select_object(0, 0xF, &RequiredSelectedObjects[i]); +} + +/* rct2: 0x006AA770 */ +void reset_selected_object_count_and_size(){ + for (uint8 object_type = 0; object_type < 11; object_type++){ + RCT2_ADDRESS(0x00F433F7, uint16)[object_type] = 0; + } + + uint32 total_object_size = 0; + + uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + rct_object_entry* installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i){ + uint8 object_type = installedObject->flags & 0xF; + + if (*selection_flags & OBJECT_SELECTION_FLAG_SELECTED){ + uint8* pos = (uint8*)installedObject; + // Skip sizeof(rct_object_entry) + pos += 16; + + // Skip filename + while (*pos++); + + // Skip no of images + pos += 4; + + // Skip name + while (*pos++); + + uint32 size_of_chunk = *((uint32*)pos); + RCT2_ADDRESS(0x00F433F7, uint16)[object_type]++; + total_object_size += size_of_chunk; + } + selection_flags++; + installedObject = object_get_next(installedObject); + } + + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_OBJECTS_FILE_SIZE, uint32) = total_object_size; +} + +/* rct2: 0x006AB863 */ +void set_required_object_flags(rct_object_entry* required_object){ + uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + rct_object_entry* installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i){ + if (object_entry_compare(required_object, installedObject)){ + *selection_flags |= OBJECT_SELECTION_FLAG_REQUIRED; + + uint8* pos = (uint8*)installedObject; + // Skip sizeof(rct_object_entry) + pos += 16; + + // Skip filename + while (*pos++); + + // Skip no of images + pos += 4; + + // Skip name + while (*pos++); + + // Skip size of chunk + pos += 4; + + uint8 no_required_objects = *pos++; + + required_object = (rct_object_entry*)pos; + for (; no_required_objects > 0; no_required_objects--){ + set_required_object_flags(required_object); + required_object++; + } + return; + } + + selection_flags++; + installedObject = object_get_next(installedObject); + } +} + +/* rct2: 0x006AB923 */ +void reset_required_object_flags(){ + uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i){ + *selection_flags &= ~OBJECT_SELECTION_FLAG_REQUIRED; + selection_flags++; + } + + selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + rct_object_entry* installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i){ + if (*selection_flags & OBJECT_SELECTION_FLAG_SELECTED){ + uint8* pos = (uint8*)installedObject; + // Skip sizeof(rct_object_entry) + pos += 16; + + // Skip filename + while (*pos++); + + // Skip no of images + pos += 4; + + // Skip name + while (*pos++); + + // Skip size of chunk + pos += 4; + + uint8 no_required_objects = *pos++; + + rct_object_entry* required_object = (rct_object_entry*)pos; + for (; no_required_objects > 0; no_required_objects--){ + set_required_object_flags(required_object); + required_object++; + } + + } + + selection_flags++; + installedObject = object_get_next(installedObject); + } +} + +/* + * Master objects are objects that are not + * optional / required dependants of an + * object. + */ +void set_object_selection_error(uint8 is_master_object, rct_string_id error_msg){ + RCT2_GLOBAL(0x141E9AC, rct_string_id) = error_msg; + if (!is_master_object){ + reset_selected_object_count_and_size(); + } } /** * * rct2: 0x006AB54F */ -static int window_editor_object_selection_select_object(int flags, rct_object_entry *entry) +static int window_editor_object_selection_select_object(uint8 bh, int flags, rct_object_entry *entry) { - return (RCT2_CALLPROC_X(0x006AB54F, 0, flags, 0, 0, 0, 0, (int)entry) & 0x100) == 0; + uint8* selection_flags; + //if (bh == 0){ + // // Unsure what this does?? + // uint16 total_objects = 0; + // for (uint8 i = 0; i < 11; ++i){ + // total_objects += RCT2_ADDRESS(0x00F433E1, uint16)[i]; + // } + + // selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + // for (; total_objects != 0; total_objects--, selection_flags++){ + // uint8 select_flag = *selection_flags & ~OBJECT_SELECTION_FLAG_2; + // if (select_flag & OBJECT_SELECTION_FLAG_SELECTED){ + // select_flag |= OBJECT_SELECTION_FLAG_2; + // } + // } + //} + + selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + // There was previously a check to make sure the object list had an item + rct_object_entry* installedObject = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*); + + uint8 not_found = 1; + for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i > 0; --i){ + if (object_entry_compare(entry, installedObject)){ + not_found = 0; + break; + } + + installedObject = object_get_next(installedObject); + selection_flags++; + } + if (not_found){ + set_object_selection_error(bh, 3169); + return 0; + } + + if (!(flags & 1)){ + if (!(*selection_flags & OBJECT_SELECTION_FLAG_SELECTED)) + { + if (bh == 0){ + reset_required_object_flags(); + } + return 1; + } + else if (*selection_flags & OBJECT_SELECTION_FLAG_IN_USE){ + set_object_selection_error(bh, 3173); + return 0; + } + else if (*selection_flags & OBJECT_SELECTION_FLAG_REQUIRED){ + set_object_selection_error(bh, 3174); + return 0; + } + else if (*selection_flags & OBJECT_SELECTION_FLAG_ALWAYS_REQUIRED){ + set_object_selection_error(bh, 3175); + return 0; + } + + uint8* pos = (uint8*)installedObject; + // Skip sizeof(rct_object_entry) + pos += 16; + + // Skip filename + while (*pos++); + + // Skip no of images + pos += 4; + + // Skip name + while (*pos++); + + uint32 size_of_chunk = *((uint32*)pos); + // Skip size of chunk + pos += 4; + + // Skip required objects + pos += *pos * 16 + 1; + + uint8 no_theme_objects = *pos++; + + if (no_theme_objects != 0 && flags&(1 << 2)){ + rct_object_entry* theme_object = (rct_object_entry*)pos; + for (; no_theme_objects > 0; no_theme_objects--){ + window_editor_object_selection_select_object(++bh, flags, theme_object); + theme_object++; + } + } + + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_OBJECTS_FILE_SIZE, uint32) -= size_of_chunk; + uint8 object_type = installedObject->flags & 0xF; + RCT2_ADDRESS(0x00F433F7, uint16)[object_type]--; + *selection_flags &= ~OBJECT_SELECTION_FLAG_SELECTED; + if (bh == 0){ + reset_required_object_flags(); + } + return 1; + } + else{ + if (bh == 0){ + if (flags & (1 << 3)){ + *selection_flags |= OBJECT_SELECTION_FLAG_ALWAYS_REQUIRED; + } + } + if (*selection_flags & OBJECT_SELECTION_FLAG_SELECTED){ + if (bh == 0){ + reset_required_object_flags(); + } + return 1; + } + + uint8 object_type = installedObject->flags & 0xF; + uint16 no_objects = object_entry_group_counts[object_type]; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER){ + no_objects = 4; + } + + if (no_objects <= RCT2_ADDRESS(0x00F433F7, uint16)[object_type]){ + set_object_selection_error(bh, 3171); + return 0; + } + + uint8* pos = (uint8*)installedObject; + // Skip sizeof(rct_object_entry) + pos += 16; + + // Skip filename + while (*pos++); + + // Skip no of images + pos += 4; + + // Skip name + while (*pos++); + + uint32 size_of_chunk = *((uint32*)pos); + // Skip size of chunk + pos += 4; + + uint8 num_required_objects = *pos++; + rct_object_entry* required_objects = (rct_object_entry*)pos; + for (; num_required_objects != 0; num_required_objects--){ + if (!window_editor_object_selection_select_object(++bh, flags, required_objects)){ + if (bh != 0){ + reset_selected_object_count_and_size(); + } + return 0; + } + required_objects++; + } + pos = (uint8*)required_objects; + + uint8 num_theme_objects = *pos++; + rct_object_entry* theme_object = (rct_object_entry*)pos; + for (; num_theme_objects != 0; num_theme_objects--){ + if (flags & (1 << 2)){ + if (!window_editor_object_selection_select_object(++bh, flags, theme_object)){ + RCT2_GLOBAL(0x00F43411, uint8) |= 1; + } + } + theme_object++; + } + + if (bh != 0 && !(flags&(1 << 1))){ + uint32* arguments = RCT2_ADDRESS(0x0013CE952, uint32); + object_create_identifier_name((char*)0x009BC95A, installedObject); + *arguments = (uint32)0x009BC95A; + set_object_selection_error(bh, 3172); + return 0; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_OBJECTS_FILE_SIZE, uint32) + size_of_chunk > 0x40000){ + set_object_selection_error(bh, 3170); + return 0; + } + + if (no_objects <= RCT2_ADDRESS(0x00F433F7, uint16)[object_type]){ + set_object_selection_error(bh, 3171); + return 0; + } + + RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_OBJECTS_FILE_SIZE, uint32) += size_of_chunk; + RCT2_ADDRESS(0x00F433F7, uint16)[object_type]++; + + *selection_flags |= OBJECT_SELECTION_FLAG_SELECTED; + if (bh == 0){ + reset_required_object_flags(); + } + return 1; + } } /** @@ -1074,7 +1724,7 @@ static int get_object_from_object_selection(uint8 object_type, int y, uint8 *obj filter = get_object_filter(RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32) - i); source = ((*installed_entry)->flags & 0xF0) >> 4; if (((*installed_entry)->flags & 0xF) == object_type && filter_source(*installed_entry) && filter_string(*installed_entry) && filter_chunks(*installed_entry, filter)){ - if (!(*selection_flags & 0x20)){ + if (!(*selection_flags & OBJECT_SELECTION_FLAG_6)){ y -= 12; *object_selection_flags = *selection_flags; if (y < 0)return object_count; @@ -1140,7 +1790,7 @@ static void editor_load_selected_objects() return; for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i != 0; i--, selection_flags++) { - if (*selection_flags & 1) { + if (*selection_flags & OBJECT_SELECTION_FLAG_SELECTED) { uint8 entry_index, entry_type; if (!find_object_in_entry_group(installed_entry, &entry_type, &entry_index)){ int chunk_size;