diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 84168baf09..81e8b15d5b 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -22,7 +22,9 @@ - Feature: Allow using object files from RCT Classic. - Feature: Title sequences now testable in-game. - Fix: [#816] In the map window, there are more peeps flickering than there are selected (original bug). +- Fix: [#996, #2589, #2875] Viewport scrolling no longer shakes or gets stuck. - Fix: [#1833, #4937, #6138] 'Too low!' warning when building rides and shops on the lowest land level (original bug). +- Fix: [#2254] Edge scrolling horizontally now has the same speed as vertical edge scrolling. - Fix: [#6199] Inverted Hairpin Coaster vehicle tab is not centred. - Fix: [#4991] Inverted helices can be built on the Lay Down RC, but are not drawn. - Fix: [#5417] Hacked Crooked House tracked rides do not dispatch vehicles. diff --git a/src/openrct2-ui/input/Input.cpp b/src/openrct2-ui/input/Input.cpp index cce25a0e1c..30f0d16345 100644 --- a/src/openrct2-ui/input/Input.cpp +++ b/src/openrct2-ui/input/Input.cpp @@ -101,17 +101,7 @@ static void game_handle_key_scroll() const uint8 * keysState = context_get_keys_state(); get_keyboard_map_scroll(keysState, &scrollX, &scrollY); - // Scroll viewport - if (scrollX != 0) - { - mainWindow->saved_view_x += scrollX * (12 << mainWindow->viewport->zoom); - input_set_flag(INPUT_FLAG_VIEWPORT_SCROLLING, true); - } - if (scrollY != 0) - { - mainWindow->saved_view_y += scrollY * (12 << mainWindow->viewport->zoom); - input_set_flag(INPUT_FLAG_VIEWPORT_SCROLLING, true); - } + input_scroll_viewport(scrollX, scrollY); } static sint32 input_scancode_to_rct_keycode(sint32 sdl_key) diff --git a/src/openrct2/input.c b/src/openrct2/input.c index 2b488cb286..0b8e472bac 100644 --- a/src/openrct2/input.c +++ b/src/openrct2/input.c @@ -1508,15 +1508,7 @@ void game_handle_edge_scroll() else if (cursorState->y >= context_get_height() - 1) scrollY = 1; - // Scroll viewport - if (scrollX != 0) { - mainWindow->saved_view_x += scrollX * (12 << mainWindow->viewport->zoom); - _inputFlags |= INPUT_FLAG_VIEWPORT_SCROLLING; - } - if (scrollY != 0) { - mainWindow->saved_view_y += scrollY * (12 << mainWindow->viewport->zoom); - _inputFlags |= INPUT_FLAG_VIEWPORT_SCROLLING; - } + input_scroll_viewport(scrollX, scrollY); } void input_set_flag(INPUT_FLAGS flag, bool on) @@ -1562,3 +1554,62 @@ bool input_test_place_object_modifier(PLACE_OBJECT_MODIFIER modifier) { return gInputPlaceObjectModifier & modifier; } + +void input_scroll_viewport(sint32 scrollX, sint32 scrollY) +{ + rct_window * mainWindow = window_get_main(); + rct_viewport * viewport = mainWindow->viewport; + + sint32 dx = scrollX * (12 << viewport->zoom); + sint32 dy = scrollY * (12 << viewport->zoom); + + if (scrollX != 0) + { + // Speed up scrolling horizontally when at the edge of the map + // so that the speed is consistent with vertical edge scrolling. + sint32 x = mainWindow->saved_view_x + viewport->view_width / 2 + dx; + sint32 y = mainWindow->saved_view_y + viewport->view_height / 2; + sint32 y_dy = mainWindow->saved_view_y + viewport->view_height / 2 + dy; + LocationXY16 mapCoord, mapCoord_dy; + + mapCoord = viewport_coord_to_map_coord(x, y, 0); + mapCoord_dy = viewport_coord_to_map_coord(x, y_dy, 0); + + // Check if we're crossing the boundary + // Clamp to the map minimum value + sint32 at_map_edge = 0; + sint32 at_map_edge_dy = 0; + if (mapCoord.x < MAP_MINIMUM_X_Y || mapCoord.y < MAP_MINIMUM_X_Y) + { + at_map_edge = 1; + } + if (mapCoord_dy.x < MAP_MINIMUM_X_Y || mapCoord_dy.y < MAP_MINIMUM_X_Y) + { + at_map_edge_dy = 1; + } + + // Clamp to the map maximum value (scenario specific) + if (mapCoord.x > gMapSizeMinus2 || mapCoord.y > gMapSizeMinus2) + { + at_map_edge = 1; + } + if (mapCoord_dy.x > gMapSizeMinus2 || mapCoord_dy.y > gMapSizeMinus2) + { + at_map_edge_dy = 1; + } + + // If we crossed the boundary, multiply the distance by 2 + if (at_map_edge && at_map_edge_dy) + { + dx *= 2; + } + + mainWindow->saved_view_x += dx; + _inputFlags |= INPUT_FLAG_VIEWPORT_SCROLLING; + } + if (scrollY != 0) + { + mainWindow->saved_view_y += dy; + _inputFlags |= INPUT_FLAG_VIEWPORT_SCROLLING; + } +} diff --git a/src/openrct2/input.h b/src/openrct2/input.h index 985979a612..e3b3c5370d 100644 --- a/src/openrct2/input.h +++ b/src/openrct2/input.h @@ -119,6 +119,8 @@ void reset_tooltip_not_shown(); void input_reset_place_obj_modifier(); +void input_scroll_viewport(sint32 scrollX, sint32 scrollY); + #ifdef __cplusplus } #endif diff --git a/src/openrct2/interface/viewport.c b/src/openrct2/interface/viewport.c index 53d61c5892..af31f381b9 100644 --- a/src/openrct2/interface/viewport.c +++ b/src/openrct2/interface/viewport.c @@ -510,73 +510,76 @@ static void viewport_set_underground_flag(sint32 underground, rct_window* window * * rct2: 0x006E7A3A */ -void viewport_update_position(rct_window *window) +void viewport_update_position(rct_window * window) { window_event_resize_call(window); - rct_viewport* viewport = window->viewport; - if (!viewport)return; + rct_viewport * viewport = window->viewport; + if (!viewport) return; - if (window->viewport_target_sprite != SPRITE_INDEX_NULL) { + if (window->viewport_target_sprite != SPRITE_INDEX_NULL) + { viewport_update_sprite_follow(window); return; } - sint16 x = viewport->view_width / 2 + window->saved_view_x; - sint16 y = viewport->view_height / 2 + window->saved_view_y; - sint16 z; - - viewport_adjust_for_map_height(&x, &y, &z); - viewport_set_underground_flag(0, window, viewport); - //Clamp to the map minimum value - sint32 at_map_edge_x = 0; - if (x < MAP_MINIMUM_X_Y){ - x = MAP_MINIMUM_X_Y; - at_map_edge_x = 1; + sint16 x = window->saved_view_x + viewport->view_width / 2; + sint16 y = window->saved_view_y + viewport->view_height / 2; + LocationXY16 mapCoord; + + mapCoord = viewport_coord_to_map_coord(x, y, 0); + + // Clamp to the map minimum value + sint32 at_map_edge = 0; + if (mapCoord.x < MAP_MINIMUM_X_Y) + { + mapCoord.x = MAP_MINIMUM_X_Y; + at_map_edge = 1; } - sint32 at_map_edge_y = 0; - if (y < MAP_MINIMUM_X_Y){ - y = MAP_MINIMUM_X_Y; - at_map_edge_y = 1; + if (mapCoord.y < MAP_MINIMUM_X_Y) + { + mapCoord.y = MAP_MINIMUM_X_Y; + at_map_edge = 1; } - //Clamp to the map maximum value (scenario specific) - if (x > gMapSizeMinus2){ - x = gMapSizeMinus2; - at_map_edge_x = 1; + // Clamp to the map maximum value (scenario specific) + if (mapCoord.x > gMapSizeMinus2) + { + mapCoord.x = gMapSizeMinus2; + at_map_edge = 1; } - if (y > gMapSizeMinus2){ - y = gMapSizeMinus2; - at_map_edge_y = 1; + if (mapCoord.y > gMapSizeMinus2) + { + mapCoord.y = gMapSizeMinus2; + at_map_edge = 1; } - if (at_map_edge_x || at_map_edge_y) { - // The &0xFFFF is to prevent the sign extension messing the - // function up. - sint32 zz = tile_element_height(x & 0xFFFF, y & 0xFFFF); + if (at_map_edge) + { sint32 _2d_x, _2d_y; - centre_2d_coordinates(x, y, zz, &_2d_x, &_2d_y, viewport); + centre_2d_coordinates(mapCoord.x, mapCoord.y, 0, &_2d_x, &_2d_y, viewport); - if (at_map_edge_x) - window->saved_view_x = _2d_x; - if (at_map_edge_y) - window->saved_view_y = _2d_y; + window->saved_view_x = _2d_x; + window->saved_view_y = _2d_y; } x = window->saved_view_x; y = window->saved_view_y; - if (window->flags & WF_SCROLLING_TO_LOCATION){ + if (window->flags & WF_SCROLLING_TO_LOCATION) + { // Moves the viewport if focusing in on an item uint8 flags = 0; x -= viewport->view_x; - if (x < 0){ + if (x < 0) + { x = -x; flags |= 1; } y -= viewport->view_y; - if (y < 0){ + if (y < 0) + { y = -y; flags |= 2; } @@ -584,13 +587,16 @@ void viewport_update_position(rct_window *window) y = (y + 7) / 8; //If we are at the final zoom position - if (!x && !y){ + if (!x && !y) + { window->flags &= ~WF_SCROLLING_TO_LOCATION; } - if (flags & 1){ + if (flags & 1) + { x = -x; } - if (flags & 2){ + if (flags & 2) + { y = -y; } x += viewport->view_x;