diff --git a/docs/changelog.txt b/docs/changelog.txt index e078c870da..8f14eb8e40 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -67,6 +67,7 @@ Template for new versions: - Fixed a possible hang or assertion failure when pressing a hotkey while a DFHack GUI window was open but unfocused - In ``Screen`` module, Fix out-of-bounds color table access when Lua pens use ``COLOR_RESET`` - rename the ``stockpiles`` tool tag to ``stockpile`` so it no longer collides with the `stockpiles` plugin in `gui/launcher` +- ``Units::teleport``: update unit occupancy on the full 3x3 footprint of EQUIPMENT units (e.g. wagons) instead of only their center tile - `3dveins`: fix failure on embarks that cross midmap tiles - `aquifer`: make ``--skip-top`` and top-relative ``--levels`` take effect for the ``drain``, ``convert``, and ``add`` actions instead of being silently ignored - `autodump`: ``destroy`` no longer leaves the contents of destroyed containers in limbo or crashes when destroying unit-held items diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index 33553f2874..b188992b64 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -42,6 +42,7 @@ distribution. #include "df/caste_raw.h" #include "df/creature_interaction_effect_display_namest.h" #include "df/creature_raw.h" +#include "df/creature_raw_flags.h" #include "df/curse_attr_change.h" #include "df/entity_position.h" #include "df/entity_position_assignment.h" @@ -777,12 +778,28 @@ bool Units::teleport(df::unit *unit, df::coord target_pos) if (!old_occ || !new_occ) return false; + // EQUIPMENT units (e.g. wagons) occupy a 3x3 footprint centered on their + // position; all other units occupy just their position tile + int extent = 0; + if (auto craw = df::creature_raw::find(unit->race); craw && + craw->flags.is_set(df::creature_raw_flags::EQUIPMENT_WAGON)) + extent = 1; + + auto for_each_occupied_tile = [&](df::coord center, auto &&fn) { + for (int dy = -extent; dy <= extent; ++dy) + for (int dx = -extent; dx <= extent; ++dx) + if (auto occ = Maps::getTileOccupancy(center.x+dx, center.y+dy, center.z)) + fn(*occ); + }; + // Clear appropriate occupancy flags at old tile - if (unit->flags1.bits.on_ground) - // This is potentially wrong, but the game will recompute this as needed - old_occ->bits.unit_grounded = false; - else - old_occ->bits.unit = false; + for_each_occupied_tile(unit->pos, [&](df::tile_occupancy &occ) { + if (unit->flags1.bits.on_ground) + // This is potentially wrong, but the game will recompute this as needed + occ.bits.unit_grounded = false; + else + occ.bits.unit = false; + }); // Clear unit projectile info if (unit->flags1.bits.projectile) { @@ -801,10 +818,12 @@ bool Units::teleport(df::unit *unit, df::coord target_pos) unit->flags1.bits.on_ground = true; // Set appropriate occupancy flags at new tile - if (unit->flags1.bits.on_ground) - new_occ->bits.unit_grounded = true; - else - new_occ->bits.unit = true; + for_each_occupied_tile(target_pos, [&](df::tile_occupancy &occ) { + if (unit->flags1.bits.on_ground) + occ.bits.unit_grounded = true; + else + occ.bits.unit = true; + }); // Move unit to destination unit->pos = target_pos;