diff --git a/docs/plugins/channel-safely.rst b/docs/plugins/channel-safely.rst index 1a2866920..3acbe66cd 100644 --- a/docs/plugins/channel-safely.rst +++ b/docs/plugins/channel-safely.rst @@ -63,8 +63,6 @@ Features :monitoring: Toggle whether to monitor the conditions of active digs. (default: disabled) :resurrect: Toggle whether to resurrect units involved in cave-ins, and if monitor is enabled units who die while digging. (default: disabled) -:insta-dig: Toggle whether to use insta-digging on unreachable designations. - Runs on the refresh cycles. Use with caution. (default: disabled) Settings -------- @@ -80,10 +78,8 @@ Troubleshooting --------------- If designations aren't switching correctly, try putting the designations into marker mode. -Then press . (next) or resume. If you're debugging code you'll want these: +Then press . (next) or resume. If you're debugging code you'll want these:: -[todo: make this a block of code] - -:filter1: ``debugfilter set Info channel manager`` -:filter2: ``debugfilter set Debug channel plugin`` -:filter3: ``debugfilter set Trace channel group`` + debugfilter set Info channel manager + debugfilter set Debug channel plugin + debugfilter set Trace channel group diff --git a/plugins/channel-safely/channel-groups.cpp b/plugins/channel-safely/channel-groups.cpp index 6c310b5c4..7ee6c5b44 100644 --- a/plugins/channel-safely/channel-groups.cpp +++ b/plugins/channel-safely/channel-groups.cpp @@ -46,14 +46,14 @@ bool ChannelJobs::has_cavein_conditions(const df::coord &map_pos) { } bool ChannelJobs::possible_cavein(const df::coord &job_pos) { - for (auto iter = active.begin(); iter != active.end(); ++iter) { - if (*iter == job_pos) continue; - if (calc_distance(job_pos, *iter) <= 2) { + for (auto iter : active) { + if (iter == job_pos) continue; + if (calc_distance(job_pos, iter) <= 2) { // find neighbours df::coord n1[8]; df::coord n2[8]; get_neighbours(job_pos, n1); - get_neighbours(*iter, n2); + get_neighbours(iter, n2); // find shared neighbours for (int i = 0; i < 7; ++i) { for (int j = i + 1; j < 8; ++j) { @@ -133,7 +133,7 @@ void ChannelGroups::add(const df::coord &map_pos) { TRACE(groups).print(" -> brand new group\n"); // we create a brand-new group to use group_index = groups.size(); - groups.push_back(Group()); + groups.emplace_back(); group = &groups[group_index]; } } @@ -220,7 +220,7 @@ void ChannelGroups::scan(bool full_scan) { jobs.erase(map_pos); } block->designation[lx][ly].bits.dig = df::tile_dig_designation::No; - } else if (is_dig_designation(block->designation[lx][ly]) || block->occupancy[lx][ly].bits.dig_marked ) { + } else if (is_dig_designation(block->designation[lx][ly]) || block->occupancy[lx][ly].bits.dig_marked) { if (!is_channel_designation(block->designation[lx][ly])) { if (df::map_block* block_above = Maps::getBlock(bx, by, z+1)) { if (!is_channel_designation(block_above->designation[lx][ly])) { diff --git a/plugins/channel-safely/channel-manager.cpp b/plugins/channel-safely/channel-manager.cpp index df3bcad71..b6b19a0ef 100644 --- a/plugins/channel-safely/channel-manager.cpp +++ b/plugins/channel-safely/channel-manager.cpp @@ -52,7 +52,7 @@ void ChannelManager::manage_group(const df::coord &map_pos, bool set_marker_mode INFO(manager).print("manage_group() is done\n"); } -void ChannelManager::manage_group(const Group &group, bool set_marker_mode, bool marker_mode) { +void ChannelManager::manage_group(const Group &group, bool set_marker_mode, bool marker_mode) const { INFO(manager).print("manage_group()\n"); if (!set_marker_mode) { marker_mode = has_any_groups_above(groups, group); @@ -88,7 +88,6 @@ void ChannelManager::manage_group(const Group &group, bool set_marker_mode, bool if (config.insta_dig) { manage_one(pos, true, false); dig_now(DFHack::Core::getInstance().getConsole(), pos); - mark_done(pos); } else { // todo: engage dig management, swap channel designations for dig } @@ -101,12 +100,11 @@ void ChannelManager::manage_group(const Group &group, bool set_marker_mode, bool } else if (config.insta_dig && isEntombed(miner_pos, pos)) { manage_one(pos, true, false); dig_now(DFHack::Core::getInstance().getConsole(), pos); - mark_done(pos); } } DEBUG(manager).print("cavein possible(%d)\n" - "%zu candidates\n" - "least access %d\n", cavein_possible, cavein_candidates.size(), least_access); + "%zu candidates\n" + "least access %d\n", cavein_possible, cavein_candidates.size(), least_access); } // managing designations if (!group.empty()) { @@ -120,16 +118,18 @@ void ChannelManager::manage_group(const Group &group, bool set_marker_mode, bool continue; } // cavein is only possible if marker_mode is false + // we want to dig the cavein candidates first, the least accessible ones specifically const static uint8_t MAX = 84; //arbitrary number that indicates the value has changed + const static uint8_t OFFSET = 2; //value has been tweaked to avoid cave-ins whilst activating as many designations as possible if (CSP::dignow_queue.count(pos) || (cavein_candidates.count(pos) && - least_access < MAX && cavein_candidates[pos] <= least_access+2)) { + least_access < MAX && cavein_candidates[pos] <= least_access+OFFSET)) { - TRACE(manager).print("cave-in evaluated true and either of dignow or (%d <= %d)\n", cavein_candidates[pos], least_access+2); - // we want to dig the cavein candidates first + TRACE(manager).print("cave-in evaluated true and either of dignow or (%d <= %d)\n", cavein_candidates[pos], least_access+OFFSET); df::coord local(pos); local.x %= 16; local.y %= 16; auto block = Maps::ensureTileBlock(pos); + // if we don't find the priority in block_events, it probably means bad things for (df::block_square_event* event: block->block_events) { if (auto evT = virtual_cast(event)) { // we want to let the user keep some designations free of being managed @@ -142,8 +142,9 @@ void ChannelManager::manage_group(const Group &group, bool set_marker_mode, bool assert(manage_one(pos, true, false)); continue; } + // cavein possible, but we failed to meet the criteria for activation if (cavein_candidates.count(pos)) { - DEBUG(manager).print("cave-in evaluated true and no dignow and (%d > %d)\n", cavein_candidates[pos], least_access + 2); + DEBUG(manager).print("cave-in evaluated true and no dignow and (%d > %d)\n", cavein_candidates[pos], least_access+OFFSET); } else { DEBUG(manager).print("cave-in evaluated true and no dignow and pos is not a candidate\n"); } @@ -152,7 +153,7 @@ void ChannelManager::manage_group(const Group &group, bool set_marker_mode, bool INFO(manager).print("manage_group() is done\n"); } -bool ChannelManager::manage_one(const df::coord &map_pos, bool set_marker_mode, bool marker_mode) { +bool ChannelManager::manage_one(const df::coord &map_pos, bool set_marker_mode, bool marker_mode) const { if (Maps::isValidTilePos(map_pos)) { TRACE(manager).print("manage_one((" COORD "), %d, %d)\n", COORDARGS(map_pos), set_marker_mode, marker_mode); df::map_block* block = Maps::getTileBlock(map_pos); @@ -164,41 +165,22 @@ bool ChannelManager::manage_one(const df::coord &map_pos, bool set_marker_mode, // ensure that we aren't on the top-most layers if (map_pos.z < mapz - 3) { // do we already know whether to set marker mode? - if (set_marker_mode) { - TRACE(manager).print(" -> setting marker mode\n"); - // if enabling marker mode, just do it - if (marker_mode) { - goto markerMode; - } - // otherwise we check for some safety - if (!is_channel_designation(block->designation[Coord(local)]) || is_safe_to_dig_down(map_pos)) { - // not a channel designation, or it is safe to dig down if it is - if (!block->flags.bits.designated) { - block->flags.bits.designated = true; - } - // we need to cache the tile now that we're activating the designation - TileCache::Get().cache(map_pos, block->tiletype[Coord(local)]); - TRACE(manager).print("marker mode DISABLED\n"); - tile_occupancy.bits.dig_marked = false; - } else { - // we want to activate the designation, that's not what we get - goto markerMode; - } - } else { - // not set_marker_mode - TRACE(manager).print(" if(has_groups_above())\n"); - // check that the group has no incomplete groups directly above it - if (has_group_above(groups, map_pos) || !is_safe_to_dig_down(map_pos)) { - - markerMode: - - TRACE(manager).print("marker mode ENABLED\n"); - tile_occupancy.bits.dig_marked = true; - if (jobs.count(map_pos)) { - cancel_job(map_pos); - } + if (!marker_mode) { + // marker_mode is set to true if it is unsafe to dig + marker_mode = (!set_marker_mode && + (has_group_above(groups, map_pos) || !is_safe_to_dig_down(map_pos))) || + (set_marker_mode && + is_channel_designation(block->designation[Coord(local)]) && !is_safe_to_dig_down(map_pos)); + } + if (marker_mode) { + if (jobs.count(map_pos)) { + cancel_job(map_pos); } + } else if (!block->flags.bits.designated) { + block->flags.bits.designated = true; } + tile_occupancy.bits.dig_marked = marker_mode; + TRACE(manager).print("marker mode %s\n", marker_mode ? "ENABLED" : "DISABLED"); } else { // if we are though, it should be totally safe to dig tile_occupancy.bits.dig_marked = false; diff --git a/plugins/channel-safely/channel-safely-plugin.cpp b/plugins/channel-safely/channel-safely-plugin.cpp index 882685385..73a1fea19 100644 --- a/plugins/channel-safely/channel-safely-plugin.cpp +++ b/plugins/channel-safely/channel-safely-plugin.cpp @@ -1,7 +1,10 @@ /* Prevent channeling down into known open space. Author: Josh Cooper Created: Aug. 4 2020 -Updated: Dec. 5 2022 +Updated: Dec. 8 2022 +*/ +/* +This skeletal logic has not been kept up-to-date since ~v0.5 Enable plugin: -> build groups @@ -160,7 +163,7 @@ namespace CSP { try { pfeature.ival(MONITOR) = config.monitoring; pfeature.ival(VISION) = config.require_vision; - pfeature.ival(INSTADIG) = config.insta_dig; + pfeature.ival(INSTADIG) = false; //config.insta_dig; pfeature.ival(RESURRECT) = config.resurrect; pfeature.ival(RISKAVERSE) = config.riskaverse; @@ -186,7 +189,7 @@ namespace CSP { try { config.monitoring = pfeature.ival(MONITOR); config.require_vision = pfeature.ival(VISION); - config.insta_dig = pfeature.ival(INSTADIG); + config.insta_dig = false; //pfeature.ival(INSTADIG); config.resurrect = pfeature.ival(RESURRECT); config.riskaverse = pfeature.ival(RISKAVERSE); @@ -303,9 +306,9 @@ namespace CSP { switch (report->type) { case announcement_type::CANCEL_JOB: if (config.insta_dig) { - if (report->text.find("cancels Dig") != std::string::npos) { - dignow_queue.emplace(report->pos); - } else if (report->text.find("path") != std::string::npos) { + if (report->text.find("cancels Dig") != std::string::npos || + report->text.find("path") != std::string::npos) { + dignow_queue.emplace(report->pos); } DEBUG(plugin).print("%d, pos: " COORD ", pos2: " COORD "\n%s\n", report_id, COORDARGS(report->pos), @@ -439,7 +442,7 @@ namespace CSP { Maps::getTileOccupancy(job->pos)->bits.dig_marked = true; // prevent algorithm from re-enabling designation - for (auto &be: Maps::getBlock(job->pos)->block_events) { ; + for (auto &be: Maps::getBlock(job->pos)->block_events) { if (auto bsedp = virtual_cast( be)) { df::coord local(job->pos); @@ -603,7 +606,8 @@ command_result channel_safely(color_ostream &out, std::vector ¶ } else if (parameters[1] == "require-vision") { config.require_vision = state; } else if (parameters[1] == "insta-dig") { - config.insta_dig = state; + //config.insta_dig = state; + config.insta_dig = false; } else if (parameters[1] == "resurrect") { if (state != config.resurrect) { config.resurrect = state; @@ -641,7 +645,7 @@ command_result channel_safely(color_ostream &out, std::vector ¶ out.print(" %-20s\t%s\n", "risk-averse: ", config.riskaverse ? "on." : "off."); out.print(" %-20s\t%s\n", "monitoring: ", config.monitoring ? "on." : "off."); out.print(" %-20s\t%s\n", "require-vision: ", config.require_vision ? "on." : "off."); - out.print(" %-20s\t%s\n", "insta-dig: ", config.insta_dig ? "on." : "off."); + //out.print(" %-20s\t%s\n", "insta-dig: ", config.insta_dig ? "on." : "off."); out.print(" %-20s\t%s\n", "resurrect: ", config.resurrect ? "on." : "off."); out.print(" SETTINGS:\n"); out.print(" %-20s\t%" PRIi32 "\n", "refresh-freq: ", config.refresh_freq); diff --git a/plugins/channel-safely/include/channel-groups.h b/plugins/channel-safely/include/channel-groups.h index 5ec6b15c9..ef3f5d082 100644 --- a/plugins/channel-safely/include/channel-groups.h +++ b/plugins/channel-safely/include/channel-groups.h @@ -37,9 +37,9 @@ private: protected: void add(const df::coord &map_pos); public: - int debugGIndex(const df::coord &map_pos) { + int debugGIndex(const df::coord &map_pos) const { if (groups_map.count(map_pos)) { - return groups_map[map_pos]; + return groups_map.find(map_pos)->second; } return -1; } diff --git a/plugins/channel-safely/include/channel-jobs.h b/plugins/channel-safely/include/channel-jobs.h index 13f0d0e77..2e6c6a567 100644 --- a/plugins/channel-safely/include/channel-jobs.h +++ b/plugins/channel-safely/include/channel-jobs.h @@ -21,8 +21,6 @@ using namespace DFHack; */ class ChannelJobs { private: - friend class ChannelGroup; - using Jobs = std::unordered_set; // job* will exist until it is complete, and likely beyond std::unordered_map jobs; Jobs locations; diff --git a/plugins/channel-safely/include/channel-manager.h b/plugins/channel-safely/include/channel-manager.h index 4df02ed38..582916e06 100644 --- a/plugins/channel-safely/include/channel-manager.h +++ b/plugins/channel-safely/include/channel-manager.h @@ -27,8 +27,8 @@ public: void destroy_groups() { groups.clear(); debug(); } void manage_groups(); void manage_group(const df::coord &map_pos, bool set_marker_mode = false, bool marker_mode = false); - void manage_group(const Group &group, bool set_marker_mode = false, bool marker_mode = false); - bool manage_one(const df::coord &map_pos, bool set_marker_mode = false, bool marker_mode = false); + void manage_group(const Group &group, bool set_marker_mode = false, bool marker_mode = false) const; + bool manage_one(const df::coord &map_pos, bool set_marker_mode = false, bool marker_mode = false) const; void mark_done(const df::coord &map_pos); bool exists(const df::coord &map_pos) const { return groups.count(map_pos); } void debug() { diff --git a/plugins/channel-safely/include/inlines.h b/plugins/channel-safely/include/inlines.h index 38e73814c..172275778 100644 --- a/plugins/channel-safely/include/inlines.h +++ b/plugins/channel-safely/include/inlines.h @@ -10,10 +10,11 @@ #include #include +#include -#define Coord(id) id.x][id.y +#define Coord(id) (id).x][(id).y #define COORD "%" PRIi16 ",%" PRIi16 ",%" PRIi16 -#define COORDARGS(id) id.x, id.y, id.z +#define COORDARGS(id) (id).x, (id).y, (id).z namespace CSP { extern std::unordered_set dignow_queue; @@ -81,12 +82,9 @@ inline bool isEntombed(const df::coord &unit_pos, const df::coord &map_pos) { } df::coord neighbours[8]; get_neighbours(map_pos, neighbours); - for (auto n: neighbours) { - if (Maps::canWalkBetween(unit_pos, n)) { - return false; - } - } - return true; + return std::all_of(neighbours+0, neighbours+8, [&unit_pos](df::coord n) { + return !Maps::canWalkBetween(unit_pos, n); + }); } inline bool is_dig_job(const df::job* job) { @@ -145,22 +143,6 @@ inline bool is_safe_to_dig_down(const df::coord &map_pos) { return false; } -inline bool can_reach_designation(const df::coord &start, const df::coord &end) { - if (start != end) { - if (!Maps::canWalkBetween(start, end)) { - df::coord neighbours[8]; - get_neighbours(end, neighbours); - for (auto &pos: neighbours) { - if (Maps::isValidTilePos(pos) && Maps::canWalkBetween(start, pos)) { - return true; - } - } - return false; - } - } - return true; -} - inline bool has_unit(const df::tile_occupancy* occupancy) { return occupancy->bits.unit || occupancy->bits.unit_grounded; } @@ -235,8 +217,62 @@ inline void cancel_job(const df::coord &map_pos) { // executes dig designations for the specified tile coordinates inline bool dig_now(color_ostream &out, const df::coord &map_pos) { + static std::default_random_engine rng; + std::uniform_int_distribution<> dist(0,5); out.color(color_value::COLOR_YELLOW); out.print("channel-safely: insta-dig: digging (" COORD ")<\n", COORDARGS(map_pos)); + + df::coord below(map_pos); + below.z--; + auto ttype_below = *Maps::getTileType(below); + if (isOpenTerrain(ttype_below) || isFloorTerrain(ttype_below)) { + *Maps::getTileType(map_pos) = tiletype::OpenSpace; + } else { + auto ttype_p = Maps::getTileType(map_pos); + if (isSoilMaterial(*ttype_p)) { + switch(dist(rng)) { + case 0: + *ttype_p = tiletype::SoilFloor1; + break; + case 1: + *ttype_p = tiletype::SoilFloor2; + break; + case 2: + *ttype_p = tiletype::SoilFloor3; + break; + case 3: + *ttype_p = tiletype::SoilFloor4; + break; + default: + *ttype_p = tiletype::SoilFloor1; + break; + } + } else if (isStoneMaterial(*ttype_p)) { + switch(dist(rng)) { + case 0: + *ttype_p = tiletype::FeatureFloor1; + break; + case 1: + *ttype_p = tiletype::FeatureFloor2; + break; + case 2: + *ttype_p = tiletype::FeatureFloor3; + break; + case 3: + *ttype_p = tiletype::FeatureFloor4; + break; + default: + *ttype_p = tiletype::MineralFloor1; + break; + } + } else { + out.print("Unknown type\n"); + return false; + } + } + + return true; + /* bool ret = false; lua_State* state = Lua::Core::State; @@ -253,6 +289,7 @@ inline bool dig_now(color_ostream &out, const df::coord &map_pos) { Lua::StackUnwinder top(state); Lua::CallLuaModuleFunction(out, state, module_name, fn_name, 1, 1, args_lambda, res_lambda); return ret; + */ } // fully heals the unit specified, resurrecting if need be