1 /***************************************************************************** 2 * Copyright (c) 2014-2020 OpenRCT2 developers 3 * 4 * For a complete list of all authors, please refer to contributors.md 5 * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 6 * 7 * OpenRCT2 is licensed under the GNU General Public License version 3. 8 *****************************************************************************/ 9 10 #pragma once 11 12 #ifdef ENABLE_SCRIPTING 13 14 # include "../interface/Window.h" 15 16 # include <memory> 17 # include <openrct2/Context.h> 18 # include <openrct2/common.h> 19 # include <openrct2/interface/Viewport.h> 20 # include <openrct2/scripting/Duktape.hpp> 21 # include <openrct2/scripting/ScriptEngine.h> 22 # include <openrct2/world/Map.h> 23 24 namespace OpenRCT2::Scripting 25 { 26 class ScViewport 27 { 28 private: 29 rct_windowclass _class{}; 30 rct_windownumber _number{}; 31 32 public: ScViewport(rct_windowclass c,rct_windownumber n=0)33 ScViewport(rct_windowclass c, rct_windownumber n = 0) 34 : _class(c) 35 , _number(n) 36 { 37 } 38 39 private: left_get() const40 int32_t left_get() const 41 { 42 auto viewport = GetViewport(); 43 if (viewport != nullptr) 44 { 45 return viewport->viewPos.x; 46 } 47 return 0; 48 } left_set(int32_t value)49 void left_set(int32_t value) 50 { 51 auto viewport = GetViewport(); 52 if (viewport != nullptr) 53 { 54 SetViewLeftTop(value, viewport->viewPos.y); 55 } 56 } 57 top_get() const58 int32_t top_get() const 59 { 60 auto viewport = GetViewport(); 61 if (viewport != nullptr) 62 { 63 return viewport->viewPos.y; 64 } 65 return 0; 66 } top_set(int32_t value)67 void top_set(int32_t value) 68 { 69 auto viewport = GetViewport(); 70 if (viewport != nullptr) 71 { 72 SetViewLeftTop(viewport->viewPos.x, value); 73 } 74 } 75 right_get() const76 int32_t right_get() const 77 { 78 auto viewport = GetViewport(); 79 if (viewport != nullptr) 80 { 81 return viewport->viewPos.x + viewport->view_width; 82 } 83 return 0; 84 } right_set(int32_t value)85 void right_set(int32_t value) 86 { 87 auto viewport = GetViewport(); 88 if (viewport != nullptr) 89 { 90 SetViewLeftTop(value - viewport->view_width, viewport->viewPos.y); 91 } 92 } 93 bottom_get() const94 int32_t bottom_get() const 95 { 96 auto viewport = GetViewport(); 97 if (viewport != nullptr) 98 { 99 return viewport->viewPos.y + viewport->view_height; 100 } 101 return 0; 102 } bottom_set(int32_t value)103 void bottom_set(int32_t value) 104 { 105 auto viewport = GetViewport(); 106 if (viewport != nullptr) 107 { 108 SetViewLeftTop(viewport->viewPos.x, value - viewport->view_height); 109 } 110 } 111 rotation_get() const112 int32_t rotation_get() const 113 { 114 return get_current_rotation(); 115 } rotation_set(int32_t value)116 void rotation_set(int32_t value) 117 { 118 if (value >= 0 && value < 4) 119 { 120 auto w = GetWindow(); 121 if (w != nullptr) 122 { 123 while (get_current_rotation() != value) 124 { 125 window_rotate_camera(w, 1); 126 } 127 } 128 } 129 } 130 zoom_get() const131 int32_t zoom_get() const 132 { 133 auto viewport = GetViewport(); 134 if (viewport != nullptr) 135 { 136 return static_cast<int8_t>(viewport->zoom); 137 } 138 return 0; 139 } zoom_set(int32_t value)140 void zoom_set(int32_t value) 141 { 142 auto w = GetWindow(); 143 if (w != nullptr) 144 { 145 window_zoom_set(w, value, false); 146 } 147 } 148 visibilityFlags_get() const149 uint32_t visibilityFlags_get() const 150 { 151 auto viewport = GetViewport(); 152 if (viewport != nullptr) 153 { 154 return viewport->flags; 155 } 156 return 0; 157 } visibilityFlags_set(uint32_t value)158 void visibilityFlags_set(uint32_t value) 159 { 160 auto w = GetWindow(); 161 if (w != nullptr) 162 { 163 auto viewport = w->viewport; 164 if (viewport != nullptr) 165 { 166 if (viewport->flags != value) 167 { 168 viewport->flags = value; 169 w->Invalidate(); 170 } 171 } 172 } 173 } 174 getCentrePosition() const175 DukValue getCentrePosition() const 176 { 177 auto viewport = GetViewport(); 178 if (viewport != nullptr) 179 { 180 auto centre = viewport->viewPos + ScreenCoordsXY{ viewport->view_width / 2, viewport->view_height / 2 }; 181 auto coords = viewport_coord_to_map_coord(centre, 24); 182 183 auto ctx = GetContext()->GetScriptEngine().GetContext(); 184 auto obj = duk_push_object(ctx); 185 duk_push_number(ctx, coords.x); 186 duk_put_prop_string(ctx, obj, "x"); 187 duk_push_number(ctx, coords.y); 188 duk_put_prop_string(ctx, obj, "y"); 189 return DukValue::take_from_stack(ctx); 190 } 191 return {}; 192 } 193 moveTo(DukValue position)194 void moveTo(DukValue position) 195 { 196 auto w = GetWindow(); 197 if (w != nullptr) 198 { 199 auto viewport = w->viewport; 200 if (viewport != nullptr) 201 { 202 auto coords = GetCoordsFromObject(position); 203 if (coords) 204 { 205 auto screenCoords = translate_3d_to_2d_with_z(get_current_rotation(), *coords); 206 auto left = screenCoords.x - (viewport->view_width / 2); 207 auto top = screenCoords.y - (viewport->view_height / 2); 208 SetViewLeftTop(left, top); 209 } 210 } 211 } 212 } 213 scrollTo(DukValue position)214 void scrollTo(DukValue position) 215 { 216 auto w = GetWindow(); 217 if (w != nullptr) 218 { 219 auto coords = GetCoordsFromObject(position); 220 if (coords) 221 { 222 window_scroll_to_location(w, *coords); 223 } 224 } 225 } 226 227 public: Register(duk_context * ctx)228 static void Register(duk_context* ctx) 229 { 230 dukglue_register_property(ctx, &ScViewport::left_get, &ScViewport::left_set, "left"); 231 dukglue_register_property(ctx, &ScViewport::top_get, &ScViewport::top_set, "top"); 232 dukglue_register_property(ctx, &ScViewport::right_get, &ScViewport::right_set, "right"); 233 dukglue_register_property(ctx, &ScViewport::bottom_get, &ScViewport::bottom_set, "bottom"); 234 dukglue_register_property(ctx, &ScViewport::rotation_get, &ScViewport::rotation_set, "rotation"); 235 dukglue_register_property(ctx, &ScViewport::zoom_get, &ScViewport::zoom_set, "zoom"); 236 dukglue_register_property( 237 ctx, &ScViewport::visibilityFlags_get, &ScViewport::visibilityFlags_set, "visibilityFlags"); 238 dukglue_register_method(ctx, &ScViewport::getCentrePosition, "getCentrePosition"); 239 dukglue_register_method(ctx, &ScViewport::moveTo, "moveTo"); 240 dukglue_register_method(ctx, &ScViewport::scrollTo, "scrollTo"); 241 } 242 243 private: GetWindow() const244 rct_window* GetWindow() const 245 { 246 if (_class == WC_MAIN_WINDOW) 247 return window_get_main(); 248 249 return window_find_by_number(_class, _number); 250 } 251 GetViewport() const252 rct_viewport* GetViewport() const 253 { 254 auto w = GetWindow(); 255 if (w != nullptr) 256 { 257 return w->viewport; 258 } 259 return nullptr; 260 } 261 SetViewLeftTop(int32_t left,int32_t top)262 void SetViewLeftTop(int32_t left, int32_t top) 263 { 264 auto w = GetWindow(); 265 if (w != nullptr) 266 { 267 auto viewport = w->viewport; 268 if (viewport != nullptr) 269 { 270 viewport->viewPos.x = left; 271 viewport->viewPos.y = top; 272 viewport->flags &= ~WF_SCROLLING_TO_LOCATION; 273 w->savedViewPos.x = viewport->viewPos.x; 274 w->savedViewPos.y = viewport->viewPos.y; 275 viewport->Invalidate(); 276 } 277 } 278 } 279 GetCoordsFromObject(DukValue position) const280 std::optional<CoordsXYZ> GetCoordsFromObject(DukValue position) const 281 { 282 if (position.type() == DukValue::Type::OBJECT) 283 { 284 auto dukX = position["x"]; 285 auto dukY = position["y"]; 286 auto dukZ = position["z"]; 287 if (dukX.type() == DukValue::Type::NUMBER && dukY.type() == DukValue::Type::NUMBER) 288 { 289 auto x = dukX.as_int(); 290 auto y = dukY.as_int(); 291 if (dukZ.type() == DukValue::Type::NUMBER) 292 { 293 return CoordsXYZ(x, y, dukZ.as_int()); 294 } 295 296 auto z = tile_element_height(CoordsXY(x, y)); 297 return CoordsXYZ(x, y, z); 298 } 299 } 300 return std::nullopt; 301 } 302 }; 303 } // namespace OpenRCT2::Scripting 304 305 #endif 306