From f20c0329a141a5f73f48ced4781ab0a26f05d79b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 1 Aug 2024 17:07:52 -0700 Subject: [PATCH 1/3] clean up deconstruct --- library/modules/Buildings.cpp | 76 +++++------------------------------ 1 file changed, 9 insertions(+), 67 deletions(-) diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index 1f8feb9543..a3c32485f5 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -1056,49 +1056,6 @@ static void markBuildingTiles(df::building *bld, bool remove) } } -static void linkRooms(df::building *bld) -{ -/* TODO: understand how this changes for v50 - auto &vec = world->buildings.other[buildings_other_id::IN_PLAY]; - - bool changed = false; - - for (size_t i = 0; i < vec.size(); i++) - { - auto room = vec[i]; - if (!room->is_room || room->z != bld->z || room == bld) - continue; - - df::building_extents_type *pext = getExtentTile(room->room, df::coord2d(bld->x1, bld->y1)); - if (!pext || !*pext) - continue; - - changed = true; - room->children.push_back(bld); - bld->parents.push_back(room); - - // TODO: the game updates room rent here if economy is enabled - } - - if (changed) - df::global::plotinfo->equipment.update.bits.buildings = true; -*/ -} - -static void unlinkRooms(df::building *bld) -{ -/* TODO: understand how this changes for v50 - for (size_t i = 0; i < bld->parents.size(); i++) - { - auto parent = bld->parents[i]; - int idx = linear_index(parent->children, bld); - vector_erase_at(parent->children, idx); - } - - bld->parents.clear(); -*/ -} - static void linkBuilding(df::building *bld) { bld->id = (*building_next_id)++; @@ -1109,8 +1066,6 @@ static void linkBuilding(df::building *bld) if (bld->isSettingOccupancy()) markBuildingTiles(bld, false); - linkRooms(bld); - Job::checkBuildingsNow(); } @@ -1376,14 +1331,15 @@ static void on_civzone_delete(df::building_civzonest* civzone) bool Buildings::deconstruct(df::building *bld) { - using df::global::plotinfo; - using df::global::world; using df::global::ui_look_list; CHECK_NULL_POINTER(bld); - if (bld->isActual() && bld->getBuildStage() > 0) - { + if (bld->isActual() && bld->getBuildStage() > 0) { + if (bld->jobs.size() == 1 && bld->jobs[0]->job_type == df::job_type::DestroyBuilding) { + // already queued for destruction + return false; + } bld->queueDestroy(); return false; } @@ -1391,18 +1347,14 @@ bool Buildings::deconstruct(df::building *bld) /* Immediate destruction code path. Should only happen for abstract and unconstructed buildings.*/ - if (bld->isSettingOccupancy()) - { + if (bld->isSettingOccupancy()) { markBuildingTiles(bld, true); bld->cleanupMap(); } bld->removeUses(false, false); - // Assume: no parties. - unlinkRooms(bld); // Assume: not unit destroy target int id = bld->id; - vector_erase_at(plotinfo->tax_collection.rooms, linear_index(plotinfo->tax_collection.rooms, id)); // Assume: not used in punishment // Assume: not used in non-own jobs // Assume: does not affect pathfinding @@ -1413,24 +1365,14 @@ bool Buildings::deconstruct(df::building *bld) remove_building_from_all_zones(bld); - if (bld->getType() == df::building_type::Civzone) - { - auto zone = strict_virtual_cast(bld); - - if (zone) + if (bld->getType() == df::building_type::Civzone) { + if (auto zone = strict_virtual_cast(bld)) on_civzone_delete(zone); } delete bld; - if (world->selected_building == bld) - { - world->selected_building = NULL; - world->update_selected_building = true; - } - - for (int i = ui_look_list->size()-1; i >= 0; --i) - { + for (int i = ui_look_list->size()-1; i >= 0; --i) { auto item = (*ui_look_list)[i]; if (item->type == df::lookinfost::Building && item->data.building.bld_id == id) From c4996d2f7bb7caa5cd0ed91712026c57dfebd35a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 1 Aug 2024 18:20:41 -0700 Subject: [PATCH 2/3] restore tax collection cleanup --- library/modules/Buildings.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index a3c32485f5..f3be5b566d 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -1355,6 +1355,7 @@ bool Buildings::deconstruct(df::building *bld) bld->removeUses(false, false); // Assume: not unit destroy target int id = bld->id; + vector_erase_at(plotinfo->tax_collection.rooms, linear_index(plotinfo->tax_collection.rooms, id)); // Assume: not used in punishment // Assume: not used in non-own jobs // Assume: does not affect pathfinding From 6cda04bd79a038e7ef10a6db43df472a0c7d0e65 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 1 Aug 2024 21:42:17 -0700 Subject: [PATCH 3/3] update deconstruct logic according to reveng --- library/modules/Buildings.cpp | 174 ++++++++++++++++++++++------------ 1 file changed, 116 insertions(+), 58 deletions(-) diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index f3be5b566d..9a9489fb24 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -63,6 +63,7 @@ distribution. #include "df/buildings_other_id.h" #include "df/d_init.h" #include "df/dfhack_room_quality_level.h" +#include "df/gamest.h" #include "df/general_ref_building_holderst.h" #include "df/general_ref_contains_unitst.h" #include "df/item.h" @@ -74,6 +75,7 @@ distribution. #include "df/tile_occupancy.h" #include "df/inorganic_raw.h" #include "df/plotinfost.h" +#include "df/punishment.h" #include "df/squad.h" #include "df/unit.h" #include "df/unit_relationship_type.h" @@ -258,36 +260,10 @@ static void add_zone_to_all_buildings(df::building* zone_as_building) } } -static void remove_building_from_zone(df::building* bld, df::building_civzonest* zone) -{ - for (int bid = 0; bid < (int)zone->contained_buildings.size(); bid++) - { - if (zone->contained_buildings[bid] == bld) - { - zone->contained_buildings.erase(zone->contained_buildings.begin() + bid); - bid--; - } - } - - for (int bid = 0; bid < (int)bld->relations.size(); bid++) - { - if (bld->relations[bid] == zone) - { - bld->relations.erase(bld->relations.begin() + bid); - bid--; - } - } -} - -static void remove_building_from_all_zones(df::building* bld) -{ - df::coord coord(bld->centerx, bld->centery, bld->z); - - std::vector cv; - Buildings::findCivzonesAt(&cv, coord); +static void remove_building_from_zone(df::building* bld, df::building_civzonest* zone) { + erase_from_vector(zone->contained_buildings, &df::building::id, bld->id); + vector_erase_at(bld->relations, binsearch_index(bld->relations, &df::building::id, zone->id)); - for (auto zone : cv) - remove_building_from_zone(bld, zone); } static void remove_zone_from_all_buildings(df::building* zone_as_building) @@ -300,8 +276,8 @@ static void remove_zone_from_all_buildings(df::building* zone_as_building) if (zone == nullptr) return; - //this is a paranoid check and slower than it could be. Zones contain a list of children - //good for fixing potentially bad game states when deleting a zone + // this is a paranoid check and slower than it could be. Zones contain a list of children + // good for fixing potentially bad game states when deleting a zone for (auto bld : world->buildings.other.IN_PLAY) remove_building_from_zone(bld, zone); } @@ -1019,14 +995,11 @@ static void markBuildingTiles(df::building *bld, bool remove) if (remove) stockpile = complete = false; - for (int tx = bld->x1; tx <= bld->x2; tx++) - { - for (int ty = bld->y1; ty <= bld->y2; ty++) - { - df::coord tile(tx,ty,bld->z); + for (int tx = bld->x1; tx <= bld->x2; tx++) { + for (int ty = bld->y1; ty <= bld->y2; ty++) { + df::coord tile(tx, ty, bld->z); - if (use_extents) - { + if (use_extents) { df::building_extents_type *etile = getExtentTile(bld->room, tile); if (!etile || !*etile) continue; @@ -1043,14 +1016,17 @@ static void markBuildingTiles(df::building *bld, bool remove) if (complete) bld->updateOccupancy(tx, ty); - else - { + else { auto &occ = block->occupancy[btile.x][btile.y]; - if (remove) + if (remove) { occ.bits.building = tile_building_occ::None; - else + block->flags.bits.update_liquid = true; + block->flags.bits.update_liquid_twice = true; + } + else { occ.bits.building = tile_building_occ::Planned; + } } } } @@ -1331,12 +1307,13 @@ static void on_civzone_delete(df::building_civzonest* civzone) bool Buildings::deconstruct(df::building *bld) { + using df::global::game; using df::global::ui_look_list; CHECK_NULL_POINTER(bld); if (bld->isActual() && bld->getBuildStage() > 0) { - if (bld->jobs.size() == 1 && bld->jobs[0]->job_type == df::job_type::DestroyBuilding) { + if (markedForRemoval(bld)) { // already queued for destruction return false; } @@ -1344,33 +1321,113 @@ bool Buildings::deconstruct(df::building *bld) return false; } - /* Immediate destruction code path. - Should only happen for abstract and unconstructed buildings.*/ + // Immediate destruction code path. + // Should only happen for abstract and unconstructed buildings. + + if (bld->flags.bits.almost_deleted) + return true; + bld->flags.bits.almost_deleted = true; if (bld->isSettingOccupancy()) { markBuildingTiles(bld, true); bld->cleanupMap(); } - bld->removeUses(false, false); - // Assume: not unit destroy target - int id = bld->id; - vector_erase_at(plotinfo->tax_collection.rooms, linear_index(plotinfo->tax_collection.rooms, id)); - // Assume: not used in punishment - // Assume: not used in non-own jobs - // Assume: does not affect pathfinding - bld->deconstructItems(false, false, false); - // Don't clear arrows. - - bld->uncategorize(); + bool destitem = bld->isFarmPlot(); + bool insanify = false; + bool is_from_damage = false; - remove_building_from_all_zones(bld); + bld->removeUses(destitem, insanify); - if (bld->getType() == df::building_type::Civzone) { + const df::building_type btype = bld->getType(); + if (btype == df::building_type::Civzone) { if (auto zone = strict_virtual_cast(bld)) on_civzone_delete(zone); + } else { + while (bld->relations.size()) + remove_building_from_zone(bld, bld->relations[bld->relations.size() - 1]); } + for (auto unit : world->units.active) { + if (unit->job.destroy_target == bld) + unit->job.destroy_target = NULL; + } + + const int id = bld->id; + erase_from_vector(plotinfo->tax_collection.rooms, id); + + for (auto punishment : plotinfo->punishments) { + if (punishment->chain == id) + punishment->chain = -1; + } + + const bool interrupt_rest = + btype == df::building_type::TractionBench || + btype == df::building_type::Bed; + const bool interrupt_link = + btype == df::building_type::Door || + btype == df::building_type::Floodgate || + btype == df::building_type::Bridge || + btype == df::building_type::Support || + btype == df::building_type::Chain || + btype == df::building_type::Cage || + btype == df::building_type::Weapon || + btype == df::building_type::Hatch || + btype == df::building_type::GrateWall || + btype == df::building_type::GrateFloor || + btype == df::building_type::BarsVertical || + btype == df::building_type::BarsFloor || + btype == df::building_type::GearAssembly; + const bool interrupt_well = + btype == df::building_type::Well; + + vector to_cancel; + const df::coord pos(bld->x1, bld->y1, bld->z); + for (auto job : world->jobs.list) { + const auto jtype = job->job_type; + if (interrupt_rest && jtype == df::job_type::Rest && job->pos == pos) + to_cancel.push_back(job); + if (interrupt_link && jtype == df::job_type::LinkBuildingToTrigger && Job::getHolder(job) == bld) + to_cancel.push_back(job); + if (interrupt_well && (jtype == df::job_type::Drink || jtype == df::job_type::CleanSelf || jtype == df::job_type::FillWaterskin) && job->pos == pos) + to_cancel.push_back(job); + if (!job->flags.bits.dessource && !job->flags.bits.special) + continue; + for (int idx = (int)job->general_refs.size()-1; idx > 0; --idx) { + auto gref = job->general_refs[idx]; + if (gref->getBuilding() == bld) { + delete gref; + vector_erase_at(job->general_refs, idx); + } + } + } + for (auto job : to_cancel) + Job::removeJob(job); + + if (btype == df::building_type::Bridge || + btype == df::building_type::Door || + btype == df::building_type::Floodgate || + btype == df::building_type::Hatch || + btype == df::building_type::GrateWall || + btype == df::building_type::GrateFloor || + btype == df::building_type::BarsVertical || + btype == df::building_type::BarsFloor) + { + world->reindex_pathfinding = true; + } + + if (btype == df::building_type::Bridge) + world->buildings.check_bridge_collapse = true; + + if (bld->getMachineInfo()) + world->buildings.check_machine_collapse = true; + + bld->deconstructItems(destitem, insanify, is_from_damage); + bld->uncategorize(); + + if (world->selected_building == bld) + world->selected_building = NULL; + delete bld; for (int i = ui_look_list->size()-1; i >= 0; --i) { @@ -1383,6 +1440,7 @@ bool Buildings::deconstruct(df::building *bld) } } + game->minimap.mustmake = true; Job::checkBuildingsNow(); Job::checkDesignationsNow();