mirror of https://github.com/OpenRCT2/OpenRCT2.git
Merge pull request #11580 from IntelOrca/plugin/custom-tool
[Plugin] Implement custom tool API
This commit is contained in:
commit
1f7ef019fc
|
@ -53,11 +53,19 @@ declare global {
|
|||
dispose(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* A coordinate within the game's client screen in pixels.
|
||||
*/
|
||||
interface ScreenCoordsXY {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* A coordinate within the game.
|
||||
* Each in-game tile is a size of 32x32.
|
||||
*/
|
||||
interface Coord2 {
|
||||
interface CoordsXY {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
@ -67,10 +75,18 @@ declare global {
|
|||
* Each in-game tile is a size of 32x32.
|
||||
* The z-coordinate raises 16 per land increment. A full-height wall is 32 in height.
|
||||
*/
|
||||
interface Coord3 extends Coord2 {
|
||||
interface CoordsXYZ extends CoordsXY {
|
||||
z: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* A rectangular area specified using two coordinates.
|
||||
*/
|
||||
interface MapRange {
|
||||
leftTop: CoordsXY;
|
||||
rightBottom: CoordsXY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents information about the plugin such as type, name, author and version.
|
||||
* It also includes the entry point.
|
||||
|
@ -245,7 +261,7 @@ declare global {
|
|||
error?: number;
|
||||
errorTitle?: string;
|
||||
errorMessage?: string;
|
||||
position?: Coord3;
|
||||
position?: CoordsXYZ;
|
||||
cost?: number;
|
||||
expenditureType?: ExpenditureType;
|
||||
}
|
||||
|
@ -328,7 +344,7 @@ declare global {
|
|||
* APIs for the map.
|
||||
*/
|
||||
interface GameMap {
|
||||
readonly size: Coord2;
|
||||
readonly size: CoordsXY;
|
||||
readonly numRides: number;
|
||||
readonly numEntities: number;
|
||||
readonly rides: Ride[];
|
||||
|
@ -710,6 +726,8 @@ declare global {
|
|||
readonly height: number;
|
||||
readonly windows: number;
|
||||
readonly mainViewport: Viewport;
|
||||
readonly tileSelection: TileSelection;
|
||||
readonly tool: Tool;
|
||||
|
||||
getWindow(id: number): Window;
|
||||
getWindow(classification: string): Window;
|
||||
|
@ -717,9 +735,79 @@ declare global {
|
|||
closeWindows(classification: string, id?: number): void;
|
||||
closeAllWindows(): void;
|
||||
|
||||
/**
|
||||
* Begins a new tool session. The cursor will change to the style specified by the
|
||||
* given tool descriptor and cursor events will be provided.
|
||||
* @param tool The properties and event handlers for the tool.
|
||||
*/
|
||||
activateTool(tool: ToolDesc): void;
|
||||
|
||||
registerMenuItem(text: string, callback: () => void): void;
|
||||
}
|
||||
|
||||
interface TileSelection {
|
||||
range: MapRange;
|
||||
tiles: CoordsXY[];
|
||||
}
|
||||
|
||||
interface Tool {
|
||||
id: string;
|
||||
cursor: CursorType;
|
||||
|
||||
cancel: () => void;
|
||||
}
|
||||
|
||||
interface ToolEventArgs {
|
||||
readonly isDown: boolean;
|
||||
readonly screenCoords: ScreenCoordsXY;
|
||||
readonly mapCoords?: CoordsXYZ;
|
||||
readonly tileElementIndex?: number;
|
||||
readonly entityId?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the properties and event handlers for a custom tool.
|
||||
*/
|
||||
interface ToolDesc {
|
||||
id: string;
|
||||
cursor?: CursorType;
|
||||
|
||||
onStart: () => void;
|
||||
onDown: (e: ToolEventArgs) => void;
|
||||
onMove: (e: ToolEventArgs) => void;
|
||||
onUp: (e: ToolEventArgs) => void;
|
||||
onFinish: () => void;
|
||||
}
|
||||
|
||||
type CursorType =
|
||||
"arrow" |
|
||||
"bench_down" |
|
||||
"bin_down" |
|
||||
"blank" |
|
||||
"cross_hair" |
|
||||
"diagonal_arrows" |
|
||||
"dig_down" |
|
||||
"entrance_down" |
|
||||
"fence_down" |
|
||||
"flower_down" |
|
||||
"fountain_down" |
|
||||
"hand_closed" |
|
||||
"hand_open" |
|
||||
"hand_point" |
|
||||
"house_down" |
|
||||
"lamppost_down" |
|
||||
"paint_down" |
|
||||
"path_down" |
|
||||
"picker" |
|
||||
"statue_down" |
|
||||
"tree_down" |
|
||||
"up_arrow" |
|
||||
"up_down_arrow" |
|
||||
"volcano_down" |
|
||||
"walk_down" |
|
||||
"water_down" |
|
||||
"zzz";
|
||||
|
||||
/**
|
||||
* Represents the type of a widget, e.g. button or label.
|
||||
*/
|
||||
|
@ -822,7 +910,7 @@ declare global {
|
|||
frameBase: number;
|
||||
frameCount?: number;
|
||||
frameDuration?: number;
|
||||
offset?: Coord2;
|
||||
offset?: ScreenCoordsXY;
|
||||
}
|
||||
|
||||
interface WindowTabDesc {
|
||||
|
@ -839,8 +927,8 @@ declare global {
|
|||
zoom: number;
|
||||
visibilityFlags: number;
|
||||
|
||||
getCentrePosition(): Coord2;
|
||||
moveTo(position: Coord2 | Coord3): void;
|
||||
scrollTo(position: Coord2 | Coord3): void;
|
||||
getCentrePosition(): CoordsXY;
|
||||
moveTo(position: CoordsXY | CoordsXYZ): void;
|
||||
scrollTo(position: CoordsXY | CoordsXYZ): void;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,12 +11,72 @@
|
|||
|
||||
# include "CustomMenu.h"
|
||||
|
||||
# include <openrct2/Input.h>
|
||||
# include <openrct2/world/Map.h>
|
||||
# include <openrct2/world/Sprite.h>
|
||||
|
||||
namespace OpenRCT2::Scripting
|
||||
{
|
||||
std::optional<CustomTool> ActiveCustomTool;
|
||||
std::vector<CustomToolbarMenuItem> CustomMenuItems;
|
||||
|
||||
static void RemoveMenuItems(std::shared_ptr<Plugin> owner)
|
||||
static constexpr std::array<std::string_view, CURSOR_COUNT> CursorNames = {
|
||||
"arrow", "blank", "up_arrow", "up_down_arrow", "hand_point", "zzz", "diagonal_arrows",
|
||||
"picker", "tree_down", "fountain_down", "statue_down", "bench_down", "cross_hair", "bin_down",
|
||||
"lamppost_down", "fence_down", "flower_down", "path_down", "dig_down", "water_down", "house_down",
|
||||
"volcano_down", "walk_down", "paint_down", "entrance_down", "hand_open", "hand_closed",
|
||||
};
|
||||
|
||||
template<> DukValue ToDuk(duk_context* ctx, const CURSOR_ID& value)
|
||||
{
|
||||
if (value >= 0 && static_cast<size_t>(value) < std::size(CursorNames))
|
||||
{
|
||||
auto str = CursorNames[value];
|
||||
duk_push_lstring(ctx, str.data(), str.size());
|
||||
DukValue::take_from_stack(ctx);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
template<> CURSOR_ID FromDuk(const DukValue& s)
|
||||
{
|
||||
if (s.type() == DukValue::Type::STRING)
|
||||
{
|
||||
auto it = std::find(std::begin(CursorNames), std::end(CursorNames), s.as_c_string());
|
||||
if (it != std::end(CursorNames))
|
||||
{
|
||||
return static_cast<CURSOR_ID>(std::distance(std::begin(CursorNames), it));
|
||||
}
|
||||
}
|
||||
return CURSOR_UNDEFINED;
|
||||
}
|
||||
|
||||
template<> DukValue ToDuk(duk_context* ctx, const CoordsXY& coords)
|
||||
{
|
||||
DukObject dukCoords(ctx);
|
||||
dukCoords.Set("x", coords.x);
|
||||
dukCoords.Set("y", coords.y);
|
||||
return dukCoords.Take();
|
||||
}
|
||||
|
||||
template<> DukValue ToDuk(duk_context* ctx, const ScreenCoordsXY& coords)
|
||||
{
|
||||
DukObject dukCoords(ctx);
|
||||
dukCoords.Set("x", coords.x);
|
||||
dukCoords.Set("y", coords.y);
|
||||
return dukCoords.Take();
|
||||
}
|
||||
|
||||
static void RemoveMenuItemsAndTool(std::shared_ptr<Plugin> owner)
|
||||
{
|
||||
if (ActiveCustomTool)
|
||||
{
|
||||
if (ActiveCustomTool->Owner == owner)
|
||||
{
|
||||
tool_cancel();
|
||||
}
|
||||
}
|
||||
|
||||
auto& menuItems = CustomMenuItems;
|
||||
for (auto it = menuItems.begin(); it != menuItems.end();)
|
||||
{
|
||||
|
@ -33,8 +93,131 @@ namespace OpenRCT2::Scripting
|
|||
|
||||
void InitialiseCustomMenuItems(ScriptEngine& scriptEngine)
|
||||
{
|
||||
scriptEngine.SubscribeToPluginStoppedEvent([](std::shared_ptr<Plugin> plugin) -> void { RemoveMenuItems(plugin); });
|
||||
scriptEngine.SubscribeToPluginStoppedEvent(
|
||||
[](std::shared_ptr<Plugin> plugin) -> void { RemoveMenuItemsAndTool(plugin); });
|
||||
}
|
||||
|
||||
void CustomTool::OnUpdate(const ScreenCoordsXY& screenCoords)
|
||||
{
|
||||
InvokeEventHandler(onMove, screenCoords);
|
||||
}
|
||||
|
||||
void CustomTool::OnDown(const ScreenCoordsXY& screenCoords)
|
||||
{
|
||||
MouseDown = true;
|
||||
InvokeEventHandler(onDown, screenCoords);
|
||||
}
|
||||
|
||||
void CustomTool::OnDrag(const ScreenCoordsXY& screenCoords)
|
||||
{
|
||||
}
|
||||
|
||||
void CustomTool::Start()
|
||||
{
|
||||
auto& scriptEngine = GetContext()->GetScriptEngine();
|
||||
scriptEngine.ExecutePluginCall(Owner, onStart, {}, false);
|
||||
}
|
||||
|
||||
void CustomTool::OnUp(const ScreenCoordsXY& screenCoords)
|
||||
{
|
||||
MouseDown = false;
|
||||
InvokeEventHandler(onUp, screenCoords);
|
||||
}
|
||||
|
||||
void CustomTool::OnAbort()
|
||||
{
|
||||
auto& scriptEngine = GetContext()->GetScriptEngine();
|
||||
scriptEngine.ExecutePluginCall(Owner, onFinish, {}, false);
|
||||
}
|
||||
|
||||
void CustomTool::InvokeEventHandler(const DukValue& dukHandler, const ScreenCoordsXY& screenCoords)
|
||||
{
|
||||
if (dukHandler.is_function())
|
||||
{
|
||||
auto ctx = dukHandler.context();
|
||||
|
||||
auto flags = 0;
|
||||
CoordsXY mapCoords{};
|
||||
int32_t interactionType = 0;
|
||||
TileElement* tileElement{};
|
||||
get_map_coordinates_from_pos(screenCoords, flags, mapCoords, &interactionType, &tileElement, nullptr);
|
||||
|
||||
DukObject obj(dukHandler.context());
|
||||
obj.Set("isDown", MouseDown);
|
||||
obj.Set("screenCoords", ToDuk(ctx, screenCoords));
|
||||
obj.Set("mapCoords", ToDuk(ctx, mapCoords));
|
||||
|
||||
if (interactionType == VIEWPORT_INTERACTION_ITEM_SPRITE && tileElement != nullptr)
|
||||
{
|
||||
// get_map_coordinates_from_pos returns the sprite using tileElement... ugh
|
||||
auto sprite = reinterpret_cast<rct_sprite*>(tileElement);
|
||||
obj.Set("entityId", sprite->generic.sprite_index);
|
||||
}
|
||||
else if (tileElement != nullptr)
|
||||
{
|
||||
int32_t index = 0;
|
||||
auto el = map_get_first_element_at(mapCoords);
|
||||
if (el != nullptr)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (el == tileElement)
|
||||
{
|
||||
obj.Set("tileElementIndex", index);
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
} while (!(el++)->IsLastForTile());
|
||||
}
|
||||
}
|
||||
auto eventArgs = obj.Take();
|
||||
|
||||
auto& scriptEngine = GetContext()->GetScriptEngine();
|
||||
std::vector<DukValue> args;
|
||||
args.push_back(eventArgs);
|
||||
scriptEngine.ExecutePluginCall(Owner, dukHandler, args, false);
|
||||
}
|
||||
}
|
||||
|
||||
void InitialiseCustomTool(ScriptEngine& scriptEngine, const DukValue& dukValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (dukValue.type() == DukValue::Type::OBJECT)
|
||||
{
|
||||
CustomTool customTool;
|
||||
customTool.Owner = scriptEngine.GetExecInfo().GetCurrentPlugin();
|
||||
customTool.Id = dukValue["id"].as_string();
|
||||
customTool.Cursor = FromDuk<CURSOR_ID>(dukValue["cursor"]);
|
||||
if (customTool.Cursor == CURSOR_UNDEFINED)
|
||||
{
|
||||
customTool.Cursor = CURSOR_ARROW;
|
||||
}
|
||||
customTool.onStart = dukValue["onStart"];
|
||||
customTool.onDown = dukValue["onDown"];
|
||||
customTool.onMove = dukValue["onMove"];
|
||||
customTool.onUp = dukValue["onUp"];
|
||||
customTool.onFinish = dukValue["onFinish"];
|
||||
|
||||
auto toolbarWindow = window_find_by_class(WC_TOP_TOOLBAR);
|
||||
if (toolbarWindow != nullptr)
|
||||
{
|
||||
// Use a widget that does not exist on top toolbar but also make sure it isn't -1 as that
|
||||
// prevents abort from being called.
|
||||
rct_widgetindex widgetIndex = -2;
|
||||
tool_cancel();
|
||||
tool_set(toolbarWindow, widgetIndex, static_cast<TOOL_IDX>(customTool.Cursor));
|
||||
ActiveCustomTool = std::move(customTool);
|
||||
ActiveCustomTool->Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const DukException&)
|
||||
{
|
||||
duk_error(scriptEngine.GetContext(), DUK_ERR_ERROR, "Invalid parameters.");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OpenRCT2::Scripting
|
||||
|
||||
#endif
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
# include <memory>
|
||||
# include <openrct2/Context.h>
|
||||
# include <openrct2/interface/Cursors.h>
|
||||
# include <openrct2/scripting/Duktape.hpp>
|
||||
# include <openrct2/scripting/ScriptEngine.h>
|
||||
# include <string>
|
||||
|
@ -41,9 +42,39 @@ namespace OpenRCT2::Scripting
|
|||
}
|
||||
};
|
||||
|
||||
struct CustomTool
|
||||
{
|
||||
std::shared_ptr<Plugin> Owner;
|
||||
std::string Id;
|
||||
CURSOR_ID Cursor{};
|
||||
bool MouseDown{};
|
||||
|
||||
// Event handlers
|
||||
DukValue onStart;
|
||||
DukValue onDown;
|
||||
DukValue onMove;
|
||||
DukValue onUp;
|
||||
DukValue onFinish;
|
||||
|
||||
void Start();
|
||||
void OnUpdate(const ScreenCoordsXY& screenCoords);
|
||||
void OnDown(const ScreenCoordsXY& screenCoords);
|
||||
void OnDrag(const ScreenCoordsXY& screenCoords);
|
||||
void OnUp(const ScreenCoordsXY& screenCoords);
|
||||
void OnAbort();
|
||||
|
||||
private:
|
||||
void InvokeEventHandler(const DukValue& dukHandler, const ScreenCoordsXY& screenCoords);
|
||||
};
|
||||
|
||||
extern std::optional<CustomTool> ActiveCustomTool;
|
||||
extern std::vector<CustomToolbarMenuItem> CustomMenuItems;
|
||||
|
||||
void InitialiseCustomMenuItems(ScriptEngine& scriptEngine);
|
||||
void InitialiseCustomTool(ScriptEngine& scriptEngine, const DukValue& dukValue);
|
||||
|
||||
template<> DukValue ToDuk(duk_context* ctx, const CURSOR_ID& value);
|
||||
template<> CURSOR_ID FromDuk(const DukValue& s);
|
||||
|
||||
} // namespace OpenRCT2::Scripting
|
||||
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
/*****************************************************************************
|
||||
* Copyright (c) 2014-2020 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 <openrct2/common.h>
|
||||
# include <openrct2/scripting/Duktape.hpp>
|
||||
# include <openrct2/world/Map.h>
|
||||
|
||||
namespace OpenRCT2::Scripting
|
||||
{
|
||||
class ScTileSelection
|
||||
{
|
||||
private:
|
||||
duk_context* _ctx{};
|
||||
|
||||
public:
|
||||
ScTileSelection(duk_context* ctx)
|
||||
: _ctx(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
DukValue range_get() const
|
||||
{
|
||||
if (gMapSelectFlags & MAP_SELECT_FLAG_ENABLE)
|
||||
{
|
||||
DukObject range(_ctx);
|
||||
|
||||
DukObject leftTop(_ctx);
|
||||
leftTop.Set("x", gMapSelectPositionA.x);
|
||||
leftTop.Set("y", gMapSelectPositionA.y);
|
||||
range.Set("leftTop", leftTop.Take());
|
||||
|
||||
DukObject rightBottom(_ctx);
|
||||
rightBottom.Set("x", gMapSelectPositionB.x);
|
||||
rightBottom.Set("y", gMapSelectPositionB.y);
|
||||
range.Set("rightBottom", rightBottom.Take());
|
||||
return range.Take();
|
||||
}
|
||||
else
|
||||
{
|
||||
duk_push_null(_ctx);
|
||||
return DukValue::take_from_stack(_ctx);
|
||||
}
|
||||
}
|
||||
|
||||
void range_set(DukValue value)
|
||||
{
|
||||
map_invalidate_selection_rect();
|
||||
if (value.type() == DukValue::Type::OBJECT)
|
||||
{
|
||||
auto range = GetMapRange(value);
|
||||
if (range)
|
||||
{
|
||||
gMapSelectPositionA.x = range->GetLeft();
|
||||
gMapSelectPositionA.y = range->GetTop();
|
||||
gMapSelectPositionB.x = range->GetRight();
|
||||
gMapSelectPositionB.y = range->GetBottom();
|
||||
gMapSelectType = MAP_SELECT_TYPE_FULL;
|
||||
gMapSelectFlags |= MAP_SELECT_FLAG_ENABLE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE;
|
||||
}
|
||||
map_invalidate_selection_rect();
|
||||
}
|
||||
|
||||
DukValue tiles_get() const
|
||||
{
|
||||
duk_push_array(_ctx);
|
||||
if (gMapSelectFlags & MAP_SELECT_FLAG_ENABLE_CONSTRUCT)
|
||||
{
|
||||
duk_uarridx_t index = 0;
|
||||
for (const auto& tile : gMapSelectionTiles)
|
||||
{
|
||||
duk_push_object(_ctx);
|
||||
duk_push_int(_ctx, tile.x);
|
||||
duk_put_prop_string(_ctx, -2, "x");
|
||||
duk_push_int(_ctx, tile.y);
|
||||
duk_put_prop_string(_ctx, -2, "y");
|
||||
duk_put_prop_index(_ctx, -2, index);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return DukValue::take_from_stack(_ctx);
|
||||
}
|
||||
|
||||
void tiles_set(DukValue value)
|
||||
{
|
||||
map_invalidate_map_selection_tiles();
|
||||
gMapSelectionTiles.clear();
|
||||
if (value.is_array())
|
||||
{
|
||||
value.push();
|
||||
auto arrayLen = duk_get_length(_ctx, -1);
|
||||
for (duk_uarridx_t i = 0; i < arrayLen; i++)
|
||||
{
|
||||
if (duk_get_prop_index(_ctx, -1, i))
|
||||
{
|
||||
auto dukElement = DukValue::take_from_stack(_ctx);
|
||||
auto coords = GetCoordsXY(dukElement);
|
||||
if (coords)
|
||||
{
|
||||
gMapSelectionTiles.push_back(*coords);
|
||||
}
|
||||
}
|
||||
}
|
||||
duk_pop(_ctx);
|
||||
}
|
||||
|
||||
if (gMapSelectionTiles.empty())
|
||||
{
|
||||
gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE_CONSTRUCT;
|
||||
gMapSelectFlags &= ~MAP_SELECT_FLAG_GREEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
gMapSelectFlags |= MAP_SELECT_FLAG_ENABLE_CONSTRUCT;
|
||||
}
|
||||
map_invalidate_map_selection_tiles();
|
||||
}
|
||||
|
||||
static void Register(duk_context* ctx)
|
||||
{
|
||||
dukglue_register_property(ctx, &ScTileSelection::range_get, &ScTileSelection::range_set, "range");
|
||||
dukglue_register_property(ctx, &ScTileSelection::tiles_get, &ScTileSelection::tiles_set, "tiles");
|
||||
}
|
||||
|
||||
private:
|
||||
static std::optional<CoordsXY> GetCoordsXY(const DukValue& dukCoords)
|
||||
{
|
||||
std::optional<CoordsXY> result;
|
||||
if (dukCoords.type() == DukValue::Type::OBJECT)
|
||||
{
|
||||
auto dukX = dukCoords["x"];
|
||||
if (dukX.type() == DukValue::Type::NUMBER)
|
||||
{
|
||||
auto dukY = dukCoords["y"];
|
||||
if (dukY.type() == DukValue::Type::NUMBER)
|
||||
{
|
||||
result = { dukX.as_int(), dukY.as_int() };
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::optional<MapRange> GetMapRange(const DukValue& dukMapRange)
|
||||
{
|
||||
std::optional<MapRange> result;
|
||||
if (dukMapRange.type() == DukValue::Type::OBJECT)
|
||||
{
|
||||
auto leftTop = GetCoordsXY(dukMapRange["leftTop"]);
|
||||
if (leftTop.has_value())
|
||||
{
|
||||
auto rightBottom = GetCoordsXY(dukMapRange["rightBottom"]);
|
||||
if (rightBottom.has_value())
|
||||
{
|
||||
result = MapRange(leftTop->x, leftTop->y, rightBottom->x, rightBottom->y);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
} // namespace OpenRCT2::Scripting
|
||||
|
||||
#endif
|
|
@ -12,11 +12,14 @@
|
|||
#ifdef ENABLE_SCRIPTING
|
||||
|
||||
# include "CustomMenu.h"
|
||||
# include "ScTileSelection.hpp"
|
||||
# include "ScViewport.hpp"
|
||||
# include "ScWindow.hpp"
|
||||
|
||||
# include <algorithm>
|
||||
# include <memory>
|
||||
# include <openrct2/Context.h>
|
||||
# include <openrct2/Input.h>
|
||||
# include <openrct2/common.h>
|
||||
# include <openrct2/scripting/Duktape.hpp>
|
||||
# include <openrct2/scripting/ScriptEngine.h>
|
||||
|
@ -34,6 +37,41 @@ namespace OpenRCT2::Ui::Windows
|
|||
|
||||
namespace OpenRCT2::Scripting
|
||||
{
|
||||
class ScTool
|
||||
{
|
||||
private:
|
||||
duk_context* _ctx{};
|
||||
|
||||
public:
|
||||
ScTool(duk_context* ctx)
|
||||
: _ctx(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static void Register(duk_context* ctx)
|
||||
{
|
||||
dukglue_register_property(ctx, &ScTool::id_get, nullptr, "id");
|
||||
dukglue_register_property(ctx, &ScTool::cursor_get, nullptr, "cursor");
|
||||
dukglue_register_method(ctx, &ScTool::cancel, "cancel");
|
||||
}
|
||||
|
||||
private:
|
||||
std::string id_get() const
|
||||
{
|
||||
return ActiveCustomTool ? ActiveCustomTool->Id : "";
|
||||
}
|
||||
|
||||
DukValue cursor_get() const
|
||||
{
|
||||
return ToDuk(_ctx, static_cast<CURSOR_ID>(gCurrentToolId));
|
||||
}
|
||||
|
||||
void cancel()
|
||||
{
|
||||
tool_cancel();
|
||||
}
|
||||
};
|
||||
|
||||
class ScUi
|
||||
{
|
||||
private:
|
||||
|
@ -64,6 +102,20 @@ namespace OpenRCT2::Scripting
|
|||
return std::make_shared<ScViewport>(WC_MAIN_WINDOW);
|
||||
}
|
||||
|
||||
std::shared_ptr<ScTileSelection> tileSelection_get() const
|
||||
{
|
||||
return std::make_shared<ScTileSelection>(_scriptEngine.GetContext());
|
||||
}
|
||||
|
||||
std::shared_ptr<ScTool> tool_get() const
|
||||
{
|
||||
if (input_test_flag(INPUT_FLAG_TOOL_ACTIVE))
|
||||
{
|
||||
return std::make_shared<ScTool>(_scriptEngine.GetContext());
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::shared_ptr<ScWindow> openWindow(DukValue desc)
|
||||
{
|
||||
using namespace OpenRCT2::Ui::Windows;
|
||||
|
@ -128,6 +180,11 @@ namespace OpenRCT2::Scripting
|
|||
return {};
|
||||
}
|
||||
|
||||
void activateTool(const DukValue& desc)
|
||||
{
|
||||
InitialiseCustomTool(_scriptEngine, desc);
|
||||
}
|
||||
|
||||
void registerMenuItem(std::string text, DukValue callback)
|
||||
{
|
||||
auto& execInfo = _scriptEngine.GetExecInfo();
|
||||
|
@ -142,10 +199,13 @@ namespace OpenRCT2::Scripting
|
|||
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_property(ctx, &ScUi::tileSelection_get, nullptr, "tileSelection");
|
||||
dukglue_register_property(ctx, &ScUi::tool_get, nullptr, "tool");
|
||||
dukglue_register_method(ctx, &ScUi::openWindow, "openWindow");
|
||||
dukglue_register_method(ctx, &ScUi::closeWindows, "closeWindows");
|
||||
dukglue_register_method(ctx, &ScUi::closeAllWindows, "closeAllWindows");
|
||||
dukglue_register_method(ctx, &ScUi::getWindow, "getWindow");
|
||||
dukglue_register_method(ctx, &ScUi::activateTool, "activateTool");
|
||||
dukglue_register_method(ctx, &ScUi::registerMenuItem, "registerMenuItem");
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
# include "UiExtensions.h"
|
||||
|
||||
# include "CustomMenu.h"
|
||||
# include "ScTileSelection.hpp"
|
||||
# include "ScUi.hpp"
|
||||
# include "ScWidget.hpp"
|
||||
# include "ScWindow.hpp"
|
||||
|
@ -26,6 +27,8 @@ void UiScriptExtensions::Extend(ScriptEngine& scriptEngine)
|
|||
|
||||
dukglue_register_global(ctx, std::make_shared<ScUi>(scriptEngine), "ui");
|
||||
|
||||
ScTileSelection::Register(ctx);
|
||||
ScTool::Register(ctx);
|
||||
ScUi::Register(ctx);
|
||||
ScViewport::Register(ctx);
|
||||
ScWidget::Register(ctx);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*****************************************************************************
|
||||
* Copyright (c) 2014-2019 OpenRCT2 developers
|
||||
* Copyright (c) 2014-2020 OpenRCT2 developers
|
||||
*
|
||||
* For a complete list of all authors, please refer to contributors.md
|
||||
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||
|
@ -2961,6 +2961,15 @@ static void window_top_toolbar_tool_update(rct_window* w, rct_widgetindex widget
|
|||
case WIDX_SCENERY:
|
||||
top_toolbar_tool_update_scenery(screenCoords);
|
||||
break;
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
default:
|
||||
auto& customTool = OpenRCT2::Scripting::ActiveCustomTool;
|
||||
if (customTool)
|
||||
{
|
||||
customTool->OnUpdate(screenCoords);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3009,6 +3018,15 @@ static void window_top_toolbar_tool_down(rct_window* w, rct_widgetindex widgetIn
|
|||
case WIDX_SCENERY:
|
||||
window_top_toolbar_scenery_tool_down(screenCoords, w, widgetIndex);
|
||||
break;
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
default:
|
||||
auto& customTool = OpenRCT2::Scripting::ActiveCustomTool;
|
||||
if (customTool)
|
||||
{
|
||||
customTool->OnDown(screenCoords);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3227,6 +3245,15 @@ static void window_top_toolbar_tool_drag(rct_window* w, rct_widgetindex widgetIn
|
|||
if (gWindowSceneryEyedropperEnabled)
|
||||
window_top_toolbar_scenery_tool_down(screenCoords, w, widgetIndex);
|
||||
break;
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
default:
|
||||
auto& customTool = OpenRCT2::Scripting::ActiveCustomTool;
|
||||
if (customTool)
|
||||
{
|
||||
customTool->OnDrag(screenCoords);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3254,6 +3281,15 @@ static void window_top_toolbar_tool_up(rct_window* w, rct_widgetindex widgetInde
|
|||
gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE;
|
||||
gCurrentToolId = TOOL_CROSSHAIR;
|
||||
break;
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
default:
|
||||
auto& customTool = OpenRCT2::Scripting::ActiveCustomTool;
|
||||
if (customTool)
|
||||
{
|
||||
customTool->OnUp(screenCoords);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3270,6 +3306,16 @@ static void window_top_toolbar_tool_abort(rct_window* w, rct_widgetindex widgetI
|
|||
case WIDX_CLEAR_SCENERY:
|
||||
hide_gridlines();
|
||||
break;
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
default:
|
||||
auto& customTool = OpenRCT2::Scripting::ActiveCustomTool;
|
||||
if (customTool)
|
||||
{
|
||||
customTool->OnAbort();
|
||||
customTool = {};
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -189,6 +189,10 @@ namespace OpenRCT2::Scripting
|
|||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> DukValue ToDuk(duk_context* ctx, const T& value) = delete;
|
||||
template<typename T> T FromDuk(const DukValue& s) = delete;
|
||||
|
||||
} // namespace OpenRCT2::Scripting
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue