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

Overhaul cleaners plugin; Add Maps::isPlantInBox #4949

Open
wants to merge 36 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
79364de
Update Lua API.rst - maps.isPlantInBox
Bumber64 Sep 20, 2024
8081985
Update cleaners.rst
Bumber64 Sep 20, 2024
174aa2e
Update regrass.rst - Talk about cleaners remove grass
Bumber64 Sep 20, 2024
96ab31d
Update LuaApi.cpp - Add maps.isPlantInBox
Bumber64 Sep 20, 2024
da108ee
Update Maps.h - isPlantInBox
Bumber64 Sep 20, 2024
b5dbea2
Update tile-material.lua - Use getPlantAtTile; handle roots
Bumber64 Sep 20, 2024
8f10e8e
Update Maps.cpp - isPlantInBox
Bumber64 Sep 20, 2024
ad11f48
Update CMakeLists.txt - cleaners link lua
Bumber64 Sep 20, 2024
e3a529a
Update burrow.cpp - Use Maps::forCoord; use using better
Bumber64 Sep 20, 2024
d165e27
Update plant.cpp - Move utility fn to Maps module
Bumber64 Sep 20, 2024
86f98b0
Update regrass.cpp - Maps::isValid is cleaner
Bumber64 Sep 20, 2024
4bd5bec
Create cleaners.lua
Bumber64 Sep 20, 2024
a4ccb44
Update cleaners.cpp
Bumber64 Sep 20, 2024
9ac1ded
Update cleaners.cpp - Remove plant cleaning (just rainwater)
Bumber64 Sep 20, 2024
f910c0c
Update changelog.txt
Bumber64 Sep 20, 2024
6375c92
Update changelog.txt
Bumber64 Sep 20, 2024
f89fc3c
Update cleaners.cpp - Fix print size_t
Bumber64 Sep 20, 2024
961ceb8
Update cleaners.cpp - Really fix print size_t
Bumber64 Sep 20, 2024
3876041
Merge branch 'DFHack:develop' into cleaners_etc
Bumber64 Sep 26, 2024
317eaf3
Merge branch 'DFHack:develop' into cleaners_etc
Bumber64 Sep 27, 2024
244e848
Tidy up docs
Bumber64 Sep 27, 2024
9b1b880
More doc tidying
Bumber64 Sep 27, 2024
ed4e3e0
Update regrass.rst - Minor wording change
Bumber64 Sep 27, 2024
6d26265
Update regrass.rst
Bumber64 Sep 27, 2024
e121d8f
Fix changelog.txt
Bumber64 Dec 8, 2024
a2e1e68
Merge branch 'develop' into cleaners_etc
Bumber64 Dec 8, 2024
0c651d7
Merge branch 'develop' into cleaners_etc
Bumber64 Dec 11, 2024
7b30129
Fix changelog.txt
Bumber64 Dec 11, 2024
82ec22e
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 11, 2024
82738b4
Merge branch 'develop' into cleaners_etc
Bumber64 Dec 15, 2024
28f7fca
Update cleaners.cpp
Bumber64 Dec 27, 2024
7ecb7b7
Requested changes
Bumber64 Dec 27, 2024
79bdff8
Merge branch 'develop' into cleaners_etc
Bumber64 Dec 27, 2024
2519439
Update cleaners.cpp
Bumber64 Dec 27, 2024
9f73167
Update cleaners.cpp
Bumber64 Dec 27, 2024
16b311b
Merge branch 'develop' into cleaners_etc
Bumber64 Jan 4, 2025
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
3 changes: 3 additions & 0 deletions docs/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ Template for new versions:
## New Tools

## New Features
- `clean`: positional options to limit cleaning to a cuboid area. Options to remove grass or skip blood spatter removal.
- `stockpiles`: add simple import/export dialogs to stockpile overlay panel

## Fixes
Expand All @@ -69,10 +70,12 @@ Template for new versions:
- Added example code for creating plugin RPC endpoints that can be used to extend the DFHack API

## API
- ``Maps::isPlantInBox``: function to determine if a plant is present in a cuboid.
- ``Units::isUnitInBox``, ``Units::getUnitsInBox``: add versions accepting pos arguments
- ``Units::getVisibleName``: when acting on a unit without an impersonated identity, returns the unit's name structure instead of the associated histfig's name structure

