diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index fd6e07daf..d1204588f 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -143,3 +143,4 @@ DFHACK_PLUGIN(mode mode.cpp) #DFHACK_PLUGIN(tiles tiles.cpp) DFHACK_PLUGIN(liquids liquids.cpp) DFHACK_PLUGIN(tubefill tubefill.cpp) +DFHACK_PLUGIN(autodump autodump.cpp) diff --git a/plugins/autodump.cpp b/plugins/autodump.cpp new file mode 100644 index 000000000..87e823140 --- /dev/null +++ b/plugins/autodump.cpp @@ -0,0 +1,215 @@ +// Quick Dumper : Moves items marked as "dump" to cursor +// FIXME: local item cache in map blocks needs to be fixed after teleporting items +#include +#include +#include +#include +#include +#include +using namespace std; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace DFHack; +using MapExtras::Block; +using MapExtras::MapCache; + +DFhackCExport command_result df_autodump (Core * c, vector & parameters); + +DFhackCExport const char * plugin_name ( void ) +{ + return "autodump"; +} + +DFhackCExport command_result plugin_init ( Core * c, std::vector &commands) +{ + commands.clear(); + commands.push_back(PluginCommand("autodump", + "Teleport items marked for dumping to the cursor.", + df_autodump)); + return CR_OK; +} + +DFhackCExport command_result plugin_shutdown ( Core * c ) +{ + return CR_OK; +} + +typedef std::map coordmap; + +DFhackCExport command_result df_autodump (Core * c, vector & parameters) +{ + // Command line options + bool destroy = false; + if(parameters.size() > 0) + { + string & p = parameters[0]; + if(p == "destroy") + destroy = true; + else if(p == "?" || p == "help") + { + c->con.print( + "This utility lets you quickly move all items designated to be dumped.\n" + "Items are instantly moved to the cursor position, the dump flag is unset,\n" + "and the forbid flag is set, as if it had been dumped normally.\n" + "Be aware that any active dump item tasks still point at the item.\n\n" + ); + return CR_OK; + } + } + c->Suspend(); + DFHack::occupancies40d * occupancies; + DFHack::VersionInfo *mem = c->vinfo; + DFHack::Gui * Gui = c->getGui(); + DFHack::Items * Items = c->getItems(); + DFHack::Maps *Maps = c->getMaps(); + + vector p_items; + if(!Items->readItemVector(p_items)) + { + c->con.printerr("Can't access the item vector.\n"); + c->Resume(); + return CR_FAILURE; + } + std::size_t numItems = p_items.size(); + + // init the map + if(!Maps->Start()) + { + c->con.printerr("Can't initialize map.\n"); + c->Resume(); + return CR_FAILURE; + } + MapCache MC (Maps); + int i = 0; + int dumped_total = 0; + + int cx, cy, cz; + DFCoord pos_cursor; + if(!destroy) + { + if (!Gui->getCursorCoords(cx,cy,cz)) + { + c->con.printerr("Cursor position not found. Please enabled the cursor.\n"); + c->Resume(); + return CR_FAILURE; + } + pos_cursor = DFCoord(cx,cy,cz); + { + Block * b = MC.BlockAt(pos_cursor / 16); + if(!b) + { + c->con.printerr("Cursor is in an invalid/uninitialized area. Place it over a floor.\n"); + c->Resume(); + return CR_FAILURE; + } + uint16_t ttype = MC.tiletypeAt(pos_cursor); + if(!DFHack::isFloorTerrain(ttype)) + { + c->con.printerr("Cursor should be placed over a floor.\n"); + c->Resume(); + return CR_FAILURE; + } + } + } + coordmap counts; + // proceed with the dumpification operation + for(std::size_t i=0; i< numItems; i++) + { + t_item * itm = p_items[i]; + DFCoord pos_item(itm->x, itm->y, itm->z); + + // keep track how many items are at places. all items. + coordmap::iterator it = counts.find(pos_item); + if(it == counts.end()) + { + std::pair< coordmap::iterator, bool > inserted = counts.insert(std::make_pair(pos_item,1)); + it = inserted.first; + } + else + { + it->second ++; + } + // iterator is valid here, we use it later to decrement the pile counter if the item is moved + + // only dump the stuff marked for dumping and laying on the ground + if ( !itm->flags.dump + || !itm->flags.on_ground + || itm->flags.construction + || itm->flags.hidden + || itm->flags.in_building + || itm->flags.in_chest + || itm->flags.in_inventory + || itm->flags.construction + ) + continue; + + if(!destroy) // move to cursor + { + // Change flags to indicate the dump was completed, as if by super-dwarfs + itm->flags.dump = false; + itm->flags.forbid = true; + + // Don't move items if they're already at the cursor + if (pos_cursor == pos_item) + continue; + + // Move the item + itm->x = pos_cursor.x; + itm->y = pos_cursor.y; + itm->z = pos_cursor.z; + } + else // destroy + { + itm->flags.garbage_colect = true; + } + // keeping track of item pile sizes ;) + it->second --; + dumped_total++; + } + if(!destroy) // TODO: do we have to do any of this when destroying items? + { + // for each item pile, see if it reached zero. if so, unset item flag on the tile it's on + coordmap::iterator it = counts.begin(); + coordmap::iterator end = counts.end(); + while(it != end) + { + if(it->second == 0) + { + t_occupancy occ = MC.occupancyAt(it->first); + occ.bits.item = false; + MC.setOccupancyAt(it->first, occ); + } + it++; + } + // Set "item here" flag on target tile, if we moved any items to the target tile. + if (dumped_total > 0) + { + // assume there is a possibility the cursor points at some weird location with missing block data + Block * b = MC.BlockAt(pos_cursor / 16); + if(b) + { + t_occupancy occ = MC.occupancyAt(pos_cursor); + occ.bits.item = 1; + MC.setOccupancyAt(pos_cursor,occ); + } + } + // write map changes back to DF. + MC.WriteAll(); + // Is this necessary? Is "forbid" a dirtyable attribute like "dig" is? + Maps->WriteDirtyBit(cx/16, cy/16, cz, true); + } + c->Resume(); + c->con.print("Done. %d items %s.\n", dumped_total, destroy ? "marked for desctruction" : "quickdumped"); + return CR_OK; +} \ No newline at end of file diff --git a/tools/supported/cleanowned.cpp b/plugins/cleanowned.cpp similarity index 100% rename from tools/supported/cleanowned.cpp rename to plugins/cleanowned.cpp diff --git a/tools/supported/cleartask.cpp b/plugins/cleartask.cpp similarity index 100% rename from tools/supported/cleartask.cpp rename to plugins/cleartask.cpp diff --git a/tools/supported/deramp.cpp b/plugins/deramp.cpp similarity index 100% rename from tools/supported/deramp.cpp rename to plugins/deramp.cpp diff --git a/tools/supported/flows.cpp b/plugins/flows.cpp similarity index 100% rename from tools/supported/flows.cpp rename to plugins/flows.cpp diff --git a/plugins/probe.cpp b/plugins/probe.cpp index dc1812eb4..916989a96 100644 --- a/plugins/probe.cpp +++ b/plugins/probe.cpp @@ -46,85 +46,7 @@ DFhackCExport command_result plugin_shutdown ( Core * c ) { return CR_OK; } -/* -bool parseOptions(vector ¶ms, bool &showBlock, bool &showDesig, - bool &showOccup, bool &showTile, bool &showMisc) -{ - // With no options set, show everything. - showBlock = true; - showDesig = true; - showOccup = true; - showTile = true; - showMisc = true; - - bool _showBlock = false; - bool _showDesig = false; - bool _showOccup = false; - bool _showTile = false; - bool _showMisc = false; - - char c; - xgetopt opt(params, "bdotm"); - opt.opterr = 0; - while ((c = opt()) != -1) - { - switch (c) - { - case 'b': - _showBlock = true; - break; - case 'd': - _showDesig = true; - break; - case 'o': - _showOccup = true; - break; - case 't': - _showTile = true; - break; - case 'm': - _showMisc = true; - break; - - case '?': - switch (opt.optopt) - { - // For when we take arguments - default: - if (isprint(opt.optopt)) - std::cerr << "Unknown option -" << opt.optopt << "!" - << std::endl; - else - std::cerr << "Unknown option character " << (int) opt.optopt << "!" - << std::endl; - } - default: - // Um..... - return false; - } - } - - // If any options set, show only those requested via options. - if(_showBlock || _showDesig || _showOccup || _showTile || _showMisc) - { - showBlock = false; - showDesig = false; - showOccup = false; - showTile = false; - showMisc = false; - - showBlock = _showBlock; - showDesig = _showDesig; - showOccup = _showOccup; - showTile = _showTile; - showMisc = _showMisc; - } - - return true; -} -*/ -using namespace DFHack; DFhackCExport command_result df_probe (Core * c, vector & parameters) { //bool showBlock, showDesig, showOccup, showTile, showMisc; diff --git a/tools/supported/tiletypes.cpp b/plugins/tiletypes.cpp similarity index 100% rename from tools/supported/tiletypes.cpp rename to plugins/tiletypes.cpp diff --git a/tools/supported/autodump.cpp b/tools/supported/autodump.cpp deleted file mode 100644 index bc85967ab..000000000 --- a/tools/supported/autodump.cpp +++ /dev/null @@ -1,215 +0,0 @@ -// Quick Dumper : Moves items marked as "dump" to cursor - -#include -#include -#include -#include -#include -#include -using namespace std; - -#include -#include -#include // map cache for the win. -#include -using namespace DFHack; -using MapExtras::Block; -using MapExtras::MapCache; - -typedef std::map coordmap; - -int main (int argc, char * argv[]) -{ - bool temporary_terminal = TemporaryTerminal(); - // Command line options - bool destroy = false; - if(argc > 1 && strcmp(argv[1],"-d") == 0) - destroy = true; - - DFHack::ContextManager CM ("Memory.xml"); - DFHack::Context * DF; - DFHack::VersionInfo *mem; - DFHack::Gui * Gui; - DFHack::Items * Items; - DFHack::Maps *Maps; - DFHack::occupancies40d * occupancies; - - cout << "This utility lets you quickly move all items designated to be dumped." << endl - << "Items are instantly moved to the cursor position, the dump flag is unset," << endl - << "and the forbid flag is set, as if it had been dumped normally." << endl - << "Be aware that any active dump item tasks still point at the item." << endl << endl; - - uint32_t vector_addr = 0; - - try - { - DF = CM.getSingleContext(); - DF->Attach(); - mem = DF->getMemoryInfo(); - Gui = DF->getGui(); - Items = DF->getItems(); - Maps = DF->getMaps(); - DFHack::OffsetGroup* itemGroup = mem->getGroup("Items"); - vector_addr = itemGroup->getAddress("items_vector"); - } - catch (exception& e) - { - cerr << e.what() << endl; - if(temporary_terminal) - cin.ignore(); - return 1; - } - - DFHack::Process * p = DF->getProcess(); - DFHack::DfVector p_items (p, vector_addr); - uint32_t numItems = p_items.size(); - - // init the map - if(!Maps->Start()) - { - cerr << "Can't initialize map." << endl; - if(temporary_terminal) - cin.ignore(); - return 1; - } - MapCache MC (Maps); - - int i = 0; - int dumped_total = 0; - - int cx, cy, cz; - DFCoord pos_cursor; - if(!destroy) - { - if (!Gui->getCursorCoords(cx,cy,cz)) - { - cerr << "Cursor position not found. Please enabled the cursor." << endl; - if(temporary_terminal) - cin.ignore(); - return 1; - } - pos_cursor = DFCoord(cx,cy,cz); - { - Block * b = MC.BlockAt(pos_cursor / 16); - if(!b) - { - cerr << "Cursor is in an invalid area. Place it over something save first." << endl; - if(temporary_terminal) - cin.ignore(); - return 1; - } - uint16_t ttype = MC.tiletypeAt(pos_cursor); - if(!DFHack::isFloorTerrain(ttype)) - { - cerr << "Cursor should be placed over a floor." << endl; - if(temporary_terminal) - cin.ignore(); - return 1; - } - } - } - coordmap counts; - // proceed with the dumpification operation - for(uint32_t i=0; i< numItems; i++) - { - DFHack::dfh_item temp; - Items->readItem(p_items[i],temp); - DFCoord pos_item(temp.base.x, temp.base.y, temp.base.z); - - // keep track how many items are at places. all items. - coordmap::iterator it = counts.find(pos_item); - if(it == counts.end()) - { - std::pair< coordmap::iterator, bool > inserted = counts.insert(std::make_pair(pos_item,1)); - it = inserted.first; - } - else - { - it->second ++; - } - // iterator is valid here, we use it later to decrement the pile counter if the item is moved - - // only dump the stuff marked for dumping and laying on the ground - if ( !temp.base.flags.dump - || !temp.base.flags.on_ground - || temp.base.flags.construction - || temp.base.flags.hidden - || temp.base.flags.in_building - || temp.base.flags.in_chest - || temp.base.flags.in_inventory - || temp.base.flags.construction - ) - continue; - - if(!destroy) // move to cursor - { - // Change flags to indicate the dump was completed, as if by super-dwarfs - temp.base.flags.dump = false; - temp.base.flags.forbid = true; - - // Don't move items if they're already at the cursor - if (pos_cursor == pos_item) - continue; - - // Move the item - temp.base.x = pos_cursor.x; - temp.base.y = pos_cursor.y; - temp.base.z = pos_cursor.z; - } - else // destroy - { - temp.base.flags.garbage_colect = true; - } - Items->writeItem(temp); - // keeping track of item pile sizes ;) - it->second --; - dumped_total++; - } - if(!destroy) // TODO: do we have to do any of this when destroying items? - { - // for each item pile, see if it reached zero. if so, unset item flag on the tile it's on - coordmap::iterator it = counts.begin(); - coordmap::iterator end = counts.end(); - while(it != end) - { - if(it->second == 0) - { - t_occupancy occ = MC.occupancyAt(it->first); - occ.bits.item = false; - MC.setOccupancyAt(it->first, occ); - } - it++; - } - // Set "item here" flag on target tile, if we moved any items to the target tile. - if (dumped_total > 0) - { - // assume there is a possibility the cursor points at some weird location with missing block data - Block * b = MC.BlockAt(pos_cursor / 16); - if(b) - { - t_occupancy occ = MC.occupancyAt(pos_cursor); - occ.bits.item = 1; - MC.setOccupancyAt(pos_cursor,occ); - } - } - // write map changes back to DF. - MC.WriteAll(); - // Is this necessary? Is "forbid" a dirtyable attribute like "dig" is? - Maps->WriteDirtyBit(cx/16, cy/16, cz, true); - } - DF->Detach(); - if(!destroy) - { - cout << "Done. " << dumped_total << " items quickdumped." << endl; - } - else - { - cout << "Done. " << dumped_total << " items marked for destruction." << endl; - } - if(temporary_terminal) - { - cout << "Press any key to continue" << endl; - cin.ignore(); - } - return 0; -} \ No newline at end of file