diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index 37950a3523..2093d931bd 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -442,7 +442,11 @@ export interface ToolDesc { callback: (e: ToolCallback) => void; } -export interface ViewportInfo { +export interface Viewport { + left: number; + top: number; + right: number; + bottom: number; rotation: number; zoom: number; visibilityFlags: number; @@ -456,7 +460,7 @@ export interface Ui { readonly width: number; readonly height: number; readonly windows: number; - readonly mainViewport: ViewportInfo; + readonly mainViewport: Viewport; getWindow(id: number): Window; getWindow(classification: string, id?: number): Window; diff --git a/src/openrct2-ui/scripting/ScUi.hpp b/src/openrct2-ui/scripting/ScUi.hpp index cd47708af6..fdedf11ae2 100644 --- a/src/openrct2-ui/scripting/ScUi.hpp +++ b/src/openrct2-ui/scripting/ScUi.hpp @@ -10,6 +10,7 @@ #pragma once #include "CustomMenu.h" +#include "ScViewport.hpp" #include "ScWindow.hpp" #include @@ -42,6 +43,7 @@ namespace OpenRCT2::Scripting { } + private: int32_t width_get() { return context_get_width(); @@ -55,6 +57,11 @@ namespace OpenRCT2::Scripting return static_cast(g_window_list.size()); } + std::shared_ptr mainViewport_get() + { + return std::make_shared(WC_MAIN_WINDOW); + } + std::shared_ptr openWindow(DukValue desc) { using namespace OpenRCT2::Ui::Windows; @@ -113,11 +120,13 @@ namespace OpenRCT2::Scripting CustomMenuItems.emplace_back(owner, text, callback); } + public: static void Register(duk_context* ctx) { dukglue_register_property(ctx, &ScUi::height_get, nullptr, "height"); dukglue_register_property(ctx, &ScUi::width_get, nullptr, "width"); dukglue_register_property(ctx, &ScUi::windows_get, nullptr, "windows"); + dukglue_register_property(ctx, &ScUi::mainViewport_get, nullptr, "mainViewport"); dukglue_register_method(ctx, &ScUi::openWindow, "openWindow"); dukglue_register_method(ctx, &ScUi::closeWindows, "closeWindows"); dukglue_register_method(ctx, &ScUi::closeAllWindows, "closeAllWindows"); diff --git a/src/openrct2-ui/scripting/ScViewport.hpp b/src/openrct2-ui/scripting/ScViewport.hpp new file mode 100644 index 0000000000..f7a94d08fc --- /dev/null +++ b/src/openrct2-ui/scripting/ScViewport.hpp @@ -0,0 +1,302 @@ +/***************************************************************************** + * Copyright (c) 2014-2018 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include "../interface/Window.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace OpenRCT2::Scripting +{ + class ScViewport + { + private: + rct_windowclass _class{}; + rct_windownumber _number{}; + + public: + ScViewport(rct_windowclass c, rct_windownumber n = 0) + : _class(c) + , _number(n) + { + } + + private: + int32_t left_get() + { + auto viewport = GetViewport(); + if (viewport != nullptr) + { + return viewport->view_x; + } + return 0; + } + void left_set(int32_t value) + { + auto viewport = GetViewport(); + if (viewport != nullptr) + { + SetViewLeftTop(value, viewport->view_y); + } + } + + int32_t top_get() + { + auto viewport = GetViewport(); + if (viewport != nullptr) + { + return viewport->view_y; + } + return 0; + } + void top_set(int32_t value) + { + auto viewport = GetViewport(); + if (viewport != nullptr) + { + SetViewLeftTop(viewport->view_x, value); + } + } + + int32_t right_get() + { + auto viewport = GetViewport(); + if (viewport != nullptr) + { + return viewport->view_x + viewport->view_width; + } + return 0; + } + void right_set(int32_t value) + { + auto viewport = GetViewport(); + if (viewport != nullptr) + { + SetViewLeftTop(value - viewport->view_width, viewport->view_y); + } + } + + int32_t bottom_get() + { + auto viewport = GetViewport(); + if (viewport != nullptr) + { + return viewport->view_y + viewport->view_height; + } + return 0; + } + void bottom_set(int32_t value) + { + auto viewport = GetViewport(); + if (viewport != nullptr) + { + SetViewLeftTop(viewport->view_x, value - viewport->view_height); + } + } + + int32_t rotation_get() + { + return get_current_rotation(); + } + void rotation_set(int32_t value) + { + if (value >= 0 && value < 4) + { + auto w = GetWindow(); + if (w != nullptr) + { + while (get_current_rotation() != value) + { + window_rotate_camera(w, 1); + } + } + } + } + + int32_t zoom_get() + { + auto viewport = GetViewport(); + if (viewport != nullptr) + { + return viewport->zoom; + } + return 0; + } + void zoom_set(int32_t value) + { + auto w = GetWindow(); + if (w != nullptr) + { + window_zoom_set(w, value, false); + } + } + + uint32_t visibilityFlags_get() + { + auto viewport = GetViewport(); + if (viewport != nullptr) + { + return viewport->flags; + } + return 0; + } + void visibilityFlags_set(uint32_t value) + { + auto w = GetWindow(); + if (w != nullptr) + { + auto viewport = w->viewport; + if (viewport != nullptr) + { + if (viewport->flags != value) + { + viewport->flags = value; + w->Invalidate(); + } + } + } + } + + DukValue getCentrePosition() + { + auto viewport = GetViewport(); + if (viewport != nullptr) + { + auto centreX = viewport->view_x + (viewport->view_width / 2); + auto centreY = viewport->view_y + (viewport->view_height / 2); + auto coords = viewport_coord_to_map_coord(centreX, centreY, 24); + + auto ctx = GetContext()->GetScriptEngine().GetContext(); + auto obj = duk_push_object(ctx); + duk_push_number(ctx, coords.x); + duk_put_prop_string(ctx, obj, "x"); + duk_push_number(ctx, coords.y); + duk_put_prop_string(ctx, obj, "y"); + return DukValue::take_from_stack(ctx); + } + return {}; + } + + void moveTo(DukValue position) + { + auto w = GetWindow(); + if (w != nullptr) + { + auto viewport = w->viewport; + if (viewport != nullptr) + { + auto coords = GetCoordsFromObject(position); + if (coords) + { + auto screenCoords = translate_3d_to_2d_with_z(get_current_rotation(), *coords); + auto left = screenCoords.x - (viewport->view_width / 2); + auto top = screenCoords.y - (viewport->view_height / 2); + SetViewLeftTop(left, top); + } + } + } + } + + void scrollTo(DukValue position) + { + auto w = GetWindow(); + if (w != nullptr) + { + auto coords = GetCoordsFromObject(position); + if (coords) + { + window_scroll_to_location(w, coords->x, coords->y, coords->z); + } + } + } + + public: + static void Register(duk_context* ctx) + { + dukglue_register_property(ctx, &left_get, &left_set, "left"); + dukglue_register_property(ctx, &top_get, &top_set, "top"); + dukglue_register_property(ctx, &right_get, &right_set, "right"); + dukglue_register_property(ctx, &bottom_get, &bottom_set, "bottom"); + dukglue_register_property(ctx, &rotation_get, &rotation_set, "rotation"); + dukglue_register_property(ctx, &zoom_get, &zoom_set, "zoom"); + dukglue_register_property(ctx, &visibilityFlags_get, &visibilityFlags_set, "visibilityFlags"); + dukglue_register_method(ctx, &getCentrePosition, "getCentrePosition"); + dukglue_register_method(ctx, &moveTo, "moveTo"); + dukglue_register_method(ctx, &scrollTo, "scrollTo"); + } + + private: + rct_window* GetWindow() + { + if (_class == WC_MAIN_WINDOW) + return window_get_main(); + else + return window_find_by_number(_class, _number); + } + + rct_viewport* GetViewport() + { + auto w = GetWindow(); + if (w != nullptr) + { + return w->viewport; + } + return nullptr; + } + + void SetViewLeftTop(int32_t left, int32_t top) + { + auto w = GetWindow(); + if (w != nullptr) + { + auto viewport = w->viewport; + if (viewport != nullptr) + { + viewport->view_x = left; + viewport->view_y = top; + viewport->flags &= ~WF_SCROLLING_TO_LOCATION; + w->saved_view_x = viewport->view_x; + w->saved_view_y = viewport->view_y; + } + } + } + + std::optional GetCoordsFromObject(DukValue position) + { + if (position.type() == DukValue::Type::OBJECT) + { + auto dukX = position["x"]; + auto dukY = position["y"]; + auto dukZ = position["z"]; + if (dukX.type() == DukValue::Type::NUMBER && dukY.type() == DukValue::Type::NUMBER) + { + auto x = dukX.as_int(); + auto y = dukY.as_int(); + if (dukZ.type() == DukValue::Type::NUMBER) + { + return CoordsXYZ(x, y, dukZ.as_int()); + } + else + { + auto z = tile_element_height(CoordsXY(x, y)); + return CoordsXYZ(x, y, z); + } + } + } + return {}; + } + }; +} // namespace OpenRCT2::Scripting diff --git a/src/openrct2-ui/scripting/UiExtensions.cpp b/src/openrct2-ui/scripting/UiExtensions.cpp index 84b23901f2..c2c959bb6f 100644 --- a/src/openrct2-ui/scripting/UiExtensions.cpp +++ b/src/openrct2-ui/scripting/UiExtensions.cpp @@ -24,6 +24,7 @@ void UiScriptExtensions::Extend(ScriptEngine& scriptEngine) dukglue_register_global(ctx, std::make_shared(scriptEngine), "ui"); ScUi::Register(ctx); + ScViewport::Register(ctx); ScWindow::Register(ctx); InitialiseCustomMenuItems(scriptEngine);