## Lua
- ``dfhack.maps.isPlantInBox``: function to determine if a plant is present in a cuboid.
- ``dfhack.units.isUnitInBox``, ``dfhack.units.getUnitsInBox``: add versions accepting pos arguments
- ``widgets.FilteredList``: search keys for list items can now be functions that return a string

Expand Down
7 changes: 7 additions & 0 deletions docs/dev/Lua API.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2307,6 +2307,13 @@ Maps module

Returns the plant struct that owns the tile at the specified position.

* ``dfhack.maps.isPlantInBox(plant, pos1, pos2)``
* ``dfhack.maps.isPlantInBox(plant,x1,y1,z1,x2,y2,z2)``
Bumber64 marked this conversation as resolved.
Show resolved Hide resolved

Returns true if the plant is within a box defined by the specified
coordinates. For trees, returns true if any part of the tree is within
the box.

* ``dfhack.maps.getWalkableGroup(pos)``

Returns the walkability group for the given tile position. A return value
Expand Down
141 changes: 113 additions & 28 deletions docs/plugins/cleaners.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,57 +5,142 @@ cleaners
========

.. dfhack-tool::
:summary: Provides commands for cleaning spatter from the map.
:tags: adventure fort armok fps items map units
:summary: Cleans spatter and/or grass from map tiles.
:tags: adventure fort armok fps items map plants units
:no-command:

.. dfhack-command:: clean
:summary: Removes contaminants.

.. dfhack-command:: spotclean
:summary: Remove all contaminants from the tile under the cursor.
:summary: Remove contaminants from the tile under the cursor.
Bumber64 marked this conversation as resolved.
Show resolved Hide resolved

This plugin provides commands that clean the splatter that get scattered all
This plugin provides commands that clean the spatter that gets scattered all
over the map and that clings to your items and units. In an old fortress,
cleaning with this tool can significantly reduce FPS lag! It can also spoil your
!!FUN!!, so think before you use it.
cleaning with this tool can significantly reduce FPS lag! It can also spoil
your !!FUN!!, so think before you use it.

This plugin can also be used to remove grass in an area you don't want it
(including those hard to reach areas like stairs and under buildings).
Use it if you messed up with the `regrass` tool, or grass grew in your
dining hall after a flooding mishap. Grass may eventually regrow if the tile
remains soil, so `gui/tiletypes` may come in handy to change it to an
appropriate stone type.

Usage
-----

::

clean all|map|items|units|plants [<options>]
clean [<pos> [<pos>]] [<options>]
spotclean

By default, cleaning the map leaves mud and snow alone. Note that cleaning units
includes hostiles, and that cleaning items removes poisons from weapons.
By default, cleaning the map leaves mud, snow, and item spatter (e.g., tree
droppings) alone. Note that cleaning units includes hostiles, and that
cleaning items removes poisons from weapons.

Mud will not be cleaned out from under farm plots unless the tile is furrowed
soil, since that would render the plot inoperable.

Operates on the entire map unless otherwise specified. Supplying a ``pos``
argument can limit operation to a single tile. Supplying both can operate on
a cuboid region. ``pos`` should normally be in the form ``0,0,0``, without
spaces. The string ``here`` can be used in place of numeric coordinates to use
the position of the keyboard cursor, if active. The ``--zlevel`` option uses
the ``pos`` values differently.

``spotclean`` works like ``clean map snow mud``, removing all contaminants from
the tile under the keyboard cursor. This is ideal if you just want to clean a
specific tile but don't want the `clean <cleaners>` command to remove all the
glorious blood from your entranceway.
``spotclean`` works like ``clean here --map --mud --snow``, removing all
contaminants from a specific tile quickly. Intended as a hotkey command.

Mud will not be cleaned out from under farm plots, since that would render the
plot inoperable.

Examples
--------

``clean all``
Clean everything that can be cleaned (except mud and snow).
``clean map mud item snow``
Removes all spatter, including mud, leaves, and snow from map tiles. Farm
plots will retain their mud.
``clean --all``
Clean most spatter from all map tiles (excluding mud, snow, and item
spatter), as well as all contaminants from units and items.

``clean --map --mud --snow --item``
Removes all spatter, including mud, snow, and tree droppings from map
tiles. Farm plots will retain their mud as needed.

``clean --map --item --only --items``
Remove only tree droppings from the map (leaving blood and other
contaminants untouched). Clean all items of their contaminants.

