diff --git a/LUA_API.rst b/LUA_API.rst index 799f623eb..4d9170d6e 100644 --- a/LUA_API.rst +++ b/LUA_API.rst @@ -995,6 +995,10 @@ Maps module Returns a map block object for given df::coord or x,y,z in local tile coordinates. +* ``dfhack.maps.ensureTileBlock(coords)``, or ``ensureTileBlock(x,y,z)`` + + Like ``getTileBlock``, but if the block is not allocated, try creating it. + * ``dfhack.maps.getRegionBiome(region_coord2d)``, or ``getRegionBiome(x,y)`` Returns the biome info struct for the given global map region. @@ -1304,6 +1308,11 @@ Basic painting functions: Returns *false* if coordinates out of bounds, or other error. +* ``dfhack.screen.readTile(x,y)`` + + Retrieves the contents of the specified tile from the screen buffers. + Returns a pen, or *nil* if invalid or TrueType. + * ``dfhack.screen.paintString(pen,x,y,text)`` Paints the string starting at *x,y*. Uses the string characters diff --git a/Lua API.html b/Lua API.html index f05ee5511..dc9c8d73e 100644 --- a/Lua API.html +++ b/Lua API.html @@ -1207,6 +1207,9 @@ Returns false in case of error.
dfhack.maps.getTileBlock(coords), or getTileBlock(x,y,z)
Returns a map block object for given df::coord or x,y,z in local tile coordinates.
dfhack.maps.ensureTileBlock(coords), or ensureTileBlock(x,y,z)
+Like getTileBlock, but if the block is not allocated, try creating it.
+dfhack.maps.getRegionBiome(region_coord2d), or getRegionBiome(x,y)
Returns the biome info struct for the given global map region.
Returns false if coordinates out of bounds, or other error.
+dfhack.screen.readTile(x,y)
+Retrieves the contents of the specified tile from the screen buffers. +Returns a pen, or nil if invalid or TrueType.
+dfhack.screen.paintString(pen,x,y,text)
Paints the string starting at x,y. Uses the string characters in sequence to override the ch field of pen.
diff --git a/dfhack.init-example b/dfhack.init-example index afde13a88..658f6e9be 100644 --- a/dfhack.init-example +++ b/dfhack.init-example @@ -56,6 +56,9 @@ keybinding add Alt-R@dwarfmode/QueryBuilding/Some gui/room-list.work # interface for the liquids plugin keybinding add Alt-L@dwarfmode/LookAround gui/liquids +# machine power sensitive pressure plate construction +keybinding add Ctrl-Shift-M@dwarfmode/Build/Position/Trap gui/power-meter + # interface for universal game master's editor keybinding add Alt-Shift-E gui/gm-editor diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 1dcb001f1..807cbf539 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -935,6 +935,13 @@ static int maps_getTileBlock(lua_State *L) return 1; } +static int maps_ensureTileBlock(lua_State *L) +{ + auto pos = CheckCoordXYZ(L, 1, true); + Lua::PushDFObject(L, Maps::ensureTileBlock(pos)); + return 1; +} + static int maps_getRegionBiome(lua_State *L) { auto pos = CheckCoordXY(L, 1, true); @@ -951,6 +958,7 @@ static int maps_getTileBiomeRgn(lua_State *L) static const luaL_Reg dfhack_maps_funcs[] = { { "isValidTilePos", maps_isValidTilePos }, { "getTileBlock", maps_getTileBlock }, + { "ensureTileBlock", maps_ensureTileBlock }, { "getRegionBiome", maps_getRegionBiome }, { "getTileBiomeRgn", maps_getTileBiomeRgn }, { NULL, NULL } @@ -1146,6 +1154,45 @@ static int screen_paintTile(lua_State *L) return 1; } +static int screen_readTile(lua_State *L) +{ + int x = luaL_checkint(L, 1); + int y = luaL_checkint(L, 2); + Pen pen = Screen::readTile(x, y); + + if (!pen.valid()) + { + lua_pushnil(L); + } + else + { + lua_newtable(L); + lua_pushinteger(L, pen.ch); lua_setfield(L, -2, "ch"); + lua_pushinteger(L, pen.fg); lua_setfield(L, -2, "fg"); + lua_pushinteger(L, pen.bg); lua_setfield(L, -2, "bg"); + lua_pushboolean(L, pen.bold); lua_setfield(L, -2, "bold"); + + if (pen.tile) + { + lua_pushinteger(L, pen.tile); lua_setfield(L, -2, "tile"); + + switch (pen.tile_mode) { + case Pen::CharColor: + lua_pushboolean(L, true); lua_setfield(L, -2, "tile_color"); + break; + case Pen::TileColor: + lua_pushinteger(L, pen.tile_fg); lua_setfield(L, -2, "tile_fg"); + lua_pushinteger(L, pen.tile_bg); lua_setfield(L, -2, "tile_bg"); + break; + default: + break; + } + } + } + + return 1; +} + static int screen_paintString(lua_State *L) { Pen pen; @@ -1250,6 +1297,7 @@ static const luaL_Reg dfhack_screen_funcs[] = { { "getMousePos", screen_getMousePos }, { "getWindowSize", screen_getWindowSize }, { "paintTile", screen_paintTile }, + { "readTile", screen_readTile }, { "paintString", screen_paintString }, { "fillRect", screen_fillRect }, { "findGraphicsTile", screen_findGraphicsTile }, diff --git a/library/include/modules/MapCache.h b/library/include/modules/MapCache.h index 109a20a41..262e70bbf 100644 --- a/library/include/modules/MapCache.h +++ b/library/include/modules/MapCache.h @@ -253,6 +253,8 @@ public: bool is_valid() { return valid; } df::map_block *getRaw() { return block; } + bool Allocate(); + MapCache *getParent() { return parent; } private: @@ -262,6 +264,8 @@ private: MapCache *parent; df::map_block *block; + void init(); + int biomeIndexAt(df::coord2d p); bool valid; @@ -347,6 +351,12 @@ class DFHACK_EXPORT MapCache return BlockAt(df::coord(coord.x>>4,coord.y>>4,coord.z)); } + bool ensureBlockAt(df::coord coord) + { + Block *b = BlockAtTile(coord); + return b ? b->Allocate() : false; + } + df::tiletype baseTiletypeAt (DFCoord tilecoord) { Block *b = BlockAtTile(tilecoord); diff --git a/library/include/modules/Maps.h b/library/include/modules/Maps.h index 984cf16cf..869b21580 100644 --- a/library/include/modules/Maps.h +++ b/library/include/modules/Maps.h @@ -241,9 +241,11 @@ inline bool isValidTilePos(df::coord pos) { return isValidTilePos(pos.x, pos.y, */ extern DFHACK_EXPORT df::map_block * getBlock (int32_t blockx, int32_t blocky, int32_t blockz); extern DFHACK_EXPORT df::map_block * getTileBlock (int32_t x, int32_t y, int32_t z); +extern DFHACK_EXPORT df::map_block * ensureTileBlock (int32_t x, int32_t y, int32_t z); inline df::map_block * getBlock (df::coord pos) { return getBlock(pos.x, pos.y, pos.z); } inline df::map_block * getTileBlock (df::coord pos) { return getTileBlock(pos.x, pos.y, pos.z); } +inline df::map_block * ensureTileBlock (df::coord pos) { return ensureTileBlock(pos.x, pos.y, pos.z); } extern DFHACK_EXPORT df::tiletype *getTileType(int32_t x, int32_t y, int32_t z); extern DFHACK_EXPORT df::tile_designation *getTileDesignation(int32_t x, int32_t y, int32_t z); diff --git a/library/include/modules/Screen.h b/library/include/modules/Screen.h index 492e1eecc..4f47205f2 100644 --- a/library/include/modules/Screen.h +++ b/library/include/modules/Screen.h @@ -65,6 +65,9 @@ namespace DFHack } tile_mode; int8_t tile_fg, tile_bg; + bool valid() const { return tile >= 0; } + bool empty() const { return ch == 0 && tile == 0; } + Pen(char ch = 0, int8_t fg = 7, int8_t bg = 0, int tile = 0, bool color_tile = false) : ch(ch), fg(fg&7), bg(bg), bold(!!(fg&8)), tile(tile), tile_mode(color_tile ? CharColor : AsIs), tile_fg(0), tile_bg(0) @@ -92,6 +95,9 @@ namespace DFHack /// Paint one screen tile with the given pen DFHACK_EXPORT bool paintTile(const Pen &pen, int x, int y); + /// Retrieves one screen tile from the buffer + DFHACK_EXPORT Pen readTile(int x, int y); + /// Paint a string onto the screen. Ignores ch and tile of pen. DFHACK_EXPORT bool paintString(const Pen &pen, int x, int y, const std::string &text); diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index a1e899761..e96bb0f4b 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -84,7 +84,7 @@ function mkmodule(module,env) error("Not a table in package.loaded["..module.."]") end end - local plugname = string.match(module,'^plugins%.(%w+)$') + local plugname = string.match(module,'^plugins%.([%w%-]+)$') if plugname then dfhack.open_plugin(pkg,plugname) end diff --git a/library/lua/gui.lua b/library/lua/gui.lua index 23904c14f..f9b6ab6d2 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -162,10 +162,10 @@ function Painter:fill(x1,y1,x2,y2,pen,bg,bold) if type(x1) == 'table' then x1, y1, x2, y2, pen, bg, bold = x1.x1, x1.y1, x1.x2, x1.y2, y1, x2, y2 end - x1 = math.max(x1,self.clip_x1) - y1 = math.max(y1,self.clip_y1) - x2 = math.min(x2,self.clip_x2) - y2 = math.min(y2,self.clip_y2) + x1 = math.max(x1+self.x1,self.clip_x1) + y1 = math.max(y1+self.y1,self.clip_y1) + x2 = math.min(x2+self.x1,self.clip_x2) + y2 = math.min(y2+self.y1,self.clip_y2) dscreen.fillRect(to_pen(self.cur_pen,pen,bg,bold),x1,y1,x2,y2) return self end diff --git a/library/lua/gui/dialogs.lua b/library/lua/gui/dialogs.lua index 35720f871..c4f15c9ac 100644 --- a/library/lua/gui/dialogs.lua +++ b/library/lua/gui/dialogs.lua @@ -127,7 +127,7 @@ function InputBox:onRenderBody(dc) dc:newline(1) dc:pen(self.input_pen or COLOR_LIGHTCYAN) - dc:fill(dc.x1+1,dc.y,dc.x2-1,dc.y) + dc:fill(1,dc:localY(),dc.width-2,dc:localY()) local cursor = '_' if math.floor(dfhack.getTickCount()/300) % 2 == 0 then @@ -135,9 +135,7 @@ function InputBox:onRenderBody(dc) end local txt = self.input .. cursor if #txt > dc.width-2 then - txt = string.sub(txt, #txt-dc.width+3) - -- Add prefix arrow - dc:advance(-1):char(27) + txt = string.char(27)..string.sub(txt, #txt-dc.width+4) end dc:string(txt) end diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 1ea4bf687..8de908734 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -211,7 +211,14 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) if (ui_build_selector->building_type < 0) focus += "/Type"; else if (ui_build_selector->stage != 2) - focus += "/Position"; + { + if (ui_build_selector->stage != 1) + focus += "/NoMaterials"; + else + focus += "/Position"; + + focus += "/" + enum_item_key(ui_build_selector->building_type); + } else { focus += "/Material"; diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp index 305f1296d..d0401164a 100644 --- a/library/modules/Maps.cpp +++ b/library/modules/Maps.cpp @@ -157,6 +157,39 @@ df::map_block *Maps::getTileBlock (int32_t x, int32_t y, int32_t z) return world->map.block_index[x >> 4][y >> 4][z]; } +df::map_block *Maps::ensureTileBlock (int32_t x, int32_t y, int32_t z) +{ + if (!isValidTilePos(x,y,z)) + return NULL; + + auto column = world->map.block_index[x >> 4][y >> 4]; + auto &slot = column[z]; + if (slot) + return slot; + + // Find another block below + int z2 = z; + while (z2 >= 0 && !column[z2]) z2--; + if (z2 < 0) + return NULL; + + slot = new df::map_block(); + slot->region_pos = column[z2]->region_pos; + slot->map_pos = column[z2]->map_pos; + slot->map_pos.z = z; + + // Assume sky + df::tile_designation dsgn(0); + dsgn.bits.light = true; + dsgn.bits.outside = true; + + for (int tx = 0; tx < 16; tx++) + for (int ty = 0; ty < 16; ty++) + slot->designation[tx][ty] = dsgn; + + return slot; +} + df::tiletype *Maps::getTileType(int32_t x, int32_t y, int32_t z) { df::map_block *block = getTileBlock(x,y,z); @@ -513,8 +546,14 @@ MapExtras::Block::Block(MapCache *parent, DFCoord _bcoord) : parent(parent) valid = false; bcoord = _bcoord; block = Maps::getBlock(bcoord); - item_counts = NULL; tags = NULL; + + init(); +} + +void MapExtras::Block::init() +{ + item_counts = NULL; tiles = NULL; basemats = NULL; @@ -537,6 +576,23 @@ MapExtras::Block::Block(MapCache *parent, DFCoord _bcoord) : parent(parent) } } +bool MapExtras::Block::Allocate() +{ + if (block) + return true; + + block = Maps::ensureTileBlock(bcoord.x*16, bcoord.y*16, bcoord.z); + if (!block) + return false; + + delete item_counts; + delete tiles; + delete basemats; + init(); + + return true; +} + MapExtras::Block::~Block() { delete[] item_counts; diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index c2377f2ca..9f258fe02 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -100,7 +100,7 @@ static void doSetTile(const Pen &pen, int index) bool Screen::paintTile(const Pen &pen, int x, int y) { - if (!gps) return false; + if (!gps || !pen.valid()) return false; int dimx = gps->dimx, dimy = gps->dimy; if (x < 0 || x >= dimx || y < 0 || y >= dimy) return false; @@ -109,6 +109,41 @@ bool Screen::paintTile(const Pen &pen, int x, int y) return true; } +Pen Screen::readTile(int x, int y) +{ + if (!gps) return Pen(0,0,0,-1); + + int dimx = gps->dimx, dimy = gps->dimy; + if (x < 0 || x >= dimx || y < 0 || y >= dimy) + return Pen(0,0,0,-1); + + int index = x*dimy + y; + auto screen = gps->screen + index*4; + if (screen[3] & 0x80) + return Pen(0,0,0,-1); + + Pen pen( + screen[0], screen[1], screen[2], screen[3]?true:false, + gps->screentexpos[index] + ); + + if (pen.tile) + { + if (gps->screentexpos_grayscale[index]) + { + pen.tile_mode = Screen::Pen::TileColor; + pen.tile_fg = gps->screentexpos_cf[index]; + pen.tile_bg = gps->screentexpos_cbr[index]; + } + else if (gps->screentexpos_addcolor[index]) + { + pen.tile_mode = Screen::Pen::CharColor; + } + } + + return pen; +} + bool Screen::paintString(const Pen &pen, int x, int y, const std::string &text) { if (!gps || y < 0 || y >= gps->dimy) return false; @@ -132,7 +167,7 @@ bool Screen::paintString(const Pen &pen, int x, int y, const std::string &text) bool Screen::fillRect(const Pen &pen, int x1, int y1, int x2, int y2) { - if (!gps) return false; + if (!gps || !pen.valid()) return false; if (x1 < 0) x1 = 0; if (y1 < 0) y1 = 0; diff --git a/plugins/lua/power-meter.lua b/plugins/lua/power-meter.lua new file mode 100644 index 000000000..310e51c4e --- /dev/null +++ b/plugins/lua/power-meter.lua @@ -0,0 +1,11 @@ +local _ENV = mkmodule('plugins.power-meter') + +--[[ + + Native functions: + + * makePowerMeter(plate_info,min_power,max_power,invert) + +--]] + +return _ENV \ No newline at end of file diff --git a/plugins/power-meter.cpp b/plugins/power-meter.cpp new file mode 100644 index 000000000..0466b68e4 --- /dev/null +++ b/plugins/power-meter.cpp @@ -0,0 +1,237 @@ +#include "Core.h" +#include