diff --git a/src/language.c b/src/language.c index a276a30b6d..4e874f42e0 100644 --- a/src/language.c +++ b/src/language.c @@ -42,8 +42,12 @@ const char *language_filenames[LANGUAGE_COUNT] = { "dutch", // LANGUAGE_DUTCH "french", // LANGUAGE_FRENCH "hungarian", // LANGUAGE_HUNGARIAN +<<<<<<< HEAD "polish", // LANGUAGE_POLISH "spanish_sp" // LANGUAGE_SPANISH +======= + "polish" // LANGUAGE_POLISH +>>>>>>> new-ride-window }; int gCurrentLanguage = LANGUAGE_UNDEFINED; diff --git a/src/park.h b/src/park.h index b12fcbad51..bb7d823e86 100644 --- a/src/park.h +++ b/src/park.h @@ -35,7 +35,7 @@ enum { PARK_FLAGS_PREF_LESS_INTENSE_RIDES = (1 << 6), PARK_FLAGS_FORBID_MARKETING_CAMPAIGN = (1 << 7), PARK_FLAGS_PREF_MORE_INTENSE_RIDES = (1 << 8), - PARK_FLAGS_11 = (1 << 11), + PARK_FLAGS_11 = (1 << 11), // appears to be a copy of PARK_FLAGS_NO_MONEY PARK_FLAGS_DIFFICULT_GUEST_GENERATION = (1 << 12), PARK_FLAGS_PARK_FREE_ENTRY = (1 << 13), PARK_FLAGS_DIFFICULT_PARK_RATING = (1 << 14), diff --git a/src/ride.h b/src/ride.h index 264e7c13f4..be34a4eb33 100644 --- a/src/ride.h +++ b/src/ride.h @@ -259,7 +259,8 @@ enum { RIDE_TYPE_INVERTED_IMPULSE_COASTER, RIDE_TYPE_MINI_ROLLER_COASTER, RIDE_TYPE_MINE_RIDE, - RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER + RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER, + RIDE_TYPE_90 }; enum { diff --git a/src/string_ids.h b/src/string_ids.h index aabbb8442c..6c2d86cf8d 100644 --- a/src/string_ids.h +++ b/src/string_ids.h @@ -237,7 +237,14 @@ enum { STR_SHOPS_AND_STALLS = 975, STR_RESTROOMS_AND_INFORMATION_KIOSKS = 976, + STR_NEW_TRANSPORT_RIDES = 977, + STR_NEW_GENTLE_RIDES = 978, + STR_NEW_ROLLER_COASTERS = 979, + STR_NEW_THRILL_RIDES = 980, + STR_NEW_WATER_RIDES = 981, + STR_NEW_SHOPS_STALLS = 982, STR_RESEARCH_AND_DEVELOPMENT = 983, + STR_RAISE_COST_AMOUNT = 984, STR_LOWER_COST_AMOUNT = 985, STR_COST_AMOUNT = 986, @@ -297,6 +304,13 @@ enum { STR_NUMERIC_UP = 1218, STR_NUMERIC_DOWN = 1219, + STR_TRANSPORT_RIDES_TIP = 1223, + STR_GENTLE_RIDES_TIP = 1224, + STR_ROLLER_COASTERS_TIP = 1225, + STR_THRILL_RIDES_TIP = 1226, + STR_WATER_RIDES_TIP = 1227, + STR_SHOPS_STALLS_TIP = 1228, + STR_ROTATE_OBJECTS_90 = 1327, STR_BUILD_THIS = 1407, @@ -514,7 +528,8 @@ enum { STR_RESEARCH_FUNDING_ = 2264, STR_RESEARCH_COST_PER_MONTH = 2265, STR_RESEARCH_PRIORITIES = 2266, - + STR_CURRENTLY_IN_DEVELOPMENT = 2267, + STR_LAST_DEVELOPMENT = 2268, STR_RESEARCH_TYPE_LABEL = 2269, STR_RESEARCH_PROGRESS_LABEL = 2270, STR_RESEARCH_EXPECTED_LABEL = 2271, diff --git a/src/window.h b/src/window.h index e7880dc636..f9d1b0db8a 100644 --- a/src/window.h +++ b/src/window.h @@ -373,6 +373,7 @@ void window_park_guests_open(); void window_park_objective_open(); void window_park_rating_open(); void window_finances_open(); +void window_finances_research_open(); void window_new_campaign_open(int campaignType); void window_ride_list_open(); void window_new_ride_open(); diff --git a/src/window_finances.c b/src/window_finances.c index 8c21d63d97..e8500fc84b 100644 --- a/src/window_finances.c +++ b/src/window_finances.c @@ -553,6 +553,20 @@ void window_finances_open() window_init_scroll_widgets(w); } +/** + * + * rct2: 0x0069DDE1 + */ +void window_finances_research_open() +{ + rct_window *w; + + window_finances_open(); + w = window_find_by_id(WC_FINANCES, 0); + if (w != NULL) + window_finances_set_page(w, WINDOW_FINANCES_PAGE_RESEARCH); +} + #pragma region Summary page /** diff --git a/src/window_new_ride.c b/src/window_new_ride.c index ee82cd2f73..8f0969b269 100644 --- a/src/window_new_ride.c +++ b/src/window_new_ride.c @@ -20,18 +20,138 @@ #include #include "addresses.h" +#include "audio.h" #include "game.h" +#include "news_item.h" +#include "ride.h" +#include "string_ids.h" +#include "track.h" +#include "widget.h" #include "window.h" +#define _window_new_ride_current_tab RCT2_GLOBAL(0x00F43824, uint8) + +typedef struct { + uint8 type; + uint8 entry_index; +} ride_list_item; + +#pragma region Ride type view order + +/** + * The order of ride types shown in the new ride window so that the order stays consistent across games and rides of the same + * type are kept together. + */ +const char RideTypeViewOrder[] = { + // Transport rides + RIDE_TYPE_MINIATURE_RAILWAY, + RIDE_TYPE_MONORAIL, + RIDE_TYPE_SUSPENDED_MONORAIL, + RIDE_TYPE_CHAIRLIFT, + RIDE_TYPE_ELEVATOR, + + // Roller Coasters + RIDE_TYPE_SIDE_FRICTION_ROLLER_COASTER, + RIDE_TYPE_VIRGINIA_REEL, + RIDE_TYPE_REVERSER_ROLLER_COASTER, + RIDE_TYPE_WOODEN_ROLLER_COASTER, + RIDE_TYPE_WOODEN_WILD_MOUSE, + RIDE_TYPE_WILD_MOUSE, + RIDE_TYPE_INVERTED_HAIRPIN_COASTER, + RIDE_TYPE_JUNIOR_ROLLER_COASTER, + RIDE_TYPE_MINI_ROLLER_COASTER, + RIDE_TYPE_SPIRAL_ROLLER_COASTER, + RIDE_TYPE_MINE_TRAIN_COASTER, + RIDE_TYPE_LOOPING_ROLLER_COASTER, + RIDE_TYPE_STAND_UP_ROLLER_COASTER, + RIDE_TYPE_CORKSCREW_ROLLER_COASTER, + RIDE_TYPE_90, + RIDE_TYPE_TWISTER_ROLLER_COASTER, + RIDE_TYPE_GIGA_COASTER, + RIDE_TYPE_SUSPENDED_SWINGING_COASTER, + RIDE_TYPE_COMPACT_INVERTED_COASTER, + RIDE_TYPE_INVERTED_ROLLER_COASTER, + RIDE_TYPE_INVERTED_IMPULSE_COASTER, + RIDE_TYPE_MINI_SUSPENDED_COASTER, + RIDE_TYPE_STEEPLECHASE, + RIDE_TYPE_BOBSLEIGH_COASTER, + RIDE_TYPE_MINE_RIDE, + RIDE_TYPE_HEARTLINE_TWISTER_COASTER, + RIDE_TYPE_LAY_DOWN_ROLLER_COASTER, + RIDE_TYPE_FLYING_ROLLER_COASTER, + RIDE_TYPE_MULTI_DIMENSION_ROLLER_COASTER, + RIDE_TYPE_REVERSE_FREEFALL_COASTER, + RIDE_TYPE_VERTICAL_DROP_ROLLER_COASTER, + RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER, + + // Gentle rides + RIDE_TYPE_MONORAIL_CYCLES, + RIDE_TYPE_CROOKED_HOUSE, + RIDE_TYPE_HAUNTED_HOUSE, + RIDE_TYPE_FERRIS_WHEEL, + RIDE_TYPE_MAZE, + RIDE_TYPE_MERRY_GO_ROUND, + RIDE_TYPE_MINI_GOLF, + RIDE_TYPE_OBSERVATION_TOWER, + RIDE_TYPE_CAR_RIDE, + RIDE_TYPE_MINI_HELICOPTERS, + RIDE_TYPE_SPIRAL_SLIDE, + RIDE_TYPE_BUMPER_CARS, + RIDE_TYPE_SPACE_RINGS, + RIDE_TYPE_CIRCUS_SHOW, + RIDE_TYPE_GHOST_TRAIN, + RIDE_TYPE_FLYING_SAUCERS, + + // Thrill rides + RIDE_TYPE_TWIST, + RIDE_TYPE_MAGIC_CARPET, + RIDE_TYPE_LAUNCHED_FREEFALL, + RIDE_TYPE_PIRATE_SHIP, + RIDE_TYPE_GO_KARTS, + RIDE_TYPE_SWINGING_INVERTER_SHIP, + RIDE_TYPE_MOTION_SIMULATOR, + RIDE_TYPE_3D_CINEMA, + RIDE_TYPE_TOP_SPIN, + RIDE_TYPE_ROTO_DROP, + RIDE_TYPE_ENTERPRISE, + + // Water rides + RIDE_TYPE_DINGHY_SLIDE, + RIDE_TYPE_LOG_FLUME, + RIDE_TYPE_RIVER_RAPIDS, + RIDE_TYPE_SPLASH_BOATS, + RIDE_TYPE_SUBMARINE_RIDE, + RIDE_TYPE_BUMPER_BOATS, + RIDE_TYPE_RIVER_RAFTS, + RIDE_TYPE_WATER_COASTER, + + // Shops / stalls + RIDE_TYPE_FOOD_STALL, + RIDE_TYPE_1D, + RIDE_TYPE_DRINK_STALL, + RIDE_TYPE_1F, + RIDE_TYPE_SHOP, + RIDE_TYPE_22, + RIDE_TYPE_INFORMATION_KIOSK, + RIDE_TYPE_FIRST_AID, + RIDE_TYPE_ATM, + RIDE_TYPE_BATHROOM +}; + +#pragma endregion + enum { - WINDOW_NEW_RIDE_TAB_TRANSPORT, - WINDOW_NEW_RIDE_TAB_GENTLE, - WINDOW_NEW_RIDE_TAB_ROLLER_COASTER, - WINDOW_NEW_RIDE_TAB_THRILL, - WINDOW_NEW_RIDE_TAB_WATER, - WINDOW_NEW_RIDE_TAB_SHOP, - WINDOW_NEW_RIDE_TAB_RESEARCH -} WINDOW_RIDE_CONSTRUCTION_TAB; + WINDOW_NEW_RIDE_PAGE_TRANSPORT, + WINDOW_NEW_RIDE_PAGE_GENTLE, + WINDOW_NEW_RIDE_PAGE_ROLLER_COASTER, + WINDOW_NEW_RIDE_PAGE_THRILL, + WINDOW_NEW_RIDE_PAGE_WATER, + WINDOW_NEW_RIDE_PAGE_SHOP, + WINDOW_NEW_RIDE_PAGE_RESEARCH, + WINDOW_NEW_RIDE_PAGE_COUNT +}; + +#pragma region Widgets enum { WIDX_BACKGROUND, @@ -45,12 +165,95 @@ enum { WIDX_TAB_5, WIDX_TAB_6, WIDX_TAB_7, - + WIDX_RIDE_LIST, WIDX_CURRENTLY_IN_DEVELOPMENT_GROUP, WIDX_LAST_DEVELOPMENT_GROUP, - WIDX_LAST_DEVELOPMENT_BUTTON + WIDX_LAST_DEVELOPMENT_BUTTON, + WIDX_RESEARCH_FUNDING_BUTTON }; +static rct_widget window_new_ride_widgets[] = { + { WWT_FRAME, 0, 0, 600, 0, 369, 0xFFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 599, 1, 14, 0xFFFFFFFF, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 588, 598, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 600, 43, 369, 0xFFFFFFFF, STR_NONE }, + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_TRANSPORT_RIDES_TIP }, + { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_GENTLE_RIDES_TIP }, + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_ROLLER_COASTERS_TIP }, + { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_THRILL_RIDES_TIP }, + { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_WATER_RIDES_TIP }, + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_SHOPS_STALLS_TIP }, + { WWT_TAB, 1, 189, 219, 17, 43, 0x2000144E, STR_RESEARCH_AND_DEVELOPMENT_TIP }, + { WWT_SCROLL, 1, 3, 597, 46, 317, 2, STR_NONE }, + { WWT_GROUPBOX, 2, 3, 292, 47, 116, STR_CURRENTLY_IN_DEVELOPMENT, STR_NONE }, + { WWT_GROUPBOX, 2, 3, 292, 124, 188, STR_LAST_DEVELOPMENT, STR_NONE }, + { WWT_FLATBTN, 2, 265, 288, 161, 184, 0xFFFFFFFF, STR_RESEARCH_SHOW_DETAILS_TIP }, + { WWT_FLATBTN, 2, 265, 288, 68, 91, 5190, STR_FINANCES_RESEARCH }, + { WIDGETS_END }, +}; + +#pragma endregion + +#pragma region Events + +static void window_new_ride_emptysub() { } + +static void window_new_ride_mouseup(); +static void window_new_ride_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); +static void window_new_ride_update(rct_window *w); +static void window_new_ride_scrollgetsize(); +static void window_new_ride_scrollmousedown(); +static void window_new_ride_scrollmouseover(); +static void window_new_ride_tooltip(); +static void window_new_ride_invalidate(); +static void window_new_ride_paint(); +static void window_new_ride_scrollpaint(); + +// 0x0098E354 +static void* window_new_ride_events[] = { + window_new_ride_emptysub, + window_new_ride_mouseup, + window_new_ride_emptysub, + window_new_ride_mousedown, + window_new_ride_emptysub, + window_new_ride_emptysub, + window_new_ride_update, + window_new_ride_emptysub, + window_new_ride_emptysub, + window_new_ride_emptysub, + window_new_ride_emptysub, + window_new_ride_emptysub, + window_new_ride_emptysub, + window_new_ride_emptysub, + window_new_ride_emptysub, + window_new_ride_scrollgetsize, + window_new_ride_scrollmousedown, + window_new_ride_emptysub, + window_new_ride_scrollmouseover, + window_new_ride_emptysub, + window_new_ride_emptysub, + window_new_ride_emptysub, + window_new_ride_tooltip, + window_new_ride_emptysub, + window_new_ride_emptysub, + window_new_ride_invalidate, + window_new_ride_paint, + window_new_ride_scrollpaint +}; + +#pragma endregion + +const int window_new_ride_tab_animation_loops[] = { 20, 32, 10, 72, 24, 28, 16 }; +const int window_new_ride_tab_animation_divisor[] = { 4, 8, 2, 4, 4, 4, 2 }; + +static void window_new_ride_refresh_widget_sizing(rct_window *w); +static ride_list_item window_new_ride_scroll_get_ride_list_item_at(rct_window *w, int x, int y); +static void window_new_ride_paint_ride_information(rct_window *w, rct_drawpixelinfo *dpi, ride_list_item item, int x, int y, int width); +static void window_new_ride_select(rct_window *w); + +static ride_list_item _lastTrackDesignCountRideType; +static int _lastTrackDesignCount; + /** * * rct2: 0x006ACA58 @@ -58,10 +261,10 @@ enum { void window_new_ride_init_vars() { // If we are in the track designer, default to the Roller Coaster tab if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_DESIGNER) { - RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_RIDE_LIST_SELECTED_TAB, uint8) = WINDOW_NEW_RIDE_TAB_ROLLER_COASTER; + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_RIDE_LIST_SELECTED_TAB, uint8) = WINDOW_NEW_RIDE_PAGE_ROLLER_COASTER; } else { - RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_RIDE_LIST_SELECTED_TAB, uint8) = WINDOW_NEW_RIDE_TAB_TRANSPORT; + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_RIDE_LIST_SELECTED_TAB, uint8) = WINDOW_NEW_RIDE_PAGE_TRANSPORT; } for (short i = 0; i < 6; i++) { @@ -75,6 +278,124 @@ void window_new_ride_init_vars() { RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_RIDE_LIST_INFORMATION_TYPE, uint8) = 0; } +uint8 *get_ride_entry_indices_for_ride_type(uint8 rideType) +{ + uint8 *typeToRideEntryIndexMap = (uint8*)0x009E32F8; + uint8 *entryIndexList = typeToRideEntryIndexMap; + while (rideType > 0) { + do { + entryIndexList++; + } while (*(entryIndexList - 1) != 255); + rideType--; + } + return entryIndexList; +} + +/** + * + * rct2: 0x006B6F3E + */ +static void window_new_ride_populate_list() +{ + int i, quadIndex, bitIndex; + + uint8 currentCategory = _window_new_ride_current_tab; + ride_list_item *nextListItem = (ride_list_item*)0x00F43523; + uint8 **rideEntries = (uint8**)0x009ACFA4; + + // For each ride type in the view order list + for (i = 0; i < countof(RideTypeViewOrder); i++) { + uint8 rideType = RideTypeViewOrder[i]; + if (rideType == RIDE_TYPE_NULL) + continue; + + quadIndex = rideType >> 5; + bitIndex = rideType & 0x1F; + if (RCT2_ADDRESS(0x01357404, uint32)[quadIndex] & (1 << bitIndex)) { + int dh = 0; + uint8 *rideEntryIndexPtr = get_ride_entry_indices_for_ride_type(rideType); + + // For each ride entry for this ride type + while (*rideEntryIndexPtr != 255) { + uint8 rideEntryIndex = *rideEntryIndexPtr++; + + quadIndex = rideEntryIndex >> 5; + bitIndex = rideEntryIndex & 0x1F; + if (!(RCT2_ADDRESS(0x01357424, uint32)[quadIndex] & (1 << bitIndex))) + continue; + + // Ride entries + uint8 *rideEntry = rideEntries[rideEntryIndex]; + uint8 categoryA = rideEntry[0x1BE]; + uint8 categoryB = rideEntry[0x1BF]; + + // Check if ride is in this category + if (currentCategory != categoryA && currentCategory != categoryB) + continue; + + if (RCT2_GLOBAL(rideEntry + 8, uint32) & 0x2000) { + dh &= ~4; + nextListItem->type = rideType; + nextListItem->entry_index = rideEntryIndex; + nextListItem++; + } else if (!(dh & 1)) { + dh |= 5; + nextListItem->type = rideType; + nextListItem->entry_index = rideEntryIndex; + nextListItem++; + } else if (dh & 4) { + if (rideType == rideEntry[0x0C]) { + nextListItem--; + nextListItem->type = rideType; + nextListItem->entry_index = rideEntryIndex; + nextListItem++; + } + } + } + } + } + + nextListItem->type = 255; + nextListItem->entry_index = 255; +} + +/** + * + * rct2: 0x006B7220 + */ +static void window_new_ride_scroll_to_focused_ride(rct_window *w) +{ + int eax, ebx, ecx, edx, esi, edi, ebp; + + // Get the scroll height + eax = 0; + esi = (int)w; + RCT2_CALLFUNC_X(w->event_handlers[WE_SCROLL_GETSIZE], &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + int scrollHeight = edx; + ebx = 0; + + // Find row index of the focused ride type + rct_widget *listWidget = &window_new_ride_widgets[WIDX_RIDE_LIST]; + int focusRideType = RCT2_ADDRESS(0x00F43825, uint16)[_window_new_ride_current_tab]; + int count = 0, row = 0; + ride_list_item *listItem = (ride_list_item*)0x00F43523; + while (listItem->type != 255 || listItem->entry_index != 255) { + if (listItem->type == focusRideType) { + row = count / 5; + break; + } + + count++; + listItem++; + }; + + // Update the Y scroll position + int listWidgetHeight = listWidget->bottom - listWidget->top - 1; + scrollHeight = max(0, scrollHeight - listWidgetHeight); + w->scrolls[0].v_top = min(row * 116, scrollHeight); + widget_scroll_update_thumbs(w, WIDX_RIDE_LIST); +} + /** * * rct2: 0x006B3CFF @@ -91,8 +412,8 @@ void window_new_ride_open() window_close_by_id(161, 0); window_close_by_id(162, 0); - w = window_create_auto_pos(601, 370, (uint32*)0x0098E354, WC_CONSTRUCT_RIDE, 0x400); - w->widgets = (rct_widget*)0x009AEBF4; + w = window_create_auto_pos(601, 370, (uint32*)window_new_ride_events, WC_CONSTRUCT_RIDE, 0x400); + w->widgets = window_new_ride_widgets; w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | @@ -112,15 +433,561 @@ void window_new_ride_open() w->colours[2] = 26; w->var_480 = -1; w->var_482 = -1; - RCT2_GLOBAL(0x00F43866, sint16) = -1; + _lastTrackDesignCountRideType.type = 255; + _lastTrackDesignCountRideType.entry_index = 255; - RCT2_CALLPROC_EBPSAFE(0x006B6F3E); + window_new_ride_populate_list(); - w->var_482 = RCT2_ADDRESS(0x00F43825, sint16)[RCT2_GLOBAL(0x00F43824, uint8)]; + w->var_482 = RCT2_ADDRESS(0x00F43825, sint16)[_window_new_ride_current_tab]; if (w->var_482 == -1) w->var_482 = RCT2_GLOBAL(0x00F43523, sint16); w->width = 1; - RCT2_CALLPROC_X(0x006B3DF1, 0, 0, 0, 0, (int)w, 0, 0); // initialise window size and widgets - RCT2_CALLPROC_X(0x006B7220, 0, 0, 0, 0, (int)w, 0, 0); + window_new_ride_refresh_widget_sizing(w); + window_new_ride_scroll_to_focused_ride(w); +} + +/** + * + * rct2: 0x006B3DF1 + */ +static void window_new_ride_refresh_widget_sizing(rct_window *w) +{ + int width, height; + + // Show or hide unrelated widgets + if (_window_new_ride_current_tab != WINDOW_NEW_RIDE_PAGE_RESEARCH) { + window_new_ride_widgets[WIDX_RIDE_LIST].type = WWT_SCROLL; + window_new_ride_widgets[WIDX_CURRENTLY_IN_DEVELOPMENT_GROUP].type = WWT_EMPTY; + window_new_ride_widgets[WIDX_LAST_DEVELOPMENT_GROUP].type = WWT_EMPTY; + window_new_ride_widgets[WIDX_LAST_DEVELOPMENT_BUTTON].type = WWT_EMPTY; + window_new_ride_widgets[WIDX_RESEARCH_FUNDING_BUTTON].type = WWT_EMPTY; + + width = 601; + height = 370; + } else { + window_new_ride_widgets[WIDX_RIDE_LIST].type = WWT_EMPTY; + window_new_ride_widgets[WIDX_CURRENTLY_IN_DEVELOPMENT_GROUP].type = WWT_GROUPBOX; + window_new_ride_widgets[WIDX_LAST_DEVELOPMENT_GROUP].type = WWT_GROUPBOX; + window_new_ride_widgets[WIDX_LAST_DEVELOPMENT_BUTTON].type = WWT_FLATBTN; + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_11)) + window_new_ride_widgets[WIDX_RESEARCH_FUNDING_BUTTON].type = WWT_FLATBTN; + + width = 300; + height = 196; + } + + // Handle new window size + if (w->width != width || w->height != height) { + window_invalidate(w); + + // Resize widgets to new window size + window_new_ride_widgets[WIDX_BACKGROUND].right = width - 1; + window_new_ride_widgets[WIDX_BACKGROUND].bottom = height - 1; + window_new_ride_widgets[WIDX_PAGE_BACKGROUND].right = width - 1; + window_new_ride_widgets[WIDX_PAGE_BACKGROUND].bottom = height - 1; + window_new_ride_widgets[WIDX_TITLE].right = width - 2; + window_new_ride_widgets[WIDX_CLOSE].left = width - 13; + window_new_ride_widgets[WIDX_CLOSE].right = width - 3; + + w->width = width; + w->height = height; + window_invalidate(w); + } + + window_init_scroll_widgets(w); +} + +static void window_new_ride_set_pressed_tab(rct_window *w) +{ + int i; + for (i = 0; i < WINDOW_NEW_RIDE_PAGE_COUNT; i++) + w->pressed_widgets &= ~(1 << (WIDX_TAB_1 + i)); + w->pressed_widgets |= 1LL << (WIDX_TAB_1 + _window_new_ride_current_tab); +} + +const int ThrillRidesTabAnimationSequence[] = { + 5, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0 +}; + +static void window_new_ride_draw_tab_image(rct_drawpixelinfo *dpi, rct_window *w, int page, int spriteIndex) +{ + int widgetIndex = WIDX_TAB_1 + page; + + if (!(w->disabled_widgets & (1LL << widgetIndex))) { + int frame = 0; + if (_window_new_ride_current_tab == page) + frame = w->frame_no / window_new_ride_tab_animation_divisor[page]; + + spriteIndex += page == WINDOW_NEW_RIDE_PAGE_THRILL ? + ThrillRidesTabAnimationSequence[frame] : frame; + + spriteIndex |= w->colours[1] << 19; + + gfx_draw_sprite(dpi, spriteIndex, w->x + w->widgets[widgetIndex].left, w->y + w->widgets[widgetIndex].top, 0); + } +} + +static void window_new_ride_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w) +{ + window_new_ride_draw_tab_image(dpi, w, WINDOW_NEW_RIDE_PAGE_TRANSPORT, 0x200015A1); + window_new_ride_draw_tab_image(dpi, w, WINDOW_NEW_RIDE_PAGE_GENTLE, 5542); + window_new_ride_draw_tab_image(dpi, w, WINDOW_NEW_RIDE_PAGE_ROLLER_COASTER, 0x200015AA); + window_new_ride_draw_tab_image(dpi, w, WINDOW_NEW_RIDE_PAGE_THRILL, 5557); + window_new_ride_draw_tab_image(dpi, w, WINDOW_NEW_RIDE_PAGE_WATER, 5551); + window_new_ride_draw_tab_image(dpi, w, WINDOW_NEW_RIDE_PAGE_SHOP, 5530); + window_new_ride_draw_tab_image(dpi, w, WINDOW_NEW_RIDE_PAGE_RESEARCH, 5327); +} + +/** + * + * rct2: 0x006B6B38 + */ +static void window_new_ride_mouseup() +{ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_LAST_DEVELOPMENT_BUTTON: + news_item_open_subject(NEWS_ITEM_RESEARCH, RCT2_GLOBAL(RCT2_ADDRESS_LAST_RESEARCHED_ITEM_SUBJECT, sint32)); + break; + case WIDX_RESEARCH_FUNDING_BUTTON: + window_finances_research_open(); + break; + } +} + +/** + * + * rct2: 0x006B6B4F + */ +static void window_new_ride_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) +{ + int page; + if (widgetIndex < WIDX_TAB_1 || widgetIndex > WIDX_TAB_7) + return; + + page = widgetIndex - WIDX_TAB_1; + + _window_new_ride_current_tab = page; + w->frame_no = 0; + w->var_482 = -1; + w->var_480 = -1; + window_new_ride_populate_list(); + if (page < WINDOW_NEW_RIDE_PAGE_RESEARCH) { + w->var_482 = RCT2_ADDRESS(0x00F43825, sint16)[page]; + if (w->var_482 == -1) + w->var_482 = RCT2_GLOBAL(0x00F43523, sint16); + } + + window_new_ride_refresh_widget_sizing(w); + window_invalidate(w); + window_new_ride_scroll_to_focused_ride(w); +} + +/** + * + * rct2: 0x006B6CE7 + */ +static void window_new_ride_update(rct_window *w) +{ + w->frame_no++; + if (w->frame_no >= window_new_ride_tab_animation_loops[_window_new_ride_current_tab]) + w->frame_no = 0; + + widget_invalidate(w->classification, w->number, WIDX_TAB_1 + _window_new_ride_current_tab); + + if (w->var_480 != -1 && w->var_488-- == 0) + window_new_ride_select(w); +} + +/** + * + * rct2: 0x006B6BC9 + */ +static void window_new_ride_scrollgetsize() +{ + ride_list_item *listItem = (ride_list_item*)0x00F43523; + int scrollWidth, scrollHeight; + + int count = 0; + while (listItem->type != 255 || listItem->entry_index != 255) { + count++; + listItem++; + } + scrollWidth = 0; + scrollHeight = ((count + 4) / 5) * 116; + + #ifdef _MSC_VER + __asm mov ecx, scrollWidth + #else + __asm__ ( "mov ecx, %[scrollWidth] " : [scrollWidth] "+m" (scrollWidth) ); + #endif + + #ifdef _MSC_VER + __asm mov edx, scrollHeight + #else + __asm__ ( "mov edx, %[scrollHeight] " : [scrollHeight] "+m" (scrollHeight) ); + #endif +} + +/** + * + * rct2: 0x006B6C89 + */ +static void window_new_ride_scrollmousedown() +{ + short x, y; + rct_window *w; + + window_scrollmouse_get_registers(w, x, y); + + if (RCT2_GLOBAL(0x009DEA6E, uint8) != 0) + return; + + ride_list_item item = window_new_ride_scroll_get_ride_list_item_at(w, x, y); + if (item.type == 255 && item.entry_index == 255) + return; + + RCT2_ADDRESS(0x00F43825, ride_list_item)[_window_new_ride_current_tab] = item; + w->var_480 = *((sint16*)&item); + + sound_play_panned(SOUND_CLICK_1, w->x + (w->width / 2)); + w->var_488 = 8; + window_invalidate(w); +} + +/** + * + * rct2: 0x006B6C51 + */ +static void window_new_ride_scrollmouseover() +{ + short x, y; + rct_window *w; + + window_scrollmouse_get_registers(w, x, y); + + if (w->var_480 != -1) + return; + + ride_list_item item = window_new_ride_scroll_get_ride_list_item_at(w, x, y); + if (w->var_482 == *((sint16*)&item)) + return; + + w->var_482 = *((sint16*)&item); + RCT2_ADDRESS(0x00F43825, ride_list_item)[_window_new_ride_current_tab] = item; + window_invalidate(w); +} + +/** + * + * rct2: 0x006B6BBF + */ +static void window_new_ride_tooltip() +{ + RCT2_GLOBAL(0x013CE952, uint16) = 3159; +} + +/** + * + * rct2: 0x006B6819 + */ +static void window_new_ride_invalidate() +{ + rct_window *w; + + window_get_register(w); + + window_new_ride_set_pressed_tab(w); + + window_new_ride_widgets[WIDX_TITLE].image = STR_NEW_TRANSPORT_RIDES + _window_new_ride_current_tab; + window_new_ride_widgets[WIDX_TAB_7].type = WWT_TAB; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 4) + window_new_ride_widgets[WIDX_TAB_7].type = WWT_EMPTY; + + if (_window_new_ride_current_tab == WINDOW_NEW_RIDE_PAGE_RESEARCH) { + window_new_ride_widgets[WIDX_LAST_DEVELOPMENT_BUTTON].type = WWT_EMPTY; + uint32 typeId = RCT2_GLOBAL(0x01357CF4, uint32); + if (typeId != 0xFFFFFFFF) { + window_new_ride_widgets[WIDX_LAST_DEVELOPMENT_BUTTON].type = WWT_FLATBTN; + window_new_ride_widgets[WIDX_LAST_DEVELOPMENT_BUTTON].image = typeId >= 0x10000 ? 5189 : 5191; + } + } +} + +/** + * + * rct2: 0x006B689B + */ +static void window_new_ride_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_new_ride_draw_tab_images(dpi, w); + + if (_window_new_ride_current_tab != WINDOW_NEW_RIDE_PAGE_RESEARCH) { + ride_list_item item = *((ride_list_item*)&w->var_482); + if (item.type == 255 && item.entry_index == 255) + return; + + window_new_ride_paint_ride_information(w, dpi, item, w->x + 3, w->y + w->height - 52, w->width - 6); + return; + } + + int x = w->x + 10; + int y = w->y + window_new_ride_widgets[WIDX_CURRENTLY_IN_DEVELOPMENT_GROUP].top + 12; + + // Research type + rct_string_id stringId = STR_RESEARCH_UNKNOWN; + if (RCT2_GLOBAL(0x01357CF3, uint8) != 0) { + stringId = STR_TRANSPORT_RIDE + RCT2_GLOBAL(0x013580E6, uint8); + if (RCT2_GLOBAL(0x01357CF3, uint8) != 1) { + uint32 typeId = RCT2_GLOBAL(0x013580E0, uint32); + if (typeId >= 0x10000) { + uint8 *rideEntry = RCT2_GLOBAL(0x009ACFA4 + (typeId & 0xFF) * 4, uint8*); + if (RCT2_GLOBAL(rideEntry + 8, uint32) & 0x1000) + stringId = RCT2_GLOBAL(rideEntry, uint16); + else + stringId = (typeId & 0xFF00) + 2; + } else { + uint8 *sceneryEntry = RCT2_GLOBAL(0x009ADA90 + (typeId & 0xFFFF) * 4, uint8*); + stringId = RCT2_GLOBAL(sceneryEntry, uint16); + } + } + } + gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 296, STR_RESEARCH_TYPE_LABEL, 0); + y += 25; + + // Progress + stringId = 2285 + RCT2_GLOBAL(0x01357CF3, uint8); + gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 296, STR_RESEARCH_PROGRESS_LABEL, 0); + y += 15; + + // Expected + RCT2_GLOBAL(0x013CE952, uint16) = STR_UNKNOWN; + if (RCT2_GLOBAL(0x01357CF3, uint8) != 0) { + uint16 expectedDay = RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_DAY, uint8); + if (expectedDay != 255) { + RCT2_GLOBAL(0x013CE952 + 2, uint16) = STR_DATE_DAY_1 + expectedDay; + RCT2_GLOBAL(0x013CE952 + 4, uint16) = STR_MONTH_MARCH + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_MONTH, uint8); + RCT2_GLOBAL(0x013CE952, uint16) = 2289; + } + } + gfx_draw_string_left(dpi, STR_RESEARCH_EXPECTED_LABEL, (void*)0x013CE952, 0, x, y); + + // Last development + x = w->x + 10; + y = w->y + window_new_ride_widgets[WIDX_LAST_DEVELOPMENT_GROUP].top + 12; + + uint32 typeId = RCT2_GLOBAL(0x01357CF4, uint32); + if (typeId != 0xFFFFFFFF) { + if (typeId >= 0x10000) { + uint8 *rideEntry = RCT2_GLOBAL(0x009ACFA4 + (typeId & 0xFF) * 4, uint8*); + if (RCT2_GLOBAL(rideEntry + 8, uint32) & 0x1000) + stringId = RCT2_GLOBAL(rideEntry, uint16); + else + stringId = (typeId & 0xFF00) + 2; + } else { + uint8 *sceneryEntry = RCT2_GLOBAL(0x009ADA90 + (typeId & 0xFFFF) * 4, uint8*); + stringId = RCT2_GLOBAL(sceneryEntry, uint16); + } + gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 266, STR_RESEARCH_RIDE_LABEL, 0); + } +} + +/** + * + * rct2: 0x006B6ABF + */ +static void window_new_ride_scrollpaint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + uint8 **rideEntries = (uint8**)0x009ACFA4; + + window_paint_get_registers(w, dpi); + + if (_window_new_ride_current_tab == WINDOW_NEW_RIDE_PAGE_RESEARCH) + return; + + gfx_clear(dpi, RCT2_GLOBAL(0x0141FC48 + (w->colours[1] * 8), uint8) * 0x1010101); + + int x = 1; + int y = 1; + ride_list_item *listItem = (ride_list_item*)0x00F43523; + while (listItem->type != 255 || listItem->entry_index != 255) { + // Draw flat button rectangle + int flags = 0; + if (w->var_480 == *((sint16*)listItem)) + flags |= 0x20; + if (w->var_482 == *((sint16*)listItem) || flags != 0) + gfx_fill_rect_inset(dpi, x, y, x + 115, y + 115, w->colours[1], 0x80 | flags); + + // Draw ride image + uint8 *rideEntry = rideEntries[listItem->entry_index]; + int unk = RCT2_GLOBAL(rideEntry + 4, uint32); + if (listItem->type != RCT2_GLOBAL(rideEntry + 12, uint8)) { + unk++; + if (listItem->type != RCT2_GLOBAL(rideEntry + 13, uint8)) + unk++; + } + RCT2_CALLPROC_X(0x00681DE2, 0, 29013, x + 2, y + 2, 0xA0, (int)dpi, unk); + + // Next position + x += 116; + if (x >= 116 * 5 + 1) { + x = 1; + y += 116; + } + + // Next item + listItem++; + } +} + +/** + * + * rct2: 0x006B6D3C + */ +static ride_list_item window_new_ride_scroll_get_ride_list_item_at(rct_window *w, int x, int y) +{ + ride_list_item result; + result.type = 255; + result.entry_index = 255; + + if (--x < 0 || --y < 0) + return result; + + int column = x / 116; + int row = y / 116; + if (row >= 5) + return result; + + int index = column + (row * 5); + + ride_list_item *listItem = (ride_list_item*)0x00F43523; + while (listItem->type != 255 || listItem->entry_index != 255) { + if (index-- == 0) + return *listItem; + listItem++; + } + + return result; +} + +static int get_num_track_designs(ride_list_item item) +{ + track_load_list(*((uint16*)&item)); + + uint8 *trackDesignList = (uint8*)0x00F441EC; + int count = 0; + while (*trackDesignList != 0 && trackDesignList < (uint8*)0x00F635EC) { + trackDesignList += 128; + count++; + } + return count; +} + +/** + * + * rct2: 0x006B701C + */ +static void window_new_ride_paint_ride_information(rct_window *w, rct_drawpixelinfo *dpi, ride_list_item item, int x, int y, int width) +{ + uint8 **rideEntries = (uint8**)0x009ACFA4; + uint8 *rideEntry = rideEntries[item.entry_index]; + + // Ride name and description + rct_string_id rideName = RCT2_GLOBAL(rideEntry + 0, uint16); + rct_string_id rideDescription = RCT2_GLOBAL(rideEntry + 2, uint16); + if (!(RCT2_GLOBAL(rideEntry + 8, uint32) & 0x1000)) { + rideName = item.type + 2; + rideDescription = item.type + 512; + } + + RCT2_GLOBAL(0x013CE952 + 0, rct_string_id) = rideName; + RCT2_GLOBAL(0x013CE952 + 2, rct_string_id) = rideDescription; + gfx_draw_string_left_wrapped(dpi, (void*)0x013CE952, x, y, width, 1690, 0); + + // Number of designs available + uint32 rideTypeFlags = RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (item.type * 8), uint32); + if (rideTypeFlags & 0x10000000) { + if (item.type != _lastTrackDesignCountRideType.type || item.entry_index != _lastTrackDesignCountRideType.entry_index) { + _lastTrackDesignCountRideType = item; + _lastTrackDesignCount = get_num_track_designs(item); + } + + rct_string_id stringId; + switch (_lastTrackDesignCount) { + case 0: + stringId = 3338; + break; + case 1: + stringId = 3339; + break; + default: + stringId = 3340; + break; + } + gfx_draw_string_left(dpi, stringId, &_lastTrackDesignCount, 0, x, y + 40); + } + + // Price + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_11)) { + // Get price of ride + int unk2 = RCT2_GLOBAL(0x0097CC68 + (item.type * 2), uint8); + money32 price = RCT2_GLOBAL(0x0097DD78 + (item.type * 4), uint16); + if (rideTypeFlags & 0x80000) { + price *= RCT2_ADDRESS(0x0099DE34, uint32)[unk2]; + } else { + price *= RCT2_ADDRESS(0x0099DA34, uint32)[unk2]; + } + price = (price >> 17) * 10 * RCT2_GLOBAL(0x0097D21D + (item.type * 8), uint8); + + // + rct_string_id stringId = 1691; + if (!(rideTypeFlags & 0x8000)) + stringId++; + + gfx_draw_string_right(dpi, stringId, &price, 0, x + width, y + 40); + } +} + +/** + * + * rct2: 0x006B6B78 + */ +static void window_new_ride_select(rct_window *w) +{ + ride_list_item item = *((ride_list_item*)&w->var_480); + if (item.type == 255) + return; + + window_close(w); + + uint32 rideTypeFlags = RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (item.type * 8), uint32); + if (rideTypeFlags & 0x10000000) { + track_load_list(*((sint16*)&item)); + + uint8 *trackDesignList = (uint8*)0x00F441EC; + if (*trackDesignList != 0) { + // Show track design list + RCT2_CALLPROC_X(0x006CF1A2, *((sint16*)&item), 0, 0, 0, 0, 0, 0); + return; + } + } + + // Show ride construction window + RCT2_CALLPROC_X(0x006B4800, *((sint16*)&item), 0, 0, 0, 0, 0, 0); } \ No newline at end of file diff --git a/src/window_research.c b/src/window_research.c index c0138a751e..30d9787e18 100644 --- a/src/window_research.c +++ b/src/window_research.c @@ -68,8 +68,8 @@ static rct_widget window_research_development_widgets[] = { { WWT_RESIZE, 1, 0, 299, 43, 195, 0xFFFFFFFF, STR_NONE }, { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_RESEARCH_AND_DEVELOPMENT_TIP }, { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_FINANCES_RESEARCH }, - { WWT_GROUPBOX, 2, 3, 292, 47, 116, 2267, STR_NONE }, - { WWT_GROUPBOX, 2, 3, 292, 124, 188, 2268, STR_NONE }, + { WWT_GROUPBOX, 2, 3, 292, 47, 116, STR_CURRENTLY_IN_DEVELOPMENT, STR_NONE }, + { WWT_GROUPBOX, 2, 3, 292, 124, 188, STR_LAST_DEVELOPMENT, STR_NONE }, { WWT_FLATBTN, 2, 265, 288, 161, 184, 0xFFFFFFFF, STR_RESEARCH_SHOW_DETAILS_TIP }, { WIDGETS_END }, }; @@ -382,10 +382,10 @@ static void window_research_development_paint() if (typeId != 0xFFFFFFFF) { if (typeId >= 0x10000) { uint8 *rideEntry = RCT2_GLOBAL(0x009ACFA4 + (typeId & 0xFF) * 4, uint8*); - if (RCT2_GLOBAL(rideEntry + 8, uint32) & 0x1000) - stringId = RCT2_GLOBAL(rideEntry, uint16); - else - stringId = (typeId & 0xFF00) + 2; + if (RCT2_GLOBAL(rideEntry + 8, uint32) & 0x1000) + stringId = RCT2_GLOBAL(rideEntry, uint16); + else + stringId = (typeId & 0xFF00) + 2; lastDevelopmentFormat = STR_RESEARCH_RIDE_LABEL; } else { @@ -394,7 +394,7 @@ static void window_research_development_paint() lastDevelopmentFormat = STR_RESEARCH_SCENERY_LABEL; } gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 266, lastDevelopmentFormat, 0); - } + } } #pragma endregion