``clean here -mdstu``
Clean any sort of contaminant from the map tile under the keyboard cursor,
as well as any contaminant found on a unit there, but don't touch contaminants
on any item (e.g., the unit's poisoned weapon).

``clean 0,0,90 0,0,120 -uiz``
Clean all contaminants from units and items on z-levels 90 through 120.
Don't touch map spatter at all.

``clean -mgxoz``
Reduce all grass on the current z-level to barren soil. Don't touch
any contaminants.

``clean 0,0,100 19,19,119 -adstg``
Remove all contaminants of any type from the 20 x 20 x 20 cube defined
by the coords, including on any units, items, and ground spatter
(excluding mud for farms). Also remove any unused grass type events from
the affected map blocks, but don't remove any grass present.

Options
-------

When cleaning the map, you can specify extra options for extra cleaning:

``mud``
Also remove mud.
``item``
Also remove item spatter, like fallen leaves and flowers.
``snow``
Also remove snow coverings.
``-a``, ``--all``
Equivalent to ``--map --units --items``.
``-m``, ``--map``
Clean selected map tiles. Cleans most spatter by default, but not mud,
snow, or item spatter.
``-d``, ``--mud``
Also remove mud from map tiles. Excludes mud required for farm plots.
``-s``, ``--snow``
Also remove snow coverings from map tiles.
``-t``, ``--item``
Also remove item spatter (e.g., fallen leaves, flowers, and gatherable
tree fruit) from map tiles. Not to be confused with ``--items``, which
cleans contaminants *off* of items.
``-g``, ``--grass``
Remove unused (entirely depleted) grass events from map blocks. DF will
create a grass event for each type of grass that grows in a block, but
doesn't remove them if you pave over the block or if the grass got
depleted and entirely replaced with a different type. Could possibly
improve FPS if you had a ton of unused grass events everywhere (a likely
outcome of using ``regrass --new``). Requires ``--map`` option to be
specified.

``-x``, ``--desolate``
Use with caution! Remove grass from the selected area. You probably don't
want to use this on the entire map, so make sure to use ``pos`` arguments.
Requires ``--map`` and ``--grass`` options to be specified.
``-o``, ``--only``
Ignore most spatter (e.g., blood, vomit, and ooze) and focus only on the
other specified options. Requires ``--map`` and at least one of: ``--mud``,
``--snow``, ``--item``, or ``--grass``.
``-u``, ``--units``
Clean all contaminants off of units in the selected area. Not affected by
map options that specify spatter types (e.g., snow). Units will always be
completely cleaned.
``-i``, ``--items``
Clean all contaminants off of items in the selected area (including those
held by units). Not affected by map options that specify spatter types.
Not to be confused with ``--item``, which removes tree droppings found on
the ground.
``-z``, ``--zlevel``
Select entire z-levels. Will do all z-levels between ``pos`` arguments if
both are given, z-level of first ``pos`` if one is given, else z-level of
current view if no ``pos`` is given.

Troubleshooting
---------------

Use ``debugfilter set Debug cleaners log`` (or
``debugfilter set Trace cleaners log`` for more detail) to help diagnose
issues. (Avoid cleaning large parts of the map using many options with
Trace enabled, as it could make the game unresponsive and flood the console
for a good minute.)

Disable with ``debugfilter set Info cleaners log``.
9 changes: 8 additions & 1 deletion docs/plugins/regrass.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ This command can refresh the grass (and subterranean moss) growing on your map.
Operates on floors, stairs, and ramps. Also works underneath shrubs, saplings,
and tree trunks. Ignores furrowed soil and wet sand (beaches).

The `cleaners` tool can help remove grass if you messed up and suddenly there
are staring eyeballs growing all over your fort. `gui/tiletypes` can then be used
to change the soil back to stone.

Usage
-----

Expand Down Expand Up @@ -74,7 +78,10 @@ Options
``-n``, ``--new``
Adds all biome-compatible grass types that were not originally present in
the map block. Allows regrass to work in blocks that never had any grass to
begin with. Will still fail in incompatible biomes.
begin with. Will still fail in incompatible biomes. Note: This can add an
excessive number of grass events to your map, so it may be desirable to run
``clean --map --grass --only`` (see: `cleaners`) afterwards to clean up any
unused events.
``-f``, ``--force``
Force a grass type on tiles with no compatible grass types. Unsets the
``no_grow`` flag on all tiles. The ``--new`` option takes precedence for
Expand Down
24 changes: 24 additions & 0 deletions library/LuaApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2556,6 +2556,29 @@ static int maps_getPlantAtTile(lua_State *L)
return 1;
}

