#include "DataDefs.h" #include "Error.h" #include "modules/Designations.h" #include "modules/Job.h" #include "modules/Maps.h" #include "df/job.h" #include "df/map_block.h" #include "df/plant.h" #include "df/plant_tree_info.h" #include "df/plant_tree_tile.h" #include "df/tile_dig_designation.h" #include "df/world.h" using namespace DFHack; using namespace df::enums; using df::global::world; static df::map_block *getPlantBlock(const df::plant *plant) { if (!world) return nullptr; return Maps::getTileBlock(Designations::getPlantDesignationTile(plant)); } df::coord Designations::getPlantDesignationTile(const df::plant *plant) { CHECK_NULL_POINTER(plant); if (!plant->tree_info) return plant->pos; int dimx = plant->tree_info->dim_x; int dimy = plant->tree_info->dim_y; int cx = dimx / 2; int cy = dimy / 2; // Find the southeast trunk tile int x = cx; int y = cy; while (x + 1 < dimx && y + 1 < dimy) { if (plant->tree_info->body[0][(y * dimx) + (x + 1)].bits.trunk) ++x; else if (plant->tree_info->body[0][((y + 1) * dimx) + x].bits.trunk) ++y; else break; } return df::coord(plant->pos.x - cx + x, plant->pos.y - cy + y, plant->pos.z); } bool Designations::isPlantMarked(const df::plant *plant) { CHECK_NULL_POINTER(plant); df::coord des_pos = getPlantDesignationTile(plant); df::map_block *block = Maps::getTileBlock(des_pos); if (!block) return false; if (block->designation[des_pos.x % 16][des_pos.y % 16].bits.dig == tile_dig_designation::Default) return true; for (auto *link = world->jobs.list.next; link; link = link->next) { df::job *job = link->item; if (!job) continue; if (job->job_type != job_type::FellTree && job->job_type != job_type::GatherPlants) continue; if (job->pos == des_pos) return true; } return false; } bool Designations::canMarkPlant(const df::plant *plant) { CHECK_NULL_POINTER(plant); if (!getPlantBlock(plant)) return false; return !isPlantMarked(plant); } bool Designations::markPlant(const df::plant *plant) { CHECK_NULL_POINTER(plant); if (canMarkPlant(plant)) { df::coord des_pos = getPlantDesignationTile(plant); df::map_block *block = Maps::getTileBlock(des_pos); block->designation[des_pos.x % 16][des_pos.y % 16].bits.dig = tile_dig_designation::Default; block->flags.bits.designated = true; return true; } else { return false; } } bool Designations::canUnmarkPlant(const df::plant *plant) { CHECK_NULL_POINTER(plant); if (!getPlantBlock(plant)) return false; return isPlantMarked(plant); } bool Designations::unmarkPlant(const df::plant *plant) { CHECK_NULL_POINTER(plant); if (canUnmarkPlant(plant)) { df::coord des_pos = getPlantDesignationTile(plant); df::map_block *block = Maps::getTileBlock(des_pos); block->designation[des_pos.x % 16][des_pos.y % 16].bits.dig = tile_dig_designation::No; block->flags.bits.designated = true; auto *link = world->jobs.list.next; while (link) { auto *next = link->next; df::job *job = link->item; if (job && (job->job_type == job_type::FellTree || job->job_type == job_type::GatherPlants) && job->pos == des_pos) { Job::removeJob(job); } link = next; } return true; } else { return false; } }