|
|
|
@ -6,7 +6,6 @@
|
|
|
|
|
#include "PluginManager.h"
|
|
|
|
|
#include "TileTypes.h"
|
|
|
|
|
#include "LuaTools.h"
|
|
|
|
|
#include "Debug.h"
|
|
|
|
|
|
|
|
|
|
#include "modules/Buildings.h"
|
|
|
|
|
#include "modules/Gui.h"
|
|
|
|
@ -15,8 +14,6 @@
|
|
|
|
|
#include "modules/Random.h"
|
|
|
|
|
#include "modules/Units.h"
|
|
|
|
|
#include "modules/World.h"
|
|
|
|
|
#include "modules/EventManager.h"
|
|
|
|
|
#include "modules/Job.h"
|
|
|
|
|
|
|
|
|
|
#include <df/historical_entity.h>
|
|
|
|
|
#include <df/map_block.h>
|
|
|
|
@ -29,129 +26,12 @@
|
|
|
|
|
#include <df/world.h>
|
|
|
|
|
#include <df/world_site.h>
|
|
|
|
|
|
|
|
|
|
#include <cinttypes>
|
|
|
|
|
#include <unordered_set>
|
|
|
|
|
#include <unordered_map>
|
|
|
|
|
|
|
|
|
|
DFHACK_PLUGIN("dig-now");
|
|
|
|
|
REQUIRE_GLOBAL(plotinfo);
|
|
|
|
|
REQUIRE_GLOBAL(world);
|
|
|
|
|
|
|
|
|
|
// Debugging
|
|
|
|
|
namespace DFHack {
|
|
|
|
|
DBG_DECLARE(dignow, general, DebugCategory::LINFO);
|
|
|
|
|
DBG_DECLARE(dignow, channels, DebugCategory::LINFO);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define COORD "%" PRIi16 " %" PRIi16 " %" PRIi16
|
|
|
|
|
#define COORDARGS(id) id.x, id.y, id.z
|
|
|
|
|
|
|
|
|
|
using namespace DFHack;
|
|
|
|
|
|
|
|
|
|
struct designation{
|
|
|
|
|
df::coord pos;
|
|
|
|
|
df::tile_designation type;
|
|
|
|
|
df::tile_occupancy occupancy;
|
|
|
|
|
designation() = default;
|
|
|
|
|
designation(const df::coord &c, const df::tile_designation &td, const df::tile_occupancy &to) : pos(c), type(td), occupancy(to) {}
|
|
|
|
|
|
|
|
|
|
bool operator==(const designation &rhs) const {
|
|
|
|
|
return pos == rhs.pos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool operator!=(const designation &rhs) const {
|
|
|
|
|
return !(rhs == *this);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
namespace std {
|
|
|
|
|
template<>
|
|
|
|
|
struct hash<designation> {
|
|
|
|
|
std::size_t operator()(const designation &c) const {
|
|
|
|
|
std::hash<df::coord> hash_coord;
|
|
|
|
|
return hash_coord(c.pos);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class DesignationJobs {
|
|
|
|
|
private:
|
|
|
|
|
std::unordered_map<df::coord, designation> designations;
|
|
|
|
|
std::unordered_map<df::coord, df::job*> jobs;
|
|
|
|
|
public:
|
|
|
|
|
void load(MapExtras::MapCache &map) {
|
|
|
|
|
designations.clear();
|
|
|
|
|
df::job_list_link* node = df::global::world->jobs.list.next;
|
|
|
|
|
while (node) {
|
|
|
|
|
df::job* job = node->item;
|
|
|
|
|
if(!job || !Maps::isValidTilePos(job->pos))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
node = node->next;
|
|
|
|
|
df::tile_designation td = map.designationAt(job->pos);
|
|
|
|
|
df::tile_occupancy to = map.occupancyAt(job->pos);
|
|
|
|
|
const auto ctd = td.whole;
|
|
|
|
|
const auto cto = to.whole;
|
|
|
|
|
switch (job->job_type){
|
|
|
|
|
case job_type::Dig:
|
|
|
|
|
td.bits.dig = tile_dig_designation::Default;
|
|
|
|
|
break;
|
|
|
|
|
case job_type::DigChannel:
|
|
|
|
|
td.bits.dig = tile_dig_designation::Channel;
|
|
|
|
|
break;
|
|
|
|
|
case job_type::CarveRamp:
|
|
|
|
|
td.bits.dig = tile_dig_designation::Ramp;
|
|
|
|
|
break;
|
|
|
|
|
case job_type::CarveUpwardStaircase:
|
|
|
|
|
td.bits.dig = tile_dig_designation::UpStair;
|
|
|
|
|
break;
|
|
|
|
|
case job_type::CarveDownwardStaircase:
|
|
|
|
|
td.bits.dig = tile_dig_designation::DownStair;
|
|
|
|
|
break;
|
|
|
|
|
case job_type::CarveUpDownStaircase:
|
|
|
|
|
td.bits.dig = tile_dig_designation::UpDownStair;
|
|
|
|
|
break;
|
|
|
|
|
case job_type::DetailWall:
|
|
|
|
|
case job_type::DetailFloor: {
|
|
|
|
|
df::tiletype tt = map.tiletypeAt(job->pos);
|
|
|
|
|
if (tileSpecial(tt) != df::tiletype_special::SMOOTH) {
|
|
|
|
|
td.bits.smooth = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case job_type::CarveTrack:
|
|
|
|
|
to.bits.carve_track_north = (job->item_category.whole >> 18) & 1;
|
|
|
|
|
to.bits.carve_track_south = (job->item_category.whole >> 19) & 1;
|
|
|
|
|
to.bits.carve_track_west = (job->item_category.whole >> 20) & 1;
|
|
|
|
|
to.bits.carve_track_east = (job->item_category.whole >> 21) & 1;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (ctd != td.whole || cto != to.whole) {
|
|
|
|
|
// we found a designation job
|
|
|
|
|
designations.emplace(job->pos, designation(job->pos, td, to));
|
|
|
|
|
jobs.emplace(job->pos, job);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void remove(const df::coord &pos) {
|
|
|
|
|
if(jobs.count(pos)) {
|
|
|
|
|
Job::removeJob(jobs[pos]);
|
|
|
|
|
jobs.erase(pos);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
designation get(const df::coord &pos) {
|
|
|
|
|
if (designations.count(pos)) {
|
|
|
|
|
return designations[pos];
|
|
|
|
|
}
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
bool count(const df::coord &pos) {
|
|
|
|
|
return jobs.count(pos);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct boulder_percent_options {
|
|
|
|
|
// percent chance ([0..100]) for creating a boulder for the given rock type
|
|
|
|
|
uint32_t layer;
|
|
|
|
@ -440,19 +320,8 @@ static bool dig_tile(color_ostream &out, MapExtras::MapCache &map,
|
|
|
|
|
std::vector<dug_tile_info> &dug_tiles) {
|
|
|
|
|
df::tiletype tt = map.tiletypeAt(pos);
|
|
|
|
|
|
|
|
|
|
if (!is_diggable(map, pos, tt)) {
|
|
|
|
|
DEBUG(general).print("dig_tile: not diggable\n");
|
|
|
|
|
if (!is_diggable(map, pos, tt))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** The algorithm process seems to be:
|
|
|
|
|
* for each tile
|
|
|
|
|
* check for a designation
|
|
|
|
|
* if a designation exists send it to dig_tile
|
|
|
|
|
*
|
|
|
|
|
* dig_tile (below) then digs the layer below the channel designated tile
|
|
|
|
|
* thereby changing it and causing its designation to be lost
|
|
|
|
|
* */
|
|
|
|
|
|
|
|
|
|
df::tiletype target_type = df::tiletype::Void;
|
|
|
|
|
switch(designation) {
|
|
|
|
@ -472,22 +341,19 @@ static bool dig_tile(color_ostream &out, MapExtras::MapCache &map,
|
|
|
|
|
DFCoord pos_below(pos.x, pos.y, pos.z-1);
|
|
|
|
|
if (can_dig_channel(tt) && map.ensureBlockAt(pos_below)
|
|
|
|
|
&& is_diggable(map, pos_below, map.tiletypeAt(pos_below))) {
|
|
|
|
|
TRACE(channels).print("dig_tile: channeling at (" COORD ") [can_dig_channel: true]\n",COORDARGS(pos_below));
|
|
|
|
|
target_type = df::tiletype::OpenSpace;
|
|
|
|
|
DFCoord pos_above(pos.x, pos.y, pos.z+1);
|
|
|
|
|
if (map.ensureBlockAt(pos_above)) {
|
|
|
|
|
if (map.ensureBlockAt(pos_above))
|
|
|
|
|
remove_ramp_top(map, pos_above);
|
|
|
|
|
}
|
|
|
|
|
df::tile_dig_designation td_below = map.designationAt(pos_below).bits.dig;
|
|
|
|
|
if (dig_tile(out, map, pos_below, df::tile_dig_designation::Ramp, dug_tiles)) {
|
|
|
|
|
df::tile_dig_designation td_below =
|
|
|
|
|
map.designationAt(pos_below).bits.dig;
|
|
|
|
|
if (dig_tile(out, map, pos_below,
|
|
|
|
|
df::tile_dig_designation::Ramp, dug_tiles)) {
|
|
|
|
|
clean_ramps(map, pos_below);
|
|
|
|
|
if (td_below == df::tile_dig_designation::Default) {
|
|
|
|
|
if (td_below == df::tile_dig_designation::Default)
|
|
|
|
|
dig_tile(out, map, pos_below, td_below, dug_tiles);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
DEBUG(channels).print("dig_tile: failed to channel at (" COORD ") [can_dig_channel: false]\n", COORDARGS(pos_below));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
@ -541,8 +407,7 @@ static bool dig_tile(color_ostream &out, MapExtras::MapCache &map,
|
|
|
|
|
if (target_type == df::tiletype::Void || target_type == tt)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
dug_tiles.emplace_back(map, pos);
|
|
|
|
|
TRACE(general).print("dig_tile: digging the designation tile at (" COORD ")\n",COORDARGS(pos));
|
|
|
|
|
dug_tiles.push_back(dug_tile_info(map, pos));
|
|
|
|
|
dig_type(map, pos, target_type);
|
|
|
|
|
|
|
|
|
|
// let light filter down to newly exposed tiles
|
|
|
|
@ -729,12 +594,9 @@ static void do_dig(color_ostream &out, std::vector<DFCoord> &dug_coords,
|
|
|
|
|
item_coords_t &item_coords, const dig_now_options &options) {
|
|
|
|
|
MapExtras::MapCache map;
|
|
|
|
|
Random::MersenneRNG rng;
|
|
|
|
|
DesignationJobs jobs;
|
|
|
|
|
|
|
|
|
|
jobs.load(map);
|
|
|
|
|
rng.init();
|
|
|
|
|
|
|
|
|
|
std::unordered_set<designation> buffer;
|
|
|
|
|
// go down levels instead of up so stacked ramps behave as expected
|
|
|
|
|
for (int16_t z = options.end.z; z >= options.start.z; --z) {
|
|
|
|
|
for (int16_t y = options.start.y; y <= options.end.y; ++y) {
|
|
|
|
@ -747,68 +609,46 @@ static void do_dig(color_ostream &out, std::vector<DFCoord> &dug_coords,
|
|
|
|
|
DFCoord pos(x, y, z);
|
|
|
|
|
df::tile_designation td = map.designationAt(pos);
|
|
|
|
|
df::tile_occupancy to = map.occupancyAt(pos);
|
|
|
|
|
if (jobs.count(pos)) {
|
|
|
|
|
buffer.emplace(jobs.get(pos));
|
|
|
|
|
jobs.remove(pos);
|
|
|
|
|
// if it does get removed, then we're gonna buffer the jobs info then remove the job
|
|
|
|
|
} else if ((td.bits.dig != df::tile_dig_designation::No && !to.bits.dig_marked)
|
|
|
|
|
|| td.bits.smooth == 1
|
|
|
|
|
|| to.bits.carve_track_north == 1
|
|
|
|
|
|| to.bits.carve_track_east == 1
|
|
|
|
|
|| to.bits.carve_track_south == 1
|
|
|
|
|
|| to.bits.carve_track_west == 1) {
|
|
|
|
|
|
|
|
|
|
// we're only buffering designations, so that processing doesn't affect what we're buffering
|
|
|
|
|
buffer.emplace(pos, td, to);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// process designations
|
|
|
|
|
for(auto &d : buffer) {
|
|
|
|
|
auto pos = d.pos;
|
|
|
|
|
auto td = d.type;
|
|
|
|
|
auto to = d.occupancy;
|
|
|
|
|
|
|
|
|
|
if (td.bits.dig != df::tile_dig_designation::No && !to.bits.dig_marked) {
|
|
|
|
|
std::vector<dug_tile_info> dug_tiles;
|
|
|
|
|
|
|
|
|
|
if (dig_tile(out, map, pos, td.bits.dig, dug_tiles)) {
|
|
|
|
|
for (auto info: dug_tiles) {
|
|
|
|
|
td = map.designationAt(info.pos);
|
|
|
|
|
td.bits.dig = df::tile_dig_designation::No;
|
|
|
|
|
map.setDesignationAt(info.pos, td);
|
|
|
|
|
|
|
|
|
|
dug_coords.push_back(info.pos);
|
|
|
|
|
refresh_adjacent_smooth_walls(map, info.pos);
|
|
|
|
|
if (info.imat < 0)
|
|
|
|
|
continue;
|
|
|
|
|
if (produces_item(options.boulder_percents,
|
|
|
|
|
map, rng, info)) {
|
|
|
|
|
auto k = std::make_pair(info.itype, info.imat);
|
|
|
|
|
item_coords[k].push_back(info.pos);
|
|
|
|
|
if (td.bits.dig != df::tile_dig_designation::No &&
|
|
|
|
|
!to.bits.dig_marked) {
|
|
|
|
|
std::vector<dug_tile_info> dug_tiles;
|
|
|
|
|
if (dig_tile(out, map, pos, td.bits.dig, dug_tiles)) {
|
|
|
|
|
for (auto info : dug_tiles) {
|
|
|
|
|
td = map.designationAt(info.pos);
|
|
|
|
|
td.bits.dig = df::tile_dig_designation::No;
|
|
|
|
|
map.setDesignationAt(info.pos, td);
|
|
|
|
|
|
|
|
|
|
dug_coords.push_back(info.pos);
|
|
|
|
|
refresh_adjacent_smooth_walls(map, info.pos);
|
|
|
|
|
if (info.imat < 0)
|
|
|
|
|
continue;
|
|
|
|
|
if (produces_item(options.boulder_percents,
|
|
|
|
|
map, rng, info)) {
|
|
|
|
|
auto k = std::make_pair(info.itype, info.imat);
|
|
|
|
|
item_coords[k].push_back(info.pos);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (td.bits.smooth == 1) {
|
|
|
|
|
if (smooth_tile(out, map, pos)) {
|
|
|
|
|
td = map.designationAt(pos);
|
|
|
|
|
td.bits.smooth = 0;
|
|
|
|
|
map.setDesignationAt(pos, td);
|
|
|
|
|
}
|
|
|
|
|
} else if (to.bits.carve_track_north == 1
|
|
|
|
|
|| to.bits.carve_track_east == 1
|
|
|
|
|
|| to.bits.carve_track_south == 1
|
|
|
|
|
|| to.bits.carve_track_west == 1) {
|
|
|
|
|
if (carve_tile(map, pos, to)) {
|
|
|
|
|
to = map.occupancyAt(pos);
|
|
|
|
|
to.bits.carve_track_north = 0;
|
|
|
|
|
to.bits.carve_track_east = 0;
|
|
|
|
|
to.bits.carve_track_south = 0;
|
|
|
|
|
to.bits.carve_track_west = 0;
|
|
|
|
|
map.setOccupancyAt(pos, to);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (td.bits.smooth == 1) {
|
|
|
|
|
if (smooth_tile(out, map, pos)) {
|
|
|
|
|
td = map.designationAt(pos);
|
|
|
|
|
td.bits.smooth = 0;
|
|
|
|
|
map.setDesignationAt(pos, td);
|
|
|
|
|
}
|
|
|
|
|
} else if (to.bits.carve_track_north == 1
|
|
|
|
|
|| to.bits.carve_track_east == 1
|
|
|
|
|
|| to.bits.carve_track_south == 1
|
|
|
|
|
|| to.bits.carve_track_west == 1) {
|
|
|
|
|
if (carve_tile(map, pos, to)) {
|
|
|
|
|
to = map.occupancyAt(pos);
|
|
|
|
|
to.bits.carve_track_north = 0;
|
|
|
|
|
to.bits.carve_track_east = 0;
|
|
|
|
|
to.bits.carve_track_south = 0;
|
|
|
|
|
to.bits.carve_track_west = 0;
|
|
|
|
|
map.setOccupancyAt(pos, to);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|