dfhack/library/modules/Designations.cpp

154 lines
3.6 KiB
C++

#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;
}
}