Merge branch 'develop' into myk_no_stuck_df_viewscreens

develop
Myk 2023-01-28 12:03:50 -08:00 committed by GitHub
commit 2003efc21f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 204 additions and 167 deletions

@ -37,7 +37,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
## Fixes ## Fixes
-@ Ensure DF windows don't get "stuck" on transitions when DFHack tool windows are visible. Instead, those DF screens are force-paused while DFHack windows are visible so the player can close them first and not corrupt the screen sequence. The "force pause" indicator will appear on these DFHack windows to indicate what is happening. -@ Ensure DF windows don't get "stuck" on transitions when DFHack tool windows are visible. Instead, those DF screens are force-paused while DFHack windows are visible so the player can close them first and not corrupt the screen sequence. The "force pause" indicator will appear on these DFHack windows to indicate what is happening.
- Fix issues with clicks "passing through" some DFHack window elements, like scrollbars -@ Fix issues with clicks "passing through" some DFHack window elements, like scrollbars
## Misc Improvements ## Misc Improvements
- A new cross-compile build script was added for building the Windows files from a Linux Docker builder (see the Compile instructions in the docs) - A new cross-compile build script was added for building the Windows files from a Linux Docker builder (see the Compile instructions in the docs)
@ -47,10 +47,12 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
- `gui/quickcmd`: now has it's own global keybinding for your convenience: Ctrl-Shift-A - `gui/quickcmd`: now has it's own global keybinding for your convenience: Ctrl-Shift-A
- Many DFHack windows can now be unfocused by clicking somewhere not over the tool window. This has the same effect as pinning previously did, but without the extra clicking. - Many DFHack windows can now be unfocused by clicking somewhere not over the tool window. This has the same effect as pinning previously did, but without the extra clicking.
- `overlay`: overlay widgets can now specify a default enabled state if they are not already set in the player's overlay config file - `overlay`: overlay widgets can now specify a default enabled state if they are not already set in the player's overlay config file
-@ New borders for DFHack tool windows -- tell us what you think!
## Documentation ## Documentation
## API ## API
- ``Buildings::containsTile()``: no longer takes a ``room`` parameter since that's not how rooms work anymore. If the building has extents, the extents will be checked. otherwise, the result just depends on whether the tile is within the building's bounding box.
## Lua ## Lua
- `helpdb`: new function: ``helpdb.refresh()`` to force a refresh of the database. Call if you are a developer adding new scripts, loading new plugins, or changing help text during play - `helpdb`: new function: ``helpdb.refresh()`` to force a refresh of the database. Call if you are a developer adding new scripts, loading new plugins, or changing help text during play

@ -1933,9 +1933,11 @@ General
Returns the number of tiles included by extents, or defval. Returns the number of tiles included by extents, or defval.
* ``dfhack.buildings.containsTile(building, x, y[, room])`` * ``dfhack.buildings.containsTile(building, x, y)``
Checks if the building contains the specified tile, either directly, or as room. Checks if the building contains the specified tile. If the building contains extents,
then the extents are checked. Otherwise, returns whether the x and y map coordinates
are within the building's bounding box.
* ``dfhack.buildings.hasSupport(pos,size)`` * ``dfhack.buildings.hasSupport(pos,size)``
@ -5603,6 +5605,13 @@ sort
The `sort <sort>` plugin does not export any native functions as of now. The `sort <sort>` plugin does not export any native functions as of now.
Instead, it calls Lua code to perform the actual ordering of list items. Instead, it calls Lua code to perform the actual ordering of list items.
tiletypes
=========
* ``bool tiletypes_setTile(pos, shape, material, special, variant)`` where
the parameters are enum values from ``df.tiletype_shape``,
``df.tiletype_material``, etc. Returns whether the conversion succeeded.
.. _xlsxreader-api: .. _xlsxreader-api:
xlsxreader xlsxreader

