2011-08-03 20:04:46 -06:00
|
|
|
// Quick Dumper : Moves items marked as "dump" to cursor
|
|
|
|
// FIXME: local item cache in map blocks needs to be fixed after teleporting items
|
|
|
|
|
2011-12-31 04:48:42 -07:00
|
|
|
#include "Core.h"
|
2012-01-15 13:54:14 -07:00
|
|
|
#include "Console.h"
|
2023-01-18 14:38:23 -07:00
|
|
|
#include "DataDefs.h"
|
2012-01-15 13:54:14 -07:00
|
|
|
#include "Export.h"
|
|
|
|
#include "PluginManager.h"
|
2023-01-18 14:38:23 -07:00
|
|
|
|
2012-01-15 13:54:14 -07:00
|
|
|
#include "modules/Maps.h"
|
|
|
|
#include "modules/Gui.h"
|
|
|
|
#include "modules/Items.h"
|
|
|
|
#include "modules/Materials.h"
|
|
|
|
#include "modules/MapCache.h"
|
2011-08-03 20:04:46 -06:00
|
|
|
|
2012-01-15 13:54:14 -07:00
|
|
|
#include "df/item.h"
|
|
|
|
#include "df/world.h"
|
|
|
|
#include "df/general_ref.h"
|
2014-06-04 04:01:17 -06:00
|
|
|
#include "df/viewscreen_dwarfmodest.h"
|
|
|
|
#include "df/building_stockpilest.h"
|
2012-01-14 10:13:30 -07:00
|
|
|
|
2023-01-18 14:38:23 -07:00
|
|
|
#include <iostream>
|
|
|
|
#include <iomanip>
|
|
|
|
#include <sstream>
|
|
|
|
#include <climits>
|
|
|
|
#include <vector>
|
|
|
|
#include <string>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <set>
|
|
|
|
|
|
|
|
using namespace std;
|
2011-08-03 20:04:46 -06:00
|
|
|
using namespace DFHack;
|
2012-01-21 17:31:15 -07:00
|
|
|
using namespace df::enums;
|
|
|
|
|
2011-08-03 20:04:46 -06:00
|
|
|
using MapExtras::Block;
|
|
|
|
using MapExtras::MapCache;
|
2014-06-04 04:01:17 -06:00
|
|
|
|
|
|
|
using df::building_stockpilest;
|
2011-08-03 20:04:46 -06:00
|
|
|
|
2012-02-21 10:19:17 -07:00
|
|
|
DFHACK_PLUGIN("autodump");
|
2015-07-28 19:48:00 -06:00
|
|
|
REQUIRE_GLOBAL(gps);
|
2014-12-02 19:44:20 -07:00
|
|
|
REQUIRE_GLOBAL(world);
|
2012-02-21 10:19:17 -07:00
|
|
|
|
2012-03-10 04:55:42 -07:00
|
|
|
command_result df_autodump(color_ostream &out, vector <string> & parameters);
|
|
|
|
command_result df_autodump_destroy_here(color_ostream &out, vector <string> & parameters);
|
|
|
|
command_result df_autodump_destroy_item(color_ostream &out, vector <string> & parameters);
|
2011-08-03 20:04:46 -06:00
|
|
|
|
2012-03-10 04:55:42 -07:00
|
|
|
DFhackCExport command_result plugin_init ( color_ostream &out, vector <PluginCommand> &commands)
|
2011-08-03 20:04:46 -06:00
|
|
|
{
|
2012-01-28 05:03:56 -07:00
|
|
|
commands.push_back(PluginCommand(
|
2022-07-18 14:28:16 -06:00
|
|
|
"autodump",
|
2023-01-18 14:38:23 -07:00
|
|
|
"Teleport items marked for dumping to the keyboard cursor.",
|
2023-05-18 17:56:22 -06:00
|
|
|
df_autodump));
|
2012-01-14 10:13:30 -07:00
|
|
|
commands.push_back(PluginCommand(
|
2022-07-18 14:28:16 -06:00
|
|
|
"autodump-destroy-here",
|
2023-01-18 14:38:23 -07:00
|
|
|
"Destroy items marked for dumping under the keyboard cursor.",
|
2022-07-18 14:28:16 -06:00
|
|
|
df_autodump_destroy_here,
|
2023-01-18 14:57:42 -07:00
|
|
|
Gui::cursor_hotkey));
|
2012-01-14 10:13:30 -07:00
|
|
|
commands.push_back(PluginCommand(
|
2022-07-18 14:28:16 -06:00
|
|
|
"autodump-destroy-item",
|
|
|
|
"Destroy the selected item.",
|
|
|
|
df_autodump_destroy_item,
|
|
|
|
Gui::any_item_hotkey));
|
2011-08-03 20:04:46 -06:00
|
|
|
return CR_OK;
|
|
|
|
}
|
|
|
|
|
2012-03-10 04:55:42 -07:00
|
|
|
DFhackCExport command_result plugin_shutdown ( color_ostream &out )
|
2011-08-03 20:04:46 -06:00
|
|
|
{
|
|
|
|
return CR_OK;
|
|
|
|
}
|
|
|
|
|
2012-01-31 09:55:38 -07:00
|
|
|
typedef map <DFCoord, uint32_t> coordmap;
|
2011-08-03 20:04:46 -06:00
|
|
|
|
2012-03-10 04:55:42 -07:00
|
|
|
static command_result autodump_main(color_ostream &out, vector <string> & parameters)
|
2011-08-03 20:04:46 -06:00
|
|
|
{
|
|
|
|
// Command line options
|
|
|
|
bool destroy = false;
|
2012-01-14 10:13:30 -07:00
|
|
|
bool here = false;
|
2012-01-28 06:40:09 -07:00
|
|
|
bool need_visible = false;
|
|
|
|
bool need_hidden = false;
|
|
|
|
bool need_forbidden = false;
|
2012-01-31 09:55:38 -07:00
|
|
|
for (size_t i = 0; i < parameters.size(); i++)
|
2011-08-03 20:04:46 -06:00
|
|
|
{
|
2012-01-29 07:17:06 -07:00
|
|
|
string & p = parameters[i];
|
2011-08-03 20:04:46 -06:00
|
|
|
if(p == "destroy")
|
|
|
|
destroy = true;
|
2012-01-14 10:13:30 -07:00
|
|
|
else if (p == "destroy-here")
|
|
|
|
destroy = here = true;
|
2012-01-28 06:40:09 -07:00
|
|
|
else if (p == "visible")
|
|
|
|
need_visible = true;
|
|
|
|
else if (p == "hidden")
|
|
|
|
need_hidden = true;
|
|
|
|
else if (p == "forbidden")
|
|
|
|
need_forbidden = true;
|
2012-01-28 05:03:56 -07:00
|
|
|
else
|
|
|
|
return CR_WRONG_USAGE;
|
2011-08-03 20:04:46 -06:00
|
|
|
}
|
2012-01-15 13:59:47 -07:00
|
|
|
|
2012-01-28 06:40:09 -07:00
|
|
|
if (need_visible && need_hidden)
|
|
|
|
{
|
2012-03-10 04:55:42 -07:00
|
|
|
out.printerr("An item can't be both hidden and visible.\n");
|
2012-01-28 06:40:09 -07:00
|
|
|
return CR_WRONG_USAGE;
|
|
|
|
}
|
|
|
|
|
2012-01-19 20:44:17 -07:00
|
|
|
if (!Maps::IsValid())
|
2011-08-03 20:04:46 -06:00
|
|
|
{
|
2012-03-10 04:55:42 -07:00
|
|
|
out.printerr("Map is not available!\n");
|
2011-08-03 20:04:46 -06:00
|
|
|
return CR_FAILURE;
|
|
|
|
}
|
2012-01-31 09:55:38 -07:00
|
|
|
size_t numItems = world->items.all.size();
|
2012-01-19 20:44:17 -07:00
|
|
|
|
|
|
|
MapCache MC;
|
2011-08-03 20:04:46 -06:00
|
|
|
int dumped_total = 0;
|
|
|
|
|
2023-01-18 14:57:42 -07:00
|
|
|
df::coord pos_cursor;
|
2012-01-14 10:13:30 -07:00
|
|
|
if(!destroy || here)
|
2011-08-03 20:04:46 -06:00
|
|
|
{
|
2023-01-18 14:57:42 -07:00
|
|
|
pos_cursor = Gui::getCursorPos();
|
2023-01-18 14:38:23 -07:00
|
|
|
if (!pos_cursor.isValid()) {
|
2023-01-18 14:57:42 -07:00
|
|
|
out.printerr("Keyboard cursor must be over a suitable map tile.\n");
|
2011-08-03 20:04:46 -06:00
|
|
|
return CR_FAILURE;
|
|
|
|
}
|
2012-01-14 10:13:30 -07:00
|
|
|
}
|
|
|
|
if (!destroy)
|
|
|
|
{
|
2011-08-03 20:04:46 -06:00
|
|
|
{
|
|
|
|
Block * b = MC.BlockAt(pos_cursor / 16);
|
|
|
|
if(!b)
|
|
|
|
{
|
2012-03-10 04:55:42 -07:00
|
|
|
out.printerr("Cursor is in an invalid/uninitialized area. Place it over a floor.\n");
|
2011-08-03 20:04:46 -06:00
|
|
|
return CR_FAILURE;
|
|
|
|
}
|
2012-02-13 15:56:33 -07:00
|
|
|
df::tiletype ttype = MC.tiletypeAt(pos_cursor);
|
2023-07-17 07:42:08 -06:00
|
|
|
if(!DFHack::isWalkable(ttype))
|
2011-08-03 20:04:46 -06:00
|
|
|
{
|
2012-03-10 04:55:42 -07:00
|
|
|
out.printerr("Cursor should be placed over a floor.\n");
|
2011-08-03 20:04:46 -06:00
|
|
|
return CR_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-04-10 10:19:41 -06:00
|
|
|
|
2011-08-03 20:04:46 -06:00
|
|
|
// proceed with the dumpification operation
|
2012-01-31 09:55:38 -07:00
|
|
|
for(size_t i=0; i< numItems; i++)
|
2011-08-03 20:04:46 -06:00
|
|
|
{
|
2012-01-16 21:12:58 -07:00
|
|
|
df::item * itm = world->items.all[i];
|
2012-01-19 03:30:22 -07:00
|
|
|
DFCoord pos_item(itm->pos.x, itm->pos.y, itm->pos.z);
|
2011-08-03 20:04:46 -06:00
|
|
|
|
|
|
|
// only dump the stuff marked for dumping and laying on the ground
|
2012-01-16 19:16:16 -07:00
|
|
|
if ( !itm->flags.bits.dump
|
2012-05-15 04:32:09 -06:00
|
|
|
// || !itm->flags.bits.on_ground
|
2012-01-16 19:16:16 -07:00
|
|
|
|| itm->flags.bits.construction
|
|
|
|
|| itm->flags.bits.in_building
|
|
|
|
|| itm->flags.bits.in_chest
|
2012-05-15 04:32:09 -06:00
|
|
|
// || itm->flags.bits.in_inventory
|
2012-11-28 11:46:56 -07:00
|
|
|
|| itm->flags.bits.artifact
|
2011-08-03 20:04:46 -06:00
|
|
|
)
|
|
|
|
continue;
|
|
|
|
|
2012-01-28 06:40:09 -07:00
|
|
|
if (need_visible && itm->flags.bits.hidden)
|
|
|
|
continue;
|
|
|
|
if (need_hidden && !itm->flags.bits.hidden)
|
|
|
|
continue;
|
|
|
|
if (need_forbidden && !itm->flags.bits.forbid)
|
|
|
|
continue;
|
|
|
|
if (!need_forbidden && itm->flags.bits.forbid)
|
|
|
|
continue;
|
|
|
|
|
2023-02-12 14:49:40 -07:00
|
|
|
if (!destroy) // move to cursor
|
2011-08-03 20:04:46 -06:00
|
|
|
{
|
|
|
|
// Don't move items if they're already at the cursor
|
2012-04-10 10:19:41 -06:00
|
|
|
if (pos_cursor != pos_item)
|
2012-05-20 11:57:45 -06:00
|
|
|
{
|
2023-02-12 14:49:40 -07:00
|
|
|
if (Items::moveToGround(MC, itm, pos_cursor))
|
|
|
|
{
|
|
|
|
// Change flags to indicate the dump was completed, as if by super-dwarfs
|
|
|
|
itm->flags.bits.dump = false;
|
|
|
|
itm->flags.bits.forbid = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-05-20 11:57:45 -06:00
|
|
|
out.print("Could not move item: %s\n",
|
2023-02-12 14:49:40 -07:00
|
|
|
Items::getDescription(itm, 0, true).c_str());
|
|
|
|
}
|
2012-05-20 11:57:45 -06:00
|
|
|
}
|
2011-08-03 20:04:46 -06:00
|
|
|
}
|
|
|
|
else // destroy
|
|
|
|
{
|
2012-01-14 10:13:30 -07:00
|
|
|
if (here && pos_item != pos_cursor)
|
|
|
|
continue;
|
|
|
|
|
2012-03-30 00:44:52 -06:00
|
|
|
itm->flags.bits.garbage_collect = true;
|
2012-01-14 10:13:30 -07:00
|
|
|
|
|
|
|
// Cosmetic changes: make them disappear from view instantly
|
2012-01-16 19:16:16 -07:00
|
|
|
itm->flags.bits.forbid = true;
|
|
|
|
itm->flags.bits.hidden = true;
|
2011-08-03 20:04:46 -06:00
|
|
|
}
|
2012-04-10 10:19:41 -06:00
|
|
|
|
2011-08-03 20:04:46 -06:00
|
|
|
dumped_total++;
|
|
|
|
}
|
2012-04-10 10:19:41 -06:00
|
|
|
|
|
|
|
// write map changes back to DF.
|
|
|
|
if(!destroy)
|
2011-08-03 20:04:46 -06:00
|
|
|
MC.WriteAll();
|
2012-04-10 10:19:41 -06:00
|
|
|
|
2012-03-10 04:55:42 -07:00
|
|
|
out.print("Done. %d items %s.\n", dumped_total, destroy ? "marked for destruction" : "quickdumped");
|
2011-08-03 20:04:46 -06:00
|
|
|
return CR_OK;
|
2012-01-14 10:13:30 -07:00
|
|
|
}
|
|
|
|
|
2012-03-10 04:55:42 -07:00
|
|
|
command_result df_autodump(color_ostream &out, vector <string> & parameters)
|
2012-01-14 10:13:30 -07:00
|
|
|
{
|
2012-03-10 04:55:42 -07:00
|
|
|
CoreSuspender suspend;
|
2012-01-14 10:13:30 -07:00
|
|
|
|
2012-03-10 04:55:42 -07:00
|
|
|
return autodump_main(out, parameters);
|
2012-01-14 10:13:30 -07:00
|
|
|
}
|
|
|
|
|
2012-03-10 04:55:42 -07:00
|
|
|
command_result df_autodump_destroy_here(color_ostream &out, vector <string> & parameters)
|
2012-01-14 10:13:30 -07:00
|
|
|
{
|
|
|
|
if (!parameters.empty())
|
|
|
|
return CR_WRONG_USAGE;
|
|
|
|
|
|
|
|
vector<string> args;
|
|
|
|
args.push_back("destroy-here");
|
|
|
|
|
2023-01-18 14:38:23 -07:00
|
|
|
CoreSuspender suspend;
|
|
|
|
|
2012-03-10 04:55:42 -07:00
|
|
|
return autodump_main(out, args);
|
2012-01-14 10:13:30 -07:00
|
|
|
}
|
|
|
|
|
2012-01-31 09:55:38 -07:00
|
|
|
static map<int, df::item_flags> pending_destroy;
|
2012-01-14 10:13:30 -07:00
|
|
|
static int last_frame = 0;
|
|
|
|
|
2012-03-10 04:55:42 -07:00
|
|
|
command_result df_autodump_destroy_item(color_ostream &out, vector <string> & parameters)
|
2012-01-14 10:13:30 -07:00
|
|
|
{
|
|
|
|
if (!parameters.empty())
|
|
|
|
return CR_WRONG_USAGE;
|
|
|
|
|
2023-02-06 02:23:52 -07:00
|
|
|
CoreSuspender suspend;
|
|
|
|
|
2012-03-10 04:55:42 -07:00
|
|
|
df::item *item = Gui::getSelectedItem(out);
|
2012-01-14 10:13:30 -07:00
|
|
|
if (!item)
|
|
|
|
return CR_FAILURE;
|
|
|
|
|
|
|
|
// Allow undoing the destroy
|
2012-01-21 17:31:15 -07:00
|
|
|
if (world->frame_counter != last_frame)
|
2012-01-14 10:13:30 -07:00
|
|
|
{
|
2012-01-21 17:31:15 -07:00
|
|
|
last_frame = world->frame_counter;
|
2012-01-14 10:13:30 -07:00
|
|
|
pending_destroy.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pending_destroy.count(item->id))
|
|
|
|
{
|
|
|
|
df::item_flags old_flags = pending_destroy[item->id];
|
|
|
|
pending_destroy.erase(item->id);
|
|
|
|
|
2012-03-30 00:44:52 -06:00
|
|
|
item->flags.bits.garbage_collect = false;
|
2012-01-14 10:13:30 -07:00
|
|
|
item->flags.bits.hidden = old_flags.bits.hidden;
|
|
|
|
item->flags.bits.dump = old_flags.bits.dump;
|
|
|
|
item->flags.bits.forbid = old_flags.bits.forbid;
|
|
|
|
return CR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check the item is good to destroy
|
2012-03-30 00:44:52 -06:00
|
|
|
if (item->flags.bits.garbage_collect)
|
2012-01-14 10:13:30 -07:00
|
|
|
{
|
2012-03-10 04:55:42 -07:00
|
|
|
out.printerr("Item is already marked for destroy.\n");
|
2012-01-14 10:13:30 -07:00
|
|
|
return CR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (item->flags.bits.construction ||
|
|
|
|
item->flags.bits.in_building ||
|
2012-11-28 11:46:56 -07:00
|
|
|
item->flags.bits.artifact)
|
2012-01-14 10:13:30 -07:00
|
|
|
{
|
2012-03-10 04:55:42 -07:00
|
|
|
out.printerr("Choosing not to destroy buildings, constructions and artifacts.\n");
|
2012-01-14 10:13:30 -07:00
|
|
|
return CR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2012-11-12 07:27:58 -07:00
|
|
|
for (size_t i = 0; i < item->general_refs.size(); i++)
|
2012-01-14 10:13:30 -07:00
|
|
|
{
|
2012-11-12 07:27:58 -07:00
|
|
|
df::general_ref *ref = item->general_refs[i];
|
2012-01-21 17:31:15 -07:00
|
|
|
if (ref->getType() == general_ref_type::UNIT_HOLDER)
|
2012-01-14 10:13:30 -07:00
|
|
|
{
|
2012-03-10 04:55:42 -07:00
|
|
|
out.printerr("Choosing not to destroy items in unit inventory.\n");
|
2012-01-14 10:13:30 -07:00
|
|
|
return CR_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the flags
|
|
|
|
pending_destroy[item->id] = item->flags;
|
|
|
|
|
2012-03-30 00:44:52 -06:00
|
|
|
item->flags.bits.garbage_collect = true;
|
2012-01-14 10:13:30 -07:00
|
|
|
item->flags.bits.hidden = true;
|
|
|
|
item->flags.bits.dump = true;
|
|
|
|
item->flags.bits.forbid = true;
|
|
|
|
return CR_OK;
|
|
|
|
}
|