OpenRCT2/src/openrct2-ui/scripting/ScViewport.hpp

307 lines
9.3 KiB
C++

/*****************************************************************************
* Copyright (c) 2014-2024 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
#ifdef ENABLE_SCRIPTING
# include "../interface/Window.h"
# include <memory>
# include <openrct2/Context.h>
# include <openrct2/common.h>
# include <openrct2/interface/Viewport.h>
# include <openrct2/scripting/Duktape.hpp>
# include <openrct2/scripting/ScriptEngine.h>
# include <openrct2/world/Map.h>
namespace OpenRCT2::Scripting
{
class ScViewport
{
private:
WindowClass _class{};
rct_windownumber _number{};
public:
ScViewport(WindowClass c, rct_windownumber n = 0)
: _class(c)
, _number(n)
{
}
private:
int32_t left_get() const
{
auto viewport = GetViewport();
if (viewport != nullptr)
{
return viewport->viewPos.x;
}
return 0;
}
void left_set(int32_t value)
{
auto viewport = GetViewport();
if (viewport != nullptr)
{
SetViewLeftTop(value, viewport->viewPos.y);
}
}
int32_t top_get() const
{
auto viewport = GetViewport();
if (viewport != nullptr)
{
return viewport->viewPos.y;
}
return 0;
}
void top_set(int32_t value)
{
auto viewport = GetViewport();
if (viewport != nullptr)
{
SetViewLeftTop(viewport->viewPos.x, value);
}
}
int32_t right_get() const
{
auto viewport = GetViewport();
if (viewport != nullptr)
{
return viewport->viewPos.x + viewport->view_width;
}
return 0;
}
void right_set(int32_t value)
{
auto viewport = GetViewport();
if (viewport != nullptr)
{
SetViewLeftTop(value - viewport->view_width, viewport->viewPos.y);
}
}
int32_t bottom_get() const
{
auto viewport = GetViewport();
if (viewport != nullptr)
{
return viewport->viewPos.y + viewport->view_height;
}
return 0;
}
void bottom_set(int32_t value)
{
auto viewport = GetViewport();
if (viewport != nullptr)
{
SetViewLeftTop(viewport->viewPos.x, value - viewport->view_height);
}
}
int32_t rotation_get() const
{
return GetCurrentRotation();
}
void rotation_set(int32_t value)
{
if (value >= 0 && value < 4)
{
auto w = GetWindow();
if (w != nullptr)
{
while (GetCurrentRotation() != value)
{
WindowRotateCamera(*w, 1);
}
}
}
}
int32_t zoom_get() const
{
auto viewport = GetViewport();
if (viewport != nullptr)
{
return static_cast<int8_t>(viewport->zoom);
}
return 0;
}
void zoom_set(int32_t value)
{
auto w = GetWindow();
if (w != nullptr)
{
auto i8Value = static_cast<int8_t>(value);
WindowZoomSet(*w, ZoomLevel{ i8Value }, false);
}
}
uint32_t visibilityFlags_get() const
{
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() const
{
auto viewport = GetViewport();
if (viewport != nullptr)
{
auto centre = viewport->viewPos + ScreenCoordsXY{ viewport->view_width / 2, viewport->view_height / 2 };
auto coords = ViewportPosToMapPos(centre, 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 = Translate3DTo2DWithZ(GetCurrentRotation(), *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)
{
WindowScrollToLocation(*w, *coords);
}
}
}
public:
static void Register(duk_context* ctx)
{
dukglue_register_property(ctx, &ScViewport::left_get, &ScViewport::left_set, "left");
dukglue_register_property(ctx, &ScViewport::top_get, &ScViewport::top_set, "top");
dukglue_register_property(ctx, &ScViewport::right_get, &ScViewport::right_set, "right");
dukglue_register_property(ctx, &ScViewport::bottom_get, &ScViewport::bottom_set, "bottom");
dukglue_register_property(ctx, &ScViewport::rotation_get, &ScViewport::rotation_set, "rotation");
dukglue_register_property(ctx, &ScViewport::zoom_get, &ScViewport::zoom_set, "zoom");
dukglue_register_property(
ctx, &ScViewport::visibilityFlags_get, &ScViewport::visibilityFlags_set, "visibilityFlags");
dukglue_register_method(ctx, &ScViewport::getCentrePosition, "getCentrePosition");
dukglue_register_method(ctx, &ScViewport::moveTo, "moveTo");
dukglue_register_method(ctx, &ScViewport::scrollTo, "scrollTo");
}
private:
WindowBase* GetWindow() const
{
if (_class == WindowClass::MainWindow)
return WindowGetMain();
return WindowFindByNumber(_class, _number);
}
Viewport* GetViewport() const
{
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->viewPos.x = left;
viewport->viewPos.y = top;
viewport->flags &= ~WF_SCROLLING_TO_LOCATION;
w->savedViewPos.x = viewport->viewPos.x;
w->savedViewPos.y = viewport->viewPos.y;
viewport->Invalidate();
}
}
}
std::optional<CoordsXYZ> GetCoordsFromObject(DukValue position) const
{
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());
}
auto z = TileElementHeight(CoordsXY(x, y));
return CoordsXYZ(x, y, z);
}
}
return std::nullopt;
}
};
} // namespace OpenRCT2::Scripting
#endif