danger of rotting)

develop
Kelly Martin 2012-04-18 11:33:17 -05:00
parent 9e1e34f69b
commit 2dc3aa1b89
1 changed files with 193 additions and 36 deletions

@ -8,10 +8,14 @@
#include "df/ui.h"
#include "df/building_stockpilest.h"
#include "df/global_objects.h"
#include "df/viewscreen_dwarfmodest.h"
#include "df/item.h"
#include "df/unit.h"
#include "df/building.h"
#include "df/items_other_id.h"
#include "df/item_stockpile_ref.h"
#include "modules/MapCache.h"
#include "modules/Items.h"
using std::vector;
using std::string;
@ -35,9 +39,9 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector <Plugi
{
if (world && ui) {
commands.push_back(
PluginCommand("stockcheck", "Check for stockpile adequacy.",
PluginCommand("stockcheck", "Check for unprotected rottable items.",
stockcheck, false,
"Scan world for unstockpiled items and verify stockpiles exist for them.\n"
"Scan world for items that are susceptible to rot. Currently just lists the items.\n"
)
);
}
@ -49,10 +53,74 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out )
return CR_OK;
}
struct StockpileInfo {
building_stockpilest* sp;
int size;
int free;
int x1, x2, y1, y2, z;
public:
StockpileInfo(building_stockpilest *sp_) : sp(sp_)
{
MapExtras::MapCache mc;
z = sp_->z;
x1 = sp_->room.x;
x2 = sp_->room.x + sp_->room.width;
y1 = sp_->room.y;
y2 = sp_->room.y + sp_->room.height;
int e = 0;
size = 0;
free = 0;
for (int y = y1; y < y2; y++)
for (int x = x1; x < x2; x++)
if (sp_->room.extents[e++] == 1)
{
size++;
DFCoord cursor (x,y,z);
uint32_t blockX = x / 16;
uint32_t tileX = x % 16;
uint32_t blockY = y / 16;
uint32_t tileY = y % 16;
MapExtras::Block * b = mc.BlockAt(cursor/16);
if(b && b->is_valid())
{
auto &block = *b->getRaw();
df::tile_occupancy &occ = block.occupancy[tileX][tileY];
if (!occ.bits.item)
free++;
}
}
}
bool isFull() { return free == 0; }
bool canHold(df::item *i)
{
return false;
}
bool inStockpile(df::item *i)
{
df::item *container = Items::getContainer(i);
if (container)
return inStockpile(container);
if (i->pos.z != z) return false;
if (i->pos.x < x1 || i->pos.x >= x2 ||
i->pos.y < y1 || i->pos.y >= y2) return false;
int e = (i->pos.x - x1) + (i->pos.y - y1) * sp->room.width;
return sp->room.extents[e] == 1;
}
int getId() { return sp->id; }
};
static command_result stockcheck(color_ostream &out, vector <string> & parameters)
{
CoreSuspender suspend;
MapExtras::MapCache mc;
std::vector<StockpileInfo*> stockpiles;
for (int i = 0; i < world->buildings.all.size(); ++i)
{
@ -61,38 +129,10 @@ static command_result stockcheck(color_ostream &out, vector <string> & parameter
if (df::enums::building_type::Stockpile == type)
{
building_stockpilest *sp = virtual_cast<building_stockpilest>(build);
df::stockpile_settings st = sp->settings;
out << "Stockpile " << sp->stockpile_number << ":\n";
out << " width=" << build->room.width << " height= " << build->room.height << endl;
int x1 = build->room.x;
int x2 = build->room.x + build->room.width;
int y1 = build->room.y;
int y2 = build->room.y + build->room.height;
int e = 0;
int size = 0, free = 0;
for (int x = x1; x < x2; x++)
for (int y = y1; y < y2; y++)
if (build->room.extents[e++] == 1)
{
size++;
DFCoord cursor (x,y,build->z);
uint32_t blockX = x / 16;
uint32_t tileX = x % 16;
uint32_t blockY = y / 16;
uint32_t tileY = y % 16;
MapExtras::Block * b = mc.BlockAt(cursor/16);
if(b && b->is_valid())
{
auto &block = *b->getRaw();
df::tile_occupancy &occ = block.occupancy[tileX][tileY];
if (!occ.bits.item)
free++;
}
}
out << " size=" << size << " free= " << free << endl;
StockpileInfo *spi = new StockpileInfo(sp);
stockpiles.push_back(spi);
}
}
std::vector<df::item*> &items = world->items.other[items_other_id::ANY_FREE];
@ -105,6 +145,7 @@ static command_result stockcheck(color_ostream &out, vector <string> & parameter
F(dump); F(forbid); F(garbage_collect);
F(hostile); F(on_fire); F(rotten); F(trader);
F(in_building); F(construction); F(artifact1);
F(spider_web); F(owned); F(in_job);
#undef F
for (size_t i = 0; i < items.size(); i++)
@ -113,9 +154,125 @@ static command_result stockcheck(color_ostream &out, vector <string> & parameter
if (item->flags.whole & bad_flags.whole)
continue;
// we really only care about MEAT, FISH, FISH_RAW, PLANT, CHEESE, FOOD, and EGG
df::item_type typ = item->getType();
if (typ != df::enums::item_type::MEAT &&
typ != df::enums::item_type::FISH &&
typ != df::enums::item_type::FISH_RAW &&
typ != df::enums::item_type::PLANT &&
typ != df::enums::item_type::CHEESE &&
typ != df::enums::item_type::FOOD &&
typ != df::enums::item_type::EGG)
continue;
df::item *container = 0;
df::unit *holder = 0;
df::building *building = 0;
for (size_t i = 0; i < item->itemrefs.size(); i++)
{
df::general_ref *ref = item->itemrefs[i];
switch (ref->getType())
{
case general_ref_type::CONTAINED_IN_ITEM:
container = ref->getItem();
break;
case general_ref_type::UNIT_HOLDER:
holder = ref->getUnit();
break;
case general_ref_type::BUILDING_HOLDER:
building = ref->getBuilding();
break;
}
}
df::item *nextcontainer = container;
df::item *lastcontainer = 0;
while(nextcontainer) {
df::item *thiscontainer = nextcontainer;
nextcontainer = 0;
for (size_t i = 0; i < thiscontainer->itemrefs.size(); i++)
{
df::general_ref *ref = thiscontainer->itemrefs[i];
switch (ref->getType())
{
case general_ref_type::CONTAINED_IN_ITEM:
lastcontainer = nextcontainer = ref->getItem();
break;
case general_ref_type::UNIT_HOLDER:
holder = ref->getUnit();
break;
case general_ref_type::BUILDING_HOLDER:
building = ref->getBuilding();
break;
}
}
}
if (holder)
continue; // carried items do not rot as far as i know
if (building) {
df::building_type btype = building->getType();
if (btype == df::enums::building_type::TradeDepot ||
btype == df::enums::building_type::Wagon)
continue; // items in trade depot or the embark wagon do not rot
if (typ == df::enums::item_type::EGG && btype ==df::enums::building_type::NestBox)
continue; // eggs in nest box do not rot
}
int canHoldCount = 0;
StockpileInfo *current = 0;
for (int idx = 0; idx < stockpiles.size(); idx++)
{
StockpileInfo *spi = stockpiles[idx];
if (spi->canHold(item)) canHoldCount++;
if (spi->inStockpile(item)) current=spi;
}
if (current)
continue;
std::string description;
item->getItemDescription(&description, 0);
out << " * " << description;
if (container) {
std::string containerDescription;
container->getItemDescription(&containerDescription, 0);
out << ", in container " << containerDescription;
if (lastcontainer) {
std::string lastcontainerDescription;
lastcontainer->getItemDescription(&lastcontainerDescription, 0);
out << ", in container " << lastcontainerDescription;
}
}
if (holder) {
out << ", carried";
}
if (building) {
out << ", in building " << building->id << " (type=" << building->getType() << ")";
}
out << ", flags=" << std::hex << item->flags.whole << std::dec;
out << endl;
}
out << "Stockcheck done" << endl;
return CR_OK;
}