diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 116bdd445..46a7d4097 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -126,7 +126,7 @@ if(BUILD_SUPPORTED) dfhack_plugin(flows flows.cpp) dfhack_plugin(follow follow.cpp) dfhack_plugin(forceequip forceequip.cpp) - dfhack_plugin(fortplan fortplan.cpp LINK_LIBRARIES buildingplan-lib) + dfhack_plugin(fortplan fortplan.cpp LINK_LIBRARIES buildingplan-lib lua) dfhack_plugin(generated-creature-renamer generated-creature-renamer.cpp) dfhack_plugin(getplants getplants.cpp) dfhack_plugin(hotkeys hotkeys.cpp) diff --git a/plugins/buildingplan-planner.cpp b/plugins/buildingplan-planner.cpp index 3cb27145e..925d0f4c3 100644 --- a/plugins/buildingplan-planner.cpp +++ b/plugins/buildingplan-planner.cpp @@ -522,42 +522,6 @@ bool Planner::isPlannableBuilding(BuildingTypeKey key) return item_for_building_type.count(std::get<0>(key)) > 0; } -bool Planner::allocatePlannedBuilding(BuildingTypeKey key) -{ - coord32_t cursor; - if (!DFHack::Gui::getCursorCoords(cursor.x, cursor.y, cursor.z)) - return false; - - auto type = std::get<0>(key); - auto newinst = Buildings::allocInstance(cursor.get_coord16(), type); - if (!newinst) - return false; - - df::job_item *filter = new df::job_item(); - filter->item_type = item_type::NONE; - filter->mat_index = 0; - filter->flags2.bits.building_material = true; - std::vector filters; - filters.push_back(filter); - - if (!Buildings::constructWithFilters(newinst, filters)) - { - delete newinst; - return false; - } - - if (type == building_type::Door) - { - auto door = virtual_cast(newinst); - if (door) - door->door_flags.bits.pet_passable = true; - } - - addPlannedBuilding(newinst); - - return true; -} - Planner::ItemFiltersWrapper Planner::getItemFilters(BuildingTypeKey key) { static std::vector empty_vector; diff --git a/plugins/buildingplan-planner.h b/plugins/buildingplan-planner.h index 9341ad03f..cda217d81 100644 --- a/plugins/buildingplan-planner.h +++ b/plugins/buildingplan-planner.h @@ -106,7 +106,6 @@ public: void initialize(); void reset(); - bool allocatePlannedBuilding(BuildingTypeKey key); void addPlannedBuilding(df::building *bld); PlannedBuilding *getPlannedBuilding(df::building *bld); diff --git a/plugins/buildingplan.cpp b/plugins/buildingplan.cpp index 1d25da6f0..82551be23 100644 --- a/plugins/buildingplan.cpp +++ b/plugins/buildingplan.cpp @@ -287,6 +287,33 @@ static bool is_planmode_enabled(BuildingTypeKey key) return planmode_enabled[key] || quickfort_mode; } +static bool construct_planned_building() +{ + auto L = Lua::Core::State; + color_ostream_proxy out(Core::getInstance().getConsole()); + + CoreSuspendClaimer suspend; + Lua::StackUnwinder top(L); + + if (!(lua_checkstack(L, 1) && + Lua::PushModulePublic(out, L, "plugins.buildingplan", + "construct_building_from_ui_state") && + Lua::SafeCall(out, L, 0, 1))) + { + return false; + } + + auto bld = Lua::CheckDFObject(L, -1); + lua_pop(L, 1); + + if (!bld) + return false; + + planner.addPlannedBuilding(bld); + + return true; +} + struct buildingplan_query_hook : public df::viewscreen_dwarfmodest { typedef df::viewscreen_dwarfmodest interpose_base; @@ -417,7 +444,7 @@ struct buildingplan_place_hook : public df::viewscreen_dwarfmodest if (input->count(interface_key::SELECT)) { - if (ui_build_selector->errors.size() == 0 && planner.allocatePlannedBuilding(key)) + if (ui_build_selector->errors.size() == 0 && construct_planned_building()) { Gui::refreshSidebar(); if (quickfort_mode) diff --git a/plugins/fortplan.cpp b/plugins/fortplan.cpp index ff8aa547f..07685ca2b 100644 --- a/plugins/fortplan.cpp +++ b/plugins/fortplan.cpp @@ -1,14 +1,17 @@ #include #include -#include "df/world.h" +#include "df/job_item.h" #include "df/trap_type.h" +#include "df/world.h" +#include "modules/Buildings.h" #include "modules/Filesystem.h" #include "modules/Gui.h" #include "modules/Maps.h" #include "modules/World.h" +#include "LuaTools.h" #include "PluginManager.h" #include "buildingplan-lib.h" @@ -47,8 +50,37 @@ struct BuildingInfo { hasCustomOptions = false; } - bool allocate() { - return planner.allocatePlannedBuilding(toBuildingTypeKey(type, -1, -1)); + bool allocate(coord32_t cursor) { + auto L = Lua::Core::State; + color_ostream_proxy out(Core::getInstance().getConsole()); + + CoreSuspendClaimer suspend; + Lua::StackUnwinder top(L); + + if (!lua_checkstack(L, 5) || + !Lua::PushModulePublic(out, L, "plugins.fortplan", + "construct_building_from_params")) + { + return false; + } + + Lua::Push(L, type); + Lua::Push(L, cursor.x); + Lua::Push(L, cursor.y); + Lua::Push(L, cursor.z); + + if (!Lua::SafeCall(out, L, 4, 1)) + return false; + + auto bld = Lua::CheckDFObject(L, -1); + lua_pop(L, 1); + + if (!bld) + return false; + + planner.addPlannedBuilding(bld); + + return true; } }; @@ -347,13 +379,13 @@ command_result fortplan(color_ostream &out, vector & params) { offsetCursor.x -= xOffset; offsetCursor.y -= yOffset; DFHack::Gui::setCursorCoords(offsetCursor.x, offsetCursor.y, offsetCursor.z); - if (!buildingInfo.allocate()) { + if (!buildingInfo.allocate(offsetCursor)) { con.print("*** There was an error placing building with code '%s' centered at (%zu,%zu).\n",curCode.c_str(),x,y); } DFHack::Gui::setCursorCoords(cursor.x, cursor.y, cursor.z); } else if (block) { //con.print("Placing a building with code '%s' with corner at (%d,%d) and default size %dx%d.\n",curCode.c_str(),x,y,buildingInfo.defaultWidth,buildingInfo.defaultHeight); - if (!buildingInfo.allocate()) { + if (!buildingInfo.allocate(cursor)) { con.print("*** There was an error placing building with code '%s' with corner at (%zu,%zu).\n",curCode.c_str(),x,y); } } else { @@ -366,7 +398,7 @@ command_result fortplan(color_ostream &out, vector & params) { } } else { //con.print("Building a(n) %s.\n",buildingInfo.name.c_str()); - if (!buildingInfo.allocate()) { + if (!buildingInfo.allocate(cursor)) { con.print("*** There was an error placing the %s at (%zu,%zu).\n",buildingInfo.name.c_str(),x,y); } } diff --git a/plugins/lua/buildingplan.lua b/plugins/lua/buildingplan.lua index 157b6211b..1ab462201 100644 --- a/plugins/lua/buildingplan.lua +++ b/plugins/lua/buildingplan.lua @@ -11,4 +11,40 @@ local _ENV = mkmodule('plugins.buildingplan') --]] +local guidm = require('gui.dwarfmode') +require('dfhack.buildings') + +-- needs the core suspended +function construct_building_from_ui_state() + local uibs = df.global.ui_build_selector + local world = df.global.world + local direction = world.selected_direction + local _, width, height = dfhack.buildings.getCorrectSize( + world.building_width, world.building_height, uibs.building_type, + uibs.building_subtype, uibs.custom_type, direction) + -- the cursor is at the center of the building; we need the upper-left + -- corner of the building + local pos = guidm.getCursorPos() + pos.x = pos.x - math.floor(width/2) + pos.y = pos.y - math.floor(height/2) + local bld, err = dfhack.buildings.constructBuilding{ + type=uibs.building_type, subtype=uibs.building_subtype, + custom=uibs.custom_type, pos=pos, width=width, height=height, + direction=direction} + if err then error(err) end + -- TODO: assign fields for the types that need them. we can't pass them all + -- in to the call to constructBuilding since the unneeded fields will cause + -- errors + --local fields = { + -- friction=uibs.friction, + -- use_dump=uibs.use_dump, + -- dump_x_shift=uibs.dump_x_shift, + -- dump_y_shift=uibs.dump_y_shift, + -- speed=uibs.speed + --} + -- TODO: use quickfort's post_construction_fns? maybe move those functions + -- into the library so they get applied automatically + return bld +end + return _ENV diff --git a/plugins/lua/fortplan.lua b/plugins/lua/fortplan.lua new file mode 100644 index 000000000..71e69c69d --- /dev/null +++ b/plugins/lua/fortplan.lua @@ -0,0 +1,13 @@ +local _ENV = mkmodule('plugins.fortplan') + +require('dfhack.buildings') + +function construct_building_from_params(building_type, x, y, z) + local pos = xyz2pos(x, y, z) + local bld, err = + dfhack.buildings.constructBuilding{type=building_type, pos=pos} + if err then error(err) end + return bld +end + +return _ENV