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();
}
/**