From 9fe7f7ab2cb1c2e412398cb4e42ee7f0428162de Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Fri, 5 Sep 2014 02:37:48 +0100 Subject: [PATCH] implement maintenance tab on ride window --- src/ride.h | 28 +++- src/string_ids.h | 35 +++++ src/window_ride.c | 348 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 407 insertions(+), 4 deletions(-) diff --git a/src/ride.h b/src/ride.h index e8c0508931..4e2c39e83f 100644 --- a/src/ride.h +++ b/src/ride.h @@ -137,12 +137,18 @@ typedef struct { uint16 race_winner; // 0x184 uint8 pad_186[0x06]; uint8 var_18C; - uint8 pad_18D[0x09]; + uint8 mechanic_status; // 0x18D + uint16 mechanic; // 0x18E + uint8 pad_190[0x03]; + uint8 breakdown_reason; // 0x193 + uint8 pad_194[2]; uint16 var_196; // used in computing excitement, nausea, etc uint8 var_198; uint8 var_199; - uint8 pad_19A[0xA]; + uint8 inspection_interval; // 0x19A + uint8 last_inspection; // 0x19B + uint8 pad_19C[0x8]; uint32 var_1A4; uint8 pad_1A8[6]; uint8 var_1AE; @@ -397,6 +403,24 @@ enum { MUSIC_STYLE_CANDY_STYLE }; +enum { + BREAKDOWN_NONE = 255, + BREAKDOWN_SAFETY_CUT_OUT = 0, + BREAKDOWN_RESTRAINTS_STUCK_CLOSED, + BREAKDOWN_RESTRAINTS_STUCK_OPEN, + BREAKDOWN_DOORS_STUCK_CLOSED, + BREAKDOWN_DOORS_STUCK_OPEN, + BREAKDOWN_VEHICLE_MALFUNCTION, + BREAKDOWN_BRAKES_FAILURE, + BREAKDOWN_CONTROL_FAILURE +}; + +enum { + RIDE_MECHANIC_STATUS_CALLING = 1, + RIDE_MECHANIC_STATUS_HEADING = 2, + RIDE_MECHANIC_STATUS_FIXING = 3, +}; + #define MAX_RIDES 255 #define MAX_RIDE_MEASUREMENTS 8 diff --git a/src/string_ids.h b/src/string_ids.h index 6dc09dbab2..3bbe41dc3e 100644 --- a/src/string_ids.h +++ b/src/string_ids.h @@ -462,6 +462,7 @@ enum { STR_INDIVIDUAL_GUESTS_TIP = 1752, STR_SUMMARISED_GUESTS_TIP = 1753, STR_ADMISSION_PRICE = 1756, + STR_RELIABILITY_LABEL_1757 = 1757, STR_OFF = 1775, STR_ON = 1776, @@ -474,6 +475,18 @@ enum { STR_FIXING_RIDE = 1794, STR_ANSWERING_RADIO_CALL = 1795, + STR_SAFETY_CUT_OUT = 1800, + STR_RESTRAINTS_STUCK_CLOSED = 1801, + STR_RESTRAINTS_STUCK_OPEN = 1802, + STR_DOORS_STUCK_CLOSED = 1803, + STR_DOORS_STUCK_OPEN = 1804, + STR_VEHICLE_MALFUNCTION = 1805, + STR_BRAKES_FAILURE = 1806, + STR_CONTROL_FAILURE = 1807, + + STR_LAST_BREAKDOWN = 1808, + STR_CURRENT_BREAKDOWN = 1809, + STR_ACTIONS = 1814, STR_THOUGHTS = STR_ACTIONS + 1, STR_INFORMATION_TYPE_TIP = 1816, @@ -526,8 +539,25 @@ enum { STR_ENTERTAINER_SINGULAR = 1866, STR_STAFF_LIST_COUNTER = 1867, + STR_INSPECT_RIDES = 1876, + STR_FIX_RIDES = 1877, + STR_INSPECTION = 1878, + + STR_EVERY_10_MINUTES = 1879, + STR_EVERY_20_MINUTES = 1880, + STR_EVERY_30_MINUTES = 1881, + STR_EVERY_45_MINUTES = 1882, + STR_EVERY_HOUR = 1883, + STR_EVERY_2_HOURS = 1884, + STR_NEVER = 1885, + STR_INSPECTING_RIDE = 1886, + STR_TIME_SINCE_LAST_INSPECTION_MINUTES = 1887, + STR_TIME_SINCE_LAST_INSPECTION_MORE_THAN_4_HOURS = 1888, + STR_DOWN_TIME_LABEL_1889 = 1889, + STR_SELECT_HOW_OFTEN_A_MECHANIC_SHOULD_CHECK_THIS_RIDE = 1890, + STR_ITEMS_SOLD = 1894, STR_BUILD_RIDE_TIP = 1895, STR_FINANCES_SUMMARY_EXPENDITURE_INCOME = 1896, @@ -957,6 +987,11 @@ enum { STR_TEST_RIDE = 3108, STR_OPEN_RIDE = 3109, + STR_CALLING_MECHANIC = 3117, + STR_MEHCANIC_IS_HEADING_FOR_THE_RIDE = 3118, + STR_MEHCANIC_IS_FIXING_THE_RIDE = 3119, + STR_LOCATE_NEAREST_AVAILABLE_MECHANIC_TIP = 3120, + STR_FAVOURITE_RIDE_OF_GUEST = 3122, STR_FAVOURITE_RIDE_OF_GUESTS = 3123, diff --git a/src/window_ride.c b/src/window_ride.c index a7497af872..d4d2a60b19 100644 --- a/src/window_ride.c +++ b/src/window_ride.c @@ -24,6 +24,7 @@ #include "map.h" #include "ride.h" #include "ride_data.h" +#include "staff.h" #include "string_ids.h" #include "sprite.h" #include "sprites.h" @@ -74,6 +75,10 @@ enum { WIDX_LOCATE, WIDX_DEMOLISH, + WIDX_INSPECTION_INTERVAL = 14, + WIDX_INSPECTION_INTERVAL_DROPDOWN, + WIDX_LOCATE_MECHANIC, + WIDX_PLAY_MUSIC = 14, WIDX_MUSIC, WIDX_MUSIC_DROPDOWN, @@ -112,6 +117,29 @@ static rct_widget window_ride_main_widgets[] = { { WIDGETS_END }, }; +// 0x009AE190 +static rct_widget window_ride_maintenance_widgets[] = { + { WWT_FRAME, 0, 0, 315, 0, 206, 0x0FFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 314, 1, 14, 0x3DD, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 303, 313, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + { WWT_RESIZE, 1, 0, 315, 43, 179, 0x0FFFFFFFF, STR_NONE }, + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_VIEW_OF_RIDE_ATTRACTION_TIP }, + { WWT_TAB, 1, 34, 64, 17, 46, 0x2000144E, STR_VEHICLE_DETAILS_AND_OPTIONS_TIP }, + { WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_OPERATING_OPTIONS_TIP }, + { WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_MAINTENANCE_OPTIONS_TIP }, + { WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_COLOUR_SCHEME_OPTIONS_TIP }, + { WWT_TAB, 1, 158, 188, 17, 43, 0x2000144E, STR_SOUND_AND_MUSIC_OPTIONS_TIP }, + { WWT_TAB, 1, 189, 219, 17, 43, 0x2000144E, STR_MEASUREMENTS_AND_TEST_DATA_TIP }, + { WWT_TAB, 1, 220, 250, 17, 43, 0x2000144E, STR_GRAPHS_TIP }, + { WWT_TAB, 1, 251, 281, 17, 43, 0x2000144E, STR_INCOME_AND_COSTS_TIP }, + { WWT_TAB, 1, 282, 312, 17, 43, 0x2000144E, STR_CUSTOMER_INFORMATION_TIP }, + + { WWT_DROPDOWN, 1, 107, 308, 71, 82, 0, STR_SELECT_HOW_OFTEN_A_MECHANIC_SHOULD_CHECK_THIS_RIDE }, + { WWT_DROPDOWN_BUTTON, 1, 297, 307, 72, 81, 876, STR_SELECT_HOW_OFTEN_A_MECHANIC_SHOULD_CHECK_THIS_RIDE }, + { WWT_FLATBTN, 1, 289, 312, 108, 131, 0xFFFFFFFF, STR_LOCATE_NEAREST_AVAILABLE_MECHANIC_TIP }, + { WIDGETS_END }, +}; + // 0x009AE4C8 static rct_widget window_ride_music_widgets[] = { { WWT_FRAME, 0, 0, 315, 0, 206, 0x0FFFFFFFF, STR_NONE }, @@ -162,7 +190,7 @@ static rct_widget *window_ride_page_widgets[] = { window_ride_main_widgets, (rct_widget*)0x009ADDA8, (rct_widget*)0x009ADEFC, - (rct_widget*)0x009AE190, + window_ride_maintenance_widgets, (rct_widget*)0x009AE2A4, window_ride_music_widgets, (rct_widget*)0x009AE5DC, @@ -200,6 +228,14 @@ static void window_ride_main_unknown_14(); static void window_ride_main_invalidate(); static void window_ride_main_paint(); +static void window_ride_maintenance_mouseup(); +static void window_ride_maintenance_resize(); +static void window_ride_maintenance_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); +static void window_ride_maintenance_dropdown(); +static void window_ride_maintenance_update(rct_window *w); +static void window_ride_maintenance_invalidate(); +static void window_ride_maintenance_paint(); + static void window_ride_music_mouseup(); static void window_ride_music_resize(); static void window_ride_music_mousedown(int widgetIndex, rct_window *w, rct_widget *widget); @@ -246,6 +282,38 @@ static void* window_ride_main_events[] = { window_ride_emptysub }; +// 0x0098E124 +static void* window_ride_maintenance_events[] = { + window_ride_emptysub, + window_ride_maintenance_mouseup, + window_ride_maintenance_resize, + window_ride_maintenance_mousedown, + window_ride_maintenance_dropdown, + window_ride_emptysub, + window_ride_maintenance_update, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_emptysub, + window_ride_maintenance_invalidate, + window_ride_maintenance_paint, + window_ride_emptysub +}; + // 0x0098E194 static void* window_ride_music_events[] = { window_ride_emptysub, @@ -314,7 +382,7 @@ static uint32* window_ride_page_events[] = { (uint32*)window_ride_main_events, (uint32*)0x0098E204, (uint32*)0x0098E0B4, - (uint32*)0x0098E124, + (uint32*)window_ride_maintenance_events, (uint32*)0x0098E044, (uint32*)window_ride_music_events, (uint32*)0x0098DE14, @@ -1358,6 +1426,281 @@ static void window_ride_main_paint() #pragma endregion +#pragma region Maintenance + +/** + * + * rct2: 0x006B1AE4 + */ +static void window_ride_locate_mechanic(rct_window *w) +{ + RCT2_CALLPROC_X(0x006B1AE4, 0, 0, 0, 0, (int)w, 0, 0); +} + +/** + * + * rct2: 0x006B7D08 + */ +static void window_ride_maintenance_draw_bar(rct_window *w, rct_drawpixelinfo *dpi, int x, int y, int value, int unk) +{ + RCT2_CALLPROC_X(0x006B7D08, value, 0, x, y, (int)w, (int)dpi, unk); +} + +/** + * + * rct2: 0x006B1AAD + */ +static void window_ride_maintenance_mouseup() +{ + short widgetIndex; + rct_window *w; + + window_widget_get_registers(w, widgetIndex); + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + case WIDX_TAB_3: + case WIDX_TAB_4: + case WIDX_TAB_5: + case WIDX_TAB_6: + case WIDX_TAB_7: + case WIDX_TAB_8: + case WIDX_TAB_9: + case WIDX_TAB_10: + window_ride_set_page(w, widgetIndex - WIDX_TAB_1); + break; + case WIDX_LOCATE_MECHANIC: + window_ride_locate_mechanic(w); + break; + } +} + +/** + * + * rct2: 0x006B1D70 + */ +static void window_ride_maintenance_resize() +{ + rct_window *w; + + window_get_register(w); + + window_set_resize(w, 316, 135, 316, 135); +} + +/** + * + * rct2: 0x006B1ACE + */ +static void window_ride_maintenance_mousedown(int widgetIndex, rct_window *w, rct_widget *widget) +{ + rct_widget *dropdownWidget; + int i; + + if (widgetIndex != WIDX_INSPECTION_INTERVAL_DROPDOWN) + return; + + dropdownWidget = widget - 1; + rct_ride *ride = GET_RIDE(w->number); + + for (i = 0; i < 7; i++) { + gDropdownItemsFormat[i] = 1142; + gDropdownItemsArgs[i] = STR_EVERY_10_MINUTES + i; + } + window_dropdown_show_text_custom_width( + w->x + dropdownWidget->left, + w->y + dropdownWidget->top, + dropdownWidget->bottom - dropdownWidget->top + 1, + w->colours[1], + 0, + 7, + widget->right - dropdownWidget->left + ); + + gDropdownItemsChecked = (1 << ride->inspection_interval); +} + +/** + * + * rct2: 0x006B1AD9 + */ +static void window_ride_maintenance_dropdown() +{ + rct_window *w; + rct_ride *ride; + short widgetIndex, dropdownIndex; + + window_dropdown_get_registers(w, widgetIndex, dropdownIndex); + + if (widgetIndex != WIDX_INSPECTION_INTERVAL_DROPDOWN || dropdownIndex == -1) + return; + + ride = GET_RIDE(w->number); + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_CHANGE_OPERATING_MODE; + game_do_command(0, (dropdownIndex << 8) | 1, 0, (5 << 8) | w->number, GAME_COMMAND_11, 0, 0); +} + +/** + * + * rct2: 0x006B1D37 + */ +static void window_ride_maintenance_update(rct_window *w) +{ + rct_ride *ride; + + w->frame_no++; + RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0); + widget_invalidate(WC_RIDE, w->number, WIDX_TAB_4); + + ride = GET_RIDE(w->number); + if (ride->var_14D & 20) { + ride->var_14D &= ~20; + window_invalidate(w); + } +} + +/** + * + * rct2: 0x006B17C8 + */ +static void window_ride_maintenance_invalidate() +{ + rct_window *w; + rct_widget *widgets; + + window_get_register(w); + + widgets = window_ride_page_widgets[w->page]; + if (w->widgets != widgets) { + w->widgets = widgets; + window_init_scroll_widgets(w); + } + + window_ride_set_pressed_tab(w); + + rct_ride *ride = GET_RIDE(w->number); + RCT2_GLOBAL(0x013CE952 + 0, uint16) = ride->name; + RCT2_GLOBAL(0x013CE952 + 2, uint32) = ride->name_arguments; + + window_ride_maintenance_widgets[WIDX_INSPECTION_INTERVAL].image = STR_EVERY_10_MINUTES + ride->inspection_interval; + + window_ride_anchor_border_widgets(w); + window_align_tabs(w, WIDX_TAB_1, WIDX_TAB_10); +} + +/** + * + * rct2: 0x006B1877 + */ +static void window_ride_maintenance_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + rct_ride *ride; + rct_widget *widget; + rct_peep *mechanicSprite; + int x, y; + uint16 reliability, downTime, lastInspection; + rct_string_id stringId, breakdownMessage; + + window_paint_get_registers(w, dpi); + + window_draw_widgets(w, dpi); + window_ride_draw_tab_images(dpi, w); + + ride = GET_RIDE(w->number); + + // Locate mechanic button image + widget = &window_ride_maintenance_widgets[WIDX_LOCATE_MECHANIC]; + x = w->x + widget->left; + y = w->y + widget->top; + gfx_draw_sprite(dpi, (RCT2_GLOBAL(RCT2_ADDRESS_MECHANIC_COLOUR, uint8) << 24) | 0xA0000000 | 5196, x, y, 0); + + // Inspection label + widget = &window_ride_maintenance_widgets[WIDX_INSPECTION_INTERVAL]; + x = w->x + 4; + y = w->y + widget->top + 1; + gfx_draw_string_left(dpi, STR_INSPECTION, NULL, 0, x, y); + + // Reliability + widget = &window_ride_maintenance_widgets[WIDX_PAGE_BACKGROUND]; + x = w->x + widget->left + 4; + y = w->y + widget->top + 4; + + reliability = ride->var_196 >> 8; + gfx_draw_string_left(dpi, STR_RELIABILITY_LABEL_1757, &reliability, 0, x, y); + window_ride_maintenance_draw_bar(w, dpi, x + 103, y, max(10, reliability), 14); + y += 11; + + // Down time + downTime = ride->var_199; + gfx_draw_string_left(dpi, STR_DOWN_TIME_LABEL_1889, &downTime, 0, x, y); + window_ride_maintenance_draw_bar(w, dpi, x + 103, y, downTime, 28); + y += 26; + + // Last inspection + lastInspection = ride->last_inspection; + stringId = lastInspection <= 240 ? + STR_TIME_SINCE_LAST_INSPECTION_MINUTES : + STR_TIME_SINCE_LAST_INSPECTION_MORE_THAN_4_HOURS; + gfx_draw_string_left(dpi, stringId, &lastInspection, 0, x, y); + y += 12; + + // Last / current breakdown + if (ride->breakdown_reason == BREAKDOWN_NONE) + return; + + stringId = (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) ? + STR_CURRENT_BREAKDOWN : + STR_LAST_BREAKDOWN; + breakdownMessage = STR_SAFETY_CUT_OUT + ride->breakdown_reason; + gfx_draw_string_left(dpi, stringId, &breakdownMessage, 0, x, y); + y += 10; + + // Mechanic status + if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) { + switch (ride->mechanic_status) { + case RIDE_MECHANIC_STATUS_CALLING: + stringId = STR_CALLING_MECHANIC; + break; + case RIDE_MECHANIC_STATUS_HEADING: + stringId = STR_MEHCANIC_IS_HEADING_FOR_THE_RIDE; + break; + case RIDE_MECHANIC_STATUS_FIXING: + case 4: + stringId = STR_MEHCANIC_IS_FIXING_THE_RIDE; + break; + default: + stringId = 0; + break; + } + + if (stringId != 0) { + if (stringId == STR_CALLING_MECHANIC) { + gfx_draw_string_left_wrapped(dpi, NULL, x + 4, y, 280, stringId, 0); + } else { + mechanicSprite = &(g_sprite_list[ride->mechanic].peep); + if ( + mechanicSprite->sprite_identifier == SPRITE_IDENTIFIER_PEEP && + mechanicSprite->type == PEEP_TYPE_STAFF && + mechanicSprite->staff_type == STAFF_TYPE_MECHANIC + ) { + RCT2_GLOBAL(0x013CE952 + 0, uint16) = mechanicSprite->name_string_idx; + RCT2_GLOBAL(0x013CE952 + 2, uint32) = mechanicSprite->id; + gfx_draw_string_left_wrapped(dpi, (void*)0x013CE952, x + 4, y, 280, stringId, 0); + } + } + } + } +} + +#pragma endregion + #pragma region Music const uint8 MusicStyleOrder[] = { @@ -1519,6 +1862,7 @@ static void window_ride_music_dropdown() ride = GET_RIDE(w->number); musicStyle = window_ride_current_music_style_order[dropdownIndex]; + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_CHANGE_OPERATING_MODE; game_do_command(0, (musicStyle << 8) | 1, 0, (7 << 8) | w->number, GAME_COMMAND_11, 0, 0); }