Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[dig] add warm/damp highlight overlay for ascii mode #3587

Merged
merged 7 commits into from
Jul 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
## New Plugins
- `3dveins`: reinstated for v50, this plugin replaces vanilla DF's blobby vein generation with veins that flow smoothly and naturally between z-levels
- `zone`: new searchable, sortable, filterable screen for assigning units to pastures
- `dig`: new ``dig.asciiwarmdamp`` overlay that highlights warm and damp tiles when in ASCII mode. there is no effect in graphics mode since the tiles are already highlighted there

## Fixes
- Fix extra keys appearing in DFHack text boxes when shift (or any other modifier) is released before the other key you were pressing
Expand Down
9 changes: 9 additions & 0 deletions docs/plugins/dig.rst
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,12 @@ 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. Box selection characters and the keyboard cursor will also
change color as appropriate when over the warm or damp tile.
29 changes: 29 additions & 0 deletions plugins/lua/dig.lua
Original file line number Diff line number Diff line change
@@ -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 = {asciiwarmdamp=WarmDampOverlay}

return _ENV
119 changes: 108 additions & 11 deletions plugins/pathable.cpp
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
#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 <functional>

using namespace DFHack;

DFHACK_PLUGIN("pathable");

REQUIRE_GLOBAL(gps);
REQUIRE_GLOBAL(init);
REQUIRE_GLOBAL(window_x);
REQUIRE_GLOBAL(window_y);
REQUIRE_GLOBAL(window_z);
REQUIRE_GLOBAL(world);

namespace DFHack {
DBG_DECLARE(pathable, log, DebugCategory::LINFO);
Expand All @@ -31,16 +34,16 @@ 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();

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;
Expand All @@ -61,7 +64,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;
}
Expand Down Expand Up @@ -110,7 +113,101 @@ static void paintScreen(df::coord target, bool skip_unrevealed = false) {
}
}

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;

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 (!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;
}

// this will also change the color of the cursor or any selection box that overlaps
// the tile. this is intentional since it makes the UI more readable
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
};