From 237075080924cc01cd45ad5c7d3b4939a96ab5eb Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 20 Jul 2023 19:17:09 -0700 Subject: [PATCH] add warm/damp highlight overlay for ascii mode --- docs/plugins/dig.rst | 8 +++ plugins/lua/dig.lua | 29 +++++++++ plugins/pathable.cpp | 148 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 174 insertions(+), 11 deletions(-) create mode 100644 plugins/lua/dig.lua diff --git a/docs/plugins/dig.rst b/docs/plugins/dig.rst index a10db97df..46238add6 100644 --- a/docs/plugins/dig.rst +++ b/docs/plugins/dig.rst @@ -179,3 +179,11 @@ Filters: Take current designation and apply the selected pattern to it. 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. diff --git a/plugins/lua/dig.lua b/plugins/lua/dig.lua new file mode 100644 index 000000000..c9b8cf62b --- /dev/null +++ b/plugins/lua/dig.lua @@ -0,0 +1,29 @@ +local _ENV = mkmodule('plugins.dig') + +local overlay = require('plugins.overlay') +local pathable = require('plugins.pathable') + +WarmDampOverlay = defclass(WarmDampOverlay, overlay.OverlayWidget) +WarmDampOverlay.ATTRS{ + viewscreens={ + 'dwarfmode/Designate/DIG_DIG', + 'dwarfmode/Designate/DIG_REMOVE_STAIRS_RAMPS', + 'dwarfmode/Designate/DIG_STAIR_UP', + 'dwarfmode/Designate/DIG_STAIR_UPDOWN', + 'dwarfmode/Designate/DIG_STAIR_DOWN', + 'dwarfmode/Designate/DIG_RAMP', + 'dwarfmode/Designate/DIG_CHANNEL', + 'dwarfmode/Designate/DIG_FROM_MARKER', + 'dwarfmode/Designate/DIG_TO_MARKER', + }, + default_enabled=true, + overlay_only=true, +} + +function WarmDampOverlay:onRenderFrame(dc) + pathable.paintScreenWarmDamp() +end + +OVERLAY_WIDGETS = {overlay=WarmDampOverlay} + +return _ENV diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index 6ed890325..a7f6af0cd 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -1,23 +1,27 @@ +#include "Debug.h" +#include "PluginManager.h" +#include "TileTypes.h" + #include "modules/Gui.h" #include "modules/Maps.h" #include "modules/Screen.h" #include "modules/Textures.h" -#include "Debug.h" -#include "LuaTools.h" -#include "PluginManager.h" - #include "df/init.h" +#include "df/map_block.h" +#include "df/tile_designation.h" + +#include using namespace DFHack; DFHACK_PLUGIN("pathable"); -REQUIRE_GLOBAL(gps); +REQUIRE_GLOBAL(init); +REQUIRE_GLOBAL(selection_rect); REQUIRE_GLOBAL(window_x); REQUIRE_GLOBAL(window_y); REQUIRE_GLOBAL(window_z); -REQUIRE_GLOBAL(world); namespace DFHack { DBG_DECLARE(pathable, log, DebugCategory::LINFO); @@ -31,7 +35,7 @@ DFhackCExport command_result plugin_shutdown(color_ostream &out) { return CR_OK; } -static void paintScreen(df::coord target, bool skip_unrevealed = false) { +static void paintScreenPathable(df::coord target, bool show_hidden = false) { DEBUG(log).print("entering paintScreen\n"); bool use_graphics = Screen::inGraphicsMode(); @@ -39,8 +43,8 @@ static void paintScreen(df::coord target, bool skip_unrevealed = false) { int selected_tile_texpos = 0; Screen::findGraphicsTile("CURSORS", 4, 3, &selected_tile_texpos); - long pathable_tile_texpos = df::global::init->load_bar_texpos[1]; - long unpathable_tile_texpos = df::global::init->load_bar_texpos[4]; + long pathable_tile_texpos = init->load_bar_texpos[1]; + long unpathable_tile_texpos = init->load_bar_texpos[4]; long on_off_texpos = Textures::getMapPathableTexposStart(); if (on_off_texpos > 0) { pathable_tile_texpos = on_off_texpos + 0; @@ -61,7 +65,7 @@ static void paintScreen(df::coord target, bool skip_unrevealed = false) { continue; } - if (skip_unrevealed && !Maps::isTileVisible(map_pos)) { + if (!show_hidden && !Maps::isTileVisible(map_pos)) { TRACE(log).print("skipping hidden tile\n"); continue; } @@ -110,7 +114,129 @@ static void paintScreen(df::coord target, bool skip_unrevealed = false) { } } +static bool init_mouse_selection_rect(rect2d &rect) { + df::coord mouse_pos = Gui::getMousePos(); + if (!mouse_pos.isValid()) + return false; + rect.first.x = std::min(selection_rect->start_x, (int32_t)mouse_pos.x); + rect.second.x = std::max(selection_rect->start_x, (int32_t)mouse_pos.x); + rect.first.y = std::min(selection_rect->start_y, (int32_t)mouse_pos.y); + rect.second.y = std::max(selection_rect->start_y, (int32_t)mouse_pos.y); + return true; +} + +static bool in_mouse_selection_rect(const rect2d &rect, const df::coord &pos) { + return ((pos.y == rect.first.y || pos.y == rect.second.y) && (pos.x >= rect.first.x || pos.x <= rect.second.x)) || + ((pos.x == rect.first.x || pos.x == rect.second.x) && (pos.y >= rect.first.y || pos.y <= rect.second.y)); +} + +static bool is_warm(const df::coord &pos) { + auto block = Maps::getTileBlock(pos); + if (!block) + return false; + return block->temperature_1[pos.x&15][pos.y&15] >= 10075; +} + +static bool is_rough_wall(int16_t x, int16_t y, int16_t z) { + df::tiletype *tt = Maps::getTileType(x, y, z); + if (!tt) + return false; + + return tileShape(*tt) == df::tiletype_shape::WALL && + tileSpecial(*tt) != df::tiletype_special::SMOOTH; +} + +static bool will_leak(int16_t x, int16_t y, int16_t z) { + auto des = Maps::getTileDesignation(x, y, z); + if (!des) + return false; + if (des->bits.liquid_type == df::tile_liquid::Water && des->bits.flow_size >= 1) + return true; + if (des->bits.water_table && is_rough_wall(x, y, z)) + return true; + return false; +} + +static bool is_damp(const df::coord &pos) { + return will_leak(pos.x-1, pos.y-1, pos.z) || + will_leak(pos.x, pos.y-1, pos.z) || + will_leak(pos.x+1, pos.y-1, pos.z) || + will_leak(pos.x-1, pos.y, pos.z) || + will_leak(pos.x+1, pos.y, pos.z) || + will_leak(pos.x-1, pos.y+1, pos.z) || + will_leak(pos.x, pos.y+1, pos.z) || + will_leak(pos.x+1, pos.y+1, pos.z); + will_leak(pos.x, pos.y+1, pos.z+1); +} + +static void paintScreenWarmDamp(bool show_hidden = false) { + DEBUG(log).print("entering paintScreenDampWarm\n"); + + if (Screen::inGraphicsMode()) + return; + + bool has_mouse_selection_rect = selection_rect->start_x >= 0; + rect2d mouse_sel_rect; + if (has_mouse_selection_rect) { + has_mouse_selection_rect = init_mouse_selection_rect(mouse_sel_rect); + } + + bool has_kbd_selection_rect = false; // TODO where is this info stored? + + 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; + + // don't overwrite selection box tiles + if (has_mouse_selection_rect && in_mouse_selection_rect(mouse_sel_rect, map_pos)) { + TRACE(log).print("skipping mouse selection box tile\n"); + continue; + } + + if (!show_hidden && !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 = Screen::readTile(x, y, true); + if (!cur_tile.valid()) { + DEBUG(log).print("cannot read tile at offset %d, %d\n", x, y); + continue; + } + + int color = is_warm(map_pos) ? COLOR_RED : is_damp(map_pos) ? COLOR_BLUE : COLOR_BLACK; + if (color == COLOR_BLACK) { + TRACE(log).print("skipping non-warm, non-damp tile\n"); + continue; + } + + if (cur_tile.fg && cur_tile.ch != ' ') { + cur_tile.fg = color; + cur_tile.bg = 0; + } else { + cur_tile.fg = 0; + cur_tile.bg = color; + } + + cur_tile.bold = false; + + if (cur_tile.tile) + cur_tile.tile_mode = Screen::Pen::CharColor; + + Screen::paintTile(cur_tile, x, y, true); + } + } +} + DFHACK_PLUGIN_LUA_FUNCTIONS { - DFHACK_LUA_FUNCTION(paintScreen), + DFHACK_LUA_FUNCTION(paintScreenPathable), + DFHACK_LUA_FUNCTION(paintScreenWarmDamp), DFHACK_LUA_END };