diff --git a/src/config.c b/src/config.c
index 4e6f9383c0..8a0fdbd6f6 100644
--- a/src/config.c
+++ b/src/config.c
@@ -18,13 +18,63 @@
* along with this program. If not, see .
*****************************************************************************/
+#include
#include
#include "addresses.h"
#include "config.h"
#include "rct2.h"
+// Current keyboard shortcuts
+uint16 gShortcutKeys[SHORTCUT_COUNT];
+
+// Magic number for original game cfg file
static const int MagicNumber = 0x0003113A;
+// Default keyboard shortcuts
+static const uint16 _defaultShortcutKeys[SHORTCUT_COUNT] = {
+ SDL_SCANCODE_BACKSPACE, // SHORTCUT_CLOSE_TOP_MOST_WINDOW
+ 0x0100 | SDL_SCANCODE_BACKSPACE, // SHORTCUT_CLOSE_ALL_FLOATING_WINDOWS
+ SDL_SCANCODE_ESCAPE, // SHORTCUT_CANCEL_CONSTRUCTION_MODE
+ SDL_SCANCODE_PAUSE, // SHORTCUT_PAUSE_GAME
+ SDL_SCANCODE_PAGEUP, // SHORTCUT_ZOOM_VIEW_OUT
+ SDL_SCANCODE_PAGEDOWN, // SHORTCUT_ZOOM_VIEW_IN
+ SDL_SCANCODE_RETURN, // SHORTCUT_ROTATE_VIEW
+ SDL_SCANCODE_Z, // SHORTCUT_ROTATE_CONSTRUCTION_OBJECT
+ SDL_SCANCODE_1, // SHORTCUT_UNDERGROUND_VIEW_TOGGLE
+ SDL_SCANCODE_H, // SHORTCUT_REMOVE_BASE_LAND_TOGGLE
+ SDL_SCANCODE_V, // SHORTCUT_REMOVE_VERTICAL_LAND_TOGGLE
+ SDL_SCANCODE_3, // SHORTCUT_SEE_THROUGH_RIDES_TOGGLE
+ SDL_SCANCODE_4, // SHORTCUT_SEE_THROUGH_SCENERY_TOGGLE
+ SDL_SCANCODE_5, // SHORTCUT_INVISIBLE_SUPPORTS_TOGGLE
+ SDL_SCANCODE_6, // SHORTCUT_INVISIBLE_PEOPLE_TOGGLE
+ SDL_SCANCODE_8, // SHORTCUT_HEIGHT_MARKS_ON_LAND_TOGGLE
+ SDL_SCANCODE_9, // SHORTCUT_HEIGHT_MARKS_ON_RIDE_TRACKS_TOGGLE
+ SDL_SCANCODE_0, // SHORTCUT_HEIGHT_MARKS_ON_PATHS_TOGGLE
+ SDL_SCANCODE_F1, // SHORTCUT_ADJUST_LAND
+ SDL_SCANCODE_F2, // SHORTCUT_ADJUST_WATER
+ SDL_SCANCODE_F3, // SHORTCUT_BUILD_SCENERY
+ SDL_SCANCODE_F4, // SHORTCUT_BUILD_PATHS
+ SDL_SCANCODE_F5, // SHORTCUT_BUILD_NEW_RIDE
+ SDL_SCANCODE_F, // SHORTCUT_SHOW_FINANCIAL_INFORMATION
+ SDL_SCANCODE_D, // SHORTCUT_SHOW_RESEARCH_INFORMATION
+ SDL_SCANCODE_R, // SHORTCUT_SHOW_RIDES_LIST
+ SDL_SCANCODE_P, // SHORTCUT_SHOW_PARK_INFORMATION
+ SDL_SCANCODE_G, // SHORTCUT_SHOW_GUEST_LIST
+ SDL_SCANCODE_S, // SHORTCUT_SHOW_STAFF_LIST
+ SDL_SCANCODE_M, // SHORTCUT_SHOW_RECENT_MESSAGES
+ SDL_SCANCODE_TAB, // SHORTCUT_SHOW_MAP
+ 0x0200 | SDL_SCANCODE_S // SHORTCUT_SCREENSHOT
+};
+
+/**
+ *
+ * rct2: 0x006E3604
+ */
+void config_reset_shortcut_keys()
+{
+ memcpy(gShortcutKeys, _defaultShortcutKeys, sizeof(gShortcutKeys));
+}
+
/**
*
* rct2: 0x006752D5
diff --git a/src/config.h b/src/config.h
index 019c995232..efc5df03ba 100644
--- a/src/config.h
+++ b/src/config.h
@@ -21,12 +21,53 @@
#ifndef _CONFIG_H_
#define _CONFIG_H_
+#include "rct2.h"
+
enum {
CONFIG_FLAG_ALWAYS_SHOW_GRIDLINES = (1 << 0),
CONFIG_FLAG_SHOW_HEIGHT_AS_UNITS = (1 << 1),
CONFIG_FLAG_DISABLE_SMOOTH_LANDSCAPE = (1 << 2)
};
+enum {
+ SHORTCUT_CLOSE_TOP_MOST_WINDOW,
+ SHORTCUT_CLOSE_ALL_FLOATING_WINDOWS,
+ SHORTCUT_CANCEL_CONSTRUCTION_MODE,
+ SHORTCUT_PAUSE_GAME,
+ SHORTCUT_ZOOM_VIEW_OUT,
+ SHORTCUT_ZOOM_VIEW_IN,
+ SHORTCUT_ROTATE_VIEW,
+ SHORTCUT_ROTATE_CONSTRUCTION_OBJECT,
+ SHORTCUT_UNDERGROUND_VIEW_TOGGLE,
+ SHORTCUT_REMOVE_BASE_LAND_TOGGLE,
+ SHORTCUT_REMOVE_VERTICAL_LAND_TOGGLE,
+ SHORTCUT_SEE_THROUGH_RIDES_TOGGLE,
+ SHORTCUT_SEE_THROUGH_SCENERY_TOGGLE,
+ SHORTCUT_INVISIBLE_SUPPORTS_TOGGLE,
+ SHORTCUT_INVISIBLE_PEOPLE_TOGGLE,
+ SHORTCUT_HEIGHT_MARKS_ON_LAND_TOGGLE,
+ SHORTCUT_HEIGHT_MARKS_ON_RIDE_TRACKS_TOGGLE,
+ SHORTCUT_HEIGHT_MARKS_ON_PATHS_TOGGLE,
+ SHORTCUT_ADJUST_LAND,
+ SHORTCUT_ADJUST_WATER,
+ SHORTCUT_BUILD_SCENERY,
+ SHORTCUT_BUILD_PATHS,
+ SHORTCUT_BUILD_NEW_RIDE,
+ SHORTCUT_SHOW_FINANCIAL_INFORMATION,
+ SHORTCUT_SHOW_RESEARCH_INFORMATION,
+ SHORTCUT_SHOW_RIDES_LIST,
+ SHORTCUT_SHOW_PARK_INFORMATION,
+ SHORTCUT_SHOW_GUEST_LIST,
+ SHORTCUT_SHOW_STAFF_LIST,
+ SHORTCUT_SHOW_RECENT_MESSAGES,
+ SHORTCUT_SHOW_MAP,
+ SHORTCUT_SCREENSHOT,
+ SHORTCUT_COUNT
+};
+
+extern uint16 gShortcutKeys[SHORTCUT_COUNT];
+
+void config_reset_shortcut_keys();
void config_load();
void config_save();
diff --git a/src/game.c b/src/game.c
index 43faabb0d7..7c94a2fb76 100644
--- a/src/game.c
+++ b/src/game.c
@@ -28,6 +28,7 @@
#include "peep.h"
#include "screenshot.h"
#include "strings.h"
+#include "tutorial.h"
#include "widget.h"
#include "window.h"
#include "window_error.h"
@@ -761,7 +762,140 @@ static void input_leftmousedown(int x, int y, rct_window *w, int widgetIndex)
}
}
+void game_handle_edge_scroll()
+{
+ rct_window *mainWindow;
+ int scrollX, scrollY;
+ mainWindow = window_get_main();
+ if (mainWindow == NULL)
+ return;
+ if ((mainWindow->flags & WF_2) || (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 9))
+ return;
+ if (mainWindow->viewport == NULL)
+ return;
+
+ scrollX = 0;
+ scrollY = 0;
+
+ // Scroll left / right
+ if (gCursorState.x == 0)
+ scrollX = -1;
+ else if (gCursorState.x == RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, uint16) - 1)
+ scrollX = 1;
+
+ // Scroll up / down
+ if (gCursorState.y == 0)
+ scrollY = -1;
+ else if (gCursorState.y == RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, uint16) - 1)
+ scrollY = 1;
+
+ // Scroll viewport
+ if (scrollX != 0) {
+ mainWindow->var_4B2 += scrollX * (12 << mainWindow->viewport->zoom);
+ RCT2_GLOBAL(0x009DE518, uint32) |= (1 << 7);
+ }
+ if (scrollY != 0) {
+ mainWindow->var_4B4 += scrollY * (12 << mainWindow->viewport->zoom);
+ RCT2_GLOBAL(0x009DE518, uint32) |= (1 << 7);
+ }
+}
+
+#include
+
+void game_handle_key_scroll()
+{
+ rct_window *mainWindow;
+ int scrollX, scrollY;
+
+ mainWindow = window_get_main();
+ if (mainWindow == NULL)
+ return;
+ if ((mainWindow->flags & WF_2) || (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & 9))
+ return;
+ if (mainWindow->viewport == NULL)
+ return;
+
+ scrollX = 0;
+ scrollY = 0;
+
+ // Scroll left / right
+ if (gKeysState[SDL_SCANCODE_LEFT])
+ scrollX = -1;
+ else if (gKeysState[SDL_SCANCODE_RIGHT])
+ scrollX = 1;
+
+ // Scroll up / down
+ if (gKeysState[SDL_SCANCODE_UP])
+ scrollY = -1;
+ else if (gKeysState[SDL_SCANCODE_DOWN])
+ scrollY = 1;
+
+ // Scroll viewport
+ if (scrollX != 0) {
+ mainWindow->var_4B2 += scrollX * (12 << mainWindow->viewport->zoom);
+ RCT2_GLOBAL(0x009DE518, uint32) |= (1 << 7);
+ }
+ if (scrollY != 0) {
+ mainWindow->var_4B4 += scrollY * (12 << mainWindow->viewport->zoom);
+ RCT2_GLOBAL(0x009DE518, uint32) |= (1 << 7);
+ }
+}
+
+/**
+ *
+ * rct2: 0x00406CD2
+ */
+int get_next_key()
+{
+ int i;
+ for (i = 0; i < 221; i++) {
+ if (gKeysState[i]) {
+ gKeysState[i] = 0;
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ *
+ * rct2: 0x006E3E68
+ */
+void handle_shortcut(int key)
+{
+ int i;
+ for (i = 0; i < 32; i++) {
+ if (key == gShortcutKeys[i]) {
+ RCT2_CALLPROC_EBPSAFE(RCT2_ADDRESS(0x006E3FB4, uint32)[i]);
+ break;
+ }
+ }
+}
+
+/**
+ *
+ * rct2: 0x006E3E91
+ */
+void set_shortcut(int key)
+{
+ int i;
+
+ // Unmap shortcut that already uses this key
+ for (i = 0; i < 32; i++) {
+ if (key == gShortcutKeys[i]) {
+ gShortcutKeys[i] = 0xFFFF;
+ break;
+ }
+ }
+
+ // Map shortcut to this key
+ gShortcutKeys[RCT2_GLOBAL(0x009DE511, uint8)] = key;
+ window_close_by_id(WC_CHANGE_KEYBOARD_SHORTCUT, 0);
+ window_invalidate_by_id(WC_KEYBOARD_SHORTCUT_LIST, 0);
+ config_save();
+}
/**
*
@@ -769,5 +903,70 @@ static void input_leftmousedown(int x, int y, rct_window *w, int widgetIndex)
*/
void game_handle_keyboard_input()
{
- RCT2_CALLPROC_EBPSAFE(0x006E3B43);
+ rct_window *w;
+ int key, i;
+
+ // Handle mouse scrolling
+ if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) == 0)
+ if (RCT2_GLOBAL(0x009AACBA, uint8) != 0)
+ if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) == 1)
+ if (!(RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) & 3))
+ game_handle_edge_scroll();
+
+ // Handle modifier keys and key scrolling
+ RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) = 0;
+ if (RCT2_GLOBAL(0x009E2B64, uint32) != 1) {
+ if (gKeysState[SDL_SCANCODE_LSHIFT] || gKeysState[SDL_SCANCODE_RSHIFT])
+ RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) |= 1;
+ if (gKeysState[SDL_SCANCODE_LCTRL] || gKeysState[SDL_SCANCODE_RCTRL])
+ RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) |= 2;
+ if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) == 0)
+ game_handle_key_scroll();
+ }
+
+
+ // Handle key input
+ while ((key = get_next_key()) != 0) {
+ if (key == 255 || key == 0x10 || key == 0x11)
+ continue;
+
+ key |= RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) << 8;
+
+ w = window_find_by_id(WC_CHANGE_KEYBOARD_SHORTCUT, 0);
+ if (w != NULL)
+ set_shortcut(key);
+ else if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) == 1)
+ tutorial_stop();
+ else
+ handle_shortcut(key);
+ }
+
+ if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) == 0)
+ return;
+
+ // Tutorial and the modifier key
+ if (RCT2_GLOBAL(RCT2_ADDRESS_ON_TUTORIAL, uint8) == 1) {
+ int eax, ebx, ecx, edx, esi, edi, ebp;
+ RCT2_CALLFUNC_X(0x0066EEB4, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp);
+ eax &= 0xFF;
+ RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) = eax;
+ if (RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) & 4) {
+ window_tooltip_close();
+ if ((w = window_get_main()) != NULL) {
+ RCT2_CALLPROC_X(0x006EA2AA, 0, 0, 0, 0, w, RCT2_GLOBAL(0x009DEA72, uint16), 0);
+ RCT2_GLOBAL(0x009DEA72, uint16)++;
+ }
+ }
+ } else {
+ if (!(RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) & 4)) {
+ window_tooltip_close();
+ if ((w = window_get_main()) != NULL) {
+ RCT2_CALLPROC_X(0x006EA2AA, 0, 0, 0, 0, w, RCT2_GLOBAL(0x009DEA72, uint16), 0);
+ RCT2_GLOBAL(0x009DEA72, uint16)++;
+ }
+ }
+
+ // Write tutorial input
+ RCT2_CALLPROC_X(0x0066EEE1, RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8), 0, 0, 0, 0, 0, 0);
+ }
}
\ No newline at end of file
diff --git a/src/osinterface.c b/src/osinterface.c
index ac66460855..6c8418400d 100644
--- a/src/osinterface.c
+++ b/src/osinterface.c
@@ -30,7 +30,7 @@
typedef void(*update_palette_func)(char*, int, int);
openrct2_cursor gCursorState;
-const unsigned char* gKeysState;
+unsigned char* gKeysState;
unsigned int gLastKeyPressed;
static void osinterface_create_window();
@@ -265,13 +265,6 @@ void osinterface_process_messages()
// Updates the state of the keys
int numKeys = 256;
gKeysState = SDL_GetKeyboardState(&numKeys);
- // memcpy(0x01425C00, gKeysState, 256);
-
- RCT2_GLOBAL(0x009DEA70, uint8) = 0;
- if (gKeysState[SDL_SCANCODE_LSHIFT] || gKeysState[SDL_SCANCODE_RSHIFT])
- RCT2_GLOBAL(0x009DEA70, uint8) |= 1;
- if (gKeysState[SDL_SCANCODE_LCTRL] || gKeysState[SDL_SCANCODE_RCTRL])
- RCT2_GLOBAL(0x009DEA70, uint8) |= 2;
}
static void osinterface_close_window()
diff --git a/src/osinterface.h b/src/osinterface.h
index 4c0fed94ba..ee7e83505f 100644
--- a/src/osinterface.h
+++ b/src/osinterface.h
@@ -37,7 +37,7 @@ typedef struct {
} openrct2_cursor;
extern openrct2_cursor gCursorState;
-const extern unsigned char* gKeysState;
+extern unsigned char* gKeysState;
extern unsigned int gLastKeyPressed;
void osinterface_init();
diff --git a/src/rct2.c b/src/rct2.c
index 2f14daf7f9..b85514bfaa 100644
--- a/src/rct2.c
+++ b/src/rct2.c
@@ -107,7 +107,7 @@ void rct2_init()
RCT2_GLOBAL(0x009DEA6B, short) = RCT2_GLOBAL(0x01424304, short);
rct2_init_directories();
rct2_startup_checks();
- RCT2_CALLPROC_EBPSAFE(0x06E3604); // reset_keyboard_shortcuts()
+ config_reset_shortcut_keys();
RCT2_GLOBAL(RCT2_ADDRESS_PLACE_OBJECT_MODIFIER, uint8) = 0;
config_load();
// RCT2_CALLPROC_EBPSAFE(0x00674B81); // pointless expansion pack crap
diff --git a/src/tutorial.c b/src/tutorial.c
index 17fd8dd196..a7c6639c9c 100644
--- a/src/tutorial.c
+++ b/src/tutorial.c
@@ -29,3 +29,12 @@ void tutorial_start(int type)
{
RCT2_CALLPROC_X(0x0066ECC1, type, 0, 0, 0, 0, 0, 0);
}
+
+/**
+ *
+ * rct2: 0x0066EE25
+ */
+void tutorial_stop()
+{
+ RCT2_CALLPROC_EBPSAFE(0x0066EE25);
+}
\ No newline at end of file
diff --git a/src/tutorial.h b/src/tutorial.h
index 916da5fa33..a9db5b71db 100644
--- a/src/tutorial.h
+++ b/src/tutorial.h
@@ -22,5 +22,6 @@
#define _TUTORIAL_H_
void tutorial_start(int type);
+void tutorial_stop();
#endif
diff --git a/src/window.h b/src/window.h
index d6fe4e1928..f4b3d8de5c 100644
--- a/src/window.h
+++ b/src/window.h
@@ -188,6 +188,7 @@ typedef enum {
WF_STICK_TO_BACK = (1 << 0),
WF_STICK_TO_FRONT = (1 << 1),
+ WF_2 = (1 << 2),
WF_TRANSPARENT = (1 << 4),
WF_5 = (1 << 5),
WF_RESIZABLE = (1 << 8),