diff --git a/projects/openrct2.vcxproj b/projects/openrct2.vcxproj index f948462979..459c5bbc01 100644 --- a/projects/openrct2.vcxproj +++ b/projects/openrct2.vcxproj @@ -87,7 +87,9 @@ + + diff --git a/projects/openrct2.vcxproj.filters b/projects/openrct2.vcxproj.filters index 181b6cd8bd..c5dcc45474 100644 --- a/projects/openrct2.vcxproj.filters +++ b/projects/openrct2.vcxproj.filters @@ -257,6 +257,12 @@ Source Files + + Windows + + + Windows + diff --git a/src/addresses.h b/src/addresses.h index 364989cf5c..d9c7a46036 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -98,12 +98,20 @@ #define RCT2_ADDRESS_TOOL_WINDOWNUMBER 0x009DE542 #define RCT2_ADDRESS_TOOL_WINDOWCLASS 0x009DE544 +#define RCT2_ADDRESS_CURRENT_TOOL 0x009DE545 #define RCT2_ADDRESS_TOOL_WIDGETINDEX 0x009DE546 #define RCT2_ADDRESS_CURSOR_OVER_WINDOWCLASS 0x009DE55C #define RCT2_ADDRESS_CURSOR_OVER_WINDOWNUMBER 0x009DE55E #define RCT2_ADDRESS_CURSOR_OVER_WIDGETINDEX 0x009DE560 +#define RCT2_ADDRESS_MAP_SELECTION_FLAGS 0x009DE58A +#define RCT2_ADDRESS_MAP_SELECTION_A_X 0x009DE58C +#define RCT2_ADDRESS_MAP_SELECTION_B_X 0x009DE58E +#define RCT2_ADDRESS_MAP_SELECTION_A_Y 0x009DE590 +#define RCT2_ADDRESS_MAP_SELECTION_B_Y 0x009DE592 +#define RCT2_ADDRESS_MAP_SELECTION_TYPE 0x009DE594 + #define RCT2_ADDRESS_SCREEN_FLAGS 0x009DEA68 #define RCT2_ADDRESS_SCREENSHOT_COUNTDOWN 0x009DEA6D #define RCT2_ADDRESS_PLACE_OBJECT_MODIFIER 0x009DEA70 @@ -133,7 +141,7 @@ #define RCT2_ADDRESS_SPRITES_START_LITTER 0x013573C4 #define RCT2_ADDRESS_CURRENT_LOAN 0x013573E0 -#define RCT2_ADDRESS_GAME_FLAGS 0x013573E4 +#define RCT2_ADDRESS_PARK_FLAGS 0x013573E4 #define RCT2_ADDRESS_PARK_ENTRANCE_FEE 0x013573E8 #define RCT2_ADDRESS_GUESTS_IN_PARK 0x01357844 #define RCT2_ADDRESS_MONTHLY_RIDE_INCOME 0x01357894 @@ -155,6 +163,7 @@ #define RCT2_ADDRESS_MAP_SIZE 0x01358834 +#define RCT2_ADDRESS_SCENARIO_NAME 0x0135920A #define RCT2_ADDRESS_SCENARIO_DETAILS 0x0135924A #define RCT2_ADDRESS_PARK_ENTRANCE_X 0x01359350 @@ -188,6 +197,7 @@ #define RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT 0x0141E9AC #define RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE 0x0141E9AE +#define RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID 0x0141E9AE #define RCT2_ADDRESS_CURRENT_ROTATION 0x0141E9E0 #define RCT2_ADDRESS_SCENARIO_NAME 0x0141F5B8 diff --git a/src/editor.c b/src/editor.c index c34485048d..109e947e36 100644 --- a/src/editor.c +++ b/src/editor.c @@ -58,7 +58,7 @@ void editor_load() RCT2_CALLPROC_EBPSAFE(0x006BD39C); RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_SCENARIO_EDITOR; RCT2_GLOBAL(0x0141F570, uint8) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_GAME_FLAGS, uint32) |= 16; + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= 16; RCT2_CALLPROC_EBPSAFE(0x006ACA58); RCT2_GLOBAL(0x0141F571, uint8) = 4; viewport_init_all(); diff --git a/src/game.c b/src/game.c index b83169e0d8..cf8fe6b6fc 100644 --- a/src/game.c +++ b/src/game.c @@ -29,6 +29,7 @@ #include "peep.h" #include "screenshot.h" #include "strings.h" +#include "title.h" #include "tutorial.h" #include "widget.h" #include "window.h" @@ -986,6 +987,8 @@ static int game_check_affordability(int cost) return ebp; } +static uint32 game_do_command_table[58]; + /** * * rct2: 0x006677F2 @@ -1004,9 +1007,6 @@ int game_do_command(int eax, int ebx, int ecx, int edx, int esi, int edi, int eb original_edi = edi; original_ebp = ebp; - RCT2_CALLFUNC_X(0x006677F2, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - return ebx; - flags = ebx; RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = 0xFFFF; @@ -1016,7 +1016,7 @@ int game_do_command(int eax, int ebx, int ecx, int edx, int esi, int edi, int eb ebx &= ~1; // Primary command - RCT2_CALLFUNC_X(RCT2_ADDRESS(0x0097B9A4, uint32)[esi], &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + RCT2_CALLFUNC_X(game_do_command_table[esi], &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); cost = ebx; if (cost != 0x80000000) { @@ -1039,7 +1039,7 @@ int game_do_command(int eax, int ebx, int ecx, int edx, int esi, int edi, int eb } // Secondary command - RCT2_CALLFUNC_X(RCT2_ADDRESS(0x0097B9A4, uint32)[esi], &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + RCT2_CALLFUNC_X(game_do_command_table[esi], &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); edx = ebx; if (edx != 0x80000000 && edx < cost) @@ -1075,4 +1075,257 @@ int game_do_command(int eax, int ebx, int ecx, int edx, int esi, int edi, int eb window_error_open(RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16), RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16)); return 0x80000000; -} \ No newline at end of file +} + +/** + * + * rct2: 0x00667C15 + */ +static void game_pause_toggle() +{ + rct_window *w; + char input_bl, input_dl; + short input_di; + + __asm mov input_bl, bl + + if (input_bl & 1) { + RCT2_GLOBAL(0x009DEA6E, uint32) ^= 1; + window_invalidate_by_id(WC_TOP_TOOLBAR, 0); + if (RCT2_GLOBAL(0x009DEA6E, uint32) & 1) + RCT2_CALLPROC_EBPSAFE(0x006BABB4); // pause_sounds + else + RCT2_CALLPROC_EBPSAFE(0x006BABD8); // unpause_sounds + } + + __asm mov ebx, 0 +} + +/** + * + * rct2: 0x0066DB5F + */ +static void game_load_or_quit() +{ + rct_window *w; + char input_bl, input_dl; + short input_di; + + __asm mov input_bl, bl + __asm mov input_dl, dl + __asm mov input_di, di + + if (!(input_bl & 1)) + return 0; + + switch (input_dl) { + case 0: + RCT2_GLOBAL(0x009A9802, uint16) = input_di; + window_save_prompt_open(); + break; + case 1: + window_close_by_id(WC_SAVE_PROMPT, 0); + break; + default: + game_load_or_quit_no_save_prompt(); + break; + } + + __asm mov ebx, 0 +} + +/** + * + * rct2: 0x00674F40 + */ +static int open_landscape_file_dialog() +{ + format_string(0x0141ED68, STR_LOAD_LANDSCAPE_DIALOG_TITLE, 0); + strcpy(0x0141EF68, RCT2_ADDRESS_LANDSCAPES_PATH); + format_string(0x0141EE68, STR_RCT2_LANDSCAPE_FILE, 0); + RCT2_CALLPROC_EBPSAFE(0x006BABB4); // pause_sounds + osinterface_open_common_file_dialog(1, 0x0141ED68, 0x0141EF68, "*.SV6;*.SV4;*.SC6", 0x0141EE68); + RCT2_CALLPROC_EBPSAFE(0x006BABD8); // unpause_sounds + // window_proc +} + +/** + * + * rct2: 0x00674EB6 + */ +static int open_load_game_dialog() +{ + format_string(0x0141ED68, STR_LOAD_GAME_DIALOG_TITLE, 0); + strcpy(0x0141EF68, RCT2_ADDRESS_SAVED_GAMES_PATH); + format_string(0x0141EE68, STR_RCT2_SAVED_GAME, 0); + RCT2_CALLPROC_EBPSAFE(0x006BABB4); // pause_sounds + osinterface_open_common_file_dialog(1, 0x0141ED68, 0x0141EF68, "*.SV6", 0x0141EE68); + RCT2_CALLPROC_EBPSAFE(0x006BABD8); // unpause_sounds + // window_proc +} + +/** + * + * rct2: 0x0066DC0F + */ +static void load_landscape() +{ + if (open_landscape_file_dialog() == 0) { + gfx_invalidate_screen(); + } else { + // Set default filename + char *esi = 0x0141EF67; + while (1) { + esi++; + if (*esi == '.') + break; + if (*esi != 0) + continue; + strcpy(esi, ".SC6"); + break; + } + strcpy(0x009ABB37, 0x0141EF68); + + RCT2_CALLPROC_EBPSAFE(0x006758C0); // landscape_load + if (1) { + gfx_invalidate_screen(); + // game_loop_iteration + } else { + RCT2_GLOBAL(0x009DEA66, uint16) = 0; + // game_loop_iteration + } + } +} + +/** + * + * rct2: 0x0066DBB7 + */ +static void load_game() +{ + if (open_load_game_dialog() == 0) { + gfx_invalidate_screen(); + } else { + // Set default filename + char *esi = 0x0141EF67; + while (1) { + esi++; + if (*esi == '.') + break; + if (*esi != 0) + continue; + strcpy(esi, ".SV6"); + break; + } + strcpy(0x009ABB37, 0x0141EF68); + + RCT2_CALLPROC_EBPSAFE(0x00675E1B); // game_load + if (1) { + gfx_invalidate_screen(); + // game_loop_iteration + } else { + RCT2_GLOBAL(0x009DEA66, uint16) = 0; + // game_loop_iteration + } + } +} + +/** + * + * rct2: 0x006E3879 + */ +static void rct2_exit() +{ + RCT2_CALLPROC_EBPSAFE(0x006E3879); +} + +/** + * + * rct2: 0x0066DB79 + */ +void game_load_or_quit_no_save_prompt() +{ + if (RCT2_GLOBAL(0x009A9802, uint16) < 1) { + game_do_command(0, 1, 0, 1, 5, 0, 0); + tool_cancel(); + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2) + load_landscape(); + else + load_game(); + } else if (RCT2_GLOBAL(0x009A9802, uint16) == 1) { + game_do_command(0, 1, 0, 1, 5, 0, 0); + if (RCT2_GLOBAL(0x009DE518, uint32) & (1 << 5)) { + RCT2_CALLPROC_EBPSAFE(0x0040705E); + RCT2_GLOBAL(0x009DE518, uint32) &= ~(1 << 5); + } + title_load(); + // game_loop_iteration + } else { + rct2_exit(); + } +} + +#pragma region Game command function table + +static uint32 game_do_command_table[58] = { + 0x006B2FC5, + 0x0066397F, + game_pause_toggle, + 0x006C511D, + 0x006C5B69, + game_load_or_quit, + 0x006B3F0F, + 0x006B49D9, + 0x006B4EA6, + 0x006B52D4, + 0x006B578B, + 0x006B5559, + 0x006660A8, + 0x0066640B, + 0x006E0E01, + 0x006E08F4, + 0x006E650F, + 0x006A61DE, + 0x006A68AE, + 0x006A67C0, + 0x00663CCD, + 0x006B53E9, + 0x00698D6C, + 0x0068C542, + 0x0068C6D1, + 0x0068BC01, + 0x006E66A0, + 0x006E6878, + 0x006C5AE9, + 0x006BEFA1, + 0x006C09D1, + 0x006C0B83, + 0x006C0BB5, + 0x00669C6D, + 0x00669D4A, + 0x006649BD, + 0x006666E7, + 0x00666A63, + 0x006CD8CE, + 0x00669E30, + 0x00669E55, + 0x006E519A, + 0x006E5597, + 0x006B893C, + 0x006B8E1B, + 0x0069DFB3, + 0x00684A7F, + 0x006D13FE, + 0x0069E73C, + 0x006CDEE4, + 0x006B9E6D, + 0x006BA058, + 0x006E0F26, + 0x006E56B5, + 0x006B909A, + 0x006BA16A, + 0x006648E3, + 0x0068DF91 +}; + +#pragma endregion \ No newline at end of file diff --git a/src/game.h b/src/game.h index cca9afb469..23aaff9a33 100644 --- a/src/game.h +++ b/src/game.h @@ -27,4 +27,6 @@ void game_logic_update(); int game_do_command(int eax, int ebx, int ecx, int edx, int esi, int edi, int ebp); +void game_load_or_quit_no_save_prompt(); + #endif diff --git a/src/gfx.c b/src/gfx.c index 7785422d87..1a313818c3 100644 --- a/src/gfx.c +++ b/src/gfx.c @@ -27,6 +27,10 @@ #include "strings.h" #include "window.h" +// HACK These were originally passed back through registers +int gLastDrawStringX; +int gLastDrawStringY; + uint8 _screenDirtyBlocks[5120]; static void gfx_draw_dirty_blocks(int x, int y, int columns, int rows); @@ -486,5 +490,17 @@ void gfx_draw_string_left(rct_drawpixelinfo *dpi, int format, void *args, int co */ void gfx_draw_string(rct_drawpixelinfo *dpi, char *format, int colour, int x, int y) { - RCT2_CALLPROC_X(0x00682702, colour, 0, x, y, format, dpi, 0); + int eax, ebx, ecx, edx, esi, edi, ebp; + + eax = colour; + ebx = 0; + ecx = x; + edx = y; + esi = format; + edi = dpi; + ebp = 0; + RCT2_CALLFUNC_X(0x00682702, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + + gLastDrawStringX = ecx; + gLastDrawStringY = edx; } diff --git a/src/gfx.h b/src/gfx.h index 47ef36c70a..9af771d4f8 100644 --- a/src/gfx.h +++ b/src/gfx.h @@ -46,6 +46,9 @@ typedef struct { sint16 unused; // 0x0E } rct_g1_element; +extern int gLastDrawStringX; +extern int gLastDrawStringY; + void gfx_load_g1(); void gfx_clear(rct_drawpixelinfo *dpi, int colour); diff --git a/src/map.c b/src/map.c index 1e2dc405bd..bae30cd6fa 100644 --- a/src/map.c +++ b/src/map.c @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (c) 2014 Ted John + * Copyright (c) 2014 Ted John, Peter Hill * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. * * This file is part of OpenRCT2. @@ -123,34 +123,147 @@ void map_update_tile_pointers() } /** - * + * Return the absolute height of an element, given its (x,y) coordinates + * * rct2: 0x00662783 - * UNFINISHED */ -int sub_662783(int x, int y) +int map_element_height(int x, int y) { int i; rct_map_element *mapElement; + // Off the map if (x >= 8192 || y >= 8192) return 16; - x &= 0xFFFFFFE0; - y &= 0xFFFFFFE0; + // Find the tile the element is on + int x_tile = x & 0xFFFFFFE0; + int y_tile = y & 0xFFFFFFE0; - i = ((y * 256) + x) / 8; + i = ((y_tile * 256) + x_tile) / 32; mapElement = TILE_MAP_ELEMENT_POINTER(i); while (mapElement->type & MAP_ELEMENT_TYPE_MASK) { mapElement++; } - uint32 result = + uint32 height = ((mapElement->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK) << 20) | (mapElement->base_height << 3); - uint32 ebx = (mapElement->properties.surface.slope & MAP_ELEMENT_SLOPE_MASK) & ~0x16; - // slope logic + uint32 slope = (mapElement->properties.surface.slope & MAP_ELEMENT_SLOPE_MASK); + uint8 extra_height = (slope & 0x10) >> 4; // 0x10 is the 5th bit - sets slope to double height + // Remove the extra height bit + slope &= 0xF; - return result; + uint8 quad, quad_extra; // which quadrant the element is in? + // quad_extra is for extra height tiles + + uint8 xl, yl; // coordinates across this tile + + uint8 TILE_SIZE = 31; + + xl = x & 0x1f; + yl = y & 0x1f; + + // Slope logic: + // Each of the four bits in slope represents that corner being raised + // slope == 15 (all four bits) is not used and slope == 0 is flat + // If the extra_height bit is set, then the slope goes up two z-levels + + // We arbitrarily take the SW corner to be closest to the viewer + + // One corner up + if ((slope == 1) || (slope == 2) || (slope == 4) || (slope == 8)) { + switch (slope) { + case 1: // NE corner up + quad = xl + yl - TILE_SIZE; + break; + case 2: // SE corner up + quad = xl - yl; + break; + case 4: // SW corner up + quad = TILE_SIZE - yl - xl; + break; + case 8: // NW corner up + quad = xl - yl; + break; + } + // If the element is in the quadrant with the slope, raise its height + if (quad > 0) { + height += quad / 2; + } + } + + // One side up + switch (slope) { + case 3: // E side up + height += xl / 2; + break; + case 6: // S side up + height += (TILE_SIZE - yl) / 2; + break; + case 9: // N side up + height += yl / 2; + height++; + break; + case 12: // W side up + height += (TILE_SIZE - xl) / 2; + break; + } + + // One corner down + if ((slope == 7) || (slope == 11) || (slope == 13) || (slope == 14)) { + switch (slope) { + case 7: // NW corner down + quad_extra = xl + TILE_SIZE - yl; + quad = xl - yl; + break; + case 11: // SW corner down + quad_extra = xl + yl; + quad = xl + yl - TILE_SIZE; + break; + case 13: // SE corner down + quad_extra = TILE_SIZE - xl + yl; + quad = xl - yl; + break; + case 14: // NE corner down + quad_extra = (TILE_SIZE - xl) + (TILE_SIZE - yl); + quad = TILE_SIZE - yl - xl; + break; + } + + if (extra_height) { + height += quad_extra / 2; + height++; + return height; + } + // This tile is essentially at the next height level + height += 0x10; + // so we move *down* the slope + if (quad < 0) { + height += quad / 2; + height += 0xFF00; + } + } + + // Valleys + if ((slope == 5) || (slope == 10)) { + switch (slope) { + case 5: // NW-SE valley + if (xl + yl <= TILE_SIZE + 1) { + return height; + } + quad = TILE_SIZE - xl - yl; + break; + case 10: // NE-SW valley + quad = xl - yl; + break; + } + if (quad > 0) { + height += quad / 2; + } + } + + return height; } diff --git a/src/map.h b/src/map.h index 8a42517699..5d0f1a655b 100644 --- a/src/map.h +++ b/src/map.h @@ -184,5 +184,6 @@ enum { void map_init(); void map_update_tile_pointers(); +int map_element_height(int x, int y); #endif diff --git a/src/news_item.c b/src/news_item.c index f09f7f19c8..4e862d599b 100644 --- a/src/news_item.c +++ b/src/news_item.c @@ -184,17 +184,9 @@ void news_item_get_subject_location(int type, int subject, int *x, int *y, int * *x = SPRITE_LOCATION_NULL; break; } - { - uint32 eax, ebx, ecx, edx, esi, edi, ebp; - eax = (ride->var_050 & 0xFF) * 32 + 16; - ecx = (ride->var_050 >> 8) * 32 + 16; - RCT2_CALLFUNC_X(0x00662783, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - if (edx & 0xFFFF0000) - edx >>= 16; - *x = eax; - *y = ecx; - *z = edx; - } + *x = (ride->var_050 & 0xFF) * 32 + 16; + *y = (ride->var_050 >> 8) * 32 + 16; + *z = map_element_height(*x, *y); break; case NEWS_ITEM_PEEP_ON_RIDE: peep = &(RCT2_ADDRESS(RCT2_ADDRESS_SPRITE_LIST, rct_sprite)[subject]); @@ -233,16 +225,10 @@ void news_item_get_subject_location(int type, int subject, int *x, int *y, int * *z = peep->z; break; case NEWS_ITEM_BLANK: - { - uint32 eax, ebx, ecx, edx, esi, edi, ebp; - eax = subject; - ecx = subject >> 16; - RCT2_CALLFUNC_X(0x00662783, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - *x = eax; - *y = ecx; - *z = edx; - } - break; + *x = subject; + *y = subject >> 16; + *z = map_element_height(*x, *y); + break; default: *x = SPRITE_LOCATION_NULL; break; diff --git a/src/news_item.h b/src/news_item.h index be8dd55e42..de12b44e22 100644 --- a/src/news_item.h +++ b/src/news_item.h @@ -22,6 +22,7 @@ #define _NEWS_ITEM_H_ #include "rct2.h" +#include "map.h" enum { NEWS_ITEM_NULL, diff --git a/src/osinterface.c b/src/osinterface.c index 2b2484f70c..3e97491e5b 100644 --- a/src/osinterface.c +++ b/src/osinterface.c @@ -19,6 +19,7 @@ *****************************************************************************/ #include +#include #include #include @@ -288,3 +289,63 @@ void osinterface_free() osinterface_close_window(); SDL_Quit(); } + +/** + * + * rct2: 0x004080EA + */ +int osinterface_open_common_file_dialog(int type, char *title, char *filename, char *filterPattern, char *filterName) +{ + char initialDirectory[MAX_PATH], *dotAddress, *slashAddress; + OPENFILENAME openFileName; + BOOL result; + int tmp; + + // Get directory path from given filename + strcpy(initialDirectory, filename); + dotAddress = strrchr(filename, '.'); + if (dotAddress != NULL) { + slashAddress = strrchr(filename, '\\'); + if (slashAddress < dotAddress) + *(slashAddress + 1) = 0; + } + + // Clear filename + *filename = 0; + + // Set open file name options + memset(&openFileName, 0, sizeof(OPENFILENAME)); + openFileName.lStructSize = sizeof(OPENFILENAME); + openFileName.hwndOwner = RCT2_GLOBAL(0x009E2D70, HWND); + openFileName.lpstrFile = filename; + openFileName.nMaxFile = MAX_PATH; + openFileName.lpstrInitialDir = initialDirectory; + openFileName.lpstrTitle = title; + + // Copy filter name + strcpy(0x01423800, filterName); + + // Copy filter pattern + strcpy(0x01423800 + strlen(filterName) + 1, filterPattern); + *((char*)(0x01423800 + strlen(filterName) + 1 + strlen(filterPattern) + 1)) = 0; + openFileName.lpstrFilter = 0x01423800; + + // + tmp = RCT2_GLOBAL(0x009E2C74, uint32); + if (RCT2_GLOBAL(0x009E2BB8, uint32) == 2 && RCT2_GLOBAL(0x009E1AF8, uint32) == 1) + RCT2_GLOBAL(0x009E2C74, uint32) = 1; + + // Open dialog + if (type == 0) { + openFileName.Flags = OFN_EXPLORER | OFN_CREATEPROMPT | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; + result = GetSaveFileName(&openFileName); + } else if (type == 1) { + openFileName.Flags = OFN_EXPLORER | OFN_NONETWORKBUTTON | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; + result = GetOpenFileName(&openFileName); + } + + // + RCT2_GLOBAL(0x009E2C74, uint32) = tmp; + + return result; +} \ No newline at end of file diff --git a/src/osinterface.h b/src/osinterface.h index 205d0170a0..9ec682fea2 100644 --- a/src/osinterface.h +++ b/src/osinterface.h @@ -46,4 +46,6 @@ void osinterface_process_messages(); void osinterface_draw(); void osinterface_free(); +int osinterface_open_common_file_dialog(int type, char *title, char *filename, char *filterPattern, char *filterName); + #endif diff --git a/src/park.c b/src/park.c index 7a80e0356d..13f3728c2f 100644 --- a/src/park.c +++ b/src/park.c @@ -28,7 +28,7 @@ int park_is_open() { - return (RCT2_GLOBAL(RCT2_ADDRESS_GAME_FLAGS, uint32) & GAME_FLAGS_PARK_OPEN) != 0; + return (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_OPEN) != 0; } /** @@ -86,7 +86,7 @@ int calculate_park_rating() int result; result = 1150; - if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_FLAGS, uint32) & 0x4000) + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & 0x4000) result = 1050; // Guests diff --git a/src/park.h b/src/park.h index 98b27d299f..287729ac6f 100644 --- a/src/park.h +++ b/src/park.h @@ -51,6 +51,22 @@ enum { PARK_AWARD_BEST_GENTLE_RIDES, }; +enum { + PARK_FLAGS_PARK_OPEN = (1 << 0), + PARK_FLAGS_FORBID_LANDSCAPE_CHANGES = (1 << 2), + PARK_FLAGS_FORBID_TREE_REMOVAL = (1 << 3), + PARK_FLAGS_SHOW_REAL_GUEST_NAMES = (1 << 4), + PARK_FLAGS_FORBID_HIGH_CONSTRUCTION = (1 << 5), // below tree height + PARK_FLAGS_PREF_LESS_INTENSE_RIDES = (1 << 6), + PARK_FLAGS_FORBID_MARKETING_CAMPAIGN = (1 << 7), + PARK_FLAGS_PREF_MORE_INTENSE_RIDES = (1 << 11), + PARK_FLAGS_DIFFICULT_GUEST_GENERATION = (1 << 12), + PARK_FLAGS_PARK_FREE_ENTRY = (1 << 13), + PARK_FLAGS_DIFFICULT_PARK_RATING = (1 << 14), + PARK_FLAGS_NO_MONEY = (1 << 17), + PARK_FLAGS_18 = (1 << 18) +}; + int park_is_open(); void park_init(); int park_calculate_size(); diff --git a/src/peep.h b/src/peep.h index f78b5d1f43..67c1d65654 100644 --- a/src/peep.h +++ b/src/peep.h @@ -8,12 +8,12 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - + * You should have received a copy of the GNU General Public License * along with this program. If not, see . *****************************************************************************/ @@ -45,6 +45,32 @@ enum PEEP_THOUGHT_TYPE { PEEP_THOUGHT_TYPE_NONE = 255 }; +enum PEEP_STATE { + + PEEP_STATE_QUEUING_FRONT = 2, + PEEP_STATE_ON_RIDE = 3, + PEEP_STATE_LEAVING_RIDE = 4, + PEEP_STATE_WALKING = 5, + PEEP_STATE_QUEUING = 6, + PEEP_STATE_ENTERING_RIDE = 7, + PEEP_STATE_SITTING = 8, + PEEP_STATE_PICKED = 9, + PEEP_STATE_PATROLLING = 10, // Not sure + PEEP_STATE_MOPING = 11, + PEEP_STATE_SWEEPING = 12, + PEEP_STATE_ENTERING_PARK = 13, + PEEP_STATE_LEAVING_PARK = 14, + PEEP_STATE_ANSWERING = 15, + PEEP_STATE_FIXING = 16, + PEEP_STATE_BUYING = 17, + PEEP_STATE_WATCHING = 18, + PEEP_STATE_EMPTYING_BIN = 19, + + PEEP_STATE_WATERING = 21, + PEEP_STATE_HEADING_TO_INSPECTION = 22, + PEEP_STATE_INSPECTING = 23 +}; + typedef struct { uint8 type; uint8 item; @@ -65,7 +91,9 @@ typedef struct { sint16 x; // 0x0E sint16 y; // 0x10 sint16 z; // 0x12 - uint8 pad_14[0x0E]; + uint8 pad_14[0x09]; + uint8 direction; // 0x1D + uint32 pad_1E; uint16 name_string_idx; // 0x22 uint16 next_x; // 0x24 uint16 next_y; // 0x26 @@ -76,35 +104,49 @@ typedef struct { uint8 sprite_type; // 0x2D uint8 type; // 0x2E uint8 staff_type; // 0x2F - uint8 var_30; - uint8 var_31; + uint8 tshirt_colour; // 0x30 + uint8 trousers_colour; // 0x31 uint8 pad_32[0x06]; uint8 energy; // 0x38 - uint8 var_39; + uint8 energy_growth_rate; // 0x39 uint8 happiness; // 0x3A - uint8 var_03B; + uint8 happiness_growth_rate; // 0x3B uint8 nausea; // 0x3C - uint8 var_03D; + uint8 nausea_growth_rate; // 0x3D uint8 hunger; // 0x3E uint8 thirst; // 0x3F - uint8 pad_040[0x28]; + uint8 bathroom; // 0x40 + uint8 pad_041[0x27]; uint8 current_ride; // 0x68 - uint8 pad_6A; // 0x6A Part of current_ride? - uint8 current_train; // 0x6B - uint8 current_car; // 0x6C - uint8 current_seat; // 0x6D - uint8 pad_6E[0x2E]; + uint8 pad_69; + uint8 current_train; // 0x6A + uint8 current_car; // 0x6B + uint8 current_seat; // 0x6C + uint8 pad_6D[0x0F]; + uint8 rides_been_on[32]; // 0x7C uint32 id; // 0x9C - uint8 pad_A0[0x10]; + sint32 cash_in_pocket; // 0xA0 + sint32 cash_spent; // 0xA4 + uint8 pad_A8[8]; rct_peep_thought thoughts[PEEP_MAX_THOUGHTS]; // 0xB0 uint16 pad_C4; uint8 var_C6; uint8 pad_C7; - uint32 var_C8; - uint8 pad_CC[0x2A]; + uint32 var_C8; // Bit 25 Ice Cream, Bit 24 mad, Bit 3 tracking, Bit 0 leaving the park + uint8 var_CC; + uint8 pad_CD[0x17]; + uint16 paid_to_enter; // 0xE4 + uint16 paid_on_rides; // 0xE6 + uint16 paid_on_food; // 0xE8 + uint16 paid_on_souvenirs; // 0xEA + uint8 no_of_food; // 0xEC + uint8 no_of_drinks; // 0xED + uint8 no_of_souvenirs; // 0xEE + uint8 pad_EF[0x07]; uint8 balloon_colour; // 0xF6 uint8 umbrella_colour; // 0xF7 uint8 hat_colour; // 0xF8 + uint8 favourite_ride; // 0xF9 } rct_peep; int peep_get_staff_count(); diff --git a/src/rct2.c b/src/rct2.c index a118b12d5f..b54f1dbb5d 100644 --- a/src/rct2.c +++ b/src/rct2.c @@ -194,6 +194,53 @@ void rct2_update() rct2_update_2(); } +void check_cmdline_arg() +{ + if(RCT2_GLOBAL(0x009AC310, uint32) == 0xFFFFFFFF) + return; + + char *arg = RCT2_GLOBAL(0x009AC310, char *); + char processed_arg[255]; + int len, i, j; + int quote = 0; + int last_period = 0; + + RCT2_GLOBAL(0x009AC310, uint32) = 0xFFFFFFFF; + len = strlen(arg); + + for(i = 0, j = 0; i < len; i ++) + { + if(arg[i] == '\"') + { + if(quote) + quote = 0; + else + quote = 1; + continue; + } + if(arg[i] == ' ' && !quote) + break; + if(arg[i] == '.') + last_period = i; + processed_arg[j ++] = arg[i]; + } + processed_arg[j ++] = 0; + + if(!stricmp(processed_arg + last_period, "sv6")) + { + strcpy(0x00141EF68, processed_arg); + RCT2_CALLPROC_EBPSAFE(0x00675E1B); //load_saved_game + } + else if(!stricmp(processed_arg + last_period, "sc6")) + { + //TODO: scenario install + } + else if(!stricmp(processed_arg + last_period, "td6") || !stricmp(processed_arg + last_period, "td4")) + { + //TODO: track design install + } +} + void rct2_update_2() { int tick, tick2; @@ -216,6 +263,7 @@ void rct2_update_2() // TODO: screenshot countdown process + check_cmdline_arg(); // Screens if (RCT2_GLOBAL(RCT2_ADDRESS_RUN_INTRO_TICK_PART, uint8) != 0) intro_update(); diff --git a/src/rct2.h b/src/rct2.h index c62e92e1d9..7239b89b7a 100644 --- a/src/rct2.h +++ b/src/rct2.h @@ -120,14 +120,6 @@ enum { }; -enum { - GAME_FLAGS_PARK_OPEN = (1 << 0), - GAME_FLAGS_BELOW_TREE_HEIGHT_ONLY = (1 << 5), - GAME_FLAGS_NO_MONEY = (1 << 11), - GAME_FLAGS_PARK_FREE_ENTRY = (1 << 13), - GAME_FLAGS_18 = (1 << 18) -}; - void rct2_endupdate(); char *get_file_path(int pathId); void get_system_info(); diff --git a/src/scenario.c b/src/scenario.c index d8da316012..a4aa7f3510 100644 --- a/src/scenario.c +++ b/src/scenario.c @@ -446,9 +446,9 @@ void scenario_load_and_play(rct_scenario_basic *scenario) RCT2_GLOBAL(0x00F663B0, sint32) = RCT2_GLOBAL(0x009AA0F0, sint32); RCT2_GLOBAL(0x00F663B4, sint32) = RCT2_GLOBAL(0x009AA0F4, sint32); RCT2_GLOBAL(0x009DEB7C, sint16) = 0; - RCT2_GLOBAL(RCT2_ADDRESS_GAME_FLAGS, sint32) &= 0xFFFFF7FF; - if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_FLAGS, sint32) & 0x20000) - RCT2_GLOBAL(RCT2_ADDRESS_GAME_FLAGS, sint32) |= 0x800; + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, sint32) &= 0xFFFFF7FF; + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, sint32) & 0x20000) + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, sint32) |= 0x800; RCT2_CALLPROC_EBPSAFE(0x00684AC3); RCT2_CALLPROC_EBPSAFE(0x006DFEE4); news_item_init_queue(); @@ -479,11 +479,13 @@ void scenario_load_and_play(rct_scenario_basic *scenario) // format_string(0x0141ED68, RCT2_GLOBAL(ebp + 0, uint16), 0); - strcpy_s(0x0135920A, 32, 0x0141ED68); + strncpy(RCT2_ADDRESS_SCENARIO_NAME, 0x0141ED68, 31); + ((char*)RCT2_ADDRESS_SCENARIO_NAME)[31] = '\0'; // Set scenario details format_string(0x0141ED68, RCT2_GLOBAL(ebp + 4, uint16), 0); - strcpy_s(RCT2_ADDRESS_SCENARIO_DETAILS, 256, 0x0141ED68); + strncpy(RCT2_ADDRESS_SCENARIO_DETAILS, 0x0141ED68, 255); + ((char*)RCT2_ADDRESS_SCENARIO_DETAILS)[255] = '\0'; } // Set the last saved game path @@ -512,12 +514,12 @@ void scenario_load_and_play(rct_scenario_basic *scenario) RCT2_GLOBAL(0x00135882E, uint16) = 0; // Open park with free entry when there is no money - if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_FLAGS, uint32) & GAME_FLAGS_NO_MONEY) { - RCT2_GLOBAL(RCT2_ADDRESS_GAME_FLAGS, uint32) |= GAME_FLAGS_PARK_OPEN; + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) { + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_PARK_OPEN; RCT2_GLOBAL(RCT2_ADDRESS_PARK_ENTRANCE_FEE, uint16) = 0; } - RCT2_GLOBAL(RCT2_ADDRESS_GAME_FLAGS, uint32) |= GAME_FLAGS_18; + RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) |= PARK_FLAGS_18; RCT2_CALLPROC_EBPSAFE(0x006837E3); // (palette related) diff --git a/src/strings.h b/src/strings.h index 583bc4738e..1a990782d6 100644 --- a/src/strings.h +++ b/src/strings.h @@ -162,6 +162,8 @@ enum { STR_CREDIT_SPARE_6 = 863, STR_CREDIT_SPARE_7 = 864, + STR_QUIT_SCENARIO_EDITOR = 887, + STR_SCR_BMP = 890, STR_SCREENSHOT = 891, STR_SCREENSHOT_SAVED_AS = 892, @@ -170,6 +172,19 @@ enum { STR_VIEW_OPTIONS_TIP = 937, STR_ADJUST_LAND_TIP = 938, + STR_SAVE_PROMPT_SAVE = 944, + STR_SAVE_PROMPT_DONT_SAVE = 945, + STR_SAVE_PROMPT_CANCEL = 946, + + STR_SAVE_BEFORE_LOADING = 947, + STR_SAVE_BEFORE_QUITTING = 948, + STR_SAVE_BEFORE_QUITTING_2 = 949, + + STR_LOAD_GAME = 950, + STR_QUIT_GAME = 951, + STR_QUIT_GAME_2 = 952, + STR_LOAD_LANDSCAPE = 953, + STR_CANCEL = 972, STR_OK = 973, @@ -190,12 +205,31 @@ enum { STR_LOCATE_SUBJECT_TIP = 1027, + STR_LOAD_GAME_DIALOG_TITLE = 1036, + STR_LOAD_LANDSCAPE_DIALOG_TITLE = 1037, + + STR_RCT2_SAVED_GAME = 1043, + STR_RCT2_LANDSCAPE_FILE = 1045, + STR_RIDES_IN_PARK_TIP = 1053, STR_PLACE_SCENERY_TIP = 1159, STR_ADJUST_WATER_TIP = 1160, STR_BUILD_FOOTPATH_TIP = 1173, + STR_CANT_BUILD_FOOTPATH_HERE = 1176, + STR_CANT_REMOVE_FOOTPATH_FROM_HERE = 1177, + + STR_FOOTPATHS = 1181, + STR_TYPE = 1182, + STR_DIRECTION = 1183, + STR_SLOPE = 1184, + STR_DIRECTION_TIP = 1185, + STR_SLOPE_DOWN_TIP = 1186, + STR_LEVEL_TIP = 1187, + STR_SLOPE_UP_TIP = 1188, + STR_CONSTRUCT_THE_SELECTED_FOOTPATH_SECTION_TIP = 1189, + STR_REMOVE_PREVIOUS_FOOTPATH_SECTION_TIP = 1190, STR_CLOSED = 1194, STR_TEST_RUN = 1195, @@ -212,10 +246,19 @@ enum { STR_NUMERIC_UP = 1218, STR_NUMERIC_DOWN = 1219, + STR_BUILD_THIS = 1407, + STR_COST_LABEL = 1408, + + STR_QUEUE_LINE_PATH_TIP = 1423, + STR_FOOTPATH_TIP = 1424, + STR_FREE = 1430, STR_GUESTS = 1463, + STR_CONSTRUCT_FOOTPATH_ON_LAND_TIP = 1655, + STR_CONSTRUCT_BRIDGE_OR_TUNNEL_FOOTPATH_TIP = 1656, + STR_GUESTS_TIP = 1693, STR_STAFF_TIP = 1694, @@ -227,6 +270,9 @@ enum { STR_PARK_CLOSED = 1721, STR_PARK_OPEN = 1722, + STR_CANT_OPEN_PARK = 1723, + STR_CANT_CLOSE_PARK = 1724, + STR_INDIVIDUAL_GUESTS_TIP = 1752, STR_SUMMARISED_GUESTS_TIP = 1753, STR_ADMISSION_PRICE = 1756, diff --git a/src/title.c b/src/title.c index 61d2e78f52..6a85e4e6c0 100644 --- a/src/title.c +++ b/src/title.c @@ -152,7 +152,7 @@ static void title_update_showcase() { rct_window* w; uint8 script_opcode, script_operand; - short x, y; + short x, y, z; int i, _edx; if (_scriptWaitCounter <= 0) { @@ -201,18 +201,12 @@ static void title_update_showcase() case TITLE_SCRIPT_LOCATION: x = (*_currentScript++) * 32 + 16; y = (*_currentScript++) * 32 + 16; - - // Set location - int eax, ebx, ecx, edx, esi, edi, ebp; - eax = x; - ecx = y; - RCT2_CALLFUNC_X(0x00662783, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - _edx = edx; + z = map_element_height(x, y); // Update viewport w = window_get_main(); if (w != NULL) { - window_scroll_to_location(w, x, y, _edx); + window_scroll_to_location(w, x, y, z); w->flags &= ~0x08; viewport_update_position(w); } diff --git a/src/widget.c b/src/widget.c index cf4c44f959..fe5bcd96cd 100644 --- a/src/widget.c +++ b/src/widget.c @@ -18,6 +18,7 @@ * along with this program. If not, see . *****************************************************************************/ +#include #include #include "addresses.h" #include "sprites.h" @@ -33,6 +34,8 @@ static void widget_text_button(rct_drawpixelinfo *dpi, rct_window *w, int widget static void widget_text_unknown(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex); static void widget_text(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex); static void widget_text_inset(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex); +static void widget_text_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex); +static void widget_groupbox_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex); static void widget_caption_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex); static void widget_closebox_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex); static void widget_scroll_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex); @@ -94,6 +97,10 @@ void widget_scroll_update_thumbs(rct_window *w, int widget_index) } } +/** + * + * rct2: 0x006EB2A8 + */ void widget_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) { switch (w->widgets[widgetIndex].type) { @@ -134,7 +141,8 @@ void widget_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) break; case WWT_18: break; - case WWT_19: + case WWT_GROUPBOX: + widget_groupbox_draw(dpi, w, widgetIndex); break; case WWT_CAPTION: widget_caption_draw(dpi, w, widgetIndex); @@ -500,6 +508,99 @@ static void widget_text_inset(rct_drawpixelinfo *dpi, rct_window *w, int widgetI widget_text(dpi, w, widgetIndex); } +/** + * + * rct2: 0x006EC1A6 + */ +static void widget_text_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) +{ + rct_widget* widget; + int l, t, r, b, press; + uint8 colour; + + // Get the widget + widget = &w->widgets[widgetIndex]; + + // Resolve the absolute ltrb + l = w->x + widget->left + 5; + t = w->y + widget->top; + r = w->x + widget->right; + b = w->y + widget->bottom; + + // Get the colour + colour = w->colours[widget->colour]; + + press = 0; + if (widget_is_pressed(w, widgetIndex) || widget_is_active_tool(w, widgetIndex)) + press |= 0x20; + + gfx_fill_rect_inset(dpi, l, t, r, b, colour, press); + + // TODO + + gfx_fill_rect(dpi, l, t, r, b, colour); +} + +/** + * + * rct2: 0x006EB535 + */ +static void widget_groupbox_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) +{ + rct_widget* widget; + int l, t, r, b, textRight; + uint8 colour; + + // Get the widget + widget = &w->widgets[widgetIndex]; + + // Resolve the absolute ltrb + l = w->x + widget->left + 5; + t = w->y + widget->top; + r = w->x + widget->right; + b = w->y + widget->bottom; + textRight = l; + + // Text + if (widget->image != (uint32)-1) { + colour = w->colours[widget->colour] & 0x7F; + if (colour & 1) + colour |= 0x40; + gfx_draw_string_left(dpi, widget->image, 0x013CE952, colour, l, t); + textRight = gLastDrawStringX + 1; + } + + // Border + // Resolve the absolute ltrb + l = w->x + widget->left; + t = w->y + widget->top + 4; + r = w->x + widget->right; + b = w->y + widget->bottom; + + // Get the colour + colour = w->colours[widget->colour] & 0x7F; + + // Border left of text + gfx_fill_rect(dpi, l, t, l + 4, t, RCT2_ADDRESS(0x0141FC47, uint8)[colour * 8]); + gfx_fill_rect(dpi, l + 1, t + 1, l + 4, t + 1, RCT2_ADDRESS(0x0141FC4B, uint8)[colour * 8]); + + // Border right of text + gfx_fill_rect(dpi, textRight, t, r - 1, t, RCT2_ADDRESS(0x0141FC47, uint8)[colour * 8]); + gfx_fill_rect(dpi, textRight, t + 1, r - 2, t + 1, RCT2_ADDRESS(0x0141FC4B, uint8)[colour * 8]); + + // Border right + gfx_fill_rect(dpi, r - 1, t + 1, r - 1, b - 1, RCT2_ADDRESS(0x0141FC47, uint8)[colour * 8]); + gfx_fill_rect(dpi, r, t, r, b, RCT2_ADDRESS(0x0141FC4B, uint8)[colour * 8]); + + // Border bottom + gfx_fill_rect(dpi, l, b - 1, r - 2, b - 1, RCT2_ADDRESS(0x0141FC47, uint8)[colour * 8]); + gfx_fill_rect(dpi, l, b, r - 1, b, RCT2_ADDRESS(0x0141FC4B, uint8)[colour * 8]); + + // Border left + gfx_fill_rect(dpi, l, t + 1, l, b - 2, RCT2_ADDRESS(0x0141FC47, uint8)[colour * 8]); + gfx_fill_rect(dpi, l + 1, t + 2, l + 1, b - 2, RCT2_ADDRESS(0x0141FC4B, uint8)[colour * 8]); +} + /** * * rct2: 0x006EB2F9 @@ -734,6 +835,10 @@ static void widget_vscrollbar_draw(rct_drawpixelinfo *dpi, rct_scroll *scroll, i gfx_draw_string(dpi, (char*)0x009DED69, 0, l + 1, b - 8); } +/** + * + * rct2: 0x006EB951 + */ static void widget_draw_image(rct_drawpixelinfo *dpi, rct_window *w, int widgetIndex) { int l, t, r, b, colour, image; @@ -760,7 +865,26 @@ static void widget_draw_image(rct_drawpixelinfo *dpi, rct_window *w, int widgetI if (widget_is_pressed(w, widgetIndex) || widget_is_active_tool(w, widgetIndex)) image++; - if (!widget_is_disabled(w, widgetIndex)) { + if (widget_is_disabled(w, widgetIndex)) { + // Draw greyed out (light border bottom right shadow) + colour = w->colours[widget->colour]; + colour = RCT2_ADDRESS(0x00141FC4A, uint8)[(colour & 0x7F) * 8] & 0xFF; + RCT2_GLOBAL(0x009ABDA4, uint32) = 0x009DED74; + memset(0x009DED74, colour, 256); + RCT2_GLOBAL(0x009DED74, uint8) = 0; + RCT2_GLOBAL(0x00EDF81C, uint32) = 0x20000000; + image &= 0x7FFFF; + RCT2_CALLPROC_X(0x0067A46E, 0, image, l + 1, t + 1, 0, dpi, 0); + + // Draw greyed out (dark) + colour = w->colours[widget->colour]; + colour = RCT2_ADDRESS(0x00141FC48, uint8)[(colour & 0x7F) * 8] & 0xFF; + RCT2_GLOBAL(0x009ABDA4, uint32) = 0x009DED74; + memset(0x009DED74, colour, 256); + RCT2_GLOBAL(0x009DED74, uint8) = 0; + RCT2_GLOBAL(0x00EDF81C, uint32) = 0x20000000; + RCT2_CALLPROC_X(0x0067A46E, 0, image, l, t, 0, dpi, 0); + } else { if (image & 0x80000000) { // ? } @@ -771,8 +895,6 @@ static void widget_draw_image(rct_drawpixelinfo *dpi, rct_window *w, int widgetI image |= colour << 19; gfx_draw_sprite(dpi, image, l, t); - } else { - // ? } } diff --git a/src/widget.h b/src/widget.h index 96ac2e6d68..ea4eccbf11 100644 --- a/src/widget.h +++ b/src/widget.h @@ -43,7 +43,7 @@ typedef enum { WWT_DROPDOWN = 16, WWT_VIEWPORT = 17, WWT_18, - WWT_19, + WWT_GROUPBOX = 19, WWT_CAPTION = 20, WWT_CLOSEBOX = 21, WWT_SCROLL = 22, diff --git a/src/window.c b/src/window.c index 1c9b5e503b..da21178b58 100644 --- a/src/window.c +++ b/src/window.c @@ -1105,3 +1105,70 @@ void window_set_resize(rct_window *w, int minWidth, int minHeight, int maxWidth, window_invalidate(w); } } + +/** + * + * rct2: 0x006EE212 + * + * @param tool (al) + * @param widgetIndex (dx) + * @param w (esi) + */ +int tool_set(rct_window *w, int widgetIndex, int tool) +{ + if (RCT2_GLOBAL(0x009DE518, uint32) & (1 << 3)) { + if ( + w->classification == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) && + w->number == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) && + widgetIndex == RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) + ) { + tool_cancel(); + return 1; + } + } + + RCT2_GLOBAL(0x009DE518, uint32) |= (1 << 3); + RCT2_GLOBAL(0x009DE518, uint32) &= ~(1 << 6); + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TOOL, uint8) = tool; + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) = w->classification; + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) = w->number; + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) = widgetIndex; + return 0; +} + +/** + * + * rct2: 0x006EE281 + */ +void tool_cancel() +{ + rct_window *w; + + if (RCT2_GLOBAL(0x009DE518, uint32) & (1 << 3)) { + RCT2_GLOBAL(0x009DE518, uint32) &= ~(1 << 3); + + // + RCT2_CALLPROC_EBPSAFE(0x0068AAE1); + RCT2_CALLPROC_EBPSAFE(0x0068AB1B); + + // Reset map selection + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) = 0; + + if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, sint16) >= 0) { + // Invalidate tool widget + widget_invalidate( + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass), + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber), + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) + ); + + // Abort tool event + w = window_find_by_id( + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass), + RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber) + ); + if (w != NULL) + RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_ABORT], 0, 0, 0, RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16), w, 0, 0); + } + } +} \ No newline at end of file diff --git a/src/window.h b/src/window.h index d74e7e98d7..9fab72b82c 100644 --- a/src/window.h +++ b/src/window.h @@ -22,6 +22,7 @@ #define _WINDOW_H_ #include "gfx.h" +#include "park.h" #include "rct2.h" struct rct_window; @@ -250,6 +251,7 @@ enum { WC_ERROR = 11, WC_RIDE = 12, WC_RIDE_CONSTRUCTION = 13, + WC_SAVE_PROMPT = 14, WC_RIDE_LIST = 15, WC_CONSTRUCT_RIDE = 16, WC_SCENERY = 18, @@ -319,11 +321,16 @@ void window_move_position(rct_window *w, int dx, int dy); void window_resize(rct_window *w, int dw, int dh); void window_set_resize(rct_window *w, int minWidth, int minHeight, int maxWidth, int maxHeight); +int tool_set(rct_window *w, int widgetIndex, int tool); +void tool_cancel(); + // Open window functions void window_main_open(); void window_game_top_toolbar_open(); void window_game_bottom_toolbar_open(); void window_about_open(); +void window_footpath_open(); +void window_save_prompt_open(); void window_title_menu_open(); void window_title_exit_open(); void window_title_logo_open(); diff --git a/src/window_cheats.c b/src/window_cheats.c index 8e09e207cc..47ae59c9cd 100644 --- a/src/window_cheats.c +++ b/src/window_cheats.c @@ -21,13 +21,17 @@ #include #include "addresses.h" #include "park.h" +#include "peep.h" #include "strings.h" +#include "sprite.h" #include "sprites.h" #include "widget.h" #include "window.h" + #define WW 200 #define WH 128 +#define CHEATS_MONEY_INCREMENT 10000 enum { WINDOW_CHEATS_PAGE_MONEY, @@ -41,10 +45,11 @@ static enum WINDOW_CHEATS_WIDGET_IDX { WIDX_PAGE_BACKGROUND, WIDX_TAB_1, WIDX_TAB_2, - WIDX_HIGH_MONEY + WIDX_HIGH_MONEY, + WIDX_HAPPY_GUESTS = 6 //Same as HIGH_MONEY as it is also the 6th widget but on a different page }; -static rct_widget window_cheats_widgets[] = { +static rct_widget window_cheats_money_widgets[] = { { WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, 0x0FFFFFFFF, 65535}, // panel / background { WWT_CAPTION, 0, 1, WW - 2, 1, 14, 3165, STR_WINDOW_TITLE_TIP}, // title bar { WWT_CLOSEBOX, 0, WW - 13, WW - 3, 2, 13, 0x338, STR_CLOSE_WINDOW_TIP}, // close x button @@ -55,15 +60,33 @@ static rct_widget window_cheats_widgets[] = { { WIDGETS_END }, }; +static rct_widget window_cheats_guests_widgets[] = { + { WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, 0x0FFFFFFFF, 65535 }, // panel / background + { WWT_CAPTION, 0, 1, WW - 2, 1, 14, 3165, STR_WINDOW_TITLE_TIP }, // title bar + { WWT_CLOSEBOX, 0, WW - 13, WW - 3, 2, 13, 0x338, STR_CLOSE_WINDOW_TIP }, // close x button + { WWT_IMGBTN, 1, 0, WW - 1, 43, WH - 1, 0x0FFFFFFFF, 65535 }, // tab content panel + { WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 2462 }, // tab 1 + { WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, 2462 }, // tab 2 + { WWT_CLOSEBOX, 1, 4, 74, 47, 63, 2376, 2376 }, // happy guests + { WIDGETS_END }, +}; + +static rct_widget *window_cheats_page_widgets[] = { + window_cheats_money_widgets, + window_cheats_guests_widgets +}; + static void window_cheats_emptysub() { } -static void window_cheats_mouseup(); +static void window_cheats_money_mouseup(); +static void window_cheats_guests_mouseup(); static void window_cheats_update(); static void window_cheats_invalidate(); static void window_cheats_paint(); +static void window_cheats_set_page(rct_window *w, int page); -static uint32 window_cheats_events[] = { +static uint32 window_cheats_money_events[] = { window_cheats_emptysub, - window_cheats_mouseup, + window_cheats_money_mouseup, window_cheats_emptysub, window_cheats_emptysub, window_cheats_emptysub, @@ -92,6 +115,47 @@ static uint32 window_cheats_events[] = { window_cheats_emptysub }; +static uint32 window_cheats_guests_events[] = { + window_cheats_emptysub, + window_cheats_guests_mouseup, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_update, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_emptysub, + window_cheats_invalidate, + window_cheats_paint, + window_cheats_emptysub +}; + +static uint32 *window_cheats_page_events[] = { + window_cheats_money_events, + window_cheats_guests_events, +}; + +static uint32 window_cheats_page_enabled_widgets[] = { + (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | (1 << WIDX_TAB_2) | (1 << WIDX_HIGH_MONEY), + (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | (1 << WIDX_TAB_2) | (1 << WIDX_HAPPY_GUESTS) +}; + static void window_cheats_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w); void window_cheats_open() @@ -103,18 +167,17 @@ void window_cheats_open() if (window != NULL) return; - window = window_create(32, 32, WW, WH, window_cheats_events, WC_CHEATS, 0); - window->widgets = window_cheats_widgets; - window->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | (1 << WIDX_TAB_2) | (1 << WIDX_HIGH_MONEY); + window = window_create(32, 32, WW, WH, window_cheats_money_events, WC_CHEATS, 0); + window->widgets = window_cheats_money_widgets; + window->enabled_widgets = window_cheats_page_enabled_widgets[0]; window_init_scroll_widgets(window); - window->page = WINDOW_CHEATS_PAGE_MONEY; window->colours[0] = 1; window->colours[1] = 19; window->colours[2] = 19; } -static void window_cheats_mouseup() +static void window_cheats_money_mouseup() { int i; short widgetIndex; @@ -127,11 +190,53 @@ static void window_cheats_mouseup() case WIDX_CLOSE: window_close(w); break; + case WIDX_TAB_1: + case WIDX_TAB_2: + window_cheats_set_page(w, widgetIndex - WIDX_TAB_1); + break; case WIDX_HIGH_MONEY: i = DECRYPT_MONEY(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, sint32)); - i += 100000; - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, sint32) = ENCRYPT_MONEY(i); + if (i < INT_MAX - CHEATS_MONEY_INCREMENT) { + i += CHEATS_MONEY_INCREMENT; + } + else { + i = INT_MAX; + } + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, sint32) = ENCRYPT_MONEY(i); + window_invalidate_by_id(0x40 | WC_BOTTOM_TOOLBAR, 0); + break; + } +} + +static void window_cheats_guests_mouseup() +{ + int i; + short widgetIndex; + rct_window *w; + + __asm mov widgetIndex, dx + __asm mov w, esi + rct_peep* peep; + uint16 sprite_idx; + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_TAB_1: + case WIDX_TAB_2: + window_cheats_set_page(w, widgetIndex - WIDX_TAB_1); + break; + case WIDX_HAPPY_GUESTS: + for (sprite_idx = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_PEEP, uint16); sprite_idx != SPRITE_INDEX_NULL; sprite_idx = peep->next) { + peep = &(RCT2_ADDRESS(RCT2_ADDRESS_SPRITE_LIST, rct_sprite)[sprite_idx].peep); + if (peep->type != PEEP_TYPE_GUEST) + continue; + if (peep->var_2A != 0) + continue; + peep->happiness = 255; + } window_invalidate_by_id(0x40 | WC_BOTTOM_TOOLBAR, 0); break; } @@ -144,7 +249,7 @@ static void window_cheats_update() __asm mov w, esi w->var_48E++; - widget_invalidate(w->classification, w->number, WIDX_TAB_1); + widget_invalidate(w->classification, w->number, WIDX_TAB_1+w->page); } static void window_cheats_invalidate() @@ -153,9 +258,14 @@ static void window_cheats_invalidate() rct_window *w; __asm mov w, esi - strcpy((char*)0x009BC677, "Cheats"); + rct_widget **widgets = window_cheats_page_widgets[w->page]; + if (w->widgets != widgets) { + w->widgets = widgets; + window_init_scroll_widgets(w); + } + // Set correct active tab for (i = 0; i < 7; i++) w->pressed_widgets &= ~(1 << (WIDX_TAB_1 + i)); @@ -190,7 +300,19 @@ static void window_cheats_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w) if (!(w->disabled_widgets & (1 << WIDX_TAB_2))) { sprite_idx = 5568; if (w->page == WINDOW_CHEATS_PAGE_GUESTS) - sprite_idx += w->var_48E / 4; + sprite_idx += (w->var_48E / 3) % 8; gfx_draw_sprite(dpi, sprite_idx, w->x + w->widgets[WIDX_TAB_2].left, w->y + w->widgets[WIDX_TAB_2].top); } } + +static void window_cheats_set_page(rct_window *w, int page) +{ + w->page = page; + + w->enabled_widgets = window_cheats_page_enabled_widgets[page]; + + w->event_handlers = window_cheats_page_events[page]; + w->widgets = window_cheats_page_widgets[page]; + + window_invalidate(w); +} diff --git a/src/window_clear_scenery.c b/src/window_clear_scenery.c index 061de23294..f5a708f83d 100644 --- a/src/window_clear_scenery.c +++ b/src/window_clear_scenery.c @@ -116,7 +116,7 @@ static void window_clear_scenery_close() { // If the tool wasn't changed, turn tool off if (!window_clear_scenery_should_close()) - RCT2_CALLPROC_EBPSAFE(0x006EE281); + tool_cancel(); } /** diff --git a/src/window_footpath.c b/src/window_footpath.c new file mode 100644 index 0000000000..de147ada3d --- /dev/null +++ b/src/window_footpath.c @@ -0,0 +1,854 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#include +#include "addresses.h" +#include "audio.h" +#include "game.h" +#include "map.h" +#include "strings.h" +#include "sprites.h" +#include "viewport.h" +#include "widget.h" +#include "window.h" +#include "window_dropdown.h" + +enum { + PATH_CONSTRUCTION_MODE_LAND, + PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL, + PATH_CONSTRUCTION_MODE_2 +}; + +typedef struct { + uint16 pad_00; + uint32 image; // 0x02 + uint32 pad_06; + uint8 pad_0A; + uint8 flags; // 0x0B +} rct_path_type; + +static enum WINDOW_FOOTPATH_WIDGET_IDX { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + + WIDX_TYPE_GROUP, + WIDX_FOOTPATH_TYPE, + WIDX_QUEUELINE_TYPE, + + WIDX_DIRECTION_GROUP, + WIDX_DIRECTION_NW, + WIDX_DIRECTION_NE, + WIDX_DIRECTION_SW, + WIDX_DIRECTION_SE, + + WIDX_SLOPE_GROUP, + WIDX_SLOPEDOWN, + WIDX_LEVEL, + WIDX_SLOPEUP, + WIDX_CONSTRUCT, + WIDX_REMOVE, + + WIDX_MODE_GROUP, + WIDX_CONSTRUCT_ON_LAND, + WIDX_CONSTRUCT_BRIDGE_OR_TUNNEL, +}; + +static rct_widget window_footpath_widgets[] = { + { WWT_FRAME, 0, 0, 105, 0, 380, 0x0FFFFFFFF, STR_NONE }, + { WWT_CAPTION, 0, 1, 104, 1, 14, STR_FOOTPATHS, STR_WINDOW_TITLE_TIP }, + { WWT_CLOSEBOX, 0, 93, 103, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, + + // Type group + { WWT_GROUPBOX, 0, 3, 102, 17, 71, STR_TYPE, STR_NONE }, + { WWT_FLATBTN, 1, 6, 52, 30, 65, 0xFFFFFFFF, STR_FOOTPATH_TIP }, + { WWT_FLATBTN, 1, 53, 99, 30, 65, 0xFFFFFFFF, STR_QUEUE_LINE_PATH_TIP }, + + // Direction group + { WWT_GROUPBOX, 0, 3, 102, 75, 151, STR_DIRECTION, STR_NONE }, + { WWT_FLATBTN, 1, 53, 97, 87, 115, 5635, STR_DIRECTION_TIP }, + { WWT_FLATBTN, 1, 53, 97, 116, 144, 5636, STR_DIRECTION_TIP }, + { WWT_FLATBTN, 1, 8, 52, 116, 144, 5637, STR_DIRECTION_TIP }, + { WWT_FLATBTN, 1, 8, 52, 87, 115, 5638, STR_DIRECTION_TIP }, + + // Slope group + { WWT_GROUPBOX, 0, 3, 102, 155, 195, STR_SLOPE, STR_NONE }, + { WWT_FLATBTN, 1, 17, 40, 167, 190, 5145, STR_SLOPE_DOWN_TIP }, + { WWT_FLATBTN, 1, 41, 64, 167, 190, 5146, STR_LEVEL_TIP }, + { WWT_FLATBTN, 1, 65, 88, 167, 190, 5147, STR_SLOPE_UP_TIP }, + { WWT_FLATBTN, 1, 8, 97, 202, 291, 0xFFFFFFFF, STR_CONSTRUCT_THE_SELECTED_FOOTPATH_SECTION_TIP }, + { WWT_FLATBTN, 1, 30, 75, 295, 318, 5162, STR_REMOVE_PREVIOUS_FOOTPATH_SECTION_TIP }, + + // Mode group + { WWT_GROUPBOX, 0, 3, 102, 321, 374, 0xFFFFFFFF, STR_NONE }, + { WWT_FLATBTN, 1, 13, 48, 332, 367, 5639, STR_CONSTRUCT_FOOTPATH_ON_LAND_TIP }, + { WWT_FLATBTN, 1, 57, 92, 332, 367, 5640, STR_CONSTRUCT_BRIDGE_OR_TUNNEL_FOOTPATH_TIP }, + { WIDGETS_END }, +}; + +static void window_footpath_emptysub() { } +static void window_footpath_close(); +static void window_footpath_mouseup(); +static void window_footpath_mousedown(); +static void window_footpath_dropdown(); +static void window_footpath_update(); +static void window_footpath_toolupdate(); +static void window_footpath_tooldown(); +static void window_footpath_tooldrag(); +static void window_footpath_toolup(); +static void window_footpath_invalidate(); +static void window_footpath_paint(); + +static uint32 window_footpath_events[] = { + window_footpath_close, + window_footpath_mouseup, + window_footpath_emptysub, + window_footpath_mousedown, + window_footpath_dropdown, + window_footpath_emptysub, + window_footpath_update, + window_footpath_emptysub, + window_footpath_emptysub, + window_footpath_toolupdate, + window_footpath_tooldown, + window_footpath_tooldrag, + window_footpath_toolup, + window_footpath_emptysub, + window_footpath_emptysub, + window_footpath_emptysub, + window_footpath_emptysub, + window_footpath_emptysub, + window_footpath_emptysub, + window_footpath_emptysub, + window_footpath_emptysub, + window_footpath_emptysub, + window_footpath_emptysub, + window_footpath_emptysub, + window_footpath_emptysub, + window_footpath_invalidate, + window_footpath_paint, + window_footpath_emptysub +}; + +sint32 _window_footpath_cost; + +static void window_footpath_show_footpath_types_dialog(rct_window *w, rct_widget *widget, int showQueues); +static void window_footpath_set_provisional_path_at_point(int x, int y); +static int window_footpath_set_provisional_path(int type, int x, int y, int z, int slope); +static void window_footpath_place_path_at_point(int x, int y); +static void window_footpath_construct(); +static void window_footpath_remove(); + +/** + * + * rct2: 0x006A7C43 + */ +void window_footpath_open() +{ + rct_window* window; + + // Check if window is already open + window = window_bring_to_front_by_id(WC_FOOTPATH, 0); + if (window != NULL) + return; + + window = window_create( + 0, + 29, + 106, + 381, + window_footpath_events, + WC_FOOTPATH, + 0 + ); + window->widgets = window_footpath_widgets; + window->enabled_widgets = + (1 << WIDX_CLOSE) | + (1 << WIDX_FOOTPATH_TYPE) | + (1 << WIDX_QUEUELINE_TYPE) | + (1 << WIDX_DIRECTION_NW) | + (1 << WIDX_DIRECTION_NE) | + (1 << WIDX_DIRECTION_SW) | + (1 << WIDX_DIRECTION_SE) | + (1 << WIDX_SLOPEDOWN) | + (1 << WIDX_LEVEL) | + (1 << WIDX_SLOPEUP) | + (1 << WIDX_CONSTRUCT) | + (1 << WIDX_REMOVE) | + (1 << WIDX_CONSTRUCT_ON_LAND) | + (1 << WIDX_CONSTRUCT_BRIDGE_OR_TUNNEL); + + window_init_scroll_widgets(window); + RCT2_CALLPROC_EBPSAFE(0x006EE65A); + show_gridlines(); + window->colours[0] = 24; + window->colours[1] = 24; + window->colours[2] = 24; + + tool_cancel(); + RCT2_GLOBAL(0x00F3EF99, uint8) = PATH_CONSTRUCTION_MODE_LAND; + tool_set(window, WIDX_CONSTRUCT_ON_LAND, 17); + RCT2_GLOBAL(0x009DE518, uint32) |= (1 << 6); + RCT2_GLOBAL(0x00F3EF9F, uint8) = 0; + RCT2_CALLPROC_EBPSAFE(0x006A855C); +} + +/** + * + * rct2: 0x006A852F + */ +static void window_footpath_close() +{ + rct_window *w; + + __asm mov w, esi + + RCT2_CALLPROC_EBPSAFE(0x006A7831); + RCT2_CALLPROC_X(0x006CB70A, 0, 0, 0, 0, 0, 0, 0); + RCT2_CALLPROC_EBPSAFE(0x0068AB1B); + RCT2_GLOBAL(0x009DE58A, uint16) &= ~2; + window_invalidate_by_id(WC_TOP_TOOLBAR, 0); + hide_gridlines(); +} + +/** + * + * rct2: 0x006A7E92 + */ +static void window_footpath_mouseup() +{ + short widgetIndex; + rct_window *w; + + __asm mov widgetIndex, dx + __asm mov w, esi + + switch (widgetIndex) { + case WIDX_CLOSE: + window_close(w); + break; + case WIDX_CONSTRUCT: + window_footpath_construct(); + break; + case WIDX_REMOVE: + window_footpath_remove(); + break; + case WIDX_CONSTRUCT_ON_LAND: + if (RCT2_GLOBAL(0x00F3EF99, uint8) == PATH_CONSTRUCTION_MODE_LAND) + break; + + _window_footpath_cost = 0x80000000; + tool_cancel(); + RCT2_CALLPROC_EBPSAFE(0x006A7831); + RCT2_CALLPROC_EBPSAFE(0x0068AB1B); + RCT2_GLOBAL(0x009DE58A, uint16) &= ~2; + RCT2_GLOBAL(0x00F3EF99, uint8) = PATH_CONSTRUCTION_MODE_LAND; + tool_set(w, WIDX_CONSTRUCT_ON_LAND, 17); + RCT2_GLOBAL(0x009DE518, uint32) |= (1 << 6); + RCT2_GLOBAL(0x00F3EF9F, uint8) = 0; + RCT2_CALLPROC_EBPSAFE(0x006A855C); + break; + case WIDX_CONSTRUCT_BRIDGE_OR_TUNNEL: + if (RCT2_GLOBAL(0x00F3EF99, uint8) == PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL) + break; + + _window_footpath_cost = 0x80000000; + RCT2_CALLPROC_EBPSAFE(0x006EE281); + RCT2_CALLPROC_EBPSAFE(0x006A7831); + RCT2_CALLPROC_EBPSAFE(0x0068AB1B); + RCT2_GLOBAL(0x009DE58A, uint16) &= ~2; + RCT2_GLOBAL(0x00F3EF99, uint8) = PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL; + tool_set(w, WIDX_CONSTRUCT_BRIDGE_OR_TUNNEL, 12); + RCT2_GLOBAL(0x009DE518, uint32) |= (1 << 6); + RCT2_GLOBAL(0x00F3EF9F, uint8) = 0; + RCT2_CALLPROC_EBPSAFE(0x006A855C); + break; + } +} + +/** + * + * rct2: 0x006A7EC5 + */ +static void window_footpath_mousedown() +{ + short widgetIndex; + rct_window *w; + rct_widget *widget; + + __asm mov widgetIndex, dx + __asm mov w, esi + __asm mov widget, edi + + switch (widgetIndex) { + case WIDX_FOOTPATH_TYPE: + window_footpath_show_footpath_types_dialog(w, widget, 0); + break; + case WIDX_QUEUELINE_TYPE: + window_footpath_show_footpath_types_dialog(w, widget, 1); + break; + case WIDX_DIRECTION_NW: + RCT2_CALLPROC_X(0x006A8111, 0, 0, 0, 0, w, 0, 0); + break; + case WIDX_DIRECTION_NE: + RCT2_CALLPROC_X(0x006A8135, 0, 0, 0, 0, w, 0, 0); + break; + case WIDX_DIRECTION_SW: + RCT2_CALLPROC_X(0x006A815C, 0, 0, 0, 0, w, 0, 0); + break; + case WIDX_DIRECTION_SE: + RCT2_CALLPROC_X(0x006A8183, 0, 0, 0, 0, w, 0, 0); + break; + case WIDX_SLOPEDOWN: + RCT2_CALLPROC_X(0x006A81AA, 0, 0, 0, 0, w, 0, 0); + break; + case WIDX_LEVEL: + RCT2_CALLPROC_X(0x006A81C5, 0, 0, 0, 0, w, 0, 0); + break; + case WIDX_SLOPEUP: + RCT2_CALLPROC_X(0x006A81E0, 0, 0, 0, 0, w, 0, 0); + break; + } +} + +/** + * + * rct2: 0x006A7F18 + */ +static void window_footpath_dropdown() +{ + int i, j, pathId; + short dropdownIndex; + short widgetIndex; + rct_window *w; + rct_path_type *pathType; + + __asm mov dropdownIndex, ax + __asm mov widgetIndex, dx + __asm mov w, esi + + if (widgetIndex == WIDX_FOOTPATH_TYPE) + RCT2_GLOBAL(0x00F3EFA2, uint8) = 0; + else if (widgetIndex == WIDX_QUEUELINE_TYPE) + RCT2_GLOBAL(0x00F3EFA2, uint8) = 1; + else + return; + + // Get path id + pathId = dropdownIndex; + if (pathId == -1) { + pathId = RCT2_GLOBAL(0x00F3EFA0, sint16); + } else { + int flags = 4; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2) + flags = 0; + + j = 0; + for (i = 0; i < 16; i++) { + pathType = RCT2_ADDRESS(0x009ADA14, rct_path_type*)[i]; + if (pathType == (rct_path_type*)-1) + continue; + if (pathType->flags & flags) + continue; + + if (j == pathId) + break; + j++; + } + pathId = i; + } + + // Set selected path id + RCT2_GLOBAL(0x00F3EFA0, sint16) = pathId; + RCT2_CALLPROC_EBPSAFE(0x006A7831); + _window_footpath_cost = 0x80000000; + window_invalidate(w); +} + +/** + * + * rct2: 0x006A8032 + */ +static void window_footpath_toolupdate() +{ + int x, y, z; + short widgetIndex; + rct_window *w; + rct_map_element *mapElement; + + __asm mov x, eax + __asm mov y, ebx + __asm mov widgetIndex, dx + __asm mov w, esi + + if (widgetIndex == WIDX_CONSTRUCT_ON_LAND) { + window_footpath_set_provisional_path_at_point(x, y); + } else if (widgetIndex == WIDX_CONSTRUCT_BRIDGE_OR_TUNNEL) { + RCT2_CALLPROC_X(0x006A8388, 0, 0, 0, 0, w, 0, 0); + } +} + +/** + * + * rct2: 0x006A8047 + */ +static void window_footpath_tooldown() +{ + int x, y, z; + short widgetIndex; + rct_window *w; + rct_map_element *mapElement; + + __asm mov x, eax + __asm mov y, ebx + __asm mov widgetIndex, dx + __asm mov w, esi + + if (widgetIndex == WIDX_CONSTRUCT_ON_LAND) { + window_footpath_place_path_at_point(x, y); + } else if (widgetIndex == WIDX_CONSTRUCT_BRIDGE_OR_TUNNEL) { + RCT2_CALLPROC_X(0x006A840F, x, y, 0, 0, w, 0, 0); + } +} + +/** + * + * rct2: 0x006A8067 + */ +static void window_footpath_tooldrag() +{ + int x, y; + short widgetIndex; + rct_window *w; + + __asm mov x, eax + __asm mov y, ebx + __asm mov widgetIndex, dx + __asm mov w, esi + + if (widgetIndex == WIDX_CONSTRUCT_ON_LAND) { + RCT2_CALLPROC_X(0x006A82C5, x, y, 0, 0, w, 0, 0); + } +} + +/** + * + * rct2: 0x006A8066 + */ +static void window_footpath_toolup() +{ + int x, y; + short widgetIndex; + rct_window *w; + + __asm mov x, eax + __asm mov y, ebx + __asm mov widgetIndex, dx + __asm mov w, esi + + if (widgetIndex == WIDX_CONSTRUCT_ON_LAND) { + RCT2_CALLPROC_X(0x006A8380, x, y, 0, 0, w, 0, 0); + } +} + +/** + * + * rct2: 0x006A84BB + */ +static void window_footpath_update() +{ + rct_window *w; + + __asm mov w, esi + + // Invalidate construct button + widget_invalidate(WC_FOOTPATH, 0, WIDX_CONSTRUCT); + + RCT2_CALLPROC_EBPSAFE(0x006A7760); + + // Check tool + if (RCT2_GLOBAL(0x00F3EF99, uint8) == PATH_CONSTRUCTION_MODE_LAND) { + if (!(RCT2_GLOBAL(0x009DE518, uint32) & (1 << 3))) + window_close(w); + if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) != WC_FOOTPATH) + window_close(w); + if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) != WIDX_CONSTRUCT_ON_LAND) + window_close(w); + } else if (RCT2_GLOBAL(0x00F3EF99, uint8) == PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL) { + if (!(RCT2_GLOBAL(0x009DE518, uint32) & (1 << 3))) + window_close(w); + if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass) != WC_FOOTPATH) + window_close(w); + if (RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) != WIDX_CONSTRUCT_BRIDGE_OR_TUNNEL) + window_close(w); + } +} + +/** + * + * rct2: 0x006A7D1C + */ +static void window_footpath_invalidate() +{ + int selectedPath; + rct_path_type *pathType; + rct_window *w; + + __asm mov w, esi + + // Press / unpress footpath and queue type buttons + w->pressed_widgets &= ~(1 << WIDX_FOOTPATH_TYPE); + w->pressed_widgets &= ~(1 << WIDX_QUEUELINE_TYPE); + w->pressed_widgets |= RCT2_GLOBAL(0x00F3EFA2, uint8) == 0 ? + (1 << WIDX_FOOTPATH_TYPE) : + (1 << WIDX_QUEUELINE_TYPE); + + // Enable / disable construct button + window_footpath_widgets[WIDX_CONSTRUCT].type = RCT2_GLOBAL(0x00F3EF99, uint8) == PATH_CONSTRUCTION_MODE_LAND ? WWT_EMPTY : WWT_IMGBTN; + + // Set footpath and queue type button images + selectedPath = RCT2_GLOBAL(0x00F3EFA0, uint16); + pathType = RCT2_ADDRESS(0x009ADA14, rct_path_type*)[selectedPath]; + + int pathImage = 71 + pathType->image; + window_footpath_widgets[WIDX_FOOTPATH_TYPE].image = pathImage; + window_footpath_widgets[WIDX_QUEUELINE_TYPE].image = pathImage + 1; + window_footpath_widgets[WIDX_QUEUELINE_TYPE].type = WWT_FLATBTN; + + // Disable queue in if in editor + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2) + window_footpath_widgets[WIDX_QUEUELINE_TYPE].type = WWT_EMPTY; +} + +/** + * + * rct2: 0x006A7D8B + */ +static void window_footpath_paint() +{ + int x, y, image, selectedPath; + rct_path_type *pathType; + rct_window *w; + rct_drawpixelinfo *dpi; + + __asm mov w, esi + __asm mov dpi, edi + + window_draw_widgets(w, dpi); + + if (!(w->disabled_widgets & (1 << WIDX_CONSTRUCT))) { + // Get construction image + image = (RCT2_GLOBAL(0x00F3EF90, uint8) + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)) % 4; + if (RCT2_GLOBAL(0x00F3EF91, uint8) == 2) + image += 4; + else if (RCT2_GLOBAL(0x00F3EF91, uint8) == 6) + image += 8; + image = RCT2_ADDRESS(0x0098D7E0, uint8)[image]; + + selectedPath = RCT2_GLOBAL(0x00F3EFA0, uint16); + pathType = RCT2_ADDRESS(0x009ADA14, rct_path_type*)[selectedPath]; + image += pathType->image; + if (RCT2_GLOBAL(0x00F3EFA2, uint8) != 0) + image += 51; + + // Draw construction image + x = w->x + (window_footpath_widgets[WIDX_CONSTRUCT].left + window_footpath_widgets[WIDX_CONSTRUCT].right) / 2; + y = w->y + window_footpath_widgets[WIDX_CONSTRUCT].bottom - 60; + gfx_draw_sprite(dpi, image, x, y); + + // Draw build this... label + x = w->x + (window_footpath_widgets[WIDX_CONSTRUCT].left + window_footpath_widgets[WIDX_CONSTRUCT].right) / 2; + y = w->y + window_footpath_widgets[WIDX_CONSTRUCT].bottom - 23; + gfx_draw_string_centred(dpi, STR_BUILD_THIS, x, y, 0, 0); + } + + // Draw cost + x = w->x + (window_footpath_widgets[WIDX_CONSTRUCT].left + window_footpath_widgets[WIDX_CONSTRUCT].right) / 2; + y = w->y + window_footpath_widgets[WIDX_CONSTRUCT].bottom - 12; + if (_window_footpath_cost != 0x80000000) + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) + gfx_draw_string_centred(dpi, STR_COST_LABEL, x, y, 0, &_window_footpath_cost); +} + +/** + * + * rct2: 0x006A7F88 + */ +static void window_footpath_show_footpath_types_dialog(rct_window *w, rct_widget *widget, int showQueues) +{ + int i, flags, numPathTypes, image; + rct_path_type *pathType; + + numPathTypes = 0; + flags = 4; + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2) + flags = 0; + + for (i = 0; i < 16; i++) { + pathType = RCT2_ADDRESS(0x009ADA14, rct_path_type*)[i]; + if (pathType == (rct_path_type*)-1) + continue; + if (pathType->flags & flags) + continue; + + image = pathType->image + 71; + if (showQueues) + image++; + + gDropdownItemsFormat[numPathTypes] = -1; + gDropdownItemsArgs[numPathTypes] = image; + numPathTypes++; + } + + window_dropdown_show_image( + w->x + widget->left, w->y + widget->top, widget->bottom - widget->top + 1, + w->colours[1], + 0, + numPathTypes, + 47, + 36, + gAppropriateImageDropdownItemsPerRow[numPathTypes] + ); +} + +/** + * + * rct2: 0x006A81FB + */ +static void window_footpath_set_provisional_path_at_point(int x, int y) +{ + int z, slope, pathType; + rct_map_element *mapElement; + + RCT2_CALLPROC_EBPSAFE(0x0068AAE1); + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~4; + + // Get map coordinates from point + int eax, ebx, ecx, edx, esi, edi, ebp; + eax = x; + ebx = y; + edx = -34; + RCT2_CALLFUNC_X(0x00685ADC, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + x = eax & 0xFFFF; + z = ebx & 0xFF; + y = ecx & 0xFFFF; + mapElement = edx; + + if (z == 0) { + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~1; + RCT2_CALLPROC_EBPSAFE(0x006A7831); + } else { + // Check for change + if ((RCT2_GLOBAL(0x00F3EF92, uint8) & 2) && RCT2_GLOBAL(0x00F3EF94, uint16) == x && RCT2_GLOBAL(0x00F3EF96, uint16) == y && RCT2_GLOBAL(0x00F3EF98, uint8) == mapElement->base_height) + return; + + // Set map selection + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) |= 1; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_TYPE, uint16) = 4; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_A_Y, uint16) = y; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, uint16) = x; + RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, uint16) = y; + + RCT2_CALLPROC_EBPSAFE(0x006A7831); + + // Set provisional path + slope = RCT2_ADDRESS(0x0098D8B4, uint8)[mapElement->properties.surface.slope & 0x1F]; + if (z == 6) + slope = mapElement->properties.surface.slope & 7; + pathType = (RCT2_GLOBAL(0x00F3EFA2, uint8) << 7) + RCT2_GLOBAL(0x00F3EFA0, uint8); + + _window_footpath_cost = window_footpath_set_provisional_path(pathType, x, y, mapElement->base_height, slope); + // window_invalidate_by_id(eax, ebx); + } +} + +/** + * + * rct2: 0x006A76FF + */ +static int window_footpath_set_provisional_path(int type, int x, int y, int z, int slope) +{ + int cost; + int eax, ebx, ecx, edx, esi, edi, ebp; + + RCT2_CALLPROC_EBPSAFE(0x006A77FF); + + // Try and show provisional path + cost = game_do_command(x, (slope << 8) | 121, y, (type << 8) | z, 17, 0, 0); + + if (cost != 0x80000000) { + RCT2_GLOBAL(0x00F3EF94, uint16) = x; + RCT2_GLOBAL(0x00F3EF96, uint16) = y; + RCT2_GLOBAL(0x00F3EF98, uint8) = z & 0xFF; + RCT2_GLOBAL(0x00F3EF92, uint8) |= 2; + + eax = 3; + if (RCT2_GLOBAL(0x00F3EFA4, uint8) & 2) + eax = 1; + RCT2_CALLPROC_X(0x006CB70A, eax, 0, 0, 0, 0, 0, 0); + } + + return cost; +} + +/** + * + * rct2: 0x006A82C5 + */ +static void window_footpath_place_path_at_point(int x, int y) +{ + int z, presentType, selectedType, cost; + rct_map_element *mapElement; + + if (RCT2_GLOBAL(0x00F3EF9F, uint8) != 0) + return; + + RCT2_CALLPROC_EBPSAFE(0x006A7831); + + // Get map coordinates from point + int eax, ebx, ecx, edx, esi, edi, ebp; + eax = x; + ebx = y; + edx = -34; + RCT2_CALLFUNC_X(0x00685ADC, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + x = eax & 0xFFFF; + z = ebx & 0xFF; + y = ecx & 0xFFFF; + mapElement = edx; + + if (z == 0) + return; + + // Set path + presentType = RCT2_ADDRESS(0x0098D8B4, uint8)[mapElement->properties.path.type & 0x1F]; + if (z == 6) + presentType = mapElement->properties.path.type & 7; + z = mapElement->base_height; + selectedType = (RCT2_GLOBAL(0x00F3EFA2, uint8) << 7) + RCT2_GLOBAL(0x00F3EFA0, uint8); + + // Prepare error text + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = STR_CANT_BUILD_FOOTPATH_HERE; + + // Try and place path + cost = game_do_command(x, (presentType << 8) | 1, y, (selectedType << 8) | z, 17, 0, 0); + + if (cost == 0x80000000) { + RCT2_GLOBAL(0x00F3EF9F, uint8) = 1; + } else if (RCT2_GLOBAL(0x00F3EFD9, uint32) != 0) { + // bp = 0x009DEA62 + // dx = 0x009DEA60 + // cx = 0x009DEA5E + sound_play_panned(6, 0x8001); + } +} + +/** + * + * rct2: 0x006A79B7 + */ +static void window_footpath_construct() +{ + RCT2_CALLPROC_EBPSAFE(0x006A79B7); +} + +/** + * + * rct2: 0x006A7863 + */ +static void window_footpath_remove() +{ + int x, y, z, lastTile; + rct_map_element *mapElement; + + // RCT2_CALLPROC_EBPSAFE(0x006A7863); + + _window_footpath_cost = 0x80000000; + RCT2_CALLPROC_EBPSAFE(0x006A7831); + + x = RCT2_GLOBAL(0x00F3EF8A, uint16) / 32; + y = RCT2_GLOBAL(0x00F3EF8C, uint16) / 32; + int dl = (RCT2_GLOBAL(0x00F3EF8E, uint16) >> 3) & 0xFF; + int dh = dl - 2; + + if (x >= 256 || y >= 256) + goto loc_6A79B0; + + mapElement = RCT2_ADDRESS(RCT2_ADDRESS_TILE_MAP_ELEMENT_POINTERS, rct_map_element*)[y * 256 + x]; + do { + if ((mapElement->type & MAP_ELEMENT_TYPE_MASK) == MAP_ELEMENT_TYPE_PATH) { + if (mapElement->base_height == dl) { + if (mapElement->properties.path.type & 4) + if (((mapElement->properties.path.type & 3) ^ 2) != RCT2_GLOBAL(0x00F3EF90, uint8)) + continue; + goto loc_6A78EF; + } else if (mapElement->base_height == dh) { + if (!(mapElement->properties.path.type & 4)) + if ((mapElement->properties.path.type & 3) == RCT2_GLOBAL(0x00F3EF90, uint8)) + continue; + goto loc_6A78EF; + } + } + lastTile = (mapElement->flags & MAP_ELEMENT_FLAG_LAST_TILE) != 0; + mapElement++; + } while (!lastTile); + goto loc_6A79B0; + +loc_6A78EF: + dl = mapElement->base_height; + int pathType = mapElement->properties.path.type; + if (pathType & 4) { + pathType &= 3; + pathType ^= 2; + if (pathType == RCT2_GLOBAL(0x00F3EF90, uint8)) + dl += 2; + } + + // Find a connected edge + int edge = RCT2_GLOBAL(0x00F3EF90, uint8) ^ 2; + if (!(mapElement->properties.path.edges & (1 << edge))) { + edge = (edge + 1) % 4; + if (!(mapElement->properties.path.edges & (1 << edge))) { + edge = (edge + 2) % 4; + if (!(mapElement->properties.path.edges & (1 << edge))) { + edge = (edge - 1) % 4; + if (!(mapElement->properties.path.edges & (1 << edge))) + edge ^= 2; + } + } + } + + // Remove path + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = STR_CANT_REMOVE_FOOTPATH_FROM_HERE; + game_do_command(RCT2_GLOBAL(0x00F3EF8A, uint16), 1, RCT2_GLOBAL(0x00F3EF8C, uint16), mapElement->base_height, 19, 0, 0); + + // Move selection + edge ^= 2; + x = RCT2_GLOBAL(0x00F3EF8A, uint16) - RCT2_GLOBAL(0x00993CCC + (edge * 4), sint16); + y = RCT2_GLOBAL(0x00F3EF8C, uint16) - RCT2_GLOBAL(0x00993CCE + (edge * 4), sint16); + RCT2_GLOBAL(0x00F3EF8A, uint16) = x; + RCT2_GLOBAL(0x00F3EF8C, uint16) = y; + RCT2_GLOBAL(0x00F3EF8E, uint16) = dl << 3; + RCT2_GLOBAL(0x00F3EF90, uint8) = edge; + RCT2_GLOBAL(0x00F3EF9E, uint8) = 255; + +loc_6A79B0: + RCT2_CALLPROC_EBPSAFE(0x006A855C); +} \ No newline at end of file diff --git a/src/window_game_bottom_toolbar.c b/src/window_game_bottom_toolbar.c index 19b4bfa581..53559bd86a 100644 --- a/src/window_game_bottom_toolbar.c +++ b/src/window_game_bottom_toolbar.c @@ -159,7 +159,7 @@ static void window_game_bottom_toolbar_mouseup() switch (widgetIndex) { case WIDX_LEFT_OUTSET: case WIDX_MONEY: - if (!(RCT2_GLOBAL(RCT2_ADDRESS_GAME_FLAGS, uint32) & 0x800)) + if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & 0x800)) RCT2_CALLPROC_EBPSAFE(0x0069DDF1); break; case WIDX_GUESTS: @@ -302,7 +302,7 @@ static void window_game_bottom_toolbar_invalidate() } // Hide money if there is no money - if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_FLAGS, uint32) & 0x800) { + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & 0x800) { window_game_bottom_toolbar_widgets[WIDX_MONEY].type = WWT_EMPTY; window_game_bottom_toolbar_widgets[WIDX_GUESTS].top = 1; window_game_bottom_toolbar_widgets[WIDX_GUESTS].bottom = 17; diff --git a/src/window_game_top_toolbar.c b/src/window_game_top_toolbar.c index b5acb6ebae..e1740b87b7 100644 --- a/src/window_game_top_toolbar.c +++ b/src/window_game_top_toolbar.c @@ -176,10 +176,10 @@ static void window_game_top_toolbar_mouseup() case WIDX_CLEAR_SCENERY: if ((RCT2_GLOBAL(0x009DE518, uint32) & (1 << 3)) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8) == 1 && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) == 16) { - RCT2_CALLPROC_EBPSAFE(0x006EE281); + tool_cancel(); } else { show_gridlines(); - RCT2_CALLPROC_X(0x006EE212, 12, 0, 0, WIDX_CLEAR_SCENERY, w, 0, 0); + tool_set(w, WIDX_CLEAR_SCENERY, 12); RCT2_GLOBAL(0x009DE518, uint32) |= (1 << 6); RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 2; window_clear_scenery_open(); @@ -187,10 +187,10 @@ static void window_game_top_toolbar_mouseup() break; case WIDX_LAND: if ((RCT2_GLOBAL(0x009DE518, uint32) & (1 << 3)) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8) == 1 && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) == 7) { - RCT2_CALLPROC_EBPSAFE(0x006EE281); + tool_cancel(); } else { show_gridlines(); - RCT2_CALLPROC_X(0x006EE212, 18, 0, 0, WIDX_LAND, w, 0, 0); + tool_set(w, WIDX_LAND, 18); RCT2_GLOBAL(0x009DE518, uint32) |= (1 << 6); RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 1; window_land_open(); @@ -198,26 +198,26 @@ static void window_game_top_toolbar_mouseup() break; case WIDX_WATER: if ((RCT2_GLOBAL(0x009DE518, uint32) & (1 << 3)) && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, uint8) == 1 && RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16) == 8) { - RCT2_CALLPROC_EBPSAFE(0x006EE281); + tool_cancel(); } else { show_gridlines(); - RCT2_CALLPROC_X(0x006EE212, 19, 0, 0, WIDX_WATER, w, 0, 0); + tool_set(w, WIDX_WATER, 19); RCT2_GLOBAL(0x009DE518, uint32) |= (1 << 6); RCT2_GLOBAL(RCT2_ADDRESS_LAND_TOOL_SIZE, sint16) = 1; window_water_open(); } break; case WIDX_SCENERY: - RCT2_CALLPROC_X(0x006EE212, 0, 0, 0, WIDX_SCENERY, w, 0, 0); + tool_set(w, WIDX_SCENERY, 0); RCT2_GLOBAL(0x009DE518, uint32) |= (1 << 6); RCT2_CALLPROC_EBPSAFE(0x006E0FEF); break; case WIDX_PATH: - if (window_find_by_id(20, 0) == NULL) { - RCT2_CALLPROC_EBPSAFE(0x00006A7C43); + if (window_find_by_id(WC_FOOTPATH, 0) == NULL) { + window_footpath_open(); } else { - RCT2_CALLPROC_EBPSAFE(0x006EE281); - window_close_by_id(0x80 | 20, 0); + tool_cancel(); + window_close_by_id(0x80 | WC_FOOTPATH, 0); } break; case WIDX_CONSTRUCT_RIDE: @@ -346,7 +346,7 @@ static void window_game_top_toolbar_dropdown() game_do_command(0, 1, 0, 0, 5, 0, 0); break; case 1: // save game - RCT2_CALLPROC_EBPSAFE(0x006EE281); + tool_cancel(); { int eax, ebx, ecx, edx, esi, edi, ebp; RCT2_CALLFUNC_X(0x006750E9, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); diff --git a/src/window_land.c b/src/window_land.c index 0c196b46f1..ca9b9ea295 100644 --- a/src/window_land.c +++ b/src/window_land.c @@ -152,7 +152,7 @@ static void window_land_close() { // If the tool wasn't changed, turn tool off if (!window_land_should_close()) - RCT2_CALLPROC_EBPSAFE(0x006EE281); + tool_cancel(); } /** @@ -391,7 +391,7 @@ static void window_land_paint() if (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_TERRAIN_EDGE, uint8) != 255) price += numTiles * 100; - if (price != 0 && !(RCT2_GLOBAL(RCT2_ADDRESS_GAME_FLAGS, uint32) & GAME_FLAGS_NO_MONEY)) { + if (price != 0 && !(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) { RCT2_GLOBAL(0x013CE952, sint32) = price; gfx_draw_string_centred(dpi, 986, x, y, 0, 0x013CE952); } diff --git a/src/window_park.c b/src/window_park.c index e88059317b..8d2c3078f7 100644 --- a/src/window_park.c +++ b/src/window_park.c @@ -935,7 +935,7 @@ static void window_park_entrance_invalidate() } // Only allow closing of park and purchase of land when there is money - if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_FLAGS, uint32) & GAME_FLAGS_NO_MONEY) { + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) { window_park_entrance_widgets[WIDX_OPEN_OR_CLOSE].type = WWT_EMPTY; window_park_entrance_widgets[WIDX_BUY_LAND_RIGHTS].type = WWT_EMPTY; window_park_entrance_widgets[WIDX_BUY_CONSTRUCTION_RIGHTS].type = WWT_EMPTY; @@ -1417,7 +1417,7 @@ static void window_park_price_invalidate() RCT2_GLOBAL(0x013CE952, uint16) = RCT2_GLOBAL(0x013573D4, uint16); RCT2_GLOBAL(0x013CE952 + 2, uint32) = RCT2_GLOBAL(0x013573D8, uint32); - if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_FLAGS, uint32) & GAME_FLAGS_PARK_FREE_ENTRY) { + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_PARK_FREE_ENTRY) { window_park_price_widgets[WIDX_PRICE].type = WWT_12; window_park_price_widgets[WIDX_INCREASE_PRICE].type = WWT_EMPTY; window_park_price_widgets[WIDX_DECREASE_PRICE].type = WWT_EMPTY; @@ -1711,7 +1711,7 @@ static void window_park_objective_invalidate() *((short*)0x013CE954) = RCT2_GLOBAL(0x013573D8, uint32); // - if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_FLAGS, uint32) & 0x02) + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & 0x02) window_park_objective_widgets[WIDX_ENTER_NAME].type = WWT_DROPDOWN_BUTTON; else window_park_objective_widgets[WIDX_ENTER_NAME].type = WWT_EMPTY; diff --git a/src/window_ride_list.c b/src/window_ride_list.c index 1d0476640f..92d08a7918 100644 --- a/src/window_ride_list.c +++ b/src/window_ride_list.c @@ -255,7 +255,7 @@ static void window_ride_list_mousedown() numItems = 9; if (w->page != PAGE_RIDES) numItems -= 5; - if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_FLAGS, uint32) & GAME_FLAGS_NO_MONEY) + if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY) numItems--; for (i = 0; i < numItems; i++) { diff --git a/src/window_save_prompt.c b/src/window_save_prompt.c new file mode 100644 index 0000000000..35c95a7797 --- /dev/null +++ b/src/window_save_prompt.c @@ -0,0 +1,192 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of OpenRCT2. + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#include "addresses.h" +#include "game.h" +#include "rct2.h" +#include "strings.h" +#include "sprites.h" +#include "tutorial.h" +#include "widget.h" +#include "window.h" + +static enum WINDOW_SAVE_PROMPT_WIDGET_IDX { + WIDX_BACKGROUND, + WIDX_TITLE, + WIDX_CLOSE, + WIDX_3, + WIDX_SAVE, + WIDX_DONT_SAVE, + WIDX_CANCEL +}; + +static rct_widget window_save_prompt_widgets[] = { + { WWT_FRAME, 0, 0, 259, 0, 49, -1, STR_NONE }, // panel / background + { WWT_CAPTION, 0, 1, 258, 1, 14, 0, STR_WINDOW_TITLE_TIP }, // title bar + { WWT_CLOSEBOX, 0, 247, 257, 2, 13, 824, STR_CLOSE_WINDOW_TIP }, // close x button + { WWT_12, 0, 2, 257, 19, 30, 0, STR_NONE }, // + { WWT_DROPDOWN_BUTTON, 0, 8, 85, 35, 46, STR_SAVE_PROMPT_SAVE, STR_NONE }, // save + { WWT_DROPDOWN_BUTTON, 0, 91, 168, 35, 46, STR_SAVE_PROMPT_DONT_SAVE, STR_NONE }, // don't save + { WWT_DROPDOWN_BUTTON, 0, 174, 251, 35, 46, STR_SAVE_PROMPT_CANCEL, STR_NONE }, // cancel + { WIDGETS_END }, +}; + +static void window_save_prompt_emptysub() { } +static void window_save_prompt_close(); +static void window_save_prompt_mouseup(); +static void window_save_prompt_paint(); + +static uint32 window_save_prompt_events[] = { + window_save_prompt_close, + window_save_prompt_mouseup, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_emptysub, + window_save_prompt_paint, + window_save_prompt_emptysub +}; + +/** + * + * rct2: 0x0066DCBE + */ +void window_save_prompt_open() +{ + int stringId; + rct_window* window; + + // Check if window is already open + window = window_bring_to_front_by_id(WC_SAVE_PROMPT, 0); + if (window == NULL) { + window = window_create( + (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) / 2) - 130, + max(28, (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) / 2) - 25), + 260, + 50, + window_save_prompt_events, + WC_SAVE_PROMPT, + 0 + ); + + window->widgets = window_save_prompt_widgets; + window->enabled_widgets = + (1 << WIDX_CLOSE) | + (1 << WIDX_SAVE) | + (1 << WIDX_DONT_SAVE) | + (1 << WIDX_CANCEL); + window_init_scroll_widgets(window); + window->colours[0] = 154; + window->flags |= WF_TRANSPARENT; + + // Pause the game + RCT2_GLOBAL(0x009DEA6E, uint8) |= 2; + RCT2_CALLPROC_EBPSAFE(0x006BABB4); + window_invalidate_by_id(0x80 | WC_TOP_TOOLBAR, 0); + } + + stringId = RCT2_GLOBAL(0x009A9802, uint16) + STR_LOAD_GAME; + if (stringId == STR_LOAD_GAME && RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2) + stringId = STR_LOAD_LANDSCAPE; + if (stringId == STR_QUIT_GAME && RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 2) + stringId = STR_QUIT_SCENARIO_EDITOR; + window_save_prompt_widgets[WIDX_TITLE].image = stringId; + window_save_prompt_widgets[WIDX_3].image = RCT2_GLOBAL(0x009A9802, uint16) + STR_SAVE_BEFORE_LOADING; + + if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 0x0D) { + game_load_or_quit_no_save_prompt(); + return; + } + + if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) != 0) { + if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) != 1) { + RCT2_CALLPROC_EBPSAFE(0x0066EE54); + game_load_or_quit_no_save_prompt(); + return; + } else { + tutorial_stop(); + game_load_or_quit_no_save_prompt(); + return; + } + } + + if (RCT2_GLOBAL(0x009DEA66, uint16) < 3840) { + game_load_or_quit_no_save_prompt(); + return; + } +} + +/** + * + * rct2: 0x0066DF17 + */ +static void window_save_prompt_close() +{ + // Unpause the game + RCT2_GLOBAL(0x009DEA6E, uint8) &= ~2; + RCT2_CALLPROC_EBPSAFE(0x006BABD8); + window_invalidate_by_id(0x80 | WC_TOP_TOOLBAR, 0); +} + +/** + * + * rct2: 0x0066DDF2 + */ +static void window_save_prompt_mouseup() +{ + short widgetIndex; + rct_window *w; + + __asm mov widgetIndex, dx + __asm mov w, esi + + // TODO +} + +static void window_save_prompt_paint() +{ + rct_window *w; + rct_drawpixelinfo *dpi; + + __asm mov w, esi + __asm mov dpi, edi + + window_draw_widgets(w, dpi); +} \ No newline at end of file diff --git a/src/window_water.c b/src/window_water.c index 6b7eab58a5..56be72a634 100644 --- a/src/window_water.c +++ b/src/window_water.c @@ -117,7 +117,7 @@ static void window_water_close() { // If the tool wasn't changed, turn tool off if (!window_water_should_close()) - RCT2_CALLPROC_EBPSAFE(0x006EE281); + tool_cancel(); } /**