#pragma once #include "plugin.h" #include "channel-manager.h" #include #include #include #include #include #define Coord(id) id.x][id.y #define COORD "%" PRIi16 " %" PRIi16 " %" PRIi16 #define COORDARGS(id) id.x, id.y, id.z namespace CSP { extern std::unordered_set dignow_queue; } inline bool is_dig_job(const df::job* job) { return job->job_type == df::job_type::Dig || job->job_type == df::job_type::DigChannel; } inline bool is_dig_designation(const df::tile_designation &designation) { return designation.bits.dig != df::tile_dig_designation::No; } inline bool has_unit(const df::tile_occupancy* occupancy) { return occupancy->bits.unit || occupancy->bits.unit_grounded; } inline bool is_safe_fall(const df::coord &map_pos) { df::coord below(map_pos); for (uint8_t zi = 0; zi < config.fall_threshold; ++zi) { below.z--; if (config.require_vision && Maps::getTileDesignation(below)->bits.hidden) { return true; //we require vision, and we can't see below.. so we gotta assume it's safe } df::tiletype type = *Maps::getTileType(below); if (!isOpenTerrain(type)) { return true; } } return false; } inline bool is_safe_to_dig_down(const df::coord &map_pos) { df::coord pos(map_pos); for (uint8_t zi = 0; zi <= config.fall_threshold; ++zi) { // assume safe if we can't see and need vision if (config.require_vision && Maps::getTileDesignation(pos)->bits.hidden) { return true; } df::tiletype type = *Maps::getTileType(pos); if (zi == 0 && isOpenTerrain(type)) { // the starting tile is open space, that's obviously not safe return false; } else if (!isOpenTerrain(type)) { // a tile after the first one is not open space return true; } pos.z--; } return false; } inline bool is_group_occupied(const ChannelGroups &groups, const Group &group) { // return true if any tile in the group is occupied by a unit return std::any_of(group.begin(), group.end(), [](const Group::key_type &pos){ return has_unit(Maps::getTileOccupancy(pos)); }); } inline bool has_group_above(const ChannelGroups &groups, const df::coord &map_pos) { df::coord above(map_pos); above.z++; if (groups.count(above)) { return true; } return false; } inline bool has_any_groups_above(const ChannelGroups &groups, const Group &group) { // for each designation in the group for (auto &pos : group) { df::coord above(pos); above.z++; if (groups.count(above)) { return true; } } // if there are no incomplete groups above this group, then this group is ready return false; } inline void cancel_job(df::job* job) { if (job != nullptr) { df::coord &pos = job->pos; df::map_block* job_block = Maps::getTileBlock(pos); uint16_t x, y; x = pos.x % 16; y = pos.y % 16; df::tile_designation &designation = job_block->designation[x][y]; switch (job->job_type) { case job_type::Dig: designation.bits.dig = df::tile_dig_designation::Default; break; case job_type::CarveUpwardStaircase: designation.bits.dig = df::tile_dig_designation::UpStair; break; case job_type::CarveDownwardStaircase: designation.bits.dig = df::tile_dig_designation::DownStair; break; case job_type::CarveUpDownStaircase: designation.bits.dig = df::tile_dig_designation::UpDownStair; break; case job_type::CarveRamp: designation.bits.dig = df::tile_dig_designation::Ramp; break; case job_type::DigChannel: designation.bits.dig = df::tile_dig_designation::Channel; break; default: designation.bits.dig = df::tile_dig_designation::No; break; } Job::removeJob(job); } } inline void get_neighbours(const df::coord &map_pos, df::coord(&neighbours)[8]) { neighbours[0] = map_pos; neighbours[1] = map_pos; neighbours[2] = map_pos; neighbours[3] = map_pos; neighbours[4] = map_pos; neighbours[5] = map_pos; neighbours[6] = map_pos; neighbours[7] = map_pos; neighbours[0].x--; neighbours[0].y--; neighbours[1].y--; neighbours[2].x++; neighbours[2].y--; neighbours[3].x--; neighbours[4].x++; neighbours[5].x--; neighbours[5].y++; neighbours[6].y++; neighbours[7].x++; neighbours[7].y++; }