@ -2234,8 +2234,8 @@ static const luaL_Reg dfhack_burrows_funcs[] = {
/***** Buildings module *****/ /***** Buildings module *****/
static bool buildings_containsTile(df::building *bld, int x, int y, bool room) { static bool buildings_containsTile(df::building *bld, int x, int y) {
return Buildings::containsTile(bld, df::coord2d(x,y), room); return Buildings::containsTile(bld, df::coord2d(x,y));
} }
static const LuaWrapper::FunctionReg dfhack_buildings_module[] = { static const LuaWrapper::FunctionReg dfhack_buildings_module[] = {

@ -151,9 +151,11 @@ DFHACK_EXPORT bool checkFreeTiles(df::coord pos, df::coord2d size,
DFHACK_EXPORT int countExtentTiles(df::building_extents *ext, int defval = -1); DFHACK_EXPORT int countExtentTiles(df::building_extents *ext, int defval = -1);
/** /**
* Checks if the building contains the specified tile. * Checks if the building contains the specified tile. If the building has
* extents, returns whether tile is included within the extents. The x and y in
* tile are the map coordinates without the z component.
*/ */
DFHACK_EXPORT bool containsTile(df::building *bld, df::coord2d tile, bool room = false); DFHACK_EXPORT bool containsTile(df::building *bld, df::coord2d tile);
/** /**
* Checks if the area has support from the terrain. * Checks if the area has support from the terrain.

@ -902,13 +902,17 @@ THIN_FRAME = make_frame('Thin', false)
-- for compatibility with pre-steam code -- for compatibility with pre-steam code
GREY_LINE_FRAME = WINDOW_FRAME GREY_LINE_FRAME = WINDOW_FRAME
function paint_frame(dc,rect,style,title,inactive, pause_forced) function paint_frame(dc,rect,style,title,inactive,pause_forced,resizable)
local pen = style.frame_pen local pen = style.frame_pen
local x1,y1,x2,y2 = dc.x1+rect.x1, dc.y1+rect.y1, dc.x1+rect.x2, dc.y1+rect.y2 local x1,y1,x2,y2 = dc.x1+rect.x1, dc.y1+rect.y1, dc.x1+rect.x2, dc.y1+rect.y2
dscreen.paintTile(style.lt_frame_pen or pen, x1, y1) dscreen.paintTile(style.lt_frame_pen or pen, x1, y1)
dscreen.paintTile(style.rt_frame_pen or pen, x2, y1) dscreen.paintTile(style.rt_frame_pen or pen, x2, y1)
dscreen.paintTile(style.lb_frame_pen or pen, x1, y2) dscreen.paintTile(style.lb_frame_pen or pen, x1, y2)
dscreen.paintTile(style.rb_frame_pen or pen, x2, y2) local rb_frame_pen = style.rb_frame_pen
if rb_frame_pen == WINDOW_FRAME.rb_frame_pen and not resizable then
rb_frame_pen = PANEL_FRAME.rb_frame_pen
end
dscreen.paintTile(rb_frame_pen or pen, x2, y2)
dscreen.fillRect(style.t_frame_pen or style.h_frame_pen or pen,x1+1,y1,x2-1,y1) dscreen.fillRect(style.t_frame_pen or style.h_frame_pen or pen,x1+1,y1,x2-1,y1)
dscreen.fillRect(style.b_frame_pen or style.h_frame_pen or pen,x1+1,y2,x2-1,y2) dscreen.fillRect(style.b_frame_pen or style.h_frame_pen or pen,x1+1,y2,x2-1,y2)
dscreen.fillRect(style.l_frame_pen or style.v_frame_pen or pen,x1,y1+1,x1,y2-1) dscreen.fillRect(style.l_frame_pen or style.v_frame_pen or pen,x1,y1+1,x1,y2-1)

@ -502,7 +502,7 @@ function Panel:onRenderFrame(dc, rect)
and not self.parent_view:hasFocus() and not self.parent_view:hasFocus()
local pause_forced = self.parent_view and self.parent_view.force_pause local pause_forced = self.parent_view and self.parent_view.force_pause
gui.paint_frame(dc, rect, self.frame_style, self.frame_title, inactive, gui.paint_frame(dc, rect, self.frame_style, self.frame_title, inactive,
pause_forced) pause_forced, self.resizable)
if self.kbd_get_pos then if self.kbd_get_pos then
local pos = self.kbd_get_pos() local pos = self.kbd_get_pos()
local pen = to_pen{fg=COLOR_GREEN, bg=COLOR_BLACK} local pen = to_pen{fg=COLOR_GREEN, bg=COLOR_BLACK}

@ -407,7 +407,7 @@ df::building *Buildings::findAtTile(df::coord pos)
if (building && building->z == pos.z && if (building && building->z == pos.z &&
building->isSettingOccupancy() && building->isSettingOccupancy() &&
containsTile(building, pos, false)) containsTile(building, pos))
{ {
return building; return building;
} }
@ -442,23 +442,18 @@ df::building *Buildings::findAtTile(df::coord pos)
static unordered_map<int32_t, df::coord> corner1; static unordered_map<int32_t, df::coord> corner1;
static unordered_map<int32_t, df::coord> corner2; static unordered_map<int32_t, df::coord> corner2;
static void cacheBuilding(df::building *building, bool is_civzone) { static void cacheBuilding(df::building *building) {
int32_t id = building->id; int32_t id = building->id;
df::coord p1(min(building->x1, building->x2), min(building->y1,building->y2), building->z); df::coord p1(min(building->x1, building->x2), min(building->y1,building->y2), building->z);
df::coord p2(max(building->x1, building->x2), max(building->y1,building->y2), building->z); df::coord p2(max(building->x1, building->x2), max(building->y1,building->y2), building->z);
if (!is_civzone) {
// civzones can be dynamically shrunk so we don't bother to cache
// their boundaries. findCivzonesAt() will trim the cache as needed.
corner1[id] = p1; corner1[id] = p1;
corner2[id] = p2; corner2[id] = p2;
}
for (int32_t x = p1.x; x <= p2.x; x++) { for (int32_t x = p1.x; x <= p2.x; x++) {
for (int32_t y = p1.y; y <= p2.y; y++) { for (int32_t y = p1.y; y <= p2.y; y++) {
df::coord pt(x, y, building->z); df::coord pt(x, y, building->z);
if (Buildings::containsTile(building, pt, is_civzone)) { if (Buildings::containsTile(building, pt)) {
if (!is_civzone)
locationToBuilding[pt] = id; locationToBuilding[pt] = id;
} }
} }
@ -868,31 +863,16 @@ int Buildings::countExtentTiles(df::building_extents *ext, int defval)
return cnt; return cnt;
} }
bool Buildings::containsTile(df::building *bld, df::coord2d tile, bool room) bool Buildings::containsTile(df::building *bld, df::coord2d tile) {
{
CHECK_NULL_POINTER(bld); CHECK_NULL_POINTER(bld);
if (room) if (!bld->isExtentShaped() || !bld->room.extents) {
{
/* TODO: understand how this changes for v50
if (!bld->is_room || !bld->room.extents)
return false;
*/
}
else
{
if (tile.x < bld->x1 || tile.x > bld->x2 || tile.y < bld->y1 || tile.y > bld->y2) if (tile.x < bld->x1 || tile.x > bld->x2 || tile.y < bld->y1 || tile.y > bld->y2)
return false; return false;
} }
if (bld->room.extents && (room || bld->isExtentShaped()))
{
df::building_extents_type *etile = getExtentTile(bld->room, tile); df::building_extents_type *etile = getExtentTile(bld->room, tile);
if (!etile || !*etile) return etile && *etile;
return false;
}
return true;
} }
bool Buildings::hasSupport(df::coord pos, df::coord2d size) bool Buildings::hasSupport(df::coord pos, df::coord2d size)
@ -1491,7 +1471,7 @@ void Buildings::updateBuildings(color_ostream&, void* ptr)
{ {
bool is_civzone = !building->isSettingOccupancy(); bool is_civzone = !building->isSettingOccupancy();
if (!corner1.count(id) && !is_civzone) if (!corner1.count(id) && !is_civzone)
cacheBuilding(building, false); cacheBuilding(building);
} }
else if (corner1.count(id)) else if (corner1.count(id))
{ {
@ -1697,7 +1677,7 @@ StockpileIterator& StockpileIterator::operator++() {
continue; continue;
} }
if (!Buildings::containsTile(stockpile, item->pos, false)) { if (!Buildings::containsTile(stockpile, item->pos)) {
continue; continue;
} }

@ -9,7 +9,6 @@
#include "Console.h" #include "Console.h"
#include "Export.h" #include "Export.h"
#include "PluginManager.h" #include "PluginManager.h"
#include "uicommon.h"
#include "modules/Gui.h" #include "modules/Gui.h"
#include "modules/MapCache.h" #include "modules/MapCache.h"
@ -213,7 +212,7 @@ bool lineY (MapExtras::MapCache & MCache,
int32_t parse_priority(color_ostream &out, vector<string> &parameters) int32_t parse_priority(color_ostream &out, vector<string> &parameters)
{ {
int32_t default_priority = game->designation.priority; int32_t default_priority = game->main_interface.designation.priority;
for (auto it = parameters.begin(); it != parameters.end(); ++it) for (auto it = parameters.begin(); it != parameters.end(); ++it)
{ {

@ -259,7 +259,7 @@ struct TileType
inline bool matches(const df::tiletype source, inline bool matches(const df::tiletype source,
const df::tile_designation des, const df::tile_designation des,
const t_matpair mat) const t_matpair mat) const
{ {
bool rv = true; bool rv = true;
rv &= (shape == -1 || shape == tileShape(source)); rv &= (shape == -1 || shape == tileShape(source));
@ -735,93 +735,37 @@ bool processTileType(color_ostream & out, TileType &paint, std::vector<std::stri
return found; return found;
} }
command_result executePaintJob(color_ostream &out, static bool paintTile(MapExtras::MapCache &map, const df::coord &pos,
const tiletypes_options &opts) const TileType &target, const TileType &match = TileType()) {
{ MapExtras::Block *blk = map.BlockAtTile(pos);
if (paint.empty())
{
out.printerr("Set the paint first.\n");
return CR_OK;
}
CoreSuspender suspend;
if (!Maps::IsValid())
{
out.printerr("Map is not available!\n");
return CR_FAILURE;
}
uint32_t x_max = 0, y_max = 0, z_max = 0;
Maps::getSize(x_max, y_max, z_max);
df::coord cursor;
if (Maps::isValidTilePos(opts.cursor))
{
cursor = opts.cursor;
}
else
{
cursor = Gui::getCursorPos();
if (!cursor.isValid())
{
out.printerr("Can't get cursor coords! Make sure you have a cursor active in DF or specify the --cursor option.\n");
return CR_FAILURE;
}
}
if (!opts.quiet)
out.print("Cursor coords: (%d, %d, %d)\n",
cursor.x, cursor.y, cursor.z);
MapExtras::MapCache map;
coord_vec all_tiles = brush->points(map, cursor);
if (!opts.quiet)
out.print("working...\n");
// Force the game to recompute its walkability cache
world->reindex_pathfinding = true;
int failures = 0;
for (coord_vec::iterator iter = all_tiles.begin(); iter != all_tiles.end(); ++iter)
{
MapExtras::Block *blk = map.BlockAtTile(*iter);
if (!blk) if (!blk)
continue; return false;
df::tiletype source = map.tiletypeAt(*iter); df::tiletype source = map.tiletypeAt(pos);
df::tile_designation des = map.designationAt(*iter); df::tile_designation des = map.designationAt(pos);
// Stone painting operates on the base layer // Stone painting operates on the base layer
if (paint.stone_material >= 0) if (target.stone_material >= 0)
source = blk->baseTiletypeAt(*iter); source = blk->baseTiletypeAt(pos);
t_matpair basemat = blk->baseMaterialAt(*iter); t_matpair basemat = blk->baseMaterialAt(pos);
if (!filter.matches(source, des, basemat)) if (!match.matches(source, des, basemat))
{ return true;
continue;
}
df::tiletype_shape shape = paint.shape; df::tiletype_shape shape = target.shape;
if (shape == tiletype_shape::NONE) if (shape == tiletype_shape::NONE)
{
shape = tileShape(source); shape = tileShape(source);
}
df::tiletype_material material = paint.material; df::tiletype_material material = target.material;
if (material == tiletype_material::NONE) if (material == tiletype_material::NONE)
{
material = tileMaterial(source); material = tileMaterial(source);
}
df::tiletype_special special = paint.special; df::tiletype_special special = target.special;
if (special == tiletype_special::NONE) if (special == tiletype_special::NONE)
{
special = tileSpecial(source); special = tileSpecial(source);
}
df::tiletype_variant variant = paint.variant; df::tiletype_variant variant = target.variant;
/* /*
* FIXME: variant should be: * FIXME: variant should be:
* 1. If user variant: * 1. If user variant:
@ -848,52 +792,37 @@ command_result executePaintJob(color_ostream &out,
// Remove direction from directionless tiles // Remove direction from directionless tiles
DFHack::TileDirection direction = tileDirection(source); DFHack::TileDirection direction = tileDirection(source);
if (!(material == tiletype_material::RIVER || shape == tiletype_shape::BROOK_BED || special == tiletype_special::TRACK || (shape == tiletype_shape::WALL && (material == tiletype_material::CONSTRUCTION || special == tiletype_special::SMOOTH)))) if (!(material == tiletype_material::RIVER || shape == tiletype_shape::BROOK_BED || special == tiletype_special::TRACK || (shape == tiletype_shape::WALL && (material == tiletype_material::CONSTRUCTION || special == tiletype_special::SMOOTH))))
{
direction.whole = 0; direction.whole = 0;
}
df::tiletype type = DFHack::findTileType(shape, material, variant, special, direction); df::tiletype type = DFHack::findTileType(shape, material, variant, special, direction);
// hack for empty space // hack for empty space
if (shape == tiletype_shape::EMPTY && material == tiletype_material::AIR && variant == tiletype_variant::VAR_1 && special == tiletype_special::NORMAL && direction.whole == 0) if (shape == tiletype_shape::EMPTY && material == tiletype_material::AIR && variant == tiletype_variant::VAR_1 && special == tiletype_special::NORMAL && direction.whole == 0)
{
type = tiletype::OpenSpace; type = tiletype::OpenSpace;
}
// make sure it's not invalid // make sure it's not invalid
if(type != tiletype::Void) if (type != tiletype::Void) {
{ if (target.stone_material >= 0) {
if (paint.stone_material >= 0) if (!blk->setStoneAt(pos, type, target.stone_material, target.vein_type, true, true))
{ return false;
if (!blk->setStoneAt(*iter, type, paint.stone_material, paint.vein_type, true, true))
failures++;
} }
else else
map.setTiletypeAt(*iter, type); map.setTiletypeAt(pos, type);
} }
if (paint.hidden > -1) if (target.hidden > -1)
{ des.bits.hidden = target.hidden;
des.bits.hidden = paint.hidden;
}
if (paint.light > -1) if (target.light > -1)
{ des.bits.light = target.light;
des.bits.light = paint.light;
}
if (paint.subterranean > -1) if (target.subterranean > -1)
{ des.bits.subterranean = target.subterranean;
des.bits.subterranean = paint.subterranean;
}
if (paint.skyview > -1) if (target.skyview > -1)
{ des.bits.outside = target.skyview;
des.bits.outside = paint.skyview;
}
if (paint.aquifer > -1) if (target.aquifer > -1)
{ des.bits.water_table = target.aquifer;
des.bits.water_table = paint.aquifer;
}
// Remove liquid from walls, etc // Remove liquid from walls, etc
if (type != (df::tiletype)-1 && !DFHack::FlowPassable(type)) if (type != (df::tiletype)-1 && !DFHack::FlowPassable(type))
@ -907,7 +836,63 @@ command_result executePaintJob(color_ostream &out,
//des.bits.water_salt = 0; //des.bits.water_salt = 0;
} }
map.setDesignationAt(*iter, des); map.setDesignationAt(pos, des);
return true;
}
command_result executePaintJob(color_ostream &out,
const tiletypes_options &opts)
{
if (paint.empty())
{
out.printerr("Set the paint first.\n");
return CR_OK;
}
CoreSuspender suspend;
if (!Maps::IsValid())
{
out.printerr("Map is not available!\n");
return CR_FAILURE;
}
uint32_t x_max = 0, y_max = 0, z_max = 0;
Maps::getSize(x_max, y_max, z_max);
df::coord cursor;
if (Maps::isValidTilePos(opts.cursor))
{
cursor = opts.cursor;
}
else
{
cursor = Gui::getCursorPos();
if (!cursor.isValid())
{
out.printerr("Can't get cursor coords! Make sure you have a cursor active in DF or specify the --cursor option.\n");
return CR_FAILURE;
}
}
if (!opts.quiet)
out.print("Cursor coords: (%d, %d, %d)\n",
cursor.x, cursor.y, cursor.z);
MapExtras::MapCache map;
coord_vec all_tiles = brush->points(map, cursor);
if (!opts.quiet)
out.print("working...\n");
// Force the game to recompute its walkability cache
world->reindex_pathfinding = true;
int failures = 0;
for (coord_vec::iterator iter = all_tiles.begin(); iter != all_tiles.end(); ++iter)
{
if (!paintTile(map, *iter, paint, filter))
++failures;
} }
if (failures > 0) if (failures > 0)
@ -1135,3 +1120,59 @@ command_result df_tiletypes_here_point (color_ostream &out, vector <string> & pa
brush = old; brush = old;
return rv; return rv;
} }
static bool setTile(color_ostream &out, df::coord pos, df::tiletype_shape shape,
df::tiletype_material material, df::tiletype_special special,
df::tiletype_variant variant) {
if (!Maps::isValidTilePos(pos)) {
out.printerr("Invalid map position: %d, %d, %d\n", pos.x, pos.y, pos.z);
return false;
}
if (!is_valid_enum_item(shape)) {
out.printerr("Invalid shape type: %d\n", shape);
return false;
}
if (!is_valid_enum_item(material)) {
out.printerr("Invalid material type: %d\n", material);
return false;
}
if (!is_valid_enum_item(special)) {
out.printerr("Invalid special type: %d\n", special);
return false;
}
if (!is_valid_enum_item(variant)) {
out.printerr("Invalid variant type: %d\n", variant);
return false;
}
TileType target;
target.shape = shape;
target.material = material;
target.special = special;
target.variant = variant;
MapExtras::MapCache map;
return paintTile(map, pos, target) && map.WriteAll();
}
static int tiletypes_setTile(lua_State *L) {
color_ostream *out = Lua::GetOutput(L);
if (!out)
out = &Core::getInstance().getConsole();
df::coord pos;
Lua::CheckDFAssign(L, &pos, 1);
df::tiletype_shape shape = (df::tiletype_shape)lua_tointeger(L, 2);
df::tiletype_material material = (df::tiletype_material)lua_tointeger(L, 3);
df::tiletype_special special = (df::tiletype_special)lua_tointeger(L, 4);
df::tiletype_variant variant = (df::tiletype_variant)lua_tointeger(L, 5);
Lua::Push(L, setTile(*out, pos, shape, material, special, variant));
return 1;
}
DFHACK_PLUGIN_LUA_COMMANDS {
DFHACK_LUA_COMMAND(tiletypes_setTile),
DFHACK_LUA_END
};