Merge branch 'develop' into myk_dwarfvet

develop
Myk 2023-07-21 14:23:13 -07:00 committed by GitHub
commit 65fc79c5e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 177 additions and 35 deletions

@ -37,6 +37,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
- `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
- `dwarfvet`: reinstated and updated for v50's new hospital mechanics; allow your animals to have their wounds treated at hospitals
- `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

@ -45,6 +45,7 @@ this::
info.txt
graphics/...
objects/...
blueprints/...
scripts_modactive/example-mod.lua
scripts_modactive/internal/example-mod/...
scripts_modinstalled/...
@ -58,6 +59,9 @@ Let's go through that line by line.
- Modifications to the game raws (potentially with custom raw tokens) go in
the :file:`graphics/` and :file:`objects/` folders. You can read more about
the files that go in these directories on the :wiki:`Modding` wiki page.
- Any `quickfort` blueprints included with your mod go in the
:file:`blueprints` folder. Note that your mod can *just* be blueprints and
nothing else if you like.
- A control script in :file:`scripts_modactive/` directory that handles
system-level event hooks (e.g. reloading state when a world is loaded),
registering `overlays <overlay-dev-guide>`, and

@ -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.

@ -74,7 +74,7 @@ function list()
end
---------------------
-- mod script paths
-- mod paths
-- this perhaps could/should be queried from the Steam API
-- are there any installation configurations where this will be wrong, though?
@ -98,8 +98,8 @@ local function get_mod_id_and_version(path)
end
if not version then
-- note this doesn't include the closing brace since some people put
-- non-number characters in here, and DF only reads the digits as the
-- numeric version
-- non-number characters in here, and DF only reads the leading digits
-- as the numeric version
_,_,version = line:find('^%[NUMERIC_VERSION:(%d+)')
end
-- note that we do *not* want to break out of this loop early since
@ -108,37 +108,31 @@ local function get_mod_id_and_version(path)
return id, version
end
local function add_script_path(mod_script_paths, path)
local function add_mod_paths(mod_paths, id, base_path, subdir)
local sep = base_path:endswith('/') and '' or '/'
local path = ('%s%s%s'):format(base_path, sep, subdir)
if dfhack.filesystem.isdir(path) then
print('indexing mod scripts: ' .. path)
table.insert(mod_script_paths, path)
print('indexing mod path: ' .. path)
table.insert(mod_paths, {id=id, path=path})
end
end
local function add_script_paths(mod_script_paths, base_path, include_modactive)
if not base_path:endswith('/') then
base_path = base_path .. '/'
end
if include_modactive then
add_script_path(mod_script_paths, base_path..'scripts_modactive')
end
add_script_path(mod_script_paths, base_path..'scripts_modinstalled')
end
function get_mod_script_paths()
function get_mod_paths(installed_subdir, active_subdir)
-- ordered map of mod id -> {handled=bool, versions=map of version -> path}
local mods = utils.OrderedTable()
local mod_script_paths = {}
local mod_paths = {}
-- if a world is loaded, process active mods first, and lock to active version
if dfhack.isWorldLoaded() then
if active_subdir and dfhack.isWorldLoaded() then
for _,path in ipairs(df.global.world.object_loader.object_load_order_src_dir) do
path = tostring(path.value)
-- skip vanilla "mods"
if not path:startswith(INSTALLED_MODS_PATH) then goto continue end
local id = get_mod_id_and_version(path)
if not id then goto continue end
mods[id] = {handled=true}
add_script_paths(mod_script_paths, path, true)
add_mod_paths(mod_paths, id, path, active_subdir)
add_mod_paths(mod_paths, id, path, installed_subdir)
::continue::
end
end
@ -159,8 +153,8 @@ function get_mod_script_paths()
::skip_path_root::
end
-- add script paths from most recent version of all not-yet-handled mods
for _,v in pairs(mods) do
-- add paths from most recent version of all not-yet-handled mods
for id,v in pairs(mods) do
if v.handled then goto continue end
local max_version, path
for version,mod_path in pairs(v.versions) do
@ -169,11 +163,19 @@ function get_mod_script_paths()
max_version = version
end
end
add_script_paths(mod_script_paths, path)
add_mod_paths(mod_paths, id, path, installed_subdir)
::continue::
end
return mod_script_paths
return mod_paths
end
function get_mod_script_paths()
local paths = {}
for _,v in ipairs(get_mod_paths('scripts_modinstalled', 'scripts_modactive')) do
table.insert(paths, v.path)
end
return paths
end
return _ENV

@ -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

@ -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);
@ -31,7 +34,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 +42,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 +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;
}
@ -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
};