summaryrefslogtreecommitdiff
path: root/plugins/changeitem.cpp
diff options
context:
space:
mode:
authorRobert Heinrich2012-03-29 15:33:54 +0200
committerRobert Heinrich2012-03-29 15:33:54 +0200
commit88c914142bcbd1a24bac09f5057b69472d7021d9 (patch)
tree0143146a366e20152348af0865a57b3e83bb5a54 /plugins/changeitem.cpp
parent1f5c586f6203052b3bb3c0eb0cd33319082e7a2e (diff)
downloaddfhack-88c914142bcbd1a24bac09f5057b69472d7021d9.tar.gz
dfhack-88c914142bcbd1a24bac09f5057b69472d7021d9.tar.bz2
dfhack-88c914142bcbd1a24bac09f5057b69472d7021d9.tar.xz
added plugin changeitem (change material type and base quality)
Diffstat (limited to 'plugins/changeitem.cpp')
-rw-r--r--plugins/changeitem.cpp322
1 files changed, 322 insertions, 0 deletions
diff --git a/plugins/changeitem.cpp b/plugins/changeitem.cpp
new file mode 100644
index 00000000..b3fb2deb
--- /dev/null
+++ b/plugins/changeitem.cpp
@@ -0,0 +1,322 @@
+// changeitem plugin
+// allows to change the material type and quality of selected items
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <climits>
+#include <vector>
+#include <string>
+#include <algorithm>
+#include <set>
+using namespace std;
+
+#include "Core.h"
+#include "Console.h"
+#include "Export.h"
+#include "PluginManager.h"
+#include "modules/Maps.h"
+#include "modules/Gui.h"
+#include "modules/Items.h"
+#include "modules/Materials.h"
+#include "modules/MapCache.h"
+
+#include "DataDefs.h"
+#include "df/item.h"
+#include "df/world.h"
+#include "df/general_ref.h"
+
+using namespace DFHack;
+using namespace df::enums;
+
+using MapExtras::Block;
+using MapExtras::MapCache;
+using df::global::world;
+
+DFHACK_PLUGIN("changeitem");
+
+command_result df_changeitem(color_ostream &out, vector <string> & parameters);
+
+const string changeitem_help =
+ "Changeitem allows to change some item attributes.\n"
+ "By default the item currently selected in the UI will be changed\n"
+ "(you can select items in the 'k' list or inside containers/inventory).\n"
+ "By default change is only allowed if materials is of the same subtype\n"
+ "(for example wood<->wood, stone<->stone etc). But since some transformations\n"
+ "work pretty well and may be desired you can override this with 'force'.\n"
+ "Note that some attributes will not be touched, possibly resulting in weirdness.\n"
+ "To get an idea how the RAW id should look like, check some items with 'info'.\n"
+ "Using 'force' might create items which are not touched by crafters/haulers.\n"
+ "Options:\n"
+ " info - don't change anything, print some item info instead\n"
+ " here - change all items at cursor position\n"
+ " material, m - change material. must be followed by material RAW id\n"
+ " quality, q - change base quality. must be followed by number (0-5)\n"
+ " force - ignore subtypes, force change to new material.\n"
+ "Example:\n"
+ " changeitem m INORGANIC:GRANITE here"
+ " change material of all items under the cursor to granite\n"
+ " changeitem q 5\n"
+ " change currently selected item to masterpiece quality\n";
+
+
+DFhackCExport command_result plugin_init ( color_ostream &out, vector <PluginCommand> &commands)
+{
+ commands.clear();
+ commands.push_back(PluginCommand(
+ "changeitem", "Change item attributes (material, quality).",
+ df_changeitem, false,
+ changeitem_help.c_str()
+ ));
+
+ return CR_OK;
+}
+
+DFhackCExport command_result plugin_shutdown ( color_ostream &out )
+{
+ return CR_OK;
+}
+
+// probably there is some method in the library which does the same
+// todo: look for it :)
+string describeQuality(int q)
+{
+ switch(q)
+ {
+ case 0:
+ return "Basic";
+ case 1:
+ return "-Well-crafted-";
+ case 2:
+ return "+Finely-crafted+";
+ case 3:
+ return "*Superior quality*";
+ case 4:
+ return "#Exceptional#";
+ case 5:
+ return "$Masterful$";
+ default:
+ return "!INVALID!";
+ }
+}
+
+command_result changeitem_execute(
+ color_ostream &out, df::item * item,
+ bool info, bool force,
+ bool change_material, string new_material,
+ bool change_quality, int new_quality);
+
+command_result df_changeitem(color_ostream &out, vector <string> & parameters)
+{
+ CoreSuspender suspend;
+
+ bool here = false;
+ bool info = false;
+ bool force = false;
+
+ bool change_material = false;
+ string new_material = "none";
+
+ bool change_quality = false;
+ int new_quality = 0;
+
+ for (size_t i = 0; i < parameters.size(); i++)
+ {
+ string & p = parameters[i];
+
+ if (p == "help" || p == "?")
+ {
+ out << changeitem_help << endl;
+ return CR_OK;
+ }
+ else if (p == "here")
+ {
+ here = true;
+ }
+ else if (p == "info")
+ {
+ info = true;
+ }
+ else if (p == "force")
+ {
+ force = true;
+ }
+ else if (p == "material" || p == "m" )
+ {
+ // must be followed by material RAW id
+ // (string like 'INORGANIC:GRANITE', 'PLANT:MAPLE:WOOD', ...)
+ if(i == parameters.size()-1)
+ {
+ out.printerr("no material specified!\n");
+ }
+ change_material = true;
+ new_material = parameters[i+1];
+ i++;
+ }
+ else if (p == "quality" || p == "q")
+ {
+ // must be followed by numeric quality (allowed: 0-5)
+ if(i == parameters.size()-1)
+ {
+ out.printerr("no quality specified!\n");
+ }
+ string & q = parameters[i+1];
+ // meh. should use a stringstream instead. but it's only 6 numbers
+ if(q == "0")
+ new_quality = 0;
+ else if(q == "1")
+ new_quality = 1;
+ else if(q == "2")
+ new_quality = 2;
+ else if(q == "3")
+ new_quality = 3;
+ else if(q == "4")
+ new_quality = 4;
+ else if(q == "5")
+ new_quality = 5;
+ else
+ {
+ out << "Invalid quality specified!" << endl;
+ return CR_WRONG_USAGE;
+ }
+ out << "change to quality: " << describeQuality(new_quality) << endl;
+ change_quality = true;
+ i++;
+ }
+ else
+ {
+ out << p << ": Unknown command!" << endl;
+ return CR_WRONG_USAGE;
+ }
+ }
+
+ if (!Maps::IsValid())
+ {
+ out.printerr("Map is not available!\n");
+ return CR_FAILURE;
+ }
+
+ MaterialInfo mat_new;
+ if (change_material && !mat_new.find(new_material))
+ {
+ out.printerr("No such material!\n");
+ return CR_FAILURE;
+ }
+
+ if (here)
+ {
+ int processed_total = 0;
+ int cx, cy, cz;
+ DFCoord pos_cursor;
+
+ // needs a cursor
+ if (!Gui::getCursorCoords(cx,cy,cz))
+ {
+ out.printerr("Cursor position not found. Please enable the cursor.\n");
+ return CR_FAILURE;
+ }
+ pos_cursor = DFCoord(cx,cy,cz);
+
+ // uh. is this check necessary?
+ // changeitem doesn't do stuff with map blocks...
+ {
+ MapCache MC;
+ Block * b = MC.BlockAt(pos_cursor / 16);
+ if(!b)
+ {
+ out.printerr("Cursor is in an invalid/uninitialized area. Place it over a floor.\n");
+ return CR_FAILURE;
+ }
+ // when only changing material it doesn't matter if cursor is over a tile
+ //df::tiletype ttype = MC.tiletypeAt(pos_cursor);
+ //if(!DFHack::isFloorTerrain(ttype))
+ //{
+ // out.printerr("Cursor should be placed over a floor.\n");
+ // return CR_FAILURE;
+ //}
+ }
+
+ // iterate over all items, process those where pos = pos_cursor
+ size_t numItems = world->items.all.size();
+ for(size_t i=0; i< numItems; i++)
+ {
+ df::item * item = world->items.all[i];
+ DFCoord pos_item(item->pos.x, item->pos.y, item->pos.z);
+
+ if (pos_item != pos_cursor)
+ continue;
+
+ changeitem_execute(out, item, info, force, change_material, new_material, change_quality, new_quality);
+ processed_total++;
+ }
+ out.print("Done. %d items processed.\n", processed_total);
+ }
+ else
+ {
+ // needs a selected item
+ df::item *item = Gui::getSelectedItem(out);
+ if (!item)
+ {
+ out.printerr("No item selected.\n");
+ return CR_FAILURE;
+ }
+ changeitem_execute(out, item, info, force, change_material, new_material, change_quality, new_quality);
+ }
+ return CR_OK;
+}
+
+command_result changeitem_execute(
+ color_ostream &out, df::item * item,
+ bool info, bool force,
+ bool change_material, string new_material,
+ bool change_quality, int new_quality )
+{
+ MaterialInfo mat_new;
+ MaterialInfo mat_old;
+
+ if(change_material)
+ mat_new.find(new_material);
+ if(change_material || info)
+ mat_old.decode(item);
+
+ // print some info, don't change stuff
+ if(info)
+ {
+ out << "Item info: " << endl;
+ out << " quality: " << describeQuality(item->getQuality()) << endl;
+ //if(item->isImproved())
+ // out << " imp.quality: " << describeQuality(item->getImprovementQuality()) << endl;
+ out << " material: " << mat_old.getToken() << endl;
+ return CR_OK;
+ }
+
+ if(change_quality)
+ {
+ item->setQuality(new_quality);
+ // it would be nice to be able to change the improved quality, too
+ // (only allowed if the item is already improved)
+ // but there is no method in item.h which supports that
+ // ok: hints from _Q/angavrilov: improvent is a vector, an item can have more than one improvement
+ // -> virtual_cast to item_constructedst
+ }
+
+ if(change_material)
+ {
+ // subtype and mode should match to avoid doing dumb stuff like changing boulders into meat whatever
+ // changing a stone cabinet to wood is fine, though. as well as lots of other combinations.
+ // still, it's better to make the user activate 'force' if he really wants to.
+
+ if(force||(mat_old.subtype == mat_new.subtype && mat_old.mode==mat_new.mode))
+ {
+ item->setMaterial(mat_new.type);
+ item->setMaterialIndex(mat_new.index);
+ }
+ else
+ {
+ out.printerr("change denied: subtype doesn't match. use 'force' to override.\n");
+ }
+
+ item->flags.bits.unk8 = 0; // recalc temperatures next time touched
+ item->flags.bits.weight_computed = 0; // recalc weight next time touched
+ }
+ return CR_OK;
+}