static int maps_isPlantInBox(lua_State *L)
{
auto plant = Lua::CheckDFObject<df::plant>(L, 1);
if (lua_gettop(L) > 3)
{
int x1 = luaL_checkint(L, 2);
int y1 = luaL_checkint(L, 3);
int z1 = luaL_checkint(L, 4);
int x2 = luaL_checkint(L, 5);
int y2 = luaL_checkint(L, 6);
int z2 = luaL_checkint(L, 7);
lua_pushboolean(L, Maps::isPlantInBox(plant, x1, y1, z1, x2, y2, z2));
}
else
{
df::coord pos1, pos2;
Lua::CheckDFAssign(L, &pos1, 2);
Lua::CheckDFAssign(L, &pos2, 3);
lua_pushboolean(L, Maps::isPlantInBox(plant, pos1, pos2));
}
return 1;
}

static int maps_getBiomeType(lua_State *L)
{
auto pos = CheckCoordXY(L, 1, true);
Expand Down Expand Up @@ -2621,6 +2644,7 @@ static const luaL_Reg dfhack_maps_funcs[] = {
{ "getRegionBiome", maps_getRegionBiome },
{ "getTileBiomeRgn", maps_getTileBiomeRgn },
{ "getPlantAtTile", maps_getPlantAtTile },
{ "isPlantInBox", maps_isPlantInBox },
{ "getBiomeType", maps_getBiomeType },
{ "isTileAquifer", maps_isTileAquifer },
{ "isTileHeavyAquifer", maps_isTileHeavyAquifer },
Expand Down
5 changes: 5 additions & 0 deletions library/include/modules/Maps.h
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,11 @@ DFHACK_EXPORT bool canStepBetween(df::coord pos1, df::coord pos2);
// Get the plant that owns the tile at the specified position.
extern DFHACK_EXPORT df::plant *getPlantAtTile(int32_t x, int32_t y, int32_t z);
inline df::plant *getPlantAtTile(df::coord pos) { return getPlantAtTile(pos.x, pos.y, pos.z); }
// Returns true if the plant is within a box defined by the specified coordinates, accounting for trees.
DFHACK_EXPORT bool isPlantInBox(df::plant *plant, const cuboid &bounds);
inline bool isPlantInBox(df::plant *plant, int16_t x1, int16_t y1, int16_t z1,
int16_t x2, int16_t y2, int16_t z2) { return isPlantInBox(plant, cuboid(x1, y1, z1, x2, y2, z2)); }
inline bool isPlantInBox(df::plant *plant, df::coord pos1, df::coord pos2) { return isPlantInBox(plant, cuboid(pos1, pos2)); }

// Get the biome type at the given region coordinates.
DFHACK_EXPORT df::enums::biome_type::biome_type getBiomeTypeWithRef(int16_t region_x, int16_t region_y, int16_t region_ref_y);
Expand Down
30 changes: 4 additions & 26 deletions library/lua/tile-material.lua
Original file line number Diff line number Diff line change
Expand Up @@ -172,33 +172,10 @@ end

-- GetTreeMat returns the material of the tree at the given tile or nil if the tile does not have a
-- tree or giant mushroom.
-- Currently roots are ignored.
function GetTreeMat(x, y, z)
local pos = prepPos(x, y, z)

local function coordInTree(pos, tree)
local x1 = tree.pos.x - math.floor(tree.tree_info.dim_x / 2)
local x2 = tree.pos.x + math.floor(tree.tree_info.dim_x / 2)
local y1 = tree.pos.y - math.floor(tree.tree_info.dim_y / 2)
local y2 = tree.pos.y + math.floor(tree.tree_info.dim_y / 2)
local z1 = tree.pos.z
local z2 = tree.pos.z + tree.tree_info.body_height

if not ((pos.x >= x1 and pos.x <= x2) and (pos.y >= y1 and pos.y <= y2) and (pos.z >= z1 and pos.z <= z2)) then
return false
end

return not tree.tree_info.body[pos.z - tree.pos.z]:_displace((pos.y - y1) * tree.tree_info.dim_x + (pos.x - x1)).blocked
end

for _, tree in ipairs(df.global.world.plants.all) do
if tree.tree_info ~= nil then
if coordInTree(pos, tree) then
return dfhack.matinfo.decode(419, tree.material)
end
end
end
return nil
local plant = dfhack.maps.getPlantAtTile(pos)
return plant and plant.tree_info and dfhack.matinfo.decode(419, plant.material) or nil
end

-- GetShrubMat returns the material of the shrub at the given tile or nil if the tile does not
Expand Down Expand Up @@ -289,7 +266,7 @@ BasicMats = {
[df.tiletype_material.DRIFTWOOD] = GetLayerMat,
[df.tiletype_material.POOL] = GetLayerMat,
[df.tiletype_material.BROOK] = GetLayerMat,
[df.tiletype_material.ROOT] = GetLayerMat,
[df.tiletype_material.ROOT] = GetTreeMat,
[df.tiletype_material.TREE] = GetTreeMat,
[df.tiletype_material.MUSHROOM] = GetTreeMat,
[df.tiletype_material.UNDERWORLD_GATE] = nil, -- I guess this is for the gates found in vaults?
Expand Down Expand Up @@ -327,6 +304,7 @@ OnlyPlantMats = {
[df.tiletype_material.GRASS_DRY] = GetGrassMat,
[df.tiletype_material.GRASS_DEAD] = GetGrassMat,
[df.tiletype_material.PLANT] = GetShrubMat,
[df.tiletype_material.ROOT] = GetTreeMat,
[df.tiletype_material.TREE] = GetTreeMat,
[df.tiletype_material.MUSHROOM] = GetTreeMat,
}
Expand Down
41 changes: 41 additions & 0 deletions library/modules/Maps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,47 @@ df::plant *Maps::getPlantAtTile(int32_t x, int32_t y, int32_t z)
return NULL;
}

bool Maps::isPlantInBox(df::plant *plant, const cuboid &bounds)
{
if (!bounds.isValid())
return false;
else if (bounds.containsPos(plant->pos))
return true;
else if (!plant->tree_info)
return false;

auto &pos = plant->pos;
auto &t = *(plant->tree_info);
// Northwest x/y pos of tree bounds
int x_NW = pos.x - (t.dim_x >> 1);
int y_NW = pos.y - (t.dim_y >> 1);

if (!cuboid(max(0, x_NW), max(0, y_NW), max(0, pos.z - t.roots_depth),
x_NW + t.dim_x, y_NW + t.dim_y, pos.z + t.body_height - 1).clamp(bounds).isValid())
{ // No intersection of tree bounds with cuboid
return false;
}

int xy_size = t.dim_x * t.dim_y;
// Iterate tree body
for (int z_idx = 0; z_idx < t.body_height; z_idx++)
for (int xy_idx = 0; xy_idx < xy_size; xy_idx++)
if ((t.body[z_idx][xy_idx].whole & 0x7F) != 0 && // Any non-blocked
bounds.containsPos(x_NW + xy_idx % t.dim_x, y_NW + xy_idx / t.dim_x, pos.z + z_idx))
{
return true;
}
// Iterate tree roots
for (int z_idx = 0; z_idx < t.roots_depth; z_idx++)
for (int xy_idx = 0; xy_idx < xy_size; xy_idx++)
if ((t.roots[z_idx][xy_idx].whole & 0x7F) != 0 && // Any non-blocked
bounds.containsPos(x_NW + xy_idx % t.dim_x, y_NW + xy_idx / t.dim_x, pos.z - z_idx - 1))
{
return true;
}
return false;
}

/*
* Biomes
*/
Expand Down
2 changes: 1 addition & 1 deletion plugins/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ if(BUILD_SUPPORTED)
dfhack_plugin(changevein changevein.cpp)
#add_subdirectory(channel-safely)
dfhack_plugin(cleanconst cleanconst.cpp)
dfhack_plugin(cleaners cleaners.cpp)
dfhack_plugin(cleaners cleaners.cpp LINK_LIBRARIES lua)
dfhack_plugin(cleanowned cleanowned.cpp)
dfhack_plugin(createitem createitem.cpp)
dfhack_plugin(cursecheck cursecheck.cpp)
Expand Down
Loading
Loading