From a0919ec316aa6fb5c11890d86873f252f0834c9e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 10 Sep 2023 05:29:55 -0700 Subject: [PATCH 1/5] add ASCII-mode highlight for smoothing and carving designations --- docs/changelog.txt | 1 + docs/plugins/dig.rst | 19 ++++++-- library/include/modules/Maps.h | 6 +-- plugins/lua/dig.lua | 24 +++++++++- plugins/pathable.cpp | 80 ++++++++++++++++++++++++++++++++++ 5 files changed, 121 insertions(+), 9 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 0465609e9..3ac2e3c48 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -54,6 +54,7 @@ Template for new versions: ## New Tools ## New Features +- `dig`: new overlay for ASCII mode that visualizes designations for smoothing, engraving, carving tracks, and carving fortifications ## Fixes - `buildingplan`: make the construction dimensions readout visible again diff --git a/docs/plugins/dig.rst b/docs/plugins/dig.rst index 310bd1647..77b3137ae 100644 --- a/docs/plugins/dig.rst +++ b/docs/plugins/dig.rst @@ -183,8 +183,19 @@ After you have a pattern set, you can use ``expdig`` to apply it again. Overlay ------- -This tool also provides an overlay that is managed by the `overlay` framework. -When the ``dig.asciiwarmdamp`` overlay is enabled and you are in non-graphics -(ASCII) mode, warm tiles will be highlighted in red and damp tiles will be -highlighted in blue. Box selection characters and the keyboard cursor will also +This tool also provides two overlays that are managed by the `overlay` +framework. Both have no effect when in graphics mode, but when in ASCII mode, +they display useful highlights that are otherwise missing from the ASCII mode +interface. + +The ``dig.asciiwarmdamp`` overlay highlights warm tiles red and damp tiles in +blue. Box selection characters and the keyboard cursor will also change color as appropriate when over the warm or damp tile. + +The ``dig.asciicarve`` overlay highlights tiles that are designated for +smoothing, engraving, track carving, or fortification carving. The designations +blink so you can still see what is underneath them. + +Note that due to the limitations of the ASCII mode screen buffer, the +designation highlights may show through other interface elements that overlap +the designated area. diff --git a/library/include/modules/Maps.h b/library/include/modules/Maps.h index e468dcf9c..2b7d768d0 100644 --- a/library/include/modules/Maps.h +++ b/library/include/modules/Maps.h @@ -293,13 +293,13 @@ 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); extern DFHACK_EXPORT df::tile_occupancy *getTileOccupancy(int32_t x, int32_t y, int32_t z); -inline df::tiletype *getTileType(df::coord pos) { +inline df::tiletype *getTileType(const df::coord &pos) { return getTileType(pos.x, pos.y, pos.z); } -inline df::tile_designation *getTileDesignation(df::coord pos) { +inline df::tile_designation *getTileDesignation(const df::coord &pos) { return getTileDesignation(pos.x, pos.y, pos.z); } -inline df::tile_occupancy *getTileOccupancy(df::coord pos) { +inline df::tile_occupancy *getTileOccupancy(const df::coord &pos) { return getTileOccupancy(pos.x, pos.y, pos.z); } diff --git a/plugins/lua/dig.lua b/plugins/lua/dig.lua index 43012d5d2..e24885c08 100644 --- a/plugins/lua/dig.lua +++ b/plugins/lua/dig.lua @@ -20,10 +20,30 @@ WarmDampOverlay.ATTRS{ overlay_only=true, } -function WarmDampOverlay:onRenderFrame(dc) +function WarmDampOverlay:onRenderFrame() pathable.paintScreenWarmDamp() end -OVERLAY_WIDGETS = {asciiwarmdamp=WarmDampOverlay} +CarveOverlay = defclass(CarveOverlay, overlay.OverlayWidget) +CarveOverlay.ATTRS{ + viewscreens={ + 'dwarfmode/Designate/SMOOTH', + 'dwarfmode/Designate/ENGRAVE', + 'dwarfmode/Designate/TRACK', + 'dwarfmode/Designate/FORTIFY', + 'dwarfmode/Designate/ERASE', + }, + default_enabled=true, + overlay_only=true, +} + +function CarveOverlay:onRenderFrame() + pathable.paintScreenCarve() +end + +OVERLAY_WIDGETS = { + asciiwarmdamp=WarmDampOverlay, + asciicarve=CarveOverlay, +} return _ENV diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index 12a69dd31..83918fd4b 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -1,4 +1,5 @@ #include "Debug.h" +#include "MemAccess.h" #include "PluginManager.h" #include "TileTypes.h" @@ -209,8 +210,87 @@ static void paintScreenWarmDamp(bool show_hidden = false) { } } +static bool is_designated_for_smoothing(const df::coord &pos) { + auto des = Maps::getTileDesignation(pos); + if (!des) + return false; + return des->bits.smooth == 1; +} + +static bool is_designated_for_engraving(const df::coord &pos) { + auto des = Maps::getTileDesignation(pos); + if (!des) + return false; + return des->bits.smooth == 2; +} + +static bool is_designated_for_track_carving(const df::coord &pos) { + auto occ = Maps::getTileOccupancy(pos); + if (!occ) + return false; + return occ->bits.carve_track_east || occ->bits.carve_track_north || occ->bits.carve_track_south || occ->bits.carve_track_west; +} + +static bool is_smooth_wall(const df::coord &pos) { + df::tiletype *tt = Maps::getTileType(pos); + return tt && tileSpecial(*tt) == df::tiletype_special::SMOOTH + && tileShape(*tt) == df::tiletype_shape::WALL; +} + +static bool blink(int delay) { + return (Core::getInstance().p->getTickCount()/delay) % 2 == 0; +} + +static void paintScreenCarve() { + DEBUG(log).print("entering paintScreenCarve\n"); + + if (Screen::inGraphicsMode() || blink(500)) + return; + + auto dims = Gui::getDwarfmodeViewDims().map(); + for (int y = dims.first.y; y <= dims.second.y; ++y) { + for (int x = dims.first.x; x <= dims.second.x; ++x) { + df::coord map_pos(*window_x + x, *window_y + y, *window_z); + + if (!Maps::isValidTilePos(map_pos)) + continue; + + if (!Maps::isTileVisible(map_pos)) { + TRACE(log).print("skipping hidden tile\n"); + continue; + } + + TRACE(log).print("scanning map tile at (%d, %d, %d) screen offset (%d, %d)\n", + map_pos.x, map_pos.y, map_pos.z, x, y); + + Screen::Pen cur_tile; + cur_tile.fg = COLOR_DARKGREY; + + if (is_designated_for_smoothing(map_pos)) { + if (is_smooth_wall(map_pos)) + cur_tile.ch = 206; // hash, indicating a fortification designation + else + cur_tile.ch = 219; // solid block, indicating a smoothing designation + } + else if (is_designated_for_engraving(map_pos)) { + cur_tile.ch = 10; // solid block with a circle on it + } + else if (is_designated_for_track_carving(map_pos)) { + cur_tile.ch = 186; // parallel tracks + } + else { + TRACE(log).print("skipping tile with no carving designation\n"); + continue; + } + + Screen::paintTile(cur_tile, x, y, true); + } + } +} + DFHACK_PLUGIN_LUA_FUNCTIONS { DFHACK_LUA_FUNCTION(paintScreenPathable), DFHACK_LUA_FUNCTION(paintScreenWarmDamp), + DFHACK_LUA_FUNCTION(paintScreenCarve), DFHACK_LUA_END }; From 24b27c79b6a9f399d8cbab88bc9a4d08abd9c570 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 10 Sep 2023 12:11:06 -0700 Subject: [PATCH 2/5] draw directional tracks --- plugins/pathable.cpp | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index 83918fd4b..e63947caf 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -231,6 +231,41 @@ static bool is_designated_for_track_carving(const df::coord &pos) { return occ->bits.carve_track_east || occ->bits.carve_track_north || occ->bits.carve_track_south || occ->bits.carve_track_west; } +static char get_track_char(const df::coord &pos) { + auto occ = Maps::getTileOccupancy(pos); + if (occ->bits.carve_track_east && occ->bits.carve_track_north && occ->bits.carve_track_south && occ->bits.carve_track_west) + return 0xCE; // NSEW + if (occ->bits.carve_track_east && occ->bits.carve_track_north && occ->bits.carve_track_south) + return 0xCC; // NSE + if (occ->bits.carve_track_east && occ->bits.carve_track_north && occ->bits.carve_track_west) + return 0xCA; // NEW + if (occ->bits.carve_track_east && occ->bits.carve_track_south && occ->bits.carve_track_west) + return 0xCB; // SEW + if (occ->bits.carve_track_north && occ->bits.carve_track_south && occ->bits.carve_track_west) + return 0xB9; // NSW + if (occ->bits.carve_track_north && occ->bits.carve_track_south) + return 0xBA; // NS + if (occ->bits.carve_track_east && occ->bits.carve_track_west) + return 0xCD; // EW + if (occ->bits.carve_track_east && occ->bits.carve_track_north) + return 0xC8; // NE + if (occ->bits.carve_track_north && occ->bits.carve_track_west) + return 0xBC; // NW + if (occ->bits.carve_track_east && occ->bits.carve_track_south) + return 0xC9; // SE + if (occ->bits.carve_track_south && occ->bits.carve_track_west) + return 0xBB; // SW + if (occ->bits.carve_track_north) + return 0xD0; // N + if (occ->bits.carve_track_south) + return 0xD2; // S + if (occ->bits.carve_track_east) + return 0xC6; // E + if (occ->bits.carve_track_west) + return 0xB5; // W + return 0xC5; // single line cross; should never happen +} + static bool is_smooth_wall(const df::coord &pos) { df::tiletype *tt = Maps::getTileType(pos); return tt && tileSpecial(*tt) == df::tiletype_special::SMOOTH @@ -268,15 +303,15 @@ static void paintScreenCarve() { if (is_designated_for_smoothing(map_pos)) { if (is_smooth_wall(map_pos)) - cur_tile.ch = 206; // hash, indicating a fortification designation + cur_tile.ch = (char)206; // hash, indicating a fortification designation else - cur_tile.ch = 219; // solid block, indicating a smoothing designation + cur_tile.ch = (char)219; // solid block, indicating a smoothing designation } else if (is_designated_for_engraving(map_pos)) { - cur_tile.ch = 10; // solid block with a circle on it + cur_tile.ch = (char)10; // solid block with a circle on it } else if (is_designated_for_track_carving(map_pos)) { - cur_tile.ch = 186; // parallel tracks + cur_tile.ch = get_track_char(map_pos); // directional track } else { TRACE(log).print("skipping tile with no carving designation\n"); From a02d14bb5fcfdd0c25a9add6edd49109d5ff8755 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 10 Sep 2023 12:29:31 -0700 Subject: [PATCH 3/5] alternate drawing designation and priority --- plugins/pathable.cpp | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index e63947caf..1ba88631e 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -11,6 +11,7 @@ #include "df/init.h" #include "df/map_block.h" #include "df/tile_designation.h" +#include "df/block_square_event_designation_priorityst.h" #include @@ -276,12 +277,35 @@ static bool blink(int delay) { return (Core::getInstance().p->getTickCount()/delay) % 2 == 0; } +static char get_tile_char(const df::coord &pos, char desig_char, bool draw_priority) { + if (!draw_priority) + return desig_char; + + std::vector priorities; + Maps::SortBlockEvents(Maps::getTileBlock(pos), NULL, NULL, NULL, NULL, NULL, NULL, NULL, &priorities); + if (priorities.empty()) + return '4'; + switch (priorities[0]->priority[pos.x % 16][pos.y % 16] / 1000) { + case 1: return '1'; + case 2: return '2'; + case 3: return '3'; + case 4: return '4'; + case 5: return '5'; + case 6: return '6'; + case 7: return '7'; + default: + return '0'; + } +} + static void paintScreenCarve() { DEBUG(log).print("entering paintScreenCarve\n"); if (Screen::inGraphicsMode() || blink(500)) return; + bool draw_priority = blink(1000); + auto dims = Gui::getDwarfmodeViewDims().map(); for (int y = dims.first.y; y <= dims.second.y; ++y) { for (int x = dims.first.x; x <= dims.second.x; ++x) { @@ -303,15 +327,15 @@ static void paintScreenCarve() { if (is_designated_for_smoothing(map_pos)) { if (is_smooth_wall(map_pos)) - cur_tile.ch = (char)206; // hash, indicating a fortification designation + cur_tile.ch = get_tile_char(map_pos, 206, draw_priority); // hash, indicating a fortification designation else - cur_tile.ch = (char)219; // solid block, indicating a smoothing designation + cur_tile.ch = get_tile_char(map_pos, 219, draw_priority); // solid block, indicating a smoothing designation } else if (is_designated_for_engraving(map_pos)) { - cur_tile.ch = (char)10; // solid block with a circle on it + cur_tile.ch = get_tile_char(map_pos, 10, draw_priority); // solid block with a circle on it } else if (is_designated_for_track_carving(map_pos)) { - cur_tile.ch = get_track_char(map_pos); // directional track + cur_tile.ch = get_tile_char(map_pos, get_track_char(map_pos), draw_priority); // directional track } else { TRACE(log).print("skipping tile with no carving designation\n"); From 898e98bea762b9814ca3fa89ec615e5839ef6e4b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 10 Sep 2023 12:33:22 -0700 Subject: [PATCH 4/5] don't display priority if there is no priority block --- plugins/pathable.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index 1ba88631e..800681d56 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -284,7 +284,7 @@ static char get_tile_char(const df::coord &pos, char desig_char, bool draw_prior std::vector priorities; Maps::SortBlockEvents(Maps::getTileBlock(pos), NULL, NULL, NULL, NULL, NULL, NULL, NULL, &priorities); if (priorities.empty()) - return '4'; + return desig_char; switch (priorities[0]->priority[pos.x % 16][pos.y % 16] / 1000) { case 1: return '1'; case 2: return '2'; @@ -294,7 +294,7 @@ static char get_tile_char(const df::coord &pos, char desig_char, bool draw_prior case 6: return '6'; case 7: return '7'; default: - return '0'; + return '4'; } } From 9951e5f505e501339fc2ef9605e5e144e811827f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 10 Sep 2023 12:39:41 -0700 Subject: [PATCH 5/5] cast chars to chars --- plugins/pathable.cpp | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index 800681d56..e93905a71 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -235,36 +235,36 @@ static bool is_designated_for_track_carving(const df::coord &pos) { static char get_track_char(const df::coord &pos) { auto occ = Maps::getTileOccupancy(pos); if (occ->bits.carve_track_east && occ->bits.carve_track_north && occ->bits.carve_track_south && occ->bits.carve_track_west) - return 0xCE; // NSEW + return (char)0xCE; // NSEW if (occ->bits.carve_track_east && occ->bits.carve_track_north && occ->bits.carve_track_south) - return 0xCC; // NSE + return (char)0xCC; // NSE if (occ->bits.carve_track_east && occ->bits.carve_track_north && occ->bits.carve_track_west) - return 0xCA; // NEW + return (char)0xCA; // NEW if (occ->bits.carve_track_east && occ->bits.carve_track_south && occ->bits.carve_track_west) - return 0xCB; // SEW + return (char)0xCB; // SEW if (occ->bits.carve_track_north && occ->bits.carve_track_south && occ->bits.carve_track_west) - return 0xB9; // NSW + return (char)0xB9; // NSW if (occ->bits.carve_track_north && occ->bits.carve_track_south) - return 0xBA; // NS + return (char)0xBA; // NS if (occ->bits.carve_track_east && occ->bits.carve_track_west) - return 0xCD; // EW + return (char)0xCD; // EW if (occ->bits.carve_track_east && occ->bits.carve_track_north) - return 0xC8; // NE + return (char)0xC8; // NE if (occ->bits.carve_track_north && occ->bits.carve_track_west) - return 0xBC; // NW + return (char)0xBC; // NW if (occ->bits.carve_track_east && occ->bits.carve_track_south) - return 0xC9; // SE + return (char)0xC9; // SE if (occ->bits.carve_track_south && occ->bits.carve_track_west) - return 0xBB; // SW + return (char)0xBB; // SW if (occ->bits.carve_track_north) - return 0xD0; // N + return (char)0xD0; // N if (occ->bits.carve_track_south) - return 0xD2; // S + return (char)0xD2; // S if (occ->bits.carve_track_east) - return 0xC6; // E + return (char)0xC6; // E if (occ->bits.carve_track_west) - return 0xB5; // W - return 0xC5; // single line cross; should never happen + return (char)0xB5; // W + return (char)0xC5; // single line cross; should never happen } static bool is_smooth_wall(const df::coord &pos) { @@ -327,12 +327,12 @@ static void paintScreenCarve() { if (is_designated_for_smoothing(map_pos)) { if (is_smooth_wall(map_pos)) - cur_tile.ch = get_tile_char(map_pos, 206, draw_priority); // hash, indicating a fortification designation + cur_tile.ch = get_tile_char(map_pos, (char)206, draw_priority); // hash, indicating a fortification designation else - cur_tile.ch = get_tile_char(map_pos, 219, draw_priority); // solid block, indicating a smoothing designation + cur_tile.ch = get_tile_char(map_pos, (char)219, draw_priority); // solid block, indicating a smoothing designation } else if (is_designated_for_engraving(map_pos)) { - cur_tile.ch = get_tile_char(map_pos, 10, draw_priority); // solid block with a circle on it + cur_tile.ch = get_tile_char(map_pos, (char)10, draw_priority); // solid block with a circle on it } else if (is_designated_for_track_carving(map_pos)) { cur_tile.ch = get_tile_char(map_pos, get_track_char(map_pos), draw_priority); // directional track